summaryrefslogtreecommitdiff
path: root/readelf.c
diff options
context:
space:
mode:
Diffstat (limited to 'readelf.c')
-rw-r--r--readelf.c193
1 files changed, 98 insertions, 95 deletions
diff --git a/readelf.c b/readelf.c
index 6f0b328cac80..8b141e12d405 100644
--- a/readelf.c
+++ b/readelf.c
@@ -27,7 +27,7 @@
#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$File: readelf.c,v 1.81 2008/11/04 16:38:28 christos Exp $")
+FILE_RCSID("@(#)$File: readelf.c,v 1.90 2011/08/23 08:01:12 christos Exp $")
#endif
#ifdef BUILTIN_ELF
@@ -47,8 +47,8 @@ private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t,
#endif
private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t,
off_t, int *, int);
-private int doshn(struct magic_set *, int, int, int, off_t, int, size_t, int *,
- int);
+private int doshn(struct magic_set *, int, int, int, off_t, int, size_t,
+ off_t, int *, int);
private size_t donote(struct magic_set *, void *, size_t, size_t, int,
int, size_t, int *);
@@ -144,7 +144,7 @@ getu64(int swap, uint64_t value)
#define xsh_size (clazz == ELFCLASS32 \
? elf_getu32(swap, sh32.sh_size) \
: elf_getu64(swap, sh64.sh_size))
-#define xsh_offset (clazz == ELFCLASS32 \
+#define xsh_offset (off_t)(clazz == ELFCLASS32 \
? elf_getu32(swap, sh32.sh_offset) \
: elf_getu64(swap, sh64.sh_offset))
#define xsh_type (clazz == ELFCLASS32 \
@@ -283,9 +283,11 @@ private const char os_style_names[][8] = {
"NetBSD",
};
-#define FLAGS_DID_CORE 1
-#define FLAGS_DID_NOTE 2
-#define FLAGS_DID_CORE_STYLE 4
+#define FLAGS_DID_CORE 0x01
+#define FLAGS_DID_NOTE 0x02
+#define FLAGS_DID_BUILD_ID 0x04
+#define FLAGS_DID_CORE_STYLE 0x08
+#define FLAGS_IS_CORE 0x10
private int
dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
@@ -296,13 +298,6 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
size_t offset;
unsigned char nbuf[BUFSIZ];
ssize_t bufsize;
- off_t savedoffset;
- struct stat st;
-
- if (fstat(fd, &st) < 0) {
- file_badread(ms);
- return -1;
- }
if (size != xph_sizeof) {
if (file_printf(ms, ", corrupted program header size") == -1)
@@ -314,7 +309,7 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
* Loop through all the program headers.
*/
for ( ; num; num--) {
- if ((savedoffset = lseek(fd, off, SEEK_SET)) == (off_t)-1) {
+ if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
file_badseek(ms);
return -1;
}
@@ -322,15 +317,13 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
file_badread(ms);
return -1;
}
+ off += size;
+
if (xph_offset > fsize) {
- if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
+ /* Perhaps warn here */
continue;
}
- off += size;
if (xph_type != PT_NOTE)
continue;
@@ -419,7 +412,8 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
return (offset >= size) ? offset : size;
}
- if (*flags & FLAGS_DID_NOTE)
+ if ((*flags & (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) ==
+ (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID))
goto core;
if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
@@ -461,6 +455,19 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
return size;
}
+ if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
+ xnh_type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) {
+ uint32_t desc[5], i;
+ if (file_printf(ms, ", BuildID[%s]=0x", descsz == 16 ? "md5/uuid" :
+ "sha1") == -1)
+ return size;
+ (void)memcpy(desc, &nbuf[doff], descsz);
+ for (i = 0; i < descsz >> 2; i++)
+ if (file_printf(ms, "%.8x", desc[i]) == -1)
+ return size;
+ *flags |= FLAGS_DID_BUILD_ID;
+ }
+
if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 &&
xnh_type == NT_NETBSD_VERSION && descsz == 4) {
uint32_t desc;
@@ -676,7 +683,7 @@ core:
break;
default:
- if (xnh_type == NT_PRPSINFO) {
+ if (xnh_type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
size_t i, j;
unsigned char c;
/*
@@ -693,6 +700,7 @@ core:
unsigned char *cname, *cp;
size_t reloffset = prpsoffsets(i);
size_t noffset = doff + reloffset;
+ size_t k;
for (j = 0; j < 16; j++, noffset++,
reloffset++) {
/*
@@ -738,6 +746,24 @@ core:
/*
* Well, that worked.
*/
+
+ /*
+ * Try next offsets, in case this match is
+ * in the middle of a string.
+ */
+ for (k = i + 1 ; k < NOFFSETS ; k++) {
+ size_t no;
+ int adjust = 1;
+ if (prpsoffsets(k) >= prpsoffsets(i))
+ continue;
+ for (no = doff + prpsoffsets(k);
+ no < doff + prpsoffsets(i); no++)
+ adjust = adjust
+ && isprint(nbuf[no]);
+ if (adjust)
+ i = k;
+ }
+
cname = (unsigned char *)
&nbuf[doff + prpsoffsets(i)];
for (cp = cname; *cp && isprint(*cp); cp++)
@@ -816,13 +842,13 @@ static const cap_desc_t cap_desc_386[] = {
private int
doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
- size_t size, int *flags, int mach)
+ size_t size, off_t fsize, int *flags, int mach)
{
Elf32_Shdr sh32;
Elf64_Shdr sh64;
int stripped = 1;
void *nbuf;
- off_t noff;
+ off_t noff, coff;
uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilites */
uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilites */
@@ -832,16 +858,18 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
return 0;
}
- if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
-
for ( ; num; num--) {
+ if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
+ file_badseek(ms);
+ return -1;
+ }
if (read(fd, xsh_addr, xsh_sizeof) == -1) {
file_badread(ms);
return -1;
}
+ off += size;
+
+ /* Things we can determine before we seek */
switch (xsh_type) {
case SHT_SYMTAB:
#if 0
@@ -849,12 +877,17 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
#endif
stripped = 0;
break;
- case SHT_NOTE:
- if ((off = lseek(fd, (off_t)0, SEEK_CUR)) ==
- (off_t)-1) {
- file_badread(ms);
- return -1;
+ default:
+ if (xsh_offset > fsize) {
+ /* Perhaps warn here */
+ continue;
}
+ break;
+ }
+
+ /* Things we can determine when we seek */
+ switch (xsh_type) {
+ case SHT_NOTE:
if ((nbuf = malloc((size_t)xsh_size)) == NULL) {
file_error(ms, errno, "Cannot allocate memory"
" for note");
@@ -883,24 +916,12 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
if (noff == 0)
break;
}
- if ((lseek(fd, off, SEEK_SET)) == (off_t)-1) {
- free(nbuf);
- file_badread(ms);
- return -1;
- }
free(nbuf);
break;
case SHT_SUNW_cap:
- {
- off_t coff;
- if ((off = lseek(fd, (off_t)0, SEEK_CUR)) ==
- (off_t)-1) {
- file_badread(ms);
- return -1;
- }
if (lseek(fd, (off_t)xsh_offset, SEEK_SET) ==
(off_t)-1) {
- file_badread(ms);
+ file_badseek(ms);
return -1;
}
coff = 0;
@@ -909,7 +930,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
Elf64_Cap cap64;
char cbuf[/*CONSTCOND*/
MAX(sizeof cap32, sizeof cap64)];
- if ((coff += xcap_sizeof) >= (off_t)xsh_size)
+ if ((coff += xcap_sizeof) > (off_t)xsh_size)
break;
if (read(fd, cbuf, (size_t)xcap_sizeof) !=
(ssize_t)xcap_sizeof) {
@@ -929,19 +950,18 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
default:
if (file_printf(ms,
", with unknown capability "
- "0x%llx = 0x%llx",
+ "0x%" INT64_T_FORMAT "x = 0x%"
+ INT64_T_FORMAT "x",
(unsigned long long)xcap_tag,
(unsigned long long)xcap_val) == -1)
return -1;
break;
}
}
- if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
- file_badread(ms);
- return -1;
- }
break;
- }
+
+ default:
+ break;
}
}
if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
@@ -977,12 +997,13 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
}
if (cap_hw1)
if (file_printf(ms,
- " unknown hardware capability 0x%llx",
+ " unknown hardware capability 0x%"
+ INT64_T_FORMAT "x",
(unsigned long long)cap_hw1) == -1)
return -1;
} else {
if (file_printf(ms,
- " hardware capability 0x%llx",
+ " hardware capability 0x%" INT64_T_FORMAT "x",
(unsigned long long)cap_hw1) == -1)
return -1;
}
@@ -998,7 +1019,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
cap_sf1 &= ~SF1_SUNW_MASK;
if (cap_sf1)
if (file_printf(ms,
- ", with unknown software capability 0x%llx",
+ ", with unknown software capability 0x%"
+ INT64_T_FORMAT "x",
(unsigned long long)cap_sf1) == -1)
return -1;
}
@@ -1019,15 +1041,8 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
const char *linking_style = "statically";
const char *shared_libraries = "";
unsigned char nbuf[BUFSIZ];
- int bufsize;
+ ssize_t bufsize;
size_t offset, align;
- off_t savedoffset = (off_t)-1;
- struct stat st;
-
- if (fstat(fd, &st) < 0) {
- file_badread(ms);
- return -1;
- }
if (size != xph_sizeof) {
if (file_printf(ms, ", corrupted program header size") == -1)
@@ -1035,37 +1050,20 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
return 0;
}
- if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
-
for ( ; num; num--) {
- if (read(fd, xph_addr, xph_sizeof) == -1) {
- file_badread(ms);
+ if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
+ file_badseek(ms);
return -1;
}
- if (xph_offset > st.st_size && savedoffset != (off_t)-1) {
- if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
- continue;
- }
- if ((savedoffset = lseek(fd, (off_t)0, SEEK_CUR)) == (off_t)-1) {
- file_badseek(ms);
+ if (read(fd, xph_addr, xph_sizeof) == -1) {
+ file_badread(ms);
return -1;
}
- if (xph_offset > fsize) {
- if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
- continue;
- }
+ off += size;
+ /* Things we can determine before we seek */
switch (xph_type) {
case PT_DYNAMIC:
linking_style = "dynamically";
@@ -1073,8 +1071,18 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
case PT_INTERP:
shared_libraries = " (uses shared libs)";
break;
+ default:
+ if (xph_offset > fsize) {
+ /* Maybe warn here? */
+ continue;
+ }
+ break;
+ }
+
+ /* Things we can determine when we seek */
+ switch (xph_type) {
case PT_NOTE:
- if ((align = xph_align) & 0x80000000) {
+ if ((align = xph_align) & 0x80000000UL) {
if (file_printf(ms,
", invalid note alignment 0x%lx",
(unsigned long)align) == -1)
@@ -1087,8 +1095,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
* This is a PT_NOTE section; loop through all the notes
* in the section.
*/
- if (lseek(fd, xph_offset, SEEK_SET)
- == (off_t)-1) {
+ if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) {
file_badseek(ms);
return -1;
}
@@ -1108,10 +1115,6 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
if (offset == 0)
break;
}
- if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
break;
default:
break;