X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=binutils%2Freadelf.c;h=0bdabccc8eb140898254835309ecbb3482f4cc8d;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-2020-04-01;hp=4dcac968ddf02dece5685ff69fefe94e90f30ee0;hpb=c48acf6f26713427fb6870a8551a89ac12838e7b;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/readelf.c b/binutils/readelf.c index 4dcac968dd..0bdabccc8e 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -197,46 +197,20 @@ struct dump_list_entry struct dump_list_entry * next; }; -typedef struct filedata +/* A dynamic array of flags indicating for which sections a dump + has been requested via command line switches. */ +struct dump_data { - const char * file_name; - FILE * handle; - bfd_size_type file_size; - Elf_Internal_Ehdr file_header; - Elf_Internal_Shdr * section_headers; - Elf_Internal_Phdr * program_headers; - char * string_table; - unsigned long string_table_length; - /* A dynamic array of flags indicating for which sections a dump of - some kind has been requested. It is reset on a per-object file - basis and then initialised from the cmdline_dump_sects array, - the results of interpreting the -w switch, and the - dump_sects_byname list. */ dump_type * dump_sects; unsigned int num_dump_sects; -} Filedata; +}; + +static struct dump_data cmdline; + +static struct dump_list_entry * dump_sects_byname; char * program_name = "readelf"; -static unsigned long archive_file_offset; -static unsigned long archive_file_size; -static unsigned long dynamic_addr; -static bfd_size_type dynamic_size; -static size_t dynamic_nent; -static char * dynamic_strings; -static unsigned long dynamic_strings_length; -static unsigned long num_dynamic_syms; -static Elf_Internal_Sym * dynamic_symbols; -static Elf_Internal_Syminfo * dynamic_syminfo; -static unsigned long dynamic_syminfo_offset; -static unsigned int dynamic_syminfo_nent; -static char program_interpreter[PATH_MAX]; -static bfd_vma dynamic_info[DT_ENCODING]; -static bfd_vma dynamic_info_DT_GNU_HASH; -static bfd_vma dynamic_info_DT_MIPS_XHASH; -static bfd_vma version_info[16]; -static Elf_Internal_Dyn * dynamic_section; -static elf_section_list * symtab_shndx_list; static bfd_boolean show_name = FALSE; static bfd_boolean do_dynamic = FALSE; static bfd_boolean do_syms = FALSE; @@ -257,6 +231,7 @@ static bfd_boolean do_ctf = FALSE; static bfd_boolean do_arch = FALSE; static bfd_boolean do_notes = FALSE; static bfd_boolean do_archive_index = FALSE; +static bfd_boolean check_all = FALSE; static bfd_boolean is_32bit_elf = FALSE; static bfd_boolean decompress_dumps = FALSE; @@ -276,15 +251,57 @@ struct group unsigned int group_index; }; -static size_t group_count; -static struct group * section_groups; -static struct group ** section_headers_groups; - -/* A dynamic array of flags indicating for which sections a dump - has been requested via command line switches. */ -static Filedata cmdline; - -static struct dump_list_entry * dump_sects_byname; +typedef struct filedata +{ + const char * file_name; + FILE * handle; + bfd_size_type file_size; + Elf_Internal_Ehdr file_header; + Elf_Internal_Shdr * section_headers; + Elf_Internal_Phdr * program_headers; + char * string_table; + unsigned long string_table_length; + unsigned long archive_file_offset; + unsigned long archive_file_size; + unsigned long dynamic_addr; + bfd_size_type dynamic_size; + size_t dynamic_nent; + Elf_Internal_Dyn * dynamic_section; + Elf_Internal_Shdr * dynamic_strtab_section; + char * dynamic_strings; + unsigned long dynamic_strings_length; + Elf_Internal_Shdr * dynamic_symtab_section; + unsigned long num_dynamic_syms; + Elf_Internal_Sym * dynamic_symbols; + bfd_vma version_info[16]; + unsigned int dynamic_syminfo_nent; + Elf_Internal_Syminfo * dynamic_syminfo; + unsigned long dynamic_syminfo_offset; + bfd_size_type nbuckets; + bfd_size_type nchains; + bfd_vma * buckets; + bfd_vma * chains; + bfd_size_type ngnubuckets; + bfd_size_type ngnuchains; + bfd_vma * gnubuckets; + bfd_vma * gnuchains; + bfd_vma * mipsxlat; + bfd_vma gnusymidx; + char program_interpreter[PATH_MAX]; + bfd_vma dynamic_info[DT_ENCODING]; + bfd_vma dynamic_info_DT_GNU_HASH; + bfd_vma dynamic_info_DT_MIPS_XHASH; + elf_section_list * symtab_shndx_list; + size_t group_count; + struct group * section_groups; + struct group ** section_headers_groups; + /* A dynamic array of flags indicating for which sections a dump of + some kind has been requested. It is reset on a per-object file + basis and then initialised from the cmdline_dump_sects array, + the results of interpreting the -w switch, and the + dump_sects_byname list. */ + struct dump_data dump; +} Filedata; /* How to print a vma value. */ typedef enum print_mode @@ -325,10 +342,15 @@ static const char * get_symbol_version_string (is_32bit_elf ? get_32bit_elf_symbols (file, section, sym_count) \ : get_64bit_elf_symbols (file, section, sym_count)) -#define VALID_DYNAMIC_NAME(offset) ((dynamic_strings != NULL) && (offset < dynamic_strings_length)) +#define VALID_SYMBOL_NAME(strtab, strtab_size, offset) \ + (strtab != NULL && offset < strtab_size) +#define VALID_DYNAMIC_NAME(filedata, offset) \ + VALID_SYMBOL_NAME (filedata->dynamic_strings, \ + filedata->dynamic_strings_length, offset) /* GET_DYNAMIC_NAME asssumes that VALID_DYNAMIC_NAME has already been called and verified that the string exists. */ -#define GET_DYNAMIC_NAME(offset) (dynamic_strings + offset) +#define GET_DYNAMIC_NAME(filedata, offset) \ + (filedata->dynamic_strings + offset) #define REMOVE_ARCH_BITS(ADDR) \ do \ @@ -339,8 +361,8 @@ static const char * get_symbol_version_string while (0) /* Get the correct GNU hash section name. */ -#define GNU_HASH_SECTION_NAME \ - dynamic_info_DT_MIPS_XHASH ? ".MIPS.xhash" : ".gnu.hash" +#define GNU_HASH_SECTION_NAME(filedata) \ + filedata->dynamic_info_DT_MIPS_XHASH ? ".MIPS.xhash" : ".gnu.hash" /* Print a BFD_VMA to an internal buffer, for use in error messages. BFD_FMA_FMT can't be used in translated strings. */ @@ -414,9 +436,9 @@ get_data (void * var, /* Be kind to memory checkers (eg valgrind, address sanitizer) by not attempting to allocate memory when the read is bound to fail. */ - if (archive_file_offset > filedata->file_size - || offset > filedata->file_size - archive_file_offset - || amt > filedata->file_size - archive_file_offset - offset) + if (filedata->archive_file_offset > filedata->file_size + || offset > filedata->file_size - filedata->archive_file_offset + || amt > filedata->file_size - filedata->archive_file_offset - offset) { if (reason) error (_("Reading %s bytes extends past end of file for %s\n"), @@ -424,11 +446,12 @@ get_data (void * var, return NULL; } - if (fseek (filedata->handle, archive_file_offset + offset, SEEK_SET)) + if (fseek (filedata->handle, filedata->archive_file_offset + offset, + SEEK_SET)) { if (reason) error (_("Unable to seek to 0x%lx for %s\n"), - archive_file_offset + offset, reason); + filedata->archive_file_offset + offset, reason); return NULL; } @@ -1629,7 +1652,8 @@ dump_relocations (Filedata * filedata, { if (symtab == NULL || symtab_index >= nsyms) { - error (_(" bad symbol index: %08lx in reloc"), (unsigned long) symtab_index); + error (_(" bad symbol index: %08lx in reloc\n"), + (unsigned long) symtab_index); res = FALSE; } else @@ -1733,7 +1757,8 @@ dump_relocations (Filedata * filedata, printf (_(""), psym->st_name); else if (psym->st_name >= strtablen) { - error (_(""), psym->st_name); + error (_("\n"), + psym->st_name); res = FALSE; } else @@ -2276,7 +2301,7 @@ get_dynamic_type (Filedata * filedata, unsigned long type) static char * get_file_type (unsigned e_type) { - static char buff[32]; + static char buff[64]; switch (e_type) { @@ -3767,6 +3792,7 @@ get_machine_flags (Filedata * filedata, unsigned e_flags, unsigned e_machine) case EF_Z80_MACH_EZ80_Z80: strcat (buf, ", EZ80"); break; case EF_Z80_MACH_EZ80_ADL: strcat (buf, ", EZ80, ADL"); break; case EF_Z80_MACH_GBZ80: strcat (buf, ", GBZ80"); break; + case EF_Z80_MACH_Z80N: strcat (buf, ", Z80N"); break; default: strcat (buf, _(", unknown")); break; } @@ -4456,6 +4482,8 @@ static struct option options[] = {"relocs", no_argument, 0, 'r'}, {"notes", no_argument, 0, 'n'}, {"dynamic", no_argument, 0, 'd'}, + {"lint", no_argument, 0, 'L'}, + {"enable-checks", no_argument, 0, 'L'}, {"arch-specific", no_argument, 0, 'A'}, {"version-info", no_argument, 0, 'V'}, {"use-dynamic", no_argument, 0, 'D'}, @@ -4503,7 +4531,7 @@ usage (FILE * stream) -e --headers Equivalent to: -h -l -S\n\ -s --syms Display the symbol table\n\ --symbols An alias for --syms\n\ - --dyn-syms Display the dynamic symbol table\n\ + --dyn-syms Display the dynamic symbol table\n\ -n --notes Display the core notes (if present)\n\ -r --relocs Display the relocations (if present)\n\ -u --unwind Display the unwind info (if present)\n\ @@ -4512,6 +4540,7 @@ usage (FILE * stream) -A --arch-specific Display architecture specific information (if any)\n\ -c --archive-index Display the symbol/file index in an archive\n\ -D --use-dynamic Use the dynamic section info when displaying symbols\n\ + -L --lint|--enable-checks Display warning messages for possible problems\n\ -x --hex-dump=\n\ Dump the contents of section as bytes\n\ -p --string-dump=\n\ @@ -4562,9 +4591,10 @@ usage (FILE * stream) the first time. */ static void -request_dump_bynumber (Filedata * filedata, unsigned int section, dump_type type) +request_dump_bynumber (struct dump_data *dumpdata, + unsigned int section, dump_type type) { - if (section >= filedata->num_dump_sects) + if (section >= dumpdata->num_dump_sects) { dump_type * new_dump_sects; @@ -4575,22 +4605,22 @@ request_dump_bynumber (Filedata * filedata, unsigned int section, dump_type type error (_("Out of memory allocating dump request table.\n")); else { - if (filedata->dump_sects) + if (dumpdata->dump_sects) { /* Copy current flag settings. */ - memcpy (new_dump_sects, filedata->dump_sects, - filedata->num_dump_sects * sizeof (* new_dump_sects)); + memcpy (new_dump_sects, dumpdata->dump_sects, + dumpdata->num_dump_sects * sizeof (* new_dump_sects)); - free (filedata->dump_sects); + free (dumpdata->dump_sects); } - filedata->dump_sects = new_dump_sects; - filedata->num_dump_sects = section + 1; + dumpdata->dump_sects = new_dump_sects; + dumpdata->num_dump_sects = section + 1; } } - if (filedata->dump_sects) - filedata->dump_sects[section] |= type; + if (dumpdata->dump_sects) + dumpdata->dump_sects[section] |= type; } /* Request a dump by section name. */ @@ -4616,7 +4646,7 @@ request_dump_byname (const char * section, dump_type type) } static inline void -request_dump (Filedata * filedata, dump_type type) +request_dump (struct dump_data *dumpdata, dump_type type) { int section; char * cp; @@ -4625,13 +4655,13 @@ request_dump (Filedata * filedata, dump_type type) section = strtoul (optarg, & cp, 0); if (! *cp && section >= 0) - request_dump_bynumber (filedata, section, type); + request_dump_bynumber (dumpdata, section, type); else request_dump_byname (optarg, type); } static void -parse_args (Filedata * filedata, int argc, char ** argv) +parse_args (struct dump_data *dumpdata, int argc, char ** argv) { int c; @@ -4639,7 +4669,7 @@ parse_args (Filedata * filedata, int argc, char ** argv) usage (stderr); while ((c = getopt_long - (argc, argv, "ADHINR:SVWacdeghi:lnp:rstuvw::x:z", options, NULL)) != EOF) + (argc, argv, "ADHILNR:SVWacdeghi:lnp:rstuvw::x:z", options, NULL)) != EOF) { switch (c) { @@ -4713,14 +4743,17 @@ parse_args (Filedata * filedata, int argc, char ** argv) case 'c': do_archive_index = TRUE; break; + case 'L': + do_checks = TRUE; + break; case 'x': - request_dump (filedata, HEX_DUMP); + request_dump (dumpdata, HEX_DUMP); break; case 'p': - request_dump (filedata, STRING_DUMP); + request_dump (dumpdata, STRING_DUMP); break; case 'R': - request_dump (filedata, RELOC_DUMP); + request_dump (dumpdata, RELOC_DUMP); break; case 'z': decompress_dumps = TRUE; @@ -4767,7 +4800,7 @@ parse_args (Filedata * filedata, int argc, char ** argv) break; case OPTION_CTF_DUMP: do_ctf = TRUE; - request_dump (filedata, CTF_DUMP); + request_dump (dumpdata, CTF_DUMP); break; case OPTION_CTF_SYMBOLS: dump_ctf_symtab_name = strdup (optarg); @@ -4783,7 +4816,7 @@ parse_args (Filedata * filedata, int argc, char ** argv) break; #ifdef SUPPORT_DISASSEMBLY case 'i': - request_dump (filedata, DISASS_DUMP); + request_dump (dumpdata, DISASS_DUMP); break; #endif case 'v': @@ -4809,7 +4842,18 @@ parse_args (Filedata * filedata, int argc, char ** argv) && !do_histogram && !do_debugging && !do_arch && !do_notes && !do_section_groups && !do_archive_index && !do_dyn_syms) - usage (stderr); + { + if (do_checks) + { + check_all = TRUE; + do_dynamic = do_syms = do_reloc = do_unwind = do_sections = TRUE; + do_segments = do_header = do_dump = do_version = TRUE; + do_histogram = do_debugging = do_arch = do_notes = TRUE; + do_section_groups = do_archive_index = do_dyn_syms = TRUE; + } + else + usage (stderr); + } } static const char * @@ -5110,8 +5154,8 @@ process_program_headers (Filedata * filedata) unsigned int i; Elf_Internal_Phdr * previous_load = NULL; - dynamic_addr = 0; - dynamic_size = 0; + filedata->dynamic_addr = 0; + filedata->dynamic_size = 0; if (filedata->file_header.e_phnum == 0) { @@ -5288,13 +5332,13 @@ process_program_headers (Filedata * filedata) break; case PT_DYNAMIC: - if (dynamic_addr) + if (filedata->dynamic_addr) error (_("more than one dynamic segment\n")); /* By default, assume that the .dynamic section is the first section in the DYNAMIC segment. */ - dynamic_addr = segment->p_offset; - dynamic_size = segment->p_filesz; + filedata->dynamic_addr = segment->p_offset; + filedata->dynamic_size = segment->p_filesz; /* Try to locate the .dynamic section. If there is a section header table, we can easily locate it. */ @@ -5314,36 +5358,38 @@ process_program_headers (Filedata * filedata) if (sec->sh_type == SHT_NOBITS) { - dynamic_size = 0; + filedata->dynamic_size = 0; break; } - dynamic_addr = sec->sh_offset; - dynamic_size = sec->sh_size; + filedata->dynamic_addr = sec->sh_offset; + filedata->dynamic_size = sec->sh_size; - if (dynamic_addr < segment->p_offset - || dynamic_addr > segment->p_offset + segment->p_filesz) - warn (_("the .dynamic section is not contained" - " within the dynamic segment\n")); - else if (dynamic_addr > segment->p_offset) - warn (_("the .dynamic section is not the first section" - " in the dynamic segment.\n")); + /* The PT_DYNAMIC segment, which is used by the run-time + loader, should exactly match the .dynamic section. */ + if (do_checks + && (filedata->dynamic_addr != segment->p_offset + || filedata->dynamic_size != segment->p_filesz)) + warn (_("\ +the .dynamic section is not the same as the dynamic segment\n")); } /* PR binutils/17512: Avoid corrupt dynamic section info in the segment. Check this after matching against the section headers so we don't warn on debuginfo file (which have NOBITS .dynamic sections). */ - if (dynamic_addr > filedata->file_size - || dynamic_size > filedata->file_size - dynamic_addr) + if (filedata->dynamic_addr > filedata->file_size + || (filedata->dynamic_size + > filedata->file_size - filedata->dynamic_addr)) { error (_("the dynamic segment offset + size exceeds the size of the file\n")); - dynamic_addr = dynamic_size = 0; + filedata->dynamic_addr = filedata->dynamic_size = 0; } break; case PT_INTERP: - if (fseek (filedata->handle, archive_file_offset + (long) segment->p_offset, + if (fseek (filedata->handle, + filedata->archive_file_offset + (long) segment->p_offset, SEEK_SET)) error (_("Unable to find program interpreter name\n")); else @@ -5354,13 +5400,14 @@ process_program_headers (Filedata * filedata) if (ret >= (int) sizeof (fmt) || ret < 0) error (_("Internal error: failed to create format string to display program interpreter\n")); - program_interpreter[0] = 0; - if (fscanf (filedata->handle, fmt, program_interpreter) <= 0) + filedata->program_interpreter[0] = 0; + if (fscanf (filedata->handle, fmt, + filedata->program_interpreter) <= 0) error (_("Unable to read program interpreter name\n")); if (do_segments) printf (_(" [Requesting program interpreter: %s]\n"), - program_interpreter); + filedata->program_interpreter); } break; } @@ -5616,7 +5663,7 @@ get_32bit_elf_symbols (Filedata * filedata, goto exit_point; shndx = NULL; - for (entry = symtab_shndx_list; entry != NULL; entry = entry->next) + for (entry = filedata->symtab_shndx_list; entry != NULL; entry = entry->next) { if (entry->hdr->sh_link != (unsigned long) (section - filedata->section_headers)) continue; @@ -5733,7 +5780,7 @@ get_64bit_elf_symbols (Filedata * filedata, goto exit_point; shndx = NULL; - for (entry = symtab_shndx_list; entry != NULL; entry = entry->next) + for (entry = filedata->symtab_shndx_list; entry != NULL; entry = entry->next) { if (entry->hdr->sh_link != (unsigned long) (section - filedata->section_headers)) continue; @@ -6073,7 +6120,7 @@ get_elf_section_flags (Filedata * filedata, bfd_vma sh_flags) return buff; } -static unsigned int +static unsigned int ATTRIBUTE_WARN_UNUSED_RESULT get_compression_header (Elf_Internal_Chdr *chdr, unsigned char *buf, bfd_size_type size) { if (is_32bit_elf) @@ -6114,7 +6161,22 @@ process_section_headers (Filedata * filedata) Elf_Internal_Shdr * section; unsigned int i; + free (filedata->section_headers); filedata->section_headers = NULL; + free (filedata->dynamic_symbols); + filedata->dynamic_symbols = NULL; + filedata->num_dynamic_syms = 0; + free (filedata->dynamic_strings); + filedata->dynamic_strings = NULL; + filedata->dynamic_strings_length = 0; + free (filedata->dynamic_syminfo); + filedata->dynamic_syminfo = NULL; + while (filedata->symtab_shndx_list != NULL) + { + elf_section_list *next = filedata->symtab_shndx_list->next; + free (filedata->symtab_shndx_list); + filedata->symtab_shndx_list = next; + } if (filedata->file_header.e_shnum == 0) { @@ -6169,11 +6231,6 @@ process_section_headers (Filedata * filedata) /* Scan the sections for the dynamic symbol table and dynamic string table and debug sections. */ - dynamic_symbols = NULL; - dynamic_strings = NULL; - dynamic_syminfo = NULL; - symtab_shndx_list = NULL; - eh_addr_size = is_32bit_elf ? 4 : 8; switch (filedata->file_header.e_machine) { @@ -6241,7 +6298,7 @@ process_section_headers (Filedata * filedata) while (0) #define CHECK_ENTSIZE(section, i, type) \ - CHECK_ENTSIZE_VALUES (section, i, sizeof (Elf32_External_##type), \ + CHECK_ENTSIZE_VALUES (section, i, sizeof (Elf32_External_##type), \ sizeof (Elf64_External_##type)) for (i = 0, section = filedata->section_headers; @@ -6250,54 +6307,91 @@ process_section_headers (Filedata * filedata) { char * name = SECTION_NAME (section); - if (section->sh_type == SHT_DYNSYM) + /* Run some sanity checks on the headers and + possibly fill in some file data as well. */ + switch (section->sh_type) { - if (dynamic_symbols != NULL) + case SHT_DYNSYM: + if (filedata->dynamic_symbols != NULL) { error (_("File contains multiple dynamic symbol tables\n")); continue; } CHECK_ENTSIZE (section, i, Sym); - dynamic_symbols = GET_ELF_SYMBOLS (filedata, section, & num_dynamic_syms); - } - else if (section->sh_type == SHT_STRTAB - && streq (name, ".dynstr")) - { - if (dynamic_strings != NULL) + filedata->dynamic_symbols + = GET_ELF_SYMBOLS (filedata, section, &filedata->num_dynamic_syms); + filedata->dynamic_symtab_section = section; + break; + + case SHT_STRTAB: + if (streq (name, ".dynstr")) { - error (_("File contains multiple dynamic string tables\n")); - continue; + if (filedata->dynamic_strings != NULL) + { + error (_("File contains multiple dynamic string tables\n")); + continue; + } + + filedata->dynamic_strings + = (char *) get_data (NULL, filedata, section->sh_offset, + 1, section->sh_size, _("dynamic strings")); + filedata->dynamic_strings_length + = filedata->dynamic_strings == NULL ? 0 : section->sh_size; + filedata->dynamic_strtab_section = section; } + break; + + case SHT_SYMTAB_SHNDX: + { + elf_section_list * entry = xmalloc (sizeof * entry); + + entry->hdr = section; + entry->next = filedata->symtab_shndx_list; + filedata->symtab_shndx_list = entry; + } + break; + + case SHT_SYMTAB: + CHECK_ENTSIZE (section, i, Sym); + break; + + case SHT_GROUP: + CHECK_ENTSIZE_VALUES (section, i, GRP_ENTRY_SIZE, GRP_ENTRY_SIZE); + break; + + case SHT_REL: + CHECK_ENTSIZE (section, i, Rel); + if (do_checks && section->sh_size == 0) + warn (_("Section '%s': zero-sized relocation section\n"), name); + break; + + case SHT_RELA: + CHECK_ENTSIZE (section, i, Rela); + if (do_checks && section->sh_size == 0) + warn (_("Section '%s': zero-sized relocation section\n"), name); + break; - dynamic_strings = (char *) get_data (NULL, filedata, section->sh_offset, - 1, section->sh_size, - _("dynamic strings")); - dynamic_strings_length = dynamic_strings == NULL ? 0 : section->sh_size; - } - else if (section->sh_type == SHT_SYMTAB_SHNDX) - { - 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); - else if (section->sh_type == SHT_GROUP) - CHECK_ENTSIZE_VALUES (section, i, GRP_ENTRY_SIZE, GRP_ENTRY_SIZE); - else if (section->sh_type == SHT_REL) - CHECK_ENTSIZE (section, i, Rel); - else if (section->sh_type == SHT_RELA) - CHECK_ENTSIZE (section, i, Rela); - else if ((do_debugging || do_debug_info || do_debug_abbrevs - || do_debug_lines || do_debug_pubnames || do_debug_pubtypes - || do_debug_aranges || do_debug_frames || do_debug_macinfo - || do_debug_str || do_debug_loc || do_debug_ranges - || do_debug_addr || do_debug_cu_index || do_debug_links) - && (const_strneq (name, ".debug_") - || const_strneq (name, ".zdebug_"))) + case SHT_NOTE: + case SHT_PROGBITS: + /* Having a zero sized section is not illegal according to the + ELF standard, but it might be an indication that something + is wrong. So issue a warning if we are running in lint mode. */ + if (do_checks && section->sh_size == 0) + warn (_("Section '%s': has a size of zero - is this intended ?\n"), name); + break; + + default: + break; + } + + if ((do_debugging || do_debug_info || do_debug_abbrevs + || do_debug_lines || do_debug_pubnames || do_debug_pubtypes + || do_debug_aranges || do_debug_frames || do_debug_macinfo + || do_debug_str || do_debug_loc || do_debug_ranges + || do_debug_addr || do_debug_cu_index || do_debug_links) + && (const_strneq (name, ".debug_") + || const_strneq (name, ".zdebug_"))) { if (name[1] == 'z') name += sizeof (".zdebug_") - 1; @@ -6327,17 +6421,17 @@ process_section_headers (Filedata * filedata) || (do_debug_cu_index && const_strneq (name, "cu_index")) || (do_debug_cu_index && const_strneq (name, "tu_index")) ) - request_dump_bynumber (filedata, i, DEBUG_DUMP); + request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP); } /* Linkonce section to be combined with .debug_info at link time. */ else if ((do_debugging || do_debug_info) && const_strneq (name, ".gnu.linkonce.wi.")) - request_dump_bynumber (filedata, i, DEBUG_DUMP); + request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP); else if (do_debug_frames && streq (name, ".eh_frame")) - request_dump_bynumber (filedata, i, DEBUG_DUMP); + request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP); else if (do_gdb_index && (streq (name, ".gdb_index") || streq (name, ".debug_names"))) - request_dump_bynumber (filedata, i, DEBUG_DUMP); + request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP); /* Trace sections for Itanium VMS. */ else if ((do_debugging || do_trace_info || do_trace_abbrevs || do_trace_aranges) @@ -6350,12 +6444,12 @@ process_section_headers (Filedata * filedata) || (do_trace_abbrevs && streq (name, "abbrev")) || (do_trace_aranges && streq (name, "aranges")) ) - request_dump_bynumber (filedata, i, DEBUG_DUMP); + request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP); } else if ((do_debugging || do_debug_links) && (const_strneq (name, ".gnu_debuglink") || const_strneq (name, ".gnu_debugaltlink"))) - request_dump_bynumber (filedata, i, DEBUG_DUMP); + request_dump_bynumber (&filedata->dump, i, DEBUG_DUMP); } if (! do_sections) @@ -6714,15 +6808,18 @@ process_section_headers (Filedata * filedata) { Elf_Internal_Chdr chdr; - (void) get_compression_header (&chdr, buf, sizeof (buf)); - - if (chdr.ch_type == ELFCOMPRESS_ZLIB) - printf (" ZLIB, "); + if (get_compression_header (&chdr, buf, sizeof (buf)) == 0) + printf (_(" []\n")); else - printf (_(" [: 0x%x], "), - chdr.ch_type); - print_vma (chdr.ch_size, LONG_HEX); - printf (", %lu\n", (unsigned long) chdr.ch_addralign); + { + 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); + } } } } @@ -6751,6 +6848,47 @@ process_section_headers (Filedata * filedata) return TRUE; } +static bfd_boolean +get_symtab (Filedata *filedata, Elf_Internal_Shdr *symsec, + Elf_Internal_Sym **symtab, unsigned long *nsyms, + char **strtab, unsigned long *strtablen) +{ + *strtab = NULL; + *strtablen = 0; + *symtab = GET_ELF_SYMBOLS (filedata, symsec, nsyms); + + if (*symtab == NULL) + return FALSE; + + if (symsec->sh_link != 0) + { + Elf_Internal_Shdr *strsec; + + if (symsec->sh_link >= filedata->file_header.e_shnum) + { + error (_("Bad sh_link in symbol table section\n")); + free (*symtab); + *symtab = NULL; + *nsyms = 0; + return FALSE; + } + + strsec = filedata->section_headers + symsec->sh_link; + + *strtab = (char *) get_data (NULL, filedata, strsec->sh_offset, + 1, strsec->sh_size, _("string table")); + if (*strtab == NULL) + { + free (*symtab); + *symtab = NULL; + *nsyms = 0; + return FALSE; + } + *strtablen = strsec->sh_size; + } + return TRUE; +} + static const char * get_group_flags (unsigned int flags) { @@ -6761,25 +6899,13 @@ get_group_flags (unsigned int flags) else if (flags == GRP_COMDAT) return "COMDAT "; - snprintf (buff, 14, _("[0x%x: "), flags); - - flags &= ~ GRP_COMDAT; - if (flags & GRP_MASKOS) - { - strcat (buff, ""); - flags &= ~ GRP_MASKOS; - } - - if (flags & GRP_MASKPROC) - { - strcat (buff, ""); - flags &= ~ GRP_MASKPROC; - } - - if (flags) - strcat (buff, ""); + snprintf (buff, sizeof buff, "[0x%x: %s%s%s]", + flags, + flags & GRP_MASKOS ? _("") : "", + flags & GRP_MASKPROC ? _("") : "", + (flags & ~(GRP_COMDAT | GRP_MASKOS | GRP_MASKPROC) + ? _("") : "")); - strcat (buff, "]"); return buff; } @@ -6815,10 +6941,11 @@ process_section_groups (Filedata * filedata) return FALSE; } - section_headers_groups = (struct group **) calloc (filedata->file_header.e_shnum, - sizeof (struct group *)); + filedata->section_headers_groups + = (struct group **) calloc (filedata->file_header.e_shnum, + sizeof (struct group *)); - if (section_headers_groups == NULL) + if (filedata->section_headers_groups == NULL) { error (_("Out of memory reading %u section group headers\n"), filedata->file_header.e_shnum); @@ -6826,14 +6953,14 @@ process_section_groups (Filedata * filedata) } /* Scan the sections for the group section. */ - group_count = 0; + filedata->group_count = 0; for (i = 0, section = filedata->section_headers; i < filedata->file_header.e_shnum; i++, section++) if (section->sh_type == SHT_GROUP) - group_count++; + filedata->group_count++; - if (group_count == 0) + if (filedata->group_count == 0) { if (do_section_groups) printf (_("\nThere are no section groups in this file.\n")); @@ -6841,12 +6968,13 @@ process_section_groups (Filedata * filedata) return TRUE; } - section_groups = (struct group *) calloc (group_count, sizeof (struct group)); + filedata->section_groups = (struct group *) calloc (filedata->group_count, + sizeof (struct group)); - if (section_groups == NULL) + if (filedata->section_groups == NULL) { error (_("Out of memory reading %lu groups\n"), - (unsigned long) group_count); + (unsigned long) filedata->group_count); return FALSE; } @@ -6856,7 +6984,7 @@ process_section_groups (Filedata * filedata) num_syms = 0; strtab = NULL; strtab_size = 0; - for (i = 0, section = filedata->section_headers, group = section_groups; + for (i = 0, section = filedata->section_headers, group = filedata->section_groups; i < filedata->file_header.e_shnum; i++, section++) { @@ -6882,8 +7010,7 @@ process_section_groups (Filedata * filedata) if (symtab_sec != sec) { symtab_sec = sec; - if (symtab) - free (symtab); + free (symtab); symtab = GET_ELF_SYMBOLS (filedata, symtab_sec, & num_syms); } @@ -6912,8 +7039,7 @@ process_section_groups (Filedata * filedata) group_name = SECTION_NAME (filedata->section_headers + sym->st_shndx); strtab_sec = NULL; - if (strtab) - free (strtab); + free (strtab); strtab = NULL; strtab_size = 0; } @@ -6923,8 +7049,7 @@ process_section_groups (Filedata * filedata) if (symtab_sec->sh_link >= filedata->file_header.e_shnum) { strtab_sec = NULL; - if (strtab) - free (strtab); + free (strtab); strtab = NULL; strtab_size = 0; } @@ -6932,8 +7057,7 @@ process_section_groups (Filedata * filedata) != (sec = filedata->section_headers + symtab_sec->sh_link)) { strtab_sec = sec; - if (strtab) - free (strtab); + free (strtab); strtab = (char *) get_data (NULL, filedata, strtab_sec->sh_offset, 1, strtab_sec->sh_size, @@ -6996,7 +7120,7 @@ process_section_groups (Filedata * filedata) continue; } - if (section_headers_groups [entry] != NULL) + if (filedata->section_headers_groups [entry] != NULL) { if (entry) { @@ -7006,7 +7130,7 @@ process_section_groups (Filedata * filedata) { error (_("section [%5u] in group section [%5u] already in group section [%5u]\n"), entry, i, - section_headers_groups [entry]->group_index); + filedata->section_headers_groups [entry]->group_index); if (num_errs == 10) warn (_("Further error messages about already contained group sections suppressed\n")); } @@ -7021,13 +7145,13 @@ process_section_groups (Filedata * filedata) if (!warned) { error (_("section 0 in group section [%5u]\n"), - section_headers_groups [entry]->group_index); + filedata->section_headers_groups [entry]->group_index); warned = TRUE; } } } - section_headers_groups [entry] = group; + filedata->section_headers_groups [entry] = group; if (do_section_groups) { @@ -7041,17 +7165,14 @@ process_section_groups (Filedata * filedata) group->root = g; } - if (start) - free (start); + free (start); group++; } } - if (symtab) - free (symtab); - if (strtab) - free (strtab); + free (symtab); + free (strtab); return TRUE; } @@ -7087,8 +7208,9 @@ dump_ia64_vms_dynamic_fixups (Filedata * filedata, long i; const char * lib_name; - imfs = get_data (NULL, filedata, dynamic_addr + fixup->fixup_rela_off, - 1, fixup->fixup_rela_cnt * sizeof (*imfs), + imfs = get_data (NULL, filedata, + filedata->dynamic_addr + fixup->fixup_rela_off, + sizeof (*imfs), fixup->fixup_rela_cnt, _("dynamic section image fixups")); if (!imfs) return FALSE; @@ -7101,6 +7223,7 @@ dump_ia64_vms_dynamic_fixups (Filedata * filedata, (unsigned long) fixup->needed); lib_name = "???"; } + printf (_("\nImage fixups for needed library #%d: %s - ident: %lx\n"), (int) fixup->fixup_needed, lib_name, (long) fixup->needed_ident); printf @@ -7135,8 +7258,9 @@ dump_ia64_vms_dynamic_relocs (Filedata * filedata, struct ia64_vms_dynimgrela *i Elf64_External_VMS_IMAGE_RELA *imrs; long i; - imrs = get_data (NULL, filedata, dynamic_addr + imgrela->img_rela_off, - 1, imgrela->img_rela_cnt * sizeof (*imrs), + imrs = get_data (NULL, filedata, + filedata->dynamic_addr + imgrela->img_rela_off, + sizeof (*imrs), imgrela->img_rela_cnt, _("dynamic section image relocations")); if (!imrs) return FALSE; @@ -7186,8 +7310,8 @@ process_ia64_vms_dynamic_relocs (Filedata * filedata) memset (&imgrela, 0, sizeof (imgrela)); /* Note: the order of the entries is specified by the OpenVMS specs. */ - for (entry = dynamic_section; - entry < dynamic_section + dynamic_nent; + for (entry = filedata->dynamic_section; + entry < filedata->dynamic_section + filedata->dynamic_nent; entry++) { switch (entry->d_tag) @@ -7198,8 +7322,11 @@ process_ia64_vms_dynamic_relocs (Filedata * filedata) case DT_STRSZ: strtab_sz = entry->d_un.d_val; if (strtab == NULL) - strtab = get_data (NULL, filedata, dynamic_addr + strtab_off, + strtab = get_data (NULL, filedata, + filedata->dynamic_addr + strtab_off, 1, strtab_sz, _("dynamic string section")); + if (strtab == NULL) + strtab_sz = 0; break; case DT_IA_64_VMS_NEEDED_IDENT: @@ -7233,8 +7360,7 @@ process_ia64_vms_dynamic_relocs (Filedata * filedata) } } - if (strtab != NULL) - free (strtab); + free (strtab); return res; } @@ -7277,8 +7403,8 @@ process_relocs (Filedata * filedata) { is_rela = dynamic_relocations [i].rela; name = dynamic_relocations [i].name; - rel_size = dynamic_info [dynamic_relocations [i].size]; - rel_offset = dynamic_info [dynamic_relocations [i].reloc]; + rel_size = filedata->dynamic_info[dynamic_relocations [i].size]; + rel_offset = filedata->dynamic_info[dynamic_relocations [i].reloc]; if (rel_size) has_dynamic_reloc = TRUE; @@ -7286,7 +7412,7 @@ process_relocs (Filedata * filedata) if (is_rela == UNKNOWN) { if (dynamic_relocations [i].reloc == DT_JMPREL) - switch (dynamic_info[DT_PLTREL]) + switch (filedata->dynamic_info[DT_PLTREL]) { case DT_REL: is_rela = FALSE; @@ -7306,8 +7432,10 @@ process_relocs (Filedata * filedata) dump_relocations (filedata, offset_from_vma (filedata, rel_offset, rel_size), rel_size, - dynamic_symbols, num_dynamic_syms, - dynamic_strings, dynamic_strings_length, + filedata->dynamic_symbols, + filedata->num_dynamic_syms, + filedata->dynamic_strings, + filedata->dynamic_strings_length, is_rela, TRUE /* is_dynamic */); } } @@ -7338,7 +7466,6 @@ process_relocs (Filedata * filedata) if (rel_size) { - Elf_Internal_Shdr * strsec; int is_rela; unsigned long num_rela; @@ -7371,28 +7498,15 @@ process_relocs (Filedata * filedata) && symsec->sh_type != SHT_DYNSYM) continue; - symtab = GET_ELF_SYMBOLS (filedata, symsec, & nsyms); - - if (symtab == NULL) + if (!get_symtab (filedata, symsec, + &symtab, &nsyms, &strtab, &strtablen)) continue; - if (symsec->sh_link != 0 - && symsec->sh_link < filedata->file_header.e_shnum) - { - strsec = filedata->section_headers + symsec->sh_link; - - strtab = (char *) get_data (NULL, filedata, strsec->sh_offset, - 1, strsec->sh_size, - _("string table")); - strtablen = strtab == NULL ? 0 : strsec->sh_size; - } - dump_relocations (filedata, rel_offset, rel_size, symtab, nsyms, strtab, strtablen, is_rela, symsec->sh_type == SHT_DYNSYM); - if (strtab) - free (strtab); + free (strtab); free (symtab); } else @@ -7409,7 +7523,7 @@ process_relocs (Filedata * filedata) /* Users sometimes forget the -D option, so try to be helpful. */ for (i = 0; i < ARRAY_SIZE (dynamic_relocations); i++) { - if (dynamic_info [dynamic_relocations [i].size]) + if (filedata->dynamic_info[dynamic_relocations [i].size]) { printf (_("\nThere are no static relocations in this file.")); printf (_("\nTo see the dynamic relocations add --use-dynamic to the command line.\n")); @@ -7787,7 +7901,6 @@ ia64_process_unwind (Filedata * filedata) { Elf_Internal_Shdr * sec; Elf_Internal_Shdr * unwsec = NULL; - Elf_Internal_Shdr * strsec; unsigned long i, unwcount = 0, unwstart = 0; struct ia64_unw_aux_info aux; bfd_boolean res = TRUE; @@ -7796,22 +7909,19 @@ ia64_process_unwind (Filedata * filedata) for (i = 0, sec = filedata->section_headers; i < filedata->file_header.e_shnum; ++i, ++sec) { - if (sec->sh_type == SHT_SYMTAB - && sec->sh_link < filedata->file_header.e_shnum) + if (sec->sh_type == SHT_SYMTAB) { - aux.symtab = GET_ELF_SYMBOLS (filedata, sec, & aux.nsyms); - - strsec = filedata->section_headers + sec->sh_link; - if (aux.strtab != NULL) + if (aux.symtab) { - error (_("Multiple auxillary string tables encountered\n")); + error (_("Multiple symbol tables encountered\n")); + free (aux.symtab); + aux.symtab = NULL; free (aux.strtab); - res = FALSE; + aux.strtab = NULL; } - aux.strtab = (char *) get_data (NULL, filedata, strsec->sh_offset, - 1, strsec->sh_size, - _("string table")); - aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0; + if (!get_symtab (filedata, sec, &aux.symtab, &aux.nsyms, + &aux.strtab, &aux.strtab_size)) + return FALSE; } else if (sec->sh_type == SHT_IA_64_UNWIND) unwcount++; @@ -7844,12 +7954,12 @@ ia64_process_unwind (Filedata * filedata) /* We need to find which section group it is in. */ struct group_list * g; - if (section_headers_groups == NULL - || section_headers_groups [i] == NULL) + if (filedata->section_headers_groups == NULL + || filedata->section_headers_groups[i] == NULL) i = filedata->file_header.e_shnum; else { - g = section_headers_groups [i]->root; + g = filedata->section_headers_groups[i]->root; for (; g != NULL; g = g->next) { @@ -7922,19 +8032,15 @@ ia64_process_unwind (Filedata * filedata) && aux.table_len > 0) dump_ia64_unwind (filedata, & aux); - if (aux.table) - free ((char *) aux.table); - if (aux.info) - free ((char *) aux.info); + free ((char *) aux.table); + free ((char *) aux.info); aux.table = NULL; aux.info = NULL; } } - if (aux.symtab) - free (aux.symtab); - if (aux.strtab) - free ((char *) aux.strtab); + free (aux.symtab); + free ((char *) aux.strtab); return res; } @@ -8248,7 +8354,6 @@ hppa_process_unwind (Filedata * filedata) { struct hppa_unw_aux_info aux; Elf_Internal_Shdr * unwsec = NULL; - Elf_Internal_Shdr * strsec; Elf_Internal_Shdr * sec; unsigned long i; bfd_boolean res = TRUE; @@ -8260,22 +8365,19 @@ hppa_process_unwind (Filedata * filedata) for (i = 0, sec = filedata->section_headers; i < filedata->file_header.e_shnum; ++i, ++sec) { - if (sec->sh_type == SHT_SYMTAB - && sec->sh_link < filedata->file_header.e_shnum) + if (sec->sh_type == SHT_SYMTAB) { - aux.symtab = GET_ELF_SYMBOLS (filedata, sec, & aux.nsyms); - - strsec = filedata->section_headers + sec->sh_link; - if (aux.strtab != NULL) + if (aux.symtab) { - error (_("Multiple auxillary string tables encountered\n")); + error (_("Multiple symbol tables encountered\n")); + free (aux.symtab); + aux.symtab = NULL; free (aux.strtab); - res = FALSE; + aux.strtab = NULL; } - aux.strtab = (char *) get_data (NULL, filedata, strsec->sh_offset, - 1, strsec->sh_size, - _("string table")); - aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0; + if (!get_symtab (filedata, sec, &aux.symtab, &aux.nsyms, + &aux.strtab, &aux.strtab_size)) + return FALSE; } else if (streq (SECTION_NAME (sec), ".PARISC.unwind")) unwsec = sec; @@ -8308,16 +8410,13 @@ hppa_process_unwind (Filedata * filedata) res = FALSE; } - if (aux.table) - free ((char *) aux.table); + free ((char *) aux.table); aux.table = NULL; } } - if (aux.symtab) - free (aux.symtab); - if (aux.strtab) - free ((char *) aux.strtab); + free (aux.symtab); + free ((char *) aux.strtab); return res; } @@ -8377,11 +8476,8 @@ arm_print_vma_and_name (Filedata * filedata, static void arm_free_section (struct arm_section *arm_sec) { - if (arm_sec->data != NULL) - free (arm_sec->data); - - if (arm_sec->rela != NULL) - free (arm_sec->rela); + free (arm_sec->data); + free (arm_sec->rela); } /* 1) If SEC does not match the one cached in ARM_SEC, then free the current @@ -8786,7 +8882,7 @@ decode_arm_unwind_bytecode (Filedata * filedata, } if (i == sizeof (buf)) { - error (_("corrupt change to vsp")); + error (_("corrupt change to vsp\n")); res = FALSE; } else @@ -9346,7 +9442,6 @@ arm_process_unwind (Filedata * filedata) { struct arm_unw_aux_info aux; Elf_Internal_Shdr *unwsec = NULL; - Elf_Internal_Shdr *strsec; Elf_Internal_Shdr *sec; unsigned long i; unsigned int sec_type; @@ -9376,22 +9471,19 @@ arm_process_unwind (Filedata * filedata) for (i = 0, sec = filedata->section_headers; i < filedata->file_header.e_shnum; ++i, ++sec) { - if (sec->sh_type == SHT_SYMTAB && sec->sh_link < filedata->file_header.e_shnum) + if (sec->sh_type == SHT_SYMTAB) { - aux.symtab = GET_ELF_SYMBOLS (filedata, sec, & aux.nsyms); - - strsec = filedata->section_headers + sec->sh_link; - - /* PR binutils/17531 file: 011-12666-0.004. */ - if (aux.strtab != NULL) + if (aux.symtab) { - error (_("Multiple string tables found in file.\n")); + error (_("Multiple symbol tables encountered\n")); + free (aux.symtab); + aux.symtab = NULL; free (aux.strtab); - res = FALSE; + aux.strtab = NULL; } - aux.strtab = get_data (NULL, filedata, strsec->sh_offset, - 1, strsec->sh_size, _("string table")); - aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0; + if (!get_symtab (filedata, sec, &aux.symtab, &aux.nsyms, + &aux.strtab, &aux.strtab_size)) + return FALSE; } else if (sec->sh_type == sec_type) unwsec = sec; @@ -9419,10 +9511,8 @@ arm_process_unwind (Filedata * filedata) } } - if (aux.symtab) - free (aux.symtab); - if (aux.strtab) - free ((char *) aux.strtab); + free (aux.symtab); + free ((char *) aux.strtab); return res; } @@ -9472,7 +9562,7 @@ dynamic_section_aarch64_val (Elf_Internal_Dyn * entry) } static void -dynamic_section_mips_val (Elf_Internal_Dyn * entry) +dynamic_section_mips_val (Filedata * filedata, Elf_Internal_Dyn * entry) { switch (entry->d_tag) { @@ -9502,8 +9592,9 @@ dynamic_section_mips_val (Elf_Internal_Dyn * entry) break; case DT_MIPS_IVERSION: - if (VALID_DYNAMIC_NAME (entry->d_un.d_val)) - printf (_("Interface Version: %s"), GET_DYNAMIC_NAME (entry->d_un.d_val)); + if (VALID_DYNAMIC_NAME (filedata, entry->d_un.d_val)) + printf (_("Interface Version: %s"), + GET_DYNAMIC_NAME (filedata, entry->d_un.d_val)); else { char buf[40]; @@ -9548,8 +9639,8 @@ dynamic_section_mips_val (Elf_Internal_Dyn * entry) break; case DT_MIPS_XHASH: - dynamic_info_DT_MIPS_XHASH = entry->d_un.d_val; - dynamic_info_DT_GNU_HASH = entry->d_un.d_val; + filedata->dynamic_info_DT_MIPS_XHASH = entry->d_un.d_val; + filedata->dynamic_info_DT_GNU_HASH = entry->d_un.d_val; /* Falls through. */ default: @@ -9709,35 +9800,37 @@ get_32bit_dynamic_section (Filedata * filedata) Elf32_External_Dyn * ext; Elf_Internal_Dyn * entry; - edyn = (Elf32_External_Dyn *) get_data (NULL, filedata, dynamic_addr, 1, - dynamic_size, _("dynamic section")); + edyn = (Elf32_External_Dyn *) get_data (NULL, filedata, + filedata->dynamic_addr, 1, + filedata->dynamic_size, + _("dynamic section")); if (!edyn) return FALSE; /* 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 + 1) <= (char *) edyn + dynamic_size; + for (ext = edyn, filedata->dynamic_nent = 0; + (char *) (ext + 1) <= (char *) edyn + filedata->dynamic_size; ext++) { - dynamic_nent++; + filedata->dynamic_nent++; if (BYTE_GET (ext->d_tag) == DT_NULL) break; } - dynamic_section = (Elf_Internal_Dyn *) cmalloc (dynamic_nent, - sizeof (* entry)); - if (dynamic_section == NULL) + filedata->dynamic_section + = (Elf_Internal_Dyn *) cmalloc (filedata->dynamic_nent, sizeof (* entry)); + if (filedata->dynamic_section == NULL) { error (_("Out of memory allocating space for %lu dynamic entries\n"), - (unsigned long) dynamic_nent); + (unsigned long) filedata->dynamic_nent); free (edyn); return FALSE; } - for (ext = edyn, entry = dynamic_section; - entry < dynamic_section + dynamic_nent; + for (ext = edyn, entry = filedata->dynamic_section; + entry < filedata->dynamic_section + filedata->dynamic_nent; ext++, entry++) { entry->d_tag = BYTE_GET (ext->d_tag); @@ -9757,37 +9850,39 @@ get_64bit_dynamic_section (Filedata * filedata) Elf_Internal_Dyn * entry; /* Read in the data. */ - edyn = (Elf64_External_Dyn *) get_data (NULL, filedata, dynamic_addr, 1, - dynamic_size, _("dynamic section")); + edyn = (Elf64_External_Dyn *) get_data (NULL, filedata, + filedata->dynamic_addr, 1, + filedata->dynamic_size, + _("dynamic section")); if (!edyn) return FALSE; /* 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; + for (ext = edyn, filedata->dynamic_nent = 0; /* PR 17533 file: 033-67080-0.004 - do not read past end of buffer. */ - (char *) (ext + 1) <= (char *) edyn + dynamic_size; + (char *) (ext + 1) <= (char *) edyn + filedata->dynamic_size; ext++) { - dynamic_nent++; + filedata->dynamic_nent++; if (BYTE_GET (ext->d_tag) == DT_NULL) break; } - dynamic_section = (Elf_Internal_Dyn *) cmalloc (dynamic_nent, - sizeof (* entry)); - if (dynamic_section == NULL) + filedata->dynamic_section + = (Elf_Internal_Dyn *) cmalloc (filedata->dynamic_nent, sizeof (* entry)); + if (filedata->dynamic_section == NULL) { error (_("Out of memory allocating space for %lu dynamic entries\n"), - (unsigned long) dynamic_nent); + (unsigned long) filedata->dynamic_nent); free (edyn); return FALSE; } /* Convert from external to internal formats. */ - for (ext = edyn, entry = dynamic_section; - entry < dynamic_section + dynamic_nent; + for (ext = edyn, entry = filedata->dynamic_section; + entry < filedata->dynamic_section + filedata->dynamic_nent; ext++, entry++) { entry->d_tag = BYTE_GET (ext->d_tag); @@ -9829,137 +9924,471 @@ print_dynamic_flags (bfd_vma flags) puts (""); } -/* Parse and display the contents of the dynamic section. */ - -static bfd_boolean -process_dynamic_section (Filedata * filedata) +static bfd_vma * +get_dynamic_data (Filedata * filedata, bfd_size_type number, unsigned int ent_size) { - Elf_Internal_Dyn * entry; + unsigned char * e_data; + bfd_vma * i_data; - if (dynamic_size == 0) + /* If the size_t type is smaller than the bfd_size_type, eg because + you are building a 32-bit tool on a 64-bit host, then make sure + that when (number) is cast to (size_t) no information is lost. */ + if (sizeof (size_t) < sizeof (bfd_size_type) + && (bfd_size_type) ((size_t) number) != number) { - if (do_dynamic) - printf (_("\nThere is no dynamic section in this file.\n")); - - return TRUE; + error (_("Size truncation prevents reading %s elements of size %u\n"), + bfd_vmatoa ("u", number), ent_size); + return NULL; } - if (is_32bit_elf) + /* Be kind to memory checkers (eg valgrind, address sanitizer) by not + attempting to allocate memory when the read is bound to fail. */ + if (ent_size * number > filedata->file_size) { - if (! get_32bit_dynamic_section (filedata)) - return FALSE; + error (_("Invalid number of dynamic entries: %s\n"), + bfd_vmatoa ("u", number)); + return NULL; } - else + + e_data = (unsigned char *) cmalloc ((size_t) number, ent_size); + if (e_data == NULL) { - if (! get_64bit_dynamic_section (filedata)) - return FALSE; + error (_("Out of memory reading %s dynamic entries\n"), + bfd_vmatoa ("u", number)); + return NULL; } - /* Find the appropriate symbol table. */ - if (dynamic_symbols == NULL) + if (fread (e_data, ent_size, (size_t) number, filedata->handle) != number) { - for (entry = dynamic_section; - entry < dynamic_section + dynamic_nent; - ++entry) - { - Elf_Internal_Shdr section; + error (_("Unable to read in %s bytes of dynamic data\n"), + bfd_vmatoa ("u", number * ent_size)); + free (e_data); + return NULL; + } - if (entry->d_tag != DT_SYMTAB) - continue; + i_data = (bfd_vma *) cmalloc ((size_t) number, sizeof (*i_data)); + if (i_data == NULL) + { + error (_("Out of memory allocating space for %s dynamic entries\n"), + bfd_vmatoa ("u", number)); + free (e_data); + return NULL; + } - dynamic_info[DT_SYMTAB] = entry->d_un.d_val; + while (number--) + i_data[number] = byte_get (e_data + number * ent_size, ent_size); - /* Since we do not know how big the symbol table is, - we default to reading in the entire file (!) and - processing that. This is overkill, I know, but it - should work. */ - section.sh_offset = offset_from_vma (filedata, entry->d_un.d_val, 0); - if ((bfd_size_type) section.sh_offset > filedata->file_size) - { - /* See PR 21379 for a reproducer. */ - error (_("Invalid DT_SYMTAB entry: %lx"), (long) section.sh_offset); - return FALSE; - } + free (e_data); - if (archive_file_offset != 0) - section.sh_size = archive_file_size - section.sh_offset; - else - section.sh_size = filedata->file_size - section.sh_offset; + return i_data; +} - if (is_32bit_elf) - section.sh_entsize = sizeof (Elf32_External_Sym); - else - section.sh_entsize = sizeof (Elf64_External_Sym); - section.sh_name = filedata->string_table_length; +static unsigned long +get_num_dynamic_syms (Filedata * filedata) +{ + unsigned long num_of_syms = 0; - if (dynamic_symbols != NULL) - { - error (_("Multiple dynamic symbol table sections found\n")); - free (dynamic_symbols); - } - dynamic_symbols = GET_ELF_SYMBOLS (filedata, §ion, & num_dynamic_syms); - if (num_dynamic_syms < 1) - { - error (_("Unable to determine the number of symbols to load\n")); - continue; - } - } - } + if (!do_histogram && (!do_using_dynamic || do_dyn_syms)) + return num_of_syms; - /* Similarly find a string table. */ - if (dynamic_strings == NULL) + if (filedata->dynamic_info[DT_HASH]) { - for (entry = dynamic_section; - entry < dynamic_section + dynamic_nent; - ++entry) - { - unsigned long offset; - long str_tab_len; + unsigned char nb[8]; + unsigned char nc[8]; + unsigned int hash_ent_size = 4; - if (entry->d_tag != DT_STRTAB) - continue; + if ((filedata->file_header.e_machine == EM_ALPHA + || filedata->file_header.e_machine == EM_S390 + || filedata->file_header.e_machine == EM_S390_OLD) + && filedata->file_header.e_ident[EI_CLASS] == ELFCLASS64) + hash_ent_size = 8; - dynamic_info[DT_STRTAB] = entry->d_un.d_val; + if (fseek (filedata->handle, + (filedata->archive_file_offset + + offset_from_vma (filedata, filedata->dynamic_info[DT_HASH], + sizeof nb + sizeof nc)), + SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information\n")); + goto no_hash; + } - /* Since we do not know how big the string table is, - we default to reading in the entire file (!) and - processing that. This is overkill, I know, but it - should work. */ + if (fread (nb, hash_ent_size, 1, filedata->handle) != 1) + { + error (_("Failed to read in number of buckets\n")); + goto no_hash; + } - offset = offset_from_vma (filedata, entry->d_un.d_val, 0); + if (fread (nc, hash_ent_size, 1, filedata->handle) != 1) + { + error (_("Failed to read in number of chains\n")); + goto no_hash; + } - if (archive_file_offset != 0) - str_tab_len = archive_file_size - offset; - else - str_tab_len = filedata->file_size - offset; + filedata->nbuckets = byte_get (nb, hash_ent_size); + filedata->nchains = byte_get (nc, hash_ent_size); - if (str_tab_len < 1) - { - error - (_("Unable to determine the length of the dynamic string table\n")); - continue; - } + if (filedata->nbuckets != 0 && filedata->nchains != 0) + { + filedata->buckets = get_dynamic_data (filedata, filedata->nbuckets, + hash_ent_size); + filedata->chains = get_dynamic_data (filedata, filedata->nchains, + hash_ent_size); - if (dynamic_strings != NULL) + if (filedata->buckets != NULL && filedata->chains != NULL) + num_of_syms = filedata->nchains; + } + no_hash: + if (num_of_syms == 0) + { + free (filedata->buckets); + filedata->buckets = NULL; + free (filedata->chains); + filedata->chains = NULL; + filedata->nbuckets = 0; + } + } + + if (filedata->dynamic_info_DT_GNU_HASH) + { + unsigned char nb[16]; + bfd_vma i, maxchain = 0xffffffff, bitmaskwords; + bfd_vma buckets_vma; + unsigned long hn; + + if (fseek (filedata->handle, + (filedata->archive_file_offset + + offset_from_vma (filedata, + filedata->dynamic_info_DT_GNU_HASH, + sizeof nb)), + SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information\n")); + goto no_gnu_hash; + } + + if (fread (nb, 16, 1, filedata->handle) != 1) + { + error (_("Failed to read in number of buckets\n")); + goto no_gnu_hash; + } + + filedata->ngnubuckets = byte_get (nb, 4); + filedata->gnusymidx = byte_get (nb + 4, 4); + bitmaskwords = byte_get (nb + 8, 4); + buckets_vma = filedata->dynamic_info_DT_GNU_HASH + 16; + if (is_32bit_elf) + buckets_vma += bitmaskwords * 4; + else + buckets_vma += bitmaskwords * 8; + + if (fseek (filedata->handle, + (filedata->archive_file_offset + + offset_from_vma (filedata, buckets_vma, 4)), + SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information\n")); + goto no_gnu_hash; + } + + filedata->gnubuckets + = get_dynamic_data (filedata, filedata->ngnubuckets, 4); + + if (filedata->gnubuckets == NULL) + goto no_gnu_hash; + + for (i = 0; i < filedata->ngnubuckets; i++) + if (filedata->gnubuckets[i] != 0) + { + if (filedata->gnubuckets[i] < filedata->gnusymidx) + goto no_gnu_hash; + + if (maxchain == 0xffffffff || filedata->gnubuckets[i] > maxchain) + maxchain = filedata->gnubuckets[i]; + } + + if (maxchain == 0xffffffff) + goto no_gnu_hash; + + maxchain -= filedata->gnusymidx; + + if (fseek (filedata->handle, + (filedata->archive_file_offset + + offset_from_vma (filedata, + buckets_vma + 4 * (filedata->ngnubuckets + + maxchain), + 4)), + SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information\n")); + goto no_gnu_hash; + } + + do + { + if (fread (nb, 4, 1, filedata->handle) != 1) + { + error (_("Failed to determine last chain length\n")); + goto no_gnu_hash; + } + + if (maxchain + 1 == 0) + goto no_gnu_hash; + + ++maxchain; + } + while ((byte_get (nb, 4) & 1) == 0); + + if (fseek (filedata->handle, + (filedata->archive_file_offset + + offset_from_vma (filedata, (buckets_vma + + 4 * filedata->ngnubuckets), + 4)), + SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information\n")); + goto no_gnu_hash; + } + + filedata->gnuchains = get_dynamic_data (filedata, maxchain, 4); + filedata->ngnuchains = maxchain; + + if (filedata->gnuchains == NULL) + goto no_gnu_hash; + + if (filedata->dynamic_info_DT_MIPS_XHASH) + { + if (fseek (filedata->handle, + (filedata->archive_file_offset + + offset_from_vma (filedata, (buckets_vma + + 4 * (filedata->ngnubuckets + + maxchain)), 4)), + SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information\n")); + goto no_gnu_hash; + } + + filedata->mipsxlat = get_dynamic_data (filedata, maxchain, 4); + if (filedata->mipsxlat == NULL) + goto no_gnu_hash; + } + + for (hn = 0; hn < filedata->ngnubuckets; ++hn) + if (filedata->gnubuckets[hn] != 0) + { + bfd_vma si = filedata->gnubuckets[hn]; + bfd_vma off = si - filedata->gnusymidx; + + do + { + if (filedata->dynamic_info_DT_MIPS_XHASH) + { + if (off < filedata->ngnuchains + && filedata->mipsxlat[off] >= num_of_syms) + num_of_syms = filedata->mipsxlat[off] + 1; + } + else + { + if (si >= num_of_syms) + num_of_syms = si + 1; + } + si++; + } + while (off < filedata->ngnuchains + && (filedata->gnuchains[off++] & 1) == 0); + } + + if (num_of_syms == 0) + { + no_gnu_hash: + free (filedata->mipsxlat); + filedata->mipsxlat = NULL; + free (filedata->gnuchains); + filedata->gnuchains = NULL; + free (filedata->gnubuckets); + filedata->gnubuckets = NULL; + filedata->ngnubuckets = 0; + filedata->ngnuchains = 0; + } + } + + return num_of_syms; +} + +/* Parse and display the contents of the dynamic section. */ + +static bfd_boolean +process_dynamic_section (Filedata * filedata) +{ + Elf_Internal_Dyn * entry; + + if (filedata->dynamic_size == 0) + { + if (do_dynamic) + printf (_("\nThere is no dynamic section in this file.\n")); + + return TRUE; + } + + if (is_32bit_elf) + { + if (! get_32bit_dynamic_section (filedata)) + return FALSE; + } + else + { + if (! get_64bit_dynamic_section (filedata)) + return FALSE; + } + + /* Find the appropriate symbol table. */ + if (filedata->dynamic_symbols == NULL || do_histogram) + { + unsigned long num_of_syms; + + for (entry = filedata->dynamic_section; + entry < filedata->dynamic_section + filedata->dynamic_nent; + ++entry) + if (entry->d_tag == DT_SYMTAB) + filedata->dynamic_info[DT_SYMTAB] = entry->d_un.d_val; + else if (entry->d_tag == DT_SYMENT) + filedata->dynamic_info[DT_SYMENT] = entry->d_un.d_val; + else if (entry->d_tag == DT_HASH) + filedata->dynamic_info[DT_HASH] = entry->d_un.d_val; + else if (entry->d_tag == DT_GNU_HASH) + filedata->dynamic_info_DT_GNU_HASH = entry->d_un.d_val; + else if ((filedata->file_header.e_machine == EM_MIPS + || filedata->file_header.e_machine == EM_MIPS_RS3_LE) + && entry->d_tag == DT_MIPS_XHASH) + { + filedata->dynamic_info_DT_MIPS_XHASH = entry->d_un.d_val; + filedata->dynamic_info_DT_GNU_HASH = entry->d_un.d_val; + } + + num_of_syms = get_num_dynamic_syms (filedata); + + if (num_of_syms != 0 + && filedata->dynamic_symbols == NULL + && filedata->dynamic_info[DT_SYMTAB] + && filedata->dynamic_info[DT_SYMENT]) + { + Elf_Internal_Phdr *seg; + bfd_vma vma = filedata->dynamic_info[DT_SYMTAB]; + + if (! get_program_headers (filedata)) { - error (_("Multiple dynamic string tables found\n")); - free (dynamic_strings); + error (_("Cannot interpret virtual addresses " + "without program headers.\n")); + return FALSE; } - dynamic_strings = (char *) get_data (NULL, filedata, offset, 1, - str_tab_len, - _("dynamic string table")); - dynamic_strings_length = dynamic_strings == NULL ? 0 : str_tab_len; + for (seg = filedata->program_headers; + seg < filedata->program_headers + filedata->file_header.e_phnum; + ++seg) + { + if (seg->p_type != PT_LOAD) + continue; + + if (seg->p_offset + seg->p_filesz > filedata->file_size) + { + /* See PR 21379 for a reproducer. */ + error (_("Invalid PT_LOAD entry\n")); + return FALSE; + } + + if (vma >= (seg->p_vaddr & -seg->p_align) + && vma < seg->p_vaddr + seg->p_filesz) + { + /* Since we do not know how big the symbol table is, + we default to reading in up to the end of PT_LOAD + segment and processing that. This is overkill, I + know, but it should work. */ + Elf_Internal_Shdr section; + section.sh_offset = (vma - seg->p_vaddr + + seg->p_offset); + section.sh_size = (num_of_syms + * filedata->dynamic_info[DT_SYMENT]); + section.sh_entsize = filedata->dynamic_info[DT_SYMENT]; + + if (do_checks + && filedata->dynamic_symtab_section != NULL + && ((filedata->dynamic_symtab_section->sh_offset + != section.sh_offset) + || (filedata->dynamic_symtab_section->sh_size + != section.sh_size) + || (filedata->dynamic_symtab_section->sh_entsize + != section.sh_entsize))) + warn (_("\ +the .dynsym section doesn't match the DT_SYMTAB and DT_SYMENT tags\n")); + + section.sh_name = filedata->string_table_length; + filedata->dynamic_symbols + = GET_ELF_SYMBOLS (filedata, §ion, + &filedata->num_dynamic_syms); + if (filedata->dynamic_symbols == NULL + || filedata->num_dynamic_syms != num_of_syms) + { + error (_("Corrupt DT_SYMTAB dynamic entry\n")); + return FALSE; + } + break; + } + } } } + /* Similarly find a string table. */ + if (filedata->dynamic_strings == NULL) + for (entry = filedata->dynamic_section; + entry < filedata->dynamic_section + filedata->dynamic_nent; + ++entry) + { + if (entry->d_tag == DT_STRTAB) + filedata->dynamic_info[DT_STRTAB] = entry->d_un.d_val; + + if (entry->d_tag == DT_STRSZ) + filedata->dynamic_info[DT_STRSZ] = entry->d_un.d_val; + + if (filedata->dynamic_info[DT_STRTAB] + && filedata->dynamic_info[DT_STRSZ]) + { + unsigned long offset; + bfd_size_type str_tab_len = filedata->dynamic_info[DT_STRSZ]; + + offset = offset_from_vma (filedata, + filedata->dynamic_info[DT_STRTAB], + str_tab_len); + if (do_checks + && filedata->dynamic_strtab_section + && ((filedata->dynamic_strtab_section->sh_offset + != (file_ptr) offset) + || (filedata->dynamic_strtab_section->sh_size + != str_tab_len))) + warn (_("\ +the .dynstr section doesn't match the DT_STRTAB and DT_STRSZ tags\n")); + + filedata->dynamic_strings + = (char *) get_data (NULL, filedata, offset, 1, str_tab_len, + _("dynamic string table")); + if (filedata->dynamic_strings == NULL) + { + error (_("Corrupt DT_STRTAB dynamic entry\n")); + break; + } + + filedata->dynamic_strings_length = str_tab_len; + break; + } + } + /* And find the syminfo section if available. */ - if (dynamic_syminfo == NULL) + if (filedata->dynamic_syminfo == NULL) { unsigned long syminsz = 0; - for (entry = dynamic_section; - entry < dynamic_section + dynamic_nent; + for (entry = filedata->dynamic_section; + entry < filedata->dynamic_section + filedata->dynamic_nent; ++entry) { if (entry->d_tag == DT_SYMINENT) @@ -9975,11 +10404,11 @@ process_dynamic_section (Filedata * filedata) else if (entry->d_tag == DT_SYMINSZ) syminsz = entry->d_un.d_val; else if (entry->d_tag == DT_SYMINFO) - dynamic_syminfo_offset = offset_from_vma (filedata, entry->d_un.d_val, - syminsz); + filedata->dynamic_syminfo_offset + = offset_from_vma (filedata, entry->d_un.d_val, syminsz); } - if (dynamic_syminfo_offset != 0 && syminsz != 0) + if (filedata->dynamic_syminfo_offset != 0 && syminsz != 0) { Elf_External_Syminfo * extsyminfo; Elf_External_Syminfo * extsym; @@ -9987,27 +10416,30 @@ process_dynamic_section (Filedata * filedata) /* There is a syminfo section. Read the data. */ extsyminfo = (Elf_External_Syminfo *) - get_data (NULL, filedata, dynamic_syminfo_offset, 1, syminsz, - _("symbol information")); + get_data (NULL, filedata, filedata->dynamic_syminfo_offset, + 1, syminsz, _("symbol information")); if (!extsyminfo) return FALSE; - if (dynamic_syminfo != NULL) + if (filedata->dynamic_syminfo != NULL) { error (_("Multiple dynamic symbol information sections found\n")); - free (dynamic_syminfo); + free (filedata->dynamic_syminfo); } - dynamic_syminfo = (Elf_Internal_Syminfo *) malloc (syminsz); - if (dynamic_syminfo == NULL) + filedata->dynamic_syminfo = (Elf_Internal_Syminfo *) malloc (syminsz); + if (filedata->dynamic_syminfo == NULL) { - error (_("Out of memory allocating %lu byte for dynamic symbol info\n"), + error (_("Out of memory allocating %lu bytes " + "for dynamic symbol info\n"), (unsigned long) syminsz); return FALSE; } - dynamic_syminfo_nent = syminsz / sizeof (Elf_External_Syminfo); - for (syminfo = dynamic_syminfo, extsym = extsyminfo; - syminfo < dynamic_syminfo + dynamic_syminfo_nent; + filedata->dynamic_syminfo_nent + = syminsz / sizeof (Elf_External_Syminfo); + for (syminfo = filedata->dynamic_syminfo, extsym = extsyminfo; + syminfo < (filedata->dynamic_syminfo + + filedata->dynamic_syminfo_nent); ++syminfo, ++extsym) { syminfo->si_boundto = BYTE_GET (extsym->si_boundto); @@ -10018,18 +10450,18 @@ process_dynamic_section (Filedata * filedata) } } - if (do_dynamic && dynamic_addr) + if (do_dynamic && filedata->dynamic_addr) printf (ngettext ("\nDynamic section at offset 0x%lx " "contains %lu entry:\n", "\nDynamic section at offset 0x%lx " "contains %lu entries:\n", - dynamic_nent), - dynamic_addr, (unsigned long) dynamic_nent); + filedata->dynamic_nent), + filedata->dynamic_addr, (unsigned long) filedata->dynamic_nent); if (do_dynamic) printf (_(" Tag Type Name/Value\n")); - for (entry = dynamic_section; - entry < dynamic_section + dynamic_nent; + for (entry = filedata->dynamic_section; + entry < filedata->dynamic_section + filedata->dynamic_nent; entry++) { if (do_dynamic) @@ -10080,8 +10512,9 @@ process_dynamic_section (Filedata * filedata) break; } - if (VALID_DYNAMIC_NAME (entry->d_un.d_val)) - printf (": [%s]\n", GET_DYNAMIC_NAME (entry->d_un.d_val)); + if (VALID_DYNAMIC_NAME (filedata, entry->d_un.d_val)) + printf (": [%s]\n", + GET_DYNAMIC_NAME (filedata, entry->d_un.d_val)); else { printf (": "); @@ -10320,7 +10753,7 @@ process_dynamic_section (Filedata * filedata) break; case DT_PLTREL: - dynamic_info[entry->d_tag] = entry->d_un.d_val; + filedata->dynamic_info[entry->d_tag] = entry->d_un.d_val; if (do_dynamic) puts (get_dynamic_type (filedata, entry->d_un.d_val)); break; @@ -10342,14 +10775,14 @@ process_dynamic_section (Filedata * filedata) case DT_TEXTREL : case DT_JMPREL : case DT_RUNPATH : - dynamic_info[entry->d_tag] = entry->d_un.d_val; + filedata->dynamic_info[entry->d_tag] = entry->d_un.d_val; if (do_dynamic) { char * name; - if (VALID_DYNAMIC_NAME (entry->d_un.d_val)) - name = GET_DYNAMIC_NAME (entry->d_un.d_val); + if (VALID_DYNAMIC_NAME (filedata, entry->d_un.d_val)) + name = GET_DYNAMIC_NAME (filedata, entry->d_un.d_val); else name = NULL; @@ -10360,7 +10793,7 @@ process_dynamic_section (Filedata * filedata) case DT_NEEDED: printf (_("Shared library: [%s]"), name); - if (streq (name, program_interpreter)) + if (streq (name, filedata->program_interpreter)) printf (_(" program interpreter")); break; @@ -10395,7 +10828,7 @@ process_dynamic_section (Filedata * filedata) case DT_RELAENT : case DT_SYMENT : case DT_RELENT : - dynamic_info[entry->d_tag] = entry->d_un.d_val; + filedata->dynamic_info[entry->d_tag] = entry->d_un.d_val; /* Fall through. */ case DT_PLTPADSZ: case DT_MOVEENT : @@ -10431,9 +10864,9 @@ process_dynamic_section (Filedata * filedata) if (do_dynamic) { if (entry->d_tag == DT_USED - && VALID_DYNAMIC_NAME (entry->d_un.d_val)) + && VALID_DYNAMIC_NAME (filedata, entry->d_un.d_val)) { - char * name = GET_DYNAMIC_NAME (entry->d_un.d_val); + char * name = GET_DYNAMIC_NAME (filedata, entry->d_un.d_val); if (*name) { @@ -10473,7 +10906,7 @@ process_dynamic_section (Filedata * filedata) break; case DT_GNU_HASH: - dynamic_info_DT_GNU_HASH = entry->d_un.d_val; + filedata->dynamic_info_DT_GNU_HASH = entry->d_un.d_val; if (do_dynamic) { print_vma (entry->d_un.d_val, PREFIX_HEX); @@ -10483,8 +10916,8 @@ process_dynamic_section (Filedata * filedata) default: if ((entry->d_tag >= DT_VERSYM) && (entry->d_tag <= DT_VERNEEDNUM)) - version_info[DT_VERSIONTAGIDX (entry->d_tag)] = - entry->d_un.d_val; + filedata->version_info[DT_VERSIONTAGIDX (entry->d_tag)] + = entry->d_un.d_val; if (do_dynamic) { @@ -10495,7 +10928,7 @@ process_dynamic_section (Filedata * filedata) break; case EM_MIPS: case EM_MIPS_RS3_LE: - dynamic_section_mips_val (entry); + dynamic_section_mips_val (filedata, entry); break; case EM_PARISC: dynamic_section_parisc_val (entry); @@ -10646,8 +11079,9 @@ process_version_sections (Filedata * filedata) aux.vda_name = BYTE_GET (eaux->vda_name); aux.vda_next = BYTE_GET (eaux->vda_next); - if (VALID_DYNAMIC_NAME (aux.vda_name)) - printf (_("Name: %s\n"), GET_DYNAMIC_NAME (aux.vda_name)); + if (VALID_DYNAMIC_NAME (filedata, aux.vda_name)) + printf (_("Name: %s\n"), + GET_DYNAMIC_NAME (filedata, aux.vda_name)); else printf (_("Name index: %ld\n"), aux.vda_name); @@ -10677,9 +11111,10 @@ process_version_sections (Filedata * filedata) aux.vda_name = BYTE_GET (eaux->vda_name); aux.vda_next = BYTE_GET (eaux->vda_next); - if (VALID_DYNAMIC_NAME (aux.vda_name)) + if (VALID_DYNAMIC_NAME (filedata, aux.vda_name)) printf (_(" %#06lx: Parent %d: %s\n"), - isum, j, GET_DYNAMIC_NAME (aux.vda_name)); + isum, j, + GET_DYNAMIC_NAME (filedata, aux.vda_name)); else printf (_(" %#06lx: Parent %d, name index: %ld\n"), isum, j, aux.vda_name); @@ -10762,8 +11197,9 @@ process_version_sections (Filedata * filedata) printf (_(" %#06lx: Version: %d"), idx, ent.vn_version); - if (VALID_DYNAMIC_NAME (ent.vn_file)) - printf (_(" File: %s"), GET_DYNAMIC_NAME (ent.vn_file)); + if (VALID_DYNAMIC_NAME (filedata, ent.vn_file)) + printf (_(" File: %s"), + GET_DYNAMIC_NAME (filedata, ent.vn_file)); else printf (_(" File: %lx"), ent.vn_file); @@ -10789,9 +11225,9 @@ process_version_sections (Filedata * filedata) aux.vna_name = BYTE_GET (eaux->vna_name); aux.vna_next = BYTE_GET (eaux->vna_next); - if (VALID_DYNAMIC_NAME (aux.vna_name)) + if (VALID_DYNAMIC_NAME (filedata, aux.vna_name)) printf (_(" %#06lx: Name: %s"), - isum, GET_DYNAMIC_NAME (aux.vna_name)); + isum, GET_DYNAMIC_NAME (filedata, aux.vna_name)); else printf (_(" %#06lx: Name index: %lx"), isum, aux.vna_name); @@ -10889,11 +11325,11 @@ process_version_sections (Filedata * filedata) printable_section_name (filedata, link_section)); off = offset_from_vma (filedata, - version_info[DT_VERSIONTAGIDX (DT_VERSYM)], + filedata->version_info[DT_VERSIONTAGIDX (DT_VERSYM)], total * sizeof (short)); - edata = (unsigned char *) get_data (NULL, filedata, off, total, - sizeof (short), - _("version symbol data")); + edata = (unsigned char *) get_data (NULL, filedata, off, + sizeof (short), total, + _("version symbol data")); if (!edata) { free (strtab); @@ -10941,13 +11377,14 @@ process_version_sections (Filedata * filedata) } name = NULL; - if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)]) + if (filedata->version_info[DT_VERSIONTAGIDX (DT_VERNEED)]) { Elf_Internal_Verneed ivn; unsigned long offset; offset = offset_from_vma - (filedata, version_info[DT_VERSIONTAGIDX (DT_VERNEED)], + (filedata, + filedata->version_info[DT_VERSIONTAGIDX (DT_VERNEED)], sizeof (Elf_External_Verneed)); do @@ -11002,14 +11439,15 @@ process_version_sections (Filedata * filedata) } if (data[cnt + j] != 0x8001 - && version_info[DT_VERSIONTAGIDX (DT_VERDEF)]) + && filedata->version_info[DT_VERSIONTAGIDX (DT_VERDEF)]) { Elf_Internal_Verdef ivd; Elf_External_Verdef evd; unsigned long offset; offset = offset_from_vma - (filedata, version_info[DT_VERSIONTAGIDX (DT_VERDEF)], + (filedata, + filedata->version_info[DT_VERSIONTAGIDX (DT_VERDEF)], sizeof evd); do @@ -11089,7 +11527,7 @@ process_version_sections (Filedata * filedata) static const char * get_symbol_binding (Filedata * filedata, unsigned int binding) { - static char buff[32]; + static char buff[64]; switch (binding) { @@ -11116,7 +11554,7 @@ get_symbol_binding (Filedata * filedata, unsigned int binding) static const char * get_symbol_type (Filedata * filedata, unsigned int type) { - static char buff[32]; + static char buff[64]; switch (type) { @@ -11176,7 +11614,7 @@ get_symbol_visibility (unsigned int visibility) case STV_HIDDEN: return "HIDDEN"; case STV_PROTECTED: return "PROTECTED"; default: - error (_("Unrecognized visibility value: %u"), visibility); + error (_("Unrecognized visibility value: %u\n"), visibility); return _(""); } } @@ -11189,7 +11627,7 @@ get_alpha_symbol_other (unsigned int other) case STO_ALPHA_NOPV: return "NOPV"; case STO_ALPHA_STD_GPLOAD: return "STD GPLOAD"; default: - error (_("Unrecognized alpha specific other value: %u"), other); + error (_("Unrecognized alpha specific other value: %u\n"), other); return _(""); } } @@ -11313,7 +11751,7 @@ get_ppc64_symbol_other (unsigned int other) other >>= STO_PPC64_LOCAL_BIT; if (other <= 6) { - static char buf[32]; + static char buf[64]; if (other >= 2) other = ppc64_decode_local_entry (other); snprintf (buf, sizeof buf, _(": %d"), other); @@ -11326,7 +11764,7 @@ static const char * get_symbol_other (Filedata * filedata, unsigned int other) { const char * result = NULL; - static char buff [32]; + static char buff [64]; if (other == 0) return ""; @@ -11394,7 +11832,8 @@ get_symbol_index_type (Filedata * filedata, unsigned int type) sprintf (buff, "OS [0x%04x]", type & 0xffff); else if (type >= SHN_LORESERVE) sprintf (buff, "RSV[0x%04x]", type & 0xffff); - else if (type >= filedata->file_header.e_shnum) + else if (filedata->file_header.e_shnum != 0 + && type >= filedata->file_header.e_shnum) sprintf (buff, _("bad section index[%3d]"), type); else sprintf (buff, "%3d", type); @@ -11404,114 +11843,6 @@ get_symbol_index_type (Filedata * filedata, unsigned int type) return buff; } -static bfd_vma * -get_dynamic_data (Filedata * filedata, bfd_size_type number, unsigned int ent_size) -{ - unsigned char * e_data; - bfd_vma * i_data; - - /* If the size_t type is smaller than the bfd_size_type, eg because - you are building a 32-bit tool on a 64-bit host, then make sure - that when (number) is cast to (size_t) no information is lost. */ - if (sizeof (size_t) < sizeof (bfd_size_type) - && (bfd_size_type) ((size_t) number) != number) - { - error (_("Size truncation prevents reading %s elements of size %u\n"), - bfd_vmatoa ("u", number), ent_size); - 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 (ent_size * number > filedata->file_size) - { - error (_("Invalid number of dynamic entries: %s\n"), - bfd_vmatoa ("u", number)); - return NULL; - } - - e_data = (unsigned char *) cmalloc ((size_t) number, ent_size); - if (e_data == NULL) - { - error (_("Out of memory reading %s dynamic entries\n"), - bfd_vmatoa ("u", number)); - return NULL; - } - - if (fread (e_data, ent_size, (size_t) number, filedata->handle) != number) - { - error (_("Unable to read in %s bytes of dynamic data\n"), - bfd_vmatoa ("u", number * ent_size)); - free (e_data); - return NULL; - } - - i_data = (bfd_vma *) cmalloc ((size_t) number, sizeof (*i_data)); - if (i_data == NULL) - { - error (_("Out of memory allocating space for %s dynamic entries\n"), - bfd_vmatoa ("u", number)); - free (e_data); - return NULL; - } - - while (number--) - i_data[number] = byte_get (e_data + number * ent_size, ent_size); - - free (e_data); - - return i_data; -} - -static void -print_dynamic_symbol (Filedata * filedata, bfd_vma si, unsigned long hn) -{ - Elf_Internal_Sym * psym; - int n; - - n = print_vma (si, DEC_5); - if (n < 5) - fputs (&" "[n], stdout); - printf (" %3lu: ", hn); - - if (dynamic_symbols == NULL || si >= num_dynamic_syms) - { - printf (_("\n"), - (unsigned long) si); - return; - } - - psym = dynamic_symbols + si; - print_vma (psym->st_value, LONG_HEX); - putchar (' '); - print_vma (psym->st_size, DEC_5); - - printf (" %-7s", get_symbol_type (filedata, ELF_ST_TYPE (psym->st_info))); - printf (" %-6s", get_symbol_binding (filedata, ELF_ST_BIND (psym->st_info))); - - if (filedata->file_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 (filedata, psym->st_other ^ vis)); - } - - printf (" %3.3s ", get_symbol_index_type (filedata, psym->st_shndx)); - if (VALID_DYNAMIC_NAME (psym->st_name)) - print_symbol (25, GET_DYNAMIC_NAME (psym->st_name)); - else - printf (_(" "), psym->st_name); - putchar ('\n'); -} - static const char * get_symbol_version_string (Filedata * filedata, bfd_boolean is_dynsym, @@ -11528,10 +11859,11 @@ get_symbol_version_string (Filedata * filedata, unsigned short max_vd_ndx; if (!is_dynsym - || version_info[DT_VERSIONTAGIDX (DT_VERSYM)] == 0) + || filedata->version_info[DT_VERSIONTAGIDX (DT_VERSYM)] == 0) return NULL; - offset = offset_from_vma (filedata, version_info[DT_VERSIONTAGIDX (DT_VERSYM)], + offset = offset_from_vma (filedata, + filedata->version_info[DT_VERSIONTAGIDX (DT_VERSYM)], sizeof data + si * sizeof (vers_data)); if (get_data (&data, filedata, offset + si * sizeof (vers_data), @@ -11557,7 +11889,7 @@ get_symbol_version_string (Filedata * filedata, if (psym->st_shndx != SHN_UNDEF && vers_data != 0x8001 - && version_info[DT_VERSIONTAGIDX (DT_VERDEF)]) + && filedata->version_info[DT_VERSIONTAGIDX (DT_VERDEF)]) { Elf_Internal_Verdef ivd; Elf_Internal_Verdaux ivda; @@ -11565,7 +11897,7 @@ get_symbol_version_string (Filedata * filedata, unsigned long off; off = offset_from_vma (filedata, - version_info[DT_VERSIONTAGIDX (DT_VERDEF)], + filedata->version_info[DT_VERSIONTAGIDX (DT_VERDEF)], sizeof (Elf_External_Verdef)); do @@ -11615,14 +11947,14 @@ get_symbol_version_string (Filedata * filedata, } } - if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)]) + if (filedata->version_info[DT_VERSIONTAGIDX (DT_VERNEED)]) { Elf_External_Verneed evn; Elf_Internal_Verneed ivn; Elf_Internal_Vernaux ivna; offset = offset_from_vma (filedata, - version_info[DT_VERSIONTAGIDX (DT_VERNEED)], + filedata->version_info[DT_VERSIONTAGIDX (DT_VERNEED)], sizeof evn); do { @@ -11685,282 +12017,100 @@ get_symbol_version_string (Filedata * filedata, return NULL; } -/* Dump the symbol table. */ -static bfd_boolean -process_symbol_table (Filedata * filedata) +static void +print_dynamic_symbol (Filedata *filedata, unsigned long si, + Elf_Internal_Sym *symtab, + Elf_Internal_Shdr *section, + char *strtab, size_t strtab_size) { - Elf_Internal_Shdr * section; - 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 * mipsxlat = NULL; - bfd_vma gnusymidx = 0; - bfd_size_type ngnuchains = 0; - - if (!do_syms && !do_dyn_syms && !do_histogram) - return TRUE; - - if (dynamic_info[DT_HASH] - && (do_histogram - || (do_using_dynamic - && !do_dyn_syms - && dynamic_strings != NULL))) - { - unsigned char nb[8]; - unsigned char nc[8]; - unsigned int hash_ent_size = 4; - - if ((filedata->file_header.e_machine == EM_ALPHA - || filedata->file_header.e_machine == EM_S390 - || filedata->file_header.e_machine == EM_S390_OLD) - && filedata->file_header.e_ident[EI_CLASS] == ELFCLASS64) - hash_ent_size = 8; - - if (fseek (filedata->handle, - (archive_file_offset - + offset_from_vma (filedata, dynamic_info[DT_HASH], - sizeof nb + sizeof nc)), - SEEK_SET)) - { - error (_("Unable to seek to start of dynamic information\n")); - goto no_hash; - } - - if (fread (nb, hash_ent_size, 1, filedata->handle) != 1) - { - error (_("Failed to read in number of buckets\n")); - goto no_hash; - } - - if (fread (nc, hash_ent_size, 1, filedata->handle) != 1) - { - error (_("Failed to read in number of chains\n")); - goto no_hash; - } - - nbuckets = byte_get (nb, hash_ent_size); - nchains = byte_get (nc, hash_ent_size); - - buckets = get_dynamic_data (filedata, nbuckets, hash_ent_size); - chains = get_dynamic_data (filedata, nchains, hash_ent_size); - - no_hash: - if (buckets == NULL || chains == NULL) - { - if (do_using_dynamic) - return FALSE; - free (buckets); - free (chains); - buckets = NULL; - chains = NULL; - nbuckets = 0; - nchains = 0; - } - } + const char *version_string; + enum versioned_symbol_info sym_info; + unsigned short vna_other; + Elf_Internal_Sym *psym = symtab + si; - if (dynamic_info_DT_GNU_HASH - && (do_histogram - || (do_using_dynamic - && !do_dyn_syms - && dynamic_strings != NULL))) + printf ("%6ld: ", si); + print_vma (psym->st_value, LONG_HEX); + putchar (' '); + print_vma (psym->st_size, DEC_5); + printf (" %-7s", get_symbol_type (filedata, ELF_ST_TYPE (psym->st_info))); + printf (" %-6s", get_symbol_binding (filedata, ELF_ST_BIND (psym->st_info))); + if (filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS) + printf (" %-7s", get_solaris_symbol_visibility (psym->st_other)); + else { - unsigned char nb[16]; - bfd_vma i, maxchain = 0xffffffff, bitmaskwords; - bfd_vma buckets_vma; - - if (fseek (filedata->handle, - (archive_file_offset - + offset_from_vma (filedata, dynamic_info_DT_GNU_HASH, - sizeof nb)), - SEEK_SET)) - { - error (_("Unable to seek to start of dynamic information\n")); - goto no_gnu_hash; - } - - if (fread (nb, 16, 1, filedata->handle) != 1) - { - error (_("Failed to read in number of buckets\n")); - goto no_gnu_hash; - } - - ngnubuckets = byte_get (nb, 4); - gnusymidx = byte_get (nb + 4, 4); - bitmaskwords = byte_get (nb + 8, 4); - buckets_vma = dynamic_info_DT_GNU_HASH + 16; - if (is_32bit_elf) - buckets_vma += bitmaskwords * 4; - else - buckets_vma += bitmaskwords * 8; - - if (fseek (filedata->handle, - (archive_file_offset - + offset_from_vma (filedata, buckets_vma, 4)), - SEEK_SET)) - { - error (_("Unable to seek to start of dynamic information\n")); - goto no_gnu_hash; - } - - gnubuckets = get_dynamic_data (filedata, ngnubuckets, 4); - - if (gnubuckets == NULL) - goto no_gnu_hash; - - for (i = 0; i < ngnubuckets; i++) - if (gnubuckets[i] != 0) - { - if (gnubuckets[i] < gnusymidx) - return FALSE; - - if (maxchain == 0xffffffff || gnubuckets[i] > maxchain) - maxchain = gnubuckets[i]; - } - - if (maxchain == 0xffffffff) - goto no_gnu_hash; - - maxchain -= gnusymidx; - - if (fseek (filedata->handle, - (archive_file_offset - + offset_from_vma (filedata, buckets_vma - + 4 * (ngnubuckets + maxchain), 4)), - SEEK_SET)) - { - error (_("Unable to seek to start of dynamic information\n")); - goto no_gnu_hash; - } - - do - { - if (fread (nb, 4, 1, filedata->handle) != 1) - { - error (_("Failed to determine last chain length\n")); - goto no_gnu_hash; - } - - if (maxchain + 1 == 0) - goto no_gnu_hash; - - ++maxchain; - } - while ((byte_get (nb, 4) & 1) == 0); - - if (fseek (filedata->handle, - (archive_file_offset - + offset_from_vma (filedata, buckets_vma + 4 * ngnubuckets, 4)), - SEEK_SET)) - { - error (_("Unable to seek to start of dynamic information\n")); - goto no_gnu_hash; - } - - gnuchains = get_dynamic_data (filedata, maxchain, 4); - ngnuchains = maxchain; - - if (gnuchains == NULL) - goto no_gnu_hash; - - if (dynamic_info_DT_MIPS_XHASH) - { - if (fseek (filedata->handle, - (archive_file_offset - + offset_from_vma (filedata, (buckets_vma - + 4 * (ngnubuckets - + maxchain)), 4)), - SEEK_SET)) - { - error (_("Unable to seek to start of dynamic information\n")); - goto no_gnu_hash; - } - - mipsxlat = get_dynamic_data (filedata, maxchain, 4); - } - - no_gnu_hash: - if (dynamic_info_DT_MIPS_XHASH && mipsxlat == NULL) - { - free (gnuchains); - gnuchains = NULL; - } - if (gnuchains == NULL) - { - free (gnubuckets); - gnubuckets = NULL; - ngnubuckets = 0; - if (do_using_dynamic) - return FALSE; - } + 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 (filedata, psym->st_other ^ vis)); + } + printf (" %4s ", get_symbol_index_type (filedata, psym->st_shndx)); + print_symbol (25, VALID_SYMBOL_NAME (strtab, strtab_size, + psym->st_name) + ? strtab + psym->st_name : _("")); + + version_string + = get_symbol_version_string (filedata, + (section == NULL + || section->sh_type == SHT_DYNSYM), + strtab, strtab_size, si, + psym, &sym_info, &vna_other); + if (version_string) + { + if (sym_info == symbol_undefined) + printf ("@%s (%d)", version_string, vna_other); + else + printf (sym_info == symbol_hidden ? "@%s" : "@@%s", + version_string); } - if ((dynamic_info[DT_HASH] || dynamic_info_DT_GNU_HASH) - && do_syms - && do_using_dynamic - && dynamic_strings != NULL - && dynamic_symbols != NULL) - { - unsigned long hn; + putchar ('\n'); - if (dynamic_info[DT_HASH]) - { - bfd_vma si; - char *visited; + if (ELF_ST_BIND (psym->st_info) == STB_LOCAL + && section != NULL + && si >= section->sh_info + /* Irix 5 and 6 MIPS binaries are known to ignore this requirement. */ + && filedata->file_header.e_machine != EM_MIPS + /* Solaris binaries have been found to violate this requirement as + well. Not sure if this is a bug or an ABI requirement. */ + && filedata->file_header.e_ident[EI_OSABI] != ELFOSABI_SOLARIS) + warn (_("local symbol %lu found at index >= %s's sh_info value of %u\n"), + si, printable_section_name (filedata, section), section->sh_info); +} - printf (_("\nSymbol table for image:\n")); - if (is_32bit_elf) - printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n")); - else - printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n")); +/* Dump the symbol table. */ +static bfd_boolean +process_symbol_table (Filedata * filedata) +{ + Elf_Internal_Shdr * section; - visited = xcmalloc (nchains, 1); - memset (visited, 0, nchains); - for (hn = 0; hn < nbuckets; hn++) - { - for (si = buckets[hn]; si > 0; si = chains[si]) - { - print_dynamic_symbol (filedata, si, hn); - if (si >= nchains || visited[si]) - { - error (_("histogram chain is corrupt\n")); - break; - } - visited[si] = 1; - } - } - free (visited); - } + if (!do_syms && !do_dyn_syms && !do_histogram) + return TRUE; - if (dynamic_info_DT_GNU_HASH) - { - printf (_("\nSymbol table of `%s' for image:\n"), - GNU_HASH_SECTION_NAME); - if (is_32bit_elf) - printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n")); - else - printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n")); + if ((filedata->dynamic_info[DT_HASH] || filedata->dynamic_info_DT_GNU_HASH) + && do_syms + && do_using_dynamic + && filedata->dynamic_strings != NULL + && filedata->dynamic_symbols != NULL) + { + unsigned long si; - for (hn = 0; hn < ngnubuckets; ++hn) - if (gnubuckets[hn] != 0) - { - bfd_vma si = gnubuckets[hn]; - bfd_vma off = si - gnusymidx; + printf (ngettext ("\nSymbol table for image contains %lu entry:\n", + "\nSymbol table for image contains %lu entries:\n", + filedata->num_dynamic_syms), + filedata->num_dynamic_syms); + if (is_32bit_elf) + printf (_(" Num: Value Size Type Bind Vis Ndx Name\n")); + else + printf (_(" Num: Value Size Type Bind Vis Ndx Name\n")); - do - { - if (dynamic_info_DT_MIPS_XHASH) - print_dynamic_symbol (filedata, mipsxlat[off], hn); - else - print_dynamic_symbol (filedata, si, hn); - si++; - } - while (off < ngnuchains && (gnuchains[off++] & 1) == 0); - } - } + for (si = 0; si < filedata->num_dynamic_syms; si++) + print_dynamic_symbol (filedata, si, filedata->dynamic_symbols, NULL, + filedata->dynamic_strings, + filedata->dynamic_strings_length); } else if ((do_dyn_syms || (do_syms && !do_using_dynamic)) && filedata->section_headers != NULL) @@ -11971,12 +12121,10 @@ process_symbol_table (Filedata * filedata) i < filedata->file_header.e_shnum; i++, section++) { - unsigned int si; char * strtab = NULL; unsigned long int strtab_size = 0; Elf_Internal_Sym * symtab; - Elf_Internal_Sym * psym; - unsigned long num_syms; + unsigned long si, num_syms; if ((section->sh_type != SHT_SYMTAB && section->sh_type != SHT_DYNSYM) @@ -12024,61 +12172,9 @@ process_symbol_table (Filedata * filedata) strtab_size = strtab != NULL ? string_sec->sh_size : 0; } - 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 (' '); - print_vma (psym->st_size, DEC_5); - printf (" %-7s", get_symbol_type (filedata, ELF_ST_TYPE (psym->st_info))); - printf (" %-6s", get_symbol_binding (filedata, ELF_ST_BIND (psym->st_info))); - if (filedata->file_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 (filedata, psym->st_other ^ vis)); - } - printf (" %4s ", get_symbol_index_type (filedata, psym->st_shndx)); - print_symbol (25, psym->st_name < strtab_size - ? strtab + psym->st_name : _("")); - - version_string - = get_symbol_version_string (filedata, - section->sh_type == SHT_DYNSYM, - strtab, strtab_size, si, - psym, &sym_info, &vna_other); - if (version_string) - { - if (sym_info == symbol_undefined) - printf ("@%s (%d)", version_string, vna_other); - else - printf (sym_info == symbol_hidden ? "@%s" : "@@%s", - version_string); - } - - putchar ('\n'); - - if (ELF_ST_BIND (psym->st_info) == STB_LOCAL - && si >= section->sh_info - /* Irix 5 and 6 MIPS binaries are known to ignore this requirement. */ - && filedata->file_header.e_machine != EM_MIPS - /* Solaris binaries have been found to violate this requirement as - well. Not sure if this is a bug or an ABI requirement. */ - && filedata->file_header.e_ident[EI_OSABI] != ELFOSABI_SOLARIS) - warn (_("local symbol %u found at index >= %s's sh_info value of %u\n"), - si, printable_section_name (filedata, section), section->sh_info); - } + for (si = 0; si < num_syms; si++) + print_dynamic_symbol (filedata, si, symtab, section, + strtab, strtab_size); free (symtab); if (strtab != filedata->string_table) @@ -12089,7 +12185,7 @@ process_symbol_table (Filedata * filedata) printf (_("\nDynamic symbol information is not available for displaying symbols.\n")); - if (do_histogram && buckets != NULL) + if (do_histogram && filedata->buckets != NULL) { unsigned long * lengths; unsigned long * counts; @@ -12104,27 +12200,28 @@ process_symbol_table (Filedata * filedata) "(total of %lu bucket):\n", "\nHistogram for bucket list length " "(total of %lu buckets):\n", - (unsigned long) nbuckets), - (unsigned long) nbuckets); + (unsigned long) filedata->nbuckets), + (unsigned long) filedata->nbuckets); - lengths = (unsigned long *) calloc (nbuckets, sizeof (*lengths)); + lengths = (unsigned long *) calloc (filedata->nbuckets, + sizeof (*lengths)); if (lengths == NULL) { error (_("Out of memory allocating space for histogram buckets\n")); - return FALSE; + goto err_out; } - visited = xcmalloc (nchains, 1); - memset (visited, 0, nchains); + visited = xcmalloc (filedata->nchains, 1); + memset (visited, 0, filedata->nchains); printf (_(" Length Number %% of total Coverage\n")); - for (hn = 0; hn < nbuckets; ++hn) + for (hn = 0; hn < filedata->nbuckets; ++hn) { - for (si = buckets[hn]; si > 0; si = chains[si]) + for (si = filedata->buckets[hn]; si > 0; si = filedata->chains[si]) { ++nsyms; if (maxlength < ++lengths[hn]) ++maxlength; - if (si >= nchains || visited[si]) + if (si >= filedata->nchains || visited[si]) { error (_("histogram chain is corrupt\n")); break; @@ -12139,22 +12236,22 @@ process_symbol_table (Filedata * filedata) { free (lengths); error (_("Out of memory allocating space for histogram counts\n")); - return FALSE; + goto err_out; } - for (hn = 0; hn < nbuckets; ++hn) + for (hn = 0; hn < filedata->nbuckets; ++hn) ++counts[lengths[hn]]; - if (nbuckets > 0) + if (filedata->nbuckets > 0) { unsigned long i; printf (" 0 %-10lu (%5.1f%%)\n", - counts[0], (counts[0] * 100.0) / nbuckets); + counts[0], (counts[0] * 100.0) / filedata->nbuckets); for (i = 1; i <= maxlength; ++i) { nzero_counts += counts[i] * i; printf ("%7lu %-10lu (%5.1f%%) %5.1f%%\n", - i, counts[i], (counts[i] * 100.0) / nbuckets, + i, counts[i], (counts[i] * 100.0) / filedata->nbuckets, (nzero_counts * 100.0) / nsyms); } } @@ -12163,13 +12260,13 @@ process_symbol_table (Filedata * filedata) free (lengths); } - if (buckets != NULL) - { - free (buckets); - free (chains); - } + free (filedata->buckets); + filedata->buckets = NULL; + filedata->nbuckets = 0; + free (filedata->chains); + filedata->chains = NULL; - if (do_histogram && gnubuckets != NULL) + if (do_histogram && filedata->gnubuckets != NULL) { unsigned long * lengths; unsigned long * counts; @@ -12182,27 +12279,29 @@ process_symbol_table (Filedata * filedata) "(total of %lu bucket):\n", "\nHistogram for `%s' bucket list length " "(total of %lu buckets):\n", - (unsigned long) ngnubuckets), - GNU_HASH_SECTION_NAME, - (unsigned long) ngnubuckets); + (unsigned long) filedata->ngnubuckets), + GNU_HASH_SECTION_NAME (filedata), + (unsigned long) filedata->ngnubuckets); - lengths = (unsigned long *) calloc (ngnubuckets, sizeof (*lengths)); + lengths = (unsigned long *) calloc (filedata->ngnubuckets, + sizeof (*lengths)); if (lengths == NULL) { error (_("Out of memory allocating space for gnu histogram buckets\n")); - return FALSE; + goto err_out; } printf (_(" Length Number %% of total Coverage\n")); - for (hn = 0; hn < ngnubuckets; ++hn) - if (gnubuckets[hn] != 0) + for (hn = 0; hn < filedata->ngnubuckets; ++hn) + if (filedata->gnubuckets[hn] != 0) { bfd_vma off, length = 1; - for (off = gnubuckets[hn] - gnusymidx; + for (off = filedata->gnubuckets[hn] - filedata->gnusymidx; /* PR 17531 file: 010-77222-0.004. */ - off < ngnuchains && (gnuchains[off] & 1) == 0; + off < filedata->ngnuchains + && (filedata->gnuchains[off] & 1) == 0; ++off) ++length; lengths[hn] = length; @@ -12216,34 +12315,54 @@ process_symbol_table (Filedata * filedata) { free (lengths); error (_("Out of memory allocating space for gnu histogram counts\n")); - return FALSE; + goto err_out; } - for (hn = 0; hn < ngnubuckets; ++hn) + for (hn = 0; hn < filedata->ngnubuckets; ++hn) ++counts[lengths[hn]]; - if (ngnubuckets > 0) + if (filedata->ngnubuckets > 0) { unsigned long j; printf (" 0 %-10lu (%5.1f%%)\n", - counts[0], (counts[0] * 100.0) / ngnubuckets); + counts[0], (counts[0] * 100.0) / filedata->ngnubuckets); for (j = 1; j <= maxlength; ++j) { nzero_counts += counts[j] * j; printf ("%7lu %-10lu (%5.1f%%) %5.1f%%\n", - j, counts[j], (counts[j] * 100.0) / ngnubuckets, + j, counts[j], (counts[j] * 100.0) / filedata->ngnubuckets, (nzero_counts * 100.0) / nsyms); } } free (counts); free (lengths); - free (gnubuckets); - free (gnuchains); - free (mipsxlat); } - + free (filedata->gnubuckets); + filedata->gnubuckets = NULL; + filedata->ngnubuckets = 0; + free (filedata->gnuchains); + filedata->gnuchains = NULL; + filedata->ngnuchains = 0; + free (filedata->mipsxlat); + filedata->mipsxlat = NULL; return TRUE; + + err_out: + free (filedata->gnubuckets); + filedata->gnubuckets = NULL; + filedata->ngnubuckets = 0; + free (filedata->gnuchains); + filedata->gnuchains = NULL; + filedata->ngnuchains = 0; + free (filedata->mipsxlat); + filedata->mipsxlat = NULL; + free (filedata->buckets); + filedata->buckets = NULL; + filedata->nbuckets = 0; + free (filedata->chains); + filedata->chains = NULL; + return FALSE; } static bfd_boolean @@ -12251,38 +12370,39 @@ process_syminfo (Filedata * filedata ATTRIBUTE_UNUSED) { unsigned int i; - if (dynamic_syminfo == NULL + if (filedata->dynamic_syminfo == NULL || !do_dynamic) /* No syminfo, this is ok. */ return TRUE; /* There better should be a dynamic symbol section. */ - if (dynamic_symbols == NULL || dynamic_strings == NULL) + if (filedata->dynamic_symbols == NULL || filedata->dynamic_strings == NULL) return FALSE; - if (dynamic_addr) + if (filedata->dynamic_addr) printf (ngettext ("\nDynamic info segment at offset 0x%lx " "contains %d entry:\n", "\nDynamic info segment at offset 0x%lx " "contains %d entries:\n", - dynamic_syminfo_nent), - dynamic_syminfo_offset, dynamic_syminfo_nent); + filedata->dynamic_syminfo_nent), + filedata->dynamic_syminfo_offset, filedata->dynamic_syminfo_nent); printf (_(" Num: Name BoundTo Flags\n")); - for (i = 0; i < dynamic_syminfo_nent; ++i) + for (i = 0; i < filedata->dynamic_syminfo_nent; ++i) { - unsigned short int flags = dynamic_syminfo[i].si_flags; + unsigned short int flags = filedata->dynamic_syminfo[i].si_flags; printf ("%4d: ", i); - if (i >= num_dynamic_syms) + if (i >= filedata->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 if (VALID_DYNAMIC_NAME (filedata, filedata->dynamic_symbols[i].st_name)) + print_symbol (30, GET_DYNAMIC_NAME (filedata, + filedata->dynamic_symbols[i].st_name)); else - printf (_(""), dynamic_symbols[i].st_name); + printf (_(""), filedata->dynamic_symbols[i].st_name); putchar (' '); - switch (dynamic_syminfo[i].si_boundto) + switch (filedata->dynamic_syminfo[i].si_boundto) { case SYMINFO_BT_SELF: fputs ("SELF ", stdout); @@ -12291,15 +12411,17 @@ process_syminfo (Filedata * filedata ATTRIBUTE_UNUSED) fputs ("PARENT ", stdout); break; default: - if (dynamic_syminfo[i].si_boundto > 0 - && dynamic_syminfo[i].si_boundto < dynamic_nent - && VALID_DYNAMIC_NAME (dynamic_section[dynamic_syminfo[i].si_boundto].d_un.d_val)) + if (filedata->dynamic_syminfo[i].si_boundto > 0 + && filedata->dynamic_syminfo[i].si_boundto < filedata->dynamic_nent + && VALID_DYNAMIC_NAME (filedata, + filedata->dynamic_section[filedata->dynamic_syminfo[i].si_boundto].d_un.d_val)) { - print_symbol (10, GET_DYNAMIC_NAME (dynamic_section[dynamic_syminfo[i].si_boundto].d_un.d_val)); + print_symbol (10, GET_DYNAMIC_NAME (filedata, + filedata->dynamic_section[filedata->dynamic_syminfo[i].si_boundto].d_un.d_val)); putchar (' ' ); } else - printf ("%-10d ", dynamic_syminfo[i].si_boundto); + printf ("%-10d ", filedata->dynamic_syminfo[i].si_boundto); break; } @@ -13255,7 +13377,13 @@ is_none_reloc (Filedata * filedata, unsigned int reloc_type) return (reloc_type == 0 /* R_XTENSA_NONE. */ || reloc_type == 17 /* R_XTENSA_DIFF8. */ || reloc_type == 18 /* R_XTENSA_DIFF16. */ - || reloc_type == 19 /* R_XTENSA_DIFF32. */); + || reloc_type == 19 /* R_XTENSA_DIFF32. */ + || reloc_type == 57 /* R_XTENSA_PDIFF8. */ + || reloc_type == 58 /* R_XTENSA_PDIFF16. */ + || reloc_type == 59 /* R_XTENSA_PDIFF32. */ + || reloc_type == 60 /* R_XTENSA_NDIFF8. */ + || reloc_type == 61 /* R_XTENSA_NDIFF16. */ + || reloc_type == 62 /* R_XTENSA_NDIFF32. */); } return FALSE; } @@ -13657,12 +13785,16 @@ dump_section_as_strings (Elf_Internal_Shdr * section, Filedata * filedata) unsigned int compression_header_size = get_compression_header (& chdr, (unsigned char *) start, num_bytes); + if (compression_header_size == 0) + /* An error message will have already been generated + by get_compression_header. */ + goto error_out; if (chdr.ch_type != ELFCOMPRESS_ZLIB) { warn (_("section '%s' has unsupported compress type: %d\n"), printable_section_name (filedata, section), chdr.ch_type); - return FALSE; + goto error_out; } uncompressed_size = chdr.ch_size; start += compression_header_size; @@ -13694,7 +13826,7 @@ dump_section_as_strings (Elf_Internal_Shdr * section, Filedata * filedata) { error (_("Unable to decompress section %s\n"), printable_section_name (filedata, section)); - return FALSE; + goto error_out; } } else @@ -13725,6 +13857,14 @@ dump_section_as_strings (Elf_Internal_Shdr * section, Filedata * filedata) end = start + num_bytes; some_strings_shown = FALSE; +#ifdef HAVE_MBSTATE_T + mbstate_t state; + /* Initialise the multibyte conversion state. */ + memset (& state, 0, sizeof (state)); +#endif + + bfd_boolean continuing = FALSE; + while (data < end) { while (!ISPRINT (* data)) @@ -13735,18 +13875,76 @@ dump_section_as_strings (Elf_Internal_Shdr * section, Filedata * filedata) { size_t maxlen = end - data; + if (continuing) + { + printf (" "); + continuing = FALSE; + } + else + { #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); + /* PR 11128: Use two separate invocations in order to work + around bugs in the Solaris 8 implementation of printf. */ + printf (" [%6tx] ", data - start); #else - printf (" [%6Ix] ", (size_t) (data - start)); + printf (" [%6Ix] ", (size_t) (data - start)); #endif + } + if (maxlen > 0) { - print_symbol ((int) maxlen, (const char *) data); - putchar ('\n'); - data += strnlen ((const char *) data, maxlen); + char c; + + while (maxlen) + { + c = *data++; + + if (c == 0) + break; + + /* PR 25543: Treat new-lines as string-ending characters. */ + if (c == '\n') + { + printf ("\\n\n"); + if (*data != 0) + continuing = TRUE; + break; + } + + /* Do not print control characters directly as they can affect terminal + settings. Such characters usually appear in the names generated + by the assembler for local labels. */ + if (ISCNTRL (c)) + { + printf ("^%c", c + 0x40); + } + else if (ISPRINT (c)) + { + putchar (c); + } + else + { + size_t n; +#ifdef HAVE_MBSTATE_T + wchar_t w; +#endif + /* Let printf do the hard work of displaying multibyte characters. */ + printf ("%.1s", data - 1); +#ifdef HAVE_MBSTATE_T + /* Try to find out how many bytes made up the character that was + just printed. Advance the symbol pointer past the bytes that + were displayed. */ + n = mbrtowc (& w, (char *)(data - 1), MB_CUR_MAX, & state); +#else + n = 1; +#endif + if (n != (size_t) -1 && n != (size_t) -2 && n > 0) + data += (n - 1); + } + } + + if (c != '\n') + putchar ('\n'); } else { @@ -13764,6 +13962,10 @@ dump_section_as_strings (Elf_Internal_Shdr * section, Filedata * filedata) putchar ('\n'); return TRUE; + +error_out: + free (real_start); + return FALSE; } static bfd_boolean @@ -13799,11 +14001,16 @@ dump_section_as_bytes (Elf_Internal_Shdr * section, unsigned int compression_header_size = get_compression_header (& chdr, start, section_size); + if (compression_header_size == 0) + /* An error message will have already been generated + by get_compression_header. */ + goto error_out; + if (chdr.ch_type != ELFCOMPRESS_ZLIB) { warn (_("section '%s' has unsupported compress type: %d\n"), printable_section_name (filedata, section), chdr.ch_type); - return FALSE; + goto error_out; } uncompressed_size = chdr.ch_size; start += compression_header_size; @@ -13838,7 +14045,7 @@ dump_section_as_bytes (Elf_Internal_Shdr * section, error (_("Unable to decompress section %s\n"), printable_section_name (filedata, section)); /* FIXME: Print the section anyway ? */ - return FALSE; + goto error_out; } } else @@ -13848,7 +14055,7 @@ dump_section_as_bytes (Elf_Internal_Shdr * section, if (relocate) { if (! apply_relocations (filedata, section, start, section_size, NULL, NULL)) - return FALSE; + goto error_out; } else { @@ -13918,6 +14125,10 @@ dump_section_as_bytes (Elf_Internal_Shdr * section, putchar ('\n'); return TRUE; + + error_out: + free (real_start); + return FALSE; } static ctf_sect_t * @@ -14122,12 +14333,16 @@ load_specific_debug_section (enum dwarf_section_display_enum debug, ? sizeof (Elf32_External_Chdr) : sizeof (Elf64_External_Chdr))) { - warn (_("compressed section %s is too small to contain a compression header"), + warn (_("compressed section %s is too small to contain a compression header\n"), section->name); return FALSE; } compression_header_size = get_compression_header (&chdr, start, size); + if (compression_header_size == 0) + /* An error message will have already been generated + by get_compression_header. */ + return FALSE; if (chdr.ch_type != ELFCOMPRESS_ZLIB) { @@ -14204,7 +14419,8 @@ get_build_id (void * data) Elf_Internal_Shdr * shdr; unsigned long i; - /* Iterate through notes to find note.gnu.build-id. */ + /* Iterate through notes to find note.gnu.build-id. + FIXME: Only the first note in any note section is examined. */ for (i = 0, shdr = filedata->section_headers; i < filedata->file_header.e_shnum && shdr != NULL; i++, shdr++) @@ -14230,7 +14446,10 @@ get_build_id (void * data) if (align < 4) align = 4; else if (align != 4 && align != 8) - continue; + { + free (enote); + continue; + } end = (char *) enote + length; data_remaining = end - (char *) enote; @@ -14240,13 +14459,11 @@ get_build_id (void * data) min_notesz = offsetof (Elf_External_Note, name); if (data_remaining < min_notesz) { - warn (ngettext ("debuginfod: Corrupt note: only %ld byte remains, " - "not enough for a full note\n", - "Corrupt note: only %ld bytes remain, " - "not enough for a full note\n", - data_remaining), - (long) data_remaining); - break; + warn (_("\ +malformed note encountered in section %s whilst scanning for build-id note\n"), + printable_section_name (filedata, shdr)); + free (enote); + continue; } data_remaining -= min_notesz; @@ -14269,13 +14486,11 @@ get_build_id (void * data) min_notesz = offsetof (Elf64_External_VMS_Note, name); if (data_remaining < min_notesz) { - warn (ngettext ("debuginfod: Corrupt note: only %ld byte remains, " - "not enough for a full note\n", - "Corrupt note: only %ld bytes remain, " - "not enough for a full note\n", - data_remaining), - (long) data_remaining); - break; + warn (_("\ +malformed note encountered in section %s whilst scanning for build-id note\n"), + printable_section_name (filedata, shdr)); + free (enote); + continue; } data_remaining -= min_notesz; @@ -14296,9 +14511,10 @@ get_build_id (void * data) || ((size_t) (next - inote.descdata) > data_remaining - (size_t) (inote.descdata - inote.namedata))) { - warn (_("debuginfod: note with invalid namesz and/or descsz found\n")); - warn (_(" type: 0x%lx, namesize: 0x%08lx, descsize: 0x%08lx, alignment: %u\n"), - inote.type, inote.namesz, inote.descsz, (int) align); + warn (_("\ +malformed note encountered in section %s whilst scanning for build-id note\n"), + printable_section_name (filedata, shdr)); + free (enote); continue; } @@ -14313,14 +14529,19 @@ get_build_id (void * data) build_id = malloc (inote.descsz * 2 + 1); if (build_id == NULL) - return NULL; + { + free (enote); + return NULL; + } for (j = 0; j < inote.descsz; ++j) sprintf (build_id + (j * 2), "%02x", inote.descdata[j] & 0xff); build_id[inote.descsz * 2] = '\0'; + free (enote); - return (unsigned char *)build_id; + return (unsigned char *) build_id; } + free (enote); } return NULL; @@ -14397,12 +14618,9 @@ free_debug_section (enum dwarf_section_display_enum debug) section->address = 0; section->size = 0; - if (section->reloc_info != NULL) - { - free (section->reloc_info); - section->reloc_info = NULL; - section->num_relocs = 0; - } + free (section->reloc_info); + section->reloc_info = NULL; + section->num_relocs = 0; } static bfd_boolean @@ -14499,7 +14717,7 @@ initialise_dumps_byname (Filedata * filedata) for (i = 0; i < filedata->file_header.e_shnum; i++) if (streq (SECTION_NAME (filedata->section_headers + i), cur->name)) { - request_dump_bynumber (filedata, i, cur->type); + request_dump_bynumber (&filedata->dump, i, cur->type); any = TRUE; } @@ -14522,10 +14740,10 @@ process_section_contents (Filedata * filedata) initialise_dumps_byname (filedata); for (i = 0, section = filedata->section_headers; - i < filedata->file_header.e_shnum && i < filedata->num_dump_sects; + i < filedata->file_header.e_shnum && i < filedata->dump.num_dump_sects; i++, section++) { - dump_type dump = filedata->dump_sects[i]; + dump_type dump = filedata->dump.dump_sects[i]; #ifdef SUPPORT_DISASSEMBLY if (dump & DISASS_DUMP) @@ -14567,9 +14785,9 @@ process_section_contents (Filedata * filedata) /* Check to see if the user requested a dump of a section that does not exist. */ - while (i < filedata->num_dump_sects) + while (i < filedata->dump.num_dump_sects) { - if (filedata->dump_sects[i]) + if (filedata->dump.dump_sects[i]) { warn (_("Section %d was not dumped because it does not exist!\n"), i); res = FALSE; @@ -16423,7 +16641,7 @@ process_mips_specific (Filedata * filedata) } /* We have a lot of special sections. Thanks SGI! */ - if (dynamic_section == NULL) + if (filedata->dynamic_section == NULL) { /* No dynamic information available. See if there is static GOT. */ sect = find_section (filedata, ".got"); @@ -16506,15 +16724,15 @@ process_mips_specific (Filedata * filedata) } sgot_print_fail: - if (data) - free (data); + free (data); } return res; } - for (entry = dynamic_section; + for (entry = filedata->dynamic_section; /* PR 17531 file: 012-50589-0.004. */ - entry < dynamic_section + dynamic_nent && entry->d_tag != DT_NULL; + (entry < filedata->dynamic_section + filedata->dynamic_nent + && entry->d_tag != DT_NULL); ++entry) switch (entry->d_tag) { @@ -16571,9 +16789,9 @@ process_mips_specific (Filedata * filedata) size_t cnt; elib = (Elf32_External_Lib *) get_data (NULL, filedata, liblist_offset, - liblistno, - sizeof (Elf32_External_Lib), - _("liblist section data")); + sizeof (Elf32_External_Lib), + liblistno, + _("liblist section data")); if (elib) { printf (ngettext ("\nSection '.liblist' contains %lu entry:\n", @@ -16603,8 +16821,8 @@ process_mips_specific (Filedata * filedata) tmp->tm_hour, tmp->tm_min, tmp->tm_sec); printf ("%3lu: ", (unsigned long) cnt); - if (VALID_DYNAMIC_NAME (liblist.l_name)) - print_symbol (20, GET_DYNAMIC_NAME (liblist.l_name)); + if (VALID_DYNAMIC_NAME (filedata, liblist.l_name)) + print_symbol (20, GET_DYNAMIC_NAME (filedata, liblist.l_name)); else printf (_(""), liblist.l_name); printf (" %s %#10lx %-7ld", timebuf, liblist.l_checksum, @@ -16685,6 +16903,7 @@ process_mips_specific (Filedata * filedata) if (iopt == NULL) { error (_("Out of memory allocating space for MIPS options\n")); + free (eopt); return FALSE; } @@ -16707,7 +16926,10 @@ process_mips_specific (Filedata * filedata) if (option->size < sizeof (* eopt) || offset + option->size > sect->sh_size) { - error (_("Invalid size (%u) for MIPS option\n"), option->size); + error (_("Invalid size (%u) for MIPS option\n"), + option->size); + free (iopt); + free (eopt); return FALSE; } offset += option->size; @@ -16901,7 +17123,7 @@ process_mips_specific (Filedata * filedata) offset += option->size; ++option; } - + free (iopt); free (eopt); } else @@ -16913,7 +17135,7 @@ process_mips_specific (Filedata * filedata) Elf32_Conflict * iconf; size_t cnt; - if (dynamic_symbols == NULL) + if (filedata->dynamic_symbols == NULL) { error (_("conflict list found without a dynamic symbol table\n")); return FALSE; @@ -16921,7 +17143,7 @@ process_mips_specific (Filedata * filedata) /* PR 21345 - print a slightly more helpful error message if we are sure that the cmalloc will fail. */ - if (conflictsno * sizeof (* iconf) > filedata->file_size) + if (conflictsno > filedata->file_size / sizeof (* iconf)) { error (_("Overlarge number of conflicts detected: %lx\n"), (long) conflictsno); @@ -16940,10 +17162,13 @@ process_mips_specific (Filedata * filedata) Elf32_External_Conflict * econf32; econf32 = (Elf32_External_Conflict *) - get_data (NULL, filedata, conflicts_offset, conflictsno, - sizeof (* econf32), _("conflict")); + get_data (NULL, filedata, conflicts_offset, + sizeof (*econf32), conflictsno, _("conflict")); if (!econf32) - return FALSE; + { + free (iconf); + return FALSE; + } for (cnt = 0; cnt < conflictsno; ++cnt) iconf[cnt] = BYTE_GET (econf32[cnt]); @@ -16955,10 +17180,13 @@ process_mips_specific (Filedata * filedata) Elf64_External_Conflict * econf64; econf64 = (Elf64_External_Conflict *) - get_data (NULL, filedata, conflicts_offset, conflictsno, - sizeof (* econf64), _("conflict")); + get_data (NULL, filedata, conflicts_offset, + sizeof (*econf64), conflictsno, _("conflict")); if (!econf64) - return FALSE; + { + free (iconf); + return FALSE; + } for (cnt = 0; cnt < conflictsno; ++cnt) iconf[cnt] = BYTE_GET (econf64[cnt]); @@ -16976,17 +17204,17 @@ process_mips_specific (Filedata * filedata) { printf ("%5lu: %8lu ", (unsigned long) cnt, iconf[cnt]); - if (iconf[cnt] >= num_dynamic_syms) + if (iconf[cnt] >= filedata->num_dynamic_syms) printf (_("")); else { Elf_Internal_Sym * psym; - psym = & dynamic_symbols[iconf[cnt]]; + psym = & filedata->dynamic_symbols[iconf[cnt]]; print_vma (psym->st_value, FULL_HEX); putchar (' '); - if (VALID_DYNAMIC_NAME (psym->st_name)) - print_symbol (25, GET_DYNAMIC_NAME (psym->st_name)); + if (VALID_DYNAMIC_NAME (filedata, psym->st_name)) + print_symbol (25, GET_DYNAMIC_NAME (filedata, psym->st_name)); else printf (_(""), psym->st_name); } @@ -17099,19 +17327,20 @@ process_mips_specific (Filedata * filedata) ent = print_mips_got_entry (data, pltgot, ent, data_end); printf (" "); - if (dynamic_symbols == NULL) + if (filedata->dynamic_symbols == NULL) printf (_("")); - else if (i < num_dynamic_syms) + else if (i < filedata->num_dynamic_syms) { - Elf_Internal_Sym * psym = dynamic_symbols + i; + Elf_Internal_Sym * psym = filedata->dynamic_symbols + i; print_vma (psym->st_value, LONG_HEX); printf (" %-7s %3s ", get_symbol_type (filedata, ELF_ST_TYPE (psym->st_info)), get_symbol_index_type (filedata, psym->st_shndx)); - if (VALID_DYNAMIC_NAME (psym->st_name)) - print_symbol (sym_width, GET_DYNAMIC_NAME (psym->st_name)); + if (VALID_DYNAMIC_NAME (filedata, psym->st_name)) + print_symbol (sym_width, + GET_DYNAMIC_NAME (filedata, psym->st_name)); else printf (_(""), psym->st_name); } @@ -17127,8 +17356,7 @@ process_mips_specific (Filedata * filedata) } got_print_fail: - if (data) - free (data); + free (data); } if (mips_pltgot != 0 && jmprel != 0 && pltrel != 0 && pltrelsz != 0) @@ -17185,18 +17413,19 @@ process_mips_specific (Filedata * filedata) ent = print_mips_pltgot_entry (data, mips_pltgot, ent); printf (" "); - if (idx >= num_dynamic_syms) + if (idx >= filedata->num_dynamic_syms) printf (_(""), idx); else { - Elf_Internal_Sym * psym = dynamic_symbols + idx; + Elf_Internal_Sym * psym = filedata->dynamic_symbols + idx; print_vma (psym->st_value, LONG_HEX); printf (" %-7s %3s ", get_symbol_type (filedata, ELF_ST_TYPE (psym->st_info)), get_symbol_index_type (filedata, psym->st_shndx)); - if (VALID_DYNAMIC_NAME (psym->st_name)) - print_symbol (sym_width, GET_DYNAMIC_NAME (psym->st_name)); + if (VALID_DYNAMIC_NAME (filedata, psym->st_name)) + print_symbol (sym_width, + GET_DYNAMIC_NAME (filedata, psym->st_name)); else printf (_(""), psym->st_name); } @@ -17204,8 +17433,7 @@ process_mips_specific (Filedata * filedata) } printf ("\n"); - if (data) - free (data); + free (data); free (rels); } @@ -17218,18 +17446,21 @@ process_nds32_specific (Filedata * filedata) Elf_Internal_Shdr *sect = NULL; sect = find_section (filedata, ".nds32_e_flags"); - if (sect != NULL) + if (sect != NULL && sect->sh_size >= 4) { - unsigned int *flag; + unsigned char *buf; + unsigned int flag; printf ("\nNDS32 elf flags section:\n"); - flag = get_data (NULL, filedata, sect->sh_offset, 1, - sect->sh_size, _("NDS32 elf flags section")); + buf = get_data (NULL, filedata, sect->sh_offset, 1, 4, + _("NDS32 elf flags section")); - if (! flag) + if (buf == NULL) return FALSE; - switch ((*flag) & 0x3) + flag = byte_get (buf, 4); + free (buf); + switch (flag & 0x3) { case 0: printf ("(VEC_SIZE):\tNo entry.\n"); @@ -17437,6 +17668,8 @@ get_note_type (Filedata * filedata, unsigned e_type) return _("NT_ARM_HW_BREAK (AArch hardware breakpoint registers)"); case NT_ARM_HW_WATCH: return _("NT_ARM_HW_WATCH (AArch hardware watchpoint registers)"); + case NT_ARC_V2: + return _("NT_ARC_V2 (ARC HS accumulator/extra registers)"); case NT_PSTATUS: return _("NT_PSTATUS (pstatus structure)"); case NT_FPREGS: @@ -18062,7 +18295,7 @@ print_gnu_property_note (Filedata * filedata, Elf_Internal_Note * pnote) printf ("%02x ", ptr[j] & 0xff); printf (">"); -next: + next: ptr += ((datasz + (size - 1)) & ~ (size - 1)); if (ptr == ptr_end) break; @@ -18286,15 +18519,17 @@ process_netbsd_elf_note (Elf_Internal_Note * pnote) switch (pnote->type) { case NT_NETBSD_IDENT: + if (pnote->descsz < 1) + break; 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, + 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, version / 100000000, (version / 1000000) % 100, (version / 100) % 100); return TRUE; @@ -18305,6 +18540,8 @@ process_netbsd_elf_note (Elf_Internal_Note * pnote) #ifdef NT_NETBSD_PAX case NT_NETBSD_PAX: + if (pnote->descsz < 1) + break; version = byte_get ((unsigned char *) pnote->descdata, sizeof (version)); printf (" NetBSD\t\t0x%08lx\tPaX <%s%s%s%s%s%s>\n", pnote->descsz, ((version & NT_NETBSD_PAX_MPROTECT) ? "+mprotect" : ""), @@ -18315,12 +18552,11 @@ process_netbsd_elf_note (Elf_Internal_Note * pnote) ((version & NT_NETBSD_PAX_NOASLR) ? "-ASLR" : "")); return TRUE; #endif - - default: - printf (" NetBSD\t0x%08lx\tUnknown note type: (0x%08lx)\n", pnote->descsz, - pnote->type); - return FALSE; } + + printf (" NetBSD\t0x%08lx\tUnknown note type: (0x%08lx)\n", + pnote->descsz, pnote->type); + return FALSE; } static const char * @@ -18370,8 +18606,13 @@ get_netbsd_elfcore_note_type (Filedata * filedata, unsigned e_type) return _("NetBSD ELF auxiliary vector data"); #endif +#ifdef NT_NETBSDCORE_LWPSTATUS + case NT_NETBSDCORE_LWPSTATUS: + return _("PT_LWPSTATUS (ptrace_lwpstatus structure)"); +#endif + default: - /* As of Jan 2002 there are no other machine-independent notes + /* As of Jan 2020 there are no other machine-independent notes defined for NetBSD core files. If the note type is less than the start of the machine-dependent note types, we don't understand it. */ @@ -18694,6 +18935,14 @@ print_ia64_vms_note (Elf_Internal_Note * pnote) return FALSE; } +struct build_attr_cache { + Filedata *filedata; + char *strtab; + unsigned long strtablen; + Elf_Internal_Sym *symtab; + unsigned long nsyms; +} ba_cache; + /* 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 @@ -18705,61 +18954,52 @@ get_symbol_for_build_attribute (Filedata * filedata, bfd_boolean is_open_attr, const char ** pname) { - static Filedata * saved_filedata = 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; + Elf_Internal_Sym *saved_sym = NULL; + Elf_Internal_Sym *sym; if (filedata->section_headers != NULL - && (saved_filedata == NULL || filedata != saved_filedata)) + && (ba_cache.filedata == NULL || filedata != ba_cache.filedata)) { Elf_Internal_Shdr * symsec; + free (ba_cache.strtab); + ba_cache.strtab = NULL; + free (ba_cache.symtab); + ba_cache.symtab = NULL; + /* Load the symbol and string sections. */ for (symsec = filedata->section_headers; symsec < filedata->section_headers + filedata->file_header.e_shnum; symsec ++) { - if (symsec->sh_type == SHT_SYMTAB) - { - symtab = GET_ELF_SYMBOLS (filedata, symsec, & nsyms); - - if (symsec->sh_link < filedata->file_header.e_shnum) - { - Elf_Internal_Shdr * strtab_sec = filedata->section_headers + symsec->sh_link; - - strtab = (char *) get_data (NULL, filedata, strtab_sec->sh_offset, - 1, strtab_sec->sh_size, - _("string table")); - strtablen = strtab != NULL ? strtab_sec->sh_size : 0; - } - } + if (symsec->sh_type == SHT_SYMTAB + && get_symtab (filedata, symsec, + &ba_cache.symtab, &ba_cache.nsyms, + &ba_cache.strtab, &ba_cache.strtablen)) + break; } - saved_filedata = filedata; + ba_cache.filedata = filedata; } - if (symtab == NULL || strtab == NULL) + if (ba_cache.symtab == NULL) return NULL; /* Find a symbol whose value matches offset. */ - for (sym = symtab; sym < symtab + nsyms; sym ++) + for (sym = ba_cache.symtab; sym < ba_cache.symtab + ba_cache.nsyms; sym ++) if (sym->st_value == offset) { - if (sym->st_name >= strtablen) + if (sym->st_name >= ba_cache.strtablen) /* Huh ? This should not happen. */ continue; - if (strtab[sym->st_name] == 0) + if (ba_cache.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) + if (ba_cache.strtab[sym->st_name] == '$' + && ba_cache.strtab[sym->st_name + 1] != 0 + && ba_cache.strtab[sym->st_name + 2] == 0) continue; if (is_open_attr) @@ -18776,7 +19016,7 @@ get_symbol_for_build_attribute (Filedata * filedata, { /* If the symbol has a size associated with it then we can stop searching. */ - sym = symtab + nsyms; + sym = ba_cache.symtab + ba_cache.nsyms; } continue; @@ -18816,7 +19056,7 @@ get_symbol_for_build_attribute (Filedata * filedata, } if (saved_sym && pname) - * pname = strtab + saved_sym->st_name; + * pname = ba_cache.strtab + saved_sym->st_name; return saved_sym; } @@ -19320,7 +19560,10 @@ process_notes_at (Filedata * filedata, if (pnotes) { if (! apply_relocations (filedata, section, (unsigned char *) pnotes, length, NULL, NULL)) - return FALSE; + { + free (pnotes); + return FALSE; + } } } else @@ -19462,11 +19705,8 @@ process_notes_at (Filedata * filedata, if (! process_note (& inote, filedata)) res = FALSE; - if (temp != NULL) - { - free (temp); - temp = NULL; - } + free (temp); + temp = NULL; } free (pnotes); @@ -19903,7 +20143,7 @@ process_object (Filedata * filedata) { bfd_boolean have_separate_files; unsigned int i; - bfd_boolean res = TRUE; + bfd_boolean res; if (! get_file_header (filedata)) { @@ -19912,13 +20152,13 @@ process_object (Filedata * filedata) } /* Initialise per file variables. */ - for (i = ARRAY_SIZE (version_info); i--;) - version_info[i] = 0; + for (i = ARRAY_SIZE (filedata->version_info); i--;) + filedata->version_info[i] = 0; - for (i = ARRAY_SIZE (dynamic_info); i--;) - dynamic_info[i] = 0; - dynamic_info_DT_GNU_HASH = 0; - dynamic_info_DT_MIPS_XHASH = 0; + for (i = ARRAY_SIZE (filedata->dynamic_info); i--;) + filedata->dynamic_info[i] = 0; + filedata->dynamic_info_DT_GNU_HASH = 0; + filedata->dynamic_info_DT_MIPS_XHASH = 0; /* Process the file. */ if (show_name) @@ -19928,18 +20168,19 @@ process_object (Filedata * filedata) Note we do this even if cmdline_dump_sects is empty because we must make sure that the dump_sets array is zeroed out before each object file is processed. */ - if (filedata->num_dump_sects > cmdline.num_dump_sects) - memset (filedata->dump_sects, 0, filedata->num_dump_sects * sizeof (* filedata->dump_sects)); + if (filedata->dump.num_dump_sects > cmdline.num_dump_sects) + memset (filedata->dump.dump_sects, 0, + filedata->dump.num_dump_sects * sizeof (*filedata->dump.dump_sects)); if (cmdline.num_dump_sects > 0) { - if (filedata->num_dump_sects == 0) + if (filedata->dump.num_dump_sects == 0) /* A sneaky way of allocating the dump_sects array. */ - request_dump_bynumber (filedata, cmdline.num_dump_sects, 0); + request_dump_bynumber (&filedata->dump, cmdline.num_dump_sects, 0); - assert (filedata->num_dump_sects >= cmdline.num_dump_sects); - memcpy (filedata->dump_sects, cmdline.dump_sects, - cmdline.num_dump_sects * sizeof (* filedata->dump_sects)); + assert (filedata->dump.num_dump_sects >= cmdline.num_dump_sects); + memcpy (filedata->dump.dump_sects, cmdline.dump_sects, + cmdline.num_dump_sects * sizeof (*filedata->dump.dump_sects)); } if (! process_file_header (filedata)) @@ -19958,10 +20199,9 @@ process_object (Filedata * filedata) /* Without loaded section groups we cannot process unwind. */ do_unwind = FALSE; - if (process_program_headers (filedata)) - process_dynamic_section (filedata); - else - res = FALSE; + res = process_program_headers (filedata); + if (res) + res = process_dynamic_section (filedata); if (! process_relocs (filedata)) res = FALSE; @@ -20020,61 +20260,50 @@ process_object (Filedata * filedata) filedata->string_table = NULL; filedata->string_table_length = 0; - if (filedata->dump_sects != NULL) - { - free (filedata->dump_sects); - filedata->dump_sects = NULL; - filedata->num_dump_sects = 0; - } + free (filedata->dump.dump_sects); + filedata->dump.dump_sects = NULL; + filedata->dump.num_dump_sects = 0; - if (dynamic_strings) - { - free (dynamic_strings); - dynamic_strings = NULL; - dynamic_strings_length = 0; - } + free (filedata->dynamic_strings); + filedata->dynamic_strings = NULL; + filedata->dynamic_strings_length = 0; - if (dynamic_symbols) - { - free (dynamic_symbols); - dynamic_symbols = NULL; - num_dynamic_syms = 0; - } + free (filedata->dynamic_symbols); + filedata->dynamic_symbols = NULL; + filedata->num_dynamic_syms = 0; - if (dynamic_syminfo) - { - free (dynamic_syminfo); - dynamic_syminfo = NULL; - } + free (filedata->dynamic_syminfo); + filedata->dynamic_syminfo = NULL; - if (dynamic_section) - { - free (dynamic_section); - dynamic_section = NULL; - } + free (filedata->dynamic_section); + filedata->dynamic_section = NULL; - if (section_headers_groups) + while (filedata->symtab_shndx_list != NULL) { - free (section_headers_groups); - section_headers_groups = NULL; + elf_section_list *next = filedata->symtab_shndx_list->next; + free (filedata->symtab_shndx_list); + filedata->symtab_shndx_list = next; } - if (section_groups) + free (filedata->section_headers_groups); + filedata->section_headers_groups = NULL; + + if (filedata->section_groups) { struct group_list * g; struct group_list * next; - for (i = 0; i < group_count; i++) + for (i = 0; i < filedata->group_count; i++) { - for (g = section_groups [i].root; g != NULL; g = next) + for (g = filedata->section_groups [i].root; g != NULL; g = next) { next = g->next; free (g); } } - free (section_groups); - section_groups = NULL; + free (filedata->section_groups); + filedata->section_groups = NULL; } free_debug_memory (); @@ -20113,7 +20342,8 @@ process_archive (Filedata * filedata, bfd_boolean is_thin_archive) nested_arch.longnames = NULL; if (setup_archive (&arch, filedata->file_name, filedata->handle, - is_thin_archive, do_archive_index) != 0) + filedata->file_size, is_thin_archive, + do_archive_index) != 0) { ret = FALSE; goto out; @@ -20122,48 +20352,58 @@ process_archive (Filedata * filedata, bfd_boolean is_thin_archive) if (do_archive_index) { if (arch.sym_table == NULL) - error (_("%s: unable to dump the index as none was found\n"), filedata->file_name); + error (_("%s: unable to dump the index as none was found\n"), + filedata->file_name); else { unsigned long i, l; unsigned long current_pos; - printf (_("Index of archive %s: (%lu entries, 0x%lx bytes in the symbol table)\n"), - filedata->file_name, (unsigned long) arch.index_num, arch.sym_size); + printf (_("Index of archive %s: (%lu entries, 0x%lx bytes " + "in the symbol table)\n"), + filedata->file_name, (unsigned long) arch.index_num, + arch.sym_size); current_pos = ftell (filedata->handle); for (i = l = 0; i < arch.index_num; i++) { - if ((i == 0) || ((i > 0) && (arch.index_array[i] != arch.index_array[i - 1]))) - { - char * member_name; - - member_name = get_archive_member_name_at (&arch, arch.index_array[i], &nested_arch); + if (i == 0 + || (i > 0 && arch.index_array[i] != arch.index_array[i - 1])) + { + char * member_name + = get_archive_member_name_at (&arch, arch.index_array[i], + &nested_arch); - if (member_name != NULL) - { - char * qualified_name = make_qualified_name (&arch, &nested_arch, member_name); + if (member_name != NULL) + { + char * qualified_name + = make_qualified_name (&arch, &nested_arch, + member_name); - if (qualified_name != NULL) - { - printf (_("Contents of binary %s at offset "), qualified_name); + if (qualified_name != NULL) + { + printf (_("Contents of binary %s at offset "), + qualified_name); (void) print_vma (arch.index_array[i], PREFIX_HEX); putchar ('\n'); - free (qualified_name); - } + free (qualified_name); + } + free (member_name); } } if (l >= arch.sym_size) { - error (_("%s: end of the symbol table reached before the end of the index\n"), + error (_("%s: end of the symbol table reached " + "before the end of the index\n"), filedata->file_name); ret = FALSE; break; } /* PR 17531: file: 0b6630b2. */ - printf ("\t%.*s\n", (int) (arch.sym_size - l), arch.sym_table + l); + printf ("\t%.*s\n", + (int) (arch.sym_size - l), arch.sym_table + l); l += strnlen (arch.sym_table + l, arch.sym_size - l) + 1; } @@ -20187,7 +20427,8 @@ process_archive (Filedata * filedata, bfd_boolean is_thin_archive) if (fseek (filedata->handle, current_pos, SEEK_SET) != 0) { - error (_("%s: failed to seek back to start of object files in the archive\n"), + error (_("%s: failed to seek back to start of object files " + "in the archive\n"), filedata->file_name); ret = FALSE; goto out; @@ -20212,34 +20453,37 @@ process_archive (Filedata * filedata, bfd_boolean is_thin_archive) /* Read the next archive header. */ if (fseek (filedata->handle, arch.next_arhdr_offset, SEEK_SET) != 0) - { - error (_("%s: failed to seek to next archive header\n"), arch.file_name); - return FALSE; - } + { + error (_("%s: failed to seek to next archive header\n"), + arch.file_name); + ret = FALSE; + break; + } got = fread (&arch.arhdr, 1, sizeof arch.arhdr, filedata->handle); if (got != sizeof arch.arhdr) - { - if (got == 0) + { + if (got == 0) break; /* PR 24049 - we cannot use filedata->file_name as this will have already been freed. */ error (_("%s: failed to read archive header\n"), arch.file_name); - ret = FALSE; - break; - } + ret = FALSE; + break; + } if (memcmp (arch.arhdr.ar_fmag, ARFMAG, 2) != 0) - { - error (_("%s: did not find a valid archive header\n"), arch.file_name); - ret = FALSE; - break; - } + { + error (_("%s: did not find a valid archive header\n"), + arch.file_name); + ret = FALSE; + break; + } arch.next_arhdr_offset += sizeof arch.arhdr; - archive_file_size = strtoul (arch.arhdr.ar_size, NULL, 10); - if (archive_file_size & 01) - ++archive_file_size; + filedata->archive_file_size = strtoul (arch.arhdr.ar_size, NULL, 10); + if (filedata->archive_file_size & 01) + ++filedata->archive_file_size; name = get_archive_member_name (&arch, &nested_arch); if (name == NULL) @@ -20254,83 +20498,97 @@ process_archive (Filedata * filedata, bfd_boolean is_thin_archive) if (qualified_name == NULL) { error (_("%s: bad archive file name\n"), arch.file_name); + free (name); ret = FALSE; break; } if (is_thin_archive && arch.nested_member_origin == 0) - { - /* This is a proxy for an external member of a thin archive. */ - Filedata * member_filedata; - char * member_file_name = adjust_relative_path + { + /* This is a proxy for an external member of a thin archive. */ + Filedata * member_filedata; + char * member_file_name = adjust_relative_path (filedata->file_name, name, namelen); - if (member_file_name == NULL) - { - ret = FALSE; - break; - } + free (name); + if (member_file_name == NULL) + { + free (qualified_name); + ret = FALSE; + break; + } - member_filedata = open_file (member_file_name); - if (member_filedata == NULL) - { - error (_("Input file '%s' is not readable.\n"), member_file_name); - free (member_file_name); - ret = FALSE; - break; - } + member_filedata = open_file (member_file_name); + if (member_filedata == NULL) + { + error (_("Input file '%s' is not readable.\n"), member_file_name); + free (member_file_name); + free (qualified_name); + ret = FALSE; + break; + } - archive_file_offset = arch.nested_member_origin; + filedata->archive_file_offset = arch.nested_member_origin; member_filedata->file_name = qualified_name; - if (! process_object (member_filedata)) + if (! process_object (member_filedata)) ret = FALSE; - close_file (member_filedata); - free (member_file_name); - } + close_file (member_filedata); + free (member_file_name); + } else if (is_thin_archive) - { - Filedata thin_filedata; + { + Filedata thin_filedata; - memset (&thin_filedata, 0, sizeof (thin_filedata)); + memset (&thin_filedata, 0, sizeof (thin_filedata)); /* PR 15140: Allow for corrupt thin archives. */ if (nested_arch.file == NULL) { error (_("%s: contains corrupt thin archive: %s\n"), qualified_name, name); + free (qualified_name); + free (name); ret = FALSE; break; } + free (name); - /* This is a proxy for a member of a nested archive. */ - archive_file_offset = arch.nested_member_origin + sizeof arch.arhdr; + /* This is a proxy for a member of a nested archive. */ + filedata->archive_file_offset + = arch.nested_member_origin + sizeof arch.arhdr; - /* The nested archive file will have been opened and setup by - get_archive_member_name. */ - if (fseek (nested_arch.file, archive_file_offset, SEEK_SET) != 0) - { - error (_("%s: failed to seek to archive member.\n"), nested_arch.file_name); - ret = FALSE; - break; - } + /* The nested archive file will have been opened and setup by + get_archive_member_name. */ + if (fseek (nested_arch.file, filedata->archive_file_offset, + SEEK_SET) != 0) + { + error (_("%s: failed to seek to archive member.\n"), + nested_arch.file_name); + free (qualified_name); + ret = FALSE; + break; + } thin_filedata.handle = nested_arch.file; thin_filedata.file_name = qualified_name; - if (! process_object (& thin_filedata)) + if (! process_object (& thin_filedata)) ret = FALSE; - } + } else - { - archive_file_offset = arch.next_arhdr_offset; - arch.next_arhdr_offset += archive_file_size; - + { + free (name); + filedata->archive_file_offset = arch.next_arhdr_offset; filedata->file_name = qualified_name; - if (! process_object (filedata)) + if (! process_object (filedata)) ret = FALSE; - } + arch.next_arhdr_offset += filedata->archive_file_size; + /* Stop looping with "negative" archive_file_size. */ + if (arch.next_arhdr_offset < filedata->archive_file_size) + arch.next_arhdr_offset = -1ul; + } free (qualified_name); } @@ -20406,20 +20664,30 @@ process_file (char * file_name) } else { - if (do_archive_index) + if (do_archive_index && !check_all) error (_("File %s is not an archive so its index cannot be displayed.\n"), file_name); rewind (filedata->handle); - archive_file_size = archive_file_offset = 0; + filedata->archive_file_size = filedata->archive_file_offset = 0; if (! process_object (filedata)) ret = FALSE; } fclose (filedata->handle); + free (filedata->section_headers); + free (filedata->program_headers); + free (filedata->string_table); + free (filedata->dump.dump_sects); free (filedata); + free (ba_cache.strtab); + ba_cache.strtab = NULL; + free (ba_cache.symtab); + ba_cache.symtab = NULL; + ba_cache.filedata = NULL; + return ret; } @@ -20459,13 +20727,17 @@ main (int argc, char ** argv) expandargv (&argc, &argv); - cmdline.file_name = ""; parse_args (& cmdline, argc, argv); if (optind < (argc - 1)) + /* When displaying information for more than one file, + prefix the information with the file name. */ show_name = TRUE; else if (optind >= argc) { + /* Ensure that the warning is always displayed. */ + do_checks = TRUE; + warn (_("Nothing to do.\n")); usage (stderr); } @@ -20475,8 +20747,7 @@ main (int argc, char ** argv) if (! process_file (argv[optind++])) err = TRUE; - if (cmdline.dump_sects != NULL) - free (cmdline.dump_sects); + free (cmdline.dump_sects); free (dump_ctf_symtab_name); free (dump_ctf_strtab_name);