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