]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/file/src/readelf.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / 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  *  
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 #include "file.h"
28
29 #ifndef lint
30 FILE_RCSID("@(#)$File: readelf.c,v 1.119 2015/04/09 20:01:41 christos Exp $")
31 #endif
32
33 #ifdef BUILTIN_ELF
34 #include <string.h>
35 #include <ctype.h>
36 #include <stdlib.h>
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40
41 #include "readelf.h"
42 #include "magic.h"
43
44 #ifdef  ELFCORE
45 private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t,
46     off_t, int *, uint16_t *);
47 #endif
48 private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t,
49     off_t, int, int *, uint16_t *);
50 private int doshn(struct magic_set *, int, int, int, off_t, int, size_t,
51     off_t, int, int, int *, uint16_t *);
52 private size_t donote(struct magic_set *, void *, size_t, size_t, int,
53     int, size_t, int *, uint16_t *);
54
55 #define ELF_ALIGN(a)    ((((a) + align - 1) / align) * align)
56
57 #define isquote(c) (strchr("'\"`", (c)) != NULL)
58
59 private uint16_t getu16(int, uint16_t);
60 private uint32_t getu32(int, uint32_t);
61 private uint64_t getu64(int, uint64_t);
62
63 #define MAX_PHNUM       128
64 #define MAX_SHNUM       32768
65 #define SIZE_UNKNOWN    ((off_t)-1)
66
67 private int
68 toomany(struct magic_set *ms, const char *name, uint16_t num)
69 {
70         if (file_printf(ms, ", too many %s (%u)", name, num
71             ) == -1)
72                 return -1;
73         return 0;
74 }
75
76 private uint16_t
77 getu16(int swap, uint16_t value)
78 {
79         union {
80                 uint16_t ui;
81                 char c[2];
82         } retval, tmpval;
83
84         if (swap) {
85                 tmpval.ui = value;
86
87                 retval.c[0] = tmpval.c[1];
88                 retval.c[1] = tmpval.c[0];
89                 
90                 return retval.ui;
91         } else
92                 return value;
93 }
94
95 private uint32_t
96 getu32(int swap, uint32_t value)
97 {
98         union {
99                 uint32_t ui;
100                 char c[4];
101         } retval, tmpval;
102
103         if (swap) {
104                 tmpval.ui = value;
105
106                 retval.c[0] = tmpval.c[3];
107                 retval.c[1] = tmpval.c[2];
108                 retval.c[2] = tmpval.c[1];
109                 retval.c[3] = tmpval.c[0];
110                 
111                 return retval.ui;
112         } else
113                 return value;
114 }
115
116 private uint64_t
117 getu64(int swap, uint64_t value)
118 {
119         union {
120                 uint64_t ui;
121                 char c[8];
122         } retval, tmpval;
123
124         if (swap) {
125                 tmpval.ui = value;
126
127                 retval.c[0] = tmpval.c[7];
128                 retval.c[1] = tmpval.c[6];
129                 retval.c[2] = tmpval.c[5];
130                 retval.c[3] = tmpval.c[4];
131                 retval.c[4] = tmpval.c[3];
132                 retval.c[5] = tmpval.c[2];
133                 retval.c[6] = tmpval.c[1];
134                 retval.c[7] = tmpval.c[0];
135                 
136                 return retval.ui;
137         } else
138                 return value;
139 }
140
141 #define elf_getu16(swap, value) getu16(swap, value)
142 #define elf_getu32(swap, value) getu32(swap, value)
143 #define elf_getu64(swap, value) getu64(swap, value)
144
145 #define xsh_addr        (clazz == ELFCLASS32                    \
146                          ? (void *)&sh32                        \
147                          : (void *)&sh64)
148 #define xsh_sizeof      (clazz == ELFCLASS32                    \
149                          ? sizeof(sh32)                         \
150                          : sizeof(sh64))
151 #define xsh_size        (size_t)(clazz == ELFCLASS32            \
152                          ? elf_getu32(swap, sh32.sh_size)       \
153                          : elf_getu64(swap, sh64.sh_size))
154 #define xsh_offset      (off_t)(clazz == ELFCLASS32             \
155                          ? elf_getu32(swap, sh32.sh_offset)     \
156                          : elf_getu64(swap, sh64.sh_offset))
157 #define xsh_type        (clazz == ELFCLASS32                    \
158                          ? elf_getu32(swap, sh32.sh_type)       \
159                          : elf_getu32(swap, sh64.sh_type))
160 #define xsh_name        (clazz == ELFCLASS32                    \
161                          ? elf_getu32(swap, sh32.sh_name)       \
162                          : elf_getu32(swap, sh64.sh_name))
163 #define xph_addr        (clazz == ELFCLASS32                    \
164                          ? (void *) &ph32                       \
165                          : (void *) &ph64)
166 #define xph_sizeof      (clazz == ELFCLASS32                    \
167                          ? sizeof(ph32)                         \
168                          : sizeof(ph64))
169 #define xph_type        (clazz == ELFCLASS32                    \
170                          ? elf_getu32(swap, ph32.p_type)        \
171                          : elf_getu32(swap, ph64.p_type))
172 #define xph_offset      (off_t)(clazz == ELFCLASS32             \
173                          ? elf_getu32(swap, ph32.p_offset)      \
174                          : elf_getu64(swap, ph64.p_offset))
175 #define xph_align       (size_t)((clazz == ELFCLASS32           \
176                          ? (off_t) (ph32.p_align ?              \
177                             elf_getu32(swap, ph32.p_align) : 4) \
178                          : (off_t) (ph64.p_align ?              \
179                             elf_getu64(swap, ph64.p_align) : 4)))
180 #define xph_filesz      (size_t)((clazz == ELFCLASS32           \
181                          ? elf_getu32(swap, ph32.p_filesz)      \
182                          : elf_getu64(swap, ph64.p_filesz)))
183 #define xnh_addr        (clazz == ELFCLASS32                    \
184                          ? (void *)&nh32                        \
185                          : (void *)&nh64)
186 #define xph_memsz       (size_t)((clazz == ELFCLASS32           \
187                          ? elf_getu32(swap, ph32.p_memsz)       \
188                          : elf_getu64(swap, ph64.p_memsz)))
189 #define xnh_sizeof      (clazz == ELFCLASS32                    \
190                          ? sizeof nh32                          \
191                          : sizeof nh64)
192 #define xnh_type        (clazz == ELFCLASS32                    \
193                          ? elf_getu32(swap, nh32.n_type)        \
194                          : elf_getu32(swap, nh64.n_type))
195 #define xnh_namesz      (clazz == ELFCLASS32                    \
196                          ? elf_getu32(swap, nh32.n_namesz)      \
197                          : elf_getu32(swap, nh64.n_namesz))
198 #define xnh_descsz      (clazz == ELFCLASS32                    \
199                          ? elf_getu32(swap, nh32.n_descsz)      \
200                          : elf_getu32(swap, nh64.n_descsz))
201 #define prpsoffsets(i)  (clazz == ELFCLASS32                    \
202                          ? prpsoffsets32[i]                     \
203                          : prpsoffsets64[i])
204 #define xcap_addr       (clazz == ELFCLASS32                    \
205                          ? (void *)&cap32                       \
206                          : (void *)&cap64)
207 #define xcap_sizeof     (clazz == ELFCLASS32                    \
208                          ? sizeof cap32                         \
209                          : sizeof cap64)
210 #define xcap_tag        (clazz == ELFCLASS32                    \
211                          ? elf_getu32(swap, cap32.c_tag)        \
212                          : elf_getu64(swap, cap64.c_tag))
213 #define xcap_val        (clazz == ELFCLASS32                    \
214                          ? elf_getu32(swap, cap32.c_un.c_val)   \
215                          : elf_getu64(swap, cap64.c_un.c_val))
216
217 #ifdef ELFCORE
218 /*
219  * Try larger offsets first to avoid false matches
220  * from earlier data that happen to look like strings.
221  */
222 static const size_t     prpsoffsets32[] = {
223 #ifdef USE_NT_PSINFO
224         104,            /* SunOS 5.x (command line) */
225         88,             /* SunOS 5.x (short name) */
226 #endif /* USE_NT_PSINFO */
227
228         100,            /* SunOS 5.x (command line) */
229         84,             /* SunOS 5.x (short name) */
230
231         44,             /* Linux (command line) */
232         28,             /* Linux 2.0.36 (short name) */
233
234         8,              /* FreeBSD */
235 };
236
237 static const size_t     prpsoffsets64[] = {
238 #ifdef USE_NT_PSINFO
239         152,            /* SunOS 5.x (command line) */
240         136,            /* SunOS 5.x (short name) */
241 #endif /* USE_NT_PSINFO */
242
243         136,            /* SunOS 5.x, 64-bit (command line) */
244         120,            /* SunOS 5.x, 64-bit (short name) */
245
246         56,             /* Linux (command line) */
247         40,             /* Linux (tested on core from 2.4.x, short name) */
248
249         16,             /* FreeBSD, 64-bit */
250 };
251
252 #define NOFFSETS32      (sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
253 #define NOFFSETS64      (sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
254
255 #define NOFFSETS        (clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
256
257 /*
258  * Look through the program headers of an executable image, searching
259  * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
260  * "FreeBSD"; if one is found, try looking in various places in its
261  * contents for a 16-character string containing only printable
262  * characters - if found, that string should be the name of the program
263  * that dropped core.  Note: right after that 16-character string is,
264  * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
265  * Linux, a longer string (80 characters, in 5.x, probably other
266  * SVR4-flavored systems, and Linux) containing the start of the
267  * command line for that program.
268  *
269  * SunOS 5.x core files contain two PT_NOTE sections, with the types
270  * NT_PRPSINFO (old) and NT_PSINFO (new).  These structs contain the
271  * same info about the command name and command line, so it probably
272  * isn't worthwhile to look for NT_PSINFO, but the offsets are provided
273  * above (see USE_NT_PSINFO), in case we ever decide to do so.  The
274  * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent;
275  * the SunOS 5.x file command relies on this (and prefers the latter).
276  *
277  * The signal number probably appears in a section of type NT_PRSTATUS,
278  * but that's also rather OS-dependent, in ways that are harder to
279  * dissect with heuristics, so I'm not bothering with the signal number.
280  * (I suppose the signal number could be of interest in situations where
281  * you don't have the binary of the program that dropped core; if you
282  * *do* have that binary, the debugger will probably tell you what
283  * signal it was.)
284  */
285
286 #define OS_STYLE_SVR4           0
287 #define OS_STYLE_FREEBSD        1
288 #define OS_STYLE_NETBSD         2
289
290 private const char os_style_names[][8] = {
291         "SVR4",
292         "FreeBSD",
293         "NetBSD",
294 };
295
296 #define FLAGS_DID_CORE                  0x001
297 #define FLAGS_DID_OS_NOTE               0x002
298 #define FLAGS_DID_BUILD_ID              0x004
299 #define FLAGS_DID_CORE_STYLE            0x008
300 #define FLAGS_DID_NETBSD_PAX            0x010
301 #define FLAGS_DID_NETBSD_MARCH          0x020
302 #define FLAGS_DID_NETBSD_CMODEL         0x040
303 #define FLAGS_DID_NETBSD_UNKNOWN        0x080
304 #define FLAGS_IS_CORE                   0x100
305
306 private int
307 dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
308     int num, size_t size, off_t fsize, int *flags, uint16_t *notecount)
309 {
310         Elf32_Phdr ph32;
311         Elf64_Phdr ph64;
312         size_t offset, len;
313         unsigned char nbuf[BUFSIZ];
314         ssize_t bufsize;
315
316         if (size != xph_sizeof) {
317                 if (file_printf(ms, ", corrupted program header size") == -1)
318                         return -1;
319                 return 0;
320         }
321
322         /*
323          * Loop through all the program headers.
324          */
325         for ( ; num; num--) {
326                 if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
327                         file_badread(ms);
328                         return -1;
329                 }
330                 off += size;
331
332                 if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
333                         /* Perhaps warn here */
334                         continue;
335                 }
336
337                 if (xph_type != PT_NOTE)
338                         continue;
339
340                 /*
341                  * This is a PT_NOTE section; loop through all the notes
342                  * in the section.
343                  */
344                 len = xph_filesz < sizeof(nbuf) ? xph_filesz : sizeof(nbuf);
345                 if ((bufsize = pread(fd, nbuf, len, xph_offset)) == -1) {
346                         file_badread(ms);
347                         return -1;
348                 }
349                 offset = 0;
350                 for (;;) {
351                         if (offset >= (size_t)bufsize)
352                                 break;
353                         offset = donote(ms, nbuf, offset, (size_t)bufsize,
354                             clazz, swap, 4, flags, notecount);
355                         if (offset == 0)
356                                 break;
357
358                 }
359         }
360         return 0;
361 }
362 #endif
363
364 static void
365 do_note_netbsd_version(struct magic_set *ms, int swap, void *v)
366 {
367         uint32_t desc;
368         (void)memcpy(&desc, v, sizeof(desc));
369         desc = elf_getu32(swap, desc);
370
371         if (file_printf(ms, ", for NetBSD") == -1)
372                 return;
373         /*
374          * The version number used to be stuck as 199905, and was thus
375          * basically content-free.  Newer versions of NetBSD have fixed
376          * this and now use the encoding of __NetBSD_Version__:
377          *
378          *      MMmmrrpp00
379          *
380          * M = major version
381          * m = minor version
382          * r = release ["",A-Z,Z[A-Z] but numeric]
383          * p = patchlevel
384          */
385         if (desc > 100000000U) {
386                 uint32_t ver_patch = (desc / 100) % 100;
387                 uint32_t ver_rel = (desc / 10000) % 100;
388                 uint32_t ver_min = (desc / 1000000) % 100;
389                 uint32_t ver_maj = desc / 100000000;
390
391                 if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1)
392                         return;
393                 if (ver_rel == 0 && ver_patch != 0) {
394                         if (file_printf(ms, ".%u", ver_patch) == -1)
395                                 return;
396                 } else if (ver_rel != 0) {
397                         while (ver_rel > 26) {
398                                 if (file_printf(ms, "Z") == -1)
399                                         return;
400                                 ver_rel -= 26;
401                         }
402                         if (file_printf(ms, "%c", 'A' + ver_rel - 1)
403                             == -1)
404                                 return;
405                 }
406         }
407 }
408
409 static void
410 do_note_freebsd_version(struct magic_set *ms, int swap, void *v)
411 {
412         uint32_t desc;
413
414         (void)memcpy(&desc, v, sizeof(desc));
415         desc = elf_getu32(swap, desc);
416         if (file_printf(ms, ", for FreeBSD") == -1)
417                 return;
418
419         /*
420          * Contents is __FreeBSD_version, whose relation to OS
421          * versions is defined by a huge table in the Porter's
422          * Handbook.  This is the general scheme:
423          * 
424          * Releases:
425          *      Mmp000 (before 4.10)
426          *      Mmi0p0 (before 5.0)
427          *      Mmm0p0
428          * 
429          * Development branches:
430          *      Mmpxxx (before 4.6)
431          *      Mmp1xx (before 4.10)
432          *      Mmi1xx (before 5.0)
433          *      M000xx (pre-M.0)
434          *      Mmm1xx
435          * 
436          * M = major version
437          * m = minor version
438          * i = minor version increment (491000 -> 4.10)
439          * p = patchlevel
440          * x = revision
441          * 
442          * The first release of FreeBSD to use ELF by default
443          * was version 3.0.
444          */
445         if (desc == 460002) {
446                 if (file_printf(ms, " 4.6.2") == -1)
447                         return;
448         } else if (desc < 460100) {
449                 if (file_printf(ms, " %d.%d", desc / 100000,
450                     desc / 10000 % 10) == -1)
451                         return;
452                 if (desc / 1000 % 10 > 0)
453                         if (file_printf(ms, ".%d", desc / 1000 % 10) == -1)
454                                 return;
455                 if ((desc % 1000 > 0) || (desc % 100000 == 0))
456                         if (file_printf(ms, " (%d)", desc) == -1)
457                                 return;
458         } else if (desc < 500000) {
459                 if (file_printf(ms, " %d.%d", desc / 100000,
460                     desc / 10000 % 10 + desc / 1000 % 10) == -1)
461                         return;
462                 if (desc / 100 % 10 > 0) {
463                         if (file_printf(ms, " (%d)", desc) == -1)
464                                 return;
465                 } else if (desc / 10 % 10 > 0) {
466                         if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
467                                 return;
468                 }
469         } else {
470                 if (file_printf(ms, " %d.%d", desc / 100000,
471                     desc / 1000 % 100) == -1)
472                         return;
473                 if ((desc / 100 % 10 > 0) ||
474                     (desc % 100000 / 100 == 0)) {
475                         if (file_printf(ms, " (%d)", desc) == -1)
476                                 return;
477                 } else if (desc / 10 % 10 > 0) {
478                         if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
479                                 return;
480                 }
481         }
482 }
483
484 private int
485 /*ARGSUSED*/
486 do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
487     int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz,
488     size_t noff, size_t doff, int *flags)
489 {
490         if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
491             type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) {
492                 uint8_t desc[20];
493                 uint32_t i;
494                 *flags |= FLAGS_DID_BUILD_ID;
495                 if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" :
496                     "sha1") == -1)
497                         return 1;
498                 (void)memcpy(desc, &nbuf[doff], descsz);
499                 for (i = 0; i < descsz; i++)
500                     if (file_printf(ms, "%02x", desc[i]) == -1)
501                         return 1;
502                 return 1;
503         }
504         return 0;
505 }
506
507 private int
508 do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
509     int swap, uint32_t namesz, uint32_t descsz,
510     size_t noff, size_t doff, int *flags)
511 {
512         if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 &&
513             type == NT_GNU_VERSION && descsz == 2) {
514             *flags |= FLAGS_DID_OS_NOTE;
515             file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]);
516             return 1;
517         }
518
519         if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
520             type == NT_GNU_VERSION && descsz == 16) {
521                 uint32_t desc[4];
522                 (void)memcpy(desc, &nbuf[doff], sizeof(desc));
523
524                 *flags |= FLAGS_DID_OS_NOTE;
525                 if (file_printf(ms, ", for GNU/") == -1)
526                         return 1;
527                 switch (elf_getu32(swap, desc[0])) {
528                 case GNU_OS_LINUX:
529                         if (file_printf(ms, "Linux") == -1)
530                                 return 1;
531                         break;
532                 case GNU_OS_HURD:
533                         if (file_printf(ms, "Hurd") == -1)
534                                 return 1;
535                         break;
536                 case GNU_OS_SOLARIS:
537                         if (file_printf(ms, "Solaris") == -1)
538                                 return 1;
539                         break;
540                 case GNU_OS_KFREEBSD:
541                         if (file_printf(ms, "kFreeBSD") == -1)
542                                 return 1;
543                         break;
544                 case GNU_OS_KNETBSD:
545                         if (file_printf(ms, "kNetBSD") == -1)
546                                 return 1;
547                         break;
548                 default:
549                         if (file_printf(ms, "<unknown>") == -1)
550                                 return 1; 
551                 }
552                 if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
553                     elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1)
554                         return 1;
555                 return 1;
556         }
557
558         if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
559                 if (type == NT_NETBSD_VERSION && descsz == 4) {
560                         *flags |= FLAGS_DID_OS_NOTE;
561                         do_note_netbsd_version(ms, swap, &nbuf[doff]);
562                         return 1;
563                 }
564         }
565
566         if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
567                 if (type == NT_FREEBSD_VERSION && descsz == 4) {
568                         *flags |= FLAGS_DID_OS_NOTE;
569                         do_note_freebsd_version(ms, swap, &nbuf[doff]);
570                         return 1;
571                 }
572         }
573
574         if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
575             type == NT_OPENBSD_VERSION && descsz == 4) {
576                 *flags |= FLAGS_DID_OS_NOTE;
577                 if (file_printf(ms, ", for OpenBSD") == -1)
578                         return 1;
579                 /* Content of note is always 0 */
580                 return 1;
581         }
582
583         if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
584             type == NT_DRAGONFLY_VERSION && descsz == 4) {
585                 uint32_t desc;
586                 *flags |= FLAGS_DID_OS_NOTE;
587                 if (file_printf(ms, ", for DragonFly") == -1)
588                         return 1;
589                 (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
590                 desc = elf_getu32(swap, desc);
591                 if (file_printf(ms, " %d.%d.%d", desc / 100000,
592                     desc / 10000 % 10, desc % 10000) == -1)
593                         return 1;
594                 return 1;
595         }
596         return 0;
597 }
598
599 private int
600 do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
601     int swap, uint32_t namesz, uint32_t descsz,
602     size_t noff, size_t doff, int *flags)
603 {
604         if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 &&
605             type == NT_NETBSD_PAX && descsz == 4) {
606                 static const char *pax[] = {
607                     "+mprotect",
608                     "-mprotect",
609                     "+segvguard",
610                     "-segvguard",
611                     "+ASLR",
612                     "-ASLR",
613                 };
614                 uint32_t desc;
615                 size_t i;
616                 int did = 0;
617
618                 *flags |= FLAGS_DID_NETBSD_PAX;
619                 (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
620                 desc = elf_getu32(swap, desc);
621
622                 if (desc && file_printf(ms, ", PaX: ") == -1)
623                         return 1;
624
625                 for (i = 0; i < __arraycount(pax); i++) {
626                         if (((1 << (int)i) & desc) == 0)
627                                 continue;
628                         if (file_printf(ms, "%s%s", did++ ? "," : "",
629                             pax[i]) == -1)
630                                 return 1;
631                 }
632                 return 1;
633         }
634         return 0;
635 }
636
637 private int
638 do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
639     int swap, uint32_t namesz, uint32_t descsz,
640     size_t noff, size_t doff, int *flags, size_t size, int clazz)
641 {
642 #ifdef ELFCORE
643         int os_style = -1;
644         /*
645          * Sigh.  The 2.0.36 kernel in Debian 2.1, at
646          * least, doesn't correctly implement name
647          * sections, in core dumps, as specified by
648          * the "Program Linking" section of "UNIX(R) System
649          * V Release 4 Programmer's Guide: ANSI C and
650          * Programming Support Tools", because my copy
651          * clearly says "The first 'namesz' bytes in 'name'
652          * contain a *null-terminated* [emphasis mine]
653          * character representation of the entry's owner
654          * or originator", but the 2.0.36 kernel code
655          * doesn't include the terminating null in the
656          * name....
657          */
658         if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) ||
659             (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) {
660                 os_style = OS_STYLE_SVR4;
661         } 
662
663         if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) {
664                 os_style = OS_STYLE_FREEBSD;
665         }
666
667         if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11)
668             == 0)) {
669                 os_style = OS_STYLE_NETBSD;
670         }
671
672         if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
673                 if (file_printf(ms, ", %s-style", os_style_names[os_style])
674                     == -1)
675                         return 1;
676                 *flags |= FLAGS_DID_CORE_STYLE;
677         }
678
679         switch (os_style) {
680         case OS_STYLE_NETBSD:
681                 if (type == NT_NETBSD_CORE_PROCINFO) {
682                         char sbuf[512];
683                         uint32_t signo;
684                         /*
685                          * Extract the program name.  It is at
686                          * offset 0x7c, and is up to 32-bytes,
687                          * including the terminating NUL.
688                          */
689                         if (file_printf(ms, ", from '%.31s'",
690                             file_printable(sbuf, sizeof(sbuf),
691                             (const char *)&nbuf[doff + 0x7c])) == -1)
692                                 return 1;
693                         
694                         /*
695                          * Extract the signal number.  It is at
696                          * offset 0x08.
697                          */
698                         (void)memcpy(&signo, &nbuf[doff + 0x08],
699                             sizeof(signo));
700                         if (file_printf(ms, " (signal %u)",
701                             elf_getu32(swap, signo)) == -1)
702                                 return 1;
703                         *flags |= FLAGS_DID_CORE;
704                         return 1;
705                 }
706                 break;
707
708         default:
709                 if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
710                         size_t i, j;
711                         unsigned char c;
712                         /*
713                          * Extract the program name.  We assume
714                          * it to be 16 characters (that's what it
715                          * is in SunOS 5.x and Linux).
716                          *
717                          * Unfortunately, it's at a different offset
718                          * in various OSes, so try multiple offsets.
719                          * If the characters aren't all printable,
720                          * reject it.
721                          */
722                         for (i = 0; i < NOFFSETS; i++) {
723                                 unsigned char *cname, *cp;
724                                 size_t reloffset = prpsoffsets(i);
725                                 size_t noffset = doff + reloffset;
726                                 size_t k;
727                                 for (j = 0; j < 16; j++, noffset++,
728                                     reloffset++) {
729                                         /*
730                                          * Make sure we're not past
731                                          * the end of the buffer; if
732                                          * we are, just give up.
733                                          */
734                                         if (noffset >= size)
735                                                 goto tryanother;
736
737                                         /*
738                                          * Make sure we're not past
739                                          * the end of the contents;
740                                          * if we are, this obviously
741                                          * isn't the right offset.
742                                          */
743                                         if (reloffset >= descsz)
744                                                 goto tryanother;
745
746                                         c = nbuf[noffset];
747                                         if (c == '\0') {
748                                                 /*
749                                                  * A '\0' at the
750                                                  * beginning is
751                                                  * obviously wrong.
752                                                  * Any other '\0'
753                                                  * means we're done.
754                                                  */
755                                                 if (j == 0)
756                                                         goto tryanother;
757                                                 else
758                                                         break;
759                                         } else {
760                                                 /*
761                                                  * A nonprintable
762                                                  * character is also
763                                                  * wrong.
764                                                  */
765                                                 if (!isprint(c) || isquote(c))
766                                                         goto tryanother;
767                                         }
768                                 }
769                                 /*
770                                  * Well, that worked.
771                                  */
772
773                                 /*
774                                  * Try next offsets, in case this match is
775                                  * in the middle of a string.
776                                  */
777                                 for (k = i + 1 ; k < NOFFSETS; k++) {
778                                         size_t no;
779                                         int adjust = 1;
780                                         if (prpsoffsets(k) >= prpsoffsets(i))
781                                                 continue;
782                                         for (no = doff + prpsoffsets(k);
783                                              no < doff + prpsoffsets(i); no++)
784                                                 adjust = adjust
785                                                          && isprint(nbuf[no]);
786                                         if (adjust)
787                                                 i = k;
788                                 }
789
790                                 cname = (unsigned char *)
791                                     &nbuf[doff + prpsoffsets(i)];
792                                 for (cp = cname; *cp && isprint(*cp); cp++)
793                                         continue;
794                                 /*
795                                  * Linux apparently appends a space at the end
796                                  * of the command line: remove it.
797                                  */
798                                 while (cp > cname && isspace(cp[-1]))
799                                         cp--;
800                                 if (file_printf(ms, ", from '%.*s'",
801                                     (int)(cp - cname), cname) == -1)
802                                         return 1;
803                                 *flags |= FLAGS_DID_CORE;
804                                 return 1;
805
806                         tryanother:
807                                 ;
808                         }
809                 }
810                 break;
811         }
812 #endif
813         return 0;
814 }
815
816 private size_t
817 donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
818     int clazz, int swap, size_t align, int *flags, uint16_t *notecount)
819 {
820         Elf32_Nhdr nh32;
821         Elf64_Nhdr nh64;
822         size_t noff, doff;
823         uint32_t namesz, descsz;
824         unsigned char *nbuf = CAST(unsigned char *, vbuf);
825
826         if (*notecount == 0)
827                 return 0;
828         --*notecount;
829
830         if (xnh_sizeof + offset > size) {
831                 /*
832                  * We're out of note headers.
833                  */
834                 return xnh_sizeof + offset;
835         }
836
837         (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
838         offset += xnh_sizeof;
839
840         namesz = xnh_namesz;
841         descsz = xnh_descsz;
842         if ((namesz == 0) && (descsz == 0)) {
843                 /*
844                  * We're out of note headers.
845                  */
846                 return (offset >= size) ? offset : size;
847         }
848
849         if (namesz & 0x80000000) {
850             (void)file_printf(ms, ", bad note name size 0x%lx",
851                 (unsigned long)namesz);
852             return 0;
853         }
854
855         if (descsz & 0x80000000) {
856             (void)file_printf(ms, ", bad note description size 0x%lx",
857                 (unsigned long)descsz);
858             return 0;
859         }
860
861         noff = offset;
862         doff = ELF_ALIGN(offset + namesz);
863
864         if (offset + namesz > size) {
865                 /*
866                  * We're past the end of the buffer.
867                  */
868                 return doff;
869         }
870
871         offset = ELF_ALIGN(doff + descsz);
872         if (doff + descsz > size) {
873                 /*
874                  * We're past the end of the buffer.
875                  */
876                 return (offset >= size) ? offset : size;
877         }
878
879         if ((*flags & FLAGS_DID_OS_NOTE) == 0) {
880                 if (do_os_note(ms, nbuf, xnh_type, swap,
881                     namesz, descsz, noff, doff, flags))
882                         return size;
883         }
884
885         if ((*flags & FLAGS_DID_BUILD_ID) == 0) {
886                 if (do_bid_note(ms, nbuf, xnh_type, swap,
887                     namesz, descsz, noff, doff, flags))
888                         return size;
889         }
890                 
891         if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) {
892                 if (do_pax_note(ms, nbuf, xnh_type, swap,
893                     namesz, descsz, noff, doff, flags))
894                         return size;
895         }
896
897         if ((*flags & FLAGS_DID_CORE) == 0) {
898                 if (do_core_note(ms, nbuf, xnh_type, swap,
899                     namesz, descsz, noff, doff, flags, size, clazz))
900                         return size;
901         }
902
903         if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
904                 if (descsz > 100)
905                         descsz = 100;
906                 switch (xnh_type) {
907                 case NT_NETBSD_VERSION:
908                         return size;
909                 case NT_NETBSD_MARCH:
910                         if (*flags & FLAGS_DID_NETBSD_MARCH)
911                                 return size;
912                         *flags |= FLAGS_DID_NETBSD_MARCH;
913                         if (file_printf(ms, ", compiled for: %.*s",
914                             (int)descsz, (const char *)&nbuf[doff]) == -1)
915                                 return size;
916                         break;
917                 case NT_NETBSD_CMODEL:
918                         if (*flags & FLAGS_DID_NETBSD_CMODEL)
919                                 return size;
920                         *flags |= FLAGS_DID_NETBSD_CMODEL;
921                         if (file_printf(ms, ", compiler model: %.*s",
922                             (int)descsz, (const char *)&nbuf[doff]) == -1)
923                                 return size;
924                         break;
925                 default:
926                         if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
927                                 return size;
928                         *flags |= FLAGS_DID_NETBSD_UNKNOWN;
929                         if (file_printf(ms, ", note=%u", xnh_type) == -1)
930                                 return size;
931                         break;
932                 }
933                 return size;
934         }
935
936         return offset;
937 }
938
939 /* SunOS 5.x hardware capability descriptions */
940 typedef struct cap_desc {
941         uint64_t cd_mask;
942         const char *cd_name;
943 } cap_desc_t;
944
945 static const cap_desc_t cap_desc_sparc[] = {
946         { AV_SPARC_MUL32,               "MUL32" },
947         { AV_SPARC_DIV32,               "DIV32" },
948         { AV_SPARC_FSMULD,              "FSMULD" },
949         { AV_SPARC_V8PLUS,              "V8PLUS" },
950         { AV_SPARC_POPC,                "POPC" },
951         { AV_SPARC_VIS,                 "VIS" },
952         { AV_SPARC_VIS2,                "VIS2" },
953         { AV_SPARC_ASI_BLK_INIT,        "ASI_BLK_INIT" },
954         { AV_SPARC_FMAF,                "FMAF" },
955         { AV_SPARC_FJFMAU,              "FJFMAU" },
956         { AV_SPARC_IMA,                 "IMA" },
957         { 0, NULL }
958 };
959
960 static const cap_desc_t cap_desc_386[] = {
961         { AV_386_FPU,                   "FPU" },
962         { AV_386_TSC,                   "TSC" },
963         { AV_386_CX8,                   "CX8" },
964         { AV_386_SEP,                   "SEP" },
965         { AV_386_AMD_SYSC,              "AMD_SYSC" },
966         { AV_386_CMOV,                  "CMOV" },
967         { AV_386_MMX,                   "MMX" },
968         { AV_386_AMD_MMX,               "AMD_MMX" },
969         { AV_386_AMD_3DNow,             "AMD_3DNow" },
970         { AV_386_AMD_3DNowx,            "AMD_3DNowx" },
971         { AV_386_FXSR,                  "FXSR" },
972         { AV_386_SSE,                   "SSE" },
973         { AV_386_SSE2,                  "SSE2" },
974         { AV_386_PAUSE,                 "PAUSE" },
975         { AV_386_SSE3,                  "SSE3" },
976         { AV_386_MON,                   "MON" },
977         { AV_386_CX16,                  "CX16" },
978         { AV_386_AHF,                   "AHF" },
979         { AV_386_TSCP,                  "TSCP" },
980         { AV_386_AMD_SSE4A,             "AMD_SSE4A" },
981         { AV_386_POPCNT,                "POPCNT" },
982         { AV_386_AMD_LZCNT,             "AMD_LZCNT" },
983         { AV_386_SSSE3,                 "SSSE3" },
984         { AV_386_SSE4_1,                "SSE4.1" },
985         { AV_386_SSE4_2,                "SSE4.2" },
986         { 0, NULL }
987 };
988
989 private int
990 doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
991     size_t size, off_t fsize, int mach, int strtab, int *flags,
992     uint16_t *notecount)
993 {
994         Elf32_Shdr sh32;
995         Elf64_Shdr sh64;
996         int stripped = 1;
997         size_t nbadcap = 0;
998         void *nbuf;
999         off_t noff, coff, name_off;
1000         uint64_t cap_hw1 = 0;   /* SunOS 5.x hardware capabilites */
1001         uint64_t cap_sf1 = 0;   /* SunOS 5.x software capabilites */
1002         char name[50];
1003         ssize_t namesize;
1004
1005         if (size != xsh_sizeof) {
1006                 if (file_printf(ms, ", corrupted section header size") == -1)
1007                         return -1;
1008                 return 0;
1009         }
1010
1011         /* Read offset of name section to be able to read section names later */
1012         if (pread(fd, xsh_addr, xsh_sizeof, CAST(off_t, (off + size * strtab)))
1013             < (ssize_t)xsh_sizeof) {
1014                 file_badread(ms);
1015                 return -1;
1016         }
1017         name_off = xsh_offset;
1018
1019         for ( ; num; num--) {
1020                 /* Read the name of this section. */
1021                 if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) {
1022                         file_badread(ms);
1023                         return -1;
1024                 }
1025                 name[namesize] = '\0';
1026                 if (strcmp(name, ".debug_info") == 0)
1027                         stripped = 0;
1028
1029                 if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) {
1030                         file_badread(ms);
1031                         return -1;
1032                 }
1033                 off += size;
1034
1035                 /* Things we can determine before we seek */
1036                 switch (xsh_type) {
1037                 case SHT_SYMTAB:
1038 #if 0
1039                 case SHT_DYNSYM:
1040 #endif
1041                         stripped = 0;
1042                         break;
1043                 default:
1044                         if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) {
1045                                 /* Perhaps warn here */
1046                                 continue;
1047                         }
1048                         break;
1049                 }
1050
1051                 /* Things we can determine when we seek */
1052                 switch (xsh_type) {
1053                 case SHT_NOTE:
1054                         if ((nbuf = malloc(xsh_size)) == NULL) {
1055                                 file_error(ms, errno, "Cannot allocate memory"
1056                                     " for note");
1057                                 return -1;
1058                         }
1059                         if (pread(fd, nbuf, xsh_size, xsh_offset) < (ssize_t)xsh_size) {
1060                                 file_badread(ms);
1061                                 free(nbuf);
1062                                 return -1;
1063                         }
1064
1065                         noff = 0;
1066                         for (;;) {
1067                                 if (noff >= (off_t)xsh_size)
1068                                         break;
1069                                 noff = donote(ms, nbuf, (size_t)noff,
1070                                     xsh_size, clazz, swap, 4, flags, notecount);
1071                                 if (noff == 0)
1072                                         break;
1073                         }
1074                         free(nbuf);
1075                         break;
1076                 case SHT_SUNW_cap:
1077                         switch (mach) {
1078                         case EM_SPARC:
1079                         case EM_SPARCV9:
1080                         case EM_IA_64:
1081                         case EM_386:
1082                         case EM_AMD64:
1083                                 break;
1084                         default:
1085                                 goto skip;
1086                         }
1087
1088                         if (nbadcap > 5)
1089                                 break;
1090                         if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) {
1091                                 file_badseek(ms);
1092                                 return -1;
1093                         }
1094                         coff = 0;
1095                         for (;;) {
1096                                 Elf32_Cap cap32;
1097                                 Elf64_Cap cap64;
1098                                 char cbuf[/*CONSTCOND*/
1099                                     MAX(sizeof cap32, sizeof cap64)];
1100                                 if ((coff += xcap_sizeof) > (off_t)xsh_size)
1101                                         break;
1102                                 if (read(fd, cbuf, (size_t)xcap_sizeof) !=
1103                                     (ssize_t)xcap_sizeof) {
1104                                         file_badread(ms);
1105                                         return -1;
1106                                 }
1107                                 if (cbuf[0] == 'A') {
1108 #ifdef notyet
1109                                         char *p = cbuf + 1;
1110                                         uint32_t len, tag;
1111                                         memcpy(&len, p, sizeof(len));
1112                                         p += 4;
1113                                         len = getu32(swap, len);
1114                                         if (memcmp("gnu", p, 3) != 0) {
1115                                             if (file_printf(ms,
1116                                                 ", unknown capability %.3s", p)
1117                                                 == -1)
1118                                                 return -1;
1119                                             break;
1120                                         }
1121                                         p += strlen(p) + 1;
1122                                         tag = *p++;
1123                                         memcpy(&len, p, sizeof(len));
1124                                         p += 4;
1125                                         len = getu32(swap, len);
1126                                         if (tag != 1) {
1127                                             if (file_printf(ms, ", unknown gnu"
1128                                                 " capability tag %d", tag)
1129                                                 == -1)
1130                                                 return -1;
1131                                             break;
1132                                         }
1133                                         // gnu attributes 
1134 #endif
1135                                         break;
1136                                 }
1137                                 (void)memcpy(xcap_addr, cbuf, xcap_sizeof);
1138                                 switch (xcap_tag) {
1139                                 case CA_SUNW_NULL:
1140                                         break;
1141                                 case CA_SUNW_HW_1:
1142                                         cap_hw1 |= xcap_val;
1143                                         break;
1144                                 case CA_SUNW_SF_1:
1145                                         cap_sf1 |= xcap_val;
1146                                         break;
1147                                 default:
1148                                         if (file_printf(ms,
1149                                             ", with unknown capability "
1150                                             "0x%" INT64_T_FORMAT "x = 0x%"
1151                                             INT64_T_FORMAT "x",
1152                                             (unsigned long long)xcap_tag,
1153                                             (unsigned long long)xcap_val) == -1)
1154                                                 return -1;
1155                                         if (nbadcap++ > 2)
1156                                                 coff = xsh_size;
1157                                         break;
1158                                 }
1159                         }
1160                         /*FALLTHROUGH*/
1161                 skip:
1162                 default:
1163                         break;
1164                 }
1165         }
1166
1167         if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
1168                 return -1;
1169         if (cap_hw1) {
1170                 const cap_desc_t *cdp;
1171                 switch (mach) {
1172                 case EM_SPARC:
1173                 case EM_SPARC32PLUS:
1174                 case EM_SPARCV9:
1175                         cdp = cap_desc_sparc;
1176                         break;
1177                 case EM_386:
1178                 case EM_IA_64:
1179                 case EM_AMD64:
1180                         cdp = cap_desc_386;
1181                         break;
1182                 default:
1183                         cdp = NULL;
1184                         break;
1185                 }
1186                 if (file_printf(ms, ", uses") == -1)
1187                         return -1;
1188                 if (cdp) {
1189                         while (cdp->cd_name) {
1190                                 if (cap_hw1 & cdp->cd_mask) {
1191                                         if (file_printf(ms,
1192                                             " %s", cdp->cd_name) == -1)
1193                                                 return -1;
1194                                         cap_hw1 &= ~cdp->cd_mask;
1195                                 }
1196                                 ++cdp;
1197                         }
1198                         if (cap_hw1)
1199                                 if (file_printf(ms,
1200                                     " unknown hardware capability 0x%"
1201                                     INT64_T_FORMAT "x",
1202                                     (unsigned long long)cap_hw1) == -1)
1203                                         return -1;
1204                 } else {
1205                         if (file_printf(ms,
1206                             " hardware capability 0x%" INT64_T_FORMAT "x",
1207                             (unsigned long long)cap_hw1) == -1)
1208                                 return -1;
1209                 }
1210         }
1211         if (cap_sf1) {
1212                 if (cap_sf1 & SF1_SUNW_FPUSED) {
1213                         if (file_printf(ms,
1214                             (cap_sf1 & SF1_SUNW_FPKNWN)
1215                             ? ", uses frame pointer"
1216                             : ", not known to use frame pointer") == -1)
1217                                 return -1;
1218                 }
1219                 cap_sf1 &= ~SF1_SUNW_MASK;
1220                 if (cap_sf1)
1221                         if (file_printf(ms,
1222                             ", with unknown software capability 0x%"
1223                             INT64_T_FORMAT "x",
1224                             (unsigned long long)cap_sf1) == -1)
1225                                 return -1;
1226         }
1227         return 0;
1228 }
1229
1230 /*
1231  * Look through the program headers of an executable image, searching
1232  * for a PT_INTERP section; if one is found, it's dynamically linked,
1233  * otherwise it's statically linked.
1234  */
1235 private int
1236 dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
1237     int num, size_t size, off_t fsize, int sh_num, int *flags,
1238     uint16_t *notecount)
1239 {
1240         Elf32_Phdr ph32;
1241         Elf64_Phdr ph64;
1242         const char *linking_style = "statically";
1243         const char *interp = "";
1244         unsigned char nbuf[BUFSIZ];
1245         char ibuf[BUFSIZ];
1246         ssize_t bufsize;
1247         size_t offset, align, len;
1248         
1249         if (size != xph_sizeof) {
1250                 if (file_printf(ms, ", corrupted program header size") == -1)
1251                         return -1;
1252                 return 0;
1253         }
1254
1255         for ( ; num; num--) {
1256                 if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
1257                         file_badread(ms);
1258                         return -1;
1259                 }
1260
1261                 off += size;
1262                 bufsize = 0;
1263                 align = 4;
1264
1265                 /* Things we can determine before we seek */
1266                 switch (xph_type) {
1267                 case PT_DYNAMIC:
1268                         linking_style = "dynamically";
1269                         break;
1270                 case PT_NOTE:
1271                         if (sh_num)     /* Did this through section headers */
1272                                 continue;
1273                         if (((align = xph_align) & 0x80000000UL) != 0 ||
1274                             align < 4) {
1275                                 if (file_printf(ms, 
1276                                     ", invalid note alignment 0x%lx",
1277                                     (unsigned long)align) == -1)
1278                                         return -1;
1279                                 align = 4;
1280                         }
1281                         /*FALLTHROUGH*/
1282                 case PT_INTERP:
1283                         len = xph_filesz < sizeof(nbuf) ? xph_filesz
1284                             : sizeof(nbuf);
1285                         bufsize = pread(fd, nbuf, len, xph_offset);
1286                         if (bufsize == -1) {
1287                                 file_badread(ms);
1288                                 return -1;
1289                         }
1290                         break;
1291                 default:
1292                         if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
1293                                 /* Maybe warn here? */
1294                                 continue;
1295                         }
1296                         break;
1297                 }
1298
1299                 /* Things we can determine when we seek */
1300                 switch (xph_type) {
1301                 case PT_INTERP:
1302                         if (bufsize && nbuf[0]) {
1303                                 nbuf[bufsize - 1] = '\0';
1304                                 interp = (const char *)nbuf;
1305                         } else
1306                                 interp = "*empty*";
1307                         break;
1308                 case PT_NOTE:
1309                         /*
1310                          * This is a PT_NOTE section; loop through all the notes
1311                          * in the section.
1312                          */
1313                         offset = 0;
1314                         for (;;) {
1315                                 if (offset >= (size_t)bufsize)
1316                                         break;
1317                                 offset = donote(ms, nbuf, offset,
1318                                     (size_t)bufsize, clazz, swap, align,
1319                                     flags, notecount);
1320                                 if (offset == 0)
1321                                         break;
1322                         }
1323                         break;
1324                 default:
1325                         break;
1326                 }
1327         }
1328         if (file_printf(ms, ", %s linked", linking_style)
1329             == -1)
1330                 return -1;
1331         if (interp[0])
1332                 if (file_printf(ms, ", interpreter %s",
1333                     file_printable(ibuf, sizeof(ibuf), interp)) == -1)
1334                         return -1;
1335         return 0;
1336 }
1337
1338
1339 protected int
1340 file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
1341     size_t nbytes)
1342 {
1343         union {
1344                 int32_t l;
1345                 char c[sizeof (int32_t)];
1346         } u;
1347         int clazz;
1348         int swap;
1349         struct stat st;
1350         off_t fsize;
1351         int flags = 0;
1352         Elf32_Ehdr elf32hdr;
1353         Elf64_Ehdr elf64hdr;
1354         uint16_t type, phnum, shnum, notecount;
1355
1356         if (ms->flags & (MAGIC_MIME|MAGIC_APPLE|MAGIC_EXTENSION))
1357                 return 0;
1358         /*
1359          * ELF executables have multiple section headers in arbitrary
1360          * file locations and thus file(1) cannot determine it from easily.
1361          * Instead we traverse thru all section headers until a symbol table
1362          * one is found or else the binary is stripped.
1363          * Return immediately if it's not ELF (so we avoid pipe2file unless needed).
1364          */
1365         if (buf[EI_MAG0] != ELFMAG0
1366             || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
1367             || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
1368                 return 0;
1369
1370         /*
1371          * If we cannot seek, it must be a pipe, socket or fifo.
1372          */
1373         if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
1374                 fd = file_pipe2file(ms, fd, buf, nbytes);
1375
1376         if (fstat(fd, &st) == -1) {
1377                 file_badread(ms);
1378                 return -1;
1379         }
1380         if (S_ISREG(st.st_mode) || st.st_size != 0)
1381                 fsize = st.st_size;
1382         else
1383                 fsize = SIZE_UNKNOWN;
1384
1385         clazz = buf[EI_CLASS];
1386
1387         switch (clazz) {
1388         case ELFCLASS32:
1389 #undef elf_getu
1390 #define elf_getu(a, b)  elf_getu32(a, b)
1391 #undef elfhdr
1392 #define elfhdr elf32hdr
1393 #include "elfclass.h"
1394         case ELFCLASS64:
1395 #undef elf_getu
1396 #define elf_getu(a, b)  elf_getu64(a, b)
1397 #undef elfhdr
1398 #define elfhdr elf64hdr
1399 #include "elfclass.h"
1400         default:
1401             if (file_printf(ms, ", unknown class %d", clazz) == -1)
1402                     return -1;
1403             break;
1404         }
1405         return 0;
1406 }
1407 #endif