DWARF-5: readelf: .debug_names
Display DWARF-5 .debug_names (standardized .gdb_index). binutils/ChangeLog 2017-07-02 Jan Kratochvil <jan.kratochvil@redhat.com> * dwarf.c: Include assert.h. (MAX, MIN, get_IDX_name, display_debug_names): New. (debug_displays): Add .debug_names. * dwarf.h: (enum dwarf_section_display_enum): Add debug_names. * readelf.c (process_section_headers): Add ".debug_names".
This commit is contained in:
parent
de837d77bc
commit
613643582c
|
@ -1,3 +1,11 @@
|
|||
2017-07-02 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
* dwarf.c: Include assert.h.
|
||||
(MAX, MIN, get_IDX_name, display_debug_names): New.
|
||||
(debug_displays): Add .debug_names.
|
||||
* dwarf.h: (enum dwarf_section_display_enum): Add debug_names.
|
||||
* readelf.c (process_section_headers): Add ".debug_names".
|
||||
|
||||
2017-07-01 Alan Modra <amodra@gmail.com>
|
||||
|
||||
PR binutils/21665
|
||||
|
|
365
binutils/dwarf.c
365
binutils/dwarf.c
|
@ -28,6 +28,12 @@
|
|||
#include "dwarf2.h"
|
||||
#include "dwarf.h"
|
||||
#include "gdb/gdb-index.h"
|
||||
#include <assert.h>
|
||||
|
||||
#undef MAX
|
||||
#undef MIN
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
static const char *regname (unsigned int regno, int row);
|
||||
|
||||
|
@ -961,6 +967,22 @@ get_FORM_name (unsigned long form)
|
|||
return name;
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_IDX_name (unsigned long idx)
|
||||
{
|
||||
const char *name = get_DW_IDX_name ((unsigned int) idx);
|
||||
|
||||
if (name == NULL)
|
||||
{
|
||||
static char buffer[100];
|
||||
|
||||
snprintf (buffer, sizeof (buffer), _("Unknown IDX value: %lx"), idx);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
display_block (unsigned char *data,
|
||||
dwarf_vma length,
|
||||
|
@ -7633,6 +7655,347 @@ display_debug_frames (struct dwarf_section *section,
|
|||
|
||||
#undef GET
|
||||
|
||||
static int
|
||||
display_debug_names (struct dwarf_section *section, void *file)
|
||||
{
|
||||
unsigned char *hdrptr = section->start;
|
||||
dwarf_vma unit_length;
|
||||
unsigned char *unit_start;
|
||||
const unsigned char *const section_end = section->start + section->size;
|
||||
unsigned char *unit_end;
|
||||
|
||||
printf (_("Contents of the %s section:\n"), section->name);
|
||||
|
||||
load_debug_section (str, file);
|
||||
|
||||
for (; hdrptr < section_end; hdrptr = unit_end)
|
||||
{
|
||||
unsigned int offset_size;
|
||||
uint16_t dwarf_version, padding;
|
||||
uint32_t comp_unit_count, local_type_unit_count, foreign_type_unit_count;
|
||||
uint32_t bucket_count, name_count, abbrev_table_size;
|
||||
uint32_t augmentation_string_size;
|
||||
unsigned int i;
|
||||
|
||||
unit_start = hdrptr;
|
||||
|
||||
/* Get and check the length of the block. */
|
||||
SAFE_BYTE_GET_AND_INC (unit_length, hdrptr, 4, section_end);
|
||||
|
||||
if (unit_length == 0xffffffff)
|
||||
{
|
||||
/* This section is 64-bit DWARF. */
|
||||
SAFE_BYTE_GET_AND_INC (unit_length, hdrptr, 8, section_end);
|
||||
offset_size = 8;
|
||||
}
|
||||
else
|
||||
offset_size = 4;
|
||||
unit_end = hdrptr + unit_length;
|
||||
|
||||
if ((hdrptr - section->start) + unit_length > section->size)
|
||||
{
|
||||
warn (_("The length field (0x%lx) for unit 0x%lx in the debug_names "
|
||||
"header is wrong - the section is too small\n"),
|
||||
(long) unit_length, (long) (unit_start - section->start));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get and check the version number. */
|
||||
SAFE_BYTE_GET_AND_INC (dwarf_version, hdrptr, 2, unit_end);
|
||||
printf (_("Version %ld\n"), (long) dwarf_version);
|
||||
|
||||
/* Prior versions did not exist, and future versions may not be
|
||||
backwards compatible. */
|
||||
if (dwarf_version != 5)
|
||||
{
|
||||
warn (_("Only DWARF version 5 .debug_names "
|
||||
"is currently supported.\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
SAFE_BYTE_GET_AND_INC (padding, hdrptr, 2, unit_end);
|
||||
if (padding != 0)
|
||||
warn (_("Padding field of .debug_names must be 0 (found 0x%x)\n"),
|
||||
padding);
|
||||
|
||||
SAFE_BYTE_GET_AND_INC (comp_unit_count, hdrptr, 4, unit_end);
|
||||
if (comp_unit_count == 0)
|
||||
warn (_("Compilation unit count must be >= 1 in .debug_names\n"));
|
||||
|
||||
SAFE_BYTE_GET_AND_INC (local_type_unit_count, hdrptr, 4, unit_end);
|
||||
SAFE_BYTE_GET_AND_INC (foreign_type_unit_count, hdrptr, 4, unit_end);
|
||||
SAFE_BYTE_GET_AND_INC (bucket_count, hdrptr, 4, unit_end);
|
||||
SAFE_BYTE_GET_AND_INC (name_count, hdrptr, 4, unit_end);
|
||||
SAFE_BYTE_GET_AND_INC (abbrev_table_size, hdrptr, 4, unit_end);
|
||||
|
||||
SAFE_BYTE_GET_AND_INC (augmentation_string_size, hdrptr, 4, unit_end);
|
||||
if (augmentation_string_size % 4 != 0)
|
||||
{
|
||||
warn (_("Augmentation string length %u must be rounded up "
|
||||
"to a multiple of 4 in .debug_names.\n"),
|
||||
augmentation_string_size);
|
||||
augmentation_string_size += (-augmentation_string_size) & 3;
|
||||
}
|
||||
printf (_("Augmentation string:"));
|
||||
for (i = 0; i < augmentation_string_size; i++)
|
||||
{
|
||||
unsigned char uc;
|
||||
|
||||
SAFE_BYTE_GET_AND_INC (uc, hdrptr, 1, unit_end);
|
||||
printf (" %02x", uc);
|
||||
}
|
||||
putchar ('\n');
|
||||
putchar ('\n');
|
||||
|
||||
printf (_("CU table:\n"));
|
||||
for (i = 0; i < comp_unit_count; i++)
|
||||
{
|
||||
uint64_t cu_offset;
|
||||
|
||||
SAFE_BYTE_GET_AND_INC (cu_offset, hdrptr, offset_size, unit_end);
|
||||
printf (_("[%3u] 0x%lx\n"), i, (unsigned long) cu_offset);
|
||||
}
|
||||
putchar ('\n');
|
||||
|
||||
printf (_("TU table:\n"));
|
||||
for (i = 0; i < local_type_unit_count; i++)
|
||||
{
|
||||
uint64_t tu_offset;
|
||||
|
||||
SAFE_BYTE_GET_AND_INC (tu_offset, hdrptr, offset_size, unit_end);
|
||||
printf (_("[%3u] 0x%lx\n"), i, (unsigned long) tu_offset);
|
||||
}
|
||||
putchar ('\n');
|
||||
|
||||
printf (_("Foreign TU table:\n"));
|
||||
for (i = 0; i < foreign_type_unit_count; i++)
|
||||
{
|
||||
uint64_t signature;
|
||||
|
||||
SAFE_BYTE_GET_AND_INC (signature, hdrptr, 8, unit_end);
|
||||
printf (_("[%3u] "), i);
|
||||
print_dwarf_vma (signature, 8);
|
||||
putchar ('\n');
|
||||
}
|
||||
putchar ('\n');
|
||||
|
||||
const uint32_t *const hash_table_buckets = (uint32_t *) hdrptr;
|
||||
hdrptr += bucket_count * sizeof (uint32_t);
|
||||
const uint32_t *const hash_table_hashes = (uint32_t *) hdrptr;
|
||||
hdrptr += name_count * sizeof (uint32_t);
|
||||
unsigned char *const name_table_string_offsets = hdrptr;
|
||||
hdrptr += name_count * offset_size;
|
||||
unsigned char *const name_table_entry_offsets = hdrptr;
|
||||
hdrptr += name_count * offset_size;
|
||||
unsigned char *const abbrev_table = hdrptr;
|
||||
hdrptr += abbrev_table_size;
|
||||
const unsigned char *const abbrev_table_end = hdrptr;
|
||||
unsigned char *const entry_pool = hdrptr;
|
||||
if (hdrptr > unit_end)
|
||||
{
|
||||
warn (_("Entry pool offset (0x%lx) exceeds unit size 0x%lx "
|
||||
"for unit 0x%lx in the debug_names\n"),
|
||||
(long) (hdrptr - section->start),
|
||||
(long) (unit_end - section->start),
|
||||
(long) (unit_start - section->start));
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t buckets_filled = 0;
|
||||
size_t bucketi;
|
||||
for (bucketi = 0; bucketi < bucket_count; bucketi++)
|
||||
{
|
||||
const uint32_t bucket = hash_table_buckets[bucketi];
|
||||
|
||||
if (bucket != 0)
|
||||
++buckets_filled;
|
||||
}
|
||||
printf (_("Used %zu of %lu buckets.\n"), buckets_filled,
|
||||
(unsigned long) bucket_count);
|
||||
|
||||
uint32_t hash_prev;
|
||||
size_t hash_clash_count = 0;
|
||||
size_t longest_clash = 0;
|
||||
size_t this_length = 0;
|
||||
size_t hashi;
|
||||
for (hashi = 0; hashi < name_count; hashi++)
|
||||
{
|
||||
const uint32_t hash_this = hash_table_hashes[hashi];
|
||||
|
||||
if (hashi > 0)
|
||||
{
|
||||
if (hash_prev % bucket_count == hash_this % bucket_count)
|
||||
{
|
||||
++hash_clash_count;
|
||||
++this_length;
|
||||
longest_clash = MAX (longest_clash, this_length);
|
||||
}
|
||||
else
|
||||
this_length = 0;
|
||||
}
|
||||
hash_prev = hash_this;
|
||||
}
|
||||
printf (_("Out of %lu items there are %zu bucket clashes"
|
||||
" (longest of %zu entries).\n"),
|
||||
(unsigned long) name_count, hash_clash_count, longest_clash);
|
||||
assert (name_count == buckets_filled + hash_clash_count);
|
||||
|
||||
struct abbrev_lookup_entry
|
||||
{
|
||||
dwarf_vma abbrev_tag;
|
||||
unsigned char *abbrev_lookup_ptr;
|
||||
};
|
||||
struct abbrev_lookup_entry *abbrev_lookup = NULL;
|
||||
size_t abbrev_lookup_used = 0;
|
||||
size_t abbrev_lookup_allocated = 0;
|
||||
|
||||
unsigned char *abbrevptr = abbrev_table;
|
||||
for (;;)
|
||||
{
|
||||
unsigned int bytes_read;
|
||||
const dwarf_vma abbrev_tag = read_uleb128 (abbrevptr, &bytes_read,
|
||||
abbrev_table_end);
|
||||
abbrevptr += bytes_read;
|
||||
if (abbrev_tag == 0)
|
||||
break;
|
||||
if (abbrev_lookup_used == abbrev_lookup_allocated)
|
||||
{
|
||||
abbrev_lookup_allocated = MAX (0x100,
|
||||
abbrev_lookup_allocated * 2);
|
||||
abbrev_lookup = xrealloc (abbrev_lookup,
|
||||
(abbrev_lookup_allocated
|
||||
* sizeof (*abbrev_lookup)));
|
||||
}
|
||||
assert (abbrev_lookup_used < abbrev_lookup_allocated);
|
||||
struct abbrev_lookup_entry *entry;
|
||||
for (entry = abbrev_lookup;
|
||||
entry < abbrev_lookup + abbrev_lookup_used;
|
||||
entry++)
|
||||
if (entry->abbrev_tag == abbrev_tag)
|
||||
{
|
||||
warn (_("Duplicate abbreviation tag %lu "
|
||||
"in unit 0x%lx in the debug_names\n"),
|
||||
(long) abbrev_tag, (long) (unit_start - section->start));
|
||||
break;
|
||||
}
|
||||
entry = &abbrev_lookup[abbrev_lookup_used++];
|
||||
entry->abbrev_tag = abbrev_tag;
|
||||
entry->abbrev_lookup_ptr = abbrevptr;
|
||||
|
||||
/* Skip DWARF tag. */
|
||||
read_uleb128 (abbrevptr, &bytes_read, abbrev_table_end);
|
||||
abbrevptr += bytes_read;
|
||||
for (;;)
|
||||
{
|
||||
const dwarf_vma index = read_uleb128 (abbrevptr, &bytes_read,
|
||||
abbrev_table_end);
|
||||
abbrevptr += bytes_read;
|
||||
const dwarf_vma form = read_uleb128 (abbrevptr, &bytes_read,
|
||||
abbrev_table_end);
|
||||
abbrevptr += bytes_read;
|
||||
if (index == 0 && form == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf (_("\nSymbol table:\n"));
|
||||
uint32_t namei;
|
||||
for (namei = 0; namei < name_count; ++namei)
|
||||
{
|
||||
uint64_t string_offset, entry_offset;
|
||||
|
||||
SAFE_BYTE_GET (string_offset,
|
||||
name_table_string_offsets + namei * offset_size,
|
||||
offset_size, unit_end);
|
||||
SAFE_BYTE_GET (entry_offset,
|
||||
name_table_entry_offsets + namei * offset_size,
|
||||
offset_size, unit_end);
|
||||
|
||||
printf ("[%3u] #%08x %s:", namei, hash_table_hashes[namei],
|
||||
fetch_indirect_string (string_offset));
|
||||
|
||||
unsigned char *entryptr = entry_pool + entry_offset;
|
||||
|
||||
// We need to scan first whether there is a single or multiple
|
||||
// entries. TAGNO is -2 for the first entry, it is -1 for the
|
||||
// initial tag read of the second entry, then it becomes 0 for the
|
||||
// first entry for real printing etc.
|
||||
int tagno = -2;
|
||||
/* Initialize it due to a false compiler warning. */
|
||||
dwarf_vma second_abbrev_tag = -1;
|
||||
for (;;)
|
||||
{
|
||||
unsigned int bytes_read;
|
||||
const dwarf_vma abbrev_tag = read_uleb128 (entryptr, &bytes_read,
|
||||
unit_end);
|
||||
entryptr += bytes_read;
|
||||
if (tagno == -1)
|
||||
{
|
||||
second_abbrev_tag = abbrev_tag;
|
||||
tagno = 0;
|
||||
entryptr = entry_pool + entry_offset;
|
||||
continue;
|
||||
}
|
||||
if (abbrev_tag == 0)
|
||||
break;
|
||||
if (tagno >= 0)
|
||||
printf ("%s<%lu>",
|
||||
(tagno == 0 && second_abbrev_tag == 0 ? " " : "\n\t"),
|
||||
(unsigned long) abbrev_tag);
|
||||
|
||||
const struct abbrev_lookup_entry *entry;
|
||||
for (entry = abbrev_lookup;
|
||||
entry < abbrev_lookup + abbrev_lookup_used;
|
||||
entry++)
|
||||
if (entry->abbrev_tag == abbrev_tag)
|
||||
break;
|
||||
if (entry >= abbrev_lookup + abbrev_lookup_used)
|
||||
{
|
||||
warn (_("Undefined abbreviation tag %lu "
|
||||
"in unit 0x%lx in the debug_names\n"),
|
||||
(long) abbrev_tag,
|
||||
(long) (unit_start - section->start));
|
||||
break;
|
||||
}
|
||||
abbrevptr = entry->abbrev_lookup_ptr;
|
||||
const dwarf_vma dwarf_tag = read_uleb128 (abbrevptr, &bytes_read,
|
||||
abbrev_table_end);
|
||||
abbrevptr += bytes_read;
|
||||
if (tagno >= 0)
|
||||
printf (" %s", get_TAG_name (dwarf_tag));
|
||||
for (;;)
|
||||
{
|
||||
const dwarf_vma index = read_uleb128 (abbrevptr, &bytes_read,
|
||||
abbrev_table_end);
|
||||
abbrevptr += bytes_read;
|
||||
const dwarf_vma form = read_uleb128 (abbrevptr, &bytes_read,
|
||||
abbrev_table_end);
|
||||
abbrevptr += bytes_read;
|
||||
if (index == 0 && form == 0)
|
||||
break;
|
||||
|
||||
if (tagno >= 0)
|
||||
printf (" %s", get_IDX_name (index));
|
||||
entryptr = read_and_display_attr_value (0, form, 0, entryptr,
|
||||
unit_end, 0, 0,
|
||||
offset_size,
|
||||
dwarf_version, NULL,
|
||||
(tagno < 0), NULL,
|
||||
NULL, '=');
|
||||
}
|
||||
++tagno;
|
||||
}
|
||||
if (tagno <= 0)
|
||||
printf (_(" <no entries>"));
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
free (abbrev_lookup);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
display_gdb_index (struct dwarf_section *section,
|
||||
void *file ATTRIBUTE_UNUSED)
|
||||
|
@ -8628,6 +8991,8 @@ struct dwarf_section_display debug_displays[] =
|
|||
display_debug_not_supported, NULL, FALSE },
|
||||
{ { ".gdb_index", "", NULL, NULL, 0, 0, 0, NULL, 0, NULL },
|
||||
display_gdb_index, &do_gdb_index, FALSE },
|
||||
{ { ".debug_names", "", NULL, NULL, 0, 0, 0, NULL, 0, NULL },
|
||||
display_debug_names, &do_gdb_index, FALSE },
|
||||
{ { ".trace_info", "", NULL, NULL, 0, 0, trace_abbrev, NULL, 0, NULL },
|
||||
display_trace_info, &do_trace_info, TRUE },
|
||||
{ { ".trace_abbrev", "", NULL, NULL, 0, 0, 0, NULL, 0, NULL },
|
||||
|
|
|
@ -99,6 +99,7 @@ enum dwarf_section_display_enum
|
|||
types,
|
||||
weaknames,
|
||||
gdb_index,
|
||||
debug_names,
|
||||
trace_info,
|
||||
trace_abbrev,
|
||||
trace_aranges,
|
||||
|
|
|
@ -6060,7 +6060,8 @@ process_section_headers (FILE * file)
|
|||
request_dump_bynumber (i, DEBUG_DUMP);
|
||||
else if (do_debug_frames && streq (name, ".eh_frame"))
|
||||
request_dump_bynumber (i, DEBUG_DUMP);
|
||||
else if (do_gdb_index && streq (name, ".gdb_index"))
|
||||
else if (do_gdb_index && (streq (name, ".gdb_index")
|
||||
|| streq (name, ".debug_names")))
|
||||
request_dump_bynumber (i, DEBUG_DUMP);
|
||||
/* Trace sections for Itanium VMS. */
|
||||
else if ((do_debugging || do_trace_info || do_trace_abbrevs
|
||||
|
|
Loading…
Reference in New Issue