readelf.c revision 275666
150724Scg/* 250724Scg * Copyright (c) Christos Zoulas 2003. 350724Scg * All Rights Reserved. 450724Scg * 550724Scg * Redistribution and use in source and binary forms, with or without 650724Scg * modification, are permitted provided that the following conditions 750724Scg * are met: 850724Scg * 1. Redistributions of source code must retain the above copyright 950724Scg * notice immediately at the beginning of the file, without modification, 1050724Scg * this list of conditions, and the following disclaimer. 1150724Scg * 2. Redistributions in binary form must reproduce the above copyright 1250724Scg * notice, this list of conditions and the following disclaimer in the 1350724Scg * documentation and/or other materials provided with the distribution. 1450724Scg * 1550724Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1650724Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1750724Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1850724Scg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 1950724Scg * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2050724Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2150724Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2250724Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2350724Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2450724Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2550724Scg * SUCH DAMAGE. 2650733Speter */ 2750724Scg#include "file.h" 2850724Scg 2953465Scg#ifndef lint 3050724ScgFILE_RCSID("@(#)$File: readelf.c,v 1.103 2014/05/02 02:25:10 christos Exp $") 3150724Scg#endif 3250724Scg 3350724Scg#ifdef BUILTIN_ELF 3450724Scg#include <string.h> 3550724Scg#include <ctype.h> 3650724Scg#include <stdlib.h> 3750724Scg#ifdef HAVE_UNISTD_H 3850724Scg#include <unistd.h> 3950724Scg#endif 4050724Scg 4150724Scg#include "readelf.h" 4250724Scg#include "magic.h" 4350724Scg 4450724Scg#ifdef ELFCORE 4550724Scgprivate int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t, 4650724Scg off_t, int *); 4750724Scg#endif 4850724Scgprivate int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t, 4950724Scg off_t, int *, int); 5050724Scgprivate int doshn(struct magic_set *, int, int, int, off_t, int, size_t, 5150724Scg off_t, int *, int, int); 5250724Scgprivate size_t donote(struct magic_set *, void *, size_t, size_t, int, 5350724Scg int, size_t, int *); 5450724Scg 5550724Scg#define ELF_ALIGN(a) ((((a) + align - 1) / align) * align) 5650724Scg 5750724Scg#define isquote(c) (strchr("'\"`", (c)) != NULL) 5850724Scg 5950724Scgprivate uint16_t getu16(int, uint16_t); 6050724Scgprivate uint32_t getu32(int, uint32_t); 6150724Scgprivate uint64_t getu64(int, uint64_t); 6250724Scg 6350724Scg#define MAX_PHNUM 256 6450724Scg#define MAX_SHNUM 1024 6550724Scg 6650724Scgprivate int 6750724Scgtoomany(struct magic_set *ms, const char *name, uint16_t num) 6850724Scg{ 6950724Scg if (file_printf(ms, ", too many %s header sections (%u)", name, num 7050724Scg ) == -1) 7150724Scg return -1; 7250724Scg return 0; 7350724Scg} 7450724Scg 7550724Scgprivate uint16_t 7650724Scggetu16(int swap, uint16_t value) 7750724Scg{ 7850724Scg union { 7950724Scg uint16_t ui; 8050724Scg char c[2]; 8150724Scg } retval, tmpval; 8250724Scg 8350724Scg if (swap) { 8450724Scg tmpval.ui = value; 8550724Scg 8650724Scg retval.c[0] = tmpval.c[1]; 8750724Scg retval.c[1] = tmpval.c[0]; 8850724Scg 8950724Scg return retval.ui; 9050724Scg } else 9150724Scg return value; 9250724Scg} 9350724Scg 9450724Scgprivate uint32_t 9550724Scggetu32(int swap, uint32_t value) 9650724Scg{ 9750724Scg union { 9850724Scg uint32_t ui; 9950724Scg char c[4]; 10050724Scg } retval, tmpval; 10150724Scg 10250724Scg if (swap) { 10350724Scg tmpval.ui = value; 10450724Scg 10550724Scg retval.c[0] = tmpval.c[3]; 10650724Scg retval.c[1] = tmpval.c[2]; 10750724Scg retval.c[2] = tmpval.c[1]; 10850724Scg retval.c[3] = tmpval.c[0]; 10953205Scg 11050724Scg return retval.ui; 11150923Scg } else 11250724Scg return value; 11353205Scg} 11453205Scg 11553205Scgprivate uint64_t 11653205Scggetu64(int swap, uint64_t value) 11753205Scg{ 11853205Scg union { 11953205Scg uint64_t ui; 12050923Scg char c[8]; 12150923Scg } retval, tmpval; 12250923Scg 12350923Scg if (swap) { 12450923Scg tmpval.ui = value; 12550923Scg 12650923Scg retval.c[0] = tmpval.c[7]; 12752713Stanimura retval.c[1] = tmpval.c[6]; 12852713Stanimura retval.c[2] = tmpval.c[5]; 12950724Scg retval.c[3] = tmpval.c[4]; 13051769Scg retval.c[4] = tmpval.c[3]; 13150724Scg retval.c[5] = tmpval.c[2]; 13250724Scg retval.c[6] = tmpval.c[1]; 13350724Scg retval.c[7] = tmpval.c[0]; 13450724Scg 13553205Scg return retval.ui; 13650724Scg } else 13750724Scg return value; 13853205Scg} 13950724Scg 14050724Scg#define elf_getu16(swap, value) getu16(swap, value) 14150724Scg#define elf_getu32(swap, value) getu32(swap, value) 14250724Scg#define elf_getu64(swap, value) getu64(swap, value) 14350724Scg 14450724Scg#define xsh_addr (clazz == ELFCLASS32 \ 14550724Scg ? (void *)&sh32 \ 14650724Scg : (void *)&sh64) 14751769Scg#define xsh_sizeof (clazz == ELFCLASS32 \ 14850724Scg ? sizeof(sh32) \ 14950724Scg : sizeof(sh64)) 15050724Scg#define xsh_size (size_t)(clazz == ELFCLASS32 \ 15150724Scg ? elf_getu32(swap, sh32.sh_size) \ 15250724Scg : elf_getu64(swap, sh64.sh_size)) 15350724Scg#define xsh_offset (off_t)(clazz == ELFCLASS32 \ 15450724Scg ? elf_getu32(swap, sh32.sh_offset) \ 15550724Scg : elf_getu64(swap, sh64.sh_offset)) 15650724Scg#define xsh_type (clazz == ELFCLASS32 \ 15750724Scg ? elf_getu32(swap, sh32.sh_type) \ 15850724Scg : elf_getu32(swap, sh64.sh_type)) 15950724Scg#define xsh_name (clazz == ELFCLASS32 \ 16050724Scg ? elf_getu32(swap, sh32.sh_name) \ 16150724Scg : elf_getu32(swap, sh64.sh_name)) 16250724Scg#define xph_addr (clazz == ELFCLASS32 \ 16350724Scg ? (void *) &ph32 \ 16450724Scg : (void *) &ph64) 16550724Scg#define xph_sizeof (clazz == ELFCLASS32 \ 16650724Scg ? sizeof(ph32) \ 16753205Scg : sizeof(ph64)) 16850724Scg#define xph_type (clazz == ELFCLASS32 \ 16950724Scg ? elf_getu32(swap, ph32.p_type) \ 17050724Scg : elf_getu32(swap, ph64.p_type)) 17153205Scg#define xph_offset (off_t)(clazz == ELFCLASS32 \ 17250724Scg ? elf_getu32(swap, ph32.p_offset) \ 17350724Scg : elf_getu64(swap, ph64.p_offset)) 17450724Scg#define xph_align (size_t)((clazz == ELFCLASS32 \ 17550724Scg ? (off_t) (ph32.p_align ? \ 17650724Scg elf_getu32(swap, ph32.p_align) : 4) \ 17750724Scg : (off_t) (ph64.p_align ? \ 17850724Scg elf_getu64(swap, ph64.p_align) : 4))) 17951769Scg#define xph_filesz (size_t)((clazz == ELFCLASS32 \ 18050724Scg ? elf_getu32(swap, ph32.p_filesz) \ 18150724Scg : elf_getu64(swap, ph64.p_filesz))) 18250724Scg#define xnh_addr (clazz == ELFCLASS32 \ 18350724Scg ? (void *)&nh32 \ 18453205Scg : (void *)&nh64) 18550724Scg#define xph_memsz (size_t)((clazz == ELFCLASS32 \ 18653205Scg ? elf_getu32(swap, ph32.p_memsz) \ 18750724Scg : elf_getu64(swap, ph64.p_memsz))) 18850724Scg#define xnh_sizeof (clazz == ELFCLASS32 \ 18950724Scg ? sizeof nh32 \ 19050724Scg : sizeof nh64) 19150724Scg#define xnh_type (clazz == ELFCLASS32 \ 19250724Scg ? elf_getu32(swap, nh32.n_type) \ 19350724Scg : elf_getu32(swap, nh64.n_type)) 19450724Scg#define xnh_namesz (clazz == ELFCLASS32 \ 19550724Scg ? elf_getu32(swap, nh32.n_namesz) \ 19650724Scg : elf_getu32(swap, nh64.n_namesz)) 19751769Scg#define xnh_descsz (clazz == ELFCLASS32 \ 19850724Scg ? elf_getu32(swap, nh32.n_descsz) \ 19950724Scg : elf_getu32(swap, nh64.n_descsz)) 20050724Scg#define prpsoffsets(i) (clazz == ELFCLASS32 \ 20150724Scg ? prpsoffsets32[i] \ 20250724Scg : prpsoffsets64[i]) 20350724Scg#define xcap_addr (clazz == ELFCLASS32 \ 20450724Scg ? (void *)&cap32 \ 20550724Scg : (void *)&cap64) 20650724Scg#define xcap_sizeof (clazz == ELFCLASS32 \ 20750724Scg ? sizeof cap32 \ 20850724Scg : sizeof cap64) 20950724Scg#define xcap_tag (clazz == ELFCLASS32 \ 21050724Scg ? elf_getu32(swap, cap32.c_tag) \ 21150724Scg : elf_getu64(swap, cap64.c_tag)) 21250724Scg#define xcap_val (clazz == ELFCLASS32 \ 21350724Scg ? elf_getu32(swap, cap32.c_un.c_val) \ 21450724Scg : elf_getu64(swap, cap64.c_un.c_val)) 21550724Scg 21650724Scg#ifdef ELFCORE 21753205Scg/* 21850724Scg * Try larger offsets first to avoid false matches 21950724Scg * from earlier data that happen to look like strings. 22050724Scg */ 22153205Scgstatic const size_t prpsoffsets32[] = { 22250724Scg#ifdef USE_NT_PSINFO 22350724Scg 104, /* SunOS 5.x (command line) */ 22450724Scg 88, /* SunOS 5.x (short name) */ 22550724Scg#endif /* USE_NT_PSINFO */ 22650724Scg 22750724Scg 100, /* SunOS 5.x (command line) */ 22850724Scg 84, /* SunOS 5.x (short name) */ 22951769Scg 23050724Scg 44, /* Linux (command line) */ 23150724Scg 28, /* Linux 2.0.36 (short name) */ 23250724Scg 23350724Scg 8, /* FreeBSD */ 23450724Scg}; 23553205Scg 23650724Scgstatic const size_t prpsoffsets64[] = { 23750724Scg#ifdef USE_NT_PSINFO 23853205Scg 152, /* SunOS 5.x (command line) */ 23950724Scg 136, /* SunOS 5.x (short name) */ 24050724Scg#endif /* USE_NT_PSINFO */ 24150724Scg 24250724Scg 136, /* SunOS 5.x, 64-bit (command line) */ 24350724Scg 120, /* SunOS 5.x, 64-bit (short name) */ 24450724Scg 24550923Scg 56, /* Linux (command line) */ 24650724Scg 40, /* Linux (tested on core from 2.4.x, short name) */ 24751769Scg 24850724Scg 16, /* FreeBSD, 64-bit */ 24950724Scg}; 25050724Scg 25150724Scg#define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0]) 25253205Scg#define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0]) 25350724Scg 25453205Scg#define NOFFSETS (clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64) 25550724Scg 25650724Scg/* 25750724Scg * Look through the program headers of an executable image, searching 25850724Scg * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or 25950724Scg * "FreeBSD"; if one is found, try looking in various places in its 26050724Scg * contents for a 16-character string containing only printable 26150724Scg * characters - if found, that string should be the name of the program 26250724Scg * that dropped core. Note: right after that 16-character string is, 26351769Scg * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and 26450724Scg * Linux, a longer string (80 characters, in 5.x, probably other 26551769Scg * SVR4-flavored systems, and Linux) containing the start of the 26650724Scg * command line for that program. 26750724Scg * 26850724Scg * SunOS 5.x core files contain two PT_NOTE sections, with the types 26950724Scg * NT_PRPSINFO (old) and NT_PSINFO (new). These structs contain the 27053205Scg * same info about the command name and command line, so it probably 27150724Scg * isn't worthwhile to look for NT_PSINFO, but the offsets are provided 27253205Scg * above (see USE_NT_PSINFO), in case we ever decide to do so. The 27350724Scg * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent; 27450724Scg * the SunOS 5.x file command relies on this (and prefers the latter). 27550724Scg * 27650724Scg * The signal number probably appears in a section of type NT_PRSTATUS, 27750724Scg * but that's also rather OS-dependent, in ways that are harder to 27850724Scg * dissect with heuristics, so I'm not bothering with the signal number. 27950724Scg * (I suppose the signal number could be of interest in situations where 28051769Scg * you don't have the binary of the program that dropped core; if you 28150724Scg * *do* have that binary, the debugger will probably tell you what 28251769Scg * signal it was.) 28350724Scg */ 28450724Scg 28550724Scg#define OS_STYLE_SVR4 0 28650724Scg#define OS_STYLE_FREEBSD 1 28750724Scg#define OS_STYLE_NETBSD 2 28850724Scg 28950724Scgprivate const char os_style_names[][8] = { 29050724Scg "SVR4", 29150724Scg "FreeBSD", 29250724Scg "NetBSD", 29350724Scg}; 29450724Scg 29550724Scg#define FLAGS_DID_CORE 0x01 29650724Scg#define FLAGS_DID_NOTE 0x02 29750724Scg#define FLAGS_DID_BUILD_ID 0x04 29850724Scg#define FLAGS_DID_CORE_STYLE 0x08 29950724Scg#define FLAGS_IS_CORE 0x10 30050724Scg 30150724Scgprivate int 30250724Scgdophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 30350724Scg int num, size_t size, off_t fsize, int *flags) 30450724Scg{ 30550724Scg Elf32_Phdr ph32; 30650724Scg Elf64_Phdr ph64; 30750724Scg size_t offset, len; 30850724Scg unsigned char nbuf[BUFSIZ]; 30950724Scg ssize_t bufsize; 31050724Scg 31150724Scg if (size != xph_sizeof) { 31250724Scg if (file_printf(ms, ", corrupted program header size") == -1) 31350724Scg return -1; 31450724Scg return 0; 31550724Scg } 31650724Scg 31750724Scg /* 31850724Scg * Loop through all the program headers. 31950724Scg */ 32050724Scg for ( ; num; num--) { 32150724Scg if (pread(fd, xph_addr, xph_sizeof, off) == -1) { 32250724Scg file_badread(ms); 32350724Scg return -1; 32450724Scg } 32550724Scg off += size; 32650724Scg 32750724Scg if (xph_offset > fsize) { 32850724Scg /* Perhaps warn here */ 32950724Scg continue; 33050724Scg } 33150724Scg 33250724Scg if (xph_type != PT_NOTE) 33350724Scg continue; 33450724Scg 33550724Scg /* 33650724Scg * This is a PT_NOTE section; loop through all the notes 33750724Scg * in the section. 33850724Scg */ 33950724Scg len = xph_filesz < sizeof(nbuf) ? xph_filesz : sizeof(nbuf); 34050724Scg if ((bufsize = pread(fd, nbuf, len, xph_offset)) == -1) { 34150724Scg file_badread(ms); 34250724Scg return -1; 34350724Scg } 34450724Scg offset = 0; 34550724Scg for (;;) { 34650724Scg if (offset >= (size_t)bufsize) 34750724Scg break; 34850724Scg offset = donote(ms, nbuf, offset, (size_t)bufsize, 34950724Scg clazz, swap, 4, flags); 35050724Scg if (offset == 0) 35150724Scg break; 35250724Scg 35350724Scg } 35450724Scg } 35550724Scg return 0; 35650724Scg} 35750724Scg#endif 35850724Scg 35950724Scgstatic void 36050724Scgdo_note_netbsd_version(struct magic_set *ms, int swap, void *v) 36150724Scg{ 36250724Scg uint32_t desc; 36350724Scg (void)memcpy(&desc, v, sizeof(desc)); 36450724Scg desc = elf_getu32(swap, desc); 36550724Scg 36650724Scg if (file_printf(ms, ", for NetBSD") == -1) 36750724Scg return; 36851769Scg /* 36950724Scg * The version number used to be stuck as 199905, and was thus 37050724Scg * basically content-free. Newer versions of NetBSD have fixed 37150724Scg * this and now use the encoding of __NetBSD_Version__: 37250724Scg * 37350724Scg * MMmmrrpp00 37450724Scg * 37550724Scg * M = major version 37650724Scg * m = minor version 37750724Scg * r = release ["",A-Z,Z[A-Z] but numeric] 37850724Scg * p = patchlevel 37950724Scg */ 38050724Scg if (desc > 100000000U) { 38150724Scg uint32_t ver_patch = (desc / 100) % 100; 38250724Scg uint32_t ver_rel = (desc / 10000) % 100; 38350724Scg uint32_t ver_min = (desc / 1000000) % 100; 38450724Scg uint32_t ver_maj = desc / 100000000; 38550724Scg 38650724Scg if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) 38750724Scg return; 38850724Scg if (ver_rel == 0 && ver_patch != 0) { 38950724Scg if (file_printf(ms, ".%u", ver_patch) == -1) 39050724Scg return; 39150724Scg } else if (ver_rel != 0) { 39250724Scg while (ver_rel > 26) { 39350724Scg if (file_printf(ms, "Z") == -1) 39450724Scg return; 39550724Scg ver_rel -= 26; 39650724Scg } 39750724Scg if (file_printf(ms, "%c", 'A' + ver_rel - 1) 39850724Scg == -1) 39950724Scg return; 40051769Scg } 40151769Scg } 40250724Scg} 40350724Scg 40450724Scgstatic void 40550724Scgdo_note_freebsd_version(struct magic_set *ms, int swap, void *v) 40650724Scg{ 40750724Scg uint32_t desc; 40850724Scg 40950724Scg (void)memcpy(&desc, v, sizeof(desc)); 41050724Scg desc = elf_getu32(swap, desc); 41150724Scg if (file_printf(ms, ", for FreeBSD") == -1) 41250724Scg return; 41350724Scg 41450724Scg /* 41550724Scg * Contents is __FreeBSD_version, whose relation to OS 41650724Scg * versions is defined by a huge table in the Porter's 417 * Handbook. This is the general scheme: 418 * 419 * Releases: 420 * Mmp000 (before 4.10) 421 * Mmi0p0 (before 5.0) 422 * Mmm0p0 423 * 424 * Development branches: 425 * Mmpxxx (before 4.6) 426 * Mmp1xx (before 4.10) 427 * Mmi1xx (before 5.0) 428 * M000xx (pre-M.0) 429 * Mmm1xx 430 * 431 * M = major version 432 * m = minor version 433 * i = minor version increment (491000 -> 4.10) 434 * p = patchlevel 435 * x = revision 436 * 437 * The first release of FreeBSD to use ELF by default 438 * was version 3.0. 439 */ 440 if (desc == 460002) { 441 if (file_printf(ms, " 4.6.2") == -1) 442 return; 443 } else if (desc < 460100) { 444 if (file_printf(ms, " %d.%d", desc / 100000, 445 desc / 10000 % 10) == -1) 446 return; 447 if (desc / 1000 % 10 > 0) 448 if (file_printf(ms, ".%d", desc / 1000 % 10) == -1) 449 return; 450 if ((desc % 1000 > 0) || (desc % 100000 == 0)) 451 if (file_printf(ms, " (%d)", desc) == -1) 452 return; 453 } else if (desc < 500000) { 454 if (file_printf(ms, " %d.%d", desc / 100000, 455 desc / 10000 % 10 + desc / 1000 % 10) == -1) 456 return; 457 if (desc / 100 % 10 > 0) { 458 if (file_printf(ms, " (%d)", desc) == -1) 459 return; 460 } else if (desc / 10 % 10 > 0) { 461 if (file_printf(ms, ".%d", desc / 10 % 10) == -1) 462 return; 463 } 464 } else { 465 if (file_printf(ms, " %d.%d", desc / 100000, 466 desc / 1000 % 100) == -1) 467 return; 468 if ((desc / 100 % 10 > 0) || 469 (desc % 100000 / 100 == 0)) { 470 if (file_printf(ms, " (%d)", desc) == -1) 471 return; 472 } else if (desc / 10 % 10 > 0) { 473 if (file_printf(ms, ".%d", desc / 10 % 10) == -1) 474 return; 475 } 476 } 477} 478 479private size_t 480donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, 481 int clazz, int swap, size_t align, int *flags) 482{ 483 Elf32_Nhdr nh32; 484 Elf64_Nhdr nh64; 485 size_t noff, doff; 486#ifdef ELFCORE 487 int os_style = -1; 488#endif 489 uint32_t namesz, descsz; 490 unsigned char *nbuf = CAST(unsigned char *, vbuf); 491 492 if (xnh_sizeof + offset > size) { 493 /* 494 * We're out of note headers. 495 */ 496 return xnh_sizeof + offset; 497 } 498 499 (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); 500 offset += xnh_sizeof; 501 502 namesz = xnh_namesz; 503 descsz = xnh_descsz; 504 if ((namesz == 0) && (descsz == 0)) { 505 /* 506 * We're out of note headers. 507 */ 508 return (offset >= size) ? offset : size; 509 } 510 511 if (namesz & 0x80000000) { 512 (void)file_printf(ms, ", bad note name size 0x%lx", 513 (unsigned long)namesz); 514 return 0; 515 } 516 517 if (descsz & 0x80000000) { 518 (void)file_printf(ms, ", bad note description size 0x%lx", 519 (unsigned long)descsz); 520 return 0; 521 } 522 523 524 noff = offset; 525 doff = ELF_ALIGN(offset + namesz); 526 527 if (offset + namesz > size) { 528 /* 529 * We're past the end of the buffer. 530 */ 531 return doff; 532 } 533 534 offset = ELF_ALIGN(doff + descsz); 535 if (doff + descsz > size) { 536 /* 537 * We're past the end of the buffer. 538 */ 539 return (offset >= size) ? offset : size; 540 } 541 542 if ((*flags & (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) == 543 (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) 544 goto core; 545 546 if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 && 547 xnh_type == NT_GNU_VERSION && descsz == 2) { 548 file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]); 549 } 550 if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 551 xnh_type == NT_GNU_VERSION && descsz == 16) { 552 uint32_t desc[4]; 553 (void)memcpy(desc, &nbuf[doff], sizeof(desc)); 554 555 if (file_printf(ms, ", for GNU/") == -1) 556 return size; 557 switch (elf_getu32(swap, desc[0])) { 558 case GNU_OS_LINUX: 559 if (file_printf(ms, "Linux") == -1) 560 return size; 561 break; 562 case GNU_OS_HURD: 563 if (file_printf(ms, "Hurd") == -1) 564 return size; 565 break; 566 case GNU_OS_SOLARIS: 567 if (file_printf(ms, "Solaris") == -1) 568 return size; 569 break; 570 case GNU_OS_KFREEBSD: 571 if (file_printf(ms, "kFreeBSD") == -1) 572 return size; 573 break; 574 case GNU_OS_KNETBSD: 575 if (file_printf(ms, "kNetBSD") == -1) 576 return size; 577 break; 578 default: 579 if (file_printf(ms, "<unknown>") == -1) 580 return size; 581 } 582 if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]), 583 elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1) 584 return size; 585 *flags |= FLAGS_DID_NOTE; 586 return size; 587 } 588 589 if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 590 xnh_type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) { 591 uint8_t desc[20]; 592 uint32_t i; 593 if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" : 594 "sha1") == -1) 595 return size; 596 (void)memcpy(desc, &nbuf[doff], descsz); 597 for (i = 0; i < descsz; i++) 598 if (file_printf(ms, "%02x", desc[i]) == -1) 599 return size; 600 *flags |= FLAGS_DID_BUILD_ID; 601 } 602 603 if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 && 604 xnh_type == NT_NETBSD_PAX && descsz == 4) { 605 static const char *pax[] = { 606 "+mprotect", 607 "-mprotect", 608 "+segvguard", 609 "-segvguard", 610 "+ASLR", 611 "-ASLR", 612 }; 613 uint32_t desc; 614 size_t i; 615 int did = 0; 616 617 (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 618 desc = elf_getu32(swap, desc); 619 620 if (desc && file_printf(ms, ", PaX: ") == -1) 621 return size; 622 623 for (i = 0; i < __arraycount(pax); i++) { 624 if (((1 << i) & desc) == 0) 625 continue; 626 if (file_printf(ms, "%s%s", did++ ? "," : "", 627 pax[i]) == -1) 628 return size; 629 } 630 } 631 632 if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { 633 switch (xnh_type) { 634 case NT_NETBSD_VERSION: 635 if (descsz == 4) { 636 do_note_netbsd_version(ms, swap, &nbuf[doff]); 637 *flags |= FLAGS_DID_NOTE; 638 return size; 639 } 640 break; 641 case NT_NETBSD_MARCH: 642 if (file_printf(ms, ", compiled for: %.*s", (int)descsz, 643 (const char *)&nbuf[doff]) == -1) 644 return size; 645 break; 646 case NT_NETBSD_CMODEL: 647 if (file_printf(ms, ", compiler model: %.*s", 648 (int)descsz, (const char *)&nbuf[doff]) == -1) 649 return size; 650 break; 651 default: 652 if (file_printf(ms, ", note=%u", xnh_type) == -1) 653 return size; 654 break; 655 } 656 return size; 657 } 658 659 if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) { 660 if (xnh_type == NT_FREEBSD_VERSION && descsz == 4) { 661 do_note_freebsd_version(ms, swap, &nbuf[doff]); 662 *flags |= FLAGS_DID_NOTE; 663 return size; 664 } 665 } 666 667 if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && 668 xnh_type == NT_OPENBSD_VERSION && descsz == 4) { 669 if (file_printf(ms, ", for OpenBSD") == -1) 670 return size; 671 /* Content of note is always 0 */ 672 *flags |= FLAGS_DID_NOTE; 673 return size; 674 } 675 676 if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 && 677 xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) { 678 uint32_t desc; 679 if (file_printf(ms, ", for DragonFly") == -1) 680 return size; 681 (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 682 desc = elf_getu32(swap, desc); 683 if (file_printf(ms, " %d.%d.%d", desc / 100000, 684 desc / 10000 % 10, desc % 10000) == -1) 685 return size; 686 *flags |= FLAGS_DID_NOTE; 687 return size; 688 } 689 690core: 691 /* 692 * Sigh. The 2.0.36 kernel in Debian 2.1, at 693 * least, doesn't correctly implement name 694 * sections, in core dumps, as specified by 695 * the "Program Linking" section of "UNIX(R) System 696 * V Release 4 Programmer's Guide: ANSI C and 697 * Programming Support Tools", because my copy 698 * clearly says "The first 'namesz' bytes in 'name' 699 * contain a *null-terminated* [emphasis mine] 700 * character representation of the entry's owner 701 * or originator", but the 2.0.36 kernel code 702 * doesn't include the terminating null in the 703 * name.... 704 */ 705 if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) || 706 (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) { 707 os_style = OS_STYLE_SVR4; 708 } 709 710 if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) { 711 os_style = OS_STYLE_FREEBSD; 712 } 713 714 if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11) 715 == 0)) { 716 os_style = OS_STYLE_NETBSD; 717 } 718 719#ifdef ELFCORE 720 if ((*flags & FLAGS_DID_CORE) != 0) 721 return size; 722 723 if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) { 724 if (file_printf(ms, ", %s-style", os_style_names[os_style]) 725 == -1) 726 return size; 727 *flags |= FLAGS_DID_CORE_STYLE; 728 } 729 730 switch (os_style) { 731 case OS_STYLE_NETBSD: 732 if (xnh_type == NT_NETBSD_CORE_PROCINFO) { 733 uint32_t signo; 734 /* 735 * Extract the program name. It is at 736 * offset 0x7c, and is up to 32-bytes, 737 * including the terminating NUL. 738 */ 739 if (file_printf(ms, ", from '%.31s'", 740 &nbuf[doff + 0x7c]) == -1) 741 return size; 742 743 /* 744 * Extract the signal number. It is at 745 * offset 0x08. 746 */ 747 (void)memcpy(&signo, &nbuf[doff + 0x08], 748 sizeof(signo)); 749 if (file_printf(ms, " (signal %u)", 750 elf_getu32(swap, signo)) == -1) 751 return size; 752 *flags |= FLAGS_DID_CORE; 753 return size; 754 } 755 break; 756 757 default: 758 if (xnh_type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { 759 size_t i, j; 760 unsigned char c; 761 /* 762 * Extract the program name. We assume 763 * it to be 16 characters (that's what it 764 * is in SunOS 5.x and Linux). 765 * 766 * Unfortunately, it's at a different offset 767 * in various OSes, so try multiple offsets. 768 * If the characters aren't all printable, 769 * reject it. 770 */ 771 for (i = 0; i < NOFFSETS; i++) { 772 unsigned char *cname, *cp; 773 size_t reloffset = prpsoffsets(i); 774 size_t noffset = doff + reloffset; 775 size_t k; 776 for (j = 0; j < 16; j++, noffset++, 777 reloffset++) { 778 /* 779 * Make sure we're not past 780 * the end of the buffer; if 781 * we are, just give up. 782 */ 783 if (noffset >= size) 784 goto tryanother; 785 786 /* 787 * Make sure we're not past 788 * the end of the contents; 789 * if we are, this obviously 790 * isn't the right offset. 791 */ 792 if (reloffset >= descsz) 793 goto tryanother; 794 795 c = nbuf[noffset]; 796 if (c == '\0') { 797 /* 798 * A '\0' at the 799 * beginning is 800 * obviously wrong. 801 * Any other '\0' 802 * means we're done. 803 */ 804 if (j == 0) 805 goto tryanother; 806 else 807 break; 808 } else { 809 /* 810 * A nonprintable 811 * character is also 812 * wrong. 813 */ 814 if (!isprint(c) || isquote(c)) 815 goto tryanother; 816 } 817 } 818 /* 819 * Well, that worked. 820 */ 821 822 /* 823 * Try next offsets, in case this match is 824 * in the middle of a string. 825 */ 826 for (k = i + 1 ; k < NOFFSETS ; k++) { 827 size_t no; 828 int adjust = 1; 829 if (prpsoffsets(k) >= prpsoffsets(i)) 830 continue; 831 for (no = doff + prpsoffsets(k); 832 no < doff + prpsoffsets(i); no++) 833 adjust = adjust 834 && isprint(nbuf[no]); 835 if (adjust) 836 i = k; 837 } 838 839 cname = (unsigned char *) 840 &nbuf[doff + prpsoffsets(i)]; 841 for (cp = cname; *cp && isprint(*cp); cp++) 842 continue; 843 /* 844 * Linux apparently appends a space at the end 845 * of the command line: remove it. 846 */ 847 while (cp > cname && isspace(cp[-1])) 848 cp--; 849 if (file_printf(ms, ", from '%.*s'", 850 (int)(cp - cname), cname) == -1) 851 return size; 852 *flags |= FLAGS_DID_CORE; 853 return size; 854 855 tryanother: 856 ; 857 } 858 } 859 break; 860 } 861#endif 862 return offset; 863} 864 865/* SunOS 5.x hardware capability descriptions */ 866typedef struct cap_desc { 867 uint64_t cd_mask; 868 const char *cd_name; 869} cap_desc_t; 870 871static const cap_desc_t cap_desc_sparc[] = { 872 { AV_SPARC_MUL32, "MUL32" }, 873 { AV_SPARC_DIV32, "DIV32" }, 874 { AV_SPARC_FSMULD, "FSMULD" }, 875 { AV_SPARC_V8PLUS, "V8PLUS" }, 876 { AV_SPARC_POPC, "POPC" }, 877 { AV_SPARC_VIS, "VIS" }, 878 { AV_SPARC_VIS2, "VIS2" }, 879 { AV_SPARC_ASI_BLK_INIT, "ASI_BLK_INIT" }, 880 { AV_SPARC_FMAF, "FMAF" }, 881 { AV_SPARC_FJFMAU, "FJFMAU" }, 882 { AV_SPARC_IMA, "IMA" }, 883 { 0, NULL } 884}; 885 886static const cap_desc_t cap_desc_386[] = { 887 { AV_386_FPU, "FPU" }, 888 { AV_386_TSC, "TSC" }, 889 { AV_386_CX8, "CX8" }, 890 { AV_386_SEP, "SEP" }, 891 { AV_386_AMD_SYSC, "AMD_SYSC" }, 892 { AV_386_CMOV, "CMOV" }, 893 { AV_386_MMX, "MMX" }, 894 { AV_386_AMD_MMX, "AMD_MMX" }, 895 { AV_386_AMD_3DNow, "AMD_3DNow" }, 896 { AV_386_AMD_3DNowx, "AMD_3DNowx" }, 897 { AV_386_FXSR, "FXSR" }, 898 { AV_386_SSE, "SSE" }, 899 { AV_386_SSE2, "SSE2" }, 900 { AV_386_PAUSE, "PAUSE" }, 901 { AV_386_SSE3, "SSE3" }, 902 { AV_386_MON, "MON" }, 903 { AV_386_CX16, "CX16" }, 904 { AV_386_AHF, "AHF" }, 905 { AV_386_TSCP, "TSCP" }, 906 { AV_386_AMD_SSE4A, "AMD_SSE4A" }, 907 { AV_386_POPCNT, "POPCNT" }, 908 { AV_386_AMD_LZCNT, "AMD_LZCNT" }, 909 { AV_386_SSSE3, "SSSE3" }, 910 { AV_386_SSE4_1, "SSE4.1" }, 911 { AV_386_SSE4_2, "SSE4.2" }, 912 { 0, NULL } 913}; 914 915private int 916doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, 917 size_t size, off_t fsize, int *flags, int mach, int strtab) 918{ 919 Elf32_Shdr sh32; 920 Elf64_Shdr sh64; 921 int stripped = 1; 922 size_t nbadcap = 0; 923 void *nbuf; 924 off_t noff, coff, name_off; 925 uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilites */ 926 uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilites */ 927 char name[50]; 928 929 if (size != xsh_sizeof) { 930 if (file_printf(ms, ", corrupted section header size") == -1) 931 return -1; 932 return 0; 933 } 934 935 /* Read offset of name section to be able to read section names later */ 936 if (pread(fd, xsh_addr, xsh_sizeof, off + size * strtab) == -1) { 937 file_badread(ms); 938 return -1; 939 } 940 name_off = xsh_offset; 941 942 for ( ; num; num--) { 943 /* Read the name of this section. */ 944 if (pread(fd, name, sizeof(name), name_off + xsh_name) == -1) { 945 file_badread(ms); 946 return -1; 947 } 948 name[sizeof(name) - 1] = '\0'; 949 if (strcmp(name, ".debug_info") == 0) 950 stripped = 0; 951 952 if (pread(fd, xsh_addr, xsh_sizeof, off) == -1) { 953 file_badread(ms); 954 return -1; 955 } 956 off += size; 957 958 /* Things we can determine before we seek */ 959 switch (xsh_type) { 960 case SHT_SYMTAB: 961#if 0 962 case SHT_DYNSYM: 963#endif 964 stripped = 0; 965 break; 966 default: 967 if (xsh_offset > fsize) { 968 /* Perhaps warn here */ 969 continue; 970 } 971 break; 972 } 973 974 /* Things we can determine when we seek */ 975 switch (xsh_type) { 976 case SHT_NOTE: 977 if ((nbuf = malloc(xsh_size)) == NULL) { 978 file_error(ms, errno, "Cannot allocate memory" 979 " for note"); 980 return -1; 981 } 982 if (pread(fd, nbuf, xsh_size, xsh_offset) == -1) { 983 file_badread(ms); 984 free(nbuf); 985 return -1; 986 } 987 988 noff = 0; 989 for (;;) { 990 if (noff >= (off_t)xsh_size) 991 break; 992 noff = donote(ms, nbuf, (size_t)noff, 993 xsh_size, clazz, swap, 4, flags); 994 if (noff == 0) 995 break; 996 } 997 free(nbuf); 998 break; 999 case SHT_SUNW_cap: 1000 switch (mach) { 1001 case EM_SPARC: 1002 case EM_SPARCV9: 1003 case EM_IA_64: 1004 case EM_386: 1005 case EM_AMD64: 1006 break; 1007 default: 1008 goto skip; 1009 } 1010 1011 if (nbadcap > 5) 1012 break; 1013 if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) { 1014 file_badseek(ms); 1015 return -1; 1016 } 1017 coff = 0; 1018 for (;;) { 1019 Elf32_Cap cap32; 1020 Elf64_Cap cap64; 1021 char cbuf[/*CONSTCOND*/ 1022 MAX(sizeof cap32, sizeof cap64)]; 1023 if ((coff += xcap_sizeof) > (off_t)xsh_size) 1024 break; 1025 if (read(fd, cbuf, (size_t)xcap_sizeof) != 1026 (ssize_t)xcap_sizeof) { 1027 file_badread(ms); 1028 return -1; 1029 } 1030 if (cbuf[0] == 'A') { 1031#ifdef notyet 1032 char *p = cbuf + 1; 1033 uint32_t len, tag; 1034 memcpy(&len, p, sizeof(len)); 1035 p += 4; 1036 len = getu32(swap, len); 1037 if (memcmp("gnu", p, 3) != 0) { 1038 if (file_printf(ms, 1039 ", unknown capability %.3s", p) 1040 == -1) 1041 return -1; 1042 break; 1043 } 1044 p += strlen(p) + 1; 1045 tag = *p++; 1046 memcpy(&len, p, sizeof(len)); 1047 p += 4; 1048 len = getu32(swap, len); 1049 if (tag != 1) { 1050 if (file_printf(ms, ", unknown gnu" 1051 " capability tag %d", tag) 1052 == -1) 1053 return -1; 1054 break; 1055 } 1056 // gnu attributes 1057#endif 1058 break; 1059 } 1060 (void)memcpy(xcap_addr, cbuf, xcap_sizeof); 1061 switch (xcap_tag) { 1062 case CA_SUNW_NULL: 1063 break; 1064 case CA_SUNW_HW_1: 1065 cap_hw1 |= xcap_val; 1066 break; 1067 case CA_SUNW_SF_1: 1068 cap_sf1 |= xcap_val; 1069 break; 1070 default: 1071 if (file_printf(ms, 1072 ", with unknown capability " 1073 "0x%" INT64_T_FORMAT "x = 0x%" 1074 INT64_T_FORMAT "x", 1075 (unsigned long long)xcap_tag, 1076 (unsigned long long)xcap_val) == -1) 1077 return -1; 1078 if (nbadcap++ > 2) 1079 coff = xsh_size; 1080 break; 1081 } 1082 } 1083 /*FALLTHROUGH*/ 1084 skip: 1085 default: 1086 break; 1087 } 1088 } 1089 1090 if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1) 1091 return -1; 1092 if (cap_hw1) { 1093 const cap_desc_t *cdp; 1094 switch (mach) { 1095 case EM_SPARC: 1096 case EM_SPARC32PLUS: 1097 case EM_SPARCV9: 1098 cdp = cap_desc_sparc; 1099 break; 1100 case EM_386: 1101 case EM_IA_64: 1102 case EM_AMD64: 1103 cdp = cap_desc_386; 1104 break; 1105 default: 1106 cdp = NULL; 1107 break; 1108 } 1109 if (file_printf(ms, ", uses") == -1) 1110 return -1; 1111 if (cdp) { 1112 while (cdp->cd_name) { 1113 if (cap_hw1 & cdp->cd_mask) { 1114 if (file_printf(ms, 1115 " %s", cdp->cd_name) == -1) 1116 return -1; 1117 cap_hw1 &= ~cdp->cd_mask; 1118 } 1119 ++cdp; 1120 } 1121 if (cap_hw1) 1122 if (file_printf(ms, 1123 " unknown hardware capability 0x%" 1124 INT64_T_FORMAT "x", 1125 (unsigned long long)cap_hw1) == -1) 1126 return -1; 1127 } else { 1128 if (file_printf(ms, 1129 " hardware capability 0x%" INT64_T_FORMAT "x", 1130 (unsigned long long)cap_hw1) == -1) 1131 return -1; 1132 } 1133 } 1134 if (cap_sf1) { 1135 if (cap_sf1 & SF1_SUNW_FPUSED) { 1136 if (file_printf(ms, 1137 (cap_sf1 & SF1_SUNW_FPKNWN) 1138 ? ", uses frame pointer" 1139 : ", not known to use frame pointer") == -1) 1140 return -1; 1141 } 1142 cap_sf1 &= ~SF1_SUNW_MASK; 1143 if (cap_sf1) 1144 if (file_printf(ms, 1145 ", with unknown software capability 0x%" 1146 INT64_T_FORMAT "x", 1147 (unsigned long long)cap_sf1) == -1) 1148 return -1; 1149 } 1150 return 0; 1151} 1152 1153/* 1154 * Look through the program headers of an executable image, searching 1155 * for a PT_INTERP section; if one is found, it's dynamically linked, 1156 * otherwise it's statically linked. 1157 */ 1158private int 1159dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 1160 int num, size_t size, off_t fsize, int *flags, int sh_num) 1161{ 1162 Elf32_Phdr ph32; 1163 Elf64_Phdr ph64; 1164 const char *linking_style = "statically"; 1165 const char *shared_libraries = ""; 1166 unsigned char nbuf[BUFSIZ]; 1167 ssize_t bufsize; 1168 size_t offset, align, len; 1169 1170 if (size != xph_sizeof) { 1171 if (file_printf(ms, ", corrupted program header size") == -1) 1172 return -1; 1173 return 0; 1174 } 1175 1176 for ( ; num; num--) { 1177 if (pread(fd, xph_addr, xph_sizeof, off) == -1) { 1178 file_badread(ms); 1179 return -1; 1180 } 1181 1182 off += size; 1183 1184 /* Things we can determine before we seek */ 1185 switch (xph_type) { 1186 case PT_DYNAMIC: 1187 linking_style = "dynamically"; 1188 break; 1189 case PT_INTERP: 1190 shared_libraries = " (uses shared libs)"; 1191 break; 1192 default: 1193 if (xph_offset > fsize) { 1194 /* Maybe warn here? */ 1195 continue; 1196 } 1197 break; 1198 } 1199 1200 /* Things we can determine when we seek */ 1201 switch (xph_type) { 1202 case PT_NOTE: 1203 if ((align = xph_align) & 0x80000000UL) { 1204 if (file_printf(ms, 1205 ", invalid note alignment 0x%lx", 1206 (unsigned long)align) == -1) 1207 return -1; 1208 align = 4; 1209 } 1210 if (sh_num) 1211 break; 1212 /* 1213 * This is a PT_NOTE section; loop through all the notes 1214 * in the section. 1215 */ 1216 len = xph_filesz < sizeof(nbuf) ? xph_filesz 1217 : sizeof(nbuf); 1218 bufsize = pread(fd, nbuf, len, xph_offset); 1219 if (bufsize == -1) { 1220 file_badread(ms); 1221 return -1; 1222 } 1223 offset = 0; 1224 for (;;) { 1225 if (offset >= (size_t)bufsize) 1226 break; 1227 offset = donote(ms, nbuf, offset, 1228 (size_t)bufsize, clazz, swap, align, 1229 flags); 1230 if (offset == 0) 1231 break; 1232 } 1233 break; 1234 default: 1235 break; 1236 } 1237 } 1238 if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries) 1239 == -1) 1240 return -1; 1241 return 0; 1242} 1243 1244 1245protected int 1246file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, 1247 size_t nbytes) 1248{ 1249 union { 1250 int32_t l; 1251 char c[sizeof (int32_t)]; 1252 } u; 1253 int clazz; 1254 int swap; 1255 struct stat st; 1256 off_t fsize; 1257 int flags = 0; 1258 Elf32_Ehdr elf32hdr; 1259 Elf64_Ehdr elf64hdr; 1260 uint16_t type, phnum, shnum; 1261 1262 if (ms->flags & (MAGIC_MIME|MAGIC_APPLE)) 1263 return 0; 1264 /* 1265 * ELF executables have multiple section headers in arbitrary 1266 * file locations and thus file(1) cannot determine it from easily. 1267 * Instead we traverse thru all section headers until a symbol table 1268 * one is found or else the binary is stripped. 1269 * Return immediately if it's not ELF (so we avoid pipe2file unless needed). 1270 */ 1271 if (buf[EI_MAG0] != ELFMAG0 1272 || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) 1273 || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) 1274 return 0; 1275 1276 /* 1277 * If we cannot seek, it must be a pipe, socket or fifo. 1278 */ 1279 if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) 1280 fd = file_pipe2file(ms, fd, buf, nbytes); 1281 1282 if (fstat(fd, &st) == -1) { 1283 file_badread(ms); 1284 return -1; 1285 } 1286 fsize = st.st_size; 1287 1288 clazz = buf[EI_CLASS]; 1289 1290 switch (clazz) { 1291 case ELFCLASS32: 1292#undef elf_getu 1293#define elf_getu(a, b) elf_getu32(a, b) 1294#undef elfhdr 1295#define elfhdr elf32hdr 1296#include "elfclass.h" 1297 case ELFCLASS64: 1298#undef elf_getu 1299#define elf_getu(a, b) elf_getu64(a, b) 1300#undef elfhdr 1301#define elfhdr elf64hdr 1302#include "elfclass.h" 1303 default: 1304 if (file_printf(ms, ", unknown class %d", clazz) == -1) 1305 return -1; 1306 break; 1307 } 1308 return 0; 1309} 1310#endif 1311