/* A dynamic array of flags indicating for which sections a dump
has been requested via command line switches. */
-struct dump_data {
+struct dump_data
+{
dump_type * dump_sects;
unsigned int num_dump_sects;
};
static bfd_boolean do_arch = FALSE;
static bfd_boolean do_notes = FALSE;
static bfd_boolean do_archive_index = FALSE;
+static bfd_boolean do_checks = FALSE;
+static bfd_boolean check_all = FALSE;
static bfd_boolean is_32bit_elf = FALSE;
static bfd_boolean decompress_dumps = FALSE;
return ret;
}
+/* A version of the warn() function that is disabled if do_checks is not active. */
+
+void
+warn (const char *message, ...)
+{
+ va_list args;
+
+ if (!do_checks)
+ return;
+
+ /* Try to keep warning messages in sync with the program's normal output. */
+ fflush (stdout);
+
+ va_start (args, message);
+ fprintf (stderr, _("%s: Warning: "), program_name);
+ vfprintf (stderr, message, args);
+ va_end (args);
+}
+
/* Retrieve NMEMB structures, each SIZE bytes long from FILEDATA starting at
OFFSET + the offset of the current archive member, if we are examining an
archive. Put the retrieved data into VAR, if it is not NULL. Otherwise
{"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'},
-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\
-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=<number|name>\n\
Dump the contents of section <number|name> as bytes\n\
-p --string-dump=<number|name>\n\
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)
{
case 'c':
do_archive_index = TRUE;
break;
+ case 'L':
+ do_checks = TRUE;
+ break;
case 'x':
request_dump (dumpdata, HEX_DUMP);
break;
&& !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 *
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;
{
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)
{
+ case SHT_DYNSYM:
if (filedata->dynamic_symbols != NULL)
{
error (_("File contains multiple dynamic symbol tables\n"));
CHECK_ENTSIZE (section, i, Sym);
filedata->dynamic_symbols
= GET_ELF_SYMBOLS (filedata, section, &filedata->num_dynamic_syms);
- }
- else if (section->sh_type == SHT_STRTAB
- && streq (name, ".dynstr"))
- {
- if (filedata->dynamic_strings != NULL)
+ 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;
}
+ 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;
- 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;
- }
- else if (section->sh_type == SHT_SYMTAB_SHNDX)
- {
- elf_section_list * entry = xmalloc (sizeof * entry);
-
- entry->hdr = section;
- entry->next = filedata->symtab_shndx_list;
- filedata->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_REL:
+ CHECK_ENTSIZE (section, i, Rel);
+ if (section->sh_size == 0)
+ warn (_("Section '%s': zero-sized relocation section\n"), name);
+ break;
+
+ case SHT_RELA:
+ CHECK_ENTSIZE (section, i, Rela);
+ if (section->sh_size == 0)
+ warn (_("Section '%s': zero-sized relocation section\n"), name);
+ break;
+
+ case SHT_NOTE:
+ case SHT_PROGBITS:
+ if (section->sh_size == 0)
+ /* This is not illegal according to the ELF standard, but
+ it might be an indication that something is wrong. */
+ 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;
filedata->nbuckets = byte_get (nb, hash_ent_size);
filedata->nchains = byte_get (nc, hash_ent_size);
- filedata->buckets = get_dynamic_data (filedata, filedata->nbuckets,
- hash_ent_size);
- filedata->chains = get_dynamic_data (filedata, filedata->nchains,
- hash_ent_size);
-
- if (filedata->buckets != NULL && filedata->chains != NULL)
- num_of_syms = filedata->nchains;
+ 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 (filedata->buckets != NULL && filedata->chains != NULL)
+ num_of_syms = filedata->nchains;
+ }
no_hash:
if (num_of_syms == 0)
{
bfd_vma i, maxchain = 0xffffffff, bitmaskwords;
bfd_vma buckets_vma;
unsigned long hn;
- bfd_boolean gnu_hash_error = FALSE;
if (fseek (filedata->handle,
(filedata->archive_file_offset
SEEK_SET))
{
error (_("Unable to seek to start of dynamic information\n"));
- gnu_hash_error = TRUE;
goto no_gnu_hash;
}
if (fread (nb, 16, 1, filedata->handle) != 1)
{
error (_("Failed to read in number of buckets\n"));
- gnu_hash_error = TRUE;
goto no_gnu_hash;
}
SEEK_SET))
{
error (_("Unable to seek to start of dynamic information\n"));
- gnu_hash_error = TRUE;
goto no_gnu_hash;
}
= get_dynamic_data (filedata, filedata->ngnubuckets, 4);
if (filedata->gnubuckets == NULL)
- {
- gnu_hash_error = TRUE;
- goto no_gnu_hash;
- }
+ goto no_gnu_hash;
for (i = 0; i < filedata->ngnubuckets; i++)
if (filedata->gnubuckets[i] != 0)
{
if (filedata->gnubuckets[i] < filedata->gnusymidx)
- {
- gnu_hash_error = TRUE;
- goto no_gnu_hash;
- }
+ goto no_gnu_hash;
if (maxchain == 0xffffffff || filedata->gnubuckets[i] > maxchain)
maxchain = filedata->gnubuckets[i];
}
if (maxchain == 0xffffffff)
- {
- gnu_hash_error = TRUE;
- goto no_gnu_hash;
- }
+ goto no_gnu_hash;
maxchain -= filedata->gnusymidx;
SEEK_SET))
{
error (_("Unable to seek to start of dynamic information\n"));
- gnu_hash_error = TRUE;
goto no_gnu_hash;
}
if (fread (nb, 4, 1, filedata->handle) != 1)
{
error (_("Failed to determine last chain length\n"));
- gnu_hash_error = TRUE;
goto no_gnu_hash;
}
if (maxchain + 1 == 0)
- {
- gnu_hash_error = TRUE;
- goto no_gnu_hash;
- }
+ goto no_gnu_hash;
++maxchain;
}
SEEK_SET))
{
error (_("Unable to seek to start of dynamic information\n"));
- gnu_hash_error = TRUE;
goto no_gnu_hash;
}
filedata->ngnuchains = maxchain;
if (filedata->gnuchains == NULL)
- {
- gnu_hash_error = TRUE;
- goto no_gnu_hash;
- }
+ goto no_gnu_hash;
if (filedata->dynamic_info_DT_MIPS_XHASH)
{
SEEK_SET))
{
error (_("Unable to seek to start of dynamic information\n"));
- gnu_hash_error = TRUE;
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)
&& (filedata->gnuchains[off++] & 1) == 0);
}
- no_gnu_hash:
- if (gnu_hash_error)
+ if (num_of_syms == 0)
{
+ no_gnu_hash:
if (filedata->mipsxlat)
{
free (filedata->mipsxlat);
/* 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)
filedata->dynamic_info_DT_GNU_HASH = entry->d_un.d_val;
}
- if (filedata->dynamic_info[DT_SYMTAB]
+ 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 (_("Cannot interpret virtual addresses without program headers.\n"));
- return FALSE;
- }
+ bfd_vma vma = filedata->dynamic_info[DT_SYMTAB];
- for (seg = filedata->program_headers;
- seg < filedata->program_headers + filedata->file_header.e_phnum;
- ++seg)
- {
- unsigned long num_of_syms;
+ if (! get_program_headers (filedata))
+ {
+ error (_("Cannot interpret virtual addresses "
+ "without program headers.\n"));
+ return FALSE;
+ }
- if (seg->p_type != PT_LOAD)
- continue;
+ 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 (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
- && (num_of_syms = get_num_dynamic_syms (filedata)) != 0
- && filedata->dynamic_symbols == NULL)
- {
- /* 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];
- 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;
- }
- }
- }
- }
- }
+ 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];
+ 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)
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;
}
- filedata->dynamic_syminfo_nent = syminsz / sizeof (Elf_External_Syminfo);
+ 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 < (filedata->dynamic_syminfo
+ + filedata->dynamic_syminfo_nent);
++syminfo, ++extsym)
{
syminfo->si_boundto = BYTE_GET (extsym->si_boundto);
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");
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:
{
bfd_boolean have_separate_files;
unsigned int i;
- bfd_boolean res = TRUE;
+ bfd_boolean res;
if (! get_file_header (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;
}
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);
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);
}