diff options
Diffstat (limited to 'readelf/readelf.c')
-rw-r--r-- | readelf/readelf.c | 143 |
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; |