X-Git-Url: http://drtracing.org/?a=blobdiff_plain;ds=inline;f=binutils%2Freadelf.c;h=7ff29bc8ba162d14147098dc8b231b7bf053a5ea;hb=25499ac7ee92bca177c9436383ee167d6a220066;hp=6ede2399fc574af9949e80b34438eb443d2fd49e;hpb=75d7d2986cf896fac8f0690db68ebc552e0b0339;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/readelf.c b/binutils/readelf.c index 6ede2399fc..7ff29bc8ba 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -151,6 +151,7 @@ #include "elf/v850.h" #include "elf/vax.h" #include "elf/visium.h" +#include "elf/wasm32.h" #include "elf/x86-64.h" #include "elf/xc16x.h" #include "elf/xgate.h" @@ -809,6 +810,7 @@ guess_is_rela (unsigned int e_machine) case EM_XTENSA_OLD: case EM_MICROBLAZE: case EM_MICROBLAZE_OLD: + case EM_WEBASSEMBLY: return TRUE; case EM_68HC05: @@ -1498,6 +1500,10 @@ dump_relocations (FILE * file, rtype = elf_tilepro_reloc_type (type); break; + case EM_WEBASSEMBLY: + rtype = elf_wasm32_reloc_type (type); + break; + case EM_XGATE: rtype = elf_xgate_reloc_type (type); break; @@ -2502,6 +2508,9 @@ decode_ARC_machine_flags (unsigned e_flags, unsigned e_machine, char buf[]) case E_ARC_OSABI_V3: strcat (buf, ", v3 no-legacy-syscalls ABI"); break; + case E_ARC_OSABI_V4: + strcat (buf, ", v4 ABI"); + break; default: strcat (buf, ", unrecognised ARC OSABI flag"); break; @@ -3819,7 +3828,12 @@ get_segment_type (unsigned long p_type) case PT_GNU_RELRO: return "GNU_RELRO"; default: - if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC)) + if (p_type >= PT_GNU_MBIND_LO && p_type <= PT_GNU_MBIND_HI) + { + sprintf (buff, "GNU_MBIND+%#lx", + p_type - PT_GNU_MBIND_LO); + } + else if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC)) { const char * result; @@ -3886,6 +3900,18 @@ get_segment_type (unsigned long p_type) } } +static const char * +get_arc_section_type_name (unsigned int sh_type) +{ + switch (sh_type) + { + case SHT_ARC_ATTRIBUTES: return "ARC_ATTRIBUTES"; + default: + break; + } + return NULL; +} + static const char * get_mips_section_type_name (unsigned int sh_type) { @@ -4095,6 +4121,11 @@ get_section_type_name (unsigned int sh_type) { switch (elf_header.e_machine) { + case EM_ARC: + case EM_ARC_COMPACT: + case EM_ARC_COMPACT2: + result = get_arc_section_type_name (sh_type); + break; case EM_MIPS: case EM_MIPS_RS3_LE: result = get_mips_section_type_name (sh_type); @@ -4788,9 +4819,19 @@ get_program_headers (FILE * file) if (program_headers != NULL) return TRUE; - phdrs = (Elf_Internal_Phdr *) cmalloc (elf_header.e_phnum, - sizeof (Elf_Internal_Phdr)); + /* Be kind to memory checkers by looking for + e_phnum values which we know must be invalid. */ + if (elf_header.e_phnum + * (is_32bit_elf ? sizeof (Elf32_External_Phdr) : sizeof (Elf64_External_Phdr)) + >= current_file_size) + { + error (_("Too many program headers - %#x - the file is not that big\n"), + elf_header.e_phnum); + return FALSE; + } + phdrs = (Elf_Internal_Phdr *) cmalloc (elf_header.e_phnum, + sizeof (Elf_Internal_Phdr)); if (phdrs == NULL) { error (_("Out of memory reading %u program headers\n"), @@ -5528,7 +5569,9 @@ get_elf_section_flags (bfd_vma sh_flags) /* ARM specific. */ /* 21 */ { STRING_COMMA_LEN ("ENTRYSECT") }, /* 22 */ { STRING_COMMA_LEN ("ARM_PURECODE") }, - /* 23 */ { STRING_COMMA_LEN ("COMDEF") } + /* 23 */ { STRING_COMMA_LEN ("COMDEF") }, + /* GNU specific. */ + /* 24 */ { STRING_COMMA_LEN ("GNU_MBIND") }, }; if (do_section_details) @@ -5561,6 +5604,7 @@ get_elf_section_flags (bfd_vma sh_flags) case SHF_TLS: sindex = 9; break; case SHF_EXCLUDE: sindex = 18; break; case SHF_COMPRESSED: sindex = 20; break; + case SHF_GNU_MBIND: sindex = 24; break; default: sindex = -1; @@ -5654,6 +5698,7 @@ get_elf_section_flags (bfd_vma sh_flags) case SHF_TLS: *p = 'T'; break; case SHF_EXCLUDE: *p = 'E'; break; case SHF_COMPRESSED: *p = 'C'; break; + case SHF_GNU_MBIND: *p = 'D'; break; default: if ((elf_header.e_machine == EM_X86_64 @@ -6182,12 +6227,21 @@ process_section_headers (FILE * file) if (section->sh_info < 1 || section->sh_info >= elf_header.e_shnum) warn (_("[%2u]: Expected link to another section in info field"), i); } - else if (section->sh_type < SHT_LOOS && section->sh_info != 0) + else if (section->sh_type < SHT_LOOS + && (section->sh_flags & SHF_GNU_MBIND) == 0 + && section->sh_info != 0) warn (_("[%2u]: Unexpected value (%u) in info field.\n"), i, section->sh_info); break; } + /* 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)); @@ -8047,9 +8101,9 @@ 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) - /* PR 18879 */ - || (sec->sh_size < 5 && word_offset >= sec->sh_size) + if (/* PR 21343 *//* PR 18879 */ + sec->sh_size < 4 + || word_offset > (sec->sh_size - 4) || ((bfd_signed_vma) word_offset) < 0) return FALSE; @@ -9409,6 +9463,12 @@ process_dynamic_section (FILE * file) processing that. This is overkill, I know, but it should work. */ section.sh_offset = offset_from_vma (file, entry->d_un.d_val, 0); + if ((bfd_size_type) section.sh_offset > current_file_size) + { + /* See PR 21379 for a reproducer. */ + error (_("Invalid DT_SYMTAB entry: %lx"), (long) section.sh_offset); + return FALSE; + } if (archive_file_offset != 0) section.sh_size = archive_file_size - section.sh_offset; @@ -10138,8 +10198,9 @@ process_version_sections (FILE * file) printf (_(" Index: %d Cnt: %d "), ent.vd_ndx, ent.vd_cnt); - /* Check for overflow. */ - if (ent.vd_aux + sizeof (* eaux) > (size_t) (endbuf - vstart)) + /* Check for overflow and underflow. */ + if (ent.vd_aux + sizeof (* eaux) > (size_t) (endbuf - vstart) + || (vstart + ent.vd_aux < vstart)) break; vstart += ent.vd_aux; @@ -12091,6 +12152,8 @@ is_32bit_abs_reloc (unsigned int reloc_type) return reloc_type == 1; /* R_VAX_32. */ case EM_VISIUM: return reloc_type == 3; /* R_VISIUM_32. */ + case EM_WEBASSEMBLY: + return reloc_type == 1; /* R_WASM32_32. */ case EM_X86_64: case EM_L1OM: case EM_K1OM: @@ -12396,6 +12459,7 @@ is_none_reloc (unsigned int reloc_type) case EM_TI_C6000:/* R_C6000_NONE. */ case EM_X86_64: /* R_X86_64_NONE. */ case EM_XC16X: + case EM_WEBASSEMBLY: /* R_WASM32_NONE. */ return reloc_type == 0; case EM_AARCH64: @@ -13447,6 +13511,180 @@ display_tag_value (signed int tag, return p; } +/* ARC ABI attributes section. */ + +static unsigned char * +display_arc_attribute (unsigned char * p, + const unsigned char * const end) +{ + unsigned int tag; + unsigned int len; + unsigned int val; + + tag = read_uleb128 (p, &len, end); + p += len; + + switch (tag) + { + case Tag_ARC_PCS_config: + val = read_uleb128 (p, &len, end); + p += len; + printf (" Tag_ARC_PCS_config: "); + switch (val) + { + case 0: + printf (_("Absent/Non standard\n")); + break; + case 1: + printf (_("Bare metal/mwdt\n")); + break; + case 2: + printf (_("Bare metal/newlib\n")); + break; + case 3: + printf (_("Linux/uclibc\n")); + break; + case 4: + printf (_("Linux/glibc\n")); + break; + default: + printf (_("Unknown\n")); + break; + } + break; + + case Tag_ARC_CPU_base: + val = read_uleb128 (p, &len, end); + p += len; + printf (" Tag_ARC_CPU_base: "); + switch (val) + { + default: + case TAG_CPU_NONE: + printf (_("Absent\n")); + break; + case TAG_CPU_ARC6xx: + printf ("ARC6xx\n"); + break; + case TAG_CPU_ARC7xx: + printf ("ARC7xx\n"); + break; + case TAG_CPU_ARCEM: + printf ("ARCEM\n"); + break; + case TAG_CPU_ARCHS: + printf ("ARCHS\n"); + break; + } + break; + + case Tag_ARC_CPU_variation: + val = read_uleb128 (p, &len, end); + p += len; + printf (" Tag_ARC_CPU_variation: "); + switch (val) + { + default: + if (val > 0 && val < 16) + { + printf ("Core%d\n", val); + break; + } + case 0: + printf (_("Absent\n")); + break; + } + break; + + case Tag_ARC_CPU_name: + printf (" Tag_ARC_CPU_name: "); + p = display_tag_value (-1, p, end); + break; + + case Tag_ARC_ABI_rf16: + val = read_uleb128 (p, &len, end); + p += len; + printf (" Tag_ARC_ABI_rf16: %s\n", val ? _("yes") : _("no")); + break; + + case Tag_ARC_ABI_osver: + val = read_uleb128 (p, &len, end); + p += len; + printf (" Tag_ARC_ABI_osver: v%d\n", val); + break; + + case Tag_ARC_ABI_pic: + case Tag_ARC_ABI_sda: + val = read_uleb128 (p, &len, end); + p += len; + printf (tag == Tag_ARC_ABI_sda ? " Tag_ARC_ABI_sda: " + : " Tag_ARC_ABI_pic: "); + switch (val) + { + case 0: + printf (_("Absent\n")); + break; + case 1: + printf ("MWDT\n"); + break; + case 2: + printf ("GNU\n"); + break; + default: + printf (_("Unknown\n")); + break; + } + break; + + case Tag_ARC_ABI_tls: + val = read_uleb128 (p, &len, end); + p += len; + printf (" Tag_ARC_ABI_tls: %s\n", val ? "r25": "none"); + break; + + case Tag_ARC_ABI_enumsize: + val = read_uleb128 (p, &len, end); + p += len; + printf (" Tag_ARC_ABI_enumsize: %s\n", val ? _("default") : + _("smallest")); + break; + + case Tag_ARC_ABI_exceptions: + val = read_uleb128 (p, &len, end); + p += len; + printf (" Tag_ARC_ABI_exceptions: %s\n", val ? _("OPTFP") + : _("default")); + break; + + case Tag_ARC_ABI_double_size: + val = read_uleb128 (p, &len, end); + p += len; + printf (" Tag_ARC_ABI_double_size: %d\n", val); + break; + + case Tag_ARC_ISA_config: + printf (" Tag_ARC_ISA_config: "); + p = display_tag_value (-1, p, end); + break; + + case Tag_ARC_ISA_apex: + printf (" Tag_ARC_ISA_apex: "); + p = display_tag_value (-1, p, end); + break; + + case Tag_ARC_ISA_mpy_option: + val = read_uleb128 (p, &len, end); + p += len; + printf (" Tag_ARC_ISA_mpy_option: %d\n", val); + break; + + default: + return display_tag_value (tag & 1, p, end); + } + + return p; +} + /* ARM EABI attributes section. */ typedef struct { @@ -14805,6 +15043,8 @@ print_mips_ases (unsigned int mask) fputs ("\n\tMICROMIPS ASE", stdout); if (mask & AFL_ASE_XPA) fputs ("\n\tXPA ASE", stdout); + if (mask & AFL_ASE_MIPS16E2) + fputs ("\n\tMIPS16e2 ASE", stdout); if (mask == 0) fprintf (stdout, "\n\t%s", _("None")); else if ((mask & ~AFL_ASE_MASK) != 0) @@ -14971,8 +15211,93 @@ process_mips_specific (FILE * file) /* We have a lot of special sections. Thanks SGI! */ if (dynamic_section == NULL) - /* No information available. */ - return res; + { + /* No dynamic information available. See if there is static GOT. */ + sect = find_section (".got"); + if (sect != NULL) + { + unsigned char *data_end; + unsigned char *data; + bfd_vma ent, end; + int addr_size; + + pltgot = sect->sh_addr; + + ent = pltgot; + addr_size = (is_32bit_elf ? 4 : 8); + end = pltgot + sect->sh_size; + + data = (unsigned char *) get_data (NULL, file, sect->sh_offset, + end - pltgot, 1, + _("Global Offset Table data")); + /* PR 12855: Null data is handled gracefully throughout. */ + data_end = data + (end - pltgot); + + printf (_("\nStatic GOT:\n")); + printf (_(" Canonical gp value: ")); + print_vma (ent + 0x7ff0, LONG_HEX); + printf ("\n\n"); + + /* In a dynamic binary GOT[0] is reserved for the dynamic + loader to store the lazy resolver pointer, however in + a static binary it may well have been omitted and GOT + reduced to a table of addresses. + PR 21344: Check for the entry being fully available + before fetching it. */ + if (data + && data + ent - pltgot + addr_size <= data_end + && byte_get (data + ent - pltgot, addr_size) == 0) + { + printf (_(" Reserved entries:\n")); + printf (_(" %*s %10s %*s\n"), + addr_size * 2, _("Address"), _("Access"), + addr_size * 2, _("Value")); + ent = print_mips_got_entry (data, pltgot, ent, data_end); + printf ("\n"); + if (ent == (bfd_vma) -1) + goto sgot_print_fail; + + /* Check for the MSB of GOT[1] being set, identifying a + GNU object. This entry will be used by some runtime + loaders, to store the module pointer. Otherwise this + is an ordinary local entry. + PR 21344: Check for the entry being fully available + before fetching it. */ + if (data + && data + ent - pltgot + addr_size <= data_end + && (byte_get (data + ent - pltgot, addr_size) + >> (addr_size * 8 - 1)) != 0) + { + ent = print_mips_got_entry (data, pltgot, ent, data_end); + printf ("\n"); + if (ent == (bfd_vma) -1) + goto sgot_print_fail; + } + printf ("\n"); + } + + if (ent < end) + { + printf (_(" Local entries:\n")); + printf (" %*s %10s %*s\n", + addr_size * 2, _("Address"), _("Access"), + addr_size * 2, _("Value")); + while (ent < end) + { + ent = print_mips_got_entry (data, pltgot, ent, data_end); + printf ("\n"); + if (ent == (bfd_vma) -1) + goto sgot_print_fail; + } + printf ("\n"); + } + + sgot_print_fail: + if (data) + free (data); + } + return res; + } for (entry = dynamic_section; /* PR 17531 file: 012-50589-0.004. */ @@ -15340,6 +15665,15 @@ process_mips_specific (FILE * file) return FALSE; } + /* PR 21345 - print a slightly more helpful error message + if we are sure that the cmalloc will fail. */ + if (conflictsno * sizeof (* iconf) > current_file_size) + { + error (_("Overlarge number of conflicts detected: %lx\n"), + (long) conflictsno); + return FALSE; + } + iconf = (Elf32_Conflict *) cmalloc (conflictsno, sizeof (* iconf)); if (iconf == NULL) { @@ -15438,8 +15772,7 @@ process_mips_specific (FILE * file) data = (unsigned char *) get_data (NULL, file, offset, global_end - pltgot, 1, _("Global Offset Table data")); - if (data == NULL) - return FALSE; + /* PR 12855: Null data is handled gracefully throughout. */ data_end = data + (global_end - pltgot); printf (_("\nPrimary GOT:\n")); @@ -15455,7 +15788,14 @@ process_mips_specific (FILE * file) printf (_(" Lazy resolver\n")); if (ent == (bfd_vma) -1) goto got_print_fail; + + /* Check for the MSB of GOT[1] being set, denoting a GNU object. + This entry will be used by some runtime loaders, to store the + module pointer. Otherwise this is an ordinary local entry. + PR 21344: Check for the entry being fully available before + fetching it. */ if (data + && data + ent - pltgot + addr_size <= data_end && (byte_get (data + ent - pltgot, addr_size) >> (addr_size * 8 - 1)) != 0) { @@ -16615,10 +16955,11 @@ print_symbol_for_build_attribute (FILE * file, static unsigned long strtablen; static Elf_Internal_Sym * symtab; static unsigned long nsyms; - Elf_Internal_Sym * saved_sym = NULL; - Elf_Internal_Sym * sym; + Elf_Internal_Sym * saved_sym = NULL; + Elf_Internal_Sym * sym; - if (saved_file == NULL || file != saved_file) + if (section_headers != NULL + && (saved_file == NULL || file != saved_file)) { Elf_Internal_Shdr * symsec; @@ -16768,9 +17109,12 @@ print_gnu_build_attribute_description (Elf_Internal_Note * pnote, 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; - char * expected_types; + const char * expected_types; const char * name = pnote->namedata; const char * text; int left; @@ -16778,7 +17122,7 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote) if (name == NULL || pnote->namesz < 2) { error (_("corrupt name field in GNU build attribute note: size = %ld\n"), pnote->namesz); - print_symbol (-20, _(" ")); + print_symbol (-20, _(" ")); return FALSE; } @@ -16804,7 +17148,7 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote) { case GNU_BUILD_ATTRIBUTE_VERSION: text = _(""); - expected_types = "$"; + expected_types = string_expected; ++ name; break; case GNU_BUILD_ATTRIBUTE_STACK_PROT: @@ -16814,17 +17158,17 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote) break; case GNU_BUILD_ATTRIBUTE_RELRO: text = _(""); - expected_types = "!+"; + expected_types = bool_expected; ++ name; break; case GNU_BUILD_ATTRIBUTE_STACK_SIZE: text = _(""); - expected_types = "*"; + expected_types = number_expected; ++ name; break; case GNU_BUILD_ATTRIBUTE_TOOL: text = _(""); - expected_types = "$"; + expected_types = string_expected; ++ name; break; case GNU_BUILD_ATTRIBUTE_ABI: @@ -16834,15 +17178,14 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote) break; case GNU_BUILD_ATTRIBUTE_PIC: text = _(""); - expected_types = "*"; + expected_types = number_expected; ++ name; break; case GNU_BUILD_ATTRIBUTE_SHORT_ENUM: text = _(""); - expected_types = "!+"; + expected_types = bool_expected; ++ name; break; - default: if (ISPRINT (* name)) { @@ -16856,9 +17199,11 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote) } else { - error (_("unexpected character in name field\n")); - print_symbol (- left, _("")); - return 0; + static char tmpbuf [128]; + error (_("unrecognised byte in name field: %d\n"), * name); + sprintf (tmpbuf, _(""), * name); + text = tmpbuf; + name ++; } expected_types = "*$!+"; break; @@ -16888,10 +17233,28 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote) { case GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC: { - unsigned int bytes = pnote->namesz - (name - pnote->namedata); - unsigned long val = 0; - unsigned int shift = 0; - char * decoded = NULL; + 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 --) { @@ -16931,13 +17294,21 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote) } if (decoded != NULL) - print_symbol (-left, decoded); + { + print_symbol (-left, decoded); + left = 0; + } + else if (val == 0) + { + printf ("0x0"); + left -= 3; + } else { if (do_wide) - left -= printf ("0x%lx", val); + left -= printf ("0x%llx", val); else - left -= printf ("0x%-.*lx", left, val); + left -= printf ("0x%-.*llx", left, val); } } break; @@ -17398,6 +17769,12 @@ process_arch_specific (FILE * file) switch (elf_header.e_machine) { + case EM_ARC: + case EM_ARC_COMPACT: + case EM_ARC_COMPACT2: + return process_attributes (file, "ARC", SHT_ARC_ATTRIBUTES, + display_arc_attribute, + display_generic_attribute); case EM_ARM: return process_attributes (file, "aeabi", SHT_ARM_ATTRIBUTES, display_arm_attribute, @@ -17408,7 +17785,7 @@ process_arch_specific (FILE * file) return process_mips_specific (file); case EM_MSP430: - return process_attributes (file, "mspabi", SHT_MSP430_ATTRIBUTES, + return process_attributes (file, "mspabi", SHT_MSP430_ATTRIBUTES, display_msp430x_attribute, display_generic_attribute);