=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/file/Attic/readelf.c,v retrieving revision 1.7 retrieving revision 1.8 diff -c -r1.7 -r1.8 *** src/usr.bin/file/Attic/readelf.c 2003/11/09 20:13:57 1.7 --- src/usr.bin/file/Attic/readelf.c 2004/05/19 02:32:35 1.8 *************** *** 1,9 **** /* ! * ELF routines for the file command. ! * ! * Copyright (c) Ian F. Darwin 1986-1995. ! * Software written by Ian F. Darwin and others; ! * maintained 1995-present by Christos Zoulas and others. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions --- 1,7 ---- + /* $OpenBSD: readelf.c,v 1.8 2004/05/19 02:32:35 tedu Exp $ */ /* ! * Copyright (c) Christos Zoulas 2003. ! * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions *************** *** 14,19 **** --- 12,19 ---- * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE *************** *** 27,33 **** * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ - #include "file.h" #ifdef BUILTIN_ELF --- 27,32 ---- *************** *** 41,60 **** #include "readelf.h" #ifndef lint ! static char *RCSID = "@(#)$Id: readelf.c,v 1.7 2003/11/09 20:13:57 otto Exp $"; #endif #ifdef ELFCORE ! static void dophn_core(int, int, int, off_t, int, size_t); #endif ! static void dophn_exec(int, int, int, off_t, int, size_t); ! static void doshn(int, int, int, off_t, int, size_t); ! static uint16_t getu16(int, uint16_t); ! static uint32_t getu32(int, uint32_t); ! static uint64_t getu64(int, uint64_t); ! static uint16_t getu16(int swap, uint16_t value) { union { --- 40,63 ---- #include "readelf.h" #ifndef lint ! FILE_RCSID("@(#)$Id: readelf.c,v 1.8 2004/05/19 02:32:35 tedu Exp $") #endif #ifdef ELFCORE ! private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t); #endif ! private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t); ! private int doshn(struct magic_set *, int, int, int, off_t, int, size_t); ! private size_t donote(struct magic_set *, unsigned char *, size_t, size_t, int, ! int, size_t); ! #define ELF_ALIGN(a) ((((a) + align - 1) / align) * align) ! private uint16_t getu16(int, uint16_t); ! private uint32_t getu32(int, uint32_t); ! private uint64_t getu64(int, uint64_t); ! ! private uint16_t getu16(int swap, uint16_t value) { union { *************** *** 73,79 **** return value; } ! static uint32_t getu32(int swap, uint32_t value) { union { --- 76,82 ---- return value; } ! private uint32_t getu32(int swap, uint32_t value) { union { *************** *** 94,100 **** return value; } ! static uint64_t getu64(int swap, uint64_t value) { union { --- 97,103 ---- return value; } ! private uint64_t getu64(int swap, uint64_t value) { union { *************** *** 140,344 **** #define ph_offset (class == ELFCLASS32 \ ? getu32(swap, ph32.p_offset) \ : getu64(swap, ph64.p_offset)) ! #define ph_align (class == ELFCLASS32 \ ! ? (ph32.p_align ? getu32(swap, ph32.p_align) : 4) \ ! : (ph64.p_align ? getu64(swap, ph64.p_align) : 4)) #define nh_size (class == ELFCLASS32 \ ! ? sizeof *nh32 \ ! : sizeof *nh64) #define nh_type (class == ELFCLASS32 \ ! ? getu32(swap, nh32->n_type) \ ! : getu32(swap, nh64->n_type)) #define nh_namesz (class == ELFCLASS32 \ ! ? getu32(swap, nh32->n_namesz) \ ! : getu32(swap, nh64->n_namesz)) #define nh_descsz (class == ELFCLASS32 \ ! ? getu32(swap, nh32->n_descsz) \ ! : getu32(swap, nh64->n_descsz)) #define prpsoffsets(i) (class == ELFCLASS32 \ ? prpsoffsets32[i] \ : prpsoffsets64[i]) - static void - doshn(int class, int swap, int fd, off_t off, int num, size_t size) - { - Elf32_Shdr sh32; - Elf64_Shdr sh64; - - if (size != sh_size) - error("corrupted section header size.\n"); - - if (lseek(fd, off, SEEK_SET) == -1) - error("lseek failed (%s).\n", strerror(errno)); - - for ( ; num; num--) { - if (read(fd, sh_addr, sh_size) == -1) - error("read failed (%s).\n", strerror(errno)); - if (shs_type == SHT_SYMTAB /* || shs_type == SHT_DYNSYM */) { - (void) printf (", not stripped"); - return; - } - } - (void) printf (", stripped"); - } - - /* - * Look through the program headers of an executable image, searching - * for a PT_INTERP section; if one is found, it's dynamically linked, - * otherwise it's statically linked. - */ - static void - dophn_exec(int class, int swap, int fd, off_t off, int num, size_t size) - { - Elf32_Phdr ph32; - Elf32_Nhdr *nh32 = NULL; - Elf64_Phdr ph64; - Elf64_Nhdr *nh64 = NULL; - char *linking_style = "statically"; - char *shared_libraries = ""; - char nbuf[BUFSIZ]; - int bufsize; - size_t offset, nameoffset; - off_t savedoffset; - - if (size != ph_size) - error("corrupted program header size.\n"); - if (lseek(fd, off, SEEK_SET) == -1) - error("lseek failed (%s).\n", strerror(errno)); - - for ( ; num; num--) { - if (read(fd, ph_addr, ph_size) == -1) - error("read failed (%s).\n", strerror(errno)); - if ((savedoffset = lseek(fd, 0, SEEK_CUR)) == -1) - error("lseek failed (%s).\n", strerror(errno)); - - switch (ph_type) { - case PT_DYNAMIC: - linking_style = "dynamically"; - break; - case PT_INTERP: - shared_libraries = " (uses shared libs)"; - break; - case PT_NOTE: - /* - * This is a PT_NOTE section; loop through all the notes - * in the section. - */ - if (lseek(fd, (off_t) ph_offset, SEEK_SET) == -1) - error("lseek failed (%s).\n", strerror(errno)); - bufsize = read(fd, nbuf, sizeof(nbuf)); - if (bufsize == -1) - error(": " "read failed (%s).\n", - strerror(errno)); - offset = 0; - for (;;) { - if (offset >= bufsize) - break; - if (class == ELFCLASS32) - nh32 = (Elf32_Nhdr *)&nbuf[offset]; - else - nh64 = (Elf64_Nhdr *)&nbuf[offset]; - offset += nh_size; - - if (offset + nh_namesz >= bufsize) { - /* - * We're past the end of the buffer. - */ - break; - } - - nameoffset = offset; - offset += nh_namesz; - offset = ((offset+ph_align-1)/ph_align)*ph_align; - - if ((nh_namesz == 0) && (nh_descsz == 0)) { - /* - * We're out of note headers. - */ - break; - } - - if (offset + nh_descsz >= bufsize) - break; - - if (nh_namesz == 4 && - strcmp(&nbuf[nameoffset], "GNU") == 0 && - nh_type == NT_GNU_VERSION && - nh_descsz == 16) { - uint32_t *desc = - (uint32_t *)&nbuf[offset]; - - printf(", for GNU/"); - switch (getu32(swap, desc[0])) { - case GNU_OS_LINUX: - printf("Linux"); - break; - case GNU_OS_HURD: - printf("Hurd"); - break; - case GNU_OS_SOLARIS: - printf("Solaris"); - break; - default: - printf(""); - } - printf(" %d.%d.%d", - getu32(swap, desc[1]), - getu32(swap, desc[2]), - getu32(swap, desc[3])); - } - - if (nh_namesz == 7 && - strcmp(&nbuf[nameoffset], "NetBSD") == 0 && - nh_type == NT_NETBSD_VERSION && - nh_descsz == 4) { - printf(", for NetBSD"); - /* - * Version number is stuck at 199905, - * and hence is basically content-free. - */ - } - - if (nh_namesz == 8 && - strcmp(&nbuf[nameoffset], "FreeBSD") == 0 && - nh_type == NT_FREEBSD_VERSION && - nh_descsz == 4) { - uint32_t desc = getu32(swap, - *(uint32_t *)&nbuf[offset]); - printf(", for FreeBSD"); - /* - * Contents is __FreeBSD_version, - * whose relation to OS versions is - * defined by a huge table in the - * Porters' Handbook. Happily, the - * first three digits are the version - * number, at least in versions of - * FreeBSD that use this note. - */ - - printf(" %d.%d", desc / 100000, - desc / 10000 % 10); - if (desc / 1000 % 10 > 0) - printf(".%d", - desc / 1000 % 10); - } - - if (nh_namesz == 8 && - strcmp(&nbuf[nameoffset], "OpenBSD") == 0 && - nh_type == NT_OPENBSD_VERSION && - nh_descsz == 4) { - printf(", for OpenBSD"); - /* Content of note is always 0 */ - } - } - if ((lseek(fd, savedoffset + offset, SEEK_SET)) == -1) - error("lseek failed (%s).\n", strerror(errno)); - break; - } - } - printf(", %s linked%s", linking_style, shared_libraries); - } - #ifdef ELFCORE size_t prpsoffsets32[] = { 8, /* FreeBSD */ --- 143,169 ---- #define ph_offset (class == ELFCLASS32 \ ? getu32(swap, ph32.p_offset) \ : getu64(swap, ph64.p_offset)) ! #define ph_align (size_t)((class == ELFCLASS32 \ ! ? (off_t) (ph32.p_align ? \ ! getu32(swap, ph32.p_align) : 4) \ ! : (off_t) (ph64.p_align ? \ ! getu64(swap, ph64.p_align) : 4))) #define nh_size (class == ELFCLASS32 \ ! ? sizeof nh32 \ ! : sizeof nh64) #define nh_type (class == ELFCLASS32 \ ! ? getu32(swap, nh32.n_type) \ ! : getu32(swap, nh64.n_type)) #define nh_namesz (class == ELFCLASS32 \ ! ? getu32(swap, nh32.n_namesz) \ ! : getu32(swap, nh64.n_namesz)) #define nh_descsz (class == ELFCLASS32 \ ! ? getu32(swap, nh32.n_descsz) \ ! : getu32(swap, nh64.n_descsz)) #define prpsoffsets(i) (class == ELFCLASS32 \ ? prpsoffsets32[i] \ : prpsoffsets64[i]) #ifdef ELFCORE size_t prpsoffsets32[] = { 8, /* FreeBSD */ *************** *** 381,416 **** #define OS_STYLE_FREEBSD 1 #define OS_STYLE_NETBSD 2 ! static const char *os_style_names[] = { "SVR4", "FreeBSD", "NetBSD", }; ! static void ! dophn_core(int class, int swap, int fd, off_t off, int num, size_t size) { Elf32_Phdr ph32; - Elf32_Nhdr *nh32 = NULL; Elf64_Phdr ph64; ! Elf64_Nhdr *nh64 = NULL; ! size_t offset, nameoffset, noffset, reloffset; ! unsigned char c; ! int i, j; ! char nbuf[BUFSIZ]; ! int bufsize; ! int os_style = -1; ! if (size != ph_size) ! error("corrupted program header size.\n"); /* * Loop through all the program headers. */ for ( ; num; num--) { ! if (lseek(fd, off, SEEK_SET) == -1) ! error("lseek failed (%s).\n", strerror(errno)); ! if (read(fd, ph_addr, ph_size) == -1) ! error("read failed (%s).\n", strerror(errno)); off += size; if (ph_type != PT_NOTE) continue; --- 206,244 ---- #define OS_STYLE_FREEBSD 1 #define OS_STYLE_NETBSD 2 ! private const char *os_style_names[] = { "SVR4", "FreeBSD", "NetBSD", }; ! private int ! dophn_core(struct magic_set *ms, int class, int swap, int fd, off_t off, ! int num, size_t size) { Elf32_Phdr ph32; Elf64_Phdr ph64; ! size_t offset; ! unsigned char nbuf[BUFSIZ]; ! ssize_t bufsize; ! if (size != ph_size) { ! if (file_printf(ms, ", corrupted program header size") == -1) ! return -1; ! return 0; ! } /* * Loop through all the program headers. */ for ( ; num; num--) { ! if (lseek(fd, off, SEEK_SET) == (off_t)-1) { ! file_badseek(ms); ! return -1; ! } ! if (read(fd, ph_addr, ph_size) == -1) { ! file_badread(ms); ! return -1; ! } off += size; if (ph_type != PT_NOTE) continue; *************** *** 419,592 **** * This is a PT_NOTE section; loop through all the notes * in the section. */ ! if (lseek(fd, (off_t) ph_offset, SEEK_SET) == -1) ! error("lseek failed (%s).\n", strerror(errno)); bufsize = read(fd, nbuf, BUFSIZ); ! if (bufsize == -1) ! error(": " "read failed (%s).\n", strerror(errno)); offset = 0; for (;;) { ! if (offset >= bufsize) break; ! if (class == ELFCLASS32) ! nh32 = (Elf32_Nhdr *)&nbuf[offset]; ! else ! nh64 = (Elf64_Nhdr *)&nbuf[offset]; ! offset += nh_size; ! ! /* ! * Check whether this note has the name "CORE" or ! * "FreeBSD", or "NetBSD-CORE". ! */ ! if (offset + nh_namesz >= bufsize) { ! /* ! * We're past the end of the buffer. ! */ break; } ! nameoffset = offset; ! offset += nh_namesz; ! offset = ((offset + 3)/4)*4; ! /* ! * Sigh. The 2.0.36 kernel in Debian 2.1, at ! * least, doesn't correctly implement name ! * sections, in core dumps, as specified by ! * the "Program Linking" section of "UNIX(R) System ! * V Release 4 Programmer's Guide: ANSI C and ! * Programming Support Tools", because my copy ! * clearly says "The first 'namesz' bytes in 'name' ! * contain a *null-terminated* [emphasis mine] ! * character representation of the entry's owner ! * or originator", but the 2.0.36 kernel code ! * doesn't include the terminating null in the ! * name.... ! */ ! if (os_style == -1) { ! if ((nh_namesz == 4 && ! strncmp(&nbuf[nameoffset], ! "CORE", 4) == 0) || ! (nh_namesz == 5 && ! strcmp(&nbuf[nameoffset], ! "CORE") == 0)) { ! os_style = OS_STYLE_SVR4; ! } else ! if ((nh_namesz == 8 && ! strcmp(&nbuf[nameoffset], ! "FreeBSD") == 0)) { ! os_style = OS_STYLE_FREEBSD; ! } else ! if ((nh_namesz >= 11 && ! strncmp(&nbuf[nameoffset], ! "NetBSD-CORE", 11) == 0)) { ! os_style = OS_STYLE_NETBSD; ! } else ! continue; ! printf(", %s-style", os_style_names[os_style]); } ! if (os_style == OS_STYLE_NETBSD && ! nh_type == NT_NETBSD_CORE_PROCINFO) { ! uint32_t signo; /* ! * Extract the program name. It is at ! * offset 0x7c, and is up to 32-bytes, ! * including the terminating NUL. */ ! printf(", from '%.31s'", &nbuf[offset + 0x7c]); ! /* ! * Extract the signal number. It is at ! * offset 0x08. */ ! memcpy(&signo, &nbuf[offset + 0x08], ! sizeof(signo)); ! printf(" (signal %u)", getu32(swap, signo)); ! } else ! if (os_style != OS_STYLE_NETBSD && ! nh_type == NT_PRPSINFO) { ! /* ! * Extract the program name. We assume ! * it to be 16 characters (that's what it ! * is in SunOS 5.x and Linux). ! * ! * Unfortunately, it's at a different offset ! * in various OSes, so try multiple offsets. ! * If the characters aren't all printable, ! * reject it. ! */ ! for (i = 0; i < NOFFSETS; i++) { ! reloffset = prpsoffsets(i); ! noffset = offset + reloffset; ! for (j = 0; j < 16; ! j++, noffset++, reloffset++) { ! /* ! * Make sure we're not past ! * the end of the buffer; if ! * we are, just give up. ! */ ! if (noffset >= bufsize) ! goto tryanother; ! /* ! * Make sure we're not past ! * the end of the contents; ! * if we are, this obviously ! * isn't the right offset. ! */ ! if (reloffset >= nh_descsz) ! goto tryanother; ! ! c = nbuf[noffset]; ! if (c == '\0') { ! /* ! * A '\0' at the ! * beginning is ! * obviously wrong. ! * Any other '\0' ! * means we're done. ! */ ! if (j == 0) ! goto tryanother; ! else ! break; ! } else { ! /* ! * A nonprintable ! * character is also ! * wrong. ! */ ! #define isquote(c) (strchr("'\"`", (c)) != NULL) ! if (!isprint(c) || ! isquote(c)) ! goto tryanother; ! } ! } ! /* ! * Well, that worked. */ ! printf(", from '%.16s'", ! &nbuf[offset + prpsoffsets(i)]); ! break; ! ! tryanother: ! ; } - break; } ! offset += nh_descsz; ! offset = ((offset + 3)/4)*4; } } - } #endif ! void ! tryelf(int fd, unsigned char *buf, int nbytes) { union { int32_t l; char c[sizeof (int32_t)]; --- 247,709 ---- * This is a PT_NOTE section; loop through all the notes * in the section. */ ! if (lseek(fd, (off_t) ph_offset, SEEK_SET) == (off_t)-1) { ! file_badseek(ms); ! return -1; ! } bufsize = read(fd, nbuf, BUFSIZ); ! if (bufsize == -1) { ! file_badread(ms); ! return -1; ! } offset = 0; for (;;) { ! if (offset >= (size_t)bufsize) break; ! offset = donote(ms, nbuf, offset, (size_t)bufsize, ! class, swap, 4); ! if (offset == 0) break; + + } + } + return 0; + } + #endif + + private size_t + donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size, + int class, int swap, size_t align) + { + Elf32_Nhdr nh32; + Elf64_Nhdr nh64; + size_t noff, doff; + #ifdef ELFCORE + int os_style = -1; + #endif + uint32_t namesz, descsz; + + if (class == ELFCLASS32) + memcpy(&nh32, &nbuf[offset], sizeof(nh32)); + else + memcpy(&nh64, &nbuf[offset], sizeof(nh64)); + offset += nh_size; + + namesz = nh_namesz; + descsz = nh_descsz; + if ((namesz == 0) && (descsz == 0)) { + /* + * We're out of note headers. + */ + return offset; + } + + if (namesz & 0x80000000) { + (void)file_printf(ms, ", bad note name size 0x%lx", + (unsigned long)namesz); + return offset; + } + + if (descsz & 0x80000000) { + (void)file_printf(ms, ", bad note description size 0x%lx", + (unsigned long)descsz); + return offset; + } + + + noff = offset; + doff = ELF_ALIGN(offset + namesz); + + if (offset + namesz >= size) { + /* + * We're past the end of the buffer. + */ + return doff; + } + + offset = ELF_ALIGN(doff + descsz); + if (offset + descsz >= size) { + return offset; + } + + if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && + nh_type == NT_GNU_VERSION && descsz == 16) { + uint32_t desc[4]; + (void)memcpy(desc, &nbuf[doff], sizeof(desc)); + + if (file_printf(ms, ", for GNU/") == -1) + return size; + switch (getu32(swap, desc[0])) { + case GNU_OS_LINUX: + if (file_printf(ms, "Linux") == -1) + return size; + break; + case GNU_OS_HURD: + if (file_printf(ms, "Hurd") == -1) + return size; + break; + case GNU_OS_SOLARIS: + if (file_printf(ms, "Solaris") == -1) + return size; + break; + default: + if (file_printf(ms, "") == -1) + return size; + } + if (file_printf(ms, " %d.%d.%d", getu32(swap, desc[1]), + getu32(swap, desc[2]), getu32(swap, desc[3])) == -1) + return size; + return size; + } + + if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 && + nh_type == NT_NETBSD_VERSION && descsz == 4) { + uint32_t desc; + (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); + desc = getu32(swap, desc); + + if (file_printf(ms, ", for NetBSD") == -1) + return size; + /* + * The version number used to be stuck as 199905, and was thus + * basically content-free. Newer versions of NetBSD have fixed + * this and now use the encoding of __NetBSD_Version__: + * + * MMmmrrpp00 + * + * M = major version + * m = minor version + * r = release ["",A-Z,Z[A-Z] but numeric] + * p = patchlevel + */ + if (desc > 100000000U) { + u_int ver_patch = (desc / 100) % 100; + u_int ver_rel = (desc / 10000) % 100; + u_int ver_min = (desc / 1000000) % 100; + u_int ver_maj = desc / 100000000; + + if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) + return size; + if (ver_rel == 0 && ver_patch != 0) { + if (file_printf(ms, ".%u", ver_patch) == -1) + return size; + } else if (ver_rel != 0) { + while (ver_rel > 26) { + file_printf(ms, "Z"); + ver_rel -= 26; + } + file_printf(ms, "%c", 'A' + ver_rel - 1); } + } + return size; + } ! if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 && ! nh_type == NT_FREEBSD_VERSION && descsz == 4) { ! uint32_t desc; ! (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); ! desc = getu32(swap, desc); ! if (file_printf(ms, ", for FreeBSD") == -1) ! return size; ! /* ! * Contents is __FreeBSD_version, whose relation to OS ! * versions is defined by a huge table in the Porters' ! * Handbook. For up to 5.x, the first three digits are ! * the version number. For 5.x and higher, the scheme ! * is: <0 if release branch, ! * otherwise 1>xx ! */ ! if (desc / 100000 < 5) { ! if (file_printf(ms, " %d.%d", desc / 100000, ! desc / 10000 % 10) == -1) ! return size; ! if (desc / 1000 % 10 > 0) ! if (file_printf(ms, ".%d", desc / 1000 % 10) ! == -1) ! return size; ! } else { ! if (file_printf(ms, " %d.%d", desc / 100000, ! desc / 1000 % 100) == -1) ! return size; ! desc %= 1000; ! if (desc > 100) { ! if (file_printf(ms, "-CURRENT (rev %d)", ! desc % 100) == -1) ! return size; ! } else if (desc != 0) { ! if (file_printf(ms, ".%d", desc / 10) == -1) ! return size; } + } + return size; + } ! if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && ! nh_type == NT_OPENBSD_VERSION && descsz == 4) { ! if (file_printf(ms, ", for OpenBSD") == -1) ! return size; ! /* Content of note is always 0 */ ! return size; ! } + /* + * Sigh. The 2.0.36 kernel in Debian 2.1, at + * least, doesn't correctly implement name + * sections, in core dumps, as specified by + * the "Program Linking" section of "UNIX(R) System + * V Release 4 Programmer's Guide: ANSI C and + * Programming Support Tools", because my copy + * clearly says "The first 'namesz' bytes in 'name' + * contain a *null-terminated* [emphasis mine] + * character representation of the entry's owner + * or originator", but the 2.0.36 kernel code + * doesn't include the terminating null in the + * name.... + */ + if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) || + (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) { + os_style = OS_STYLE_SVR4; + } + + if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) { + os_style = OS_STYLE_FREEBSD; + } + + if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11) + == 0)) { + os_style = OS_STYLE_NETBSD; + } + + #ifdef ELFCORE + if (os_style != -1) + if (file_printf(ms, ", %s-style", os_style_names[os_style]) == -1) + return size; + + if (os_style == OS_STYLE_NETBSD && nh_type == NT_NETBSD_CORE_PROCINFO) { + uint32_t signo; + /* + * Extract the program name. It is at + * offset 0x7c, and is up to 32-bytes, + * including the terminating NUL. + */ + if (file_printf(ms, ", from '%.31s'", &nbuf[doff + 0x7c]) == -1) + return size; + + /* + * Extract the signal number. It is at + * offset 0x08. + */ + memcpy(&signo, &nbuf[doff + 0x08], + sizeof(signo)); + if (file_printf(ms, " (signal %u)", getu32(swap, signo)) == -1) + return size; + return size; + } else if (os_style != OS_STYLE_NETBSD && nh_type == NT_PRPSINFO) { + size_t i, j; + unsigned char c; + /* + * Extract the program name. We assume + * it to be 16 characters (that's what it + * is in SunOS 5.x and Linux). + * + * Unfortunately, it's at a different offset + * in varous OSes, so try multiple offsets. + * If the characters aren't all printable, + * reject it. + */ + for (i = 0; i < NOFFSETS; i++) { + size_t reloffset = prpsoffsets(i); + size_t noffset = doff + reloffset; + for (j = 0; j < 16; j++, noffset++, reloffset++) { /* ! * Make sure we're not past ! * the end of the buffer; if ! * we are, just give up. */ ! if (noffset >= size) ! goto tryanother; ! /* ! * Make sure we're not past ! * the end of the contents; ! * if we are, this obviously ! * isn't the right offset. */ ! if (reloffset >= descsz) ! goto tryanother; ! c = nbuf[noffset]; ! if (c == '\0') { /* ! * A '\0' at the ! * beginning is ! * obviously wrong. ! * Any other '\0' ! * means we're done. */ ! if (j == 0) ! goto tryanother; ! else ! break; ! } else { ! /* ! * A nonprintable ! * character is also ! * wrong. ! */ ! #define isquote(c) (strchr("'\"`", (c)) != NULL) ! if (!isprint(c) || isquote(c)) ! goto tryanother; } } ! ! /* ! * Well, that worked. ! */ ! if (file_printf(ms, ", from '%.16s'", ! &nbuf[doff + prpsoffsets(i)]) == -1) ! return size; ! return size; ! ! tryanother: ! ; } + return offset; } #endif + return offset; + } ! private int ! doshn(struct magic_set *ms, int class, int swap, int fd, off_t off, int num, ! size_t size) { + Elf32_Shdr sh32; + Elf64_Shdr sh64; + + if (size != sh_size) { + if (file_printf(ms, ", corrupted section header size") == -1) + return -1; + return 0; + } + + if (lseek(fd, off, SEEK_SET) == (off_t)-1) { + file_badseek(ms); + return -1; + } + + for ( ; num; num--) { + if (read(fd, sh_addr, sh_size) == -1) { + file_badread(ms); + return -1; + } + if (shs_type == SHT_SYMTAB /* || shs_type == SHT_DYNSYM */) { + if (file_printf(ms, ", not stripped") == -1) + return -1; + return 0; + } + } + if (file_printf(ms, ", stripped") == -1) + return -1; + return 0; + } + + /* + * Look through the program headers of an executable image, searching + * for a PT_INTERP section; if one is found, it's dynamically linked, + * otherwise it's statically linked. + */ + private int + dophn_exec(struct magic_set *ms, int class, int swap, int fd, off_t off, + int num, size_t size) + { + Elf32_Phdr ph32; + Elf64_Phdr ph64; + const char *linking_style = "statically"; + const char *shared_libraries = ""; + unsigned char nbuf[BUFSIZ]; + int bufsize; + size_t offset, align; + off_t savedoffset; + + if (size != ph_size) { + if (file_printf(ms, ", corrupted program header size") == -1) + return -1; + return 0; + } + if (lseek(fd, off, SEEK_SET) == (off_t)-1) { + file_badseek(ms); + return -1; + } + + for ( ; num; num--) { + if (read(fd, ph_addr, ph_size) == -1) { + file_badread(ms); + return -1; + } + if ((savedoffset = lseek(fd, (off_t)0, SEEK_CUR)) == (off_t)-1) { + file_badseek(ms); + return -1; + } + + switch (ph_type) { + case PT_DYNAMIC: + linking_style = "dynamically"; + break; + case PT_INTERP: + shared_libraries = " (uses shared libs)"; + break; + case PT_NOTE: + if ((align = ph_align) & 0x80000000) { + if (file_printf(ms, + ", invalid note alignment 0x%lx", + (unsigned long)align) == -1) + return -1; + align = 4; + } + /* + * This is a PT_NOTE section; loop through all the notes + * in the section. + */ + if (lseek(fd, (off_t) ph_offset, SEEK_SET) + == (off_t)-1) { + file_badseek(ms); + return -1; + } + bufsize = read(fd, nbuf, sizeof(nbuf)); + if (bufsize == -1) { + file_badread(ms); + return -1; + } + offset = 0; + for (;;) { + if (offset >= (size_t)bufsize) + break; + offset = donote(ms, nbuf, offset, + (size_t)bufsize, class, swap, align); + if (offset == 0) + break; + } + if (lseek(fd, savedoffset + offset, SEEK_SET) + == (off_t)-1) { + file_badseek(ms); + return -1; + } + break; + } + } + if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries) + == -1) + return -1; + return 0; + } + + + protected int + file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, + size_t nbytes) + { union { int32_t l; char c[sizeof (int32_t)]; *************** *** 595,604 **** int swap; /* ! * If we can't seek, it must be a pipe, socket or fifo. */ if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) ! fd = pipe2file(fd, buf, nbytes); /* * ELF executables have multiple section headers in arbitrary --- 712,721 ---- int swap; /* ! * If we cannot seek, it must be a pipe, socket or fifo. */ if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) ! fd = file_pipe2file(ms, fd, buf, nbytes); /* * ELF executables have multiple section headers in arbitrary *************** *** 609,615 **** if (buf[EI_MAG0] != ELFMAG0 || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) ! return; class = buf[4]; --- 726,732 ---- if (buf[EI_MAG0] != ELFMAG0 || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) ! return 0; class = buf[4]; *************** *** 617,704 **** if (class == ELFCLASS32) { Elf32_Ehdr elfhdr; if (nbytes <= sizeof (Elf32_Ehdr)) ! return; u.l = 1; (void) memcpy(&elfhdr, buf, sizeof elfhdr); swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5]; ! if (getu16(swap, elfhdr.e_type) == ET_CORE) #ifdef ELFCORE ! dophn_core(class, swap, ! fd, ! getu32(swap, elfhdr.e_phoff), ! getu16(swap, elfhdr.e_phnum), ! getu16(swap, elfhdr.e_phentsize)); #else ; #endif ! else { if (getu16(swap, elfhdr.e_type) == ET_EXEC) { ! dophn_exec(class, swap, ! fd, ! getu32(swap, elfhdr.e_phoff), ! getu16(swap, elfhdr.e_phnum), ! getu16(swap, elfhdr.e_phentsize)); } ! doshn(class, swap, ! fd, ! getu32(swap, elfhdr.e_shoff), ! getu16(swap, elfhdr.e_shnum), ! getu16(swap, elfhdr.e_shentsize)); } ! return; } if (class == ELFCLASS64) { Elf64_Ehdr elfhdr; if (nbytes <= sizeof (Elf64_Ehdr)) ! return; u.l = 1; (void) memcpy(&elfhdr, buf, sizeof elfhdr); swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5]; ! if (getu16(swap, elfhdr.e_type) == ET_CORE) #ifdef ELFCORE ! dophn_core(class, swap, ! fd, #ifdef USE_ARRAY_FOR_64BIT_TYPES ! getu32(swap, elfhdr.e_phoff[1]), #else ! getu64(swap, elfhdr.e_phoff), #endif ! getu16(swap, elfhdr.e_phnum), ! getu16(swap, elfhdr.e_phentsize)); #else ; #endif ! else ! { if (getu16(swap, elfhdr.e_type) == ET_EXEC) { ! dophn_exec(class, swap, ! fd, #ifdef USE_ARRAY_FOR_64BIT_TYPES ! getu32(swap, elfhdr.e_phoff[1]), #else ! getu64(swap, elfhdr.e_phoff), #endif ! getu16(swap, elfhdr.e_phnum), ! getu16(swap, elfhdr.e_phentsize)); } ! doshn(class, swap, ! fd, #ifdef USE_ARRAY_FOR_64BIT_TYPES ! getu32(swap, elfhdr.e_shoff[1]), #else ! getu64(swap, elfhdr.e_shoff), #endif ! getu16(swap, elfhdr.e_shnum), ! getu16(swap, elfhdr.e_shentsize)); } ! return; } } #endif --- 734,823 ---- if (class == ELFCLASS32) { Elf32_Ehdr elfhdr; if (nbytes <= sizeof (Elf32_Ehdr)) ! return 0; u.l = 1; (void) memcpy(&elfhdr, buf, sizeof elfhdr); swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5]; ! if (getu16(swap, elfhdr.e_type) == ET_CORE) { #ifdef ELFCORE ! if (dophn_core(ms, class, swap, fd, ! (off_t)getu32(swap, elfhdr.e_phoff), ! getu16(swap, elfhdr.e_phnum), ! (size_t)getu16(swap, elfhdr.e_phentsize)) == -1) ! return -1; #else ; #endif ! } else { if (getu16(swap, elfhdr.e_type) == ET_EXEC) { ! if (dophn_exec(ms, class, swap, ! fd, (off_t)getu32(swap, elfhdr.e_phoff), ! getu16(swap, elfhdr.e_phnum), ! (size_t)getu16(swap, elfhdr.e_phentsize)) ! == -1) ! return -1; } ! if (doshn(ms, class, swap, fd, ! (off_t)getu32(swap, elfhdr.e_shoff), ! getu16(swap, elfhdr.e_shnum), ! (size_t)getu16(swap, elfhdr.e_shentsize)) == -1) ! return -1; } ! return 1; } if (class == ELFCLASS64) { Elf64_Ehdr elfhdr; if (nbytes <= sizeof (Elf64_Ehdr)) ! return 0; u.l = 1; (void) memcpy(&elfhdr, buf, sizeof elfhdr); swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5]; ! if (getu16(swap, elfhdr.e_type) == ET_CORE) { #ifdef ELFCORE ! if (dophn_core(ms, class, swap, fd, #ifdef USE_ARRAY_FOR_64BIT_TYPES ! (off_t)getu32(swap, elfhdr.e_phoff[1]), #else ! (off_t)getu64(swap, elfhdr.e_phoff), #endif ! getu16(swap, elfhdr.e_phnum), ! (size_t)getu16(swap, elfhdr.e_phentsize)) == -1) ! return -1; #else ; #endif ! } else { if (getu16(swap, elfhdr.e_type) == ET_EXEC) { ! if (dophn_exec(ms, class, swap, fd, #ifdef USE_ARRAY_FOR_64BIT_TYPES ! (off_t)getu32(swap, elfhdr.e_phoff[1]), #else ! (off_t)getu64(swap, elfhdr.e_phoff), #endif ! getu16(swap, elfhdr.e_phnum), ! (size_t)getu16(swap, elfhdr.e_phentsize)) ! == -1) ! return -1; } ! if (doshn(ms, class, swap, fd, #ifdef USE_ARRAY_FOR_64BIT_TYPES ! (off_t)getu32(swap, elfhdr.e_shoff[1]), #else ! (off_t)getu64(swap, elfhdr.e_shoff), #endif ! getu16(swap, elfhdr.e_shnum), ! (size_t)getu16(swap, elfhdr.e_shentsize)) == -1) ! return -1; } ! return 1; } + return 0; } #endif