summaryrefslogtreecommitdiff
path: root/readelf/readelf.c
diff options
context:
space:
mode:
Diffstat (limited to 'readelf/readelf.c')
-rw-r--r--readelf/readelf.c272
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;