]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/file/src/readelf.c
MFC r298192,299234,299238,299736:
[FreeBSD/stable/10.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.127 2015/11/18 12:29:29 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 *, int, off_t, int, off_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_vaddr       (size_t)((clazz == ELFCLASS32           \
181                          ? (off_t) (ph32.p_vaddr ?              \
182                             elf_getu32(swap, ph32.p_vaddr) : 4) \
183                          : (off_t) (ph64.p_vaddr ?              \
184                             elf_getu64(swap, ph64.p_vaddr) : 4)))
185 #define xph_filesz      (size_t)((clazz == ELFCLASS32           \
186                          ? elf_getu32(swap, ph32.p_filesz)      \
187                          : elf_getu64(swap, ph64.p_filesz)))
188 #define xnh_addr        (clazz == ELFCLASS32                    \
189                          ? (void *)&nh32                        \
190                          : (void *)&nh64)
191 #define xph_memsz       (size_t)((clazz == ELFCLASS32           \
192                          ? elf_getu32(swap, ph32.p_memsz)       \
193                          : elf_getu64(swap, ph64.p_memsz)))
194 #define xnh_sizeof      (clazz == ELFCLASS32                    \
195                          ? sizeof(nh32)                         \
196                          : sizeof(nh64))
197 #define xnh_type        (clazz == ELFCLASS32                    \
198                          ? elf_getu32(swap, nh32.n_type)        \
199                          : elf_getu32(swap, nh64.n_type))
200 #define xnh_namesz      (clazz == ELFCLASS32                    \
201                          ? elf_getu32(swap, nh32.n_namesz)      \
202                          : elf_getu32(swap, nh64.n_namesz))
203 #define xnh_descsz      (clazz == ELFCLASS32                    \
204                          ? elf_getu32(swap, nh32.n_descsz)      \
205                          : elf_getu32(swap, nh64.n_descsz))
206 #define prpsoffsets(i)  (clazz == ELFCLASS32                    \
207                          ? prpsoffsets32[i]                     \
208                          : prpsoffsets64[i])
209 #define xcap_addr       (clazz == ELFCLASS32                    \
210                          ? (void *)&cap32                       \
211                          : (void *)&cap64)
212 #define xcap_sizeof     (clazz == ELFCLASS32                    \
213                          ? sizeof cap32                         \
214                          : sizeof cap64)
215 #define xcap_tag        (clazz == ELFCLASS32                    \
216                          ? elf_getu32(swap, cap32.c_tag)        \
217                          : elf_getu64(swap, cap64.c_tag))
218 #define xcap_val        (clazz == ELFCLASS32                    \
219                          ? elf_getu32(swap, cap32.c_un.c_val)   \
220                          : elf_getu64(swap, cap64.c_un.c_val))
221 #define xauxv_addr      (clazz == ELFCLASS32                    \
222                          ? (void *)&auxv32                      \
223                          : (void *)&auxv64)
224 #define xauxv_sizeof    (clazz == ELFCLASS32                    \
225                          ? sizeof(auxv32)                       \
226                          : sizeof(auxv64))
227 #define xauxv_type      (clazz == ELFCLASS32                    \
228                          ? elf_getu32(swap, auxv32.a_type)      \
229                          : elf_getu64(swap, auxv64.a_type))
230 #define xauxv_val       (clazz == ELFCLASS32                    \
231                          ? elf_getu32(swap, auxv32.a_v)         \
232                          : elf_getu64(swap, auxv64.a_v))
233
234 #ifdef ELFCORE
235 /*
236  * Try larger offsets first to avoid false matches
237  * from earlier data that happen to look like strings.
238  */
239 static const size_t     prpsoffsets32[] = {
240 #ifdef USE_NT_PSINFO
241         104,            /* SunOS 5.x (command line) */
242         88,             /* SunOS 5.x (short name) */
243 #endif /* USE_NT_PSINFO */
244
245         100,            /* SunOS 5.x (command line) */
246         84,             /* SunOS 5.x (short name) */
247
248         44,             /* Linux (command line) */
249         28,             /* Linux 2.0.36 (short name) */
250
251         8,              /* FreeBSD */
252 };
253
254 static const size_t     prpsoffsets64[] = {
255 #ifdef USE_NT_PSINFO
256         152,            /* SunOS 5.x (command line) */
257         136,            /* SunOS 5.x (short name) */
258 #endif /* USE_NT_PSINFO */
259
260         136,            /* SunOS 5.x, 64-bit (command line) */
261         120,            /* SunOS 5.x, 64-bit (short name) */
262
263         56,             /* Linux (command line) */
264         40,             /* Linux (tested on core from 2.4.x, short name) */
265
266         16,             /* FreeBSD, 64-bit */
267 };
268
269 #define NOFFSETS32      (sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
270 #define NOFFSETS64      (sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
271
272 #define NOFFSETS        (clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
273
274 /*
275  * Look through the program headers of an executable image, searching
276  * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
277  * "FreeBSD"; if one is found, try looking in various places in its
278  * contents for a 16-character string containing only printable
279  * characters - if found, that string should be the name of the program
280  * that dropped core.  Note: right after that 16-character string is,
281  * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
282  * Linux, a longer string (80 characters, in 5.x, probably other
283  * SVR4-flavored systems, and Linux) containing the start of the
284  * command line for that program.
285  *
286  * SunOS 5.x core files contain two PT_NOTE sections, with the types
287  * NT_PRPSINFO (old) and NT_PSINFO (new).  These structs contain the
288  * same info about the command name and command line, so it probably
289  * isn't worthwhile to look for NT_PSINFO, but the offsets are provided
290  * above (see USE_NT_PSINFO), in case we ever decide to do so.  The
291  * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent;
292  * the SunOS 5.x file command relies on this (and prefers the latter).
293  *
294  * The signal number probably appears in a section of type NT_PRSTATUS,
295  * but that's also rather OS-dependent, in ways that are harder to
296  * dissect with heuristics, so I'm not bothering with the signal number.
297  * (I suppose the signal number could be of interest in situations where
298  * you don't have the binary of the program that dropped core; if you
299  * *do* have that binary, the debugger will probably tell you what
300  * signal it was.)
301  */
302
303 #define OS_STYLE_SVR4           0
304 #define OS_STYLE_FREEBSD        1
305 #define OS_STYLE_NETBSD         2
306
307 private const char os_style_names[][8] = {
308         "SVR4",
309         "FreeBSD",
310         "NetBSD",
311 };
312
313 #define FLAGS_DID_CORE                  0x001
314 #define FLAGS_DID_OS_NOTE               0x002
315 #define FLAGS_DID_BUILD_ID              0x004
316 #define FLAGS_DID_CORE_STYLE            0x008
317 #define FLAGS_DID_NETBSD_PAX            0x010
318 #define FLAGS_DID_NETBSD_MARCH          0x020
319 #define FLAGS_DID_NETBSD_CMODEL         0x040
320 #define FLAGS_DID_NETBSD_UNKNOWN        0x080
321 #define FLAGS_IS_CORE                   0x100
322 #define FLAGS_DID_AUXV                  0x200
323
324 private int
325 dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
326     int num, size_t size, off_t fsize, int *flags, uint16_t *notecount)
327 {
328         Elf32_Phdr ph32;
329         Elf64_Phdr ph64;
330         size_t offset, len;
331         unsigned char nbuf[BUFSIZ];
332         ssize_t bufsize;
333         off_t ph_off = off;
334         int ph_num = num;
335
336         if (size != xph_sizeof) {
337                 if (file_printf(ms, ", corrupted program header size") == -1)
338                         return -1;
339                 return 0;
340         }
341
342         /*
343          * Loop through all the program headers.
344          */
345         for ( ; num; num--) {
346                 if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
347                         file_badread(ms);
348                         return -1;
349                 }
350                 off += size;
351
352                 if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
353                         /* Perhaps warn here */
354                         continue;
355                 }
356
357                 if (xph_type != PT_NOTE)
358                         continue;
359
360                 /*
361                  * This is a PT_NOTE section; loop through all the notes
362                  * in the section.
363                  */
364                 len = xph_filesz < sizeof(nbuf) ? xph_filesz : sizeof(nbuf);
365                 if ((bufsize = pread(fd, nbuf, len, xph_offset)) == -1) {
366                         file_badread(ms);
367                         return -1;
368                 }
369                 offset = 0;
370                 for (;;) {
371                         if (offset >= (size_t)bufsize)
372                                 break;
373                         offset = donote(ms, nbuf, offset, (size_t)bufsize,
374                             clazz, swap, 4, flags, notecount, fd, ph_off,
375                             ph_num, fsize);
376                         if (offset == 0)
377                                 break;
378
379                 }
380         }
381         return 0;
382 }
383 #endif
384
385 static void
386 do_note_netbsd_version(struct magic_set *ms, int swap, void *v)
387 {
388         uint32_t desc;
389         (void)memcpy(&desc, v, sizeof(desc));
390         desc = elf_getu32(swap, desc);
391
392         if (file_printf(ms, ", for NetBSD") == -1)
393                 return;
394         /*
395          * The version number used to be stuck as 199905, and was thus
396          * basically content-free.  Newer versions of NetBSD have fixed
397          * this and now use the encoding of __NetBSD_Version__:
398          *
399          *      MMmmrrpp00
400          *
401          * M = major version
402          * m = minor version
403          * r = release ["",A-Z,Z[A-Z] but numeric]
404          * p = patchlevel
405          */
406         if (desc > 100000000U) {
407                 uint32_t ver_patch = (desc / 100) % 100;
408                 uint32_t ver_rel = (desc / 10000) % 100;
409                 uint32_t ver_min = (desc / 1000000) % 100;
410                 uint32_t ver_maj = desc / 100000000;
411
412                 if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1)
413                         return;
414                 if (ver_rel == 0 && ver_patch != 0) {
415                         if (file_printf(ms, ".%u", ver_patch) == -1)
416                                 return;
417                 } else if (ver_rel != 0) {
418                         while (ver_rel > 26) {
419                                 if (file_printf(ms, "Z") == -1)
420                                         return;
421                                 ver_rel -= 26;
422                         }
423                         if (file_printf(ms, "%c", 'A' + ver_rel - 1)
424                             == -1)
425                                 return;
426                 }
427         }
428 }
429
430 static void
431 do_note_freebsd_version(struct magic_set *ms, int swap, void *v)
432 {
433         uint32_t desc;
434
435         (void)memcpy(&desc, v, sizeof(desc));
436         desc = elf_getu32(swap, desc);
437         if (file_printf(ms, ", for FreeBSD") == -1)
438                 return;
439
440         /*
441          * Contents is __FreeBSD_version, whose relation to OS
442          * versions is defined by a huge table in the Porter's
443          * Handbook.  This is the general scheme:
444          * 
445          * Releases:
446          *      Mmp000 (before 4.10)
447          *      Mmi0p0 (before 5.0)
448          *      Mmm0p0
449          * 
450          * Development branches:
451          *      Mmpxxx (before 4.6)
452          *      Mmp1xx (before 4.10)
453          *      Mmi1xx (before 5.0)
454          *      M000xx (pre-M.0)
455          *      Mmm1xx
456          * 
457          * M = major version
458          * m = minor version
459          * i = minor version increment (491000 -> 4.10)
460          * p = patchlevel
461          * x = revision
462          * 
463          * The first release of FreeBSD to use ELF by default
464          * was version 3.0.
465          */
466         if (desc == 460002) {
467                 if (file_printf(ms, " 4.6.2") == -1)
468                         return;
469         } else if (desc < 460100) {
470                 if (file_printf(ms, " %d.%d", desc / 100000,
471                     desc / 10000 % 10) == -1)
472                         return;
473                 if (desc / 1000 % 10 > 0)
474                         if (file_printf(ms, ".%d", desc / 1000 % 10) == -1)
475                                 return;
476                 if ((desc % 1000 > 0) || (desc % 100000 == 0))
477                         if (file_printf(ms, " (%d)", desc) == -1)
478                                 return;
479         } else if (desc < 500000) {
480                 if (file_printf(ms, " %d.%d", desc / 100000,
481                     desc / 10000 % 10 + desc / 1000 % 10) == -1)
482                         return;
483                 if (desc / 100 % 10 > 0) {
484                         if (file_printf(ms, " (%d)", desc) == -1)
485                                 return;
486                 } else if (desc / 10 % 10 > 0) {
487                         if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
488                                 return;
489                 }
490         } else {
491                 if (file_printf(ms, " %d.%d", desc / 100000,
492                     desc / 1000 % 100) == -1)
493                         return;
494                 if ((desc / 100 % 10 > 0) ||
495                     (desc % 100000 / 100 == 0)) {
496                         if (file_printf(ms, " (%d)", desc) == -1)
497                                 return;
498                 } else if (desc / 10 % 10 > 0) {
499                         if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
500                                 return;
501                 }
502         }
503 }
504
505 private int
506 /*ARGSUSED*/
507 do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
508     int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz,
509     size_t noff, size_t doff, int *flags)
510 {
511         if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
512             type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) {
513                 uint8_t desc[20];
514                 uint32_t i;
515                 *flags |= FLAGS_DID_BUILD_ID;
516                 if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" :
517                     "sha1") == -1)
518                         return 1;
519                 (void)memcpy(desc, &nbuf[doff], descsz);
520                 for (i = 0; i < descsz; i++)
521                     if (file_printf(ms, "%02x", desc[i]) == -1)
522                         return 1;
523                 return 1;
524         }
525         return 0;
526 }
527
528 private int
529 do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
530     int swap, uint32_t namesz, uint32_t descsz,
531     size_t noff, size_t doff, int *flags)
532 {
533         if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 &&
534             type == NT_GNU_VERSION && descsz == 2) {
535             *flags |= FLAGS_DID_OS_NOTE;
536             file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]);
537             return 1;
538         }
539
540         if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
541             type == NT_GNU_VERSION && descsz == 16) {
542                 uint32_t desc[4];
543                 (void)memcpy(desc, &nbuf[doff], sizeof(desc));
544
545                 *flags |= FLAGS_DID_OS_NOTE;
546                 if (file_printf(ms, ", for GNU/") == -1)
547                         return 1;
548                 switch (elf_getu32(swap, desc[0])) {
549                 case GNU_OS_LINUX:
550                         if (file_printf(ms, "Linux") == -1)
551                                 return 1;
552                         break;
553                 case GNU_OS_HURD:
554                         if (file_printf(ms, "Hurd") == -1)
555                                 return 1;
556                         break;
557                 case GNU_OS_SOLARIS:
558                         if (file_printf(ms, "Solaris") == -1)
559                                 return 1;
560                         break;
561                 case GNU_OS_KFREEBSD:
562                         if (file_printf(ms, "kFreeBSD") == -1)
563                                 return 1;
564                         break;
565                 case GNU_OS_KNETBSD:
566                         if (file_printf(ms, "kNetBSD") == -1)
567                                 return 1;
568                         break;
569                 default:
570                         if (file_printf(ms, "<unknown>") == -1)
571                                 return 1; 
572                 }
573                 if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
574                     elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1)
575                         return 1;
576                 return 1;
577         }
578
579         if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
580                 if (type == NT_NETBSD_VERSION && descsz == 4) {
581                         *flags |= FLAGS_DID_OS_NOTE;
582                         do_note_netbsd_version(ms, swap, &nbuf[doff]);
583                         return 1;
584                 }
585         }
586
587         if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
588                 if (type == NT_FREEBSD_VERSION && descsz == 4) {
589                         *flags |= FLAGS_DID_OS_NOTE;
590                         do_note_freebsd_version(ms, swap, &nbuf[doff]);
591                         return 1;
592                 }
593         }
594
595         if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
596             type == NT_OPENBSD_VERSION && descsz == 4) {
597                 *flags |= FLAGS_DID_OS_NOTE;
598                 if (file_printf(ms, ", for OpenBSD") == -1)
599                         return 1;
600                 /* Content of note is always 0 */
601                 return 1;
602         }
603
604         if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
605             type == NT_DRAGONFLY_VERSION && descsz == 4) {
606                 uint32_t desc;
607                 *flags |= FLAGS_DID_OS_NOTE;
608                 if (file_printf(ms, ", for DragonFly") == -1)
609                         return 1;
610                 (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
611                 desc = elf_getu32(swap, desc);
612                 if (file_printf(ms, " %d.%d.%d", desc / 100000,
613                     desc / 10000 % 10, desc % 10000) == -1)
614                         return 1;
615                 return 1;
616         }
617         return 0;
618 }
619
620 private int
621 do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
622     int swap, uint32_t namesz, uint32_t descsz,
623     size_t noff, size_t doff, int *flags)
624 {
625         if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 &&
626             type == NT_NETBSD_PAX && descsz == 4) {
627                 static const char *pax[] = {
628                     "+mprotect",
629                     "-mprotect",
630                     "+segvguard",
631                     "-segvguard",
632                     "+ASLR",
633                     "-ASLR",
634                 };
635                 uint32_t desc;
636                 size_t i;
637                 int did = 0;
638
639                 *flags |= FLAGS_DID_NETBSD_PAX;
640                 (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
641                 desc = elf_getu32(swap, desc);
642
643                 if (desc && file_printf(ms, ", PaX: ") == -1)
644                         return 1;
645
646                 for (i = 0; i < __arraycount(pax); i++) {
647                         if (((1 << (int)i) & desc) == 0)
648                                 continue;
649                         if (file_printf(ms, "%s%s", did++ ? "," : "",
650                             pax[i]) == -1)
651                                 return 1;
652                 }
653                 return 1;
654         }
655         return 0;
656 }
657
658 private int
659 do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
660     int swap, uint32_t namesz, uint32_t descsz,
661     size_t noff, size_t doff, int *flags, size_t size, int clazz)
662 {
663 #ifdef ELFCORE
664         int os_style = -1;
665         /*
666          * Sigh.  The 2.0.36 kernel in Debian 2.1, at
667          * least, doesn't correctly implement name
668          * sections, in core dumps, as specified by
669          * the "Program Linking" section of "UNIX(R) System
670          * V Release 4 Programmer's Guide: ANSI C and
671          * Programming Support Tools", because my copy
672          * clearly says "The first 'namesz' bytes in 'name'
673          * contain a *null-terminated* [emphasis mine]
674          * character representation of the entry's owner
675          * or originator", but the 2.0.36 kernel code
676          * doesn't include the terminating null in the
677          * name....
678          */
679         if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) ||
680             (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) {
681                 os_style = OS_STYLE_SVR4;
682         } 
683
684         if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) {
685                 os_style = OS_STYLE_FREEBSD;
686         }
687
688         if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11)
689             == 0)) {
690                 os_style = OS_STYLE_NETBSD;
691         }
692
693         if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
694                 if (file_printf(ms, ", %s-style", os_style_names[os_style])
695                     == -1)
696                         return 1;
697                 *flags |= FLAGS_DID_CORE_STYLE;
698         }
699
700         switch (os_style) {
701         case OS_STYLE_NETBSD:
702                 if (type == NT_NETBSD_CORE_PROCINFO) {
703                         char sbuf[512];
704                         uint32_t signo;
705                         /*
706                          * Extract the program name.  It is at
707                          * offset 0x7c, and is up to 32-bytes,
708                          * including the terminating NUL.
709                          */
710                         if (file_printf(ms, ", from '%.31s'",
711                             file_printable(sbuf, sizeof(sbuf),
712                             (const char *)&nbuf[doff + 0x7c])) == -1)
713                                 return 1;
714                         
715                         /*
716                          * Extract the signal number.  It is at
717                          * offset 0x08.
718                          */
719                         (void)memcpy(&signo, &nbuf[doff + 0x08],
720                             sizeof(signo));
721                         if (file_printf(ms, " (signal %u)",
722                             elf_getu32(swap, signo)) == -1)
723                                 return 1;
724                         *flags |= FLAGS_DID_CORE;
725                         return 1;
726                 }
727                 break;
728
729         default:
730                 if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
731                         size_t i, j;
732                         unsigned char c;
733                         /*
734                          * Extract the program name.  We assume
735                          * it to be 16 characters (that's what it
736                          * is in SunOS 5.x and Linux).
737                          *
738                          * Unfortunately, it's at a different offset
739                          * in various OSes, so try multiple offsets.
740                          * If the characters aren't all printable,
741                          * reject it.
742                          */
743                         for (i = 0; i < NOFFSETS; i++) {
744                                 unsigned char *cname, *cp;
745                                 size_t reloffset = prpsoffsets(i);
746                                 size_t noffset = doff + reloffset;
747                                 size_t k;
748                                 for (j = 0; j < 16; j++, noffset++,
749                                     reloffset++) {
750                                         /*
751                                          * Make sure we're not past
752                                          * the end of the buffer; if
753                                          * we are, just give up.
754                                          */
755                                         if (noffset >= size)
756                                                 goto tryanother;
757
758                                         /*
759                                          * Make sure we're not past
760                                          * the end of the contents;
761                                          * if we are, this obviously
762                                          * isn't the right offset.
763                                          */
764                                         if (reloffset >= descsz)
765                                                 goto tryanother;
766
767                                         c = nbuf[noffset];
768                                         if (c == '\0') {
769                                                 /*
770                                                  * A '\0' at the
771                                                  * beginning is
772                                                  * obviously wrong.
773                                                  * Any other '\0'
774                                                  * means we're done.
775                                                  */
776                                                 if (j == 0)
777                                                         goto tryanother;
778                                                 else
779                                                         break;
780                                         } else {
781                                                 /*
782                                                  * A nonprintable
783                                                  * character is also
784                                                  * wrong.
785                                                  */
786                                                 if (!isprint(c) || isquote(c))
787                                                         goto tryanother;
788                                         }
789                                 }
790                                 /*
791                                  * Well, that worked.
792                                  */
793
794                                 /*
795                                  * Try next offsets, in case this match is
796                                  * in the middle of a string.
797                                  */
798                                 for (k = i + 1 ; k < NOFFSETS; k++) {
799                                         size_t no;
800                                         int adjust = 1;
801                                         if (prpsoffsets(k) >= prpsoffsets(i))
802                                                 continue;
803                                         for (no = doff + prpsoffsets(k);
804                                              no < doff + prpsoffsets(i); no++)
805                                                 adjust = adjust
806                                                          && isprint(nbuf[no]);
807                                         if (adjust)
808                                                 i = k;
809                                 }
810
811                                 cname = (unsigned char *)
812                                     &nbuf[doff + prpsoffsets(i)];
813                                 for (cp = cname; *cp && isprint(*cp); cp++)
814                                         continue;
815                                 /*
816                                  * Linux apparently appends a space at the end
817                                  * of the command line: remove it.
818                                  */
819                                 while (cp > cname && isspace(cp[-1]))
820                                         cp--;
821                                 if (file_printf(ms, ", from '%.*s'",
822                                     (int)(cp - cname), cname) == -1)
823                                         return 1;
824                                 *flags |= FLAGS_DID_CORE;
825                                 return 1;
826
827                         tryanother:
828                                 ;
829                         }
830                 }
831                 break;
832         }
833 #endif
834         return 0;
835 }
836
837 private off_t
838 get_offset_from_virtaddr(struct magic_set *ms, int swap, int clazz, int fd,
839     off_t off, int num, off_t fsize, uint64_t virtaddr)
840 {
841         Elf32_Phdr ph32;
842         Elf64_Phdr ph64;
843
844         /*
845          * Loop through all the program headers and find the header with
846          * virtual address in which the "virtaddr" belongs to.
847          */
848         for ( ; num; num--) {
849                 if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
850                         file_badread(ms);
851                         return -1;
852                 }
853                 off += xph_sizeof;
854
855                 if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
856                         /* Perhaps warn here */
857                         continue;
858                 }
859
860                 if (virtaddr >= xph_vaddr && virtaddr < xph_vaddr + xph_filesz)
861                         return xph_offset + (virtaddr - xph_vaddr);
862         }
863         return 0;
864 }
865
866 private size_t
867 get_string_on_virtaddr(struct magic_set *ms,
868     int swap, int clazz, int fd, off_t ph_off, int ph_num,
869     off_t fsize, uint64_t virtaddr, char *buf, ssize_t buflen)
870 {
871         char *bptr;
872         off_t offset;
873
874         if (buflen == 0)
875                 return 0;
876
877         offset = get_offset_from_virtaddr(ms, swap, clazz, fd, ph_off, ph_num,
878             fsize, virtaddr);
879         if ((buflen = pread(fd, buf, buflen, offset)) <= 0) {
880                 file_badread(ms);
881                 return 0;
882         }
883
884         buf[buflen - 1] = '\0';
885
886         /* We expect only printable characters, so return if buffer contains
887          * non-printable character before the '\0' or just '\0'. */
888         for (bptr = buf; *bptr && isprint((unsigned char)*bptr); bptr++)
889                 continue;
890         if (*bptr != '\0')
891                 return 0;
892
893         return bptr - buf;
894 }
895
896
897 private int
898 do_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
899     int swap, uint32_t namesz __attribute__((__unused__)),
900     uint32_t descsz __attribute__((__unused__)),
901     size_t noff __attribute__((__unused__)), size_t doff,
902     int *flags, size_t size __attribute__((__unused__)), int clazz,
903     int fd, off_t ph_off, int ph_num, off_t fsize)
904 {
905 #ifdef ELFCORE
906         Aux32Info auxv32;
907         Aux64Info auxv64;
908         size_t elsize = xauxv_sizeof;
909         const char *tag;
910         int is_string;
911         size_t nval;
912
913         if (type != NT_AUXV || (*flags & FLAGS_IS_CORE) == 0)
914                 return 0;
915
916         *flags |= FLAGS_DID_AUXV;
917
918         nval = 0;
919         for (size_t off = 0; off + elsize <= descsz; off += elsize) {
920                 (void)memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof);
921                 /* Limit processing to 50 vector entries to prevent DoS */
922                 if (nval++ >= 50) {
923                         file_error(ms, 0, "Too many ELF Auxv elements");
924                         return 1;
925                 }
926
927                 switch(xauxv_type) {
928                 case AT_LINUX_EXECFN:
929                         is_string = 1;
930                         tag = "execfn";
931                         break;
932                 case AT_LINUX_PLATFORM:
933                         is_string = 1;
934                         tag = "platform";
935                         break;
936                 case AT_LINUX_UID:
937                         is_string = 0;
938                         tag = "real uid";
939                         break;
940                 case AT_LINUX_GID:
941                         is_string = 0;
942                         tag = "real gid";
943                         break;
944                 case AT_LINUX_EUID:
945                         is_string = 0;
946                         tag = "effective uid";
947                         break;
948                 case AT_LINUX_EGID:
949                         is_string = 0;
950                         tag = "effective gid";
951                         break;
952                 default:
953                         is_string = 0;
954                         tag = NULL;
955                         break;
956                 }
957
958                 if (tag == NULL)
959                         continue;
960
961                 if (is_string) {
962                         char buf[256];
963                         ssize_t buflen;
964                         buflen = get_string_on_virtaddr(ms, swap, clazz, fd,
965                             ph_off, ph_num, fsize, xauxv_val, buf, sizeof(buf));
966
967                         if (buflen == 0)
968                                 continue;
969                         
970                         if (file_printf(ms, ", %s: '%s'", tag, buf) == -1)
971                                 return 0;
972                 } else {
973                         if (file_printf(ms, ", %s: %d", tag, (int) xauxv_val)
974                             == -1)
975                                 return 0;
976                 }
977         }
978         return 1;
979 #else
980         return 0;
981 #endif
982 }
983
984 private size_t
985 donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
986     int clazz, int swap, size_t align, int *flags, uint16_t *notecount,
987     int fd, off_t ph_off, int ph_num, off_t fsize)
988 {
989         Elf32_Nhdr nh32;
990         Elf64_Nhdr nh64;
991         size_t noff, doff;
992         uint32_t namesz, descsz;
993         unsigned char *nbuf = CAST(unsigned char *, vbuf);
994
995         if (*notecount == 0)
996                 return 0;
997         --*notecount;
998
999         if (xnh_sizeof + offset > size) {
1000                 /*
1001                  * We're out of note headers.
1002                  */
1003                 return xnh_sizeof + offset;
1004         }
1005
1006         (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
1007         offset += xnh_sizeof;
1008
1009         namesz = xnh_namesz;
1010         descsz = xnh_descsz;
1011
1012         if ((namesz == 0) && (descsz == 0)) {
1013                 /*
1014                  * We're out of note headers.
1015                  */
1016                 return (offset >= size) ? offset : size;
1017         }
1018
1019         if (namesz & 0x80000000) {
1020             (void)file_printf(ms, ", bad note name size 0x%lx",
1021                 (unsigned long)namesz);
1022             return 0;
1023         }
1024
1025         if (descsz & 0x80000000) {
1026             (void)file_printf(ms, ", bad note description size 0x%lx",
1027                 (unsigned long)descsz);
1028             return 0;
1029         }
1030
1031         noff = offset;
1032         doff = ELF_ALIGN(offset + namesz);
1033
1034         if (offset + namesz > size) {
1035                 /*
1036                  * We're past the end of the buffer.
1037                  */
1038                 return doff;
1039         }
1040
1041         offset = ELF_ALIGN(doff + descsz);
1042         if (doff + descsz > size) {
1043                 /*
1044                  * We're past the end of the buffer.
1045                  */
1046                 return (offset >= size) ? offset : size;
1047         }
1048
1049
1050         if ((*flags & FLAGS_DID_OS_NOTE) == 0) {
1051                 if (do_os_note(ms, nbuf, xnh_type, swap,
1052                     namesz, descsz, noff, doff, flags))
1053                         return offset;
1054         }
1055
1056         if ((*flags & FLAGS_DID_BUILD_ID) == 0) {
1057                 if (do_bid_note(ms, nbuf, xnh_type, swap,
1058                     namesz, descsz, noff, doff, flags))
1059                         return offset;
1060         }
1061                 
1062         if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) {
1063                 if (do_pax_note(ms, nbuf, xnh_type, swap,
1064                     namesz, descsz, noff, doff, flags))
1065                         return offset;
1066         }
1067
1068         if ((*flags & FLAGS_DID_CORE) == 0) {
1069                 if (do_core_note(ms, nbuf, xnh_type, swap,
1070                     namesz, descsz, noff, doff, flags, size, clazz))
1071                         return offset;
1072         }
1073
1074         if ((*flags & FLAGS_DID_AUXV) == 0) {
1075                 if (do_auxv_note(ms, nbuf, xnh_type, swap,
1076                         namesz, descsz, noff, doff, flags, size, clazz,
1077                         fd, ph_off, ph_num, fsize))
1078                         return offset;
1079         }
1080
1081         if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
1082                 if (descsz > 100)
1083                         descsz = 100;
1084                 switch (xnh_type) {
1085                 case NT_NETBSD_VERSION:
1086                         return offset;
1087                 case NT_NETBSD_MARCH:
1088                         if (*flags & FLAGS_DID_NETBSD_MARCH)
1089                                 return offset;
1090                         *flags |= FLAGS_DID_NETBSD_MARCH;
1091                         if (file_printf(ms, ", compiled for: %.*s",
1092                             (int)descsz, (const char *)&nbuf[doff]) == -1)
1093                                 return offset;
1094                         break;
1095                 case NT_NETBSD_CMODEL:
1096                         if (*flags & FLAGS_DID_NETBSD_CMODEL)
1097                                 return offset;
1098                         *flags |= FLAGS_DID_NETBSD_CMODEL;
1099                         if (file_printf(ms, ", compiler model: %.*s",
1100                             (int)descsz, (const char *)&nbuf[doff]) == -1)
1101                                 return offset;
1102                         break;
1103                 default:
1104                         if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
1105                                 return offset;
1106                         *flags |= FLAGS_DID_NETBSD_UNKNOWN;
1107                         if (file_printf(ms, ", note=%u", xnh_type) == -1)
1108                                 return offset;
1109                         break;
1110                 }
1111                 return offset;
1112         }
1113
1114         return offset;
1115 }
1116
1117 /* SunOS 5.x hardware capability descriptions */
1118 typedef struct cap_desc {
1119         uint64_t cd_mask;
1120         const char *cd_name;
1121 } cap_desc_t;
1122
1123 static const cap_desc_t cap_desc_sparc[] = {
1124         { AV_SPARC_MUL32,               "MUL32" },
1125         { AV_SPARC_DIV32,               "DIV32" },
1126         { AV_SPARC_FSMULD,              "FSMULD" },
1127         { AV_SPARC_V8PLUS,              "V8PLUS" },
1128         { AV_SPARC_POPC,                "POPC" },
1129         { AV_SPARC_VIS,                 "VIS" },
1130         { AV_SPARC_VIS2,                "VIS2" },
1131         { AV_SPARC_ASI_BLK_INIT,        "ASI_BLK_INIT" },
1132         { AV_SPARC_FMAF,                "FMAF" },
1133         { AV_SPARC_FJFMAU,              "FJFMAU" },
1134         { AV_SPARC_IMA,                 "IMA" },
1135         { 0, NULL }
1136 };
1137
1138 static const cap_desc_t cap_desc_386[] = {
1139         { AV_386_FPU,                   "FPU" },
1140         { AV_386_TSC,                   "TSC" },
1141         { AV_386_CX8,                   "CX8" },
1142         { AV_386_SEP,                   "SEP" },
1143         { AV_386_AMD_SYSC,              "AMD_SYSC" },
1144         { AV_386_CMOV,                  "CMOV" },
1145         { AV_386_MMX,                   "MMX" },
1146         { AV_386_AMD_MMX,               "AMD_MMX" },
1147         { AV_386_AMD_3DNow,             "AMD_3DNow" },
1148         { AV_386_AMD_3DNowx,            "AMD_3DNowx" },
1149         { AV_386_FXSR,                  "FXSR" },
1150         { AV_386_SSE,                   "SSE" },
1151         { AV_386_SSE2,                  "SSE2" },
1152         { AV_386_PAUSE,                 "PAUSE" },
1153         { AV_386_SSE3,                  "SSE3" },
1154         { AV_386_MON,                   "MON" },
1155         { AV_386_CX16,                  "CX16" },
1156         { AV_386_AHF,                   "AHF" },
1157         { AV_386_TSCP,                  "TSCP" },
1158         { AV_386_AMD_SSE4A,             "AMD_SSE4A" },
1159         { AV_386_POPCNT,                "POPCNT" },
1160         { AV_386_AMD_LZCNT,             "AMD_LZCNT" },
1161         { AV_386_SSSE3,                 "SSSE3" },
1162         { AV_386_SSE4_1,                "SSE4.1" },
1163         { AV_386_SSE4_2,                "SSE4.2" },
1164         { 0, NULL }
1165 };
1166
1167 private int
1168 doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
1169     size_t size, off_t fsize, int mach, int strtab, int *flags,
1170     uint16_t *notecount)
1171 {
1172         Elf32_Shdr sh32;
1173         Elf64_Shdr sh64;
1174         int stripped = 1;
1175         size_t nbadcap = 0;
1176         void *nbuf;
1177         off_t noff, coff, name_off;
1178         uint64_t cap_hw1 = 0;   /* SunOS 5.x hardware capabilites */
1179         uint64_t cap_sf1 = 0;   /* SunOS 5.x software capabilites */
1180         char name[50];
1181         ssize_t namesize;
1182
1183         if (size != xsh_sizeof) {
1184                 if (file_printf(ms, ", corrupted section header size") == -1)
1185                         return -1;
1186                 return 0;
1187         }
1188
1189         /* Read offset of name section to be able to read section names later */
1190         if (pread(fd, xsh_addr, xsh_sizeof, CAST(off_t, (off + size * strtab)))
1191             < (ssize_t)xsh_sizeof) {
1192                 file_badread(ms);
1193                 return -1;
1194         }
1195         name_off = xsh_offset;
1196
1197         for ( ; num; num--) {
1198                 /* Read the name of this section. */
1199                 if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) {
1200                         file_badread(ms);
1201                         return -1;
1202                 }
1203                 name[namesize] = '\0';
1204                 if (strcmp(name, ".debug_info") == 0)
1205                         stripped = 0;
1206
1207                 if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) {
1208                         file_badread(ms);
1209                         return -1;
1210                 }
1211                 off += size;
1212
1213                 /* Things we can determine before we seek */
1214                 switch (xsh_type) {
1215                 case SHT_SYMTAB:
1216 #if 0
1217                 case SHT_DYNSYM:
1218 #endif
1219                         stripped = 0;
1220                         break;
1221                 default:
1222                         if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) {
1223                                 /* Perhaps warn here */
1224                                 continue;
1225                         }
1226                         break;
1227                 }
1228
1229
1230                 /* Things we can determine when we seek */
1231                 switch (xsh_type) {
1232                 case SHT_NOTE:
1233                         if ((uintmax_t)(xsh_size + xsh_offset) >
1234                             (uintmax_t)fsize) {
1235                                 if (file_printf(ms,
1236                                     ", note offset/size 0x%" INTMAX_T_FORMAT
1237                                     "x+0x%" INTMAX_T_FORMAT "x exceeds"
1238                                     " file size 0x%" INTMAX_T_FORMAT "x",
1239                                     (uintmax_t)xsh_offset, (uintmax_t)xsh_size,
1240                                     (uintmax_t)fsize) == -1)
1241                                         return -1;
1242                                 return 0; 
1243                         }
1244                         if ((nbuf = malloc(xsh_size)) == NULL) {
1245                                 file_error(ms, errno, "Cannot allocate memory"
1246                                     " for note");
1247                                 return -1;
1248                         }
1249                         if (pread(fd, nbuf, xsh_size, xsh_offset) <
1250                             (ssize_t)xsh_size) {
1251                                 file_badread(ms);
1252                                 free(nbuf);
1253                                 return -1;
1254                         }
1255
1256                         noff = 0;
1257                         for (;;) {
1258                                 if (noff >= (off_t)xsh_size)
1259                                         break;
1260                                 noff = donote(ms, nbuf, (size_t)noff,
1261                                     xsh_size, clazz, swap, 4, flags, notecount,
1262                                     fd, 0, 0, 0);
1263                                 if (noff == 0)
1264                                         break;
1265                         }
1266                         free(nbuf);
1267                         break;
1268                 case SHT_SUNW_cap:
1269                         switch (mach) {
1270                         case EM_SPARC:
1271                         case EM_SPARCV9:
1272                         case EM_IA_64:
1273                         case EM_386:
1274                         case EM_AMD64:
1275                                 break;
1276                         default:
1277                                 goto skip;
1278                         }
1279
1280                         if (nbadcap > 5)
1281                                 break;
1282                         if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) {
1283                                 file_badseek(ms);
1284                                 return -1;
1285                         }
1286                         coff = 0;
1287                         for (;;) {
1288                                 Elf32_Cap cap32;
1289                                 Elf64_Cap cap64;
1290                                 char cbuf[/*CONSTCOND*/
1291                                     MAX(sizeof cap32, sizeof cap64)];
1292                                 if ((coff += xcap_sizeof) > (off_t)xsh_size)
1293                                         break;
1294                                 if (read(fd, cbuf, (size_t)xcap_sizeof) !=
1295                                     (ssize_t)xcap_sizeof) {
1296                                         file_badread(ms);
1297                                         return -1;
1298                                 }
1299                                 if (cbuf[0] == 'A') {
1300 #ifdef notyet
1301                                         char *p = cbuf + 1;
1302                                         uint32_t len, tag;
1303                                         memcpy(&len, p, sizeof(len));
1304                                         p += 4;
1305                                         len = getu32(swap, len);
1306                                         if (memcmp("gnu", p, 3) != 0) {
1307                                             if (file_printf(ms,
1308                                                 ", unknown capability %.3s", p)
1309                                                 == -1)
1310                                                 return -1;
1311                                             break;
1312                                         }
1313                                         p += strlen(p) + 1;
1314                                         tag = *p++;
1315                                         memcpy(&len, p, sizeof(len));
1316                                         p += 4;
1317                                         len = getu32(swap, len);
1318                                         if (tag != 1) {
1319                                             if (file_printf(ms, ", unknown gnu"
1320                                                 " capability tag %d", tag)
1321                                                 == -1)
1322                                                 return -1;
1323                                             break;
1324                                         }
1325                                         // gnu attributes 
1326 #endif
1327                                         break;
1328                                 }
1329                                 (void)memcpy(xcap_addr, cbuf, xcap_sizeof);
1330                                 switch (xcap_tag) {
1331                                 case CA_SUNW_NULL:
1332                                         break;
1333                                 case CA_SUNW_HW_1:
1334                                         cap_hw1 |= xcap_val;
1335                                         break;
1336                                 case CA_SUNW_SF_1:
1337                                         cap_sf1 |= xcap_val;
1338                                         break;
1339                                 default:
1340                                         if (file_printf(ms,
1341                                             ", with unknown capability "
1342                                             "0x%" INT64_T_FORMAT "x = 0x%"
1343                                             INT64_T_FORMAT "x",
1344                                             (unsigned long long)xcap_tag,
1345                                             (unsigned long long)xcap_val) == -1)
1346                                                 return -1;
1347                                         if (nbadcap++ > 2)
1348                                                 coff = xsh_size;
1349                                         break;
1350                                 }
1351                         }
1352                         /*FALLTHROUGH*/
1353                 skip:
1354                 default:
1355                         break;
1356                 }
1357         }
1358
1359         if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
1360                 return -1;
1361         if (cap_hw1) {
1362                 const cap_desc_t *cdp;
1363                 switch (mach) {
1364                 case EM_SPARC:
1365                 case EM_SPARC32PLUS:
1366                 case EM_SPARCV9:
1367                         cdp = cap_desc_sparc;
1368                         break;
1369                 case EM_386:
1370                 case EM_IA_64:
1371                 case EM_AMD64:
1372                         cdp = cap_desc_386;
1373                         break;
1374                 default:
1375                         cdp = NULL;
1376                         break;
1377                 }
1378                 if (file_printf(ms, ", uses") == -1)
1379                         return -1;
1380                 if (cdp) {
1381                         while (cdp->cd_name) {
1382                                 if (cap_hw1 & cdp->cd_mask) {
1383                                         if (file_printf(ms,
1384                                             " %s", cdp->cd_name) == -1)
1385                                                 return -1;
1386                                         cap_hw1 &= ~cdp->cd_mask;
1387                                 }
1388                                 ++cdp;
1389                         }
1390                         if (cap_hw1)
1391                                 if (file_printf(ms,
1392                                     " unknown hardware capability 0x%"
1393                                     INT64_T_FORMAT "x",
1394                                     (unsigned long long)cap_hw1) == -1)
1395                                         return -1;
1396                 } else {
1397                         if (file_printf(ms,
1398                             " hardware capability 0x%" INT64_T_FORMAT "x",
1399                             (unsigned long long)cap_hw1) == -1)
1400                                 return -1;
1401                 }
1402         }
1403         if (cap_sf1) {
1404                 if (cap_sf1 & SF1_SUNW_FPUSED) {
1405                         if (file_printf(ms,
1406                             (cap_sf1 & SF1_SUNW_FPKNWN)
1407                             ? ", uses frame pointer"
1408                             : ", not known to use frame pointer") == -1)
1409                                 return -1;
1410                 }
1411                 cap_sf1 &= ~SF1_SUNW_MASK;
1412                 if (cap_sf1)
1413                         if (file_printf(ms,
1414                             ", with unknown software capability 0x%"
1415                             INT64_T_FORMAT "x",
1416                             (unsigned long long)cap_sf1) == -1)
1417                                 return -1;
1418         }
1419         return 0;
1420 }
1421
1422 /*
1423  * Look through the program headers of an executable image, searching
1424  * for a PT_INTERP section; if one is found, it's dynamically linked,
1425  * otherwise it's statically linked.
1426  */
1427 private int
1428 dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
1429     int num, size_t size, off_t fsize, int sh_num, int *flags,
1430     uint16_t *notecount)
1431 {
1432         Elf32_Phdr ph32;
1433         Elf64_Phdr ph64;
1434         const char *linking_style = "statically";
1435         const char *interp = "";
1436         unsigned char nbuf[BUFSIZ];
1437         char ibuf[BUFSIZ];
1438         ssize_t bufsize;
1439         size_t offset, align, len;
1440         
1441         if (size != xph_sizeof) {
1442                 if (file_printf(ms, ", corrupted program header size") == -1)
1443                         return -1;
1444                 return 0;
1445         }
1446
1447         for ( ; num; num--) {
1448                 if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
1449                         file_badread(ms);
1450                         return -1;
1451                 }
1452
1453                 off += size;
1454                 bufsize = 0;
1455                 align = 4;
1456
1457                 /* Things we can determine before we seek */
1458                 switch (xph_type) {
1459                 case PT_DYNAMIC:
1460                         linking_style = "dynamically";
1461                         break;
1462                 case PT_NOTE:
1463                         if (sh_num)     /* Did this through section headers */
1464                                 continue;
1465                         if (((align = xph_align) & 0x80000000UL) != 0 ||
1466                             align < 4) {
1467                                 if (file_printf(ms, 
1468                                     ", invalid note alignment 0x%lx",
1469                                     (unsigned long)align) == -1)
1470                                         return -1;
1471                                 align = 4;
1472                         }
1473                         /*FALLTHROUGH*/
1474                 case PT_INTERP:
1475                         len = xph_filesz < sizeof(nbuf) ? xph_filesz
1476                             : sizeof(nbuf);
1477                         bufsize = pread(fd, nbuf, len, xph_offset);
1478                         if (bufsize == -1) {
1479                                 file_badread(ms);
1480                                 return -1;
1481                         }
1482                         break;
1483                 default:
1484                         if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
1485                                 /* Maybe warn here? */
1486                                 continue;
1487                         }
1488                         break;
1489                 }
1490
1491                 /* Things we can determine when we seek */
1492                 switch (xph_type) {
1493                 case PT_INTERP:
1494                         if (bufsize && nbuf[0]) {
1495                                 nbuf[bufsize - 1] = '\0';
1496                                 interp = (const char *)nbuf;
1497                         } else
1498                                 interp = "*empty*";
1499                         break;
1500                 case PT_NOTE:
1501                         /*
1502                          * This is a PT_NOTE section; loop through all the notes
1503                          * in the section.
1504                          */
1505                         offset = 0;
1506                         for (;;) {
1507                                 if (offset >= (size_t)bufsize)
1508                                         break;
1509                                 offset = donote(ms, nbuf, offset,
1510                                     (size_t)bufsize, clazz, swap, align,
1511                                     flags, notecount, fd, 0, 0, 0);
1512                                 if (offset == 0)
1513                                         break;
1514                         }
1515                         break;
1516                 default:
1517                         break;
1518                 }
1519         }
1520         if (file_printf(ms, ", %s linked", linking_style)
1521             == -1)
1522                 return -1;
1523         if (interp[0])
1524                 if (file_printf(ms, ", interpreter %s",
1525                     file_printable(ibuf, sizeof(ibuf), interp)) == -1)
1526                         return -1;
1527         return 0;
1528 }
1529
1530
1531 protected int
1532 file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
1533     size_t nbytes)
1534 {
1535         union {
1536                 int32_t l;
1537                 char c[sizeof (int32_t)];
1538         } u;
1539         int clazz;
1540         int swap;
1541         struct stat st;
1542         off_t fsize;
1543         int flags = 0;
1544         Elf32_Ehdr elf32hdr;
1545         Elf64_Ehdr elf64hdr;
1546         uint16_t type, phnum, shnum, notecount;
1547
1548         if (ms->flags & (MAGIC_MIME|MAGIC_APPLE|MAGIC_EXTENSION))
1549                 return 0;
1550         /*
1551          * ELF executables have multiple section headers in arbitrary
1552          * file locations and thus file(1) cannot determine it from easily.
1553          * Instead we traverse thru all section headers until a symbol table
1554          * one is found or else the binary is stripped.
1555          * Return immediately if it's not ELF (so we avoid pipe2file unless needed).
1556          */
1557         if (buf[EI_MAG0] != ELFMAG0
1558             || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
1559             || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
1560                 return 0;
1561
1562         /*
1563          * If we cannot seek, it must be a pipe, socket or fifo.
1564          */
1565         if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
1566                 fd = file_pipe2file(ms, fd, buf, nbytes);
1567
1568         if (fstat(fd, &st) == -1) {
1569                 file_badread(ms);
1570                 return -1;
1571         }
1572         if (S_ISREG(st.st_mode) || st.st_size != 0)
1573                 fsize = st.st_size;
1574         else
1575                 fsize = SIZE_UNKNOWN;
1576
1577         clazz = buf[EI_CLASS];
1578
1579         switch (clazz) {
1580         case ELFCLASS32:
1581 #undef elf_getu
1582 #define elf_getu(a, b)  elf_getu32(a, b)
1583 #undef elfhdr
1584 #define elfhdr elf32hdr
1585 #include "elfclass.h"
1586         case ELFCLASS64:
1587 #undef elf_getu
1588 #define elf_getu(a, b)  elf_getu64(a, b)
1589 #undef elfhdr
1590 #define elfhdr elf64hdr
1591 #include "elfclass.h"
1592         default:
1593             if (file_printf(ms, ", unknown class %d", clazz) == -1)
1594                     return -1;
1595             break;
1596         }
1597         return 0;
1598 }
1599 #endif