diff options
Diffstat (limited to 'readelf/readelf.c')
| -rw-r--r-- | readelf/readelf.c | 272 |
1 files changed, 181 insertions, 91 deletions
diff --git a/readelf/readelf.c b/readelf/readelf.c index 2ef5c71d82dd6..dd2854e9bacda 100644 --- a/readelf/readelf.c +++ b/readelf/readelf.c @@ -47,7 +47,7 @@ #include "_elftc.h" -ELFTC_VCSID("$Id: readelf.c 3519 2017-04-09 23:15:58Z kaiwang27 $"); +ELFTC_VCSID("$Id: readelf.c 3580 2017-09-15 23:29:59Z emaste $"); /* * readelf(1) options. @@ -287,6 +287,7 @@ static void dump_elf(struct readelf *re); 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); +static void dump_mips_abiflags(struct readelf *re, struct section *s); static void dump_mips_attributes(struct readelf *re, uint8_t *p, uint8_t *pe); static void dump_mips_odk_reginfo(struct readelf *re, uint8_t *p, size_t sz); static void dump_mips_options(struct readelf *re, struct section *s); @@ -316,6 +317,7 @@ static const char *dwarf_regname(struct readelf *re, unsigned int num); static struct dumpop *find_dumpop(struct readelf *re, size_t si, const char *sn, int op, int t); static int get_ent_count(struct section *s, int *ent_count); +static int get_mips_register_size(uint8_t flag); static char *get_regoff_str(struct readelf *re, Dwarf_Half reg, Dwarf_Addr off); static const char *get_string(struct readelf *re, int strtab, size_t off); @@ -775,6 +777,81 @@ dt_type(unsigned int mach, unsigned int dtype) { static char s_dtype[32]; + switch (dtype) { + case DT_NULL: return "NULL"; + case DT_NEEDED: return "NEEDED"; + case DT_PLTRELSZ: return "PLTRELSZ"; + case DT_PLTGOT: return "PLTGOT"; + case DT_HASH: return "HASH"; + case DT_STRTAB: return "STRTAB"; + case DT_SYMTAB: return "SYMTAB"; + case DT_RELA: return "RELA"; + case DT_RELASZ: return "RELASZ"; + case DT_RELAENT: return "RELAENT"; + case DT_STRSZ: return "STRSZ"; + case DT_SYMENT: return "SYMENT"; + case DT_INIT: return "INIT"; + case DT_FINI: return "FINI"; + case DT_SONAME: return "SONAME"; + case DT_RPATH: return "RPATH"; + case DT_SYMBOLIC: return "SYMBOLIC"; + case DT_REL: return "REL"; + case DT_RELSZ: return "RELSZ"; + case DT_RELENT: return "RELENT"; + case DT_PLTREL: return "PLTREL"; + case DT_DEBUG: return "DEBUG"; + case DT_TEXTREL: return "TEXTREL"; + case DT_JMPREL: return "JMPREL"; + case DT_BIND_NOW: return "BIND_NOW"; + case DT_INIT_ARRAY: return "INIT_ARRAY"; + case DT_FINI_ARRAY: return "FINI_ARRAY"; + case DT_INIT_ARRAYSZ: return "INIT_ARRAYSZ"; + case DT_FINI_ARRAYSZ: return "FINI_ARRAYSZ"; + case DT_RUNPATH: return "RUNPATH"; + case DT_FLAGS: return "FLAGS"; + case DT_PREINIT_ARRAY: return "PREINIT_ARRAY"; + case DT_PREINIT_ARRAYSZ: return "PREINIT_ARRAYSZ"; + case DT_MAXPOSTAGS: return "MAXPOSTAGS"; + case DT_SUNW_AUXILIARY: return "SUNW_AUXILIARY"; + case DT_SUNW_RTLDINF: return "SUNW_RTLDINF"; + case DT_SUNW_FILTER: return "SUNW_FILTER"; + case DT_SUNW_CAP: return "SUNW_CAP"; + case DT_SUNW_ASLR: return "SUNW_ASLR"; + case DT_CHECKSUM: return "CHECKSUM"; + case DT_PLTPADSZ: return "PLTPADSZ"; + case DT_MOVEENT: return "MOVEENT"; + case DT_MOVESZ: return "MOVESZ"; + case DT_FEATURE: return "FEATURE"; + case DT_POSFLAG_1: return "POSFLAG_1"; + case DT_SYMINSZ: return "SYMINSZ"; + case DT_SYMINENT: return "SYMINENT"; + case DT_GNU_HASH: return "GNU_HASH"; + case DT_TLSDESC_PLT: return "DT_TLSDESC_PLT"; + case DT_TLSDESC_GOT: return "DT_TLSDESC_GOT"; + case DT_GNU_CONFLICT: return "GNU_CONFLICT"; + case DT_GNU_LIBLIST: return "GNU_LIBLIST"; + case DT_CONFIG: return "CONFIG"; + case DT_DEPAUDIT: return "DEPAUDIT"; + case DT_AUDIT: return "AUDIT"; + case DT_PLTPAD: return "PLTPAD"; + case DT_MOVETAB: return "MOVETAB"; + case DT_SYMINFO: return "SYMINFO"; + case DT_VERSYM: return "VERSYM"; + case DT_RELACOUNT: return "RELACOUNT"; + case DT_RELCOUNT: return "RELCOUNT"; + case DT_FLAGS_1: return "FLAGS_1"; + case DT_VERDEF: return "VERDEF"; + case DT_VERDEFNUM: return "VERDEFNUM"; + case DT_VERNEED: return "VERNEED"; + case DT_VERNEEDNUM: return "VERNEEDNUM"; + case DT_AUXILIARY: return "AUXILIARY"; + case DT_USED: return "USED"; + case DT_FILTER: return "FILTER"; + case DT_GNU_PRELINKED: return "GNU_PRELINKED"; + case DT_GNU_CONFLICTSZ: return "GNU_CONFLICTSZ"; + case DT_GNU_LIBLISTSZ: return "GNU_LIBLISTSZ"; + } + if (dtype >= DT_LOPROC && dtype <= DT_HIPROC) { switch (mach) { case EM_ARM: @@ -895,87 +972,10 @@ dt_type(unsigned int mach, unsigned int dtype) default: break; } - snprintf(s_dtype, sizeof(s_dtype), "<unknown: %#x>", dtype); - return (s_dtype); } - switch (dtype) { - case DT_NULL: return "NULL"; - case DT_NEEDED: return "NEEDED"; - case DT_PLTRELSZ: return "PLTRELSZ"; - case DT_PLTGOT: return "PLTGOT"; - case DT_HASH: return "HASH"; - case DT_STRTAB: return "STRTAB"; - case DT_SYMTAB: return "SYMTAB"; - case DT_RELA: return "RELA"; - case DT_RELASZ: return "RELASZ"; - case DT_RELAENT: return "RELAENT"; - case DT_STRSZ: return "STRSZ"; - case DT_SYMENT: return "SYMENT"; - case DT_INIT: return "INIT"; - case DT_FINI: return "FINI"; - case DT_SONAME: return "SONAME"; - case DT_RPATH: return "RPATH"; - case DT_SYMBOLIC: return "SYMBOLIC"; - case DT_REL: return "REL"; - case DT_RELSZ: return "RELSZ"; - case DT_RELENT: return "RELENT"; - case DT_PLTREL: return "PLTREL"; - case DT_DEBUG: return "DEBUG"; - case DT_TEXTREL: return "TEXTREL"; - case DT_JMPREL: return "JMPREL"; - case DT_BIND_NOW: return "BIND_NOW"; - case DT_INIT_ARRAY: return "INIT_ARRAY"; - case DT_FINI_ARRAY: return "FINI_ARRAY"; - case DT_INIT_ARRAYSZ: return "INIT_ARRAYSZ"; - case DT_FINI_ARRAYSZ: return "FINI_ARRAYSZ"; - case DT_RUNPATH: return "RUNPATH"; - case DT_FLAGS: return "FLAGS"; - case DT_PREINIT_ARRAY: return "PREINIT_ARRAY"; - case DT_PREINIT_ARRAYSZ: return "PREINIT_ARRAYSZ"; - case DT_MAXPOSTAGS: return "MAXPOSTAGS"; - case DT_SUNW_AUXILIARY: return "SUNW_AUXILIARY"; - case DT_SUNW_RTLDINF: return "SUNW_RTLDINF"; - case DT_SUNW_FILTER: return "SUNW_FILTER"; - case DT_SUNW_CAP: return "SUNW_CAP"; - case DT_SUNW_ASLR: return "SUNW_ASLR"; - case DT_CHECKSUM: return "CHECKSUM"; - case DT_PLTPADSZ: return "PLTPADSZ"; - case DT_MOVEENT: return "MOVEENT"; - case DT_MOVESZ: return "MOVESZ"; - case DT_FEATURE: return "FEATURE"; - case DT_POSFLAG_1: return "POSFLAG_1"; - case DT_SYMINSZ: return "SYMINSZ"; - case DT_SYMINENT: return "SYMINENT"; - case DT_GNU_HASH: return "GNU_HASH"; - case DT_TLSDESC_PLT: return "DT_TLSDESC_PLT"; - case DT_TLSDESC_GOT: return "DT_TLSDESC_GOT"; - case DT_GNU_CONFLICT: return "GNU_CONFLICT"; - case DT_GNU_LIBLIST: return "GNU_LIBLIST"; - case DT_CONFIG: return "CONFIG"; - case DT_DEPAUDIT: return "DEPAUDIT"; - case DT_AUDIT: return "AUDIT"; - case DT_PLTPAD: return "PLTPAD"; - case DT_MOVETAB: return "MOVETAB"; - case DT_SYMINFO: return "SYMINFO"; - case DT_VERSYM: return "VERSYM"; - case DT_RELACOUNT: return "RELACOUNT"; - case DT_RELCOUNT: return "RELCOUNT"; - case DT_FLAGS_1: return "FLAGS_1"; - case DT_VERDEF: return "VERDEF"; - case DT_VERDEFNUM: return "VERDEFNUM"; - case DT_VERNEED: return "VERNEED"; - case DT_VERNEEDNUM: return "VERNEEDNUM"; - case DT_AUXILIARY: return "AUXILIARY"; - case DT_USED: return "USED"; - case DT_FILTER: return "FILTER"; - case DT_GNU_PRELINKED: return "GNU_PRELINKED"; - case DT_GNU_CONFLICTSZ: return "GNU_CONFLICTSZ"; - case DT_GNU_LIBLISTSZ: return "GNU_LIBLISTSZ"; - default: - snprintf(s_dtype, sizeof(s_dtype), "<unknown: %#x>", dtype); - return (s_dtype); - } + snprintf(s_dtype, sizeof(s_dtype), "<unknown: %#x>", dtype); + return (s_dtype); } static const char * @@ -1136,7 +1136,9 @@ note_type_freebsd_core(unsigned int nt) case 14: return "NT_PROCSTAT_OSREL"; case 15: return "NT_PROCSTAT_PSSTRINGS"; case 16: return "NT_PROCSTAT_AUXV"; + case 17: return "NT_PTLWPINFO"; case 0x202: return "NT_X86_XSTATE (x86 XSAVE extended state)"; + case 0x400: return "NT_ARM_VFP (arm VFP registers)"; default: return (note_type_unknown(nt)); } } @@ -2631,10 +2633,8 @@ dyn_str(struct readelf *re, uint32_t stab, uint64_t d_val) } static void -dump_arch_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab) +dump_arch_dyn_val(struct readelf *re, GElf_Dyn *dyn) { - const char *name; - switch (re->ehdr.e_machine) { case EM_MIPS: case EM_MIPS_RS3_LE: @@ -2687,14 +2687,12 @@ dump_arch_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab) break; case DT_MIPS_IVERSION: case DT_MIPS_PERF_SUFFIX: - case DT_AUXILIARY: - case DT_FILTER: - name = dyn_str(re, stab, dyn->d_un.d_val); - printf(" %s\n", name); - break; case DT_MIPS_TIME_STAMP: printf(" %s\n", timestamp(dyn->d_un.d_val)); break; + default: + printf("\n"); + break; } break; default: @@ -2708,14 +2706,16 @@ dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab) { const char *name; - if (dyn->d_tag >= DT_LOPROC && dyn->d_tag <= DT_HIPROC) { - dump_arch_dyn_val(re, dyn, stab); + if (dyn->d_tag >= DT_LOPROC && dyn->d_tag <= DT_HIPROC && + dyn->d_tag != DT_AUXILIARY && dyn->d_tag != DT_FILTER) { + dump_arch_dyn_val(re, dyn); return; } /* These entry values are index into the string table. */ name = NULL; - if (dyn->d_tag == DT_NEEDED || dyn->d_tag == DT_SONAME || + if (dyn->d_tag == DT_AUXILIARY || dyn->d_tag == DT_FILTER || + dyn->d_tag == DT_NEEDED || dyn->d_tag == DT_SONAME || dyn->d_tag == DT_RPATH || dyn->d_tag == DT_RUNPATH) name = dyn_str(re, stab, dyn->d_un.d_val); @@ -2760,6 +2760,12 @@ dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab) case DT_VERNEEDNUM: printf(" %ju\n", (uintmax_t) dyn->d_un.d_val); break; + case DT_AUXILIARY: + printf(" Auxiliary library: [%s]\n", name); + break; + case DT_FILTER: + printf(" Filter library: [%s]\n", name); + break; case DT_NEEDED: printf(" Shared library: [%s]\n", name); break; @@ -2833,6 +2839,8 @@ dump_rel(struct readelf *re, struct section *s, Elf_Data *d) type2 = (type >> 8) & 0xFF; type3 = (type >> 16) & 0xFF; type = type & 0xFF; + } else { + type2 = type3 = 0; } if (re->options & RE_WW) printf("%16.16jx %16.16jx %-24.24s" @@ -2916,6 +2924,8 @@ dump_rela(struct readelf *re, struct section *s, Elf_Data *d) type2 = (type >> 8) & 0xFF; type3 = (type >> 16) & 0xFF; type = type & 0xFF; + } else { + type2 = type3 = 0; } if (re->options & RE_WW) printf("%16.16jx %16.16jx %-24.24s" @@ -4099,6 +4109,10 @@ dump_mips_specific_info(struct readelf *re) } } + if (s->name != NULL && (!strcmp(s->name, ".MIPS.abiflags") || + (s->type == SHT_MIPS_ABIFLAGS))) + dump_mips_abiflags(re, s); + /* * Dump .reginfo if present (although it will be ignored by an OS if a * .MIPS.options section is present, according to SGI mips64 spec). @@ -4112,6 +4126,82 @@ dump_mips_specific_info(struct readelf *re) } static void +dump_mips_abiflags(struct readelf *re, struct section *s) +{ + Elf_Data *d; + uint8_t *p; + int elferr; + uint32_t isa_ext, ases, flags1, flags2; + uint16_t version; + uint8_t isa_level, isa_rev, gpr_size, cpr1_size, cpr2_size, fp_abi; + + if ((d = elf_rawdata(s->scn, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_rawdata failed: %s", + elf_errmsg(elferr)); + return; + } + if (d->d_size != 24) { + warnx("invalid MIPS abiflags section size"); + return; + } + + p = d->d_buf; + version = re->dw_decode(&p, 2); + printf("MIPS ABI Flags Version: %u", version); + if (version != 0) { + printf(" (unknown)\n\n"); + return; + } + printf("\n\n"); + + isa_level = re->dw_decode(&p, 1); + isa_rev = re->dw_decode(&p, 1); + gpr_size = re->dw_decode(&p, 1); + cpr1_size = re->dw_decode(&p, 1); + cpr2_size = re->dw_decode(&p, 1); + fp_abi = re->dw_decode(&p, 1); + isa_ext = re->dw_decode(&p, 4); + ases = re->dw_decode(&p, 4); + flags1 = re->dw_decode(&p, 4); + flags2 = re->dw_decode(&p, 4); + + printf("ISA: "); + if (isa_rev <= 1) + printf("MIPS%u\n", isa_level); + else + printf("MIPS%ur%u\n", isa_level, isa_rev); + printf("GPR size: %d\n", get_mips_register_size(gpr_size)); + printf("CPR1 size: %d\n", get_mips_register_size(cpr1_size)); + printf("CPR2 size: %d\n", get_mips_register_size(cpr2_size)); + printf("FP ABI: "); + switch (fp_abi) { + case 3: + printf("Soft float"); + break; + default: + printf("%u", fp_abi); + break; + } + printf("\nISA Extension: %u\n", isa_ext); + printf("ASEs: %u\n", ases); + printf("FLAGS 1: %08x\n", flags1); + printf("FLAGS 2: %08x\n", flags2); +} + +static int +get_mips_register_size(uint8_t flag) +{ + switch (flag) { + case 0: return 0; + case 1: return 32; + case 2: return 64; + case 3: return 128; + default: return -1; + } +} +static void dump_mips_reginfo(struct readelf *re, struct section *s) { Elf_Data *d; |
