X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=binutils%2Freadelf.c;h=a6d563fbf5e2924ea35a8c1486da9e0600936311;hb=8066deb11b8e23de5c75e3e2526524bdef0f5a41;hp=7c0c3ff60d790d3eb809ee3d48934db6da9333e0;hpb=df97ab2af780b9588a7158c61b6fdd25577b1c68;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/readelf.c b/binutils/readelf.c index 7c0c3ff60d..a6d563fbf5 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -165,12 +165,12 @@ #endif char * program_name = "readelf"; -static long archive_file_offset; +static unsigned long archive_file_offset; static unsigned long archive_file_size; static bfd_size_type current_file_size; static unsigned long dynamic_addr; static bfd_size_type dynamic_size; -static unsigned int dynamic_nent; +static size_t dynamic_nent; static char * dynamic_strings; static unsigned long dynamic_strings_length; static char * string_table; @@ -272,6 +272,20 @@ typedef enum print_mode } print_mode; +/* Versioned symbol info. */ +enum versioned_symbol_info +{ + symbol_undefined, + symbol_hidden, + symbol_public +}; + +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); + #define UNKNOWN -1 #define SECTION_NAME(X) \ @@ -299,21 +313,35 @@ print_mode; } \ while (0) -/* Retrieve NMEMB structures, each SIZE bytes long from FILE starting at OFFSET. +/* Retrieve NMEMB structures, each SIZE bytes long from FILE starting at OFFSET + + the offset of the current archive member, if we are examining an archive. Put the retrieved data into VAR, if it is not NULL. Otherwise allocate a buffer using malloc and fill that. In either case return the pointer to the start of the retrieved data or NULL if something went wrong. If something does go wrong - emit an error message using REASON as part of the context. */ + and REASON is not NULL then emit an error message using REASON as part of the + context. */ static void * -get_data (void * var, FILE * file, long offset, size_t size, size_t nmemb, +get_data (void * var, FILE * file, unsigned long offset, size_t size, size_t nmemb, const char * reason) { void * mvar; + size_t amt = size * nmemb; if (size == 0 || nmemb == 0) return NULL; + /* Be kind to memory chekers (eg valgrind, address sanitizer) by not + attempting to allocate memory when the read is bound to fail. */ + if (amt > current_file_size + || offset + archive_file_offset + amt > current_file_size) + { + if (reason) + error (_("Reading 0x%lx bytes extends past end of file for %s\n"), + (unsigned long) amt, reason); + return NULL; + } + if (fseek (file, archive_file_offset + offset, SEEK_SET)) { if (reason) @@ -338,14 +366,14 @@ get_data (void * var, FILE * file, long offset, size_t size, size_t nmemb, return NULL; } - ((char *) mvar)[size * nmemb] = '\0'; + ((char *) mvar)[amt] = '\0'; } if (fread (mvar, size, nmemb, file) != nmemb) { if (reason) error (_("Unable to read in 0x%lx bytes of %s\n"), - (unsigned long)(size * nmemb), reason); + (unsigned long) amt, reason); if (mvar != var) free (mvar); return NULL; @@ -422,6 +450,7 @@ print_symbol (int width, const char *symbol) width = - width; extra_padding = TRUE; } + assert (width != 0); if (do_wide) /* Set the remaining width to a very large value. @@ -494,6 +523,66 @@ print_symbol (int width, const char *symbol) return num_printed; } +/* 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) +{ +#define MAX_PRINT_SEC_NAME_LEN 128 + static char sec_name_buf [MAX_PRINT_SEC_NAME_LEN + 1]; + const char * name = SECTION_NAME (sec); + char * buf = sec_name_buf; + char c; + unsigned int remaining = MAX_PRINT_SEC_NAME_LEN; + + while ((c = * name ++) != 0) + { + if (ISCNTRL (c)) + { + if (remaining < 2) + break; + + * buf ++ = '^'; + * buf ++ = c + 0x40; + remaining -= 2; + } + else if (ISPRINT (c)) + { + * buf ++ = c; + remaining -= 1; + } + else + { + static char hex[17] = "0123456789ABCDEF"; + + if (remaining < 4) + break; + * buf ++ = '<'; + * buf ++ = hex[(c & 0xf0) >> 4]; + * buf ++ = hex[c & 0x0f]; + * buf ++ = '>'; + remaining -= 4; + } + + if (remaining == 0) + break; + } + + * buf = 0; + return sec_name_buf; +} + +static const char * +printable_section_name_from_index (unsigned long ndx) +{ + if (ndx >= elf_header.e_shnum) + return _(""); + + return printable_section_name (section_headers + ndx); +} + /* Return a pointer to section NAME, or NULL if no such section exists. */ static Elf_Internal_Shdr * @@ -526,6 +615,21 @@ find_section_by_address (bfd_vma addr) return NULL; } +static Elf_Internal_Shdr * +find_section_by_type (unsigned int type) +{ + unsigned int i; + + for (i = 0; i < elf_header.e_shnum; i++) + { + Elf_Internal_Shdr *sec = section_headers + i; + if (sec->sh_type == type) + return sec; + } + + return NULL; +} + /* Return a pointer to section NAME, or NULL if no such section exists, restricted to the list of sections given in SET. */ @@ -691,7 +795,7 @@ slurp_rela_relocs (FILE * file, unsigned long * nrelasp) { Elf_Internal_Rela * relas; - unsigned long nrelas; + size_t nrelas; unsigned int i; if (is_32bit_elf) @@ -789,7 +893,7 @@ slurp_rel_relocs (FILE * file, unsigned long * nrelsp) { Elf_Internal_Rela * rels; - unsigned long nrels; + size_t nrels; unsigned int i; if (is_32bit_elf) @@ -929,7 +1033,8 @@ dump_relocations (FILE * file, unsigned long nsyms, char * strtab, unsigned long strtablen, - int is_rela) + int is_rela, + int is_dynsym) { unsigned int i; Elf_Internal_Rela * rels; @@ -1362,9 +1467,20 @@ dump_relocations (FILE * file, else { Elf_Internal_Sym * psym; + const char * version_string; + enum versioned_symbol_info sym_info; + unsigned short vna_other; psym = symtab + symtab_index; + version_string + = get_symbol_version_string (file, is_dynsym, + strtab, strtablen, + symtab_index, + psym, + &sym_info, + &vna_other); + printf (" "); if (ELF_ST_TYPE (psym->st_info) == STT_GNU_IFUNC) @@ -1391,6 +1507,9 @@ dump_relocations (FILE * file, name = strtab + psym->st_name; len = print_symbol (width, name); + if (version_string) + printf (sym_info == symbol_public ? "@@%s" : "@%s", + version_string); printf ("()%-*s", len <= width ? (width + 1) - len : 1, " "); } else @@ -1408,8 +1527,7 @@ dump_relocations (FILE * file, if (ELF_ST_TYPE (psym->st_info) == STT_SECTION) { if (psym->st_shndx < elf_header.e_shnum) - sec_name - = SECTION_NAME (section_headers + psym->st_shndx); + sec_name = SECTION_NAME (section_headers + psym->st_shndx); else if (psym->st_shndx == SHN_ABS) sec_name = "ABS"; else if (psym->st_shndx == SHN_COMMON) @@ -1448,7 +1566,12 @@ dump_relocations (FILE * file, else if (psym->st_name >= strtablen) printf (_(""), psym->st_name); else - print_symbol (22, strtab + psym->st_name); + { + print_symbol (22, strtab + psym->st_name); + if (version_string) + printf (sym_info == symbol_public ? "@@%s" : "@%s", + version_string); + } if (is_rela) { @@ -4208,7 +4331,8 @@ get_program_headers (FILE * file) if (phdrs == NULL) { - error (_("Out of memory\n")); + error (_("Out of memory reading %u program headers\n"), + elf_header.e_phnum); return 0; } @@ -4462,7 +4586,7 @@ process_program_headers (FILE * file) { if (!ELF_TBSS_SPECIAL (section, segment) && ELF_SECTION_IN_SEGMENT_STRICT (section, segment)) - printf ("%s ", SECTION_NAME (section)); + printf ("%s ", printable_section_name (section)); } putc ('\n',stdout); @@ -4542,7 +4666,7 @@ get_32bit_section_headers (FILE * file, bfd_boolean probe) if (section_headers == NULL) { if (!probe) - error (_("Out of memory\n")); + error (_("Out of memory reading %u section headers\n"), num); return FALSE; } @@ -4600,7 +4724,7 @@ get_64bit_section_headers (FILE * file, bfd_boolean probe) if (section_headers == NULL) { if (! probe) - error (_("Out of memory\n")); + error (_("Out of memory reading %u section headers\n"), num); return FALSE; } @@ -4636,17 +4760,25 @@ get_32bit_elf_symbols (FILE * file, Elf_Internal_Sym * psym; unsigned int j; + if (section->sh_size == 0) + { + if (num_syms_return != NULL) + * num_syms_return = 0; + return NULL; + } + /* Run some sanity checks first. */ - if (section->sh_entsize == 0) + if (section->sh_entsize == 0 || section->sh_entsize > section->sh_size) { - error (_("sh_entsize is zero\n")); + error (_("Section %s has an invalid sh_entsize of 0x%lx\n"), + printable_section_name (section), (unsigned long) section->sh_entsize); goto exit_point; } if (section->sh_size > current_file_size) { error (_("Section %s has an invalid sh_size of 0x%lx\n"), - SECTION_NAME (section), (unsigned long) section->sh_size); + printable_section_name (section), (unsigned long) section->sh_size); goto exit_point; } @@ -4654,7 +4786,10 @@ get_32bit_elf_symbols (FILE * file, if (number * sizeof (Elf32_External_Sym) > section->sh_size + 1) { - error (_("Invalid sh_entsize\n")); + error (_("Size (0x%lx) of section %s is not a multiple of its sh_entsize (0x%lx)\n"), + (unsigned long) section->sh_size, + printable_section_name (section), + (unsigned long) section->sh_entsize); goto exit_point; } @@ -4674,13 +4809,23 @@ get_32bit_elf_symbols (FILE * file, _("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) + { + 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; + } } isyms = (Elf_Internal_Sym *) cmalloc (number, sizeof (Elf_Internal_Sym)); if (isyms == NULL) { - error (_("Out of memory\n")); + error (_("Out of memory reading %lu symbols\n"), + (unsigned long) number); goto exit_point; } @@ -4723,17 +4868,27 @@ get_64bit_elf_symbols (FILE * file, Elf_Internal_Sym * psym; unsigned int j; + if (section->sh_size == 0) + { + if (num_syms_return != NULL) + * num_syms_return = 0; + return NULL; + } + /* Run some sanity checks first. */ - if (section->sh_entsize == 0) + if (section->sh_entsize == 0 || section->sh_entsize > section->sh_size) { - error (_("sh_entsize is zero\n")); + error (_("Section %s has an invalid sh_entsize of 0x%lx\n"), + printable_section_name (section), + (unsigned long) section->sh_entsize); goto exit_point; } if (section->sh_size > current_file_size) { error (_("Section %s has an invalid sh_size of 0x%lx\n"), - SECTION_NAME (section), (unsigned long) section->sh_size); + printable_section_name (section), + (unsigned long) section->sh_size); goto exit_point; } @@ -4741,7 +4896,10 @@ get_64bit_elf_symbols (FILE * file, if (number * sizeof (Elf64_External_Sym) > section->sh_size + 1) { - error (_("Invalid sh_entsize\n")); + error (_("Size (0x%lx) of section %s is not a multiple of its sh_entsize (0x%lx)\n"), + (unsigned long) section->sh_size, + printable_section_name (section), + (unsigned long) section->sh_entsize); goto exit_point; } @@ -4760,13 +4918,22 @@ get_64bit_elf_symbols (FILE * file, _("symbol table section indicies")); if (shndx == NULL) goto exit_point; + else if (symtab_shndx_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 (symtab_shndx_hdr), + (unsigned long) symtab_shndx_hdr->sh_size, + (unsigned long) section->sh_size); + goto exit_point; + } } isyms = (Elf_Internal_Sym *) cmalloc (number, sizeof (Elf_Internal_Sym)); if (isyms == NULL) { - error (_("Out of memory\n")); + error (_("Out of memory reading %lu symbols\n"), + (unsigned long) number); goto exit_point; } @@ -5259,7 +5426,6 @@ process_section_headers (FILE * file) ) request_dump_bynumber (i, DEBUG_DUMP); } - } if (! do_sections) @@ -5316,14 +5482,9 @@ process_section_headers (FILE * file) { printf (" [%2u] ", i); if (do_section_details) - { - print_symbol (INT_MAX, SECTION_NAME (section)); - printf ("\n "); - } + printf ("%s\n ", printable_section_name (section)); else - { - print_symbol (-17, SECTION_NAME (section)); - } + print_symbol (-17, SECTION_NAME (section)); printf (do_wide ? " %-15s " : " %-15.15s ", get_section_type_name (section->sh_type)); @@ -5556,7 +5717,8 @@ process_section_groups (FILE * file) if (section_headers_groups == NULL) { - error (_("Out of memory\n")); + error (_("Out of memory reading %u section group headers\n"), + elf_header.e_shnum); return 0; } @@ -5580,7 +5742,8 @@ process_section_groups (FILE * file) if (section_groups == NULL) { - error (_("Out of memory\n")); + error (_("Out of memory reading %lu groups\n"), + (unsigned long) group_count); return 0; } @@ -5596,8 +5759,8 @@ process_section_groups (FILE * file) { if (section->sh_type == SHT_GROUP) { - char * name = SECTION_NAME (section); - char * group_name; + const char * name = printable_section_name (section); + const char * group_name; unsigned char * start; unsigned char * indices; unsigned int entry, j, size; @@ -5668,15 +5831,26 @@ process_section_groups (FILE * file) strtab_sec = sec; if (strtab) free (strtab); + strtab = (char *) get_data (NULL, file, strtab_sec->sh_offset, - 1, strtab_sec->sh_size, - _("string table")); + 1, strtab_sec->sh_size, + _("string table")); strtab_size = strtab != NULL ? strtab_sec->sh_size : 0; } group_name = sym->st_name < strtab_size ? strtab + sym->st_name : _(""); } + /* PR 17531: file: loop. */ + if (section->sh_entsize > section->sh_size) + { + error (_("Section %s has sh_entsize (0x%lx) which is larger than its size (0x%lx)\n"), + printable_section_name (section), + (unsigned long) section->sh_entsize, + (unsigned long) section->sh_size); + break; + } + start = (unsigned char *) get_data (NULL, file, section->sh_offset, 1, section->sh_size, _("section data")); @@ -5741,7 +5915,7 @@ process_section_groups (FILE * file) if (do_section_groups) { sec = section_headers + entry; - printf (" [%5u] %s\n", entry, SECTION_NAME (sec)); + printf (" [%5u] %s\n", entry, printable_section_name (sec)); } g = (struct group_list *) xmalloc (sizeof (struct group_list)); @@ -6012,7 +6186,8 @@ process_relocs (FILE * file) offset_from_vma (file, rel_offset, rel_size), rel_size, dynamic_symbols, num_dynamic_syms, - dynamic_strings, dynamic_strings_length, is_rela); + dynamic_strings, dynamic_strings_length, + is_rela, 1); } } @@ -6049,7 +6224,7 @@ process_relocs (FILE * file) if (string_table == NULL) printf ("%d", section->sh_name); else - printf ("'%s'", SECTION_NAME (section)); + printf ("'%s'", printable_section_name (section)); printf (_(" at offset 0x%lx contains %lu entries:\n"), rel_offset, (unsigned long) (rel_size / section->sh_entsize)); @@ -6081,20 +6256,22 @@ process_relocs (FILE * file) strsec = section_headers + symsec->sh_link; strtab = (char *) get_data (NULL, file, strsec->sh_offset, - 1, strsec->sh_size, - _("string table")); + 1, strsec->sh_size, + _("string table")); strtablen = strtab == NULL ? 0 : strsec->sh_size; } dump_relocations (file, rel_offset, rel_size, - symtab, nsyms, strtab, strtablen, is_rela); + symtab, nsyms, strtab, strtablen, + is_rela, + symsec->sh_type == SHT_DYNSYM); if (strtab) free (strtab); free (symtab); } else dump_relocations (file, rel_offset, rel_size, - NULL, 0, NULL, 0, is_rela); + NULL, 0, NULL, 0, is_rela, 0); found = 1; } @@ -6387,7 +6564,11 @@ ia64_process_unwind (FILE * file) aux.symtab = GET_ELF_SYMBOLS (file, sec, & aux.nsyms); strsec = section_headers + sec->sh_link; - assert (aux.strtab == NULL); + if (aux.strtab != NULL) + { + error (_("Multiple auxillary string tables encountered\n")); + free (aux.strtab); + } aux.strtab = (char *) get_data (NULL, file, strsec->sh_offset, 1, strsec->sh_size, _("string table")); @@ -6405,13 +6586,16 @@ ia64_process_unwind (FILE * file) char * suffix; size_t len, len2; - for (i = unwstart, sec = section_headers + unwstart; + for (i = unwstart, sec = section_headers + unwstart, unwsec = NULL; i < elf_header.e_shnum; ++i, ++sec) if (sec->sh_type == SHT_IA_64_UNWIND) { unwsec = sec; break; } + /* We have already counted the number of SHT_IA64_UNWIND + sections so the loop above should never fail. */ + assert (unwsec != NULL); unwstart = i + 1; len = sizeof (ELF_STRING_ia64_unwind_once) - 1; @@ -6419,18 +6603,26 @@ ia64_process_unwind (FILE * file) if ((unwsec->sh_flags & SHF_GROUP) != 0) { /* We need to find which section group it is in. */ - struct group_list * g = section_headers_groups [i]->root; + struct group_list * g; - for (; g != NULL; g = g->next) + if (section_headers_groups == NULL + || section_headers_groups [i] == NULL) + i = elf_header.e_shnum; + else { - sec = section_headers + g->section_index; + g = section_headers_groups [i]->root; - if (streq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info)) - break; - } + for (; g != NULL; g = g->next) + { + sec = section_headers + g->section_index; - if (g == NULL) - i = elf_header.e_shnum; + if (streq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info)) + break; + } + + if (g == NULL) + i = elf_header.e_shnum; + } } else if (strneq (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind_once, len)) { @@ -6466,14 +6658,14 @@ ia64_process_unwind (FILE * file) if (string_table == NULL) printf ("%d", unwsec->sh_name); else - printf (_("'%s'"), SECTION_NAME (unwsec)); + printf ("'%s'", printable_section_name (unwsec)); } else { aux.info_addr = sec->sh_addr; aux.info = (unsigned char *) get_data (NULL, file, sec->sh_offset, 1, - sec->sh_size, - _("unwind info")); + sec->sh_size, + _("unwind info")); aux.info_size = aux.info == NULL ? 0 : sec->sh_size; printf (_("\nUnwind section ")); @@ -6481,7 +6673,7 @@ ia64_process_unwind (FILE * file) if (string_table == NULL) printf ("%d", unwsec->sh_name); else - printf (_("'%s'"), SECTION_NAME (unwsec)); + printf ("'%s'", printable_section_name (unwsec)); printf (_(" at offset 0x%lx contains %lu entries:\n"), (unsigned long) unwsec->sh_offset, @@ -6798,7 +6990,11 @@ hppa_process_unwind (FILE * file) aux.symtab = GET_ELF_SYMBOLS (file, sec, & aux.nsyms); strsec = section_headers + sec->sh_link; - assert (aux.strtab == NULL); + if (aux.strtab != NULL) + { + error (_("Multiple auxillary string tables encountered\n")); + free (aux.strtab); + } aux.strtab = (char *) get_data (NULL, file, strsec->sh_offset, 1, strsec->sh_size, _("string table")); @@ -6815,10 +7011,8 @@ hppa_process_unwind (FILE * file) { if (streq (SECTION_NAME (sec), ".PARISC.unwind")) { - printf (_("\nUnwind section ")); - printf (_("'%s'"), SECTION_NAME (sec)); - - printf (_(" at offset 0x%lx contains %lu entries:\n"), + printf (_("\nUnwind section '%s' at offset 0x%lx contains %lu entries:\n"), + printable_section_name (sec), (unsigned long) sec->sh_offset, (unsigned long) (sec->sh_size / (2 * eh_addr_size + 8))); @@ -6987,6 +7181,13 @@ get_unwind_section_word (struct arm_unw_aux_info * aux, /* Get the word at the required offset. */ word = byte_get (arm_sec->data + word_offset, 4); + /* PR 17531: file: id:000001,src:001266+003044,op:splice,rep:128. */ + if (arm_sec->rela == NULL) + { + * wordp = word; + return TRUE; + } + /* Look through the relocs to find the one that applies to the provided offset. */ wrapped = FALSE; for (rp = arm_sec->next_rela; rp != arm_sec->rela + arm_sec->nrelas; rp++) @@ -7011,7 +7212,9 @@ get_unwind_section_word (struct arm_unw_aux_info * aux, if (rp->r_offset < word_offset) continue; - sym = aux->symtab + ELF32_R_SYM (rp->r_info); + /* PR 17531: file: 027-161405-0.004 */ + if (aux->symtab == NULL) + continue; if (arm_sec->rel_type == SHT_REL) { @@ -7022,8 +7225,21 @@ get_unwind_section_word (struct arm_unw_aux_info * aux, else if (arm_sec->rel_type == SHT_RELA) offset = rp->r_addend; else - abort (); + { + error (_("Unknown section relocation type %d encountered\n"), + arm_sec->rel_type); + break; + } + + /* PR 17531 file: 027-1241568-0.004. */ + if (ELF32_R_SYM (rp->r_info) >= aux->nsyms) + { + error (_("Bad symbol index in unwind relocation (%lu > %lu)\n"), + (unsigned long) ELF32_R_SYM (rp->r_info), aux->nsyms); + break; + } + sym = aux->symtab + ELF32_R_SYM (rp->r_info); offset += sym->st_value; prelval = offset - (arm_sec->sec->sh_addr + rp->r_offset); @@ -7031,38 +7247,54 @@ get_unwind_section_word (struct arm_unw_aux_info * aux, if (elf_header.e_machine == EM_ARM) { relname = elf_arm_reloc_type (ELF32_R_TYPE (rp->r_info)); + if (relname == NULL) + { + warn (_("Skipping unknown ARM relocation type: %d\n"), + (int) ELF32_R_TYPE (rp->r_info)); + continue; + } if (streq (relname, "R_ARM_NONE")) continue; if (! streq (relname, "R_ARM_PREL31")) { - warn (_("Skipping unexpected relocation type %s\n"), relname); + warn (_("Skipping unexpected ARM relocation type %s\n"), relname); continue; } } else if (elf_header.e_machine == EM_TI_C6000) { relname = elf_tic6x_reloc_type (ELF32_R_TYPE (rp->r_info)); + if (relname == NULL) + { + warn (_("Skipping unknown C6000 relocation type: %d\n"), + (int) ELF32_R_TYPE (rp->r_info)); + continue; + } if (streq (relname, "R_C6000_NONE")) continue; if (! streq (relname, "R_C6000_PREL31")) { - warn (_("Skipping unexpected relocation type %s\n"), relname); + warn (_("Skipping unexpected C6000 relocation type %s\n"), relname); continue; } prelval >>= 1; } else - /* This function currently only supports ARM and TI unwinders. */ - abort (); + { + /* This function currently only supports ARM and TI unwinders. */ + warn (_("Only TI and ARM unwinders are currently supported\n")); + break; + } word = (word & ~ (bfd_vma) 0x7fffffff) | (prelval & 0x7fffffff); addr->section = sym->st_shndx; addr->offset = offset; + if (sym_name) * sym_name = sym->st_name; break; @@ -7250,11 +7482,15 @@ decode_arm_unwind_bytecode (struct arm_unw_aux_info *aux, if ((buf[i] & 0x80) == 0) break; } - assert (i < sizeof (buf)); - offset = read_uleb128 (buf, &len, buf + i + 1); - assert (len == i + 1); - offset = offset * 4 + 0x204; - printf ("vsp = vsp + %ld", offset); + if (i == sizeof (buf)) + printf (_("corrupt change to vsp")); + else + { + offset = read_uleb128 (buf, &len, buf + i + 1); + assert (len == i + 1); + offset = offset * 4 + 0x204; + printf ("vsp = vsp + %ld", offset); + } } else if (op == 0xb3 || op == 0xc8 || op == 0xc9) { @@ -7446,7 +7682,14 @@ decode_tic6x_unwind_bytecode (struct arm_unw_aux_info *aux, if ((buf[i] & 0x80) == 0) break; } - assert (i < sizeof (buf)); + /* PR 17531: file: id:000001,src:001906+004739,op:splice,rep:2. */ + if (i == sizeof (buf)) + { + printf ("\n"); + warn (_("Corrupt stack pointer adjustment detected\n")); + return; + } + offset = read_uleb128 (buf, &len, buf + i + 1); assert (len == i + 1); offset = offset * 8 + 0x408; @@ -7629,7 +7872,7 @@ decode_arm_unwind (struct arm_unw_aux_info * aux, break; default: - error (_("Unsupported architecture type %d encountered when decoding unwind table"), + error (_("Unsupported architecture type %d encountered when decoding unwind table\n"), elf_header.e_machine); } @@ -7749,7 +7992,7 @@ arm_process_unwind (FILE *file) break; default: - error (_("Unsupported architecture type %d encountered when processing unwind table"), + error (_("Unsupported architecture type %d encountered when processing unwind table\n"), elf_header.e_machine); return; } @@ -7767,7 +8010,13 @@ arm_process_unwind (FILE *file) aux.symtab = GET_ELF_SYMBOLS (file, sec, & aux.nsyms); strsec = section_headers + sec->sh_link; - assert (aux.strtab == NULL); + + /* PR binutils/17531 file: 011-12666-0.004. */ + if (aux.strtab != NULL) + { + error (_("Multiple string tables found in file.\n")); + free (aux.strtab); + } aux.strtab = get_data (NULL, file, strsec->sh_offset, 1, strsec->sh_size, _("string table")); aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0; @@ -7784,7 +8033,7 @@ arm_process_unwind (FILE *file) if (sec->sh_type == sec_type) { printf (_("\nUnwind table index '%s' at offset 0x%lx contains %lu entries:\n"), - SECTION_NAME (sec), + printable_section_name (sec), (unsigned long) sec->sh_offset, (unsigned long) (sec->sh_size / (2 * eh_addr_size))); @@ -8063,11 +8312,11 @@ get_32bit_dynamic_section (FILE * file) if (!edyn) return 0; -/* SGI's ELF has more than one section in the DYNAMIC segment, and we - might not have the luxury of section headers. Look for the DT_NULL - terminator to determine the number of entries. */ + /* SGI's ELF has more than one section in the DYNAMIC segment, and we + 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; + (char *) ext < (char *) edyn + dynamic_size - sizeof (* entry); ext++) { dynamic_nent++; @@ -8079,7 +8328,8 @@ get_32bit_dynamic_section (FILE * file) sizeof (* entry)); if (dynamic_section == NULL) { - error (_("Out of memory\n")); + error (_("Out of memory allocating space for %lu dynamic entries\n"), + (unsigned long) dynamic_nent); free (edyn); return 0; } @@ -8104,16 +8354,18 @@ get_64bit_dynamic_section (FILE * file) Elf64_External_Dyn * ext; Elf_Internal_Dyn * entry; + /* Read in the data. */ edyn = (Elf64_External_Dyn *) get_data (NULL, file, dynamic_addr, 1, dynamic_size, _("dynamic section")); if (!edyn) return 0; -/* SGI's ELF has more than one section in the DYNAMIC segment, and we - might not have the luxury of section headers. Look for the DT_NULL - terminator to determine the number of entries. */ + /* SGI's ELF has more than one section in the DYNAMIC segment, and we + 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; + /* PR 17533 file: 033-67080-0.004 - do not read off the end of the buffer. */ + (char *) ext < ((char *) edyn) + dynamic_size - sizeof (* ext); ext++) { dynamic_nent++; @@ -8125,11 +8377,13 @@ get_64bit_dynamic_section (FILE * file) sizeof (* entry)); if (dynamic_section == NULL) { - error (_("Out of memory\n")); + error (_("Out of memory allocating space for %lu dynamic entries\n"), + (unsigned long) dynamic_nent); free (edyn); return 0; } + /* Convert from external to internal formats. */ for (ext = edyn, entry = dynamic_section; entry < dynamic_section + dynamic_nent; ext++, entry++) @@ -8230,6 +8484,7 @@ process_dynamic_section (FILE * file) section.sh_entsize = sizeof (Elf32_External_Sym); else section.sh_entsize = sizeof (Elf64_External_Sym); + section.sh_name = string_table_length; dynamic_symbols = GET_ELF_SYMBOLS (file, §ion, & num_dynamic_syms); if (num_dynamic_syms < 1) @@ -8302,7 +8557,7 @@ process_dynamic_section (FILE * file) /* PR binutils/17531: A corrupt file can trigger this test. So do not use an assert, instead generate an error message. */ if (sizeof (Elf_External_Syminfo) != entry->d_un.d_val) - error (_("Bad value (%d) for SYMINENT entry"), + error (_("Bad value (%d) for SYMINENT entry\n"), (int) entry->d_un.d_val); } else if (entry->d_tag == DT_SYMINSZ) @@ -8328,7 +8583,8 @@ process_dynamic_section (FILE * file) dynamic_syminfo = (Elf_Internal_Syminfo *) malloc (syminsz); if (dynamic_syminfo == NULL) { - error (_("Out of memory\n")); + error (_("Out of memory allocating %lu byte for dynamic symbol info\n"), + (unsigned long) syminsz); return 0; } @@ -8346,8 +8602,8 @@ process_dynamic_section (FILE * file) } if (do_dynamic && dynamic_addr) - printf (_("\nDynamic section at offset 0x%lx contains %u entries:\n"), - dynamic_addr, dynamic_nent); + printf (_("\nDynamic section at offset 0x%lx contains %lu entries:\n"), + dynamic_addr, (unsigned long) dynamic_nent); if (do_dynamic) printf (_(" Tag Type Name/Value\n")); @@ -8759,9 +9015,14 @@ process_dynamic_section (FILE * file) time_t atime = entry->d_un.d_val; tmp = gmtime (&atime); - printf ("%04u-%02u-%02uT%02u:%02u:%02u\n", - tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, - tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + /* PR 17533 file: 041-1244816-0.004. */ + if (tmp == NULL) + printf (_("tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); } break; @@ -8868,17 +9129,15 @@ process_version_sections (FILE * file) found = 1; - printf - (_("\nVersion definition section '%s' contains %u entries:\n"), - SECTION_NAME (section), section->sh_info); + printf (_("\nVersion definition section '%s' contains %u entries:\n"), + printable_section_name (section), + section->sh_info); printf (_(" Addr: 0x")); printf_vma (section->sh_addr); - printf (_(" Offset: %#08lx Link: %u (%s)\n"), + printf (_(" Offset: %#08lx Link: %u (%s)"), (unsigned long) section->sh_offset, section->sh_link, - section->sh_link < elf_header.e_shnum - ? SECTION_NAME (section_headers + section->sh_link) - : _("")); + printable_section_name_from_index (section->sh_link)); edefs = (Elf_External_Verdef *) get_data (NULL, file, section->sh_offset, 1,section->sh_size, @@ -8966,6 +9225,10 @@ process_version_sections (FILE * file) if (j < ent.vd_cnt) printf (_(" Version def aux past end of section\n")); + /* PR 17531: file: id:000001,src:000172+005151,op:splice,rep:2. */ + if (idx + ent.vd_next <= idx) + break; + idx += ent.vd_next; } @@ -8986,15 +9249,13 @@ process_version_sections (FILE * file) found = 1; printf (_("\nVersion needs section '%s' contains %u entries:\n"), - SECTION_NAME (section), section->sh_info); + printable_section_name (section), section->sh_info); printf (_(" Addr: 0x")); printf_vma (section->sh_addr); printf (_(" Offset: %#08lx Link: %u (%s)\n"), (unsigned long) section->sh_offset, section->sh_link, - section->sh_link < elf_header.e_shnum - ? SECTION_NAME (section_headers + section->sh_link) - : _("")); + printable_section_name_from_index (section->sh_link)); eneed = (Elf_External_Verneed *) get_data (NULL, file, section->sh_offset, 1, @@ -9097,8 +9358,8 @@ process_version_sections (FILE * file) case SHT_GNU_versym: { Elf_Internal_Shdr * link_section; - int total; - int cnt; + size_t total; + unsigned int cnt; unsigned char * edata; unsigned short * data; char * strtab; @@ -9133,14 +9394,14 @@ process_version_sections (FILE * file) break; } - printf (_("\nVersion symbols section '%s' contains %d entries:\n"), - SECTION_NAME (section), total); + printf (_("\nVersion symbols section '%s' contains %lu entries:\n"), + printable_section_name (section), (unsigned long) total); printf (_(" Addr: ")); printf_vma (section->sh_addr); printf (_(" Offset: %#08lx Link: %u (%s)\n"), (unsigned long) section->sh_offset, section->sh_link, - SECTION_NAME (link_section)); + printable_section_name (link_section)); off = offset_from_vma (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)], @@ -9289,7 +9550,9 @@ process_version_sections (FILE * file) _("version def")) == NULL) { ivd.vd_next = 0; - ivd.vd_ndx = 0; + /* PR 17531: file: 046-1082287-0.004. */ + ivd.vd_ndx = (data[cnt + j] & VERSYM_VERSION) + 1; + break; } else { @@ -9621,30 +9884,41 @@ get_symbol_index_type (unsigned int type) } static bfd_vma * -get_dynamic_data (FILE * file, unsigned int number, unsigned int ent_size) +get_dynamic_data (FILE * file, size_t number, unsigned int ent_size) { unsigned char * e_data; bfd_vma * i_data; - e_data = (unsigned char *) cmalloc (number, ent_size); + /* Be kind to memory chekers (eg valgrind, address sanitizer) by not + attempting to allocate memory when the read is bound to fail. */ + if (ent_size * number > current_file_size) + { + error (_("Invalid number of dynamic entries: %lu\n"), + (unsigned long) number); + return NULL; + } + e_data = (unsigned char *) cmalloc (number, ent_size); if (e_data == NULL) { - error (_("Out of memory\n")); + error (_("Out of memory reading %lu dynamic entries\n"), + (unsigned long) number); return NULL; } if (fread (e_data, ent_size, number, file) != number) { - error (_("Unable to read in dynamic data\n")); + error (_("Unable to read in %lu bytes of dynamic data\n"), + (unsigned long) (number * ent_size)); + free (e_data); return NULL; } i_data = (bfd_vma *) cmalloc (number, sizeof (*i_data)); - if (i_data == NULL) { - error (_("Out of memory\n")); + error (_("Out of memory allocating space for %lu dynamic entries\n"), + (unsigned long) number); free (e_data); return NULL; } @@ -9670,7 +9944,8 @@ print_dynamic_symbol (bfd_vma si, unsigned long hn) if (dynamic_symbols == NULL || si >= num_dynamic_syms) { - printf (_("\n")); + printf (_("\n"), + (unsigned long) si); return; } @@ -9696,19 +9971,195 @@ print_dynamic_symbol (bfd_vma si, unsigned long hn) putchar ('\n'); } +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) +{ + const char *version_string = NULL; + + 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; + + 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; + + vers_data = byte_get (data, 2); + + is_nobits = (psym->st_shndx < elf_header.e_shnum + && section_headers[psym->st_shndx].sh_type + == SHT_NOBITS); + + check_def = (psym->st_shndx != SHN_UNDEF); + + if ((vers_data & VERSYM_HIDDEN) || vers_data > 1) + { + if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)] + && (is_nobits || ! check_def)) + { + Elf_External_Verneed evn; + Elf_Internal_Verneed ivn; + Elf_Internal_Vernaux ivna; + + /* We must test both. */ + offset = offset_from_vma + (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)], + sizeof evn); + + do + { + unsigned long vna_off; + + 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; + } + + ivn.vn_aux = BYTE_GET (evn.vn_aux); + ivn.vn_next = BYTE_GET (evn.vn_next); + + vna_off = offset + ivn.vn_aux; + + do + { + Elf_External_Vernaux evna; + + 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); + } + + vna_off += ivna.vna_next; + } + while (ivna.vna_other != vers_data + && ivna.vna_next != 0); + + if (ivna.vna_other == vers_data) + break; + + offset += ivn.vn_next; + } + while (ivn.vn_next != 0); + + if (ivna.vna_other == vers_data) + { + *sym_info = symbol_undefined; + *vna_other = ivna.vna_other; + version_string = (ivna.vna_name < strtab_size + ? strtab + ivna.vna_name + : _("")); + check_def = 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); + + off -= ivd.vd_next; + off += ivd.vd_aux; + + if (get_data (&evda, file, off, sizeof (evda), + 1, _("version def aux")) == NULL) + return version_string; + + ivda.vda_name = BYTE_GET (evda.vda_name); + + 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 + : _("")); + } + } + } + } + } + return version_string; +} + /* Dump the symbol table. */ static int process_symbol_table (FILE * file) { Elf_Internal_Shdr * section; - bfd_vma nbuckets = 0; - bfd_vma nchains = 0; + bfd_size_type nbuckets = 0; + bfd_size_type nchains = 0; bfd_vma * buckets = NULL; bfd_vma * chains = NULL; bfd_vma ngnubuckets = 0; bfd_vma * gnubuckets = NULL; bfd_vma * gnuchains = NULL; bfd_vma gnusymidx = 0; + bfd_size_type ngnuchains = 0; if (!do_syms && !do_dyn_syms && !do_histogram) return 1; @@ -9721,7 +10172,7 @@ process_symbol_table (FILE * file) { unsigned char nb[8]; unsigned char nc[8]; - int hash_ent_size = 4; + unsigned int hash_ent_size = 4; if ((elf_header.e_machine == EM_ALPHA || elf_header.e_machine == EM_S390 @@ -9870,6 +10321,7 @@ process_symbol_table (FILE * file) } gnuchains = get_dynamic_data (file, maxchain, 4); + ngnuchains = maxchain; no_gnu_hash: if (gnuchains == NULL) @@ -9885,7 +10337,8 @@ process_symbol_table (FILE * file) if ((dynamic_info[DT_HASH] || dynamic_info_DT_GNU_HASH) && do_syms && do_using_dynamic - && dynamic_strings != NULL) + && dynamic_strings != NULL + && dynamic_symbols != NULL) { unsigned long hn; @@ -9928,11 +10381,12 @@ process_symbol_table (FILE * file) print_dynamic_symbol (si, hn); si++; } - while ((gnuchains[off++] & 1) == 0); + while (off < ngnuchains && (gnuchains[off++] & 1) == 0); } } } - else if (do_dyn_syms || (do_syms && !do_using_dynamic)) + else if ((do_dyn_syms || (do_syms && !do_using_dynamic)) + && section_headers != NULL) { unsigned int i; @@ -9956,12 +10410,12 @@ process_symbol_table (FILE * file) if (section->sh_entsize == 0) { printf (_("\nSymbol table '%s' has a sh_entsize of zero!\n"), - SECTION_NAME (section)); + printable_section_name (section)); continue; } printf (_("\nSymbol table '%s' contains %lu entries:\n"), - SECTION_NAME (section), + printable_section_name (section), (unsigned long) (section->sh_size / section->sh_entsize)); if (is_32bit_elf) @@ -9992,6 +10446,10 @@ process_symbol_table (FILE * file) for (si = 0, psym = symtab; si < num_syms; si++, psym++) { + const char *version_string; + enum versioned_symbol_info sym_info; + unsigned short vna_other; + printf ("%6d: ", si); print_vma (psym->st_value, LONG_HEX); putchar (' '); @@ -10008,163 +10466,18 @@ process_symbol_table (FILE * file) print_symbol (25, psym->st_name < strtab_size ? strtab + psym->st_name : _("")); - if (section->sh_type == SHT_DYNSYM - && version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0) + version_string + = get_symbol_version_string (file, + section->sh_type == SHT_DYNSYM, + strtab, strtab_size, si, + psym, &sym_info, &vna_other); + if (version_string) { - unsigned char data[2]; - unsigned short vers_data; - unsigned long offset; - int is_nobits; - int check_def; - - 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) - break; - - vers_data = byte_get (data, 2); - - is_nobits = (psym->st_shndx < elf_header.e_shnum - && section_headers[psym->st_shndx].sh_type - == SHT_NOBITS); - - check_def = (psym->st_shndx != SHN_UNDEF); - - if ((vers_data & VERSYM_HIDDEN) || vers_data > 1) - { - if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)] - && (is_nobits || ! check_def)) - { - Elf_External_Verneed evn; - Elf_Internal_Verneed ivn; - Elf_Internal_Vernaux ivna; - - /* We must test both. */ - offset = offset_from_vma - (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)], - sizeof evn); - - do - { - unsigned long vna_off; - - 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; - } - - ivn.vn_aux = BYTE_GET (evn.vn_aux); - ivn.vn_next = BYTE_GET (evn.vn_next); - - vna_off = offset + ivn.vn_aux; - - do - { - Elf_External_Vernaux evna; - - 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); - } - - vna_off += ivna.vna_next; - } - while (ivna.vna_other != vers_data - && ivna.vna_next != 0); - - if (ivna.vna_other == vers_data) - break; - - offset += ivn.vn_next; - } - while (ivn.vn_next != 0); - - if (ivna.vna_other == vers_data) - { - printf ("@%s (%d)", - ivna.vna_name < strtab_size - ? strtab + ivna.vna_name : _(""), - ivna.vna_other); - check_def = 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); - - off -= ivd.vd_next; - off += ivd.vd_aux; - - if (get_data (&evda, file, off, sizeof (evda), - 1, _("version def aux")) == NULL) - break; - - ivda.vda_name = BYTE_GET (evda.vda_name); - - if (psym->st_name != ivda.vda_name) - printf ((vers_data & VERSYM_HIDDEN) - ? "@%s" : "@@%s", - ivda.vda_name < strtab_size - ? strtab + ivda.vda_name : _("")); - } - } - } + if (sym_info == symbol_undefined) + printf ("@%s (%d)", version_string, vna_other); + else + printf (sym_info == symbol_hidden ? "@%s" : "@@%s", + version_string); } putchar ('\n'); @@ -10191,14 +10504,15 @@ process_symbol_table (FILE * file) printf (_("\nHistogram for bucket list length (total of %lu buckets):\n"), (unsigned long) nbuckets); - printf (_(" Length Number %% of total Coverage\n")); lengths = (unsigned long *) calloc (nbuckets, sizeof (*lengths)); if (lengths == NULL) { - error (_("Out of memory\n")); + error (_("Out of memory allocating space for histogram buckets\n")); return 0; } + + printf (_(" Length Number %% of total Coverage\n")); for (hn = 0; hn < nbuckets; ++hn) { for (si = buckets[hn]; si > 0 && si < nchains; si = chains[si]) @@ -10222,7 +10536,7 @@ process_symbol_table (FILE * file) if (counts == NULL) { free (lengths); - error (_("Out of memory\n")); + error (_("Out of memory allocating space for histogram counts\n")); return 0; } @@ -10262,15 +10576,16 @@ process_symbol_table (FILE * file) unsigned long nzero_counts = 0; unsigned long nsyms = 0; + printf (_("\nHistogram for `.gnu.hash' bucket list length (total of %lu buckets):\n"), + (unsigned long) ngnubuckets); + lengths = (unsigned long *) calloc (ngnubuckets, sizeof (*lengths)); if (lengths == NULL) { - error (_("Out of memory\n")); + error (_("Out of memory allocating space for gnu histogram buckets\n")); return 0; } - printf (_("\nHistogram for `.gnu.hash' bucket list length (total of %lu buckets):\n"), - (unsigned long) ngnubuckets); printf (_(" Length Number %% of total Coverage\n")); for (hn = 0; hn < ngnubuckets; ++hn) @@ -10279,7 +10594,9 @@ process_symbol_table (FILE * file) bfd_vma off, length = 1; for (off = gnubuckets[hn] - gnusymidx; - (gnuchains[off] & 1) == 0; ++off) + /* PR 17531 file: 010-77222-0.004. */ + off < ngnuchains && (gnuchains[off] & 1) == 0; + ++off) ++length; lengths[hn] = length; if (length > maxlength) @@ -10291,7 +10608,7 @@ process_symbol_table (FILE * file) if (counts == NULL) { free (lengths); - error (_("Out of memory\n")); + error (_("Out of memory allocating space for gnu histogram counts\n")); return 0; } @@ -10345,8 +10662,9 @@ process_syminfo (FILE * file ATTRIBUTE_UNUSED) unsigned short int flags = dynamic_syminfo[i].si_flags; printf ("%4d: ", i); - assert (i < num_dynamic_syms); - if (VALID_DYNAMIC_NAME (dynamic_symbols[i].st_name)) + if (i >= num_dynamic_syms) + printf (_("")); + else if (VALID_DYNAMIC_NAME (dynamic_symbols[i].st_name)) print_symbol (30, GET_DYNAMIC_NAME (dynamic_symbols[i].st_name)); else printf (_(""), dynamic_symbols[i].st_name); @@ -10449,7 +10767,7 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc, default: if (saved_sym != NULL) - error (_("Unhandled MSP430 reloc type found after SYM_DIFF reloc")); + error (_("Unhandled MSP430 reloc type found after SYM_DIFF reloc\n")); break; } break; @@ -10485,7 +10803,7 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc, break; default: if (saved_sym != NULL) - error (_("Unhandled MN10300 reloc type found after SYM_DIFF reloc")); + error (_("Unhandled MN10300 reloc type found after SYM_DIFF reloc\n")); break; } break; @@ -11025,7 +11343,7 @@ apply_relocations (void * file, else { warn (_("unable to apply unsupported reloc type %d to section %s\n"), - reloc_type, SECTION_NAME (section)); + reloc_type, printable_section_name (section)); continue; } @@ -11034,7 +11352,7 @@ apply_relocations (void * file, { warn (_("skipping invalid relocation offset 0x%lx in section %s\n"), (unsigned long) rp->r_offset, - SECTION_NAME (section)); + printable_section_name (section)); continue; } @@ -11042,7 +11360,7 @@ apply_relocations (void * file, if (sym_index >= num_syms) { warn (_("skipping invalid relocation symbol index 0x%lx in section %s\n"), - sym_index, SECTION_NAME (section)); + sym_index, printable_section_name (section)); continue; } sym = symtab + sym_index; @@ -11066,7 +11384,7 @@ apply_relocations (void * file, warn (_("skipping unexpected symbol type %s in %ld'th relocation in section %s\n"), get_symbol_type (ELF_ST_TYPE (sym->st_info)), (long int)(rp - relocs), - SECTION_NAME (relsec)); + printable_section_name (relsec)); continue; } @@ -11109,10 +11427,9 @@ apply_relocations (void * file, static int disassemble_section (Elf_Internal_Shdr * section, FILE * file) { - printf (_("\nAssembly dump of section %s\n"), - SECTION_NAME (section)); + printf (_("\nAssembly dump of section %s\n"), printable_section_name (section)); - /* XXX -- to be done --- XXX */ + /* FIXME: XXX -- to be done --- XXX */ return 1; } @@ -11131,7 +11448,7 @@ get_section_contents (Elf_Internal_Shdr * section, FILE * file) if (num_bytes == 0 || section->sh_type == SHT_NOBITS) { printf (_("\nSection '%s' has no data to dump.\n"), - SECTION_NAME (section)); + printable_section_name (section)); return NULL; } @@ -11148,14 +11465,13 @@ dump_section_as_strings (Elf_Internal_Shdr * section, FILE * file) char * data; char * end; char * start; - char * name = SECTION_NAME (section); bfd_boolean some_strings_shown; start = get_section_contents (section, file); if (start == NULL) return; - printf (_("\nString dump of section '%s':\n"), name); + printf (_("\nString dump of section '%s':\n"), printable_section_name (section)); /* If the section being dumped has relocations against it the user might be expecting these relocations to have been applied. Check for this @@ -11190,15 +11506,26 @@ dump_section_as_strings (Elf_Internal_Shdr * section, FILE * file) if (data < end) { + size_t maxlen = end - data; + #ifndef __MSVCRT__ /* PR 11128: Use two separate invocations in order to work around bugs in the Solaris 8 implementation of printf. */ printf (" [%6tx] ", data - start); - printf ("%s\n", data); #else - printf (" [%6Ix] %s\n", (size_t) (data - start), data); + printf (" [%6Ix] ", (size_t) (data - start)); #endif - data += strlen (data); + if (maxlen > 0) + { + print_symbol ((int) maxlen, data); + putchar ('\n'); + data += strnlen (data, maxlen); + } + else + { + printf (_("\n")); + data = end; + } some_strings_shown = TRUE; } } @@ -11226,7 +11553,7 @@ dump_section_as_bytes (Elf_Internal_Shdr * section, if (start == NULL) return; - printf (_("\nHex dump of section '%s':\n"), SECTION_NAME (section)); + printf (_("\nHex dump of section '%s':\n"), printable_section_name (section)); if (relocate) { @@ -11457,6 +11784,7 @@ static int display_debug_section (int shndx, Elf_Internal_Shdr * section, FILE * file) { char * name = SECTION_NAME (section); + const char * print_name = printable_section_name (section); bfd_size_type length; int result = 1; int i; @@ -11464,7 +11792,7 @@ display_debug_section (int shndx, Elf_Internal_Shdr * section, FILE * file) length = section->sh_size; if (length == 0) { - printf (_("\nSection '%s' has no debugging data.\n"), name); + printf (_("\nSection '%s' has no debugging data.\n"), print_name); return 0; } if (section->sh_type == SHT_NOBITS) @@ -11473,7 +11801,8 @@ display_debug_section (int shndx, Elf_Internal_Shdr * section, FILE * file) which has the NOBITS type - the bits in the file will be random. This can happen when a file containing a .eh_frame section is stripped with the --only-keep-debug command line option. */ - printf (_("section '%s' has the NOBITS type - its contents are unreliable.\n"), name); + printf (_("section '%s' has the NOBITS type - its contents are unreliable.\n"), + print_name); return 0; } @@ -11518,7 +11847,7 @@ display_debug_section (int shndx, Elf_Internal_Shdr * section, FILE * file) if (i == max) { - printf (_("Unrecognized debug section: %s\n"), name); + printf (_("Unrecognized debug section: %s\n"), print_name); result = 0; } @@ -11637,13 +11966,25 @@ display_tag_value (int tag, if (p >= end) { - warn (_("corrupt tag\n")); + warn (_("\n")); } else if (tag & 1) { - /* FIXME: we could read beyond END here. */ - printf ("\"%s\"\n", p); - p += strlen ((char *) p) + 1; + /* PR 17531 file: 027-19978-0.004. */ + size_t maxlen = (end - p) - 1; + + putchar ('"'); + if (maxlen > 0) + { + print_symbol ((int) maxlen, (const char *) p); + p += strnlen ((char *) p, maxlen) + 1; + } + else + { + printf (_("")); + p = (unsigned char *) end; + } + printf ("\"\n"); } else { @@ -11654,6 +11995,7 @@ display_tag_value (int tag, printf ("%ld (0x%lx)\n", val, val); } + assert (p <= end); return p; } @@ -11675,7 +12017,7 @@ static const char * arm_attr_tag_THUMB_ISA_use[] = {"No", "Thumb-1", "Thumb-2"}; static const char * arm_attr_tag_FP_arch[] = {"No", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16", "VFPv4", "VFPv4-D16", - "FP for ARMv8"}; + "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"}; @@ -11861,14 +12203,30 @@ display_arm_attribute (unsigned char * p, break; case 32: /* Tag_compatibility. */ - val = read_uleb128 (p, &len, end); - p += len; - printf (_("flag = %d, vendor = %s\n"), val, p); - p += strlen ((char *) p) + 1; + { + val = read_uleb128 (p, &len, end); + p += len; + printf (_("flag = %d, vendor = "), val); + if (p < end - 1) + { + size_t maxlen = (end - p) - 1; + + print_symbol ((int) maxlen, (const char *) p); + p += strnlen ((char *) p, maxlen) + 1; + } + else + { + printf (_("")); + p = (unsigned char *) end; + } + putchar ('\n'); + } break; case 64: /* Tag_nodefaults. */ - p++; + /* PR 17531: file: 001-505008-0.01. */ + if (p < end) + p++; printf (_("True\n")); break; @@ -11879,14 +12237,15 @@ display_arm_attribute (unsigned char * p, { val = read_uleb128 (p, &len, end); p += len; - if ((unsigned int)val >= ARRAY_SIZE (arm_attr_tag_CPU_arch)) + if ((unsigned int) val >= ARRAY_SIZE (arm_attr_tag_CPU_arch)) printf ("??? (%d)\n", val); else printf ("%s\n", arm_attr_tag_CPU_arch[val]); } else printf ("???\n"); - while (*(p++) != '\0' /* NUL terminator. */); + while (p < end && *(p++) != '\0' /* NUL terminator. */) + ; break; default: @@ -11933,15 +12292,28 @@ display_gnu_attribute (unsigned char * p, { val = read_uleb128 (p, &len, end); p += len; + + printf (_("flag = %d, vendor = "), val); if (p == end) { - printf (_("flag = %d, vendor = \n"), val); + printf (_("\n")); warn (_("corrupt vendor attribute\n")); } else { - printf (_("flag = %d, vendor = %s\n"), val, p); - p += strlen ((char *) p) + 1; + if (p < end - 1) + { + size_t maxlen = (end - p) - 1; + + print_symbol ((int) maxlen, (const char *) p); + p += strnlen ((char *) p, maxlen) + 1; + } + else + { + printf (_("")); + p = (unsigned char *) end; + } + putchar ('\n'); } return p; } @@ -12017,7 +12389,7 @@ display_power_gnu_attribute (unsigned char * p, { if (p == end) { - warn (_("corrupt Tag_GNU_Power_ABI_Struct_Return")); + warn (_("corrupt Tag_GNU_Power_ABI_Struct_Return\n")); return p; } @@ -12051,6 +12423,7 @@ display_sparc_hwcaps (int mask) if (mask) { int first = 1; + if (mask & ELF_SPARC_HWCAP_MUL32) fputs ("mul32", stdout), first = 0; if (mask & ELF_SPARC_HWCAP_DIV32) @@ -12085,8 +12458,8 @@ display_sparc_hwcaps (int mask) printf ("%scspare", first ? "" : "|"), first = 0; } else - fputc('0', stdout); - fputc('\n', stdout); + fputc ('0', stdout); + fputc ('\n', stdout); } static void @@ -12095,6 +12468,7 @@ display_sparc_hwcaps2 (int mask) if (mask) { int first = 1; + if (mask & ELF_SPARC_HWCAP2_FJATHPLUS) fputs ("fjathplus", stdout), first = 0; if (mask & ELF_SPARC_HWCAP2_VIS3B) @@ -12119,8 +12493,8 @@ display_sparc_hwcaps2 (int mask) printf ("%sfjaes", first ? "" : "|"), first = 0; } else - fputc('0', stdout); - fputc('\n', stdout); + fputc ('0', stdout); + fputc ('\n', stdout); } static unsigned char * @@ -12436,18 +12810,45 @@ display_tic6x_attribute (unsigned char * p, return p; case Tag_ABI_compatibility: - val = read_uleb128 (p, &len, end); - p += len; - printf (" Tag_ABI_compatibility: "); - printf (_("flag = %d, vendor = %s\n"), val, p); - p += strlen ((char *) p) + 1; - return p; + { + val = read_uleb128 (p, &len, end); + p += len; + printf (" Tag_ABI_compatibility: "); + printf (_("flag = %d, vendor = "), val); + if (p < end - 1) + { + size_t maxlen = (end - p) - 1; + + print_symbol ((int) maxlen, (const char *) p); + p += strnlen ((char *) p, maxlen) + 1; + } + else + { + printf (_("")); + p = (unsigned char *) end; + } + putchar ('\n'); + return p; + } case Tag_ABI_conformance: - printf (" Tag_ABI_conformance: "); - printf ("\"%s\"\n", p); - p += strlen ((char *) p) + 1; - return p; + { + printf (" Tag_ABI_conformance: \""); + if (p < end - 1) + { + size_t maxlen = (end - p) - 1; + + print_symbol ((int) maxlen, (const char *) p); + p += strnlen ((char *) p, maxlen) + 1; + } + else + { + printf (_("")); + p = (unsigned char *) end; + } + printf ("\"\n"); + return p; + } } return display_tag_value (tag, p, end); @@ -12556,8 +12957,20 @@ display_msp430x_attribute (unsigned char * p, if (tag & 1) { - printf ("\"%s\"\n", p); - p += strlen ((char *) p) + 1; + putchar ('"'); + if (p < end - 1) + { + size_t maxlen = (end - p) - 1; + + print_symbol ((int) maxlen, (const char *) p); + p += strnlen ((char *) p, maxlen) + 1; + } + else + { + printf (_("")); + p = (unsigned char *) end; + } + printf ("\"\n"); } else { @@ -12568,6 +12981,7 @@ display_msp430x_attribute (unsigned char * p, break; } + assert (p <= end); return p; } @@ -12579,11 +12993,6 @@ process_attributes (FILE * file, unsigned char * (* display_proc_gnu_attribute) (unsigned char *, int, const unsigned char * const)) { Elf_Internal_Shdr * sect; - unsigned char * contents; - unsigned char * p; - unsigned char * end; - bfd_vma section_len; - bfd_vma len; unsigned i; /* Find the section header so that we get the size. */ @@ -12591,6 +13000,9 @@ process_attributes (FILE * file, i < elf_header.e_shnum; i++, sect++) { + unsigned char * contents; + unsigned char * p; + if (sect->sh_type != proc_type && sect->sh_type != SHT_GNU_ATTRIBUTES) continue; @@ -12602,41 +13014,52 @@ process_attributes (FILE * file, p = contents; if (*p == 'A') { - len = sect->sh_size - 1; + bfd_vma section_len; + + section_len = sect->sh_size - 1; p++; - while (len > 0) + while (section_len > 0) { + bfd_vma attr_len; unsigned int namelen; bfd_boolean public_section; bfd_boolean gnu_section; - if (len <= 4) + if (section_len <= 4) { error (_("Tag section ends prematurely\n")); break; } - section_len = byte_get (p, 4); + attr_len = byte_get (p, 4); p += 4; - if (section_len > len) + if (attr_len > section_len) { - error (_("Length of attribute (%u) greater than length of section (%u)\n"), - (unsigned) section_len, (unsigned) len); - section_len = len; + error (_("Bad attribute length (%u > %u)\n"), + (unsigned) attr_len, (unsigned) section_len); + attr_len = section_len; + } + /* PR 17531: file: 001-101425-0.004 */ + else if (attr_len < 5) + { + error (_("Attribute length of %u is too small\n"), (unsigned) attr_len); + break; } - len -= section_len; - section_len -= 4; + section_len -= attr_len; + attr_len -= 4; - namelen = strnlen ((char *) p, section_len) + 1; - if (namelen == 0 || namelen >= section_len) + namelen = strnlen ((char *) p, attr_len) + 1; + if (namelen == 0 || namelen >= attr_len) { error (_("Corrupt attribute section name\n")); break; } - printf (_("Attribute Section: %s\n"), p); + printf (_("Attribute Section: ")); + print_symbol (INT_MAX, (const char *) p); + putchar ('\n'); if (public_name && streq ((char *) p, public_name)) public_section = TRUE; @@ -12649,16 +13072,17 @@ process_attributes (FILE * file, gnu_section = FALSE; p += namelen; - section_len -= namelen; + attr_len -= namelen; - while (section_len > 0) + while (attr_len > 0 && p < contents + sect->sh_size) { int tag; int val; bfd_vma size; + unsigned char * end; /* PR binutils/17531: Safe handling of corrupt files. */ - if (section_len < 6) + if (attr_len < 6) { error (_("Unused bytes at end of section\n")); section_len = 0; @@ -12667,11 +13091,11 @@ process_attributes (FILE * file, tag = *(p++); size = byte_get (p, 4); - if (size > section_len) + if (size > attr_len) { error (_("Bad subsection length (%u > %u)\n"), - (unsigned) size, (unsigned) section_len); - size = section_len; + (unsigned) size, (unsigned) attr_len); + size = attr_len; } /* PR binutils/17531: Safe handling of corrupt files. */ if (size < 6) @@ -12682,8 +13106,9 @@ process_attributes (FILE * file, break; } - section_len -= size; + attr_len -= size; end = p + size - 1; + assert (end <= contents + sect->sh_size); p += 4; switch (tag) @@ -12715,24 +13140,28 @@ process_attributes (FILE * file, break; } - if (public_section) + if (public_section && display_pub_attribute != NULL) { while (p < end) p = display_pub_attribute (p, end); + assert (p <= end); } - else if (gnu_section) + else if (gnu_section && display_proc_gnu_attribute != NULL) { while (p < end) p = display_gnu_attribute (p, display_proc_gnu_attribute, end); + assert (p <= end); } - else + else if (p < end) { - printf (_(" Unknown section contexts\n")); + printf (_(" Unknown attribute:\n")); display_raw_attribute (p, end); p = end; } + else + attr_len = 0; } } } @@ -13021,7 +13450,10 @@ process_mips_specific (FILE * file) /* No information available. */ return 0; - for (entry = dynamic_section; entry->d_tag != DT_NULL; ++entry) + for (entry = dynamic_section; + /* PR 17531 file: 012-50589-0.004. */ + entry < dynamic_section + dynamic_nent && entry->d_tag != DT_NULL; + ++entry) switch (entry->d_tag) { case DT_MIPS_LIBLIST: @@ -13162,8 +13594,13 @@ process_mips_specific (FILE * file) sect = section_headers; /* Find the section header so that we get the size. */ - while (sect->sh_type != SHT_MIPS_OPTIONS) - ++sect; + sect = find_section_by_type (SHT_MIPS_OPTIONS); + /* PR 17533 file: 012-277276-0.004. */ + if (sect == NULL) + { + error (_("No MIPS_OPTIONS header found\n")); + return 0; + } eopt = (Elf_External_Options *) get_data (NULL, file, options_offset, 1, sect->sh_size, _("options")); @@ -13173,7 +13610,7 @@ process_mips_specific (FILE * file) cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (* iopt)); if (iopt == NULL) { - error (_("Out of memory\n")); + error (_("Out of memory allocatinf space for MIPS options\n")); return 0; } @@ -13198,7 +13635,7 @@ process_mips_specific (FILE * file) } printf (_("\nSection '%s' contains %d entries:\n"), - SECTION_NAME (sect), cnt); + printable_section_name (sect), cnt); option = iopt; @@ -13365,7 +13802,7 @@ process_mips_specific (FILE * file) iconf = (Elf32_Conflict *) cmalloc (conflictsno, sizeof (* iconf)); if (iconf == NULL) { - error (_("Out of memory\n")); + error (_("Out of memory allocating space for dynamic conflicts\n")); return 0; } @@ -13438,8 +13875,17 @@ process_mips_specific (FILE * file) ent = pltgot; addr_size = (is_32bit_elf ? 4 : 8); local_end = pltgot + local_gotno * addr_size; - global_end = local_end + (symtabno - gotsym) * addr_size; + /* PR binutils/17533 file: 012-111227-0.004 */ + if (symtabno < gotsym) + { + error (_("The GOT symbol offset (%lu) is greater than the symbol table size (%lu)\n"), + (long) gotsym, (long) symtabno); + return 0; + } + + global_end = local_end + (symtabno - gotsym) * addr_size; + assert (global_end >= local_end); offset = offset_from_vma (file, pltgot, global_end - pltgot); data = (unsigned char *) get_data (NULL, file, offset, global_end - pltgot, 1, @@ -13519,7 +13965,8 @@ process_mips_specific (FILE * file) printf (_(""), psym->st_name); } else - printf (_(""), i); + printf (_(""), + (unsigned long) i); printf ("\n"); } @@ -13690,7 +14137,7 @@ process_gnu_liblist (FILE * file) strtab_size = string_sec->sh_size; printf (_("\nLibrary list section '%s' contains %lu entries:\n"), - SECTION_NAME (section), + printable_section_name (section), (unsigned long) (section->sh_size / sizeof (Elf32_External_Lib))); puts (_(" Library Time Stamp Checksum Version Flags")); @@ -13954,6 +14401,13 @@ print_gnu_note (Elf_Internal_Note *pnote) unsigned long os, major, minor, subminor; const char *osname; + /* PR 17531: file: 030-599401-0.004. */ + if (pnote->descsz < 16) + { + printf (_(" \n")); + break; + } + os = byte_get ((unsigned char *) pnote->descdata, 4); major = byte_get ((unsigned char *) pnote->descdata + 4, 4); minor = byte_get ((unsigned char *) pnote->descdata + 8, 4); @@ -14362,6 +14816,9 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length) if (inote.descdata < (char *) external + min_notesz || next < (char *) external + min_notesz + /* PR binutils/17531: file: id:000000,sig:11,src:006986,op:havoc,rep:4. */ + || inote.namedata + inote.namesz < inote.namedata + || inote.descdata + inote.descsz < inote.descdata || data_remaining < (size_t)(next - (char *) external)) { warn (_("note with invalid namesz and/or descsz found at offset 0x%lx\n"), @@ -14380,10 +14837,9 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length) if (inote.namedata[inote.namesz - 1] != '\0') { temp = (char *) malloc (inote.namesz + 1); - if (temp == NULL) { - error (_("Out of memory\n")); + error (_("Out of memory allocating space for inote name\n")); res = 0; break; }