aboutsummaryrefslogtreecommitdiff
path: root/binutils/dwarf.c
diff options
context:
space:
mode:
authorAlexandre Oliva <aoliva@redhat.com>2017-09-22 17:05:51 -0300
committerAlexandre Oliva <aoliva@redhat.com>2017-09-22 17:05:51 -0300
commit9f272209118972864b2c3799ddf2b39683c1a7b7 (patch)
treed58a44a74397bb6499ee83ea011bf156c66b9cff /binutils/dwarf.c
parent43573013c9836f2b91b74b9b29dac35fdb41e06b (diff)
downloadgdb-9f272209118972864b2c3799ddf2b39683c1a7b7.zip
gdb-9f272209118972864b2c3799ddf2b39683c1a7b7.tar.gz
gdb-9f272209118972864b2c3799ddf2b39683c1a7b7.tar.bz2
LVU: dump loclists with locviews
When dumping location lists, also dump locview lists that may be interspersed with them, and bring view pairs next to the corresponding location list entries. This patch supports DW_AT_GNU_locviews as a separate attribute for DWARF4- loc_lists and split (dwo) loclists, as well as DWARF5 loclists. It also supports, in DWARF5 loclists, the proposed DW_LLE_GNU_view_pair loclist entry type proposed for DWARF6. The tests use 32-bit DWARF, even on 64-bit targets, resolving offsets to constants so as to reduce the risk that relocations be created for them, or that the offsets be rejected as nonconstants. The patch also adds an xfail to an unrelated test, namely dw5, so that no unexpected fails remain on nds32*-elf, one of the tested targets. Reviewed-by: Alan Modra <amodra@gmail.com> for include/ChangeLog * dwarf2.def (DW_AT_GNU_locviews): New. * dwarf2.h (enum dwarf_location_list_entry_type): Add DW_LLE_GNU_view_pair. (DW_LLE_view_pair): Define. for binutils/ChangeLog * dwarf.h (debug_info): Add loc_views and num_loc_views. * dwarf.c (vm1): New constant. (print_dwarf_view): New function. (read_and_display_attr_value): Support DW_AT_GNU_locviews. (process_debug_info): Keep num_loc_offsets and num_loc_views in sync. (display_view_pair_list): New function. (display_loc_list_dwo): Take vstart_ptr; update it. Dump location view pairs before the range they apply to, when a viewlist augments the loc list. (display_loc_list): Likewise. Check view numbers in range tests. (display_loclists_list): Likewise. Handle view pair entries, and warn on trailing ones. (loc_views): New variable. (loc_offsets_compar): Compare loc_views if loc_offsets are the same. (display_debug_loc): Check and sort loc_views too. Accept loc_view as expected_start. Skip if lists and views are the same. Dump locview list separately in order, and pass the locview list base to each list dump function. Warn and skip overlap and hole checking if we find loclists and locviews to not be adjacent. * testsuite/binutils-all/locview-1.s: New. * testsuite/binutils-all/readelf.locview-1: New. * testsuite/binutils-all/locview-2.s: New. * testsuite/binutils-all/readelf.locview-2: New. * testsuite/binutils-all/readelf.exp: Run new tests. Fix option spelling in pr18374 fail message. XFAIL dw5 test on nds32*-elf.
Diffstat (limited to 'binutils/dwarf.c')
-rw-r--r--binutils/dwarf.c332
1 files changed, 298 insertions, 34 deletions
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index d2fc799..af8732b 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -74,6 +74,10 @@ unsigned long dwarf_start_die;
int dwarf_check = 0;
+/* Convenient constant, to avoid having to cast -1 to dwarf_vma when
+ testing whether e.g. a locview list is present. */
+static const dwarf_vma vm1 = -1;
+
/* Collection of CU/TU section sets from .debug_cu_index and .debug_tu_index
sections. For version 1 package files, each set is stored in SHNDX_POOL
as a zero-terminated list of section indexes comprising one set of debug
@@ -239,6 +243,26 @@ print_dwarf_vma (dwarf_vma value, unsigned num_bytes)
printf ("%s ", dwarf_vmatoa_1 (NULL, value, num_bytes));
}
+/* Print a view number in hexadecimal value, with the same width
+ print_dwarf_vma would have printed it with the same num_bytes.
+ Print blanks for zero view, unless force is nonzero. */
+
+static void
+print_dwarf_view (dwarf_vma value, unsigned num_bytes, int force)
+{
+ int len;
+ if (!num_bytes)
+ len = 4;
+ else
+ len = num_bytes * 2;
+
+ assert (value == (unsigned long) value);
+ if (value || force)
+ printf ("v%0*lx ", len - 1, (unsigned long) value);
+ else
+ printf ("%*s", len + 1, "");
+}
+
/* Format a 64-bit value, given as two 32-bit values, in hex.
For reentrancy, this uses a buffer provided by the caller. */
@@ -2012,6 +2036,7 @@ read_and_display_attr_value (unsigned long attribute,
have_frame_base = 1;
/* Fall through. */
case DW_AT_location:
+ case DW_AT_GNU_locviews:
case DW_AT_string_length:
case DW_AT_return_addr:
case DW_AT_data_member_location:
@@ -2041,6 +2066,9 @@ read_and_display_attr_value (unsigned long attribute,
debug_info_p->loc_offsets = (dwarf_vma *)
xcrealloc (debug_info_p->loc_offsets,
lmax, sizeof (*debug_info_p->loc_offsets));
+ debug_info_p->loc_views = (dwarf_vma *)
+ xcrealloc (debug_info_p->loc_views,
+ lmax, sizeof (*debug_info_p->loc_views));
debug_info_p->have_frame_base = (int *)
xcrealloc (debug_info_p->have_frame_base,
lmax, sizeof (*debug_info_p->have_frame_base));
@@ -2048,9 +2076,23 @@ read_and_display_attr_value (unsigned long attribute,
}
if (this_set != NULL)
uvalue += this_set->section_offsets [DW_SECT_LOC];
- debug_info_p->loc_offsets [num] = uvalue;
debug_info_p->have_frame_base [num] = have_frame_base;
- debug_info_p->num_loc_offsets++;
+ if (attribute != DW_AT_GNU_locviews)
+ {
+ debug_info_p->loc_offsets [num] = uvalue;
+ debug_info_p->num_loc_offsets++;
+ assert (debug_info_p->num_loc_offsets
+ - debug_info_p->num_loc_views <= 1);
+ }
+ else
+ {
+ assert (debug_info_p->num_loc_views <= num);
+ num = debug_info_p->num_loc_views;
+ debug_info_p->loc_views [num] = uvalue;
+ debug_info_p->num_loc_views++;
+ assert (debug_info_p->num_loc_views
+ - debug_info_p->num_loc_offsets <= 1);
+ }
}
break;
@@ -2858,21 +2900,22 @@ process_debug_info (struct dwarf_section *section,
break;
}
+ debug_info *debug_info_p =
+ (debug_information && unit < alloc_num_debug_info_entries)
+ ? debug_information + unit : NULL;
+
+ assert (!debug_info_p
+ || (debug_info_p->num_loc_offsets
+ == debug_info_p->num_loc_views));
+
for (attr = entry->first_attr;
attr && attr->attribute;
attr = attr->next)
{
- debug_info *arg;
-
if (! do_loc && do_printing)
/* Show the offset from where the tag was extracted. */
printf (" <%lx>", (unsigned long)(tags - section_begin));
- if (debug_information && unit < alloc_num_debug_info_entries)
- arg = debug_information + unit;
- else
- arg = NULL;
-
tags = read_and_display_attr (attr->attribute,
attr->form,
attr->implicit_const,
@@ -2882,12 +2925,37 @@ process_debug_info (struct dwarf_section *section,
compunit.cu_pointer_size,
offset_size,
compunit.cu_version,
- arg,
+ debug_info_p,
do_loc || ! do_printing,
section,
this_set);
}
+ /* If a locview attribute appears before a location one,
+ make sure we don't associate it with an earlier
+ loclist. */
+ if (debug_info_p)
+ switch (debug_info_p->num_loc_offsets - debug_info_p->num_loc_views)
+ {
+ case 1:
+ debug_info_p->loc_views [debug_info_p->num_loc_views] = vm1;
+ debug_info_p->num_loc_views++;
+ assert (debug_info_p->num_loc_views
+ == debug_info_p->num_loc_offsets);
+ break;
+
+ case 0:
+ break;
+
+ case -1:
+ warn(_("DIE has locviews without loclist\n"));
+ debug_info_p->num_loc_views--;
+ break;
+
+ default:
+ assert (0);
+ }
+
if (entry->children)
++level;
}
@@ -5023,6 +5091,52 @@ is_max_address (dwarf_vma addr, unsigned int pointer_size)
return ((addr & mask) == mask);
}
+/* Display a view pair list starting at *VSTART_PTR and ending at
+ VLISTEND within SECTION. */
+
+static void
+display_view_pair_list (struct dwarf_section *section,
+ unsigned char **vstart_ptr,
+ unsigned int debug_info_entry,
+ unsigned char *vlistend)
+{
+ unsigned char *vstart = *vstart_ptr;
+ unsigned char *section_end = section->start + section->size;
+ unsigned int pointer_size = debug_information [debug_info_entry].pointer_size;
+
+ if (vlistend < section_end)
+ section_end = vlistend;
+
+ putchar ('\n');
+
+ while (vstart < section_end)
+ {
+ dwarf_vma off = vstart - section->start;
+ dwarf_vma vbegin, vend;
+
+ unsigned int bytes_read;
+ vbegin = read_uleb128 (vstart, &bytes_read, section_end);
+ vstart += bytes_read;
+ if (vstart == section_end)
+ {
+ vstart -= bytes_read;
+ break;
+ }
+
+ vend = read_uleb128 (vstart, &bytes_read, section_end);
+ vstart += bytes_read;
+
+ printf (" %8.8lx ", (unsigned long) off);
+
+ print_dwarf_view (vbegin, pointer_size, 1);
+ print_dwarf_view (vend, pointer_size, 1);
+ printf (_("location view pair\n"));
+ }
+
+ putchar ('\n');
+ *vstart_ptr = vstart;
+}
+
/* Display a location list from a normal (ie, non-dwo) .debug_loc section. */
static void
@@ -5031,9 +5145,10 @@ display_loc_list (struct dwarf_section *section,
unsigned int debug_info_entry,
dwarf_vma offset,
dwarf_vma base_address,
+ unsigned char **vstart_ptr,
int has_frame_base)
{
- unsigned char *start = *start_ptr;
+ unsigned char *start = *start_ptr, *vstart = *vstart_ptr;
unsigned char *section_end = section->start + section->size;
unsigned long cu_offset;
unsigned int pointer_size;
@@ -5067,6 +5182,7 @@ display_loc_list (struct dwarf_section *section,
while (1)
{
dwarf_vma off = offset + (start - *start_ptr);
+ dwarf_vma vbegin = vm1, vend = vm1;
if (start + 2 * pointer_size > section_end)
{
@@ -5107,6 +5223,24 @@ display_loc_list (struct dwarf_section *section,
continue;
}
+ if (vstart)
+ {
+ unsigned int bytes_read;
+
+ off = offset + (vstart - *start_ptr);
+
+ vbegin = read_uleb128 (vstart, &bytes_read, section_end);
+ vstart += bytes_read;
+ print_dwarf_view (vbegin, pointer_size, 1);
+
+ vend = read_uleb128 (vstart, &bytes_read, section_end);
+ vstart += bytes_read;
+ print_dwarf_view (vend, pointer_size, 1);
+
+ printf (_("views at %8.8lx for:\n %*s "),
+ (unsigned long) off, 8, "");
+ }
+
if (start + 2 > section_end)
{
warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
@@ -5138,9 +5272,9 @@ display_loc_list (struct dwarf_section *section,
if (need_frame_base && !has_frame_base)
printf (_(" [without DW_AT_frame_base]"));
- if (begin == end)
+ if (begin == end && vbegin == vend)
fputs (_(" (start == end)"), stdout);
- else if (begin > end)
+ else if (begin > end || (begin == end && vbegin > vend))
fputs (_(" (start > end)"), stdout);
putchar ('\n');
@@ -5149,6 +5283,7 @@ display_loc_list (struct dwarf_section *section,
}
*start_ptr = start;
+ *vstart_ptr = vstart;
}
/* Display a location list from a normal (ie, non-dwo) .debug_loclists section. */
@@ -5159,9 +5294,10 @@ display_loclists_list (struct dwarf_section *section,
unsigned int debug_info_entry,
dwarf_vma offset,
dwarf_vma base_address,
+ unsigned char **vstart_ptr,
int has_frame_base)
{
- unsigned char *start = *start_ptr;
+ unsigned char *start = *start_ptr, *vstart = *vstart_ptr;
unsigned char *section_end = section->start + section->size;
unsigned long cu_offset;
unsigned int pointer_size;
@@ -5170,8 +5306,8 @@ display_loclists_list (struct dwarf_section *section,
unsigned int bytes_read;
/* Initialize it due to a false compiler warning. */
- dwarf_vma begin = -1;
- dwarf_vma end = -1;
+ dwarf_vma begin = -1, vbegin = -1;
+ dwarf_vma end = -1, vend = -1;
dwarf_vma length;
int need_frame_base;
@@ -5211,6 +5347,22 @@ display_loclists_list (struct dwarf_section *section,
SAFE_BYTE_GET_AND_INC (llet, start, 1, section_end);
+ if (vstart && llet == DW_LLE_offset_pair)
+ {
+ off = offset + (vstart - *start_ptr);
+
+ vbegin = read_uleb128 (vstart, &bytes_read, section_end);
+ vstart += bytes_read;
+ print_dwarf_view (vbegin, pointer_size, 1);
+
+ vend = read_uleb128 (vstart, &bytes_read, section_end);
+ vstart += bytes_read;
+ print_dwarf_view (vend, pointer_size, 1);
+
+ printf (_("views at %8.8lx for:\n %*s "),
+ (unsigned long) off, 8, "");
+ }
+
switch (llet)
{
case DW_LLE_end_of_list:
@@ -5228,6 +5380,21 @@ display_loclists_list (struct dwarf_section *section,
print_dwarf_vma (base_address, pointer_size);
printf (_("(base address)\n"));
break;
+#ifdef DW_LLE_view_pair
+ case DW_LLE_view_pair:
+ if (vstart)
+ printf (_("View pair entry in loclist with locviews attribute\n"));
+ vbegin = read_uleb128 (start, &bytes_read, section_end);
+ start += bytes_read;
+ print_dwarf_view (vbegin, pointer_size, 1);
+
+ vend = read_uleb128 (start, &bytes_read, section_end);
+ start += bytes_read;
+ print_dwarf_view (vend, pointer_size, 1);
+
+ printf (_("views for:\n"));
+ continue;
+#endif
default:
error (_("Invalid location list entry type %d\n"), llet);
return;
@@ -5262,17 +5429,22 @@ display_loclists_list (struct dwarf_section *section,
if (need_frame_base && !has_frame_base)
printf (_(" [without DW_AT_frame_base]"));
- if (begin == end)
+ if (begin == end && vbegin == vend)
fputs (_(" (start == end)"), stdout);
- else if (begin > end)
+ else if (begin > end || (begin == end && vbegin > vend))
fputs (_(" (start > end)"), stdout);
putchar ('\n');
start += length;
+ vbegin = vend = -1;
}
+ if (vbegin != vm1 || vend != vm1)
+ printf (_("Trailing view pair not used in a range"));
+
*start_ptr = start;
+ *vstart_ptr = vstart;
}
/* Print a .debug_addr table index in decimal, surrounded by square brackets,
@@ -5295,9 +5467,10 @@ display_loc_list_dwo (struct dwarf_section *section,
unsigned char **start_ptr,
unsigned int debug_info_entry,
dwarf_vma offset,
+ unsigned char **vstart_ptr,
int has_frame_base)
{
- unsigned char *start = *start_ptr;
+ unsigned char *start = *start_ptr, *vstart = *vstart_ptr;
unsigned char *section_end = section->start + section->size;
unsigned long cu_offset;
unsigned int pointer_size;
@@ -5340,17 +5513,47 @@ display_loc_list_dwo (struct dwarf_section *section,
}
SAFE_BYTE_GET_AND_INC (entry_type, start, 1, section_end);
+
+ if (vstart)
+ switch (entry_type)
+ {
+ default:
+ break;
+
+ case 2:
+ case 3:
+ case 4:
+ {
+ dwarf_vma view;
+ dwarf_vma off = offset + (vstart - *start_ptr);
+
+ view = read_uleb128 (vstart, &bytes_read, section_end);
+ vstart += bytes_read;
+ print_dwarf_view (view, 8, 1);
+
+ view = read_uleb128 (vstart, &bytes_read, section_end);
+ vstart += bytes_read;
+ print_dwarf_view (view, 8, 1);
+
+ printf (_("views at %8.8lx for:\n %*s "),
+ (unsigned long) off, 8, "");
+
+ }
+ break;
+ }
+
switch (entry_type)
{
case 0: /* A terminating entry. */
*start_ptr = start;
+ *vstart_ptr = vstart;
printf (_("<End of list>\n"));
return;
case 1: /* A base-address entry. */
idx = read_uleb128 (start, &bytes_read, section_end);
start += bytes_read;
print_addr_index (idx, 8);
- printf (" ");
+ printf ("%*s", 9 + (vstart ? 2 * 6 : 0), "");
printf (_("(base address selection entry)\n"));
continue;
case 2: /* A start/end entry. */
@@ -5377,6 +5580,7 @@ display_loc_list_dwo (struct dwarf_section *section,
default:
warn (_("Unknown location list entry type 0x%x.\n"), entry_type);
*start_ptr = start;
+ *vstart_ptr = vstart;
return;
}
@@ -5413,11 +5617,13 @@ display_loc_list_dwo (struct dwarf_section *section,
}
*start_ptr = start;
+ *vstart_ptr = vstart;
}
-/* Sort array of indexes in ascending order of loc_offsets[idx]. */
+/* Sort array of indexes in ascending order of loc_offsets[idx] and
+ loc_views. */
-static dwarf_vma *loc_offsets;
+static dwarf_vma *loc_offsets, *loc_views;
static int
loc_offsets_compar (const void *ap, const void *bp)
@@ -5425,23 +5631,33 @@ loc_offsets_compar (const void *ap, const void *bp)
dwarf_vma a = loc_offsets[*(const unsigned int *) ap];
dwarf_vma b = loc_offsets[*(const unsigned int *) bp];
- return (a > b) - (b > a);
+ int ret = (a > b) - (b > a);
+ if (ret)
+ return ret;
+
+ a = loc_views[*(const unsigned int *) ap];
+ b = loc_views[*(const unsigned int *) bp];
+
+ ret = (a > b) - (b > a);
+
+ return ret;
}
static int
display_debug_loc (struct dwarf_section *section, void *file)
{
- unsigned char *start = section->start;
+ unsigned char *start = section->start, *vstart = NULL;
unsigned long bytes;
unsigned char *section_begin = start;
unsigned int num_loc_list = 0;
unsigned long last_offset = 0;
+ unsigned long last_view = 0;
unsigned int first = 0;
unsigned int i;
unsigned int j;
int seen_first_offset = 0;
int locs_sorted = 1;
- unsigned char *next;
+ unsigned char *next = start, *vnext = vstart;
unsigned int *array = NULL;
const char *suffix = strrchr (section->name, '.');
int is_dwo = 0;
@@ -5529,6 +5745,7 @@ display_debug_loc (struct dwarf_section *section, void *file)
{
/* This is the first location list. */
last_offset = debug_information [i].loc_offsets [0];
+ last_view = debug_information [i].loc_views [0];
first = i;
seen_first_offset = 1;
j = 1;
@@ -5539,12 +5756,15 @@ display_debug_loc (struct dwarf_section *section, void *file)
for (; j < num; j++)
{
if (last_offset >
- debug_information [i].loc_offsets [j])
+ debug_information [i].loc_offsets [j]
+ || (last_offset == debug_information [i].loc_offsets [j]
+ && last_view > debug_information [i].loc_views [j]))
{
locs_sorted = 0;
break;
}
last_offset = debug_information [i].loc_offsets [j];
+ last_view = debug_information [i].loc_views [j];
}
}
}
@@ -5553,7 +5773,8 @@ display_debug_loc (struct dwarf_section *section, void *file)
error (_("No location lists in .debug_info section!\n"));
if (debug_information [first].num_loc_offsets > 0
- && debug_information [first].loc_offsets [0] != expected_start)
+ && debug_information [first].loc_offsets [0] != expected_start
+ && debug_information [first].loc_views [0] != expected_start)
warn (_("Location lists in %s section start at 0x%s\n"),
section->name,
dwarf_vmatoa ("x", debug_information [first].loc_offsets [0]));
@@ -5568,7 +5789,7 @@ display_debug_loc (struct dwarf_section *section, void *file)
seen_first_offset = 0;
for (i = first; i < num_debug_info_entries; i++)
{
- dwarf_vma offset;
+ dwarf_vma offset, voffset;
dwarf_vma base_address;
unsigned int k;
int has_frame_base;
@@ -5578,24 +5799,42 @@ display_debug_loc (struct dwarf_section *section, void *file)
for (k = 0; k < debug_information [i].num_loc_offsets; k++)
array[k] = k;
loc_offsets = debug_information [i].loc_offsets;
+ loc_views = debug_information [i].loc_views;
qsort (array, debug_information [i].num_loc_offsets,
sizeof (*array), loc_offsets_compar);
}
+ int adjacent_view_loclists = 1;
for (k = 0; k < debug_information [i].num_loc_offsets; k++)
{
j = locs_sorted ? k : array[k];
if (k
- && debug_information [i].loc_offsets [locs_sorted
+ && (debug_information [i].loc_offsets [locs_sorted
? k - 1 : array [k - 1]]
- == debug_information [i].loc_offsets [j])
+ == debug_information [i].loc_offsets [j])
+ && (debug_information [i].loc_views [locs_sorted
+ ? k - 1 : array [k - 1]]
+ == debug_information [i].loc_views [j]))
continue;
has_frame_base = debug_information [i].have_frame_base [j];
offset = debug_information [i].loc_offsets [j];
next = section_begin + offset;
+ voffset = debug_information [i].loc_views [j];
+ if (voffset != vm1)
+ vnext = section_begin + voffset;
+ else
+ vnext = NULL;
base_address = debug_information [i].base_address;
- if (!seen_first_offset)
+ if (vnext && vnext < next)
+ {
+ vstart = vnext;
+ display_view_pair_list (section, &vstart, i, next);
+ if (start == vnext)
+ start = vstart;
+ }
+
+ if (!seen_first_offset || !adjacent_view_loclists)
seen_first_offset = 1;
else
{
@@ -5609,6 +5848,7 @@ display_debug_loc (struct dwarf_section *section, void *file)
(unsigned long) offset);
}
start = next;
+ vstart = vnext;
if (offset >= bytes)
{
@@ -5617,14 +5857,21 @@ display_debug_loc (struct dwarf_section *section, void *file)
continue;
}
+ if (vnext && voffset >= bytes)
+ {
+ warn (_("View Offset 0x%lx is bigger than .debug_loc section size.\n"),
+ (unsigned long) voffset);
+ continue;
+ }
+
if (!is_loclists)
{
if (is_dwo)
display_loc_list_dwo (section, &start, i, offset,
- has_frame_base);
+ &vstart, has_frame_base);
else
display_loc_list (section, &start, i, offset, base_address,
- has_frame_base);
+ &vstart, has_frame_base);
}
else
{
@@ -5632,8 +5879,25 @@ display_debug_loc (struct dwarf_section *section, void *file)
warn (_("DWO is not yet supported.\n"));
else
display_loclists_list (section, &start, i, offset, base_address,
- has_frame_base);
+ &vstart, has_frame_base);
+ }
+
+ /* FIXME: this arrangement is quite simplistic. Nothing
+ requires locview lists to be adjacent to corresponding
+ loclists, and a single loclist could be augmented by
+ different locview lists, and vice-versa, unlikely as it
+ is that it would make sense to do so. Hopefully we'll
+ have view pair support built into loclists before we ever
+ need to address all these possibilities. */
+ if (adjacent_view_loclists && vnext
+ && vnext != start && vstart != next)
+ {
+ adjacent_view_loclists = 0;
+ warn (_("Hole and overlap detection requires adjacent view lists and loclists.\n"));
}
+
+ if (vnext && vnext == start)
+ display_view_pair_list (section, &start, i, vstart);
}
}