X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=binutils%2Freadelf.c;h=9212a8f7d904b6b04783f2191a356519f784838d;hb=refs%2Ftags%2Fsubmit%2Ftizen_base%2F20190724.060247;hp=7394e76ab17a220e4994353fb6d097ec522fc344;hpb=948f632f5671aa16c239507652d92f23f7713703;p=external%2Fbinutils.git diff --git a/binutils/readelf.c b/binutils/readelf.c index 7394e76..9212a8f 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -1,5 +1,5 @@ /* readelf.c -- display contents of an ELF format file - Copyright (C) 1998-2015 Free Software Foundation, Inc. + Copyright (C) 1998-2016 Free Software Foundation, Inc. Originally developed by Eric Youngdale Modifications by Nick Clifton @@ -43,9 +43,7 @@ #include "sysdep.h" #include #include -#ifdef HAVE_ZLIB_H #include -#endif #ifdef HAVE_WCHAR_H #include #endif @@ -62,6 +60,7 @@ #include "bucomm.h" #include "elfcomm.h" #include "dwarf.h" +#include "libbfd.h" #include "elf/common.h" #include "elf/external.h" @@ -166,6 +165,12 @@ #define offsetof(TYPE, MEMBER) ((size_t) &(((TYPE *) 0)->MEMBER)) #endif +typedef struct elf_section_list +{ + Elf_Internal_Shdr * hdr; + struct elf_section_list * next; +} elf_section_list; + char * program_name = "readelf"; static unsigned long archive_file_offset; static unsigned long archive_file_size; @@ -190,7 +195,7 @@ static Elf_Internal_Ehdr elf_header; static Elf_Internal_Shdr * section_headers; static Elf_Internal_Phdr * program_headers; static Elf_Internal_Dyn * dynamic_section; -static Elf_Internal_Shdr * symtab_shndx_hdr; +static elf_section_list * symtab_shndx_list; static int show_name; static int do_dynamic; static int do_syms; @@ -211,6 +216,7 @@ static int do_arch; static int do_notes; static int do_archive_index; static int is_32bit_elf; +static int decompress_dumps; struct group_list { @@ -282,7 +288,7 @@ enum versioned_symbol_info symbol_public }; -static const char *get_symbol_version_string +static const char * get_symbol_version_string (FILE *file, int is_dynsym, const char *strtab, unsigned long int strtab_size, unsigned int si, Elf_Internal_Sym *psym, enum versioned_symbol_info *sym_info, @@ -341,8 +347,9 @@ get_data (void * var, FILE * file, unsigned long offset, bfd_size_type size, || (bfd_size_type) ((size_t) nmemb) != nmemb)) { if (reason) - error (_("Size truncation prevents reading 0x%llx elements of size 0x%llx for %s\n"), - (unsigned long long) nmemb, (unsigned long long) size, reason); + error (_("Size truncation prevents reading 0x%" BFD_VMA_FMT "x" + " elements of size 0x%" BFD_VMA_FMT "x for %s\n"), + nmemb, size, reason); return NULL; } @@ -350,8 +357,9 @@ get_data (void * var, FILE * file, unsigned long offset, bfd_size_type size, if (amt < nmemb) { if (reason) - error (_("Size overflow prevents reading 0x%llx elements of size 0x%llx for %s\n"), - (unsigned long long) nmemb, (unsigned long long) size, reason); + error (_("Size overflow prevents reading 0x%" BFD_VMA_FMT "x" + " elements of size 0x%" BFD_VMA_FMT "x for %s\n"), + nmemb, size, reason); return NULL; } @@ -361,8 +369,9 @@ get_data (void * var, FILE * file, unsigned long offset, bfd_size_type size, || offset + archive_file_offset + amt > current_file_size) { if (reason) - error (_("Reading 0x%llx bytes extends past end of file for %s\n"), - (unsigned long long) amt, reason); + error (_("Reading 0x%" BFD_VMA_FMT "x" + " bytes extends past end of file for %s\n"), + amt, reason); return NULL; } @@ -370,7 +379,7 @@ get_data (void * var, FILE * file, unsigned long offset, bfd_size_type size, { if (reason) error (_("Unable to seek to 0x%lx for %s\n"), - (unsigned long) archive_file_offset + offset, reason); + archive_file_offset + offset, reason); return NULL; } @@ -385,8 +394,9 @@ get_data (void * var, FILE * file, unsigned long offset, bfd_size_type size, if (mvar == NULL) { if (reason) - error (_("Out of memory allocating 0x%llx bytes for %s\n"), - (unsigned long long) amt, reason); + error (_("Out of memory allocating 0x%" BFD_VMA_FMT "x" + " bytes for %s\n"), + amt, reason); return NULL; } @@ -396,8 +406,8 @@ get_data (void * var, FILE * file, unsigned long offset, bfd_size_type size, if (fread (mvar, (size_t) size, (size_t) nmemb, file) != nmemb) { if (reason) - error (_("Unable to read in 0x%llx bytes of %s\n"), - (unsigned long long) amt, reason); + error (_("Unable to read in 0x%" BFD_VMA_FMT "x bytes of %s\n"), + amt, reason); if (mvar != var) free (mvar); return NULL; @@ -470,7 +480,7 @@ print_symbol (int width, const char *symbol) if (width < 0) { - /* Keep the width positive. This also helps. */ + /* Keep the width positive. This helps the code below. */ width = - width; extra_padding = TRUE; } @@ -547,12 +557,12 @@ print_symbol (int width, const char *symbol) return num_printed; } -/* Returns a pointer to a static buffer containing a printable version of +/* Returns a pointer to a static buffer containing a printable version of the given section's name. Like print_symbol, except that it does not try to print multibyte characters, it just interprets them as hex values. */ static const char * -printable_section_name (Elf_Internal_Shdr * sec) +printable_section_name (const Elf_Internal_Shdr * sec) { #define MAX_PRINT_SEC_NAME_LEN 128 static char sec_name_buf [MAX_PRINT_SEC_NAME_LEN + 1]; @@ -703,7 +713,7 @@ guess_is_rela (unsigned int e_machine) { /* Targets that use REL relocations. */ case EM_386: - case EM_486: + case EM_IAMCU: case EM_960: case EM_ARM: case EM_D10V: @@ -723,6 +733,9 @@ guess_is_rela (unsigned int e_machine) case EM_ADAPTEVA_EPIPHANY: case EM_ALPHA: case EM_ALTERA_NIOS2: + case EM_ARC: + case EM_ARC_COMPACT: + case EM_ARC_COMPACT2: case EM_AVR: case EM_AVR_OLD: case EM_BLACKFIN: @@ -1180,7 +1193,7 @@ dump_relocations (FILE * file, break; case EM_386: - case EM_486: + case EM_IAMCU: rtype = elf_i386_reloc_type (type); break; @@ -1310,6 +1323,8 @@ dump_relocations (FILE * file, break; case EM_ARC: + case EM_ARC_COMPACT: + case EM_ARC_COMPACT2: rtype = elf_arc_reloc_type (type); break; @@ -1609,12 +1624,9 @@ dump_relocations (FILE * file, if (is_rela) { - bfd_signed_vma off = rels[i].r_addend; + bfd_vma off = rels[i].r_addend; - /* PR 17531: file: 2e63226f. */ - if (off == ((bfd_signed_vma) 1) << ((sizeof (bfd_signed_vma) * 8) - 1)) - printf (" + %" BFD_VMA_FMT "x", off); - else if (off < 0) + if ((bfd_signed_vma) off < 0) printf (" - %" BFD_VMA_FMT "x", - off); else printf (" + %" BFD_VMA_FMT "x", off); @@ -1623,13 +1635,10 @@ dump_relocations (FILE * file, } else if (is_rela) { - bfd_signed_vma off = rels[i].r_addend; + bfd_vma off = rels[i].r_addend; printf ("%*c", is_32bit_elf ? 12 : 20, ' '); - /* PR 17531: file: 2e63226f. */ - if (off == ((bfd_signed_vma) 1) << ((sizeof (bfd_signed_vma) * 8) - 1)) - printf ("%" BFD_VMA_FMT "x", off); - else if (off < 0) + if ((bfd_signed_vma) off < 0) printf ("-%" BFD_VMA_FMT "x", - off); else printf ("%" BFD_VMA_FMT "x", off); @@ -1696,6 +1705,7 @@ get_mips_dynamic_type (unsigned long type) case DT_MIPS_GOTSYM: return "MIPS_GOTSYM"; case DT_MIPS_HIPAGENO: return "MIPS_HIPAGENO"; case DT_MIPS_RLD_MAP: return "MIPS_RLD_MAP"; + case DT_MIPS_RLD_MAP_REL: return "MIPS_RLD_MAP_REL"; case DT_MIPS_DELTA_CLASS: return "MIPS_DELTA_CLASS"; case DT_MIPS_DELTA_CLASS_NO: return "MIPS_DELTA_CLASS_NO"; case DT_MIPS_DELTA_INSTANCE: return "MIPS_DELTA_INSTANCE"; @@ -1842,6 +1852,34 @@ get_ia64_dynamic_type (unsigned long type) } static const char * +get_solaris_section_type (unsigned long type) +{ + switch (type) + { + case 0x6fffffee: return "SUNW_ancillary"; + case 0x6fffffef: return "SUNW_capchain"; + case 0x6ffffff0: return "SUNW_capinfo"; + case 0x6ffffff1: return "SUNW_symsort"; + case 0x6ffffff2: return "SUNW_tlssort"; + case 0x6ffffff3: return "SUNW_LDYNSYM"; + case 0x6ffffff4: return "SUNW_dof"; + case 0x6ffffff5: return "SUNW_cap"; + case 0x6ffffff6: return "SUNW_SIGNATURE"; + case 0x6ffffff7: return "SUNW_ANNOTATE"; + case 0x6ffffff8: return "SUNW_DEBUGSTR"; + case 0x6ffffff9: return "SUNW_DEBUG"; + case 0x6ffffffa: return "SUNW_move"; + case 0x6ffffffb: return "SUNW_COMDAT"; + case 0x6ffffffc: return "SUNW_syminfo"; + case 0x6ffffffd: return "SUNW_verdef"; + case 0x6ffffffe: return "SUNW_verneed"; + case 0x6fffffff: return "SUNW_versym"; + case 0x70000000: return "SPARC_GOTDATA"; + default: return NULL; + } +} + +static const char * get_alpha_dynamic_type (unsigned long type) { switch (type) @@ -1896,6 +1934,43 @@ get_nios2_dynamic_type (unsigned long type) } static const char * +get_solaris_dynamic_type (unsigned long type) +{ + switch (type) + { + case 0x6000000d: return "SUNW_AUXILIARY"; + case 0x6000000e: return "SUNW_RTLDINF"; + case 0x6000000f: return "SUNW_FILTER"; + case 0x60000010: return "SUNW_CAP"; + case 0x60000011: return "SUNW_SYMTAB"; + case 0x60000012: return "SUNW_SYMSZ"; + case 0x60000013: return "SUNW_SORTENT"; + case 0x60000014: return "SUNW_SYMSORT"; + case 0x60000015: return "SUNW_SYMSORTSZ"; + case 0x60000016: return "SUNW_TLSSORT"; + case 0x60000017: return "SUNW_TLSSORTSZ"; + case 0x60000018: return "SUNW_CAPINFO"; + case 0x60000019: return "SUNW_STRPAD"; + case 0x6000001a: return "SUNW_CAPCHAIN"; + case 0x6000001b: return "SUNW_LDMACH"; + case 0x6000001d: return "SUNW_CAPCHAINENT"; + case 0x6000001f: return "SUNW_CAPCHAINSZ"; + case 0x60000021: return "SUNW_PARENT"; + case 0x60000023: return "SUNW_ASLR"; + case 0x60000025: return "SUNW_RELAX"; + case 0x60000029: return "SUNW_NXHEAP"; + case 0x6000002b: return "SUNW_NXSTACK"; + + case 0x70000001: return "SPARC_REGISTER"; + case 0x7ffffffd: return "AUXILIARY"; + case 0x7ffffffe: return "USED"; + case 0x7fffffff: return "FILTER"; + + default: return NULL; + } +} + +static const char * get_dynamic_type (unsigned long type) { static char buff[64]; @@ -2013,7 +2088,10 @@ get_dynamic_type (unsigned long type) result = get_nios2_dynamic_type (type); break; default: - result = NULL; + if (elf_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS) + result = get_solaris_dynamic_type (type); + else + result = NULL; break; } @@ -2037,7 +2115,10 @@ get_dynamic_type (unsigned long type) result = get_ia64_dynamic_type (type); break; default: - result = NULL; + if (elf_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS) + result = get_solaris_dynamic_type (type); + else + result = NULL; break; } @@ -2093,7 +2174,7 @@ get_machine_name (unsigned e_machine) case EM_386: return "Intel 80386"; case EM_68K: return "MC68000"; case EM_88K: return "MC88000"; - case EM_486: return "Intel 80486"; + case EM_IAMCU: return "Intel MCU"; case EM_860: return "Intel 80860"; case EM_MIPS: return "MIPS R3000"; case EM_S370: return "IBM System/370"; @@ -2115,6 +2196,8 @@ get_machine_name (unsigned e_machine) case EM_SPARCV9: return "Sparc v9"; case EM_TRICORE: return "Siemens Tricore"; case EM_ARC: return "ARC"; + case EM_ARC_COMPACT: return "ARCompact"; + case EM_ARC_COMPACT2: return "ARCv2"; case EM_H8_300: return "Renesas H8/300"; case EM_H8_300H: return "Renesas H8/300H"; case EM_H8S: return "Renesas H8S"; @@ -2182,7 +2265,6 @@ get_machine_name (unsigned e_machine) case EM_SCORE: return "SUNPLUS S+Core"; case EM_XSTORMY16: return "Sanyo XStormy16 CPU core"; case EM_OR1K: return "OpenRISC 1000"; - case EM_ARC_A5: return "ARC International ARCompact processor"; case EM_CRX: return "National Semiconductor CRX microprocessor"; case EM_ADAPTEVA_EPIPHANY: return "Adapteva EPIPHANY"; case EM_DLX: return "OpenDLX"; @@ -2265,6 +2347,73 @@ get_machine_name (unsigned e_machine) } static void +decode_ARC_machine_flags (unsigned e_flags, unsigned e_machine, char buf[]) +{ + /* ARC has two machine types EM_ARC_COMPACT and EM_ARC_COMPACT2. Some + other compilers don't a specific architecture type in the e_flags, and + instead use EM_ARC_COMPACT for old ARC600, ARC601, and ARC700 + architectures, and switch to EM_ARC_COMPACT2 for newer ARCEM and ARCHS + architectures. + + Th GNU tools follows this use of EM_ARC_COMPACT and EM_ARC_COMPACT2, + but also sets a specific architecture type in the e_flags field. + + However, when decoding the flags we don't worry if we see an + unexpected pairing, for example EM_ARC_COMPACT machine type, with + ARCEM architecture type. */ + + switch (e_flags & EF_ARC_MACH_MSK) + { + /* We only expect these to occur for EM_ARC_COMPACT2. */ + case EF_ARC_CPU_ARCV2EM: + strcat (buf, ", ARC EM"); + break; + case EF_ARC_CPU_ARCV2HS: + strcat (buf, ", ARC HS"); + break; + + /* We only expect these to occur for EM_ARC_COMPACT. */ + case E_ARC_MACH_ARC600: + strcat (buf, ", ARC600"); + break; + case E_ARC_MACH_ARC601: + strcat (buf, ", ARC601"); + break; + case E_ARC_MACH_ARC700: + strcat (buf, ", ARC700"); + break; + + /* The only times we should end up here are (a) A corrupt ELF, (b) A + new ELF with new architecture being read by an old version of + readelf, or (c) An ELF built with non-GNU compiler that does not + set the architecture in the e_flags. */ + default: + if (e_machine == EM_ARC_COMPACT) + strcat (buf, ", Unknown ARCompact"); + else + strcat (buf, ", Unknown ARC"); + break; + } + + switch (e_flags & EF_ARC_OSABI_MSK) + { + case E_ARC_OSABI_ORIG: + strcat (buf, ", (ABI:legacy)"); + break; + case E_ARC_OSABI_V2: + strcat (buf, ", (ABI:v2)"); + break; + /* Only upstream 3.9+ kernels will support ARCv2 ISA. */ + case E_ARC_OSABI_V3: + strcat (buf, ", v3 no-legacy-syscalls ABI"); + break; + default: + strcat (buf, ", unrecognised ARC OSABI flag"); + break; + } +} + +static void decode_ARM_machine_flags (unsigned e_flags, char buf[]) { unsigned eabi; @@ -2280,12 +2429,6 @@ decode_ARM_machine_flags (unsigned e_flags, char buf[]) e_flags &= ~ EF_ARM_RELEXEC; } - if (e_flags & EF_ARM_HASENTRY) - { - strcat (buf, ", has entry point"); - e_flags &= ~ EF_ARM_HASENTRY; - } - /* Now handle EABI specific flags. */ switch (eabi) { @@ -2767,6 +2910,11 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) default: break; + case EM_ARC_COMPACT2: + case EM_ARC_COMPACT: + decode_ARC_machine_flags (e_flags, e_machine, buf); + break; + case EM_ARM: decode_ARM_machine_flags (e_flags, buf); break; @@ -2900,6 +3048,40 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) } break; + case EM_CYGNUS_MEP: + switch (e_flags & EF_MEP_CPU_MASK) + { + case EF_MEP_CPU_MEP: strcat (buf, ", generic MeP"); break; + case EF_MEP_CPU_C2: strcat (buf, ", MeP C2"); break; + case EF_MEP_CPU_C3: strcat (buf, ", MeP C3"); break; + case EF_MEP_CPU_C4: strcat (buf, ", MeP C4"); break; + case EF_MEP_CPU_C5: strcat (buf, ", MeP C5"); break; + case EF_MEP_CPU_H1: strcat (buf, ", MeP H1"); break; + default: strcat (buf, _(", ")); break; + } + + switch (e_flags & EF_MEP_COP_MASK) + { + case EF_MEP_COP_NONE: break; + case EF_MEP_COP_AVC: strcat (buf, ", AVC coprocessor"); break; + case EF_MEP_COP_AVC2: strcat (buf, ", AVC2 coprocessor"); break; + case EF_MEP_COP_FMAX: strcat (buf, ", FMAX coprocessor"); break; + case EF_MEP_COP_IVC2: strcat (buf, ", IVC2 coprocessor"); break; + default: strcat (buf, _("")); break; + } + + if (e_flags & EF_MEP_LIBRARY) + strcat (buf, ", Built for Library"); + + if (e_flags & EF_MEP_INDEX_MASK) + sprintf (buf + strlen (buf), ", Configuration Index: %#x", + e_flags & EF_MEP_INDEX_MASK); + + if (e_flags & ~ EF_MEP_ALL_FLAGS) + sprintf (buf + strlen (buf), _(", unknown flags bits: %#x"), + e_flags & ~ EF_MEP_ALL_FLAGS); + break; + case EM_PPC: if (e_flags & EF_PPC_EMB) strcat (buf, ", emb"); @@ -2952,12 +3134,8 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) { case EF_RH850_FPU_DOUBLE: strcat (buf, ", double precision FPU"); break; case EF_RH850_FPU_SINGLE: strcat (buf, ", single precision FPU"); break; - case EF_RH850_SIMD: strcat (buf, ", SIMD"); break; - case EF_RH850_CACHE: strcat (buf, ", CACHE"); break; - case EF_RH850_MMU: strcat (buf, ", MMU"); break; case EF_RH850_REGMODE22: strcat (buf, ", regmode:22"); break; case EF_RH850_REGMODE32: strcat (buf, ", regmode:23"); break; - case EF_RH850_DATA_ALIGN8: strcat (buf, ", 8-byte alignment"); break; case EF_RH850_GP_FIX: strcat (buf, ", r4 fixed"); break; case EF_RH850_GP_NOFIX: strcat (buf, ", r4 free"); break; case EF_RH850_EP_FIX: strcat (buf, ", r30 fixed"); break; @@ -3266,8 +3444,13 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) break; case EM_RL78: - if (e_flags & E_FLAG_RL78_G10) - strcat (buf, ", G10"); + switch (e_flags & E_FLAG_RL78_CPU_MASK) + { + case E_FLAG_RL78_ANY_CPU: break; + case E_FLAG_RL78_G10: strcat (buf, ", G10"); break; + case E_FLAG_RL78_G13: strcat (buf, ", G13"); break; + case E_FLAG_RL78_G14: strcat (buf, ", G14"); break; + } if (e_flags & E_FLAG_RL78_64BIT_DOUBLES) strcat (buf, ", 64-bit doubles"); break; @@ -3281,6 +3464,11 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) strcat (buf, ", pid"); if (e_flags & E_FLAG_RX_ABI) strcat (buf, ", RX ABI"); + if (e_flags & E_FLAG_RX_SINSNS_SET) + strcat (buf, e_flags & E_FLAG_RX_SINSNS_YES + ? ", uses String instructions" : ", bans String instructions"); + if (e_flags & E_FLAG_RX_V2) + strcat (buf, ", V2"); break; case EM_S390: @@ -3499,6 +3687,23 @@ get_tic6x_segment_type (unsigned long type) } static const char * +get_solaris_segment_type (unsigned long type) +{ + switch (type) + { + case 0x6464e550: return "PT_SUNW_UNWIND"; + case 0x6474e550: return "PT_SUNW_EH_FRAME"; + case 0x6ffffff7: return "PT_LOSUNW"; + case 0x6ffffffa: return "PT_SUNWBSS"; + case 0x6ffffffb: return "PT_SUNWSTACK"; + case 0x6ffffffc: return "PT_SUNWDTRACE"; + case 0x6ffffffd: return "PT_SUNWCAP"; + case 0x6fffffff: return "PT_HISUNW"; + default: return NULL; + } +} + +static const char * get_segment_type (unsigned long p_type) { static char buff[32]; @@ -3568,7 +3773,10 @@ get_segment_type (unsigned long p_type) result = get_ia64_segment_type (p_type); break; default: - result = NULL; + if (elf_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS) + result = get_solaris_segment_type (p_type); + else + result = NULL; break; } @@ -3759,9 +3967,24 @@ get_msp430x_section_type_name (unsigned int sh_type) } static const char * +get_v850_section_type_name (unsigned int sh_type) +{ + switch (sh_type) + { + case SHT_V850_SCOMMON: return "V850 Small Common"; + case SHT_V850_TCOMMON: return "V850 Tiny Common"; + case SHT_V850_ZCOMMON: return "V850 Zero Common"; + case SHT_RENESAS_IOP: return "RENESAS IOP"; + case SHT_RENESAS_INFO: return "RENESAS INFO"; + default: return NULL; + } +} + +static const char * get_section_type_name (unsigned int sh_type) { static char buff[32]; + const char * result; switch (sh_type) { @@ -3795,8 +4018,6 @@ get_section_type_name (unsigned int sh_type) default: if ((sh_type >= SHT_LOPROC) && (sh_type <= SHT_HIPROC)) { - const char * result; - switch (elf_header.e_machine) { case EM_MIPS: @@ -3826,6 +4047,11 @@ get_section_type_name (unsigned int sh_type) case EM_MSP430: result = get_msp430x_section_type_name (sh_type); break; + case EM_V800: + case EM_V850: + case EM_CYGNUS_V850: + result = get_v850_section_type_name (sh_type); + break; default: result = NULL; break; @@ -3834,29 +4060,47 @@ get_section_type_name (unsigned int sh_type) if (result != NULL) return result; - sprintf (buff, "LOPROC+%x", sh_type - SHT_LOPROC); + sprintf (buff, "LOPROC+%#x", sh_type - SHT_LOPROC); } else if ((sh_type >= SHT_LOOS) && (sh_type <= SHT_HIOS)) { - const char * result; - switch (elf_header.e_machine) { case EM_IA_64: result = get_ia64_section_type_name (sh_type); break; default: - result = NULL; + if (elf_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS) + result = get_solaris_section_type (sh_type); + else + result = NULL; break; } if (result != NULL) return result; - sprintf (buff, "LOOS+%x", sh_type - SHT_LOOS); + sprintf (buff, "LOOS+%#x", sh_type - SHT_LOOS); } else if ((sh_type >= SHT_LOUSER) && (sh_type <= SHT_HIUSER)) - sprintf (buff, "LOUSER+%x", sh_type - SHT_LOUSER); + { + switch (elf_header.e_machine) + { + case EM_V800: + case EM_V850: + case EM_CYGNUS_V850: + result = get_v850_section_type_name (sh_type); + break; + default: + result = NULL; + break; + } + + if (result != NULL) + return result; + + sprintf (buff, "LOUSER+%#x", sh_type - SHT_LOUSER); + } else /* This message is probably going to be displayed in a 15 character wide field, so put the hex value first. */ @@ -3899,6 +4143,7 @@ static struct option options[] = {"hex-dump", required_argument, 0, 'x'}, {"relocated-dump", required_argument, 0, 'R'}, {"string-dump", required_argument, 0, 'p'}, + {"decompress", no_argument, 0, 'z'}, #ifdef SUPPORT_DISASSEMBLY {"instruction-dump", required_argument, 0, 'i'}, #endif @@ -3946,6 +4191,7 @@ usage (FILE * stream) Dump the contents of section as strings\n\ -R --relocated-dump=\n\ Dump the contents of section as relocated bytes\n\ + -z --decompress Decompress section before dumping it\n\ -w[lLiaprmfFsoRt] or\n\ --debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,\n\ =frames-interp,=str,=loc,=Ranges,=pubtypes,\n\ @@ -4056,7 +4302,7 @@ parse_args (int argc, char ** argv) usage (stderr); while ((c = getopt_long - (argc, argv, "ADHINR:SVWacdeghi:lnp:rstuvw::x:", options, NULL)) != EOF) + (argc, argv, "ADHINR:SVWacdeghi:lnp:rstuvw::x:z", options, NULL)) != EOF) { switch (c) { @@ -4139,6 +4385,9 @@ parse_args (int argc, char ** argv) case 'R': request_dump (RELOC_DUMP); break; + case 'z': + decompress_dumps++; + break; case 'w': do_dump++; if (optarg == 0) @@ -4211,11 +4460,6 @@ parse_args (int argc, char ** argv) && !do_section_groups && !do_archive_index && !do_dyn_syms) usage (stderr); - else if (argc < 3) - { - warn (_("Nothing to do.\n")); - usage (stderr); - } } static const char * @@ -4813,6 +5057,10 @@ get_32bit_section_headers (FILE * file, bfd_boolean probe) internal->sh_info = BYTE_GET (shdrs[i].sh_info); internal->sh_addralign = BYTE_GET (shdrs[i].sh_addralign); internal->sh_entsize = BYTE_GET (shdrs[i].sh_entsize); + if (!probe && internal->sh_link > num) + warn (_("Section %u has an out of range sh_link value of %u\n"), i, internal->sh_link); + if (!probe && internal->sh_flags & SHF_INFO_LINK && internal->sh_info > num) + warn (_("Section %u has an out of range sh_info value of %u\n"), i, internal->sh_info); } free (shdrs); @@ -4871,6 +5119,10 @@ get_64bit_section_headers (FILE * file, bfd_boolean probe) internal->sh_info = BYTE_GET (shdrs[i].sh_info); internal->sh_offset = BYTE_GET (shdrs[i].sh_offset); internal->sh_addralign = BYTE_GET (shdrs[i].sh_addralign); + if (!probe && internal->sh_link > num) + warn (_("Section %u has an out of range sh_link value of %u\n"), i, internal->sh_link); + if (!probe && internal->sh_flags & SHF_INFO_LINK && internal->sh_info > num) + warn (_("Section %u has an out of range sh_info value of %u\n"), i, internal->sh_info); } free (shdrs); @@ -4927,27 +5179,30 @@ get_32bit_elf_symbols (FILE * file, if (esyms == NULL) goto exit_point; - shndx = NULL; - if (symtab_shndx_hdr != NULL - && (symtab_shndx_hdr->sh_link - == (unsigned long) (section - section_headers))) - { - shndx = (Elf_External_Sym_Shndx *) get_data (NULL, file, - symtab_shndx_hdr->sh_offset, - 1, symtab_shndx_hdr->sh_size, - _("symbol table section indicies")); - if (shndx == NULL) - goto exit_point; - /* PR17531: file: heap-buffer-overflow */ - else if (symtab_shndx_hdr->sh_size / sizeof (Elf_External_Sym_Shndx) < number) + { + elf_section_list * entry; + + shndx = NULL; + for (entry = symtab_shndx_list; entry != NULL; entry = entry->next) + if (entry->hdr->sh_link == (unsigned long) (section - section_headers)) { - error (_("Index section %s has an sh_size of 0x%lx - expected 0x%lx\n"), - printable_section_name (symtab_shndx_hdr), - (unsigned long) symtab_shndx_hdr->sh_size, - (unsigned long) section->sh_size); - goto exit_point; + shndx = (Elf_External_Sym_Shndx *) get_data (NULL, file, + entry->hdr->sh_offset, + 1, entry->hdr->sh_size, + _("symbol table section indicies")); + if (shndx == NULL) + goto exit_point; + /* PR17531: file: heap-buffer-overflow */ + else if (entry->hdr->sh_size / sizeof (Elf_External_Sym_Shndx) < number) + { + error (_("Index section %s has an sh_size of 0x%lx - expected 0x%lx\n"), + printable_section_name (entry->hdr), + (unsigned long) entry->hdr->sh_size, + (unsigned long) section->sh_size); + goto exit_point; + } } - } + } isyms = (Elf_Internal_Sym *) cmalloc (number, sizeof (Elf_Internal_Sym)); @@ -5037,25 +5292,30 @@ get_64bit_elf_symbols (FILE * file, if (!esyms) goto exit_point; - if (symtab_shndx_hdr != NULL - && (symtab_shndx_hdr->sh_link - == (unsigned long) (section - section_headers))) - { - shndx = (Elf_External_Sym_Shndx *) get_data (NULL, file, - symtab_shndx_hdr->sh_offset, - 1, symtab_shndx_hdr->sh_size, - _("symbol table section indicies")); - if (shndx == NULL) - goto exit_point; - else if (symtab_shndx_hdr->sh_size / sizeof (Elf_External_Sym_Shndx) < number) + { + elf_section_list * entry; + + shndx = NULL; + for (entry = symtab_shndx_list; entry != NULL; entry = entry->next) + if (entry->hdr->sh_link == (unsigned long) (section - section_headers)) { - error (_("Index section %s has an sh_size of 0x%lx - expected 0x%lx\n"), - printable_section_name (symtab_shndx_hdr), - (unsigned long) symtab_shndx_hdr->sh_size, - (unsigned long) section->sh_size); - goto exit_point; + shndx = (Elf_External_Sym_Shndx *) get_data (NULL, file, + entry->hdr->sh_offset, + 1, entry->hdr->sh_size, + _("symbol table section indicies")); + if (shndx == NULL) + goto exit_point; + /* PR17531: file: heap-buffer-overflow */ + else if (entry->hdr->sh_size / sizeof (Elf_External_Sym_Shndx) < number) + { + error (_("Index section %s has an sh_size of 0x%lx - expected 0x%lx\n"), + printable_section_name (entry->hdr), + (unsigned long) entry->hdr->sh_size, + (unsigned long) section->sh_size); + goto exit_point; + } } - } + } isyms = (Elf_Internal_Sym *) cmalloc (number, sizeof (Elf_Internal_Sym)); @@ -5136,7 +5396,12 @@ get_elf_section_flags (bfd_vma sh_flags) /* Generic. */ /* 18 */ { STRING_COMMA_LEN ("EXCLUDE") }, /* SPARC specific. */ - /* 19 */ { STRING_COMMA_LEN ("ORDERED") } + /* 19 */ { STRING_COMMA_LEN ("ORDERED") }, + /* 20 */ { STRING_COMMA_LEN ("COMPRESSED") }, + /* ARM specific. */ + /* 21 */ { STRING_COMMA_LEN ("ENTRYSECT") }, + /* 22 */ { STRING_COMMA_LEN ("ARM_NOREAD") }, + /* 23 */ { STRING_COMMA_LEN ("COMDEF") } }; if (do_section_details) @@ -5168,6 +5433,7 @@ get_elf_section_flags (bfd_vma sh_flags) case SHF_GROUP: sindex = 8; break; case SHF_TLS: sindex = 9; break; case SHF_EXCLUDE: sindex = 18; break; + case SHF_COMPRESSED: sindex = 20; break; default: sindex = -1; @@ -5194,7 +5460,7 @@ get_elf_section_flags (bfd_vma sh_flags) break; case EM_386: - case EM_486: + case EM_IAMCU: case EM_X86_64: case EM_L1OM: case EM_K1OM: @@ -5205,6 +5471,17 @@ get_elf_section_flags (bfd_vma sh_flags) if (flag == SHF_ORDERED) sindex = 19; break; + + case EM_ARM: + switch (flag) + { + case SHF_ENTRYSECT: sindex = 21; break; + case SHF_ARM_NOREAD: sindex = 22; break; + case SHF_COMDEF: sindex = 23; break; + default: break; + } + break; + default: break; } @@ -5249,6 +5526,7 @@ get_elf_section_flags (bfd_vma sh_flags) case SHF_GROUP: *p = 'G'; break; case SHF_TLS: *p = 'T'; break; case SHF_EXCLUDE: *p = 'E'; break; + case SHF_COMPRESSED: *p = 'C'; break; default: if ((elf_header.e_machine == EM_X86_64 @@ -5256,6 +5534,9 @@ get_elf_section_flags (bfd_vma sh_flags) || elf_header.e_machine == EM_K1OM) && flag == SHF_X86_64_LARGE) *p = 'l'; + else if (elf_header.e_machine == EM_ARM + && flag == SHF_ARM_NOREAD) + *p = 'y'; else if (flag & SHF_MASKOS) { *p = 'o'; @@ -5336,6 +5617,27 @@ get_elf_section_flags (bfd_vma sh_flags) return buff; } +static unsigned int +get_compression_header (Elf_Internal_Chdr *chdr, unsigned char *buf) +{ + if (is_32bit_elf) + { + Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) buf; + chdr->ch_type = BYTE_GET (echdr->ch_type); + chdr->ch_size = BYTE_GET (echdr->ch_size); + chdr->ch_addralign = BYTE_GET (echdr->ch_addralign); + return sizeof (*echdr); + } + else + { + Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) buf; + chdr->ch_type = BYTE_GET (echdr->ch_type); + chdr->ch_size = BYTE_GET (echdr->ch_size); + chdr->ch_addralign = BYTE_GET (echdr->ch_addralign); + return sizeof (*echdr); + } +} + static int process_section_headers (FILE * file) { @@ -5389,7 +5691,7 @@ process_section_headers (FILE * file) dynamic_symbols = NULL; dynamic_strings = NULL; dynamic_syminfo = NULL; - symtab_shndx_hdr = NULL; + symtab_shndx_list = NULL; eh_addr_size = is_32bit_elf ? 4 : 8; switch (elf_header.e_machine) @@ -5494,12 +5796,10 @@ process_section_headers (FILE * file) } else if (section->sh_type == SHT_SYMTAB_SHNDX) { - if (symtab_shndx_hdr != NULL) - { - error (_("File contains multiple symtab shndx tables\n")); - continue; - } - symtab_shndx_hdr = section; + elf_section_list * entry = xmalloc (sizeof * entry); + entry->hdr = section; + entry->next = symtab_shndx_list; + symtab_shndx_list = entry; } else if (section->sh_type == SHT_SYMTAB) CHECK_ENTSIZE (section, i, Sym); @@ -5621,6 +5921,13 @@ process_section_headers (FILE * file) i < elf_header.e_shnum; i++, section++) { + /* Check the sh_size field. */ + if (section->sh_size > current_file_size + && section->sh_type != SHT_NOBITS + && section->sh_type != SHT_NULL + && section->sh_type < SHT_LOOS) + warn (_("Size of section %u is larger than the entire file!\n"), i); + printf (" [%2u] ", i); if (do_section_details) printf ("%s\n ", printable_section_name (section)); @@ -5654,7 +5961,7 @@ process_section_headers (FILE * file) switch (elf_header.e_machine) { case EM_386: - case EM_486: + case EM_IAMCU: case EM_X86_64: case EM_L1OM: case EM_K1OM: @@ -5780,23 +6087,47 @@ process_section_headers (FILE * file) } if (do_section_details) - printf (" %s\n", get_elf_section_flags (section->sh_flags)); + { + printf (" %s\n", get_elf_section_flags (section->sh_flags)); + if ((section->sh_flags & SHF_COMPRESSED) != 0) + { + /* Minimum section size is 12 bytes for 32-bit compression + header + 12 bytes for compressed data header. */ + unsigned char buf[24]; + assert (sizeof (buf) >= sizeof (Elf64_External_Chdr)); + if (get_data (&buf, (FILE *) file, section->sh_offset, 1, + sizeof (buf), _("compression header"))) + { + Elf_Internal_Chdr chdr; + get_compression_header (&chdr, buf); + if (chdr.ch_type == ELFCOMPRESS_ZLIB) + printf (" ZLIB, "); + else + printf (_(" [: 0x%x], "), + chdr.ch_type); + print_vma (chdr.ch_size, LONG_HEX); + printf (", %lu\n", (unsigned long) chdr.ch_addralign); + } + } + } } if (!do_section_details) { + /* The ordering of the letters shown here matches the ordering of the + corresponding SHF_xxx values, and hence the order in which these + letters will be displayed to the user. */ + printf (_("Key to Flags:\n\ + W (write), A (alloc), X (execute), M (merge), S (strings), I (info),\n\ + L (link order), O (extra OS processing required), G (group), T (TLS),\n\ + C (compressed), x (unknown), o (OS specific), E (exclude),\n ")); if (elf_header.e_machine == EM_X86_64 || elf_header.e_machine == EM_L1OM || elf_header.e_machine == EM_K1OM) - printf (_("Key to Flags:\n\ - W (write), A (alloc), X (execute), M (merge), S (strings), l (large)\n\ - I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)\n\ - O (extra OS processing required) o (OS specific), p (processor specific)\n")); - else - printf (_("Key to Flags:\n\ - W (write), A (alloc), X (execute), M (merge), S (strings)\n\ - I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)\n\ - O (extra OS processing required) o (OS specific), p (processor specific)\n")); + printf (_("l (large), ")); + else if (elf_header.e_machine == EM_ARM) + printf (_("y (noread), ")); + printf ("p (processor specific)\n"); } return 1; @@ -5805,7 +6136,7 @@ process_section_headers (FILE * file) static const char * get_group_flags (unsigned int flags) { - static char buff[32]; + static char buff[128]; switch (flags) { case 0: @@ -6627,7 +6958,7 @@ dump_ia64_unwind (struct ia64_unw_aux_info * aux) if (end > aux->info + aux->info_size) end = aux->info + aux->info_size; for (dp = head + 8; dp < end;) - dp = unw_decode (dp, in_body, & in_body); + dp = unw_decode (dp, in_body, & in_body, end); } free (aux->funtab); @@ -7415,7 +7746,10 @@ get_unwind_section_word (struct arm_unw_aux_info * aux, return FALSE; /* If the offset is invalid then fail. */ - if (word_offset > sec->sh_size - 4) + if (/* PR 21343 *//* PR 18879 */ + sec->sh_size < 4 + || word_offset > (sec->sh_size - 4) + || ((bfd_signed_vma) word_offset) < 0) return FALSE; /* Get the word at the required offset. */ @@ -8198,6 +8532,15 @@ dump_arm_unwind (struct arm_unw_aux_info *aux, Elf_Internal_Shdr *exidx_sec) { table_sec = section_headers + entry_addr.section; table_offset = entry_addr.offset; + /* PR 18879 */ + if (table_offset > table_sec->sh_size + || ((bfd_signed_vma) table_offset) < 0) + { + warn (_("Unwind entry contains corrupt offset (0x%lx) into section %s\n"), + (unsigned long) table_offset, + printable_section_name (table_sec)); + continue; + } } else { @@ -8376,7 +8719,7 @@ dynamic_section_mips_val (Elf_Internal_Dyn * entry) case DT_MIPS_TIME_STAMP: { - char timebuf[20]; + char timebuf[128]; struct tm * tmp; time_t atime = entry->d_un.d_val; @@ -8405,7 +8748,7 @@ dynamic_section_mips_val (Elf_Internal_Dyn * entry) case DT_MIPS_DELTA_SYM_NO: case DT_MIPS_DELTA_CLASSSYM_NO: case DT_MIPS_COMPACT_SIZE: - print_vma (entry->d_un.d_ptr, DEC); + print_vma (entry->d_un.d_val, DEC); break; default: @@ -8574,7 +8917,7 @@ get_32bit_dynamic_section (FILE * file) might not have the luxury of section headers. Look for the DT_NULL terminator to determine the number of entries. */ for (ext = edyn, dynamic_nent = 0; - (char *) ext < (char *) edyn + dynamic_size - sizeof (* entry); + (char *) (ext + 1) <= (char *) edyn + dynamic_size; ext++) { dynamic_nent++; @@ -8622,8 +8965,8 @@ get_64bit_dynamic_section (FILE * file) might not have the luxury of section headers. Look for the DT_NULL terminator to determine the number of entries. */ for (ext = edyn, dynamic_nent = 0; - /* PR 17533 file: 033-67080-0.004 - do not read off the end of the buffer. */ - (char *) ext < ((char *) edyn) + dynamic_size - sizeof (* ext); + /* PR 17533 file: 033-67080-0.004 - do not read past end of buffer. */ + (char *) (ext + 1) <= (char *) edyn + dynamic_size; ext++) { dynamic_nent++; @@ -9126,6 +9469,16 @@ process_dynamic_section (FILE * file) printf (" SINGLETON"); val ^= DF_1_SINGLETON; } + if (val & DF_1_STUB) + { + printf (" STUB"); + val ^= DF_1_STUB; + } + if (val & DF_1_PIE) + { + printf (" PIE"); + val ^= DF_1_PIE; + } if (val != 0) printf (" %lx", val); puts (""); @@ -9689,8 +10042,8 @@ process_version_sections (FILE * file) for (cnt = 0; cnt < total; cnt += 4) { int j, nn; - int check_def, check_need; - char * name; + char *name; + char *invalid = _("*invalid*"); printf (" %03x:", cnt); @@ -9717,20 +10070,8 @@ process_version_sections (FILE * file) break; } - check_def = 1; - check_need = 1; - if (symbols[cnt + j].st_shndx >= elf_header.e_shnum - || section_headers[symbols[cnt + j].st_shndx].sh_type - != SHT_NOBITS) - { - if (symbols[cnt + j].st_shndx == SHN_UNDEF) - check_def = 0; - else - check_need = 0; - } - - if (check_need - && version_info[DT_VERSIONTAGIDX (DT_VERNEED)]) + name = NULL; + if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)]) { Elf_Internal_Verneed ivn; unsigned long offset; @@ -9779,14 +10120,9 @@ process_version_sections (FILE * file) ivna.vna_name = BYTE_GET (evna.vna_name); if (ivna.vna_name >= string_sec->sh_size) - name = _("*invalid*"); + name = invalid; else name = strtab + ivna.vna_name; - nn += printf ("(%s%-*s", - name, - 12 - (int) strlen (name), - ")"); - check_def = 0; break; } @@ -9795,7 +10131,7 @@ process_version_sections (FILE * file) while (ivn.vn_next); } - if (check_def && data[cnt + j] != 0x8001 + if (data[cnt + j] != 0x8001 && version_info[DT_VERSIONTAGIDX (DT_VERDEF)]) { Elf_Internal_Verdef ivd; @@ -9843,15 +10179,18 @@ process_version_sections (FILE * file) ivda.vda_name = BYTE_GET (evda.vda_name); if (ivda.vda_name >= string_sec->sh_size) - name = _("*invalid*"); + name = invalid; + else if (name != NULL && name != invalid) + name = _("*both*"); else name = strtab + ivda.vda_name; - nn += printf ("(%s%-*s", - name, - 12 - (int) strlen (name), - ")"); } } + if (name != NULL) + nn += printf ("(%s%-*s", + name, + 12 - (int) strlen (name), + ")"); if (nn < 18) printf ("%*c", 18 - nn, ' '); @@ -9977,6 +10316,18 @@ get_symbol_visibility (unsigned int visibility) } static const char * +get_solaris_symbol_visibility (unsigned int visibility) +{ + switch (visibility) + { + case 4: return "EXPORTED"; + case 5: return "SINGLETON"; + case 6: return "ELIMINATE"; + default: return get_symbol_visibility (visibility); + } +} + +static const char * get_mips_symbol_other (unsigned int other) { switch (other) @@ -10099,6 +10450,7 @@ get_symbol_other (unsigned int other) result = get_ppc64_symbol_other (other); break; default: + result = NULL; break; } @@ -10165,8 +10517,9 @@ get_dynamic_data (FILE * file, bfd_size_type number, unsigned int ent_size) if (sizeof (size_t) < sizeof (bfd_size_type) && (bfd_size_type) ((size_t) number) != number) { - error (_("Size truncation prevents reading %llu elements of size %u\n"), - (unsigned long long) number, ent_size); + error (_("Size truncation prevents reading %" BFD_VMA_FMT "u" + " elements of size %u\n"), + number, ent_size); return NULL; } @@ -10174,23 +10527,23 @@ get_dynamic_data (FILE * file, bfd_size_type number, unsigned int ent_size) attempting to allocate memory when the read is bound to fail. */ if (ent_size * number > current_file_size) { - error (_("Invalid number of dynamic entries: %llu\n"), - (unsigned long long) number); + error (_("Invalid number of dynamic entries: %" BFD_VMA_FMT "u\n"), + number); return NULL; } e_data = (unsigned char *) cmalloc ((size_t) number, ent_size); if (e_data == NULL) { - error (_("Out of memory reading %llu dynamic entries\n"), - (unsigned long long) number); + error (_("Out of memory reading %" BFD_VMA_FMT "u dynamic entries\n"), + number); return NULL; } if (fread (e_data, ent_size, (size_t) number, file) != number) { - error (_("Unable to read in %llu bytes of dynamic data\n"), - (unsigned long long) (number * ent_size)); + error (_("Unable to read in %" BFD_VMA_FMT "u bytes of dynamic data\n"), + number * ent_size); free (e_data); return NULL; } @@ -10198,8 +10551,9 @@ get_dynamic_data (FILE * file, bfd_size_type number, unsigned int ent_size) i_data = (bfd_vma *) cmalloc ((size_t) number, sizeof (*i_data)); if (i_data == NULL) { - error (_("Out of memory allocating space for %llu dynamic entries\n"), - (unsigned long long) number); + error (_("Out of memory allocating space for %" BFD_VMA_FMT "u" + " dynamic entries\n"), + number); free (e_data); return NULL; } @@ -10237,13 +10591,22 @@ print_dynamic_symbol (bfd_vma si, unsigned long hn) printf (" %-7s", get_symbol_type (ELF_ST_TYPE (psym->st_info))); printf (" %-6s", get_symbol_binding (ELF_ST_BIND (psym->st_info))); - printf (" %-7s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other))); - /* Check to see if any other bits in the st_other field are set. - Note - displaying this information disrupts the layout of the - table being generated, but for the moment this case is very - rare. */ - if (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other)) - printf (" [%s] ", get_symbol_other (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other))); + + if (elf_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS) + printf (" %-7s", get_solaris_symbol_visibility (psym->st_other)); + else + { + unsigned int vis = ELF_ST_VISIBILITY (psym->st_other); + + printf (" %-7s", get_symbol_visibility (vis)); + /* Check to see if any other bits in the st_other field are set. + Note - displaying this information disrupts the layout of the + table being generated, but for the moment this case is very + rare. */ + if (psym->st_other ^ vis) + printf (" [%s] ", get_symbol_other (psym->st_other ^ vis)); + } + printf (" %3.3s ", get_symbol_index_type (psym->st_shndx)); if (VALID_DYNAMIC_NAME (psym->st_name)) print_symbol (25, GET_DYNAMIC_NAME (psym->st_name)); @@ -10253,179 +10616,165 @@ print_dynamic_symbol (bfd_vma si, unsigned long hn) } static const char * -get_symbol_version_string (FILE *file, int is_dynsym, - const char *strtab, - unsigned long int strtab_size, - unsigned int si, Elf_Internal_Sym *psym, - enum versioned_symbol_info *sym_info, - unsigned short *vna_other) +get_symbol_version_string (FILE * file, + bfd_boolean is_dynsym, + const char * strtab, + unsigned long int strtab_size, + unsigned int si, + Elf_Internal_Sym * psym, + enum versioned_symbol_info * sym_info, + unsigned short * vna_other) { - const char *version_string = NULL; + unsigned char data[2]; + unsigned short vers_data; + unsigned long offset; - if (is_dynsym - && version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0) - { - unsigned char data[2]; - unsigned short vers_data; - unsigned long offset; - int is_nobits; - int check_def; + if (!is_dynsym + || version_info[DT_VERSIONTAGIDX (DT_VERSYM)] == 0) + return NULL; - offset = offset_from_vma - (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)], - sizeof data + si * sizeof (vers_data)); + offset = offset_from_vma (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)], + sizeof data + si * sizeof (vers_data)); - if (get_data (&data, file, offset + si * sizeof (vers_data), - sizeof (data), 1, _("version data")) == NULL) - return NULL; + if (get_data (&data, file, offset + si * sizeof (vers_data), + sizeof (data), 1, _("version data")) == NULL) + return NULL; + + vers_data = byte_get (data, 2); + + if ((vers_data & VERSYM_HIDDEN) == 0 && vers_data <= 1) + return NULL; - vers_data = byte_get (data, 2); + /* Usually we'd only see verdef for defined symbols, and verneed for + undefined symbols. However, symbols defined by the linker in + .dynbss for variables copied from a shared library in order to + avoid text relocations are defined yet have verneed. We could + use a heuristic to detect the special case, for example, check + for verneed first on symbols defined in SHT_NOBITS sections, but + it is simpler and more reliable to just look for both verdef and + verneed. .dynbss might not be mapped to a SHT_NOBITS section. */ - is_nobits = (section_headers != NULL - && psym->st_shndx < elf_header.e_shnum - && section_headers[psym->st_shndx].sh_type - == SHT_NOBITS); + if (psym->st_shndx != SHN_UNDEF + && vers_data != 0x8001 + && version_info[DT_VERSIONTAGIDX (DT_VERDEF)]) + { + Elf_Internal_Verdef ivd; + Elf_Internal_Verdaux ivda; + Elf_External_Verdaux evda; + unsigned long off; - check_def = (psym->st_shndx != SHN_UNDEF); + off = offset_from_vma (file, + version_info[DT_VERSIONTAGIDX (DT_VERDEF)], + sizeof (Elf_External_Verdef)); - if ((vers_data & VERSYM_HIDDEN) || vers_data > 1) + do { - if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)] - && (is_nobits || ! check_def)) + Elf_External_Verdef evd; + + if (get_data (&evd, file, off, sizeof (evd), 1, + _("version def")) == NULL) + { + ivd.vd_ndx = 0; + ivd.vd_aux = 0; + ivd.vd_next = 0; + } + else { - Elf_External_Verneed evn; - Elf_Internal_Verneed ivn; - Elf_Internal_Vernaux ivna; + ivd.vd_ndx = BYTE_GET (evd.vd_ndx); + ivd.vd_aux = BYTE_GET (evd.vd_aux); + ivd.vd_next = BYTE_GET (evd.vd_next); + } - /* We must test both. */ - offset = offset_from_vma - (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)], - sizeof evn); + off += ivd.vd_next; + } + while (ivd.vd_ndx != (vers_data & VERSYM_VERSION) && ivd.vd_next != 0); - do - { - unsigned long vna_off; + if (ivd.vd_ndx == (vers_data & VERSYM_VERSION)) + { + off -= ivd.vd_next; + off += ivd.vd_aux; - if (get_data (&evn, file, offset, sizeof (evn), 1, - _("version need")) == NULL) - { - ivna.vna_next = 0; - ivna.vna_other = 0; - ivna.vna_name = 0; - break; - } + if (get_data (&evda, file, off, sizeof (evda), 1, + _("version def aux")) != NULL) + { + ivda.vda_name = BYTE_GET (evda.vda_name); - ivn.vn_aux = BYTE_GET (evn.vn_aux); - ivn.vn_next = BYTE_GET (evn.vn_next); + if (psym->st_name != ivda.vda_name) + { + *sym_info = ((vers_data & VERSYM_HIDDEN) != 0 + ? symbol_hidden : symbol_public); + return (ivda.vda_name < strtab_size + ? strtab + ivda.vda_name : _("")); + } + } + } + } - vna_off = offset + ivn.vn_aux; + if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)]) + { + Elf_External_Verneed evn; + Elf_Internal_Verneed ivn; + Elf_Internal_Vernaux ivna; - do - { - Elf_External_Vernaux evna; + offset = offset_from_vma (file, + version_info[DT_VERSIONTAGIDX (DT_VERNEED)], + sizeof evn); + do + { + unsigned long vna_off; - if (get_data (&evna, file, vna_off, - sizeof (evna), 1, - _("version need aux (3)")) == NULL) - { - ivna.vna_next = 0; - ivna.vna_other = 0; - ivna.vna_name = 0; - } - else - { - ivna.vna_other = BYTE_GET (evna.vna_other); - ivna.vna_next = BYTE_GET (evna.vna_next); - ivna.vna_name = BYTE_GET (evna.vna_name); - } + if (get_data (&evn, file, offset, sizeof (evn), 1, + _("version need")) == NULL) + { + ivna.vna_next = 0; + ivna.vna_other = 0; + ivna.vna_name = 0; + break; + } - vna_off += ivna.vna_next; - } - while (ivna.vna_other != vers_data - && ivna.vna_next != 0); + ivn.vn_aux = BYTE_GET (evn.vn_aux); + ivn.vn_next = BYTE_GET (evn.vn_next); - if (ivna.vna_other == vers_data) - break; + vna_off = offset + ivn.vn_aux; - offset += ivn.vn_next; - } - while (ivn.vn_next != 0); + do + { + Elf_External_Vernaux evna; - if (ivna.vna_other == vers_data) + if (get_data (&evna, file, vna_off, sizeof (evna), 1, + _("version need aux (3)")) == NULL) { - *sym_info = symbol_undefined; - *vna_other = ivna.vna_other; - version_string = (ivna.vna_name < strtab_size - ? strtab + ivna.vna_name - : _("")); - check_def = 0; + ivna.vna_next = 0; + ivna.vna_other = 0; + ivna.vna_name = 0; } - else if (! is_nobits) - error (_("bad dynamic symbol\n")); else - check_def = 1; - } - - if (check_def) - { - if (vers_data != 0x8001 - && version_info[DT_VERSIONTAGIDX (DT_VERDEF)]) { - Elf_Internal_Verdef ivd; - Elf_Internal_Verdaux ivda; - Elf_External_Verdaux evda; - unsigned long off; - - off = offset_from_vma - (file, - version_info[DT_VERSIONTAGIDX (DT_VERDEF)], - sizeof (Elf_External_Verdef)); - - do - { - Elf_External_Verdef evd; - - if (get_data (&evd, file, off, sizeof (evd), - 1, _("version def")) == NULL) - { - ivd.vd_ndx = 0; - ivd.vd_aux = 0; - ivd.vd_next = 0; - } - else - { - ivd.vd_ndx = BYTE_GET (evd.vd_ndx); - ivd.vd_aux = BYTE_GET (evd.vd_aux); - ivd.vd_next = BYTE_GET (evd.vd_next); - } - - off += ivd.vd_next; - } - while (ivd.vd_ndx != (vers_data & VERSYM_VERSION) - && ivd.vd_next != 0); + ivna.vna_other = BYTE_GET (evna.vna_other); + ivna.vna_next = BYTE_GET (evna.vna_next); + ivna.vna_name = BYTE_GET (evna.vna_name); + } - off -= ivd.vd_next; - off += ivd.vd_aux; + vna_off += ivna.vna_next; + } + while (ivna.vna_other != vers_data && ivna.vna_next != 0); - if (get_data (&evda, file, off, sizeof (evda), - 1, _("version def aux")) == NULL) - return version_string; + if (ivna.vna_other == vers_data) + break; - ivda.vda_name = BYTE_GET (evda.vda_name); + offset += ivn.vn_next; + } + while (ivn.vn_next != 0); - if (psym->st_name != ivda.vda_name) - { - *sym_info = ((vers_data & VERSYM_HIDDEN) != 0 - ? symbol_hidden : symbol_public); - version_string = (ivda.vda_name < strtab_size - ? strtab + ivda.vda_name - : _("")); - } - } - } + if (ivna.vna_other == vers_data) + { + *sym_info = symbol_undefined; + *vna_other = ivna.vna_other; + return (ivna.vna_name < strtab_size + ? strtab + ivna.vna_name : _("")); } } - return version_string; + return NULL; } /* Dump the symbol table. */ @@ -10738,12 +11087,19 @@ process_symbol_table (FILE * file) print_vma (psym->st_size, DEC_5); printf (" %-7s", get_symbol_type (ELF_ST_TYPE (psym->st_info))); printf (" %-6s", get_symbol_binding (ELF_ST_BIND (psym->st_info))); - printf (" %-7s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other))); - /* Check to see if any other bits in the st_other field are set. - Note - displaying this information disrupts the layout of the - table being generated, but for the moment this case is very rare. */ - if (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other)) - printf (" [%s] ", get_symbol_other (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other))); + if (elf_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS) + printf (" %-7s", get_solaris_symbol_visibility (psym->st_other)); + else + { + unsigned int vis = ELF_ST_VISIBILITY (psym->st_other); + + printf (" %-7s", get_symbol_visibility (vis)); + /* Check to see if any other bits in the st_other field are set. + Note - displaying this information disrupts the layout of the + table being generated, but for the moment this case is very rare. */ + if (psym->st_other ^ vis) + printf (" [%s] ", get_symbol_other (psym->st_other ^ vis)); + } printf (" %4s ", get_symbol_index_type (psym->st_shndx)); print_symbol (25, psym->st_name < strtab_size ? strtab + psym->st_name : _("")); @@ -10783,6 +11139,7 @@ process_symbol_table (FILE * file) unsigned long maxlength = 0; unsigned long nzero_counts = 0; unsigned long nsyms = 0; + unsigned long chained; printf (_("\nHistogram for bucket list length (total of %lu buckets):\n"), (unsigned long) nbuckets); @@ -10797,21 +11154,23 @@ process_symbol_table (FILE * file) printf (_(" Length Number %% of total Coverage\n")); for (hn = 0; hn < nbuckets; ++hn) { - for (si = buckets[hn]; si > 0 && si < nchains && si < nbuckets; si = chains[si]) + for (si = buckets[hn], chained = 0; + si > 0 && si < nchains && si < nbuckets && chained <= nchains; + si = chains[si], ++chained) { ++nsyms; if (maxlength < ++lengths[hn]) ++maxlength; - - /* PR binutils/17531: A corrupt binary could contain broken - histogram data. Do not go into an infinite loop trying - to process it. */ - if (chains[si] == si) - { - error (_("histogram chain links to itself\n")); - break; - } } + + /* PR binutils/17531: A corrupt binary could contain broken + histogram data. Do not go into an infinite loop trying + to process it. */ + if (chained > nchains) + { + error (_("histogram chain is corrupt\n")); + break; + } } counts = (unsigned long *) calloc (maxlength + 1, sizeof (*counts)); @@ -11090,9 +11449,45 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc, } break; } - } - return FALSE; + case EM_RL78: + { + static bfd_vma saved_sym1 = 0; + static bfd_vma saved_sym2 = 0; + static bfd_vma value; + + switch (reloc_type) + { + case 0x80: /* R_RL78_SYM. */ + saved_sym1 = saved_sym2; + saved_sym2 = symtab[get_reloc_symindex (reloc->r_info)].st_value; + saved_sym2 += reloc->r_addend; + return TRUE; + + case 0x83: /* R_RL78_OPsub. */ + value = saved_sym1 - saved_sym2; + saved_sym2 = saved_sym1 = 0; + return TRUE; + break; + + case 0x41: /* R_RL78_ABS32. */ + byte_put (start + reloc->r_offset, value, 4); + value = 0; + return TRUE; + + case 0x43: /* R_RL78_ABS16. */ + byte_put (start + reloc->r_offset, value, 2); + value = 0; + return TRUE; + + default: + break; + } + break; + } + } + + return FALSE; } /* Returns TRUE iff RELOC_TYPE is a 32-bit absolute RELA relocation used in @@ -11109,10 +11504,11 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc, static bfd_boolean is_32bit_abs_reloc (unsigned int reloc_type) { + /* Please keep this table alpha-sorted for ease of visual lookup. */ switch (elf_header.e_machine) { case EM_386: - case EM_486: + case EM_IAMCU: return reloc_type == 1; /* R_386_32. */ case EM_68K: return reloc_type == 1; /* R_68K_32. */ @@ -11122,17 +11518,20 @@ is_32bit_abs_reloc (unsigned int reloc_type) return reloc_type == 2; /* R_960_32. */ case EM_AARCH64: return reloc_type == 258; /* R_AARCH64_ABS32 */ + case EM_ADAPTEVA_EPIPHANY: + return reloc_type == 3; case EM_ALPHA: return reloc_type == 1; /* R_ALPHA_REFLONG. */ case EM_ARC: return reloc_type == 1; /* R_ARC_32. */ + case EM_ARC_COMPACT: + case EM_ARC_COMPACT2: + return reloc_type == 4; /* R_ARC_32. */ case EM_ARM: return reloc_type == 2; /* R_ARM_ABS32 */ case EM_AVR_OLD: case EM_AVR: return reloc_type == 1; - case EM_ADAPTEVA_EPIPHANY: - return reloc_type == 3; case EM_BLACKFIN: return reloc_type == 0x12; /* R_byte4_data. */ case EM_CRIS: @@ -11161,7 +11560,8 @@ is_32bit_abs_reloc (unsigned int reloc_type) case EM_H8_300H: return reloc_type == 1; /* R_H8_DIR32. */ case EM_IA_64: - return reloc_type == 0x65; /* R_IA64_SECREL32LSB. */ + return reloc_type == 0x65 /* R_IA64_SECREL32LSB. */ + || reloc_type == 0x25; /* R_IA64_DIR32LSB. */ case EM_IP2K_OLD: case EM_IP2K: return reloc_type == 2; /* R_IP2K_32. */ @@ -11174,6 +11574,9 @@ is_32bit_abs_reloc (unsigned int reloc_type) return reloc_type == 3; /* R_M32C_32. */ case EM_M32R: return reloc_type == 34; /* R_M32R_32_RELA. */ + case EM_68HC11: + case EM_68HC12: + return reloc_type == 6; /* R_M68HC11_32. */ case EM_MCORE: return reloc_type == 1; /* R_MCORE_ADDR32. */ case EM_CYGNUS_MEP: @@ -11287,9 +11690,10 @@ static bfd_boolean is_32bit_pcrel_reloc (unsigned int reloc_type) { switch (elf_header.e_machine) + /* Please keep this table alpha-sorted for ease of visual lookup. */ { case EM_386: - case EM_486: + case EM_IAMCU: return reloc_type == 2; /* R_386_PC32. */ case EM_68K: return reloc_type == 4; /* R_68K_PC32. */ @@ -11299,8 +11703,14 @@ is_32bit_pcrel_reloc (unsigned int reloc_type) return reloc_type == 6; case EM_ALPHA: return reloc_type == 10; /* R_ALPHA_SREL32. */ + case EM_ARC_COMPACT: + case EM_ARC_COMPACT2: + return reloc_type == 49; /* R_ARC_32_PCREL. */ case EM_ARM: return reloc_type == 3; /* R_ARM_REL32 */ + case EM_AVR_OLD: + case EM_AVR: + return reloc_type == 36; /* R_AVR_32_PCREL. */ case EM_MICROBLAZE: return reloc_type == 2; /* R_MICROBLAZE_32_PCREL. */ case EM_OR1K: @@ -11366,7 +11776,8 @@ is_64bit_abs_reloc (unsigned int reloc_type) case EM_SPARC32PLUS: case EM_SPARCV9: case EM_SPARC: - return reloc_type == 54; /* R_SPARC_UA64. */ + return reloc_type == 32 /* R_SPARC_64. */ + || reloc_type == 54; /* R_SPARC_UA64. */ case EM_X86_64: case EM_L1OM: case EM_K1OM: @@ -11430,6 +11841,8 @@ is_24bit_abs_reloc (unsigned int reloc_type) case EM_CYGNUS_MN10200: case EM_MN10200: return reloc_type == 4; /* R_MN10200_24. */ + case EM_FT32: + return reloc_type == 5; /* R_FT32_20. */ default: return FALSE; } @@ -11441,13 +11854,18 @@ is_24bit_abs_reloc (unsigned int reloc_type) static bfd_boolean is_16bit_abs_reloc (unsigned int reloc_type) { + /* Please keep this table alpha-sorted for ease of visual lookup. */ switch (elf_header.e_machine) { + case EM_ARC: + case EM_ARC_COMPACT: + case EM_ARC_COMPACT2: + return reloc_type == 2; /* R_ARC_16. */ + case EM_ADAPTEVA_EPIPHANY: + return reloc_type == 5; case EM_AVR_OLD: case EM_AVR: return reloc_type == 4; /* R_AVR_16. */ - case EM_ADAPTEVA_EPIPHANY: - return reloc_type == 5; case EM_CYGNUS_D10V: case EM_D10V: return reloc_type == 3; /* R_D10V_16. */ @@ -11461,6 +11879,12 @@ is_16bit_abs_reloc (unsigned int reloc_type) case EM_M32C_OLD: case EM_M32C: return reloc_type == 1; /* R_M32C_16 */ + case EM_CYGNUS_MN10200: + case EM_MN10200: + return reloc_type == 2; /* R_MN10200_16. */ + case EM_CYGNUS_MN10300: + case EM_MN10300: + return reloc_type == 2; /* R_MN10300_16. */ case EM_MSP430: if (uses_msp430x_relocs ()) return reloc_type == 2; /* R_MSP430_ABS16. */ @@ -11476,17 +11900,11 @@ is_16bit_abs_reloc (unsigned int reloc_type) return reloc_type == 2; /* R_OR1K_16. */ case EM_TI_C6000: return reloc_type == 2; /* R_C6000_ABS16. */ + case EM_VISIUM: + return reloc_type == 2; /* R_VISIUM_16. */ case EM_XC16X: case EM_C166: return reloc_type == 2; /* R_XC16C_ABS_16. */ - case EM_CYGNUS_MN10200: - case EM_MN10200: - return reloc_type == 2; /* R_MN10200_16. */ - case EM_CYGNUS_MN10300: - case EM_MN10300: - return reloc_type == 2; /* R_MN10300_16. */ - case EM_VISIUM: - return reloc_type == 2; /* R_VISIUM_16. */ case EM_XGATE: return reloc_type == 3; /* R_XGATE_16. */ default: @@ -11502,41 +11920,53 @@ is_none_reloc (unsigned int reloc_type) { switch (elf_header.e_machine) { - case EM_68K: /* R_68K_NONE. */ case EM_386: /* R_386_NONE. */ - case EM_SPARC32PLUS: - case EM_SPARCV9: - case EM_SPARC: /* R_SPARC_NONE. */ - case EM_MIPS: /* R_MIPS_NONE. */ - case EM_PARISC: /* R_PARISC_NONE. */ - case EM_ALPHA: /* R_ALPHA_NONE. */ + case EM_68K: /* R_68K_NONE. */ case EM_ADAPTEVA_EPIPHANY: - case EM_PPC: /* R_PPC_NONE. */ - case EM_PPC64: /* R_PPC64_NONE. */ + case EM_ALPHA: /* R_ALPHA_NONE. */ + case EM_ALTERA_NIOS2: /* R_NIOS2_NONE. */ + case EM_ARC: /* R_ARC_NONE. */ + case EM_ARC_COMPACT2: /* R_ARC_NONE. */ + case EM_ARC_COMPACT: /* R_ARC_NONE. */ case EM_ARM: /* R_ARM_NONE. */ - case EM_IA_64: /* R_IA64_NONE. */ - case EM_SH: /* R_SH_NONE. */ - case EM_S390_OLD: - case EM_S390: /* R_390_NONE. */ + case EM_C166: /* R_XC16X_NONE. */ case EM_CRIS: /* R_CRIS_NONE. */ - case EM_X86_64: /* R_X86_64_NONE. */ - case EM_L1OM: /* R_X86_64_NONE. */ + case EM_FT32: /* R_FT32_NONE. */ + case EM_IA_64: /* R_IA64_NONE. */ case EM_K1OM: /* R_X86_64_NONE. */ + case EM_L1OM: /* R_X86_64_NONE. */ + case EM_M32R: /* R_M32R_NONE. */ + case EM_MIPS: /* R_MIPS_NONE. */ case EM_MN10300: /* R_MN10300_NONE. */ - case EM_FT32: /* R_FT32_NONE. */ case EM_MOXIE: /* R_MOXIE_NONE. */ - case EM_M32R: /* R_M32R_NONE. */ - case EM_TI_C6000:/* R_C6000_NONE. */ + case EM_NIOS32: /* R_NIOS_NONE. */ + case EM_OR1K: /* R_OR1K_NONE. */ + case EM_PARISC: /* R_PARISC_NONE. */ + case EM_PPC64: /* R_PPC64_NONE. */ + case EM_PPC: /* R_PPC_NONE. */ + case EM_S390: /* R_390_NONE. */ + case EM_S390_OLD: + case EM_SH: /* R_SH_NONE. */ + case EM_SPARC32PLUS: + case EM_SPARC: /* R_SPARC_NONE. */ + case EM_SPARCV9: case EM_TILEGX: /* R_TILEGX_NONE. */ case EM_TILEPRO: /* R_TILEPRO_NONE. */ + case EM_TI_C6000:/* R_C6000_NONE. */ + case EM_X86_64: /* R_X86_64_NONE. */ case EM_XC16X: - case EM_C166: /* R_XC16X_NONE. */ - case EM_ALTERA_NIOS2: /* R_NIOS2_NONE. */ - case EM_NIOS32: /* R_NIOS_NONE. */ - case EM_OR1K: /* R_OR1K_NONE. */ return reloc_type == 0; + case EM_AARCH64: return reloc_type == 0 || reloc_type == 256; + case EM_AVR_OLD: + case EM_AVR: + return (reloc_type == 0 /* R_AVR_NONE. */ + || reloc_type == 30 /* R_AVR_DIFF8. */ + || reloc_type == 31 /* R_AVR_DIFF16. */ + || reloc_type == 32 /* R_AVR_DIFF32. */); + case EM_METAG: + return reloc_type == 3; /* R_METAG_NONE. */ case EM_NDS32: return (reloc_type == 0 /* R_XTENSA_NONE. */ || reloc_type == 204 /* R_NDS32_DIFF8. */ @@ -11549,24 +11979,54 @@ is_none_reloc (unsigned int reloc_type) || reloc_type == 17 /* R_XTENSA_DIFF8. */ || reloc_type == 18 /* R_XTENSA_DIFF16. */ || reloc_type == 19 /* R_XTENSA_DIFF32. */); - case EM_METAG: - return reloc_type == 3; /* R_METAG_NONE. */ } return FALSE; } +/* Returns TRUE if there is a relocation against + section NAME at OFFSET bytes. */ + +bfd_boolean +reloc_at (struct dwarf_section * dsec, dwarf_vma offset) +{ + Elf_Internal_Rela * relocs; + Elf_Internal_Rela * rp; + + if (dsec == NULL || dsec->reloc_info == NULL) + return FALSE; + + relocs = (Elf_Internal_Rela *) dsec->reloc_info; + + for (rp = relocs; rp < relocs + dsec->num_relocs; ++rp) + if (rp->r_offset == offset) + return TRUE; + + return FALSE; +} + /* Apply relocations to a section. Note: So far support has been added only for those relocations which can be found in debug sections. + If RELOCS_RETURN is non-NULL then returns in it a pointer to the + loaded relocs. It is then the caller's responsibility to free them. FIXME: Add support for more relocations ? */ static void -apply_relocations (void * file, - Elf_Internal_Shdr * section, - unsigned char * start) +apply_relocations (void * file, + const Elf_Internal_Shdr * section, + unsigned char * start, + bfd_size_type size, + void ** relocs_return, + unsigned long * num_relocs_return) { Elf_Internal_Shdr * relsec; - unsigned char * end = start + section->sh_size; + unsigned char * end = start + size; + + if (relocs_return != NULL) + { + * (Elf_Internal_Rela **) relocs_return = NULL; + * num_relocs_return = 0; + } if (elf_header.e_type != ET_REL) return; @@ -11612,6 +12072,9 @@ apply_relocations (void * file, is_rela = FALSE; symsec = section_headers + relsec->sh_link; + if (symsec->sh_type != SHT_SYMTAB + && symsec->sh_type != SHT_DYNSYM) + return; symtab = GET_ELF_SYMBOLS ((FILE *) file, symsec, & num_syms); for (rp = relocs; rp < relocs + num_relocs; ++rp) @@ -11680,6 +12143,7 @@ apply_relocations (void * file, referencing a global array. For an example of this see the _clz.o binary in libgcc.a. */ if (sym != symtab + && ELF_ST_TYPE (sym->st_info) != STT_COMMON && ELF_ST_TYPE (sym->st_info) > STT_SECTION) { warn (_("skipping unexpected symbol type %s in %ld'th relocation in section %s\n"), @@ -11719,7 +12183,15 @@ apply_relocations (void * file, } free (symtab); - free (relocs); + + if (relocs_return) + { + * (Elf_Internal_Rela **) relocs_return = relocs; + * num_relocs_return = num_relocs; + } + else + free (relocs); + break; } } @@ -11757,23 +12229,129 @@ get_section_contents (Elf_Internal_Shdr * section, FILE * file) _("section contents")); } +/* Uncompresses a section that was compressed using zlib, in place. */ + +static bfd_boolean +uncompress_section_contents (unsigned char **buffer, + dwarf_size_type uncompressed_size, + dwarf_size_type *size) +{ + dwarf_size_type compressed_size = *size; + unsigned char * compressed_buffer = *buffer; + unsigned char * uncompressed_buffer; + z_stream strm; + int rc; + + /* It is possible the section consists of several compressed + buffers concatenated together, so we uncompress in a loop. */ + /* PR 18313: The state field in the z_stream structure is supposed + to be invisible to the user (ie us), but some compilers will + still complain about it being used without initialisation. So + we first zero the entire z_stream structure and then set the fields + that we need. */ + memset (& strm, 0, sizeof strm); + strm.avail_in = compressed_size; + strm.next_in = (Bytef *) compressed_buffer; + strm.avail_out = uncompressed_size; + uncompressed_buffer = (unsigned char *) xmalloc (uncompressed_size); + + rc = inflateInit (& strm); + while (strm.avail_in > 0) + { + if (rc != Z_OK) + goto fail; + strm.next_out = ((Bytef *) uncompressed_buffer + + (uncompressed_size - strm.avail_out)); + rc = inflate (&strm, Z_FINISH); + if (rc != Z_STREAM_END) + goto fail; + rc = inflateReset (& strm); + } + rc = inflateEnd (& strm); + if (rc != Z_OK + || strm.avail_out != 0) + goto fail; + + *buffer = uncompressed_buffer; + *size = uncompressed_size; + return TRUE; + + fail: + free (uncompressed_buffer); + /* Indicate decompression failure. */ + *buffer = NULL; + return FALSE; +} static void dump_section_as_strings (Elf_Internal_Shdr * section, FILE * file) { - Elf_Internal_Shdr * relsec; - bfd_size_type num_bytes; - char * data; - char * end; - char * start; - bfd_boolean some_strings_shown; - - start = get_section_contents (section, file); + Elf_Internal_Shdr * relsec; + bfd_size_type num_bytes; + unsigned char * data; + unsigned char * end; + unsigned char * real_start; + unsigned char * start; + bfd_boolean some_strings_shown; + + real_start = start = (unsigned char *) get_section_contents (section, + file); if (start == NULL) return; + num_bytes = section->sh_size; printf (_("\nString dump of section '%s':\n"), printable_section_name (section)); + if (decompress_dumps) + { + dwarf_size_type new_size = num_bytes; + dwarf_size_type uncompressed_size = 0; + + if ((section->sh_flags & SHF_COMPRESSED) != 0) + { + Elf_Internal_Chdr chdr; + unsigned int compression_header_size + = get_compression_header (& chdr, (unsigned char *) start); + + if (chdr.ch_type != ELFCOMPRESS_ZLIB) + { + warn (_("section '%s' has unsupported compress type: %d\n"), + printable_section_name (section), chdr.ch_type); + return; + } + else if (chdr.ch_addralign != section->sh_addralign) + { + warn (_("compressed section '%s' is corrupted\n"), + printable_section_name (section)); + return; + } + uncompressed_size = chdr.ch_size; + start += compression_header_size; + new_size -= compression_header_size; + } + else if (new_size > 12 && streq ((char *) start, "ZLIB")) + { + /* Read the zlib header. In this case, it should be "ZLIB" + followed by the uncompressed section size, 8 bytes in + big-endian order. */ + uncompressed_size = start[4]; uncompressed_size <<= 8; + uncompressed_size += start[5]; uncompressed_size <<= 8; + uncompressed_size += start[6]; uncompressed_size <<= 8; + uncompressed_size += start[7]; uncompressed_size <<= 8; + uncompressed_size += start[8]; uncompressed_size <<= 8; + uncompressed_size += start[9]; uncompressed_size <<= 8; + uncompressed_size += start[10]; uncompressed_size <<= 8; + uncompressed_size += start[11]; + start += 12; + new_size -= 12; + } + + if (uncompressed_size + && uncompress_section_contents (& start, + uncompressed_size, & new_size)) + num_bytes = new_size; + } + /* If the section being dumped has relocations against it the user might be expecting these relocations to have been applied. Check for this case and issue a warning message in order to avoid confusion. @@ -11794,7 +12372,6 @@ dump_section_as_strings (Elf_Internal_Shdr * section, FILE * file) break; } - num_bytes = section->sh_size; data = start; end = start + num_bytes; some_strings_shown = FALSE; @@ -11818,9 +12395,9 @@ dump_section_as_strings (Elf_Internal_Shdr * section, FILE * file) #endif if (maxlen > 0) { - print_symbol ((int) maxlen, data); + print_symbol ((int) maxlen, (const char *) data); putchar ('\n'); - data += strnlen (data, maxlen); + data += strnlen ((const char *) data, maxlen); } else { @@ -11834,7 +12411,7 @@ dump_section_as_strings (Elf_Internal_Shdr * section, FILE * file) if (! some_strings_shown) printf (_(" No strings found in this section.")); - free (start); + free (real_start); putchar ('\n'); } @@ -11845,20 +12422,73 @@ dump_section_as_bytes (Elf_Internal_Shdr * section, bfd_boolean relocate) { Elf_Internal_Shdr * relsec; - bfd_size_type bytes; - bfd_vma addr; - unsigned char * data; - unsigned char * start; - - start = (unsigned char *) get_section_contents (section, file); + bfd_size_type bytes; + bfd_size_type section_size; + bfd_vma addr; + unsigned char * data; + unsigned char * real_start; + unsigned char * start; + + real_start = start = (unsigned char *) get_section_contents (section, file); if (start == NULL) return; + section_size = section->sh_size; printf (_("\nHex dump of section '%s':\n"), printable_section_name (section)); + if (decompress_dumps) + { + dwarf_size_type new_size = section_size; + dwarf_size_type uncompressed_size = 0; + + if ((section->sh_flags & SHF_COMPRESSED) != 0) + { + Elf_Internal_Chdr chdr; + unsigned int compression_header_size + = get_compression_header (& chdr, start); + + if (chdr.ch_type != ELFCOMPRESS_ZLIB) + { + warn (_("section '%s' has unsupported compress type: %d\n"), + printable_section_name (section), chdr.ch_type); + return; + } + else if (chdr.ch_addralign != section->sh_addralign) + { + warn (_("compressed section '%s' is corrupted\n"), + printable_section_name (section)); + return; + } + uncompressed_size = chdr.ch_size; + start += compression_header_size; + new_size -= compression_header_size; + } + else if (new_size > 12 && streq ((char *) start, "ZLIB")) + { + /* Read the zlib header. In this case, it should be "ZLIB" + followed by the uncompressed section size, 8 bytes in + big-endian order. */ + uncompressed_size = start[4]; uncompressed_size <<= 8; + uncompressed_size += start[5]; uncompressed_size <<= 8; + uncompressed_size += start[6]; uncompressed_size <<= 8; + uncompressed_size += start[7]; uncompressed_size <<= 8; + uncompressed_size += start[8]; uncompressed_size <<= 8; + uncompressed_size += start[9]; uncompressed_size <<= 8; + uncompressed_size += start[10]; uncompressed_size <<= 8; + uncompressed_size += start[11]; + start += 12; + new_size -= 12; + } + + if (uncompressed_size + && uncompress_section_contents (& start, uncompressed_size, + & new_size)) + section_size = new_size; + } + if (relocate) { - apply_relocations (file, section, start); + apply_relocations (file, section, start, section_size, NULL, NULL); } else { @@ -11884,7 +12514,7 @@ dump_section_as_bytes (Elf_Internal_Shdr * section, } addr = section->sh_addr; - bytes = section->sh_size; + bytes = section_size; data = start; while (bytes) @@ -11924,86 +12554,14 @@ dump_section_as_bytes (Elf_Internal_Shdr * section, bytes -= lbytes; } - free (start); + free (real_start); putchar ('\n'); } -/* Uncompresses a section that was compressed using zlib, in place. */ - -static int -uncompress_section_contents (unsigned char **buffer ATTRIBUTE_UNUSED, - dwarf_size_type *size ATTRIBUTE_UNUSED) -{ -#ifndef HAVE_ZLIB_H - return FALSE; -#else - dwarf_size_type compressed_size = *size; - unsigned char * compressed_buffer = *buffer; - dwarf_size_type uncompressed_size; - unsigned char * uncompressed_buffer; - z_stream strm; - int rc; - dwarf_size_type header_size = 12; - - /* Read the zlib header. In this case, it should be "ZLIB" followed - by the uncompressed section size, 8 bytes in big-endian order. */ - if (compressed_size < header_size - || ! streq ((char *) compressed_buffer, "ZLIB")) - return 0; - - uncompressed_size = compressed_buffer[4]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[5]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[6]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[7]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[8]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[9]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[10]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[11]; - - /* It is possible the section consists of several compressed - buffers concatenated together, so we uncompress in a loop. */ - strm.zalloc = NULL; - strm.zfree = NULL; - strm.opaque = NULL; - strm.avail_in = compressed_size - header_size; - strm.next_in = (Bytef *) compressed_buffer + header_size; - strm.avail_out = uncompressed_size; - uncompressed_buffer = (unsigned char *) xmalloc (uncompressed_size); - - rc = inflateInit (& strm); - while (strm.avail_in > 0) - { - if (rc != Z_OK) - goto fail; - strm.next_out = ((Bytef *) uncompressed_buffer - + (uncompressed_size - strm.avail_out)); - rc = inflate (&strm, Z_FINISH); - if (rc != Z_STREAM_END) - goto fail; - rc = inflateReset (& strm); - } - rc = inflateEnd (& strm); - if (rc != Z_OK - || strm.avail_out != 0) - goto fail; - - free (compressed_buffer); - *buffer = uncompressed_buffer; - *size = uncompressed_size; - return 1; - - fail: - free (uncompressed_buffer); - /* Indicate decompression failure. */ - *buffer = NULL; - return 0; -#endif /* HAVE_ZLIB_H */ -} - static int load_specific_debug_section (enum dwarf_section_display_enum debug, - Elf_Internal_Shdr * sec, void * file) + const Elf_Internal_Shdr * sec, void * file) { struct dwarf_section * section = &debug_displays [debug].section; char buf [64]; @@ -12022,16 +12580,71 @@ load_specific_debug_section (enum dwarf_section_display_enum debug, section->size = 0; else { - section->size = sec->sh_size; - if (uncompress_section_contents (§ion->start, §ion->size)) - sec->sh_size = section->size; - } + unsigned char *start = section->start; + dwarf_size_type size = sec->sh_size; + dwarf_size_type uncompressed_size = 0; - if (section->start == NULL) - return 0; + if ((sec->sh_flags & SHF_COMPRESSED) != 0) + { + Elf_Internal_Chdr chdr; + unsigned int compression_header_size + = get_compression_header (&chdr, start); + if (chdr.ch_type != ELFCOMPRESS_ZLIB) + { + warn (_("section '%s' has unsupported compress type: %d\n"), + section->name, chdr.ch_type); + return 0; + } + else if (chdr.ch_addralign != sec->sh_addralign) + { + warn (_("compressed section '%s' is corrupted\n"), + section->name); + return 0; + } + uncompressed_size = chdr.ch_size; + start += compression_header_size; + size -= compression_header_size; + } + else if (size > 12 && streq ((char *) start, "ZLIB")) + { + /* Read the zlib header. In this case, it should be "ZLIB" + followed by the uncompressed section size, 8 bytes in + big-endian order. */ + uncompressed_size = start[4]; uncompressed_size <<= 8; + uncompressed_size += start[5]; uncompressed_size <<= 8; + uncompressed_size += start[6]; uncompressed_size <<= 8; + uncompressed_size += start[7]; uncompressed_size <<= 8; + uncompressed_size += start[8]; uncompressed_size <<= 8; + uncompressed_size += start[9]; uncompressed_size <<= 8; + uncompressed_size += start[10]; uncompressed_size <<= 8; + uncompressed_size += start[11]; + start += 12; + size -= 12; + } + + if (uncompressed_size + && uncompress_section_contents (&start, uncompressed_size, + &size)) + { + /* Free the compressed buffer, update the section buffer + and the section size if uncompress is successful. */ + free (section->start); + section->start = start; + } + section->size = size; + } + + if (section->start == NULL) + return 0; if (debug_displays [debug].relocate) - apply_relocations ((FILE *) file, sec, section->start); + apply_relocations ((FILE *) file, sec, section->start, section->size, + & section->reloc_info, & section->num_relocs); + else + { + section->reloc_info = NULL; + section->num_relocs = 0; + } return 1; } @@ -12313,16 +12926,18 @@ typedef struct static const char * arm_attr_tag_CPU_arch[] = {"Pre-v4", "v4", "v4T", "v5T", "v5TE", "v5TEJ", "v6", "v6KZ", "v6T2", - "v6K", "v7", "v6-M", "v6S-M", "v7E-M", "v8"}; + "v6K", "v7", "v6-M", "v6S-M", "v7E-M", "v8", "", "v8-M.baseline", + "v8-M.mainline"}; static const char * arm_attr_tag_ARM_ISA_use[] = {"No", "Yes"}; static const char * arm_attr_tag_THUMB_ISA_use[] = - {"No", "Thumb-1", "Thumb-2"}; + {"No", "Thumb-1", "Thumb-2", "Yes"}; static const char * arm_attr_tag_FP_arch[] = {"No", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16", "VFPv4", "VFPv4-D16", "FP for ARMv8", "FPv5/FP-D16 for ARMv8"}; static const char * arm_attr_tag_WMMX_arch[] = {"No", "WMMXv1", "WMMXv2"}; static const char * arm_attr_tag_Advanced_SIMD_arch[] = - {"No", "NEONv1", "NEONv1 with Fused-MAC", "NEON for ARMv8"}; + {"No", "NEONv1", "NEONv1 with Fused-MAC", "NEON for ARMv8", + "NEON for ARMv8.1"}; static const char * arm_attr_tag_PCS_config[] = {"None", "Bare platform", "Linux application", "Linux DSO", "PalmOS 2004", "PalmOS (reserved)", "SymbianOS 2004", "SymbianOS (reserved)"}; @@ -12346,7 +12961,7 @@ static const char * arm_attr_tag_ABI_FP_number_model[] = static const char * arm_attr_tag_ABI_enum_size[] = {"Unused", "small", "int", "forced to int"}; static const char * arm_attr_tag_ABI_HardFP_use[] = - {"As Tag_FP_arch", "SP only", "DP only", "SP and DP"}; + {"As Tag_FP_arch", "SP only", "Reserved", "Deprecated"}; static const char * arm_attr_tag_ABI_VFP_args[] = {"AAPCS", "VFP registers", "custom", "compatible"}; static const char * arm_attr_tag_ABI_WMMX_args[] = @@ -12362,6 +12977,8 @@ static const char * arm_attr_tag_FP_HP_extension[] = {"Not Allowed", "Allowed"}; static const char * arm_attr_tag_ABI_FP_16bit_format[] = {"None", "IEEE 754", "Alternative Format"}; +static const char * arm_attr_tag_DSP_extension[] = + {"Follow architecture", "Allowed"}; static const char * arm_attr_tag_MPextension_use[] = {"Not Allowed", "Allowed"}; static const char * arm_attr_tag_DIV_use[] = @@ -12412,6 +13029,7 @@ static arm_attr_public_tag arm_attr_public_tags[] = LOOKUP(38, ABI_FP_16bit_format), LOOKUP(42, MPextension_use), LOOKUP(44, DIV_use), + LOOKUP(46, DSP_extension), {64, "nodefaults", 0, NULL}, {65, "also_compatible_with", 0, NULL}, LOOKUP(66, T2EE_use), @@ -12720,6 +13338,41 @@ display_power_gnu_attribute (unsigned char * p, return display_tag_value (tag & 1, p, end); } +static unsigned char * +display_s390_gnu_attribute (unsigned char * p, + int tag, + const unsigned char * const end) +{ + unsigned int len; + int val; + + if (tag == Tag_GNU_S390_ABI_Vector) + { + val = read_uleb128 (p, &len, end); + p += len; + printf (" Tag_GNU_S390_ABI_Vector: "); + + switch (val) + { + case 0: + printf (_("any\n")); + break; + case 1: + printf (_("software\n")); + break; + case 2: + printf (_("hardware\n")); + break; + default: + printf ("??? (%d)\n", val); + break; + } + return p; + } + + return display_tag_value (tag & 1, p, end); +} + static void display_sparc_hwcaps (int mask) { @@ -12857,6 +13510,9 @@ print_mips_fp_abi_value (int val) case Val_GNU_MIPS_ABI_FP_64A: printf (_("Hard float compat (32-bit CPU, 64-bit FPU)\n")); break; + case Val_GNU_MIPS_ABI_FP_NAN2008: + printf (_("NaN 2008 compatibility\n")); + break; default: printf ("??? (%d)\n", val); break; @@ -13491,6 +14147,13 @@ process_power_specific (FILE * file) } static int +process_s390_specific (FILE * file) +{ + return process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL, + display_s390_gnu_attribute); +} + +static int process_sparc_specific (FILE * file) { return process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL, @@ -13579,6 +14242,8 @@ print_mips_ases (unsigned int mask) fputs ("\n\tDSP ASE", stdout); if (mask & AFL_ASE_DSPR2) fputs ("\n\tDSP R2 ASE", stdout); + if (mask & AFL_ASE_DSPR3) + fputs ("\n\tDSP R3 ASE", stdout); if (mask & AFL_ASE_EVA) fputs ("\n\tEnhanced VA Scheme", stdout); if (mask & AFL_ASE_MCU) @@ -13838,7 +14503,7 @@ process_mips_specific (FILE * file) { Elf32_Lib liblist; time_t atime; - char timebuf[20]; + char timebuf[128]; struct tm * tmp; liblist.l_name = BYTE_GET (elib[cnt].l_name); @@ -13951,7 +14616,7 @@ process_mips_specific (FILE * file) return 0; } offset += option->size; - + ++option; ++cnt; } @@ -14098,7 +14763,7 @@ process_mips_specific (FILE * file) len = sizeof (* eopt); while (len < option->size) { - char datum = * ((char *) eopt + offset + len); + unsigned char datum = * ((unsigned char *) eopt + offset + len); if (ISPRINT (datum)) printf ("%c", datum); @@ -14492,7 +15157,7 @@ process_gnu_liblist (FILE * file) { Elf32_Lib liblist; time_t atime; - char timebuf[20]; + char timebuf[128]; struct tm * tmp; liblist.l_name = BYTE_GET (elib[cnt].l_name); @@ -14612,6 +15277,10 @@ get_note_type (unsigned e_type) return _("NT_VERSION (version)"); case NT_ARCH: return _("NT_ARCH (architecture)"); + case NT_GNU_BUILD_ATTRIBUTE_OPEN: + return _("OPEN"); + case NT_GNU_BUILD_ATTRIBUTE_FUNC: + return _("func"); default: break; } @@ -14675,7 +15344,7 @@ print_core_note (Elf_Internal_Note *pnote) (int) (4 + 2 * addr_size), _("End"), (int) (4 + 2 * addr_size), _("Page Offset")); filenames = descdata + count * 3 * addr_size; - while (--count > 0) + while (count-- > 0) { bfd_vma start, end, file_ofs; @@ -14709,8 +15378,7 @@ print_core_note (Elf_Internal_Note *pnote) static const char * get_gnu_elf_note_type (unsigned e_type) { - static char buff[64]; - + /* NB/ Keep this switch statement in sync with print_gnu_note (). */ switch (e_type) { case NT_GNU_ABI_TAG: @@ -14721,17 +15389,203 @@ get_gnu_elf_note_type (unsigned e_type) return _("NT_GNU_BUILD_ID (unique build ID bitstring)"); case NT_GNU_GOLD_VERSION: return _("NT_GNU_GOLD_VERSION (gold version)"); + case NT_GNU_PROPERTY_TYPE_0: + return _("NT_GNU_PROPERTY_TYPE_0"); + case NT_GNU_BUILD_ATTRIBUTE_OPEN: + return _("NT_GNU_BUILD_ATTRIBUTE_OPEN"); + case NT_GNU_BUILD_ATTRIBUTE_FUNC: + return _("NT_GNU_BUILD_ATTRIBUTE_FUNC"); default: - break; + { + static char buff[64]; + + snprintf (buff, sizeof (buff), _("Unknown note type: (0x%08x)"), e_type); + return buff; + } } +} - snprintf (buff, sizeof (buff), _("Unknown note type: (0x%08x)"), e_type); - return buff; +static void +decode_x86_isa (unsigned int bitmask) +{ + while (bitmask) + { + unsigned int bit = bitmask & (- bitmask); + + bitmask &= ~ bit; + switch (bit) + { + case GNU_PROPERTY_X86_ISA_1_486: printf ("i486"); break; + case GNU_PROPERTY_X86_ISA_1_586: printf ("586"); break; + case GNU_PROPERTY_X86_ISA_1_686: printf ("686"); break; + case GNU_PROPERTY_X86_ISA_1_SSE: printf ("SSE"); break; + case GNU_PROPERTY_X86_ISA_1_SSE2: printf ("SSE2"); break; + case GNU_PROPERTY_X86_ISA_1_SSE3: printf ("SSE3"); break; + case GNU_PROPERTY_X86_ISA_1_SSSE3: printf ("SSSE3"); break; + case GNU_PROPERTY_X86_ISA_1_SSE4_1: printf ("SSE4_1"); break; + case GNU_PROPERTY_X86_ISA_1_SSE4_2: printf ("SSE4_2"); break; + case GNU_PROPERTY_X86_ISA_1_AVX: printf ("AVX"); break; + case GNU_PROPERTY_X86_ISA_1_AVX2: printf ("AVX2"); break; + case GNU_PROPERTY_X86_ISA_1_AVX512F: printf ("AVX512F"); break; + case GNU_PROPERTY_X86_ISA_1_AVX512CD: printf ("AVX512CD"); break; + case GNU_PROPERTY_X86_ISA_1_AVX512ER: printf ("AVX512ER"); break; + case GNU_PROPERTY_X86_ISA_1_AVX512PF: printf ("AVX512PF"); break; + case GNU_PROPERTY_X86_ISA_1_AVX512VL: printf ("AVX512VL"); break; + case GNU_PROPERTY_X86_ISA_1_AVX512DQ: printf ("AVX512DQ"); break; + case GNU_PROPERTY_X86_ISA_1_AVX512BW: printf ("AVX512BW"); break; + default: printf (_(""), bit); break; + } + if (bitmask) + printf (", "); + } } +static void +decode_compiler_flags_notes (unsigned long bitmask) +{ + printf("%#lx [", bitmask); + + printf("%c%ccxx11, ", bitmask & GNU_PROPERTY_USECXX_VALIDATION ? '=' : '~', + bitmask & GNU_PROPERTY_USECXX11_ABI ? '+' : '!'); + + printf("%c%casan", bitmask & GNU_PROPERTY_SANITIZE_VALIDATION ? '=' : '~', + bitmask & GNU_PROPERTY_SANITIZE_ADDRESS ? '+' : '!'); + + printf("]"); +} + +static void +print_gnu_property_note (Elf_Internal_Note * pnote) +{ + unsigned char * ptr = (unsigned char *) pnote->descdata; + unsigned char * ptr_end = ptr + pnote->descsz; + unsigned int size = is_32bit_elf ? 4 : 8; + + printf (_(" Properties: ")); + + if (pnote->descsz < 8 || (pnote->descsz % size) != 0) + { + printf (_("\n"), pnote->descsz); + return; + } + + while (ptr < ptr_end) + { + unsigned int j; + unsigned int type; + unsigned int datasz; + + if ((size_t) (ptr_end - ptr) < 8) + { + printf (_("\n"), pnote->descsz); + break; + } + + type = byte_get (ptr, 4); + datasz = byte_get (ptr + 4, 4); + + ptr += 8; + + if (datasz > (size_t) (ptr_end - ptr)) + { + printf (_("\n"), + type, datasz); + break; + } + + if (type >= GNU_PROPERTY_LOPROC && type <= GNU_PROPERTY_HIPROC) + { + if (elf_header.e_machine == EM_X86_64 + || elf_header.e_machine == EM_IAMCU + || elf_header.e_machine == EM_386) + { + switch (type) + { + case GNU_PROPERTY_X86_ISA_1_USED: + printf ("x86 ISA used: "); + if (datasz != 4) + printf (_(" "), datasz); + else + decode_x86_isa (byte_get (ptr, 4)); + goto next; + + case GNU_PROPERTY_X86_ISA_1_NEEDED: + printf ("x86 ISA needed: "); + if (datasz != 4) + printf (_(" "), datasz); + else + decode_x86_isa (byte_get (ptr, 4)); + goto next; + + default: + break; + } + } + } + else + { + switch (type) + { + case GNU_PROPERTY_STACK_SIZE: + printf (_("stack size: ")); + if (datasz != size) + printf (_(" "), datasz); + else + printf ("%#lx", (unsigned long) byte_get (ptr, size)); + goto next; + + case GNU_PROPERTY_NO_COPY_ON_PROTECTED: + printf ("no copy on protected "); + if (datasz) + printf (_(" "), datasz); + goto next; + + case GNU_PROPERTY_COMPILER_FLAGS: + printf ("compilations flags: "); + if ((datasz != 4) && (datasz != 8)) + printf (_(" "), datasz); + else + { + unsigned long bitmask_flags; + bitmask_flags = (unsigned long) byte_get (ptr, size); + decode_compiler_flags_notes (bitmask_flags); + } + goto next; + + default: + break; + } + } + + if (type < GNU_PROPERTY_LOPROC) + printf (_(""); + +next: + ptr += ((datasz + (size - 1)) & ~ (size - 1)); + if (ptr == ptr_end) + break; + + if (do_wide) + printf (", "); + else + printf ("\n\t"); + } + + printf ("\n"); +} + + static int print_gnu_note (Elf_Internal_Note *pnote) { + /* NB/ Keep this switch statement in sync with get_gnu_elf_note_type (). */ switch (pnote->type) { case NT_GNU_BUILD_ID: @@ -14779,6 +15633,12 @@ print_gnu_note (Elf_Internal_Note *pnote) case GNU_ABI_TAG_NETBSD: osname = "NetBSD"; break; + case GNU_ABI_TAG_SYLLABLE: + osname = "Syllable"; + break; + case GNU_ABI_TAG_NACL: + osname = "NaCl"; + break; default: osname = "Unknown"; break; @@ -14799,12 +15659,194 @@ print_gnu_note (Elf_Internal_Note *pnote) printf ("\n"); } break; + + case NT_GNU_HWCAP: + { + unsigned long num_entries, mask; + + /* Hardware capabilities information. Word 0 is the number of entries. + Word 1 is a bitmask of enabled entries. The rest of the descriptor + is a series of entries, where each entry is a single byte followed + by a nul terminated string. The byte gives the bit number to test + if enabled in the bitmask. */ + printf (_(" Hardware Capabilities: ")); + if (pnote->descsz < 8) + { + printf (_("\n")); + break; + } + num_entries = byte_get ((unsigned char *) pnote->descdata, 4); + mask = byte_get ((unsigned char *) pnote->descdata + 4, 4); + printf (_("num entries: %ld, enabled mask: %lx\n"), num_entries, mask); + /* FIXME: Add code to display the entries... */ + } + break; + + case NT_GNU_PROPERTY_TYPE_0: + print_gnu_property_note (pnote); + break; + + default: + /* Handle unrecognised types. An error message should have already been + created by get_gnu_elf_note_type(), so all that we need to do is to + display the data. */ + { + unsigned long i; + + printf (_(" Description data: ")); + for (i = 0; i < pnote->descsz; ++i) + printf ("%02x ", pnote->descdata[i] & 0xff); + printf ("\n"); + } + break; + } + + return 1; +} + +static const char * +get_v850_elf_note_type (enum v850_notes n_type) +{ + static char buff[64]; + + switch (n_type) + { + case V850_NOTE_ALIGNMENT: return _("Alignment of 8-byte objects"); + case V850_NOTE_DATA_SIZE: return _("Sizeof double and long double"); + case V850_NOTE_FPU_INFO: return _("Type of FPU support needed"); + case V850_NOTE_SIMD_INFO: return _("Use of SIMD instructions"); + case V850_NOTE_CACHE_INFO: return _("Use of cache"); + case V850_NOTE_MMU_INFO: return _("Use of MMU"); + default: + snprintf (buff, sizeof (buff), _("Unknown note type: (0x%08x)"), n_type); + return buff; + } +} + +static int +print_v850_note (Elf_Internal_Note * pnote) +{ + unsigned int val; + + if (pnote->descsz != 4) + return 0; + val = byte_get ((unsigned char *) pnote->descdata, pnote->descsz); + + if (val == 0) + { + printf (_("not set\n")); + return 1; + } + + switch (pnote->type) + { + case V850_NOTE_ALIGNMENT: + switch (val) + { + case EF_RH850_DATA_ALIGN4: printf (_("4-byte\n")); return 1; + case EF_RH850_DATA_ALIGN8: printf (_("8-byte\n")); return 1; + } + break; + + case V850_NOTE_DATA_SIZE: + switch (val) + { + case EF_RH850_DOUBLE32: printf (_("4-bytes\n")); return 1; + case EF_RH850_DOUBLE64: printf (_("8-bytes\n")); return 1; + } + break; + + case V850_NOTE_FPU_INFO: + switch (val) + { + case EF_RH850_FPU20: printf (_("FPU-2.0\n")); return 1; + case EF_RH850_FPU30: printf (_("FPU-3.0\n")); return 1; + } + break; + + case V850_NOTE_MMU_INFO: + case V850_NOTE_CACHE_INFO: + case V850_NOTE_SIMD_INFO: + if (val == EF_RH850_SIMD) + { + printf (_("yes\n")); + return 1; + } + break; + + default: + /* An 'unknown note type' message will already have been displayed. */ + break; + } + + printf (_("unknown value: %x\n"), val); + return 0; +} + +static int +process_netbsd_elf_note (Elf_Internal_Note * pnote) +{ + unsigned int version; + + switch (pnote->type) + { + case NT_NETBSD_IDENT: + version = byte_get ((unsigned char *) pnote->descdata, sizeof (version)); + if ((version / 10000) % 100) + printf (" NetBSD\t\t0x%08lx\tIDENT %u (%u.%u%s%c)\n", pnote->descsz, + version, version / 100000000, (version / 1000000) % 100, + (version / 10000) % 100 > 26 ? "Z" : "", + 'A' + (version / 10000) % 26); + else + printf (" NetBSD\t\t0x%08lx\tIDENT %u (%u.%u.%u)\n", pnote->descsz, + version, version / 100000000, (version / 1000000) % 100, + (version / 100) % 100); + return 1; + + case NT_NETBSD_MARCH: + printf (" NetBSD\t0x%08lx\tMARCH <%s>\n", pnote->descsz, + pnote->descdata); + return 1; + + default: + break; } + printf (" NetBSD\t0x%08lx\tUnknown note type: (0x%08lx)\n", pnote->descsz, + pnote->type); return 1; } static const char * +get_freebsd_elfcore_note_type (unsigned e_type) +{ + switch (e_type) + { + case NT_FREEBSD_THRMISC: + return _("NT_THRMISC (thrmisc structure)"); + case NT_FREEBSD_PROCSTAT_PROC: + return _("NT_PROCSTAT_PROC (proc data)"); + case NT_FREEBSD_PROCSTAT_FILES: + return _("NT_PROCSTAT_FILES (files data)"); + case NT_FREEBSD_PROCSTAT_VMMAP: + return _("NT_PROCSTAT_VMMAP (vmmap data)"); + case NT_FREEBSD_PROCSTAT_GROUPS: + return _("NT_PROCSTAT_GROUPS (groups data)"); + case NT_FREEBSD_PROCSTAT_UMASK: + return _("NT_PROCSTAT_UMASK (umask data)"); + case NT_FREEBSD_PROCSTAT_RLIMIT: + return _("NT_PROCSTAT_RLIMIT (rlimit data)"); + case NT_FREEBSD_PROCSTAT_OSREL: + return _("NT_PROCSTAT_OSREL (osreldate data)"); + case NT_FREEBSD_PROCSTAT_PSSTRINGS: + return _("NT_PROCSTAT_PSSTRINGS (ps_strings data)"); + case NT_FREEBSD_PROCSTAT_AUXV: + return _("NT_PROCSTAT_AUXV (auxv data)"); + } + return get_note_type (e_type); +} + +static const char * get_netbsd_elfcore_note_type (unsigned e_type) { static char buff[64]; @@ -14918,119 +15960,600 @@ print_stapsdt_note (Elf_Internal_Note *pnote) printf ("\n"); printf (_(" Arguments: %s\n"), arg_fmt); - return data == data_end; -} + return data == data_end; +} + +static const char * +get_ia64_vms_note_type (unsigned e_type) +{ + static char buff[64]; + + switch (e_type) + { + case NT_VMS_MHD: + return _("NT_VMS_MHD (module header)"); + case NT_VMS_LNM: + return _("NT_VMS_LNM (language name)"); + case NT_VMS_SRC: + return _("NT_VMS_SRC (source files)"); + case NT_VMS_TITLE: + return "NT_VMS_TITLE"; + case NT_VMS_EIDC: + return _("NT_VMS_EIDC (consistency check)"); + case NT_VMS_FPMODE: + return _("NT_VMS_FPMODE (FP mode)"); + case NT_VMS_LINKTIME: + return "NT_VMS_LINKTIME"; + case NT_VMS_IMGNAM: + return _("NT_VMS_IMGNAM (image name)"); + case NT_VMS_IMGID: + return _("NT_VMS_IMGID (image id)"); + case NT_VMS_LINKID: + return _("NT_VMS_LINKID (link id)"); + case NT_VMS_IMGBID: + return _("NT_VMS_IMGBID (build id)"); + case NT_VMS_GSTNAM: + return _("NT_VMS_GSTNAM (sym table name)"); + case NT_VMS_ORIG_DYN: + return "NT_VMS_ORIG_DYN"; + case NT_VMS_PATCHTIME: + return "NT_VMS_PATCHTIME"; + default: + snprintf (buff, sizeof (buff), _("Unknown note type: (0x%08x)"), e_type); + return buff; + } +} + +static int +print_ia64_vms_note (Elf_Internal_Note * pnote) +{ + switch (pnote->type) + { + case NT_VMS_MHD: + if (pnote->descsz > 36) + { + size_t l = strlen (pnote->descdata + 34); + printf (_(" Creation date : %.17s\n"), pnote->descdata); + printf (_(" Last patch date: %.17s\n"), pnote->descdata + 17); + printf (_(" Module name : %s\n"), pnote->descdata + 34); + printf (_(" Module version : %s\n"), pnote->descdata + 34 + l + 1); + } + else + printf (_(" Invalid size\n")); + break; + case NT_VMS_LNM: + printf (_(" Language: %s\n"), pnote->descdata); + break; +#ifdef BFD64 + case NT_VMS_FPMODE: + printf (_(" Floating Point mode: ")); + printf ("0x%016" BFD_VMA_FMT "x\n", + (bfd_vma) byte_get ((unsigned char *)pnote->descdata, 8)); + break; + case NT_VMS_LINKTIME: + printf (_(" Link time: ")); + print_vms_time + ((bfd_int64_t) byte_get ((unsigned char *)pnote->descdata, 8)); + printf ("\n"); + break; + case NT_VMS_PATCHTIME: + printf (_(" Patch time: ")); + print_vms_time + ((bfd_int64_t) byte_get ((unsigned char *)pnote->descdata, 8)); + printf ("\n"); + break; + case NT_VMS_ORIG_DYN: + printf (_(" Major id: %u, minor id: %u\n"), + (unsigned) byte_get ((unsigned char *)pnote->descdata, 4), + (unsigned) byte_get ((unsigned char *)pnote->descdata + 4, 4)); + printf (_(" Last modified : ")); + print_vms_time + ((bfd_int64_t) byte_get ((unsigned char *)pnote->descdata + 8, 8)); + printf (_("\n Link flags : ")); + printf ("0x%016" BFD_VMA_FMT "x\n", + (bfd_vma) byte_get ((unsigned char *)pnote->descdata + 16, 8)); + printf (_(" Header flags: 0x%08x\n"), + (unsigned) byte_get ((unsigned char *)pnote->descdata + 24, 4)); + printf (_(" Image id : %s\n"), pnote->descdata + 32); + break; +#endif + case NT_VMS_IMGNAM: + printf (_(" Image name: %s\n"), pnote->descdata); + break; + case NT_VMS_GSTNAM: + printf (_(" Global symbol table name: %s\n"), pnote->descdata); + break; + case NT_VMS_IMGID: + printf (_(" Image id: %s\n"), pnote->descdata); + break; + case NT_VMS_LINKID: + printf (_(" Linker id: %s\n"), pnote->descdata); + break; + default: + break; + } + return 1; +} + +/* Find the symbol associated with a build attribute that is attached + to address OFFSET. If PNAME is non-NULL then store the name of + the symbol (if found) in the provided pointer, Returns NULL if a + symbol could not be found. */ + +static Elf_Internal_Sym * +get_symbol_for_build_attribute (FILE * file, + unsigned long offset, + bfd_boolean is_open_attr, + const char ** pname) +{ + static FILE * saved_file = NULL; + static char * strtab; + static unsigned long strtablen; + static Elf_Internal_Sym * symtab; + static unsigned long nsyms; + Elf_Internal_Sym * saved_sym = NULL; + Elf_Internal_Sym * sym; + + if (saved_file == NULL || file != saved_file) + { + Elf_Internal_Shdr * symsec; + + /* Load the symbol and string sections. */ + for (symsec = section_headers; + symsec < section_headers + elf_header.e_shnum; + symsec ++) + { + if (symsec->sh_type == SHT_SYMTAB) + { + symtab = GET_ELF_SYMBOLS (file, symsec, & nsyms); + + if (symsec->sh_link < elf_header.e_shnum) + { + Elf_Internal_Shdr * strtab_sec = section_headers + symsec->sh_link; + + strtab = (char *) get_data (NULL, file, strtab_sec->sh_offset, + 1, strtab_sec->sh_size, + _("string table")); + strtablen = strtab != NULL ? strtab_sec->sh_size : 0; + } + } + } + saved_file = file; + } + + if (symtab == NULL || strtab == NULL) + return NULL; + + /* Find a symbol whose value matches offset. */ + for (sym = symtab; sym < symtab + nsyms; sym ++) + if (sym->st_value == offset) + { + if (sym->st_name >= strtablen) + /* Huh ? This should not happen. */ + continue; + + if (strtab[sym->st_name] == 0) + continue; + + /* The AArch64 and ARM architectures define mapping symbols + (eg $d, $x, $t) which we want to ignore. */ + if (strtab[sym->st_name] == '$' + && strtab[sym->st_name + 1] != 0 + && strtab[sym->st_name + 2] == 0) + continue; + + if (is_open_attr) + { + /* For OPEN attributes we prefer GLOBAL over LOCAL symbols + and FILE or OBJECT symbols over NOTYPE symbols. We skip + FUNC symbols entirely. */ + switch (ELF_ST_TYPE (sym->st_info)) + { + case STT_OBJECT: + case STT_FILE: + saved_sym = sym; + if (sym->st_size) + { + /* If the symbol has a size associated + with it then we can stop searching. */ + sym = symtab + nsyms; + } + continue; + + case STT_FUNC: + /* Ignore function symbols. */ + continue; + + default: + break; + } + + switch (ELF_ST_BIND (sym->st_info)) + { + case STB_GLOBAL: + if (saved_sym == NULL + || ELF_ST_TYPE (saved_sym->st_info) != STT_OBJECT) + saved_sym = sym; + break; + + case STB_LOCAL: + if (saved_sym == NULL) + saved_sym = sym; + break; + + default: + break; + } + } + else + { + if (ELF_ST_TYPE (sym->st_info) != STT_FUNC) + continue; + + saved_sym = sym; + break; + } + } + + if (saved_sym && pname) + * pname = strtab + saved_sym->st_name; + + return saved_sym; +} + +static bfd_boolean +print_gnu_build_attribute_description (Elf_Internal_Note * pnote, + FILE * file) +{ + static unsigned long global_offset = 0; + static unsigned long global_end = 0; + static unsigned long func_offset = 0; + static unsigned long func_end = 0; + + Elf_Internal_Sym * sym; + const char * name; + unsigned long start; + unsigned long end; + bfd_boolean is_open_attr = pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN; + + switch (pnote->descsz) + { + case 0: + /* A zero-length description means that the range of + the previous note of the same type should be used. */ + if (is_open_attr) + { + if (global_end > global_offset) + printf (_(" Applies to region from %#lx to %#lx\n"), + global_offset, global_end); + else + printf (_(" Applies to region from %#lx\n"), global_offset); + } + else + { + if (func_end > func_offset) + printf (_(" Applies to region from %#lx to %#lx\n"), func_offset, func_end); + else + printf (_(" Applies to region from %#lx\n"), func_offset); + } + return TRUE; + + case 4: + start = byte_get ((unsigned char *) pnote->descdata, 4); + end = 0; + break; + + case 8: + if (is_32bit_elf) + { + /* FIXME: We should check that version 3+ notes are being used here... */ + start = byte_get ((unsigned char *) pnote->descdata, 4); + end = byte_get ((unsigned char *) pnote->descdata + 4, 4); + } + else + { + start = byte_get ((unsigned char *) pnote->descdata, 8); + end = 0; + } + break; + + case 16: + start = byte_get ((unsigned char *) pnote->descdata, 8); + end = byte_get ((unsigned char *) pnote->descdata + 8, 8); + break; + + default: + error (_(" \n"), pnote->descsz); + printf (_(" ")); + return FALSE; + } + + name = NULL; + sym = get_symbol_for_build_attribute (file, start, is_open_attr, & name); + /* As of version 5 of the annobin plugin, filename symbols are biased by 2 + in order to avoid them being confused with the start address of the + first function in the file... */ + if (sym == NULL && is_open_attr) + sym = get_symbol_for_build_attribute (file, start + 2, is_open_attr, + & name); + + if (end == 0 && sym != NULL && sym->st_size > 0) + end = start + sym->st_size; + + if (is_open_attr) + { + /* FIXME: Need to properly allow for section alignment. 16 is just the alignment used on x86_64. */ + if (global_end > 0 && start > BFD_ALIGN (global_end, 16)) + warn (_("Gap in build notes detected from %#lx to %#lx\n"), + global_end + 1, start - 1); + + printf (_(" Applies to region from %#lx"), start); + global_offset = start; + + if (end) + { + printf (_(" to %#lx"), end); + global_end = end; + } + } + else + { + printf (_(" Applies to region from %#lx"), start); + func_offset = start; + + if (end) + { + printf (_(" to %#lx"), end); + func_end = end; + } + } + + if (sym && name) + printf (_(" (%s)"), name); + + printf ("\n"); + return TRUE; +} + +static bfd_boolean +print_gnu_build_attribute_name (Elf_Internal_Note * pnote) +{ + static const char string_expected [2] = { GNU_BUILD_ATTRIBUTE_TYPE_STRING, 0 }; + static const char number_expected [2] = { GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC, 0 }; + static const char bool_expected [3] = { GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE, GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE, 0 }; + char name_type; + char name_attribute; + const char * expected_types; + const char * name = pnote->namedata; + const char * text; + signed int left; + + if (name == NULL || pnote->namesz < 2) + { + error (_("corrupt name field in GNU build attribute note: size = %ld\n"), pnote->namesz); + print_symbol (-20, _(" ")); + return FALSE; + } + + if (do_wide) + left = 28; + else + left = 20; -static const char * -get_ia64_vms_note_type (unsigned e_type) -{ - static char buff[64]; + /* Version 2 of the spec adds a "GA" prefix to the name field. */ + if (name[0] == 'G' && name[1] == 'A') + { + if (pnote->namesz < 4) + { + error (_("corrupt name field in GNU build attribute note: size = %ld\n"), pnote->namesz); + print_symbol (-20, _(" ")); + return FALSE; + } - switch (e_type) + printf ("GA"); + name += 2; + left -= 2; + } + + switch ((name_type = * name)) { - case NT_VMS_MHD: - return _("NT_VMS_MHD (module header)"); - case NT_VMS_LNM: - return _("NT_VMS_LNM (language name)"); - case NT_VMS_SRC: - return _("NT_VMS_SRC (source files)"); - case NT_VMS_TITLE: - return "NT_VMS_TITLE"; - case NT_VMS_EIDC: - return _("NT_VMS_EIDC (consistency check)"); - case NT_VMS_FPMODE: - return _("NT_VMS_FPMODE (FP mode)"); - case NT_VMS_LINKTIME: - return "NT_VMS_LINKTIME"; - case NT_VMS_IMGNAM: - return _("NT_VMS_IMGNAM (image name)"); - case NT_VMS_IMGID: - return _("NT_VMS_IMGID (image id)"); - case NT_VMS_LINKID: - return _("NT_VMS_LINKID (link id)"); - case NT_VMS_IMGBID: - return _("NT_VMS_IMGBID (build id)"); - case NT_VMS_GSTNAM: - return _("NT_VMS_GSTNAM (sym table name)"); - case NT_VMS_ORIG_DYN: - return "NT_VMS_ORIG_DYN"; - case NT_VMS_PATCHTIME: - return "NT_VMS_PATCHTIME"; + case GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC: + case GNU_BUILD_ATTRIBUTE_TYPE_STRING: + case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE: + case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE: + printf ("%c", * name); + left --; + break; default: - snprintf (buff, sizeof (buff), _("Unknown note type: (0x%08x)"), e_type); - return buff; + error (_("unrecognised attribute type in name field: %d\n"), name_type); + print_symbol (-20, _("")); + return FALSE; } -} -static int -print_ia64_vms_note (Elf_Internal_Note * pnote) -{ - switch (pnote->type) + ++ name; + text = NULL; + + switch ((name_attribute = * name)) { - case NT_VMS_MHD: - if (pnote->descsz > 36) - { - size_t l = strlen (pnote->descdata + 34); - printf (_(" Creation date : %.17s\n"), pnote->descdata); - printf (_(" Last patch date: %.17s\n"), pnote->descdata + 17); - printf (_(" Module name : %s\n"), pnote->descdata + 34); - printf (_(" Module version : %s\n"), pnote->descdata + 34 + l + 1); - } - else - printf (_(" Invalid size\n")); + case GNU_BUILD_ATTRIBUTE_VERSION: + text = _(""); + expected_types = string_expected; + ++ name; break; - case NT_VMS_LNM: - printf (_(" Language: %s\n"), pnote->descdata); + case GNU_BUILD_ATTRIBUTE_STACK_PROT: + text = _(""); + expected_types = "!+*"; + ++ name; break; -#ifdef BFD64 - case NT_VMS_FPMODE: - printf (_(" Floating Point mode: ")); - printf ("0x%016" BFD_VMA_FMT "x\n", - (bfd_vma) byte_get ((unsigned char *)pnote->descdata, 8)); + case GNU_BUILD_ATTRIBUTE_RELRO: + text = _(""); + expected_types = bool_expected; + ++ name; break; - case NT_VMS_LINKTIME: - printf (_(" Link time: ")); - print_vms_time - ((bfd_int64_t) byte_get ((unsigned char *)pnote->descdata, 8)); - printf ("\n"); + case GNU_BUILD_ATTRIBUTE_STACK_SIZE: + text = _(""); + expected_types = number_expected; + ++ name; break; - case NT_VMS_PATCHTIME: - printf (_(" Patch time: ")); - print_vms_time - ((bfd_int64_t) byte_get ((unsigned char *)pnote->descdata, 8)); - printf ("\n"); + case GNU_BUILD_ATTRIBUTE_TOOL: + text = _(""); + expected_types = string_expected; + ++ name; break; - case NT_VMS_ORIG_DYN: - printf (_(" Major id: %u, minor id: %u\n"), - (unsigned) byte_get ((unsigned char *)pnote->descdata, 4), - (unsigned) byte_get ((unsigned char *)pnote->descdata + 4, 4)); - printf (_(" Last modified : ")); - print_vms_time - ((bfd_int64_t) byte_get ((unsigned char *)pnote->descdata + 8, 8)); - printf (_("\n Link flags : ")); - printf ("0x%016" BFD_VMA_FMT "x\n", - (bfd_vma) byte_get ((unsigned char *)pnote->descdata + 16, 8)); - printf (_(" Header flags: 0x%08x\n"), - (unsigned) byte_get ((unsigned char *)pnote->descdata + 24, 4)); - printf (_(" Image id : %s\n"), pnote->descdata + 32); + case GNU_BUILD_ATTRIBUTE_ABI: + text = _(""); + expected_types = "$*"; + ++ name; break; -#endif - case NT_VMS_IMGNAM: - printf (_(" Image name: %s\n"), pnote->descdata); + case GNU_BUILD_ATTRIBUTE_PIC: + text = _(""); + expected_types = number_expected; + ++ name; break; - case NT_VMS_GSTNAM: - printf (_(" Global symbol table name: %s\n"), pnote->descdata); + case GNU_BUILD_ATTRIBUTE_SHORT_ENUM: + text = _(""); + expected_types = bool_expected; + ++ name; break; - case NT_VMS_IMGID: - printf (_(" Image id: %s\n"), pnote->descdata); + default: + if (ISPRINT (* name)) + { + int len = strnlen (name, pnote->namesz - (name - pnote->namedata)) + 1; + + if (len > left && ! do_wide) + len = left; + printf ("%.*s:", len, name); + left -= len; + name += len; + } + else + { + static char tmpbuf [128]; + + error (_("unrecognised byte in name field: %d\n"), * name); + sprintf (tmpbuf, _(""), * name); + text = tmpbuf; + name ++; + } + expected_types = "*$!+"; break; - case NT_VMS_LINKID: - printf (_(" Linker id: %s\n"), pnote->descdata); + } + + if (text) + left -= printf ("%s", text); + + if (strchr (expected_types, name_type) == NULL) + warn (_("attribute does not have an expected type (%c)\n"), name_type); + + if ((unsigned long)(name - pnote->namedata) > pnote->namesz) + { + error (_("corrupt name field: namesz: %lu but parsing gets to %ld\n"), + (unsigned long) pnote->namesz, + (long) (name - pnote->namedata)); + return FALSE; + } + + if (left < 1 && ! do_wide) + return TRUE; + + switch (name_type) + { + case GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC: + { + unsigned int bytes; + unsigned long long val = 0; + unsigned int shift = 0; + char * decoded = NULL; + + bytes = pnote->namesz - (name - pnote->namedata); + if (bytes > 0) + /* The -1 is because the name field is always 0 terminated, and we + want to be able to ensure that the shift in the while loop below + will not overflow. */ + -- bytes; + + if (bytes > sizeof (val)) + { + fprintf (stderr, "namesz %lx name %p namedata %p\n", + pnote->namesz, name, pnote->namedata); + error (_("corrupt numeric name field: too many bytes in the value: %x\n"), + bytes); + bytes = sizeof (val); + } + /* We do not bother to warn if bytes == 0 as this can + happen with some early versions of the gcc plugin. */ + + while (bytes --) + { + unsigned long byte = (* name ++) & 0xff; + + val |= byte << shift; + shift += 8; + } + + switch (name_attribute) + { + case GNU_BUILD_ATTRIBUTE_PIC: + switch (val) + { + case 0: decoded = "static"; break; + case 1: decoded = "pic"; break; + case 2: decoded = "PIC"; break; + case 3: decoded = "pie"; break; + case 4: decoded = "PIE"; break; + default: break; + } + break; + case GNU_BUILD_ATTRIBUTE_STACK_PROT: + switch (val) + { + /* Based upon the SPCT_FLAG_xxx enum values in gcc/cfgexpand.c. */ + case 0: decoded = "off"; break; + case 1: decoded = "on"; break; + case 2: decoded = "all"; break; + case 3: decoded = "strong"; break; + case 4: decoded = "explicit"; break; + default: break; + } + break; + default: + break; + } + + if (decoded != NULL) + { + print_symbol (-left, decoded); + left = 0; + } + else if (val == 0) + { + printf ("0x0"); + left -= 3; + } + else + { + if (do_wide) + left -= printf ("0x%llx", val); + else + left -= printf ("0x%-.*llx", left, val); + } + } break; - default: + case GNU_BUILD_ATTRIBUTE_TYPE_STRING: + left -= print_symbol (- left, name); + break; + case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE: + left -= print_symbol (- left, "true"); + break; + case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE: + left -= print_symbol (- left, "false"); break; } - return 1; + + if (do_wide && left > 0) + printf ("%-*s", left, " "); + + return TRUE; } /* Note that by the ELF standard, the name field is already null byte @@ -15038,8 +16561,10 @@ print_ia64_vms_note (Elf_Internal_Note * pnote) I.E. the value of namesz for the name "FSF" is 4. If the value of namesz is zero, there is no name present. */ + static int -process_note (Elf_Internal_Note * pnote) +process_note (Elf_Internal_Note * pnote, + FILE * file) { const char * name = pnote->namesz ? pnote->namedata : "(NONE)"; const char * nt; @@ -15053,10 +16578,18 @@ process_note (Elf_Internal_Note * pnote) /* GNU-specific object file notes. */ nt = get_gnu_elf_note_type (pnote->type); + else if (const_strneq (pnote->namedata, "FreeBSD")) + /* FreeBSD-specific core file notes. */ + nt = get_freebsd_elfcore_note_type (pnote->type); + else if (const_strneq (pnote->namedata, "NetBSD-CORE")) /* NetBSD-specific core file notes. */ nt = get_netbsd_elfcore_note_type (pnote->type); + else if (const_strneq (pnote->namedata, "NetBSD")) + /* NetBSD-specific core file notes. */ + return process_netbsd_elf_note (pnote); + else if (strneq (pnote->namedata, "SPU/", 4)) { /* SPU-specific core file notes. */ @@ -15076,7 +16609,18 @@ process_note (Elf_Internal_Note * pnote) note type strings. */ nt = get_note_type (pnote->type); - printf (" %-20s 0x%08lx\t%s\n", name, pnote->descsz, nt); + printf (" "); + + if (pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN + || pnote->type == NT_GNU_BUILD_ATTRIBUTE_FUNC) + print_gnu_build_attribute_name (pnote); + else + print_symbol (-20, name); + + if (do_wide) + printf (" 0x%08lx\t%s\t", pnote->descsz, nt); + else + printf (" 0x%08lx\t%s\n", pnote->descsz, nt); if (const_strneq (pnote->namedata, "IPF/VMS")) return print_ia64_vms_note (pnote); @@ -15086,39 +16630,94 @@ process_note (Elf_Internal_Note * pnote) return print_stapsdt_note (pnote); else if (const_strneq (pnote->namedata, "CORE")) return print_core_note (pnote); - else - return 1; -} + else if (pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN + || pnote->type == NT_GNU_BUILD_ATTRIBUTE_FUNC) + return print_gnu_build_attribute_description (pnote, file); + + if (pnote->descsz) + { + unsigned long i; + + printf (_(" description data: ")); + for (i = 0; i < pnote->descsz; i++) + printf ("%02x ", pnote->descdata[i]); + } + if (do_wide) + printf ("\n"); + + return 1; +} static int -process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length) +process_notes_at (FILE * file, + Elf_Internal_Shdr * section, + bfd_vma offset, + bfd_vma length, + bfd_vma align) { Elf_External_Note * pnotes; Elf_External_Note * external; - int res = 1; + char * end; + bfd_boolean res = TRUE; if (length <= 0) return 0; - pnotes = (Elf_External_Note *) get_data (NULL, file, offset, 1, length, - _("notes")); + if (section) + { + pnotes = (Elf_External_Note *) get_section_contents (section, file); + if (pnotes) + apply_relocations (file, section, (unsigned char *) pnotes, length, NULL, NULL); + + } + else + { + pnotes = (Elf_External_Note *) get_data (NULL, file, offset, 1, length, + _("notes")); + + /* FIXME: Core notes seem to be produced with + 4-byte alignment even on 64-bit systems. */ + if (elf_header.e_type == ET_CORE) + align = 4; + else + align = is_32bit_elf ? 4 : 4; + } if (pnotes == NULL) return 0; external = pnotes; - printf (_("\nDisplaying notes found at file offset 0x%08lx with length 0x%08lx:\n"), - (unsigned long) offset, (unsigned long) length); + if (section) + printf (_("\nDisplaying notes found in: %s\n"), printable_section_name (section)); + else + printf (_("\nDisplaying notes found at file offset 0x%08lx with length 0x%08lx:\n"), + (unsigned long) offset, (unsigned long) length); + + /* NB: Some note sections may have alignment value of 0 or 1. gABI + specifies that notes should be aligned to 4 bytes in 32-bit + objects and to 8 bytes in 64-bit objects. As a Linux extension, + we also support 4 byte alignment in 64-bit objects. If section + alignment is less than 4, we treate alignment as 4 bytes. */ + if (align < 4) + align = 4; + else if (align != 4 && align != 8) + { + warn (_("Corrupt note: alignment %ld, expecting 4 or 8\n"), + (long) align); + return FALSE; + } + printf (_(" %-20s %10s\tDescription\n"), _("Owner"), _("Data size")); - while ((char *) external < (char *) pnotes + length) + end = (char *) pnotes + length; + while ((char *) external < end) { Elf_Internal_Note inote; size_t min_notesz; - char *next; + char * next; char * temp = NULL; - size_t data_remaining = ((char *) pnotes + length) - (char *) external; + size_t data_remaining = end - (char *) external; if (!is_ia64_vms ()) { @@ -15135,16 +16734,20 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length) inote.namesz = BYTE_GET (external->namesz); inote.namedata = external->name; inote.descsz = BYTE_GET (external->descsz); - inote.descdata = inote.namedata + align_power (inote.namesz, 2); + inote.descdata = ((char *) external + + ELF_NOTE_DESC_OFFSET (inote.namesz, align)); /* PR 17531: file: 3443835e. */ - if (inote.descdata < (char *) pnotes) + if (inote.descdata < (char *) pnotes || inote.descdata > end) { - warn (_("Corrupt note: name size is too big: %lx\n"), inote.namesz); + warn (_("Corrupt note: name size is too big: (got: %lx, expected no more than: %lx)\n"), + inote.namesz, (long)(end - inote.namedata)); inote.descdata = inote.namedata; inote.namesz = 0; } + inote.descpos = offset + (inote.descdata - (char *) pnotes); - next = inote.descdata + align_power (inote.descsz, 2); + next = ((char *) external + + ELF_NOTE_NEXT_OFFSET (inote.namesz, inote.descsz, align)); } else { @@ -15179,8 +16782,8 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length) { warn (_("note with invalid namesz and/or descsz found at offset 0x%lx\n"), (unsigned long) ((char *) external - (char *) pnotes)); - warn (_(" type: 0x%lx, namesize: 0x%08lx, descsize: 0x%08lx\n"), - inote.type, inote.namesz, inote.descsz); + warn (_(" type: 0x%lx, namesize: 0x%08lx, descsize: 0x%08lx, alignment: %u\n"), + inote.type, inote.namesz, inote.descsz, (int) align); break; } @@ -15200,14 +16803,14 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length) break; } - strncpy (temp, inote.namedata, inote.namesz); + memcpy (temp, inote.namedata, inote.namesz); temp[inote.namesz] = 0; /* warn (_("'%s' NOTE name not properly null terminated\n"), temp); */ inote.namedata = temp; } - res &= process_note (& inote); + res &= process_note (& inote, file); if (temp != NULL) { @@ -15236,11 +16839,93 @@ process_corefile_note_segments (FILE * file) i++, segment++) { if (segment->p_type == PT_NOTE) - res &= process_corefile_note_segment (file, - (bfd_vma) segment->p_offset, - (bfd_vma) segment->p_filesz); + res &= process_notes_at (file, NULL, + (bfd_vma) segment->p_offset, + (bfd_vma) segment->p_filesz, + (bfd_vma) segment->p_align); + } + + return res; +} + +static int +process_v850_notes (FILE * file, bfd_vma offset, bfd_vma length) +{ + Elf_External_Note * pnotes; + Elf_External_Note * external; + char * end; + int res = 1; + + if (length <= 0) + return 0; + + pnotes = (Elf_External_Note *) get_data (NULL, file, offset, 1, length, + _("v850 notes")); + if (pnotes == NULL) + return 0; + + external = pnotes; + end = (char*) pnotes + length; + + printf (_("\nDisplaying contents of Renesas V850 notes section at offset 0x%lx with length 0x%lx:\n"), + (unsigned long) offset, (unsigned long) length); + + while ((char *) external + sizeof (Elf_External_Note) < end) + { + Elf_External_Note * next; + Elf_Internal_Note inote; + + inote.type = BYTE_GET (external->type); + inote.namesz = BYTE_GET (external->namesz); + inote.namedata = external->name; + inote.descsz = BYTE_GET (external->descsz); + inote.descdata = inote.namedata + align_power (inote.namesz, 2); + inote.descpos = offset + (inote.descdata - (char *) pnotes); + + if (inote.descdata < (char *) pnotes || inote.descdata >= end) + { + warn (_("Corrupt note: name size is too big: %lx\n"), inote.namesz); + inote.descdata = inote.namedata; + inote.namesz = 0; + } + + next = (Elf_External_Note *) (inote.descdata + align_power (inote.descsz, 2)); + + if ( ((char *) next > end) + || ((char *) next < (char *) pnotes)) + { + warn (_("corrupt descsz found in note at offset 0x%lx\n"), + (unsigned long) ((char *) external - (char *) pnotes)); + warn (_(" type: 0x%lx, namesize: 0x%lx, descsize: 0x%lx\n"), + inote.type, inote.namesz, inote.descsz); + break; + } + + external = next; + + /* Prevent out-of-bounds indexing. */ + if ( inote.namedata + inote.namesz > end + || inote.namedata + inote.namesz < inote.namedata) + { + warn (_("corrupt namesz found in note at offset 0x%lx\n"), + (unsigned long) ((char *) external - (char *) pnotes)); + warn (_(" type: 0x%lx, namesize: 0x%lx, descsize: 0x%lx\n"), + inote.type, inote.namesz, inote.descsz); + break; + } + + printf (" %s: ", get_v850_elf_note_type (inote.type)); + + if (! print_v850_note (& inote)) + { + res = 0; + printf ("\n", + inote.namesz, inote.descsz); + } } + free (pnotes); + return res; } @@ -15255,13 +16940,27 @@ process_note_sections (FILE * file) for (i = 0, section = section_headers; i < elf_header.e_shnum && section != NULL; i++, section++) - if (section->sh_type == SHT_NOTE) - { - res &= process_corefile_note_segment (file, - (bfd_vma) section->sh_offset, - (bfd_vma) section->sh_size); - n++; - } + { + if (section->sh_type == SHT_NOTE) + { + res &= process_notes_at (file, section, + (bfd_vma) section->sh_offset, + (bfd_vma) section->sh_size, + (bfd_vma) section->sh_addralign); + n++; + } + + if (( elf_header.e_machine == EM_V800 + || elf_header.e_machine == EM_V850 + || elf_header.e_machine == EM_CYGNUS_V850) + && section->sh_type == SHT_RENESAS_INFO) + { + res &= process_v850_notes (file, + (bfd_vma) section->sh_offset, + (bfd_vma) section->sh_size); + n++; + } + } if (n == 0) /* Try processing NOTE segments instead. */ @@ -15308,6 +17007,10 @@ process_arch_specific (FILE * file) case EM_PPC: return process_power_specific (file); break; + case EM_S390: + case EM_S390_OLD: + return process_s390_specific (file); + break; case EM_SPARC: case EM_SPARC32PLUS: case EM_SPARCV9: @@ -15931,6 +17634,11 @@ main (int argc, char ** argv) if (optind < (argc - 1)) show_name = 1; + else if (optind >= argc) + { + warn (_("Nothing to do.\n")); + usage (stderr); + } err = 0; while (optind < argc)