summaryrefslogtreecommitdiff
path: root/readelf/readelf.c
diff options
context:
space:
mode:
Diffstat (limited to 'readelf/readelf.c')
-rw-r--r--readelf/readelf.c143
1 files changed, 134 insertions, 9 deletions
diff --git a/readelf/readelf.c b/readelf/readelf.c
index b2534792e2e0..ee0f67117361 100644
--- a/readelf/readelf.c
+++ b/readelf/readelf.c
@@ -47,7 +47,7 @@
#include "_elftc.h"
-ELFTC_VCSID("$Id: readelf.c 3649 2018-11-24 03:26:23Z emaste $");
+ELFTC_VCSID("$Id: readelf.c 3769 2019-06-29 15:15:02Z emaste $");
/*
* readelf(1) options.
@@ -206,6 +206,11 @@ struct eflags_desc {
const char *desc;
};
+struct flag_desc {
+ uint64_t flag;
+ const char *desc;
+};
+
struct mips_option {
uint64_t flag;
const char *desc;
@@ -284,6 +289,7 @@ static void dump_dwarf_ranges_foreach(struct readelf *re, Dwarf_Die die,
static void dump_dwarf_str(struct readelf *re);
static void dump_eflags(struct readelf *re, uint64_t e_flags);
static void dump_elf(struct readelf *re);
+static void dump_flags(struct flag_desc *fd, uint64_t flags);
static void dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab);
static void dump_dynamic(struct readelf *re);
static void dump_liblist(struct readelf *re);
@@ -298,6 +304,8 @@ static void dump_mips_specific_info(struct readelf *re);
static void dump_notes(struct readelf *re);
static void dump_notes_content(struct readelf *re, const char *buf, size_t sz,
off_t off);
+static void dump_notes_data(const char *name, uint32_t type, const char *buf,
+ size_t sz);
static void dump_svr4_hash(struct section *s);
static void dump_svr4_hash64(struct readelf *re, struct section *s);
static void dump_gnu_hash(struct readelf *re, struct section *s);
@@ -1184,6 +1192,7 @@ note_type_gnu(unsigned int nt)
case 2: return "NT_GNU_HWCAP (Hardware capabilities)";
case 3: return "NT_GNU_BUILD_ID (Build id set by ld(1))";
case 4: return "NT_GNU_GOLD_VERSION (GNU gold version)";
+ case 5: return "NT_GNU_PROPERTY_TYPE_0";
default: return (note_type_unknown(nt));
}
}
@@ -2261,8 +2270,15 @@ dump_eflags(struct readelf *re, uint64_t e_flags)
}
edesc = mips_eflags_desc;
break;
- case EM_PPC:
case EM_PPC64:
+ switch (e_flags) {
+ case 0: printf(", Unspecified or Power ELF V1 ABI"); break;
+ case 1: printf(", Power ELF V1 ABI"); break;
+ case 2: printf(", OpenPOWER ELF V2 ABI"); break;
+ default: break;
+ }
+ /* FALLTHROUGH */
+ case EM_PPC:
edesc = powerpc_eflags_desc;
break;
case EM_SPARC:
@@ -2714,6 +2730,59 @@ dump_arch_dyn_val(struct readelf *re, GElf_Dyn *dyn)
}
static void
+dump_flags(struct flag_desc *desc, uint64_t val)
+{
+ struct flag_desc *fd;
+
+ for (fd = desc; fd->flag != 0; fd++) {
+ if (val & fd->flag) {
+ val &= ~fd->flag;
+ printf(" %s", fd->desc);
+ }
+ }
+ if (val != 0)
+ printf(" unknown (0x%jx)", (uintmax_t)val);
+ printf("\n");
+}
+
+static struct flag_desc dt_flags[] = {
+ { DF_ORIGIN, "ORIGIN" },
+ { DF_SYMBOLIC, "SYMBOLIC" },
+ { DF_TEXTREL, "TEXTREL" },
+ { DF_BIND_NOW, "BIND_NOW" },
+ { DF_STATIC_TLS, "STATIC_TLS" },
+ { 0, NULL }
+};
+
+static struct flag_desc dt_flags_1[] = {
+ { DF_1_BIND_NOW, "NOW" },
+ { DF_1_GLOBAL, "GLOBAL" },
+ { 0x4, "GROUP" },
+ { DF_1_NODELETE, "NODELETE" },
+ { DF_1_LOADFLTR, "LOADFLTR" },
+ { 0x20, "INITFIRST" },
+ { DF_1_NOOPEN, "NOOPEN" },
+ { DF_1_ORIGIN, "ORIGIN" },
+ { 0x100, "DIRECT" },
+ { DF_1_INTERPOSE, "INTERPOSE" },
+ { DF_1_NODEFLIB, "NODEFLIB" },
+ { 0x1000, "NODUMP" },
+ { 0x2000, "CONFALT" },
+ { 0x4000, "ENDFILTEE" },
+ { 0x8000, "DISPRELDNE" },
+ { 0x10000, "DISPRELPND" },
+ { 0x20000, "NODIRECT" },
+ { 0x40000, "IGNMULDEF" },
+ { 0x80000, "NOKSYMS" },
+ { 0x100000, "NOHDR" },
+ { 0x200000, "EDITED" },
+ { 0x400000, "NORELOC" },
+ { 0x800000, "SYMINTPOSE" },
+ { 0x1000000, "GLOBAUDIT" },
+ { 0, NULL }
+};
+
+static void
dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab)
{
const char *name;
@@ -2760,6 +2829,7 @@ dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab)
case DT_SYMENT:
case DT_RELSZ:
case DT_RELENT:
+ case DT_PREINIT_ARRAYSZ:
case DT_INIT_ARRAYSZ:
case DT_FINI_ARRAYSZ:
case DT_GNU_CONFLICTSZ:
@@ -2796,6 +2866,12 @@ dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab)
case DT_GNU_PRELINKED:
printf(" %s\n", timestamp(dyn->d_un.d_val));
break;
+ case DT_FLAGS:
+ dump_flags(dt_flags, dyn->d_un.d_val);
+ break;
+ case DT_FLAGS_1:
+ dump_flags(dt_flags_1, dyn->d_un.d_val);
+ break;
default:
printf("\n");
}
@@ -3414,6 +3490,52 @@ dump_notes(struct readelf *re)
}
}
+static struct flag_desc note_feature_ctl_flags[] = {
+ { 0x1, "ASLR_DISABLE" },
+ { 0, NULL }
+};
+
+static void
+dump_notes_data(const char *name, uint32_t type, const char *buf, size_t sz)
+{
+ size_t i;
+ const uint32_t *ubuf;
+
+ /* Note data is at least 4-byte aligned. */
+ if (((uintptr_t)buf & 3) != 0) {
+ warnx("bad note data alignment");
+ goto unknown;
+ }
+ ubuf = (const uint32_t *)(const void *)buf;
+
+ if (strcmp(name, "FreeBSD") == 0) {
+ switch (type) {
+ case NT_FREEBSD_ABI_TAG:
+ if (sz != 4)
+ goto unknown;
+ printf(" ABI tag: %u\n", ubuf[0]);
+ return;
+ /* NT_FREEBSD_NOINIT_TAG carries no data, treat as unknown. */
+ case NT_FREEBSD_ARCH_TAG:
+ if (sz != 4)
+ goto unknown;
+ printf(" Arch tag: %x\n", ubuf[0]);
+ return;
+ case NT_FREEBSD_FEATURE_CTL:
+ if (sz != 4)
+ goto unknown;
+ printf(" Features:");
+ dump_flags(note_feature_ctl_flags, ubuf[0]);
+ return;
+ }
+ }
+unknown:
+ printf(" description data:");
+ for (i = 0; i < sz; i++)
+ printf(" %02x", (unsigned char)buf[i]);
+ printf("\n");
+}
+
static void
dump_notes_content(struct readelf *re, const char *buf, size_t sz, off_t off)
{
@@ -3430,7 +3552,9 @@ dump_notes_content(struct readelf *re, const char *buf, size_t sz, off_t off)
return;
}
note = (Elf_Note *)(uintptr_t) buf;
- name = (char *)(uintptr_t)(note + 1);
+ buf += sizeof(Elf_Note);
+ name = buf;
+ buf += roundup2(note->n_namesz, 4);
/*
* The name field is required to be nul-terminated, and
* n_namesz includes the terminating nul in observed
@@ -3448,8 +3572,8 @@ dump_notes_content(struct readelf *re, const char *buf, size_t sz, off_t off)
printf(" %-13s %#010jx", name, (uintmax_t) note->n_descsz);
printf(" %s\n", note_type(name, re->ehdr.e_type,
note->n_type));
- buf += sizeof(Elf_Note) + roundup2(note->n_namesz, 4) +
- roundup2(note->n_descsz, 4);
+ dump_notes_data(name, note->n_type, buf, note->n_descsz);
+ buf += roundup2(note->n_descsz, 4);
}
}
@@ -6906,13 +7030,13 @@ dump_object(struct readelf *re)
if ((re->elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
warnx("elf_begin() failed: %s", elf_errmsg(-1));
- return;
+ goto done;
}
switch (elf_kind(re->elf)) {
case ELF_K_NONE:
warnx("Not an ELF file.");
- return;
+ goto done;
case ELF_K_ELF:
dump_elf(re);
break;
@@ -6921,10 +7045,11 @@ dump_object(struct readelf *re)
break;
default:
warnx("Internal: libelf returned unknown elf kind.");
- return;
}
+done:
elf_end(re->elf);
+ close(fd);
}
static void
@@ -7345,7 +7470,7 @@ main(int argc, char **argv)
re->options |= RE_S;
break;
case 't':
- re->options |= RE_T;
+ re->options |= RE_SS | RE_T;
break;
case 'u':
re->options |= RE_U;