[BACK]Return to readelf.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / file

Annotation of src/usr.bin/file/readelf.c, Revision 1.9

1.9     ! chl         1: /*     $OpenBSD: readelf.c,v 1.8 2004/05/19 02:32:35 tedu Exp $ */
1.5       ian         2: /*
1.8       tedu        3:  * Copyright (c) Christos Zoulas 2003.
                      4:  * All Rights Reserved.
1.5       ian         5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice immediately at the beginning of the file, without modification,
                     11:  *    this list of conditions, and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     17:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     19:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
                     20:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     21:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     22:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     24:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     26:  * SUCH DAMAGE.
                     27:  */
1.4       ian        28: #include "file.h"
1.1       millert    29:
                     30: #ifdef BUILTIN_ELF
                     31: #include <string.h>
                     32: #include <ctype.h>
                     33: #include <stdlib.h>
1.4       ian        34: #ifdef HAVE_UNISTD_H
1.1       millert    35: #include <unistd.h>
1.4       ian        36: #endif
1.1       millert    37:
                     38: #include "readelf.h"
1.4       ian        39:
                     40: #ifndef lint
1.9     ! chl        41: FILE_RCSID("@(#)$Id: readelf.c,v 1.8 2004/05/19 02:32:35 tedu Exp $")
1.4       ian        42: #endif
                     43:
                     44: #ifdef ELFCORE
1.9     ! chl        45: private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t,
        !            46:     off_t, int *);
1.4       ian        47: #endif
1.9     ! chl        48: private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t,
        !            49:     off_t, int *);
        !            50: private int doshn(struct magic_set *, int, int, int, off_t, int, size_t, int *);
1.8       tedu       51: private size_t donote(struct magic_set *, unsigned char *, size_t, size_t, int,
1.9     ! chl        52:     int, size_t, int *);
1.8       tedu       53:
                     54: #define        ELF_ALIGN(a)    ((((a) + align - 1) / align) * align)
                     55:
1.9     ! chl        56: #define isquote(c) (strchr("'\"`", (c)) != NULL)
        !            57:
1.8       tedu       58: private uint16_t getu16(int, uint16_t);
                     59: private uint32_t getu32(int, uint32_t);
                     60: private uint64_t getu64(int, uint64_t);
1.4       ian        61:
1.8       tedu       62: private uint16_t
1.4       ian        63: getu16(int swap, uint16_t value)
                     64: {
                     65:        union {
                     66:                uint16_t ui;
                     67:                char c[2];
                     68:        } retval, tmpval;
                     69:
                     70:        if (swap) {
                     71:                tmpval.ui = value;
                     72:
                     73:                retval.c[0] = tmpval.c[1];
                     74:                retval.c[1] = tmpval.c[0];
                     75:
                     76:                return retval.ui;
                     77:        } else
                     78:                return value;
                     79: }
                     80:
1.8       tedu       81: private uint32_t
1.4       ian        82: getu32(int swap, uint32_t value)
                     83: {
                     84:        union {
                     85:                uint32_t ui;
                     86:                char c[4];
                     87:        } retval, tmpval;
                     88:
                     89:        if (swap) {
                     90:                tmpval.ui = value;
                     91:
                     92:                retval.c[0] = tmpval.c[3];
                     93:                retval.c[1] = tmpval.c[2];
                     94:                retval.c[2] = tmpval.c[1];
                     95:                retval.c[3] = tmpval.c[0];
                     96:
                     97:                return retval.ui;
                     98:        } else
                     99:                return value;
                    100: }
                    101:
1.8       tedu      102: private uint64_t
1.4       ian       103: getu64(int swap, uint64_t value)
                    104: {
                    105:        union {
                    106:                uint64_t ui;
                    107:                char c[8];
                    108:        } retval, tmpval;
                    109:
                    110:        if (swap) {
                    111:                tmpval.ui = value;
                    112:
                    113:                retval.c[0] = tmpval.c[7];
                    114:                retval.c[1] = tmpval.c[6];
                    115:                retval.c[2] = tmpval.c[5];
                    116:                retval.c[3] = tmpval.c[4];
                    117:                retval.c[4] = tmpval.c[3];
                    118:                retval.c[5] = tmpval.c[2];
                    119:                retval.c[6] = tmpval.c[1];
                    120:                retval.c[7] = tmpval.c[0];
                    121:
                    122:                return retval.ui;
                    123:        } else
                    124:                return value;
                    125: }
                    126:
1.9     ! chl       127: #ifdef USE_ARRAY_FOR_64BIT_TYPES
        !           128: # define elf_getu64(swap, array) \
        !           129:        ((swap ? ((uint64_t)getu32(swap, array[0])) << 32 : getu32(swap, array[0])) + \
        !           130:         (swap ? getu32(swap, array[1]) : ((uint64_t)getu32(swap, array[1]) << 32)))
        !           131: #else
        !           132: # define elf_getu64(swap, value) getu64(swap, value)
        !           133: #endif
        !           134:
        !           135: #define xsh_addr       (class == ELFCLASS32            \
1.4       ian       136:                         ? (void *) &sh32               \
                    137:                         : (void *) &sh64)
1.9     ! chl       138: #define xsh_sizeof     (class == ELFCLASS32            \
1.4       ian       139:                         ? sizeof sh32                  \
                    140:                         : sizeof sh64)
1.9     ! chl       141: #define xsh_size       (class == ELFCLASS32            \
        !           142:                         ? getu32(swap, sh32.sh_size)   \
        !           143:                         : getu64(swap, sh64.sh_size))
        !           144: #define xsh_offset     (class == ELFCLASS32            \
        !           145:                         ? getu32(swap, sh32.sh_offset) \
        !           146:                         : getu64(swap, sh64.sh_offset))
        !           147: #define xsh_type       (class == ELFCLASS32            \
1.4       ian       148:                         ? getu32(swap, sh32.sh_type)   \
                    149:                         : getu32(swap, sh64.sh_type))
1.9     ! chl       150: #define xph_addr       (class == ELFCLASS32            \
1.4       ian       151:                         ? (void *) &ph32               \
                    152:                         : (void *) &ph64)
1.9     ! chl       153: #define xph_sizeof     (class == ELFCLASS32            \
1.4       ian       154:                         ? sizeof ph32                  \
                    155:                         : sizeof ph64)
1.9     ! chl       156: #define xph_type       (class == ELFCLASS32            \
1.4       ian       157:                         ? getu32(swap, ph32.p_type)    \
                    158:                         : getu32(swap, ph64.p_type))
1.9     ! chl       159: #define xph_offset     (off_t)(class == ELFCLASS32     \
1.4       ian       160:                         ? getu32(swap, ph32.p_offset)  \
                    161:                         : getu64(swap, ph64.p_offset))
1.9     ! chl       162: #define xph_align      (size_t)((class == ELFCLASS32   \
1.8       tedu      163:                         ? (off_t) (ph32.p_align ?      \
                    164:                            getu32(swap, ph32.p_align) : 4) \
                    165:                         : (off_t) (ph64.p_align ?      \
                    166:                            getu64(swap, ph64.p_align) : 4)))
1.9     ! chl       167: #define xph_filesz     (size_t)((class == ELFCLASS32   \
        !           168:                         ? getu32(swap, ph32.p_filesz)  \
        !           169:                         : getu64(swap, ph64.p_filesz)))
        !           170: #define xnh_addr       (class == ELFCLASS32            \
        !           171:                         ? (void *) &nh32               \
        !           172:                         : (void *) &nh64)
        !           173: #define xph_memsz      (size_t)((class == ELFCLASS32   \
        !           174:                         ? getu32(swap, ph32.p_memsz)   \
        !           175:                         : getu64(swap, ph64.p_memsz)))
        !           176: #define xnh_sizeof     (class == ELFCLASS32            \
1.8       tedu      177:                         ? sizeof nh32                  \
                    178:                         : sizeof nh64)
1.9     ! chl       179: #define xnh_type       (class == ELFCLASS32            \
1.8       tedu      180:                         ? getu32(swap, nh32.n_type)    \
                    181:                         : getu32(swap, nh64.n_type))
1.9     ! chl       182: #define xnh_namesz     (class == ELFCLASS32            \
1.8       tedu      183:                         ? getu32(swap, nh32.n_namesz)  \
                    184:                         : getu32(swap, nh64.n_namesz))
1.9     ! chl       185: #define xnh_descsz     (class == ELFCLASS32            \
1.8       tedu      186:                         ? getu32(swap, nh32.n_descsz)  \
                    187:                         : getu32(swap, nh64.n_descsz))
1.4       ian       188: #define prpsoffsets(i) (class == ELFCLASS32            \
                    189:                         ? prpsoffsets32[i]             \
                    190:                         : prpsoffsets64[i])
1.1       millert   191:
1.4       ian       192: #ifdef ELFCORE
                    193: size_t prpsoffsets32[] = {
                    194:        8,              /* FreeBSD */
1.9     ! chl       195:        28,             /* Linux 2.0.36 (short name) */
        !           196:        44,             /* Linux (path name) */
1.4       ian       197:        84,             /* SunOS 5.x */
                    198: };
                    199:
                    200: size_t prpsoffsets64[] = {
1.9     ! chl       201:        16,             /* FreeBSD, 64-bit */
        !           202:        40,             /* Linux (tested on core from 2.4.x, short name) */
        !           203:        56,             /* Linux (path name) */
        !           204:        120,            /* SunOS 5.x, 64-bit */
1.1       millert   205: };
                    206:
1.4       ian       207: #define        NOFFSETS32      (sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
                    208: #define NOFFSETS64     (sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
                    209:
                    210: #define NOFFSETS       (class == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
1.1       millert   211:
                    212: /*
                    213:  * Look through the program headers of an executable image, searching
1.4       ian       214:  * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
                    215:  * "FreeBSD"; if one is found, try looking in various places in its
                    216:  * contents for a 16-character string containing only printable
                    217:  * characters - if found, that string should be the name of the program
                    218:  * that dropped core.  Note: right after that 16-character string is,
                    219:  * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
                    220:  * Linux, a longer string (80 characters, in 5.x, probably other
                    221:  * SVR4-flavored systems, and Linux) containing the start of the
                    222:  * command line for that program.
                    223:  *
                    224:  * The signal number probably appears in a section of type NT_PRSTATUS,
                    225:  * but that's also rather OS-dependent, in ways that are harder to
                    226:  * dissect with heuristics, so I'm not bothering with the signal number.
                    227:  * (I suppose the signal number could be of interest in situations where
                    228:  * you don't have the binary of the program that dropped core; if you
                    229:  * *do* have that binary, the debugger will probably tell you what
                    230:  * signal it was.)
1.1       millert   231:  */
1.4       ian       232:
                    233: #define        OS_STYLE_SVR4           0
                    234: #define        OS_STYLE_FREEBSD        1
                    235: #define        OS_STYLE_NETBSD         2
                    236:
1.8       tedu      237: private const char *os_style_names[] = {
1.4       ian       238:        "SVR4",
                    239:        "FreeBSD",
                    240:        "NetBSD",
                    241: };
                    242:
1.9     ! chl       243: #define FLAGS_DID_CORE         1
        !           244: #define FLAGS_DID_NOTE         2
        !           245:
1.8       tedu      246: private int
                    247: dophn_core(struct magic_set *ms, int class, int swap, int fd, off_t off,
1.9     ! chl       248:     int num, size_t size, off_t fsize, int *flags)
1.1       millert   249: {
1.4       ian       250:        Elf32_Phdr ph32;
                    251:        Elf64_Phdr ph64;
1.8       tedu      252:        size_t offset;
                    253:        unsigned char nbuf[BUFSIZ];
                    254:        ssize_t bufsize;
1.9     ! chl       255:        off_t savedoffset;
        !           256:        struct stat st;
1.8       tedu      257:
1.9     ! chl       258:        if (fstat(fd, &st) < 0) {
        !           259:                file_badread(ms);
        !           260:                return -1;
        !           261:        }
        !           262:
        !           263:        if (size != xph_sizeof) {
1.8       tedu      264:                if (file_printf(ms, ", corrupted program header size") == -1)
                    265:                        return -1;
                    266:                return 0;
                    267:        }
1.9     ! chl       268:
1.4       ian       269:        /*
                    270:         * Loop through all the program headers.
                    271:         */
1.1       millert   272:        for ( ; num; num--) {
1.9     ! chl       273:                if ((savedoffset = lseek(fd, off, SEEK_SET)) == (off_t)-1) {
1.8       tedu      274:                        file_badseek(ms);
                    275:                        return -1;
                    276:                }
1.9     ! chl       277:                if (read(fd, xph_addr, xph_sizeof) == -1) {
1.8       tedu      278:                        file_badread(ms);
                    279:                        return -1;
                    280:                }
1.9     ! chl       281:                if (xph_offset > fsize) {
        !           282:                        if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
        !           283:                                file_badseek(ms);
        !           284:                                return -1;
        !           285:                        }
        !           286:                        continue;
        !           287:                }
        !           288:
1.1       millert   289:                off += size;
1.9     ! chl       290:                if (xph_type != PT_NOTE)
1.1       millert   291:                        continue;
1.4       ian       292:
                    293:                /*
                    294:                 * This is a PT_NOTE section; loop through all the notes
                    295:                 * in the section.
                    296:                 */
1.9     ! chl       297:                if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) {
1.8       tedu      298:                        file_badseek(ms);
                    299:                        return -1;
                    300:                }
1.9     ! chl       301:                bufsize = read(fd, nbuf,
        !           302:                    ((xph_filesz < sizeof(nbuf)) ? xph_filesz : sizeof(nbuf)));
1.8       tedu      303:                if (bufsize == -1) {
                    304:                        file_badread(ms);
                    305:                        return -1;
                    306:                }
1.1       millert   307:                offset = 0;
                    308:                for (;;) {
1.8       tedu      309:                        if (offset >= (size_t)bufsize)
                    310:                                break;
                    311:                        offset = donote(ms, nbuf, offset, (size_t)bufsize,
1.9     ! chl       312:                            class, swap, 4, flags);
1.8       tedu      313:                        if (offset == 0)
1.1       millert   314:                                break;
                    315:
1.8       tedu      316:                }
                    317:        }
                    318:        return 0;
                    319: }
                    320: #endif
                    321:
                    322: private size_t
                    323: donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size,
1.9     ! chl       324:     int class, int swap, size_t align, int *flags)
1.8       tedu      325: {
                    326:        Elf32_Nhdr nh32;
                    327:        Elf64_Nhdr nh64;
                    328:        size_t noff, doff;
                    329: #ifdef ELFCORE
                    330:        int os_style = -1;
                    331: #endif
                    332:        uint32_t namesz, descsz;
                    333:
1.9     ! chl       334:        (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
        !           335:        offset += xnh_sizeof;
1.8       tedu      336:
1.9     ! chl       337:        namesz = xnh_namesz;
        !           338:        descsz = xnh_descsz;
1.8       tedu      339:        if ((namesz == 0) && (descsz == 0)) {
                    340:                /*
                    341:                 * We're out of note headers.
                    342:                 */
1.9     ! chl       343:                return (offset >= size) ? offset : size;
1.8       tedu      344:        }
                    345:
                    346:        if (namesz & 0x80000000) {
                    347:            (void)file_printf(ms, ", bad note name size 0x%lx",
                    348:                (unsigned long)namesz);
                    349:            return offset;
                    350:        }
                    351:
                    352:        if (descsz & 0x80000000) {
                    353:            (void)file_printf(ms, ", bad note description size 0x%lx",
                    354:                (unsigned long)descsz);
                    355:            return offset;
                    356:        }
                    357:
                    358:
                    359:        noff = offset;
                    360:        doff = ELF_ALIGN(offset + namesz);
                    361:
1.9     ! chl       362:        if (offset + namesz > size) {
1.8       tedu      363:                /*
                    364:                 * We're past the end of the buffer.
                    365:                 */
                    366:                return doff;
                    367:        }
                    368:
                    369:        offset = ELF_ALIGN(doff + descsz);
1.9     ! chl       370:        if (doff + descsz > size) {
        !           371:                /*
        !           372:                 * We're past the end of the buffer.
        !           373:                 */
        !           374:                return (offset >= size) ? offset : size;
1.8       tedu      375:        }
                    376:
1.9     ! chl       377:        if (*flags & FLAGS_DID_NOTE)
        !           378:                goto core;
        !           379:
1.8       tedu      380:        if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
1.9     ! chl       381:            xnh_type == NT_GNU_VERSION && descsz == 16) {
1.8       tedu      382:                uint32_t desc[4];
                    383:                (void)memcpy(desc, &nbuf[doff], sizeof(desc));
                    384:
                    385:                if (file_printf(ms, ", for GNU/") == -1)
                    386:                        return size;
                    387:                switch (getu32(swap, desc[0])) {
                    388:                case GNU_OS_LINUX:
                    389:                        if (file_printf(ms, "Linux") == -1)
                    390:                                return size;
                    391:                        break;
                    392:                case GNU_OS_HURD:
                    393:                        if (file_printf(ms, "Hurd") == -1)
                    394:                                return size;
                    395:                        break;
                    396:                case GNU_OS_SOLARIS:
                    397:                        if (file_printf(ms, "Solaris") == -1)
                    398:                                return size;
                    399:                        break;
                    400:                default:
                    401:                        if (file_printf(ms, "<unknown>") == -1)
                    402:                                return size;
                    403:                }
                    404:                if (file_printf(ms, " %d.%d.%d", getu32(swap, desc[1]),
                    405:                    getu32(swap, desc[2]), getu32(swap, desc[3])) == -1)
                    406:                        return size;
1.9     ! chl       407:                *flags |= FLAGS_DID_NOTE;
1.8       tedu      408:                return size;
                    409:        }
                    410:
                    411:        if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 &&
1.9     ! chl       412:            xnh_type == NT_NETBSD_VERSION && descsz == 4) {
1.8       tedu      413:                uint32_t desc;
                    414:                (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
                    415:                desc = getu32(swap, desc);
                    416:
                    417:                if (file_printf(ms, ", for NetBSD") == -1)
                    418:                        return size;
                    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) {
1.9     ! chl       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;
1.8       tedu      436:
                    437:                        if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1)
                    438:                                return size;
                    439:                        if (ver_rel == 0 && ver_patch != 0) {
                    440:                                if (file_printf(ms, ".%u", ver_patch) == -1)
                    441:                                        return size;
                    442:                        } else if (ver_rel != 0) {
                    443:                                while (ver_rel > 26) {
1.9     ! chl       444:                                        if (file_printf(ms, "Z") == -1)
        !           445:                                                return size;
1.8       tedu      446:                                        ver_rel -= 26;
                    447:                                }
1.9     ! chl       448:                                if (file_printf(ms, "%c", 'A' + ver_rel - 1)
        !           449:                                    == -1)
        !           450:                                        return size;
1.1       millert   451:                        }
1.8       tedu      452:                }
1.9     ! chl       453:                *flags |= FLAGS_DID_NOTE;
1.8       tedu      454:                return size;
                    455:        }
1.4       ian       456:
1.8       tedu      457:        if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 &&
1.9     ! chl       458:            xnh_type == NT_FREEBSD_VERSION && descsz == 4) {
1.8       tedu      459:                uint32_t desc;
                    460:                (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
                    461:                desc = getu32(swap, desc);
                    462:                if (file_printf(ms, ", for FreeBSD") == -1)
                    463:                        return size;
1.1       millert   464:
1.8       tedu      465:                /*
                    466:                 * Contents is __FreeBSD_version, whose relation to OS
1.9     ! chl       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.
1.8       tedu      490:                 */
1.9     ! chl       491:                if (desc == 460002) {
        !           492:                        if (file_printf(ms, " 4.6.2") == -1)
        !           493:                                return size;
        !           494:                } else if (desc < 460100) {
1.8       tedu      495:                        if (file_printf(ms, " %d.%d", desc / 100000,
                    496:                            desc / 10000 % 10) == -1)
                    497:                                return size;
                    498:                        if (desc / 1000 % 10 > 0)
                    499:                                if (file_printf(ms, ".%d", desc / 1000 % 10)
                    500:                                    == -1)
                    501:                                        return size;
1.9     ! chl       502:                        if ((desc % 1000 > 0) || (desc % 100000 == 0))
        !           503:                                if (file_printf(ms, " (%d)", desc) == -1)
        !           504:                                        return size;
        !           505:                } else if (desc < 500000) {
        !           506:                        if (file_printf(ms, " %d.%d", desc / 100000,
        !           507:                            desc / 10000 % 10 + desc / 1000 % 10) == -1)
        !           508:                                return size;
        !           509:                        if (desc / 100 % 10 > 0) {
        !           510:                                if (file_printf(ms, " (%d)", desc) == -1)
        !           511:                                        return size;
        !           512:                        } else if (desc / 10 % 10 > 0) {
        !           513:                                if (file_printf(ms, ".%d", desc / 10 % 10)
        !           514:                                    == -1)
        !           515:                                        return size;
        !           516:                        }
1.8       tedu      517:                } else {
                    518:                        if (file_printf(ms, " %d.%d", desc / 100000,
                    519:                            desc / 1000 % 100) == -1)
                    520:                                return size;
1.9     ! chl       521:                        if ((desc / 100 % 10 > 0) ||
        !           522:                            (desc % 100000 / 100 == 0)) {
        !           523:                                if (file_printf(ms, " (%d)", desc) == -1)
1.8       tedu      524:                                        return size;
1.9     ! chl       525:                        } else if (desc / 10 % 10 > 0) {
        !           526:                                if (file_printf(ms, ".%d", desc / 10 % 10)
        !           527:                                    == -1)
1.8       tedu      528:                                        return size;
1.4       ian       529:                        }
1.8       tedu      530:                }
1.9     ! chl       531:                *flags |= FLAGS_DID_NOTE;
1.8       tedu      532:                return size;
                    533:        }
                    534:
                    535:        if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
1.9     ! chl       536:            xnh_type == NT_OPENBSD_VERSION && descsz == 4) {
1.8       tedu      537:                if (file_printf(ms, ", for OpenBSD") == -1)
                    538:                        return size;
                    539:                /* Content of note is always 0 */
1.9     ! chl       540:                *flags |= FLAGS_DID_NOTE;
1.8       tedu      541:                return size;
                    542:        }
                    543:
1.9     ! chl       544:        if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
        !           545:            xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) {
        !           546:                uint32_t desc;
        !           547:                if (file_printf(ms, ", for DragonFly") == -1)
        !           548:                        return size;
        !           549:                (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
        !           550:                desc = getu32(swap, desc);
        !           551:                if (file_printf(ms, " %d.%d.%d", desc / 100000,
        !           552:                    desc / 10000 % 10, desc % 10000) == -1)
        !           553:                        return size;
        !           554:                *flags |= FLAGS_DID_NOTE;
        !           555:                return size;
        !           556:        }
        !           557:
        !           558: core:
1.8       tedu      559:        /*
                    560:         * Sigh.  The 2.0.36 kernel in Debian 2.1, at
                    561:         * least, doesn't correctly implement name
                    562:         * sections, in core dumps, as specified by
                    563:         * the "Program Linking" section of "UNIX(R) System
                    564:         * V Release 4 Programmer's Guide: ANSI C and
                    565:         * Programming Support Tools", because my copy
                    566:         * clearly says "The first 'namesz' bytes in 'name'
                    567:         * contain a *null-terminated* [emphasis mine]
                    568:         * character representation of the entry's owner
                    569:         * or originator", but the 2.0.36 kernel code
                    570:         * doesn't include the terminating null in the
                    571:         * name....
                    572:         */
                    573:        if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) ||
                    574:            (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) {
                    575:                os_style = OS_STYLE_SVR4;
                    576:        }
                    577:
                    578:        if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) {
                    579:                os_style = OS_STYLE_FREEBSD;
                    580:        }
                    581:
                    582:        if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11)
                    583:            == 0)) {
                    584:                os_style = OS_STYLE_NETBSD;
                    585:        }
1.4       ian       586:
1.8       tedu      587: #ifdef ELFCORE
1.9     ! chl       588:        if ((*flags & FLAGS_DID_CORE) != 0)
        !           589:                return size;
        !           590:
        !           591:        if (os_style != -1) {
        !           592:                if (file_printf(ms, ", %s-style", os_style_names[os_style])
        !           593:                    == -1)
1.8       tedu      594:                        return size;
1.9     ! chl       595:        }
1.4       ian       596:
1.9     ! chl       597:        switch (os_style) {
        !           598:        case OS_STYLE_NETBSD:
        !           599:                if (xnh_type == NT_NETBSD_CORE_PROCINFO) {
        !           600:                        uint32_t signo;
        !           601:                        /*
        !           602:                         * Extract the program name.  It is at
        !           603:                         * offset 0x7c, and is up to 32-bytes,
        !           604:                         * including the terminating NUL.
        !           605:                         */
        !           606:                        if (file_printf(ms, ", from '%.31s'",
        !           607:                            &nbuf[doff + 0x7c]) == -1)
        !           608:                                return size;
        !           609:
        !           610:                        /*
        !           611:                         * Extract the signal number.  It is at
        !           612:                         * offset 0x08.
        !           613:                         */
        !           614:                        (void)memcpy(&signo, &nbuf[doff + 0x08],
        !           615:                            sizeof(signo));
        !           616:                        if (file_printf(ms, " (signal %u)",
        !           617:                            getu32(swap, signo)) == -1)
        !           618:                                return size;
1.8       tedu      619:                        return size;
1.9     ! chl       620:                }
        !           621:                break;
1.8       tedu      622:
1.9     ! chl       623:        default:
        !           624:                if (xnh_type == NT_PRPSINFO) {
        !           625:                        size_t i, j;
        !           626:                        unsigned char c;
        !           627:                        /*
        !           628:                         * Extract the program name.  We assume
        !           629:                         * it to be 16 characters (that's what it
        !           630:                         * is in SunOS 5.x and Linux).
        !           631:                         *
        !           632:                         * Unfortunately, it's at a different offset
        !           633:                         * in various OSes, so try multiple offsets.
        !           634:                         * If the characters aren't all printable,
        !           635:                         * reject it.
        !           636:                         */
        !           637:                        for (i = 0; i < NOFFSETS; i++) {
        !           638:                                size_t reloffset = prpsoffsets(i);
        !           639:                                size_t noffset = doff + reloffset;
        !           640:                                for (j = 0; j < 16; j++, noffset++,
        !           641:                                    reloffset++) {
1.8       tedu      642:                                        /*
1.9     ! chl       643:                                         * Make sure we're not past
        !           644:                                         * the end of the buffer; if
        !           645:                                         * we are, just give up.
1.8       tedu      646:                                         */
1.9     ! chl       647:                                        if (noffset >= size)
1.8       tedu      648:                                                goto tryanother;
1.9     ! chl       649:
1.1       millert   650:                                        /*
1.9     ! chl       651:                                         * Make sure we're not past
        !           652:                                         * the end of the contents;
        !           653:                                         * if we are, this obviously
        !           654:                                         * isn't the right offset.
1.1       millert   655:                                         */
1.9     ! chl       656:                                        if (reloffset >= descsz)
1.8       tedu      657:                                                goto tryanother;
1.9     ! chl       658:
        !           659:                                        c = nbuf[noffset];
        !           660:                                        if (c == '\0') {
        !           661:                                                /*
        !           662:                                                 * A '\0' at the
        !           663:                                                 * beginning is
        !           664:                                                 * obviously wrong.
        !           665:                                                 * Any other '\0'
        !           666:                                                 * means we're done.
        !           667:                                                 */
        !           668:                                                if (j == 0)
        !           669:                                                        goto tryanother;
        !           670:                                                else
        !           671:                                                        break;
        !           672:                                        } else {
        !           673:                                                /*
        !           674:                                                 * A nonprintable
        !           675:                                                 * character is also
        !           676:                                                 * wrong.
        !           677:                                                 */
        !           678:                                                if (!isprint(c) || isquote(c))
        !           679:                                                        goto tryanother;
        !           680:                                        }
1.8       tedu      681:                                }
1.9     ! chl       682:                                /*
        !           683:                                 * Well, that worked.
        !           684:                                 */
        !           685:                                if (file_printf(ms, ", from '%.16s'",
        !           686:                                    &nbuf[doff + prpsoffsets(i)]) == -1)
        !           687:                                        return size;
1.8       tedu      688:                                return size;
                    689:
1.9     ! chl       690:                        tryanother:
        !           691:                                ;
        !           692:                        }
1.8       tedu      693:                }
1.9     ! chl       694:                break;
1.8       tedu      695:        }
                    696: #endif
1.9     ! chl       697:        *flags |= FLAGS_DID_CORE;
1.8       tedu      698:        return offset;
                    699: }
                    700:
                    701: private int
                    702: doshn(struct magic_set *ms, int class, int swap, int fd, off_t off, int num,
1.9     ! chl       703:     size_t size, int *flags)
1.8       tedu      704: {
                    705:        Elf32_Shdr sh32;
                    706:        Elf64_Shdr sh64;
1.9     ! chl       707:        int stripped = 1;
        !           708:        void *nbuf;
        !           709:        off_t noff;
1.8       tedu      710:
1.9     ! chl       711:        if (size != xsh_sizeof) {
1.8       tedu      712:                if (file_printf(ms, ", corrupted section header size") == -1)
                    713:                        return -1;
                    714:                return 0;
                    715:        }
                    716:
                    717:        if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
                    718:                file_badseek(ms);
                    719:                return -1;
                    720:        }
                    721:
                    722:        for ( ; num; num--) {
1.9     ! chl       723:                if (read(fd, xsh_addr, xsh_sizeof) == -1) {
1.8       tedu      724:                        file_badread(ms);
                    725:                        return -1;
                    726:                }
1.9     ! chl       727:                switch (xsh_type) {
        !           728:                case SHT_SYMTAB:
        !           729: #if 0
        !           730:                case SHT_DYNSYM:
        !           731: #endif
        !           732:                        stripped = 0;
        !           733:                        break;
        !           734:                case SHT_NOTE:
        !           735:                        if ((off = lseek(fd, (off_t)0, SEEK_CUR)) ==
        !           736:                            (off_t)-1) {
        !           737:                                file_badread(ms);
        !           738:                                return -1;
        !           739:                        }
        !           740:                        if ((nbuf = malloc((size_t)xsh_size)) == NULL) {
        !           741:                                file_error(ms, errno, "Cannot allocate memory"
        !           742:                                    " for note");
        !           743:                                return -1;
        !           744:                        }
        !           745:                        if ((noff = lseek(fd, (off_t)xsh_offset, SEEK_SET)) ==
        !           746:                            (off_t)-1) {
        !           747:                                file_badread(ms);
        !           748:                                free(nbuf);
        !           749:                                return -1;
        !           750:                        }
        !           751:                        if (read(fd, nbuf, (size_t)xsh_size) !=
        !           752:                            (ssize_t)xsh_size) {
        !           753:                                free(nbuf);
        !           754:                                file_badread(ms);
        !           755:                                return -1;
        !           756:                        }
        !           757:
        !           758:                        noff = 0;
        !           759:                        for (;;) {
        !           760:                                if (noff >= (size_t)xsh_size)
        !           761:                                        break;
        !           762:                                noff = donote(ms, nbuf, (size_t)noff,
        !           763:                                    (size_t)xsh_size, class, swap, 4,
        !           764:                                    flags);
        !           765:                                if (noff == 0)
        !           766:                                        break;
        !           767:                        }
        !           768:                        if ((lseek(fd, off, SEEK_SET)) == (off_t)-1) {
        !           769:                                free(nbuf);
        !           770:                                file_badread(ms);
1.8       tedu      771:                                return -1;
1.9     ! chl       772:                        }
        !           773:                        free(nbuf);
        !           774:                        break;
1.8       tedu      775:                }
                    776:        }
1.9     ! chl       777:        if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
1.8       tedu      778:                return -1;
                    779:        return 0;
                    780: }
                    781:
                    782: /*
                    783:  * Look through the program headers of an executable image, searching
                    784:  * for a PT_INTERP section; if one is found, it's dynamically linked,
                    785:  * otherwise it's statically linked.
                    786:  */
                    787: private int
                    788: dophn_exec(struct magic_set *ms, int class, int swap, int fd, off_t off,
1.9     ! chl       789:     int num, size_t size, off_t fsize, int *flags)
1.8       tedu      790: {
                    791:        Elf32_Phdr ph32;
                    792:        Elf64_Phdr ph64;
                    793:        const char *linking_style = "statically";
                    794:        const char *shared_libraries = "";
                    795:        unsigned char nbuf[BUFSIZ];
                    796:        int bufsize;
                    797:        size_t offset, align;
1.9     ! chl       798:        off_t savedoffset = (off_t)-1;
        !           799:        struct stat st;
1.8       tedu      800:
1.9     ! chl       801:        if (fstat(fd, &st) < 0) {
        !           802:                file_badread(ms);
        !           803:                return -1;
        !           804:        }
        !           805:
        !           806:        if (size != xph_sizeof) {
1.8       tedu      807:                if (file_printf(ms, ", corrupted program header size") == -1)
                    808:                    return -1;
                    809:                return 0;
                    810:        }
1.9     ! chl       811:
1.8       tedu      812:        if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
                    813:                file_badseek(ms);
                    814:                return -1;
                    815:        }
                    816:
                    817:        for ( ; num; num--) {
1.9     ! chl       818:                if (read(fd, xph_addr, xph_sizeof) == -1) {
1.8       tedu      819:                        file_badread(ms);
                    820:                        return -1;
                    821:                }
1.9     ! chl       822:                if (xph_offset > st.st_size && savedoffset != (off_t)-1) {
        !           823:                        if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
        !           824:                                file_badseek(ms);
        !           825:                                return -1;
        !           826:                        }
        !           827:                        continue;
        !           828:                }
        !           829:
1.8       tedu      830:                if ((savedoffset = lseek(fd, (off_t)0, SEEK_CUR)) == (off_t)-1) {
                    831:                        file_badseek(ms);
                    832:                        return -1;
                    833:                }
                    834:
1.9     ! chl       835:                if (xph_offset > fsize) {
        !           836:                        if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
        !           837:                                file_badseek(ms);
        !           838:                                return -1;
        !           839:                        }
        !           840:                        continue;
        !           841:                }
        !           842:
        !           843:                switch (xph_type) {
1.8       tedu      844:                case PT_DYNAMIC:
                    845:                        linking_style = "dynamically";
                    846:                        break;
                    847:                case PT_INTERP:
                    848:                        shared_libraries = " (uses shared libs)";
                    849:                        break;
                    850:                case PT_NOTE:
1.9     ! chl       851:                        if ((align = xph_align) & 0x80000000) {
1.8       tedu      852:                                if (file_printf(ms,
                    853:                                    ", invalid note alignment 0x%lx",
                    854:                                    (unsigned long)align) == -1)
                    855:                                        return -1;
                    856:                                align = 4;
                    857:                        }
                    858:                        /*
                    859:                         * This is a PT_NOTE section; loop through all the notes
                    860:                         * in the section.
                    861:                         */
1.9     ! chl       862:                        if (lseek(fd, xph_offset, SEEK_SET)
1.8       tedu      863:                            == (off_t)-1) {
                    864:                                file_badseek(ms);
                    865:                                return -1;
                    866:                        }
1.9     ! chl       867:                        bufsize = read(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ?
        !           868:                            xph_filesz : sizeof(nbuf)));
1.8       tedu      869:                        if (bufsize == -1) {
                    870:                                file_badread(ms);
                    871:                                return -1;
                    872:                        }
                    873:                        offset = 0;
                    874:                        for (;;) {
                    875:                                if (offset >= (size_t)bufsize)
                    876:                                        break;
                    877:                                offset = donote(ms, nbuf, offset,
1.9     ! chl       878:                                    (size_t)bufsize, class, swap, align,
        !           879:                                    flags);
1.8       tedu      880:                                if (offset == 0)
1.4       ian       881:                                        break;
1.1       millert   882:                        }
1.9     ! chl       883:                        if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
1.8       tedu      884:                                file_badseek(ms);
                    885:                                return -1;
                    886:                        }
                    887:                        break;
1.1       millert   888:                }
                    889:        }
1.8       tedu      890:        if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries)
                    891:            == -1)
                    892:            return -1;
                    893:        return 0;
1.1       millert   894: }
                    895:
1.8       tedu      896:
                    897: protected int
                    898: file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
                    899:     size_t nbytes)
1.1       millert   900: {
                    901:        union {
1.3       itojun    902:                int32_t l;
                    903:                char c[sizeof (int32_t)];
1.1       millert   904:        } u;
1.4       ian       905:        int class;
                    906:        int swap;
1.9     ! chl       907:        struct stat st;
        !           908:        off_t fsize;
        !           909:        int flags = 0;
1.4       ian       910:
                    911:        /*
1.8       tedu      912:         * If we cannot seek, it must be a pipe, socket or fifo.
1.4       ian       913:         */
                    914:        if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
1.8       tedu      915:                fd = file_pipe2file(ms, fd, buf, nbytes);
1.1       millert   916:
1.9     ! chl       917:        if (fstat(fd, &st) == -1) {
        !           918:                file_badread(ms);
        !           919:                return -1;
        !           920:        }
        !           921:        fsize = st.st_size;
        !           922:
1.1       millert   923:        /*
                    924:         * ELF executables have multiple section headers in arbitrary
                    925:         * file locations and thus file(1) cannot determine it from easily.
                    926:         * Instead we traverse thru all section headers until a symbol table
                    927:         * one is found or else the binary is stripped.
                    928:         */
1.4       ian       929:        if (buf[EI_MAG0] != ELFMAG0
                    930:            || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
1.1       millert   931:            || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
1.8       tedu      932:            return 0;
1.1       millert   933:
                    934:
1.9     ! chl       935:        class = buf[EI_CLASS];
1.4       ian       936:
                    937:        if (class == ELFCLASS32) {
1.1       millert   938:                Elf32_Ehdr elfhdr;
                    939:                if (nbytes <= sizeof (Elf32_Ehdr))
1.8       tedu      940:                        return 0;
1.1       millert   941:
                    942:
                    943:                u.l = 1;
                    944:                (void) memcpy(&elfhdr, buf, sizeof elfhdr);
1.9     ! chl       945:                swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
1.4       ian       946:
1.8       tedu      947:                if (getu16(swap, elfhdr.e_type) == ET_CORE) {
1.4       ian       948: #ifdef ELFCORE
1.8       tedu      949:                        if (dophn_core(ms, class, swap, fd,
                    950:                            (off_t)getu32(swap, elfhdr.e_phoff),
                    951:                            getu16(swap, elfhdr.e_phnum),
1.9     ! chl       952:                            (size_t)getu16(swap, elfhdr.e_phentsize),
        !           953:                            fsize, &flags) == -1)
1.8       tedu      954:                                return -1;
1.4       ian       955: #else
                    956:                        ;
                    957: #endif
1.8       tedu      958:                } else {
1.4       ian       959:                        if (getu16(swap, elfhdr.e_type) == ET_EXEC) {
1.8       tedu      960:                                if (dophn_exec(ms, class, swap,
                    961:                                    fd, (off_t)getu32(swap, elfhdr.e_phoff),
                    962:                                    getu16(swap, elfhdr.e_phnum),
1.9     ! chl       963:                                    (size_t)getu16(swap, elfhdr.e_phentsize),
        !           964:                                    fsize, &flags)
1.8       tedu      965:                                    == -1)
                    966:                                        return -1;
1.1       millert   967:                        }
1.8       tedu      968:                        if (doshn(ms, class, swap, fd,
                    969:                            (off_t)getu32(swap, elfhdr.e_shoff),
                    970:                            getu16(swap, elfhdr.e_shnum),
1.9     ! chl       971:                            (size_t)getu16(swap, elfhdr.e_shentsize),
        !           972:                            &flags) == -1)
1.8       tedu      973:                                return -1;
1.1       millert   974:                }
1.8       tedu      975:                return 1;
1.1       millert   976:        }
                    977:
1.4       ian       978:         if (class == ELFCLASS64) {
1.1       millert   979:                Elf64_Ehdr elfhdr;
                    980:                if (nbytes <= sizeof (Elf64_Ehdr))
1.8       tedu      981:                        return 0;
1.1       millert   982:
                    983:
                    984:                u.l = 1;
                    985:                (void) memcpy(&elfhdr, buf, sizeof elfhdr);
1.9     ! chl       986:                swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
1.1       millert   987:
1.8       tedu      988:                if (getu16(swap, elfhdr.e_type) == ET_CORE) {
1.4       ian       989: #ifdef ELFCORE
1.8       tedu      990:                        if (dophn_core(ms, class, swap, fd,
1.9     ! chl       991:                            (off_t)elf_getu64(swap, elfhdr.e_phoff),
1.8       tedu      992:                            getu16(swap, elfhdr.e_phnum),
1.9     ! chl       993:                            (size_t)getu16(swap, elfhdr.e_phentsize),
        !           994:                            fsize, &flags) == -1)
1.8       tedu      995:                                return -1;
1.4       ian       996: #else
                    997:                        ;
1.1       millert   998: #endif
1.8       tedu      999:                } else {
1.4       ian      1000:                        if (getu16(swap, elfhdr.e_type) == ET_EXEC) {
1.8       tedu     1001:                                if (dophn_exec(ms, class, swap, fd,
1.9     ! chl      1002:                                    (off_t)elf_getu64(swap, elfhdr.e_phoff),
1.8       tedu     1003:                                    getu16(swap, elfhdr.e_phnum),
1.9     ! chl      1004:                                    (size_t)getu16(swap, elfhdr.e_phentsize),
        !          1005:                                    fsize, &flags) == -1)
1.8       tedu     1006:                                        return -1;
1.1       millert  1007:                        }
1.8       tedu     1008:                        if (doshn(ms, class, swap, fd,
1.9     ! chl      1009:                            (off_t)elf_getu64(swap, elfhdr.e_shoff),
1.8       tedu     1010:                            getu16(swap, elfhdr.e_shnum),
1.9     ! chl      1011:                            (size_t)getu16(swap, elfhdr.e_shentsize), &flags)
        !          1012:                            == -1)
1.8       tedu     1013:                                return -1;
1.1       millert  1014:                }
1.8       tedu     1015:                return 1;
1.1       millert  1016:        }
1.8       tedu     1017:        return 0;
1.1       millert  1018: }
                   1019: #endif