b5abf84fa98614c1d171364315058eef1728539b
[platform/upstream/rpm.git] / file / readelf.c
1 #include "system.h"
2
3 #ifdef BUILTIN_ELF
4 #include "file.h"
5 #include "readelf.h"
6 #include "debug.h"
7
8 FILE_RCSID("@(#)Id: readelf.c,v 1.22 2002/07/03 18:26:38 christos Exp ")
9
10 /*@access fmagic @*/
11
12 static uint16_t
13 getu16(const fmagic fm, uint16_t value)
14         /*@*/
15 {
16         union {
17                 uint16_t ui;
18                 char c[2];
19         } retval, tmpval;
20
21         if (fm->swap) {
22                 tmpval.ui = value;
23
24                 retval.c[0] = tmpval.c[1];
25                 retval.c[1] = tmpval.c[0];
26                 
27                 return retval.ui;
28         } else
29                 return value;
30 }
31
32 static uint32_t
33 getu32(const fmagic fm, uint32_t value)
34         /*@*/
35 {
36         union {
37                 uint32_t ui;
38                 char c[4];
39         } retval, tmpval;
40
41         if (fm->swap) {
42                 tmpval.ui = value;
43
44                 retval.c[0] = tmpval.c[3];
45                 retval.c[1] = tmpval.c[2];
46                 retval.c[2] = tmpval.c[1];
47                 retval.c[3] = tmpval.c[0];
48                 
49                 return retval.ui;
50         } else
51                 return value;
52 }
53
54 static uint64_t
55 getu64(const fmagic fm, uint64_t value)
56         /*@*/
57 {
58         union {
59                 uint64_t ui;
60                 char c[8];
61         } retval, tmpval;
62
63         if (fm->swap) {
64                 tmpval.ui = value;
65
66                 retval.c[0] = tmpval.c[7];
67                 retval.c[1] = tmpval.c[6];
68                 retval.c[2] = tmpval.c[5];
69                 retval.c[3] = tmpval.c[4];
70                 retval.c[4] = tmpval.c[3];
71                 retval.c[5] = tmpval.c[2];
72                 retval.c[6] = tmpval.c[1];
73                 retval.c[7] = tmpval.c[0];
74                 
75                 return retval.ui;
76         } else
77                 return value;
78 }
79
80 #define sh_addr         (fm->cls == ELFCLASS32          \
81                          ? (void *) &sh32               \
82                          : (void *) &sh64)
83 #define shs_type        (fm->cls == ELFCLASS32          \
84                          ? getu32(fm, sh32.sh_type)     \
85                          : getu32(fm, sh64.sh_type))
86 #define ph_addr         (fm->cls == ELFCLASS32          \
87                          ? (void *) &ph32               \
88                          : (void *) &ph64)
89 #define ph_type         (fm->cls == ELFCLASS32          \
90                          ? getu32(fm, ph32.p_type)      \
91                          : getu32(fm, ph64.p_type))
92 #define ph_offset       (fm->cls == ELFCLASS32          \
93                          ? getu32(fm, ph32.p_offset)    \
94                          : getu64(fm, ph64.p_offset))
95 #define ph_align        (fm->cls == ELFCLASS32          \
96                          ? (ph32.p_align ? getu32(fm, ph32.p_align) : 4) \
97                          : (ph64.p_align ? getu64(fm, ph64.p_align) : 4))
98 #define nh_size         (fm->cls == ELFCLASS32          \
99                          ? sizeof *nh32                 \
100                          : sizeof *nh64)
101 #define nh_type         (fm->cls == ELFCLASS32          \
102                          ? getu32(fm, nh32->n_type)     \
103                          : getu32(fm, nh64->n_type))
104 #define nh_namesz       (fm->cls == ELFCLASS32          \
105                          ? getu32(fm, nh32->n_namesz)   \
106                          : getu32(fm, nh64->n_namesz))
107 #define nh_descsz       (fm->cls == ELFCLASS32          \
108                          ? getu32(fm, nh32->n_descsz)   \
109                          : getu32(fm, nh64->n_descsz))
110 #define prpsoffsets(i)  (fm->cls == ELFCLASS32          \
111                          ? prpsoffsets32[i]             \
112                          : prpsoffsets64[i])
113
114 static void
115 doshn(fmagic fm, off_t off, int num, size_t size)
116         /*@globals fileSystem @*/
117         /*@modifies fm, fileSystem @*/
118 {
119         Elf32_Shdr sh32;
120         Elf64_Shdr sh64;
121
122         if (lseek(fm->fd, off, SEEK_SET) == -1) {
123                 error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
124                 /*@notreached@*/
125         }
126
127         for ( ; num; num--) {
128                 if (read(fm->fd, sh_addr, size) == -1) {
129                         error(EXIT_FAILURE, 0, "read failed (%s).\n", strerror(errno));
130                         /*@notreached@*/
131                 }
132                 if (shs_type == SHT_SYMTAB /* || shs_type == SHT_DYNSYM */) {
133                         fmagicPrintf(fm, ", not stripped");
134                         return;
135                 }
136         }
137         fmagicPrintf(fm, ", stripped");
138 }
139
140 /*
141  * Look through the program headers of an executable image, searching
142  * for a PT_INTERP section; if one is found, it's dynamically linked,
143  * otherwise it's statically linked.
144  */
145 static void
146 dophn_exec(fmagic fm, off_t off, int num, size_t size)
147         /*@globals fileSystem @*/
148         /*@modifies fm, fileSystem @*/
149 {
150         Elf32_Phdr ph32;
151         Elf32_Nhdr *nh32 = NULL;
152         Elf64_Phdr ph64;
153         Elf64_Nhdr *nh64 = NULL;
154         char *linking_style = "statically";
155         char *shared_libraries = "";
156         char nbuf[BUFSIZ];
157         int bufsize;
158         size_t offset, nameoffset;
159
160         if (lseek(fm->fd, off, SEEK_SET) == -1) {
161                 error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
162                 /*@notreached@*/
163         }
164
165         for ( ; num; num--) {
166                 if (read(fm->fd, ph_addr, size) == -1) {
167                         error(EXIT_FAILURE, 0, "read failed (%s).\n", strerror(errno));
168                         /*@notreached@*/
169                 }
170
171                 switch (ph_type) {
172                 case PT_DYNAMIC:
173                         linking_style = "dynamically";
174                         /*@switchbreak@*/ break;
175                 case PT_INTERP:
176                         shared_libraries = " (uses shared libs)";
177                         /*@switchbreak@*/ break;
178                 case PT_NOTE:
179                         /*
180                          * This is a PT_NOTE section; loop through all the notes
181                          * in the section.
182                          */
183                         if (lseek(fm->fd, (off_t) ph_offset, SEEK_SET) == -1) {
184                                 error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
185                                 /*@notreached@*/
186                         }
187                         bufsize = read(fm->fd, nbuf, sizeof(nbuf));
188                         if (bufsize == -1) {
189                                 error(EXIT_FAILURE, 0, ": " "read failed (%s).\n",
190                                     strerror(errno));
191                                 /*@notreached@*/
192                         }
193                         offset = 0;
194                         for (;;) {
195                                 if (offset >= bufsize)
196                                         /*@innerbreak@*/ break;
197                                 if (fm->cls == ELFCLASS32)
198                                         nh32 = (Elf32_Nhdr *)&nbuf[offset];
199                                 else
200                                         nh64 = (Elf64_Nhdr *)&nbuf[offset];
201                                 offset += nh_size;
202         
203                                 if (offset + nh_namesz >= bufsize) {
204                                         /*
205                                          * We're past the end of the buffer.
206                                          */
207                                         /*@innerbreak@*/ break;
208                                 }
209
210                                 nameoffset = offset;
211                                 offset += nh_namesz;
212                                 offset = ((offset+ph_align-1)/ph_align)*ph_align;
213
214                                 if ((nh_namesz == 0) && (nh_descsz == 0)) {
215                                         /*
216                                          * We're out of note headers.
217                                          */
218                                         break;
219                                 }
220
221                                 if (offset + nh_descsz >= bufsize)
222                                         /*@innerbreak@*/ break;
223
224                                 if (nh_namesz == 4 &&
225                                     strcmp(&nbuf[nameoffset], "GNU") == 0 &&
226                                     nh_type == NT_GNU_VERSION &&
227                                     nh_descsz == 16) {
228                                         uint32_t *desc =
229                                             (uint32_t *)&nbuf[offset];
230
231                                         fmagicPrintf(fm, ", for GNU/");
232                                         switch (getu32(fm, desc[0])) {
233                                         case GNU_OS_LINUX:
234                                                 fmagicPrintf(fm, "Linux");
235                                                 /*@switchbreak@*/ break;
236                                         case GNU_OS_HURD:
237                                                 fmagicPrintf(fm, "Hurd");
238                                                 /*@switchbreak@*/ break;
239                                         case GNU_OS_SOLARIS:
240                                                 fmagicPrintf(fm, "Solaris");
241                                                 /*@switchbreak@*/ break;
242                                         default:
243                                                 fmagicPrintf(fm, "<unknown>");
244                                                 /*@switchbreak@*/ break;
245                                         }
246                                         fmagicPrintf(fm, " %d.%d.%d",
247                                             getu32(fm, desc[1]),
248                                             getu32(fm, desc[2]),
249                                             getu32(fm, desc[3]));
250                                 }
251
252                                 if (nh_namesz == 7 &&
253                                     strcmp(&nbuf[nameoffset], "NetBSD") == 0 &&
254                                     nh_type == NT_NETBSD_VERSION &&
255                                     nh_descsz == 4) {
256                                         fmagicPrintf(fm, ", for NetBSD");
257                                         /*
258                                          * Version number is stuck at 199905,
259                                          * and hence is basically content-free.
260                                          */
261                                 }
262
263                                 if (nh_namesz == 8 &&
264                                     strcmp(&nbuf[nameoffset], "FreeBSD") == 0 &&
265                                     nh_type == NT_FREEBSD_VERSION &&
266                                     nh_descsz == 4) {
267                                         uint32_t desc = getu32(fm,
268                                             *(uint32_t *)&nbuf[offset]);
269                                         fmagicPrintf(fm, ", for FreeBSD");
270                                         /*
271                                          * Contents is __FreeBSD_version,
272                                          * whose relation to OS versions is
273                                          * defined by a huge table in the
274                                          * Porters' Handbook.  Happily, the
275                                          * first three digits are the version
276                                          * number, at least in versions of
277                                          * FreeBSD that use this note.
278                                          */
279
280                                         fmagicPrintf(fm, " %d.%d", desc / 100000,
281                                             desc / 10000 % 10);
282                                         if (desc / 1000 % 10 > 0)
283                                                 fmagicPrintf(fm, ".%d",
284                                                     desc / 1000 % 10);
285                                 }
286
287                                 if (nh_namesz == 8 &&
288                                     strcmp(&nbuf[nameoffset], "OpenBSD") == 0 &&
289                                     nh_type == NT_OPENBSD_VERSION &&
290                                     nh_descsz == 4) {
291                                         fmagicPrintf(fm, ", for OpenBSD");
292                                         /* Content of note is always 0 */
293                                 }
294                         }
295                         if ((lseek(fm->fd, ph_offset + offset, SEEK_SET)) == -1) {
296                             error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
297                             /*@notreached@*/
298                         }
299                         /*@switchbreak@*/ break;
300                 }
301         }
302         fmagicPrintf(fm, ", %s linked%s", linking_style, shared_libraries);
303 }
304
305 #ifdef ELFCORE
306 /*@unchecked@*/ /*@observer@*/
307 static size_t   prpsoffsets32[] = {
308         8,              /* FreeBSD */
309         28,             /* Linux 2.0.36 */
310         32,             /* Linux (I forget which kernel version) */
311         84              /* SunOS 5.x */
312 };
313
314 /*@unchecked@*/ /*@observer@*/
315 static size_t   prpsoffsets64[] = {
316        120              /* SunOS 5.x, 64-bit */
317 };
318
319 #define NOFFSETS32      (sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
320 #define NOFFSETS64      (sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
321
322 #define NOFFSETS        (fm->cls == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
323
324 /*
325  * Look through the program headers of an executable image, searching
326  * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
327  * "FreeBSD"; if one is found, try looking in various places in its
328  * contents for a 16-character string containing only printable
329  * characters - if found, that string should be the name of the program
330  * that dropped core.  Note: right after that 16-character string is,
331  * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
332  * Linux, a longer string (80 characters, in 5.x, probably other
333  * SVR4-flavored systems, and Linux) containing the start of the
334  * command line for that program.
335  *
336  * The signal number probably appears in a section of type NT_PRSTATUS,
337  * but that's also rather OS-dependent, in ways that are harder to
338  * dissect with heuristics, so I'm not bothering with the signal number.
339  * (I suppose the signal number could be of interest in situations where
340  * you don't have the binary of the program that dropped core; if you
341  * *do* have that binary, the debugger will probably tell you what
342  * signal it was.)
343  */
344
345 #define OS_STYLE_SVR4           0
346 #define OS_STYLE_FREEBSD        1
347 #define OS_STYLE_NETBSD         2
348
349 /*@unchecked@*/ /*@observer@*/
350 static const char *os_style_names[] = {
351         "SVR4",
352         "FreeBSD",
353         "NetBSD",
354 };
355
356 static void
357 dophn_core(fmagic fm, off_t off, int num, size_t size)
358         /*@globals fileSystem @*/
359         /*@modifies fm, fileSystem @*/
360 {
361         Elf32_Phdr ph32;
362         Elf32_Nhdr *nh32 = NULL;
363         Elf64_Phdr ph64;
364         Elf64_Nhdr *nh64 = NULL;
365         size_t offset, nameoffset, noffset, reloffset;
366         unsigned char c;
367         int i, j;
368         char nbuf[BUFSIZ];
369         int bufsize;
370         int os_style = -1;
371
372         /*
373          * Loop through all the program headers.
374          */
375         for ( ; num; num--) {
376                 if (lseek(fm->fd, off, SEEK_SET) == -1) {
377                         error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
378                         /*@notreached@*/
379                 }
380                 if (read(fm->fd, ph_addr, size) == -1) {
381                         error(EXIT_FAILURE, 0, "read failed (%s).\n", strerror(errno));
382                         /*@notreached@*/
383                 }
384                 off += size;
385                 if (ph_type != PT_NOTE)
386                         continue;
387
388                 /*
389                  * This is a PT_NOTE section; loop through all the notes
390                  * in the section.
391                  */
392                 if (lseek(fm->fd, (off_t) ph_offset, SEEK_SET) == -1) {
393                         error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
394                         /*@notreached@*/
395                 }
396                 bufsize = read(fm->fd, nbuf, BUFSIZ);
397                 if (bufsize == -1) {
398                         error(EXIT_FAILURE, 0, ": " "read failed (%s).\n", strerror(errno));
399                         /*@notreached@*/
400                 }
401                 offset = 0;
402                 for (;;) {
403                         if (offset >= bufsize)
404                                 /*@innerbreak@*/ break;
405                         if (fm->cls == ELFCLASS32)
406                                 nh32 = (Elf32_Nhdr *)&nbuf[offset];
407                         else
408                                 nh64 = (Elf64_Nhdr *)&nbuf[offset];
409                         offset += nh_size;
410
411                         /*
412                          * Check whether this note has the name "CORE" or
413                          * "FreeBSD", or "NetBSD-CORE".
414                          */
415                         if (offset + nh_namesz >= bufsize) {
416                                 /*
417                                  * We're past the end of the buffer.
418                                  */
419                                 /*@innerbreak@*/ break;
420                         }
421
422                         nameoffset = offset;
423                         offset += nh_namesz;
424                         offset = ((offset + 3)/4)*4;
425
426                         /*
427                          * Sigh.  The 2.0.36 kernel in Debian 2.1, at
428                          * least, doesn't correctly implement name
429                          * sections, in core dumps, as specified by
430                          * the "Program Linking" section of "UNIX(R) System
431                          * V Release 4 Programmer's Guide: ANSI C and
432                          * Programming Support Tools", because my copy
433                          * clearly says "The first 'namesz' bytes in 'name'
434                          * contain a *null-terminated* [emphasis mine]
435                          * character representation of the entry's owner
436                          * or originator", but the 2.0.36 kernel code
437                          * doesn't include the terminating null in the
438                          * name....
439                          */
440                         if (os_style == -1) {
441                                 if ((nh_namesz == 4 &&
442                                      strncmp(&nbuf[nameoffset],
443                                             "CORE", 4) == 0) ||
444                                     (nh_namesz == 5 &&
445                                      strcmp(&nbuf[nameoffset],
446                                             "CORE") == 0)) {
447                                         os_style = OS_STYLE_SVR4;
448                                 } else
449                                 if ((nh_namesz == 8 &&
450                                      strcmp(&nbuf[nameoffset],
451                                             "FreeBSD") == 0)) {
452                                         os_style = OS_STYLE_FREEBSD;
453                                 } else
454                                 if ((nh_namesz >= 11 &&
455                                      strncmp(&nbuf[nameoffset],
456                                              "NetBSD-CORE", 11) == 0)) {
457                                         os_style = OS_STYLE_NETBSD;
458                                 } else
459                                         /*@innercontinue@*/ continue;
460                                 fmagicPrintf(fm, ", %s-style", os_style_names[os_style]);
461                         }
462
463                         if (os_style == OS_STYLE_NETBSD &&
464                             nh_type == NT_NETBSD_CORE_PROCINFO) {
465                                 uint32_t signo;
466
467                                 /*
468                                  * Extract the program name.  It is at
469                                  * offset 0x7c, and is up to 32-bytes,
470                                  * including the terminating NUL.
471                                  */
472                                 fmagicPrintf(fm, ", from '%.31s'", &nbuf[offset + 0x7c]);
473                                 
474                                 /*
475                                  * Extract the signal number.  It is at
476                                  * offset 0x08.
477                                  */
478                                 memcpy(&signo, &nbuf[offset + 0x08],
479                                     sizeof(signo));
480                                 fmagicPrintf(fm, " (signal %u)", getu32(fm, signo));
481                         } else
482                         if (os_style != OS_STYLE_NETBSD &&
483                             nh_type == NT_PRPSINFO) {
484                                 /*
485                                  * Extract the program name.  We assume
486                                  * it to be 16 characters (that's what it
487                                  * is in SunOS 5.x and Linux).
488                                  *
489                                  * Unfortunately, it's at a different offset
490                                  * in varous OSes, so try multiple offsets.
491                                  * If the characters aren't all printable,
492                                  * reject it.
493                                  */
494                                 for (i = 0; i < NOFFSETS; i++) {
495                                         reloffset = prpsoffsets(i);
496                                         noffset = offset + reloffset;
497                                         for (j = 0; j < 16;
498                                             j++, noffset++, reloffset++) {
499                                                 /*
500                                                  * Make sure we're not past
501                                                  * the end of the buffer; if
502                                                  * we are, just give up.
503                                                  */
504                                                 if (noffset >= bufsize)
505                                                         goto tryanother;
506
507                                                 /*
508                                                  * Make sure we're not past
509                                                  * the end of the contents;
510                                                  * if we are, this obviously
511                                                  * isn't the right offset.
512                                                  */
513                                                 if (reloffset >= nh_descsz)
514                                                         goto tryanother;
515
516                                                 c = nbuf[noffset];
517                                                 if (c == '\0') {
518                                                         /*
519                                                          * A '\0' at the
520                                                          * beginning is
521                                                          * obviously wrong.
522                                                          * Any other '\0'
523                                                          * means we're done.
524                                                          */
525                                                         if (j == 0)
526                                                                 goto tryanother;
527                                                         else
528                                                                 /*@innerbreak@*/ break;
529                                                 } else {
530                                                         /*
531                                                          * A nonprintable
532                                                          * character is also
533                                                          * wrong.
534                                                          */
535 #define isquote(c) (strchr("'\"`", (c)) != NULL)
536                                                         if (!isprint(c) ||
537                                                              isquote(c))
538                                                                 goto tryanother;
539                                                 }
540                                         }
541
542                                         /*
543                                          * Well, that worked.
544                                          */
545                                         fmagicPrintf(fm, ", from '%.16s'",
546                                             &nbuf[offset + prpsoffsets(i)]);
547                                         /*@innerbreak@*/ break;
548
549                                 tryanother:
550                                         ;
551                                 }
552                                 /*@innerbreak@*/ break;
553                         }
554                         offset += nh_descsz;
555                         offset = ((offset + 3)/4)*4;
556                 }
557         }
558 }
559 #endif
560
561 void
562 fmagicE(fmagic fm)
563 {
564         union {
565                 int32_t l;
566                 char c[sizeof (int32_t)];
567         } u;
568
569         /*
570          * If we can't seek, it must be a pipe, socket or fifo.
571          */
572         if((lseek(fm->fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
573                 fm->fd = pipe2file(fm->fd, fm->buf, fm->nb);
574
575         /*
576          * ELF executables have multiple section headers in arbitrary
577          * file locations and thus file(1) cannot determine it from easily.
578          * Instead we traverse thru all section headers until a symbol table
579          * one is found or else the binary is stripped.
580          */
581         if (fm->buf[EI_MAG0] != ELFMAG0
582             || (fm->buf[EI_MAG1] != ELFMAG1 && fm->buf[EI_MAG1] != OLFMAG1)
583             || fm->buf[EI_MAG2] != ELFMAG2 || fm->buf[EI_MAG3] != ELFMAG3)
584             return;
585
586
587         fm->cls = fm->buf[EI_CLASS];
588
589         if (fm->cls == ELFCLASS32) {
590                 Elf32_Ehdr elfhdr;
591                 if (fm->nb <= sizeof (Elf32_Ehdr))
592                         return;
593
594
595                 u.l = 1;
596                 (void) memcpy(&elfhdr, fm->buf, sizeof elfhdr);
597                 fm->swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
598
599                 if (getu16(fm, elfhdr.e_type) == ET_CORE) 
600 #ifdef ELFCORE
601                         dophn_core(fm,
602                                    getu32(fm, elfhdr.e_phoff),
603                                    getu16(fm, elfhdr.e_phnum), 
604                                    getu16(fm, elfhdr.e_phentsize));
605 #else
606                         ;
607 #endif
608                 else {
609                         if (getu16(fm, elfhdr.e_type) == ET_EXEC) {
610                                 dophn_exec(fm,
611                                            getu32(fm, elfhdr.e_phoff),
612                                            getu16(fm, elfhdr.e_phnum), 
613                                            getu16(fm, elfhdr.e_phentsize));
614                         }
615                         doshn(fm,
616                               getu32(fm, elfhdr.e_shoff),
617                               getu16(fm, elfhdr.e_shnum),
618                               getu16(fm, elfhdr.e_shentsize));
619                 }
620                 return;
621         }
622
623         if (fm->cls == ELFCLASS64) {
624                 Elf64_Ehdr elfhdr;
625                 if (fm->nb <= sizeof (Elf64_Ehdr))
626                         return;
627
628
629                 u.l = 1;
630                 (void) memcpy(&elfhdr, fm->buf, sizeof elfhdr);
631                 fm->swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
632
633                 if (getu16(fm, elfhdr.e_type) == ET_CORE) 
634 #ifdef ELFCORE
635                         dophn_core(fm,
636 #ifdef USE_ARRAY_FOR_64BIT_TYPES
637                                    getu32(fm, elfhdr.e_phoff[1]),
638 #else
639                                    getu64(fm, elfhdr.e_phoff),
640 #endif
641                                    getu16(fm, elfhdr.e_phnum), 
642                                    getu16(fm, elfhdr.e_phentsize));
643 #else
644                         ;
645 #endif
646                 else
647                 {
648                         if (getu16(fm, elfhdr.e_type) == ET_EXEC) {
649                                 dophn_exec(fm,
650 #ifdef USE_ARRAY_FOR_64BIT_TYPES
651                                            getu32(fm, elfhdr.e_phoff[1]),
652 #else
653                                            getu64(fm, elfhdr.e_phoff),
654 #endif
655                                            getu16(fm, elfhdr.e_phnum), 
656                                            getu16(fm, elfhdr.e_phentsize));
657                         }
658                         doshn(fm,
659 #ifdef USE_ARRAY_FOR_64BIT_TYPES
660                               getu32(fm, elfhdr.e_shoff[1]),
661 #else
662                               getu64(fm, elfhdr.e_shoff),
663 #endif
664                               getu16(fm, elfhdr.e_shnum),
665                               getu16(fm, elfhdr.e_shentsize));
666                 }
667                 return;
668         }
669 }
670 #endif  /* BUILTIN_ELF */