version 1.3, 2002/06/05 13:46:44 |
version 1.4, 2003/03/03 22:24:08 |
|
|
/* $OpenBSD$ */ |
#include "file.h" |
|
|
#ifdef BUILTIN_ELF |
#ifdef BUILTIN_ELF |
#include <sys/types.h> |
|
#include <string.h> |
#include <string.h> |
#include <stdio.h> |
|
#include <ctype.h> |
#include <ctype.h> |
#include <stdlib.h> |
#include <stdlib.h> |
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#include <unistd.h> |
#include <errno.h> |
#endif |
|
|
#include "readelf.h" |
#include "readelf.h" |
#include "file.h" |
|
|
|
|
#ifndef lint |
|
static char *RCSID = "@(#)$Id$"; |
|
#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 { |
|
uint16_t ui; |
|
char c[2]; |
|
} retval, tmpval; |
|
|
|
if (swap) { |
|
tmpval.ui = value; |
|
|
|
retval.c[0] = tmpval.c[1]; |
|
retval.c[1] = tmpval.c[0]; |
|
|
|
return retval.ui; |
|
} else |
|
return value; |
|
} |
|
|
|
static uint32_t |
|
getu32(int swap, uint32_t value) |
|
{ |
|
union { |
|
uint32_t ui; |
|
char c[4]; |
|
} retval, tmpval; |
|
|
|
if (swap) { |
|
tmpval.ui = value; |
|
|
|
retval.c[0] = tmpval.c[3]; |
|
retval.c[1] = tmpval.c[2]; |
|
retval.c[2] = tmpval.c[1]; |
|
retval.c[3] = tmpval.c[0]; |
|
|
|
return retval.ui; |
|
} else |
|
return value; |
|
} |
|
|
|
static uint64_t |
|
getu64(int swap, uint64_t value) |
|
{ |
|
union { |
|
uint64_t ui; |
|
char c[8]; |
|
} retval, tmpval; |
|
|
|
if (swap) { |
|
tmpval.ui = value; |
|
|
|
retval.c[0] = tmpval.c[7]; |
|
retval.c[1] = tmpval.c[6]; |
|
retval.c[2] = tmpval.c[5]; |
|
retval.c[3] = tmpval.c[4]; |
|
retval.c[4] = tmpval.c[3]; |
|
retval.c[5] = tmpval.c[2]; |
|
retval.c[6] = tmpval.c[1]; |
|
retval.c[7] = tmpval.c[0]; |
|
|
|
return retval.ui; |
|
} else |
|
return value; |
|
} |
|
|
|
#define sh_addr (class == ELFCLASS32 \ |
|
? (void *) &sh32 \ |
|
: (void *) &sh64) |
|
#define sh_size (class == ELFCLASS32 \ |
|
? sizeof sh32 \ |
|
: sizeof sh64) |
|
#define shs_type (class == ELFCLASS32 \ |
|
? getu32(swap, sh32.sh_type) \ |
|
: getu32(swap, sh64.sh_type)) |
|
#define ph_addr (class == ELFCLASS32 \ |
|
? (void *) &ph32 \ |
|
: (void *) &ph64) |
|
#define ph_size (class == ELFCLASS32 \ |
|
? sizeof ph32 \ |
|
: sizeof ph64) |
|
#define ph_type (class == ELFCLASS32 \ |
|
? getu32(swap, ph32.p_type) \ |
|
: getu32(swap, ph64.p_type)) |
|
#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 |
static void |
doshn(fd, off, num, size, buf) |
doshn(int class, int swap, int fd, off_t off, int num, size_t size) |
int fd; |
|
off_t off; |
|
int num; |
|
size_t size; |
|
char *buf; |
|
{ |
{ |
/* |
Elf32_Shdr sh32; |
* This works for both 32-bit and 64-bit ELF formats, |
Elf64_Shdr sh64; |
* because it looks only at the "sh_type" field, which is |
|
* always 32 bits, and is preceded only by the "sh_name" |
|
* field which is also always 32 bits, and because it uses |
|
* the shdr size from the ELF header rather than using |
|
* the size of an "Elf32_Shdr". |
|
*/ |
|
Elf32_Shdr *sh = (Elf32_Shdr *) buf; |
|
|
|
|
if (size != sh_size) |
|
error("corrupted section header size.\n"); |
|
|
if (lseek(fd, off, SEEK_SET) == -1) |
if (lseek(fd, off, SEEK_SET) == -1) |
err(1, "lseek failed"); |
error("lseek failed (%s).\n", strerror(errno)); |
|
|
for ( ; num; num--) { |
for ( ; num; num--) { |
if (read(fd, buf, size) == -1) |
if (read(fd, sh_addr, sh_size) == -1) |
err(1, "read failed"); |
error("read failed (%s).\n", strerror(errno)); |
if (sh->sh_type == SHT_SYMTAB) { |
if (shs_type == SHT_SYMTAB /* || shs_type == SHT_DYNSYM */) { |
(void) printf (", not stripped"); |
(void) printf (", not stripped"); |
return; |
return; |
} |
} |
|
|
* otherwise it's statically linked. |
* otherwise it's statically linked. |
*/ |
*/ |
static void |
static void |
dophn_exec(fd, off, num, size, buf) |
dophn_exec(int class, int swap, int fd, off_t off, int num, size_t size) |
int fd; |
|
off_t off; |
|
int num; |
|
size_t size; |
|
char *buf; |
|
{ |
{ |
/* I am not sure if this works for 64 bit elf formats */ |
Elf32_Phdr ph32; |
Elf32_Phdr *ph = (Elf32_Phdr *) buf; |
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) |
if (lseek(fd, off, SEEK_SET) == -1) |
err(1, "lseek failed"); |
error("lseek failed (%s).\n", strerror(errno)); |
|
|
for ( ; num; num--) { |
for ( ; num; num--) { |
if (read(fd, buf, size) == -1) |
if (read(fd, ph_addr, ph_size) == -1) |
err(1, "read failed"); |
error("read failed (%s).\n", strerror(errno)); |
if (ph->p_type == PT_INTERP) { |
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: |
/* |
/* |
* Has an interpreter - must be a dynamically-linked |
* This is a PT_NOTE section; loop through all the notes |
* executable. |
* in the section. |
*/ |
*/ |
printf(", dynamically linked"); |
if (lseek(fd, (off_t) ph_offset, SEEK_SET) == -1) |
return; |
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("<unknown>"); |
|
} |
|
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(", statically linked"); |
printf(", %s linked%s", linking_style, shared_libraries); |
} |
} |
|
|
size_t prpsoffsets[] = { |
#ifdef ELFCORE |
100, /* SunOS 5.x */ |
size_t prpsoffsets32[] = { |
32, /* Linux */ |
8, /* FreeBSD */ |
|
28, /* Linux 2.0.36 */ |
|
32, /* Linux (I forget which kernel version) */ |
|
84, /* SunOS 5.x */ |
}; |
}; |
|
|
#define NOFFSETS (sizeof prpsoffsets / sizeof prpsoffsets[0]) |
size_t prpsoffsets64[] = { |
|
120, /* SunOS 5.x, 64-bit */ |
|
}; |
|
|
|
#define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0]) |
|
#define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0]) |
|
|
|
#define NOFFSETS (class == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64) |
|
|
/* |
/* |
* Look through the program headers of an executable image, searching |
* Look through the program headers of an executable image, searching |
* for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE"; if one |
* for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or |
* is found, try looking in various places in its contents for a 16-character |
* "FreeBSD"; if one is found, try looking in various places in its |
* string containing only printable characters - if found, that string |
* contents for a 16-character string containing only printable |
* should be the name of the program that dropped core. |
* characters - if found, that string should be the name of the program |
* Note: right after that 16-character string is, at least in SunOS 5.x |
* that dropped core. Note: right after that 16-character string is, |
* (and possibly other SVR4-flavored systems) and Linux, a longer string |
* at least in SunOS 5.x (and possibly other SVR4-flavored systems) and |
* (80 characters, in 5.x, probably other SVR4-flavored systems, and Linux) |
* Linux, a longer string (80 characters, in 5.x, probably other |
* containing the start of the command line for that program. |
* SVR4-flavored systems, and Linux) containing the start of the |
|
* command line for that program. |
|
* |
|
* The signal number probably appears in a section of type NT_PRSTATUS, |
|
* but that's also rather OS-dependent, in ways that are harder to |
|
* dissect with heuristics, so I'm not bothering with the signal number. |
|
* (I suppose the signal number could be of interest in situations where |
|
* you don't have the binary of the program that dropped core; if you |
|
* *do* have that binary, the debugger will probably tell you what |
|
* signal it was.) |
*/ |
*/ |
|
|
|
#define OS_STYLE_SVR4 0 |
|
#define OS_STYLE_FREEBSD 1 |
|
#define OS_STYLE_NETBSD 2 |
|
|
|
static const char *os_style_names[] = { |
|
"SVR4", |
|
"FreeBSD", |
|
"NetBSD", |
|
}; |
|
|
static void |
static void |
dophn_core(fd, off, num, size, buf) |
dophn_core(int class, int swap, int fd, off_t off, int num, size_t size) |
int fd; |
|
off_t off; |
|
int num; |
|
size_t size; |
|
char *buf; |
|
{ |
{ |
/* |
Elf32_Phdr ph32; |
* This doesn't work for 64-bit ELF, as the "p_offset" field is |
Elf32_Nhdr *nh32 = NULL; |
* 64 bits in 64-bit ELF. |
Elf64_Phdr ph64; |
*/ |
Elf64_Nhdr *nh64 = NULL; |
/* |
size_t offset, nameoffset, noffset, reloffset; |
* This doesn't work for 64-bit ELF, as the "p_offset" field is |
|
* 64 bits in 64-bit ELF. |
|
*/ |
|
Elf32_Phdr *ph = (Elf32_Phdr *) buf; |
|
Elf32_Nhdr *nh; |
|
size_t offset, noffset, reloffset; |
|
unsigned char c; |
unsigned char c; |
int i, j; |
int i, j; |
char nbuf[BUFSIZ]; |
char nbuf[BUFSIZ]; |
int bufsize; |
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--) { |
for ( ; num; num--) { |
if (lseek(fd, off, SEEK_SET) == -1) |
if (lseek(fd, off, SEEK_SET) == -1) |
err(1, "lseek failed"); |
error("lseek failed (%s).\n", strerror(errno)); |
if (read(fd, buf, size) == -1) |
if (read(fd, ph_addr, ph_size) == -1) |
err(1, "read failed"); |
error("read failed (%s).\n", strerror(errno)); |
off += size; |
off += size; |
if (ph->p_type != PT_NOTE) |
if (ph_type != PT_NOTE) |
continue; |
continue; |
if (lseek(fd, ph->p_offset, SEEK_SET) == -1) |
|
err(1, "lseek failed"); |
/* |
|
* 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); |
bufsize = read(fd, nbuf, BUFSIZ); |
if (bufsize == -1) |
if (bufsize == -1) |
err(1, "read failed"); |
error(": " "read failed (%s).\n", strerror(errno)); |
offset = 0; |
offset = 0; |
for (;;) { |
for (;;) { |
if (offset >= bufsize) |
if (offset >= bufsize) |
break; |
break; |
nh = (Elf32_Nhdr *)&nbuf[offset]; |
if (class == ELFCLASS32) |
offset += sizeof *nh; |
nh32 = (Elf32_Nhdr *)&nbuf[offset]; |
|
else |
|
nh64 = (Elf64_Nhdr *)&nbuf[offset]; |
|
offset += nh_size; |
|
|
/* |
/* |
* If this note isn't an NT_PRPSINFO note, it's |
* Check whether this note has the name "CORE" or |
* not what we're looking for. |
* "FreeBSD", or "NetBSD-CORE". |
*/ |
*/ |
if (nh->n_type != NT_PRPSINFO) { |
if (offset + nh_namesz >= bufsize) { |
offset += nh->n_namesz; |
|
offset = ((offset + 3)/4)*4; |
|
offset += nh->n_descsz; |
|
offset = ((offset + 3)/4)*4; |
|
continue; |
|
} |
|
|
|
/* |
|
* Make sure this note has the name "CORE". |
|
*/ |
|
if (offset + nh->n_namesz >= bufsize) { |
|
/* |
/* |
* We're past the end of the buffer. |
* We're past the end of the buffer. |
*/ |
*/ |
break; |
break; |
} |
} |
if (nh->n_namesz != 5 |
|
|| strcmp(&nbuf[offset], "CORE") != 0) |
nameoffset = offset; |
continue; |
offset += nh_namesz; |
offset += nh->n_namesz; |
|
offset = ((offset + 3)/4)*4; |
offset = ((offset + 3)/4)*4; |
|
|
/* |
/* |
* Extract the program name. We assume it to be |
* Sigh. The 2.0.36 kernel in Debian 2.1, at |
* 16 characters (that's what it is in SunOS 5.x |
* least, doesn't correctly implement name |
* and Linux). |
* sections, in core dumps, as specified by |
* |
* the "Program Linking" section of "UNIX(R) System |
* Unfortunately, it's at a different offset in |
* V Release 4 Programmer's Guide: ANSI C and |
* SunOS 5.x and Linux, so try multiple offsets. |
* Programming Support Tools", because my copy |
* If the characters aren't all printable, reject |
* clearly says "The first 'namesz' bytes in 'name' |
* it. |
* 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.... |
*/ |
*/ |
for (i = 0; i < NOFFSETS; i++) { |
if (os_style == -1) { |
reloffset = prpsoffsets[i]; |
if ((nh_namesz == 4 && |
noffset = offset + reloffset; |
strncmp(&nbuf[nameoffset], |
for (j = 0; j < 16; |
"CORE", 4) == 0) || |
j++, noffset++, reloffset++) { |
(nh_namesz == 5 && |
/* |
strcmp(&nbuf[nameoffset], |
* Make sure we're not past the end |
"CORE") == 0)) { |
* of the buffer; if we are, just |
os_style = OS_STYLE_SVR4; |
* give up. |
} else |
*/ |
if ((nh_namesz == 8 && |
if (noffset >= bufsize) |
strcmp(&nbuf[nameoffset], |
return; |
"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 && |
* Make sure we're not past the |
nh_type == NT_NETBSD_CORE_PROCINFO) { |
* end of the contents; if we |
uint32_t signo; |
* are, this obviously isn't |
|
* the right offset. |
|
*/ |
|
if (reloffset >= nh->n_descsz) |
|
goto tryanother; |
|
|
|
c = nbuf[noffset]; |
|
if (c != '\0' && !isprint(c)) |
|
goto tryanother; |
|
} |
|
|
|
/* |
/* |
* Well, that worked. |
* Extract the program name. It is at |
|
* offset 0x7c, and is up to 32-bytes, |
|
* including the terminating NUL. |
*/ |
*/ |
printf(", from '%.16s'", |
printf(", from '%.31s'", &nbuf[offset + 0x7c]); |
&nbuf[offset + prpsoffsets[i]]); |
|
return; |
/* |
|
* 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 varous 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; |
|
|
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->n_descsz; |
offset += nh_descsz; |
offset = ((offset + 3)/4)*4; |
offset = ((offset + 3)/4)*4; |
} |
} |
} |
} |
} |
} |
|
#endif |
|
|
void |
void |
tryelf(fd, buf, nbytes) |
tryelf(int fd, unsigned char *buf, int nbytes) |
int fd; |
|
char *buf; |
|
int nbytes; |
|
{ |
{ |
union { |
union { |
int32_t l; |
int32_t l; |
char c[sizeof (int32_t)]; |
char c[sizeof (int32_t)]; |
} u; |
} u; |
|
int class; |
|
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 |
* ELF executables have multiple section headers in arbitrary |
* file locations and thus file(1) cannot determine it from easily. |
* file locations and thus file(1) cannot determine it from easily. |
* Instead we traverse thru all section headers until a symbol table |
* Instead we traverse thru all section headers until a symbol table |
* one is found or else the binary is stripped. |
* one is found or else the binary is stripped. |
*/ |
*/ |
if (buf[EI_MAG0] != ELFMAG0 || buf[EI_MAG1] != ELFMAG1 |
if (buf[EI_MAG0] != ELFMAG0 |
|
|| (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) |
|| buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) |
|| buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) |
return; |
return; |
|
|
|
|
if (buf[4] == ELFCLASS32) { |
class = buf[4]; |
|
|
|
if (class == ELFCLASS32) { |
Elf32_Ehdr elfhdr; |
Elf32_Ehdr elfhdr; |
if (nbytes <= sizeof (Elf32_Ehdr)) |
if (nbytes <= sizeof (Elf32_Ehdr)) |
return; |
return; |
|
|
|
|
u.l = 1; |
u.l = 1; |
(void) memcpy(&elfhdr, buf, sizeof elfhdr); |
(void) memcpy(&elfhdr, buf, sizeof elfhdr); |
/* |
swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5]; |
* If the system byteorder does not equal the |
|
* object byteorder then don't test. |
if (getu16(swap, elfhdr.e_type) == ET_CORE) |
* XXX - we could conceivably fix up the "dophn_XXX()" and |
#ifdef ELFCORE |
* "doshn()" routines to extract stuff in the right |
dophn_core(class, swap, |
* byte order.... |
fd, |
*/ |
getu32(swap, elfhdr.e_phoff), |
if ((u.c[sizeof(long) - 1] + 1) == elfhdr.e_ident[5]) { |
getu16(swap, elfhdr.e_phnum), |
if (elfhdr.e_type == ET_CORE) |
getu16(swap, elfhdr.e_phentsize)); |
dophn_core(fd, elfhdr.e_phoff, elfhdr.e_phnum, |
#else |
elfhdr.e_phentsize, buf); |
; |
else { |
#endif |
if (elfhdr.e_type == ET_EXEC) { |
else { |
dophn_exec(fd, elfhdr.e_phoff, |
if (getu16(swap, elfhdr.e_type) == ET_EXEC) { |
elfhdr.e_phnum, |
dophn_exec(class, swap, |
elfhdr.e_phentsize, buf); |
fd, |
} |
getu32(swap, elfhdr.e_phoff), |
doshn(fd, elfhdr.e_shoff, elfhdr.e_shnum, |
getu16(swap, elfhdr.e_phnum), |
elfhdr.e_shentsize, buf); |
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; |
return; |
} |
} |
|
|
if (buf[4] == ELFCLASS64) { |
if (class == ELFCLASS64) { |
Elf64_Ehdr elfhdr; |
Elf64_Ehdr elfhdr; |
if (nbytes <= sizeof (Elf64_Ehdr)) |
if (nbytes <= sizeof (Elf64_Ehdr)) |
return; |
return; |
|
|
|
|
u.l = 1; |
u.l = 1; |
(void) memcpy(&elfhdr, buf, sizeof elfhdr); |
(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) |
* If the system byteorder does not equal the |
#ifdef ELFCORE |
* object byteorder then don't test. |
dophn_core(class, swap, |
* XXX - we could conceivably fix up the "dophn_XXX()" and |
fd, |
* "doshn()" routines to extract stuff in the right |
#ifdef USE_ARRAY_FOR_64BIT_TYPES |
* byte order.... |
getu32(swap, elfhdr.e_phoff[1]), |
*/ |
#else |
if ((u.c[sizeof(long) - 1] + 1) == elfhdr.e_ident[5]) { |
getu64(swap, elfhdr.e_phoff), |
#ifdef notyet |
|
if (elfhdr.e_type == ET_CORE) |
|
dophn_core(fd, elfhdr.e_phoff, elfhdr.e_phnum, |
|
elfhdr.e_phentsize, buf); |
|
else |
|
#endif |
#endif |
{ |
getu16(swap, elfhdr.e_phnum), |
#ifdef notyet |
getu16(swap, elfhdr.e_phentsize)); |
if (elfhdr.e_type == ET_EXEC) { |
#else |
dophn_exec(fd, elfhdr.e_phoff, |
; |
elfhdr.e_phnum, |
|
elfhdr.e_phentsize, buf); |
|
} |
|
#endif |
#endif |
doshn(fd, elfhdr.e_shoff, elfhdr.e_shnum, |
else |
elfhdr.e_shentsize, buf); |
{ |
|
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; |
return; |
} |
} |