diff options
author | Ed Maste <emaste@FreeBSD.org> | 2015-02-17 14:34:11 +0000 |
---|---|---|
committer | Ed Maste <emaste@FreeBSD.org> | 2015-02-17 14:34:11 +0000 |
commit | d356830d3d227b40603d19222ab35eb8f0f5c034 (patch) | |
tree | 603c3338aa5864e50427394e4863cb695e19330f /readelf | |
parent | 42bfa111d731278ff40f9ce45298e65a373c2064 (diff) |
Notes
Diffstat (limited to 'readelf')
-rw-r--r-- | readelf/readelf.c | 254 |
1 files changed, 185 insertions, 69 deletions
diff --git a/readelf/readelf.c b/readelf/readelf.c index 16159ad09ea9a..775172646ffa9 100644 --- a/readelf/readelf.c +++ b/readelf/readelf.c @@ -46,7 +46,7 @@ #include "_elftc.h" -ELFTC_VCSID("$Id: readelf.c 3110 2014-12-20 08:32:46Z kaiwang27 $"); +ELFTC_VCSID("$Id: readelf.c 3155 2015-02-15 19:15:57Z emaste $"); /* * readelf(1) options. @@ -320,8 +320,15 @@ static const char *get_symbol_name(struct readelf *re, int symtab, int i); static uint64_t get_symbol_value(struct readelf *re, int symtab, int i); static void load_sections(struct readelf *re); static const char *mips_abi_fp(uint64_t fp); -static const char *note_type(unsigned int osabi, unsigned int et, +static const char *note_type(const char *note_name, unsigned int et, unsigned int nt); +static const char *note_type_freebsd(unsigned int nt); +static const char *note_type_freebsd_core(unsigned int nt); +static const char *note_type_linux_core(unsigned int nt); +static const char *note_type_gnu(unsigned int nt); +static const char *note_type_netbsd(unsigned int nt); +static const char *note_type_openbsd(unsigned int nt); +static const char *note_type_unknown(unsigned int nt); static const char *option_kind(uint8_t kind); static const char *phdr_type(unsigned int ptype); static const char *ppc_abi_fp(uint64_t fp); @@ -1472,6 +1479,20 @@ r_type(unsigned int mach, unsigned int type) case 21: return "R_X86_64_DTPOFF32"; case 22: return "R_X86_64_GOTTPOFF"; case 23: return "R_X86_64_TPOFF32"; + case 24: return "R_X86_64_PC64"; + case 25: return "R_X86_64_GOTOFF64"; + case 26: return "R_X86_64_GOTPC32"; + case 27: return "R_X86_64_GOT64"; + case 28: return "R_X86_64_GOTPCREL64"; + case 29: return "R_X86_64_GOTPC64"; + case 30: return "R_X86_64_GOTPLT64"; + case 31: return "R_X86_64_PLTOFF64"; + case 32: return "R_X86_64_SIZE32"; + case 33: return "R_X86_64_SIZE64"; + case 34: return "R_X86_64_GOTPC32_TLSDESC"; + case 35: return "R_X86_64_TLSDESC_CALL"; + case 36: return "R_X86_64_TLSDESC"; + case 37: return "R_X86_64_IRELATIVE"; default: return ""; } default: return ""; @@ -1479,62 +1500,130 @@ r_type(unsigned int mach, unsigned int type) } static const char * -note_type(unsigned int osabi, unsigned int et, unsigned int nt) +note_type(const char *name, unsigned int et, unsigned int nt) +{ + if ((strcmp(name, "CORE") == 0 || strcmp(name, "LINUX") == 0) && + et == ET_CORE) + return note_type_linux_core(nt); + else if (strcmp(name, "FreeBSD") == 0) + if (et == ET_CORE) + return note_type_freebsd_core(nt); + else + return note_type_freebsd(nt); + else if (strcmp(name, "GNU") == 0 && et != ET_CORE) + return note_type_gnu(nt); + else if (strcmp(name, "NetBSD") == 0 && et != ET_CORE) + return note_type_netbsd(nt); + else if (strcmp(name, "OpenBSD") == 0 && et != ET_CORE) + return note_type_openbsd(nt); + return note_type_unknown(nt); +} + +static const char * +note_type_freebsd(unsigned int nt) { - static char s_nt[32]; + switch (nt) { + case 1: return "NT_FREEBSD_ABI_TAG"; + case 2: return "NT_FREEBSD_NOINIT_TAG"; + case 3: return "NT_FREEBSD_ARCH_TAG"; + default: return (note_type_unknown(nt)); + } +} - if (et == ET_CORE) { - switch (nt) { - case NT_PRSTATUS: - return "NT_PRSTATUS (Process status)"; - case NT_FPREGSET: - return "NT_FPREGSET (Floating point information)"; - case NT_PRPSINFO: - return "NT_PRPSINFO (Process information)"; - case NT_AUXV: - return "NT_AUXV (Auxiliary vector)"; - case NT_PRXFPREG: - return "NT_PRXFPREG (Linux user_xfpregs structure)"; - case NT_PSTATUS: - return "NT_PSTATUS (Linux process status)"; - case NT_FPREGS: - return "NT_FPREGS (Linux floating point regset)"; - case NT_PSINFO: - return "NT_PSINFO (Linux process information)"; - case NT_LWPSTATUS: - return "NT_LWPSTATUS (Linux lwpstatus_t type)"; - case NT_LWPSINFO: - return "NT_LWPSINFO (Linux lwpinfo_t type)"; - default: - snprintf(s_nt, sizeof(s_nt), "<unknown: %u>", nt); - return (s_nt); - } - } else { - switch (nt) { - case NT_ABI_TAG: - switch (osabi) { - case ELFOSABI_FREEBSD: - return "NT_FREEBSD_ABI_TAG"; - case ELFOSABI_NETBSD: - return "NT_NETBSD_IDENT"; - case ELFOSABI_OPENBSD: - return "NT_OPENBSD_IDENT"; - default: - return "NT_GNU_ABI_TAG"; - } - case NT_GNU_HWCAP: - return "NT_GNU_HWCAP (Hardware capabilities)"; - case NT_GNU_BUILD_ID: - return "NT_GNU_BUILD_ID (Build id set by ld(1))"; - case NT_GNU_GOLD_VERSION: - return "NT_GNU_GOLD_VERSION (GNU gold version)"; - default: - snprintf(s_nt, sizeof(s_nt), "<unknown: %u>", nt); - return (s_nt); - } +static const char * +note_type_freebsd_core(unsigned int nt) +{ + switch (nt) { + case 1: return "NT_PRSTATUS"; + case 2: return "NT_FPREGSET"; + case 3: return "NT_PRPSINFO"; + case 7: return "NT_THRMISC"; + case 8: return "NT_PROCSTAT_PROC"; + case 9: return "NT_PROCSTAT_FILES"; + case 10: return "NT_PROCSTAT_VMMAP"; + case 11: return "NT_PROCSTAT_GROUPS"; + case 12: return "NT_PROCSTAT_UMASK"; + case 13: return "NT_PROCSTAT_RLIMIT"; + case 14: return "NT_PROCSTAT_OSREL"; + case 15: return "NT_PROCSTAT_PSSTRINGS"; + case 16: return "NT_PROCSTAT_AUXV"; + case 0x202: return "NT_X86_XSTATE (x86 XSAVE extended state)"; + default: return (note_type_unknown(nt)); + } +} + +static const char * +note_type_linux_core(unsigned int nt) +{ + switch (nt) { + case 1: return "NT_PRSTATUS (Process status)"; + case 2: return "NT_FPREGSET (Floating point information)"; + case 3: return "NT_PRPSINFO (Process information)"; + case 4: return "NT_TASKSTRUCT (Task structure)"; + case 6: return "NT_AUXV (Auxiliary vector)"; + case 10: return "NT_PSTATUS (Linux process status)"; + case 12: return "NT_FPREGS (Linux floating point regset)"; + case 13: return "NT_PSINFO (Linux process information)"; + case 16: return "NT_LWPSTATUS (Linux lwpstatus_t type)"; + case 17: return "NT_LWPSINFO (Linux lwpinfo_t type)"; + case 18: return "NT_WIN32PSTATUS (win32_pstatus structure)"; + case 0x100: return "NT_PPC_VMX (ppc Altivec registers)"; + case 0x102: return "NT_PPC_VSX (ppc VSX registers)"; + case 0x202: return "NT_X86_XSTATE (x86 XSAVE extended state)"; + case 0x300: return "NT_S390_HIGH_GPRS (s390 upper register halves)"; + case 0x301: return "NT_S390_TIMER (s390 timer register)"; + case 0x302: return "NT_S390_TODCMP (s390 TOD comparator register)"; + case 0x303: return "NT_S390_TODPREG (s390 TOD programmable register)"; + case 0x304: return "NT_S390_CTRS (s390 control registers)"; + case 0x305: return "NT_S390_PREFIX (s390 prefix register)"; + case 0x400: return "NT_ARM_VFP (arm VFP registers)"; + case 0x46494c45UL: return "NT_FILE (mapped files)"; + case 0x46E62B7FUL: return "NT_PRXFPREG (Linux user_xfpregs structure)"; + case 0x53494749UL: return "NT_SIGINFO (siginfo_t data)"; + default: return (note_type_unknown(nt)); + } +} + +static const char * +note_type_gnu(unsigned int nt) +{ + switch (nt) { + case 1: return "NT_GNU_ABI_TAG"; + 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)"; + default: return (note_type_unknown(nt)); + } +} + +static const char * +note_type_netbsd(unsigned int nt) +{ + switch (nt) { + case 1: return "NT_NETBSD_IDENT"; + default: return (note_type_unknown(nt)); } } +static const char * +note_type_openbsd(unsigned int nt) +{ + switch (nt) { + case 1: return "NT_OPENBSD_IDENT"; + default: return (note_type_unknown(nt)); + } +} + +static const char * +note_type_unknown(unsigned int nt) +{ + static char s_nt[32]; + + snprintf(s_nt, sizeof(s_nt), + nt >= 0x100 ? "<unknown: 0x%x>" : "<unknown: %u>", nt); + return (s_nt); +} + static struct { const char *name; int value; @@ -3080,6 +3169,10 @@ dump_rel(struct readelf *re, struct section *s, Elf_Data *d) warnx("gelf_getrel failed: %s", elf_errmsg(-1)); continue; } + if (s->link >= re->shnum) { + warnx("invalid section link index %u", s->link); + continue; + } symname = get_symbol_name(re, s->link, GELF_R_SYM(r.r_info)); symval = get_symbol_value(re, s->link, GELF_R_SYM(r.r_info)); if (re->ec == ELFCLASS32) { @@ -3132,6 +3225,10 @@ dump_rela(struct readelf *re, struct section *s, Elf_Data *d) warnx("gelf_getrel failed: %s", elf_errmsg(-1)); continue; } + if (s->link >= re->shnum) { + warnx("invalid section link index %u", s->link); + continue; + } symname = get_symbol_name(re, s->link, GELF_R_SYM(r.r_info)); symval = get_symbol_value(re, s->link, GELF_R_SYM(r.r_info)); if (re->ec == ELFCLASS32) { @@ -3579,25 +3676,38 @@ static void dump_notes_content(struct readelf *re, const char *buf, size_t sz, off_t off) { Elf_Note *note; - const char *end; + const char *end, *name; printf("\nNotes at offset %#010jx with length %#010jx:\n", (uintmax_t) off, (uintmax_t) sz); printf(" %-13s %-15s %s\n", "Owner", "Data size", "Description"); end = buf + sz; while (buf < end) { + if (buf + sizeof(*note) > end) { + warnx("invalid note header"); + return; + } note = (Elf_Note *)(uintptr_t) buf; - printf(" %-13s %#010jx", (char *)(uintptr_t) (note + 1), - (uintmax_t) note->n_descsz); - printf(" %s\n", note_type(re->ehdr.e_ident[EI_OSABI], - re->ehdr.e_type, note->n_type)); - buf += sizeof(Elf_Note); - if (re->ec == ELFCLASS32) - buf += roundup2(note->n_namesz, 4) + - roundup2(note->n_descsz, 4); - else - buf += roundup2(note->n_namesz, 8) + - roundup2(note->n_descsz, 8); + name = (char *)(uintptr_t)(note + 1); + /* + * The name field is required to be nul-terminated, and + * n_namesz includes the terminating nul in observed + * implementations (contrary to the ELF-64 spec). A special + * case is needed for cores generated by some older Linux + * versions, which write a note named "CORE" without a nul + * terminator and n_namesz = 4. + */ + if (note->n_namesz == 0) + name = ""; + else if (note->n_namesz == 4 && strncmp(name, "CORE", 4) == 0) + name = "CORE"; + else if (strnlen(name, note->n_namesz) >= note->n_namesz) + name = "<invalid>"; + 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); } } @@ -4132,14 +4242,22 @@ dump_attributes(struct readelf *re) len = d->d_size - 1; p++; while (len > 0) { + if (len < 4) { + warnx("truncated attribute section length"); + break; + } seclen = re->dw_decode(&p, 4); if (seclen > len) { warnx("invalid attribute section length"); break; } len -= seclen; - printf("Attribute Section: %s\n", (char *) p); nlen = strlen((char *) p) + 1; + if (nlen + 4 > seclen) { + warnx("invalid attribute section name"); + break; + } + printf("Attribute Section: %s\n", (char *) p); p += nlen; seclen -= nlen + 4; while (seclen > 0) { @@ -6609,10 +6727,8 @@ load_sections(struct readelf *re) return; } - if ((scn = elf_getscn(re->elf, 0)) == NULL) { - warnx("elf_getscn failed: %s", elf_errmsg(-1)); + if ((scn = elf_getscn(re->elf, 0)) == NULL) return; - } (void) elf_errno(); do { |