aboutsummaryrefslogtreecommitdiff
path: root/contrib/file/readelf.c
diff options
context:
space:
mode:
authorDavid E. O'Brien <obrien@FreeBSD.org>2003-03-16 04:44:56 +0000
committerDavid E. O'Brien <obrien@FreeBSD.org>2003-03-16 04:44:56 +0000
commitb2efde6a46242b4cbcd9118c3782f8d3d03dca61 (patch)
treec7487e54c0ac0c8430546e119b7a84badaf777f8 /contrib/file/readelf.c
parent58efe8034ce2368e7157ed668544fb8af68ab128 (diff)
downloadsrc-b2efde6a46242b4cbcd9118c3782f8d3d03dca61.tar.gz
src-b2efde6a46242b4cbcd9118c3782f8d3d03dca61.zip
MFC: file version 3.41
Approved by: murray(re) Desired by: nectar(so)
Notes
Notes: svn path=/stable/4/; revision=112313
Diffstat (limited to 'contrib/file/readelf.c')
-rw-r--r--contrib/file/readelf.c291
1 files changed, 225 insertions, 66 deletions
diff --git a/contrib/file/readelf.c b/contrib/file/readelf.c
index 3c5c41436878..2259558b7162 100644
--- a/contrib/file/readelf.c
+++ b/contrib/file/readelf.c
@@ -1,36 +1,31 @@
#include "file.h"
#ifdef BUILTIN_ELF
-#include <sys/types.h>
#include <string.h>
-#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#include <errno.h>
#include "readelf.h"
#ifndef lint
-FILE_RCSID("@(#)$Id: readelf.c,v 1.17 2000/08/05 19:00:12 christos Exp $")
+FILE_RCSID("@(#)$Id: readelf.c,v 1.26 2003/02/25 15:30:00 christos Exp $")
#endif
#ifdef ELFCORE
-static void dophn_core __P((int, int, int, off_t, int, size_t));
+static void dophn_core(int, int, int, off_t, int, size_t);
#endif
-static void dophn_exec __P((int, int, int, off_t, int, size_t));
-static void doshn __P((int, int, int, off_t, int, size_t));
+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 __P((int, int));
-static uint32_t getu32 __P((int, uint32_t));
-static uint64_t getu64 __P((int, uint64_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(swap, value)
- int swap;
- uint16_t value;
+getu16(int swap, uint16_t value)
{
union {
uint16_t ui;
@@ -49,9 +44,7 @@ getu16(swap, value)
}
static uint32_t
-getu32(swap, value)
- int swap;
- uint32_t value;
+getu32(int swap, uint32_t value)
{
union {
uint32_t ui;
@@ -72,9 +65,7 @@ getu32(swap, value)
}
static uint64_t
-getu64(swap, value)
- int swap;
- uint64_t value;
+getu64(int swap, uint64_t value)
{
union {
uint64_t ui;
@@ -101,18 +92,27 @@ getu64(swap, 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)
@@ -130,22 +130,19 @@ getu64(swap, value)
: prpsoffsets64[i])
static void
-doshn(class, swap, fd, off, num, size)
- int class;
- int swap;
- int fd;
- off_t off;
- int num;
- size_t size;
+doshn(int class, int swap, int fd, off_t off, int num, size_t size)
{
Elf32_Shdr sh32;
Elf64_Shdr sh64;
+ if (size != sh_size)
+ error("corrupted section header size.\n");
+
if (lseek(fd, off, SEEK_SET) == -1)
error("lseek failed (%s).\n", strerror(errno));
for ( ; num; num--) {
- if (read(fd, sh_addr, size) == -1)
+ if (read(fd, sh_addr, sh_size) == -1)
error("read failed (%s).\n", strerror(errno));
if (shs_type == SHT_SYMTAB /* || shs_type == SHT_DYNSYM */) {
(void) printf (", not stripped");
@@ -161,25 +158,29 @@ doshn(class, swap, fd, off, num, size)
* otherwise it's statically linked.
*/
static void
-dophn_exec(class, swap, fd, off, num, size)
- int class;
- int swap;
- int fd;
- off_t off;
- int num;
- size_t size;
+dophn_exec(int class, int swap, int fd, off_t off, int num, size_t size)
{
Elf32_Phdr ph32;
+ Elf32_Nhdr *nh32 = NULL;
Elf64_Phdr ph64;
+ Elf64_Nhdr *nh64 = NULL;
char *linking_style = "statically";
char *shared_libraries = "";
+ char nbuf[BUFSIZ];
+ int bufsize;
+ size_t offset, nameoffset;
+ off_t savedoffset;
+ if (size != ph_size)
+ error("corrupted program header size.\n");
if (lseek(fd, off, SEEK_SET) == -1)
error("lseek failed (%s).\n", strerror(errno));
for ( ; num; num--) {
- if (read(fd, ph_addr, size) == -1)
+ if (read(fd, ph_addr, ph_size) == -1)
error("read failed (%s).\n", strerror(errno));
+ if ((savedoffset = lseek(fd, 0, SEEK_CUR)) == -1)
+ error("lseek failed (%s).\n", strerror(errno));
switch (ph_type) {
case PT_DYNAMIC:
@@ -188,6 +189,121 @@ dophn_exec(class, swap, fd, off, num, size)
case PT_INTERP:
shared_libraries = " (uses shared libs)";
break;
+ case PT_NOTE:
+ /*
+ * This is a PT_NOTE section; loop through all the notes
+ * in the section.
+ */
+ if (lseek(fd, (off_t) ph_offset, SEEK_SET) == -1)
+ error("lseek failed (%s).\n", strerror(errno));
+ bufsize = read(fd, nbuf, sizeof(nbuf));
+ if (bufsize == -1)
+ error(": " "read failed (%s).\n",
+ strerror(errno));
+ offset = 0;
+ for (;;) {
+ if (offset >= bufsize)
+ break;
+ if (class == ELFCLASS32)
+ nh32 = (Elf32_Nhdr *)&nbuf[offset];
+ else
+ nh64 = (Elf64_Nhdr *)&nbuf[offset];
+ offset += nh_size;
+
+ if (offset + nh_namesz >= bufsize) {
+ /*
+ * We're past the end of the buffer.
+ */
+ break;
+ }
+
+ nameoffset = offset;
+ offset += nh_namesz;
+ offset = ((offset+ph_align-1)/ph_align)*ph_align;
+
+ if ((nh_namesz == 0) && (nh_descsz == 0)) {
+ /*
+ * We're out of note headers.
+ */
+ break;
+ }
+
+ if (offset + nh_descsz >= bufsize)
+ break;
+
+ if (nh_namesz == 4 &&
+ strcmp(&nbuf[nameoffset], "GNU") == 0 &&
+ nh_type == NT_GNU_VERSION &&
+ nh_descsz == 16) {
+ uint32_t *desc =
+ (uint32_t *)&nbuf[offset];
+
+ printf(", for GNU/");
+ switch (getu32(swap, desc[0])) {
+ case GNU_OS_LINUX:
+ printf("Linux");
+ break;
+ case GNU_OS_HURD:
+ printf("Hurd");
+ break;
+ case GNU_OS_SOLARIS:
+ printf("Solaris");
+ break;
+ default:
+ printf("<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(", %s linked%s", linking_style, shared_libraries);
@@ -230,33 +346,40 @@ size_t prpsoffsets64[] = {
* *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
-dophn_core(class, swap, fd, off, num, size)
- int class;
- int swap;
- int fd;
- off_t off;
- int num;
- size_t size;
+dophn_core(int class, int swap, int fd, off_t off, int num, size_t size)
{
Elf32_Phdr ph32;
- Elf32_Nhdr *nh32;
+ Elf32_Nhdr *nh32 = NULL;
Elf64_Phdr ph64;
- Elf64_Nhdr *nh64;
+ Elf64_Nhdr *nh64 = NULL;
size_t offset, nameoffset, noffset, reloffset;
unsigned char c;
int i, j;
char nbuf[BUFSIZ];
int bufsize;
- int is_freebsd;
+ int os_style = -1;
+ if (size != ph_size)
+ error("corrupted program header size.\n");
/*
* Loop through all the program headers.
*/
for ( ; num; num--) {
if (lseek(fd, off, SEEK_SET) == -1)
error("lseek failed (%s).\n", strerror(errno));
- if (read(fd, ph_addr, size) == -1)
+ if (read(fd, ph_addr, ph_size) == -1)
error("read failed (%s).\n", strerror(errno));
off += size;
if (ph_type != PT_NOTE)
@@ -283,7 +406,7 @@ dophn_core(class, swap, fd, off, num, size)
/*
* Check whether this note has the name "CORE" or
- * "FreeBSD".
+ * "FreeBSD", or "NetBSD-CORE".
*/
if (offset + nh_namesz >= bufsize) {
/*
@@ -310,17 +433,50 @@ dophn_core(class, swap, fd, off, num, size)
* doesn't include the terminating null in the
* name....
*/
- if ((nh_namesz == 4 &&
- strncmp(&nbuf[nameoffset], "CORE", 4) == 0) ||
- (nh_namesz == 5 &&
- strcmp(&nbuf[nameoffset], "CORE") == 0))
- is_freebsd = 0;
- else if ((nh_namesz == 8 &&
- strcmp(&nbuf[nameoffset], "FreeBSD") == 0))
- is_freebsd = 1;
- else
- continue;
- if (nh_type == NT_PRPSINFO) {
+ if (os_style == -1) {
+ if ((nh_namesz == 4 &&
+ strncmp(&nbuf[nameoffset],
+ "CORE", 4) == 0) ||
+ (nh_namesz == 5 &&
+ strcmp(&nbuf[nameoffset],
+ "CORE") == 0)) {
+ os_style = OS_STYLE_SVR4;
+ } else
+ if ((nh_namesz == 8 &&
+ strcmp(&nbuf[nameoffset],
+ "FreeBSD") == 0)) {
+ os_style = OS_STYLE_FREEBSD;
+ } else
+ if ((nh_namesz >= 11 &&
+ strncmp(&nbuf[nameoffset],
+ "NetBSD-CORE", 11) == 0)) {
+ os_style = OS_STYLE_NETBSD;
+ } else
+ continue;
+ printf(", %s-style", os_style_names[os_style]);
+ }
+
+ if (os_style == OS_STYLE_NETBSD &&
+ nh_type == NT_NETBSD_CORE_PROCINFO) {
+ uint32_t signo;
+
+ /*
+ * Extract the program name. It is at
+ * offset 0x7c, and is up to 32-bytes,
+ * including the terminating NUL.
+ */
+ printf(", from '%.31s'", &nbuf[offset + 0x7c]);
+
+ /*
+ * Extract the signal number. It is at
+ * offset 0x08.
+ */
+ memcpy(&signo, &nbuf[offset + 0x08],
+ sizeof(signo));
+ printf(" (signal %u)", getu32(swap, signo));
+ } else
+ if (os_style != OS_STYLE_NETBSD &&
+ nh_type == NT_PRPSINFO) {
/*
* Extract the program name. We assume
* it to be 16 characters (that's what it
@@ -399,19 +555,22 @@ dophn_core(class, swap, fd, off, num, size)
#endif
void
-tryelf(fd, buf, nbytes)
- int fd;
- unsigned char *buf;
- int nbytes;
+tryelf(int fd, unsigned char *buf, int nbytes)
{
union {
- int32 l;
- char c[sizeof (int32)];
+ int32_t l;
+ char c[sizeof (int32_t)];
} 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
* file locations and thus file(1) cannot determine it from easily.
* Instead we traverse thru all section headers until a symbol table
@@ -433,7 +592,7 @@ tryelf(fd, buf, nbytes)
u.l = 1;
(void) memcpy(&elfhdr, buf, sizeof elfhdr);
- swap = (u.c[sizeof(int32) - 1] + 1) != elfhdr.e_ident[5];
+ swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5];
if (getu16(swap, elfhdr.e_type) == ET_CORE)
#ifdef ELFCORE
@@ -470,7 +629,7 @@ tryelf(fd, buf, nbytes)
u.l = 1;
(void) memcpy(&elfhdr, buf, sizeof elfhdr);
- swap = (u.c[sizeof(int32) - 1] + 1) != elfhdr.e_ident[5];
+ swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5];
if (getu16(swap, elfhdr.e_type) == ET_CORE)
#ifdef ELFCORE