"Fossies" - the Fresh Open Source Software Archive

Member "file-5.35/src/readelf.c" (15 Oct 2018, 44359 Bytes) of package /linux/misc/file-5.35.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "readelf.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.34_vs_5.35.

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