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