This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: PATCH: BZ 615: Fix dumping .debug_loc section
- From: "H. J. Lu" <hjl at lucon dot org>
- To: binutils at sources dot redhat dot com
- Date: Wed, 29 Dec 2004 19:21:25 -0800
- Subject: Re: PATCH: BZ 615: Fix dumping .debug_loc section
- References: <20041229005926.GA13736@lucon.org>
On Tue, Dec 28, 2004 at 04:59:26PM -0800, H. J. Lu wrote:
> This patch tries to fix dumping .debug_loc section. This patch
> assumes location lists in .debug_info are in the same order as
> compilation units. It may be better to dump location lists by
> compilation units.
>
I updated the patch to dump location lists by compilation units.
H.J.
-----
2004-12-29 H.J. Lu <hongjiu.lu@intel.com>
BZ 615
* readelf.c (process_debug_info): New.
(debug_info): Add num_loc_offsets, loc_offsets and
last_loc_offset_p.
(get_debug_info): Use process_debug_info.
(display_debug_loc): Properly handle location list. Warn bad
location lists.
(read_and_process_attr_value): New.
(read_and_display_attr_value): Use "%lx" for DW_FORM_data4.
(display_debug_info): Use process_debug_info.
(process_object): Also free loc_offsets in debug_information.
--- binutils/readelf.c.loc 2004-12-27 11:39:00.000000000 -0800
+++ binutils/readelf.c 2004-12-29 19:11:57.462696492 -0800
@@ -218,6 +218,8 @@ print_mode;
static bfd_vma (*byte_get) (unsigned char *, int);
static void (*byte_put) (unsigned char *, bfd_vma, int);
+static int process_debug_info (Elf_Internal_Shdr *, unsigned char *,
+ FILE *, int);
#define UNKNOWN -1
@@ -7074,6 +7076,10 @@ typedef struct
{
unsigned int pointer_size;
unsigned long cu_offset;
+ /* This is an array of offsets to the location list table. */
+ unsigned long *loc_offsets;
+ unsigned int num_loc_offsets;
+ unsigned int max_loc_offsets;
}
debug_info;
@@ -7135,11 +7141,7 @@ get_debug_info (FILE * file)
{
Elf_Internal_Shdr * section;
unsigned char * start;
- unsigned char * end;
- unsigned char * begin;
- unsigned long length;
- unsigned int num_units;
- unsigned int unit;
+ int ret;
/* Reset the last pointer size so that we can issue correct error
messages if we are displaying the contents of more than one section. */
@@ -7154,87 +7156,14 @@ get_debug_info (FILE * file)
if (section == NULL)
return 0;
- length = section->sh_size;
start = get_data (NULL, file, section->sh_offset, section->sh_size,
_("extracting information from .debug_info section"));
if (start == NULL)
return 0;
- end = start + section->sh_size;
- /* First scan the section to get the number of comp units. */
- for (begin = start, num_units = 0; begin < end; num_units++)
- {
- /* Read the first 4 bytes. For a 32-bit DWARF section, this will
- be the length. For a 64-bit DWARF section, it'll be the escape
- code 0xffffffff followed by an 8 byte length. */
- length = byte_get (begin, 4);
-
- if (length == 0xffffffff)
- {
- length = byte_get (begin + 4, 8);
- begin += length + 12;
- }
- else
- begin += length + 4;
- }
-
- if (num_units == 0)
- {
- error (_("No comp units in .debug_info section ?"));
- free (start);
- return 0;
- }
-
- /* Then allocate an array to hold the information. */
- debug_information = malloc (num_units * sizeof * debug_information);
- if (debug_information == NULL)
- {
- error (_("Not enough memory for a debug info array of %u entries"),
- num_units);
- free (start);
- return 0;
- }
-
- /* Populate the array. */
- for (begin = start, unit = 0; begin < end; unit++)
- {
- debug_information [unit].cu_offset = begin - start;
-
- length = byte_get (begin, 4);
- if (length == 0xffffffff)
- {
- /* For 64-bit DWARF, the 1-byte address_size field is 22 bytes
- from the start of the section. This is computed as follows:
-
- unit_length: 12 bytes
- version: 2 bytes
- debug_abbrev_offset: 8 bytes
- -----------------------------
- Total: 22 bytes */
-
- debug_information [unit].pointer_size = byte_get (begin + 22, 1);
- length = byte_get (begin + 4, 8);
- begin += length + 12;
- }
- else
- {
- /* For 32-bit DWARF, the 1-byte address_size field is 10 bytes from
- the start of the section:
-
- unit_length: 4 bytes
- version: 2 bytes
- debug_abbrev_offset: 4 bytes
- -----------------------------
- Total: 10 bytes */
-
- debug_information [unit].pointer_size = byte_get (begin + 10, 1);
- begin += length + 4;
- }
- }
-
+ ret = process_debug_info (section, start, file, 1);
free (start);
-
- return num_debug_info_entries = num_units;
+ return ret ? num_debug_info_entries : 0;
}
static int
@@ -8500,7 +8429,13 @@ display_debug_loc (Elf_Internal_Shdr *se
unsigned long bytes;
unsigned char *section_begin = start;
bfd_vma addr;
- unsigned int comp_unit = 0;
+ unsigned int num_loc_list = 0;
+ unsigned long last_offset = 0;
+ unsigned int first = 0;
+ unsigned int i, j;
+ int seen_first_offset = 0;
+ int use_debug_info = 1;
+ unsigned char *next;
addr = section->sh_addr;
bytes = section->sh_size;
@@ -8514,10 +8449,65 @@ display_debug_loc (Elf_Internal_Shdr *se
get_debug_info (file);
+ /* Check the order of location list in .debug_info section. If
+ offsets of location lists are in the ascending order, we can
+ use `debug_information' directly. */
+ for (i = 0; i < num_debug_info_entries; i++)
+ {
+ unsigned int num;
+
+ num = debug_information [i].num_loc_offsets;
+ num_loc_list += num;
+
+ /* Check if we can use `debug_information' directly. */
+ if (use_debug_info && num != 0)
+ {
+ if (!seen_first_offset)
+ {
+ /* This is the first location list. */
+ last_offset = debug_information [i].loc_offsets [0];
+ first = i;
+ seen_first_offset = 1;
+ j = 1;
+ }
+ else
+ j = 0;
+
+ for (; j < num; j++)
+ {
+ if (last_offset >
+ debug_information [i].loc_offsets [j])
+ {
+ use_debug_info = 0;
+ break;
+ }
+ last_offset = debug_information [i].loc_offsets [j];
+ }
+ }
+ }
+
+ if (!use_debug_info)
+ {
+ /* FIXME: Should we handle this case? */
+ error (_("Location lists in .debug_info section aren't in ascending order!\n"));
+ }
+
+ if (!seen_first_offset)
+ {
+ error (_("No location lists in .debug_info section!\n"));
+ }
+
+ if (debug_information [first].loc_offsets [0] != 0)
+ {
+ warn (_("Location lists in .debug_loc section start at 0x%lx\n"),
+ debug_information [first].loc_offsets [0]);
+ }
+
printf (_("Contents of the .debug_loc section:\n\n"));
printf (_("\n Offset Begin End Expression\n"));
- while (start < section_end)
+ seen_first_offset = 0;
+ for (i = first; i < num_debug_info_entries; i++)
{
unsigned long begin;
unsigned long end;
@@ -8526,42 +8516,63 @@ display_debug_loc (Elf_Internal_Shdr *se
unsigned int pointer_size;
unsigned long cu_offset;
- offset = start - section_begin;
+ pointer_size = debug_information [i].pointer_size;
+ cu_offset = debug_information [i].cu_offset;
- /* Get the pointer size from the comp unit associated
- with this block of location information. */
- pointer_size = get_pointer_size_and_offset_of_comp_unit
- (comp_unit, ".debug_loc", & cu_offset);
+ for (j = 0; j < debug_information [i].num_loc_offsets; j++)
+ {
+ offset = debug_information [i].loc_offsets [j];
+ next = section_begin + offset;
- comp_unit ++;
+ if (!seen_first_offset)
+ seen_first_offset = 1;
+ else
+ {
+ if (start < next)
+ warn (_("There is a hole [0x%lx - 0x%lx] in .debug_loc section.\n"),
+ start, next);
+ else if (start > next)
+ warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_loc section.\n"),
+ start, next);
+ }
- while (1)
- {
- begin = byte_get (start, pointer_size);
- start += pointer_size;
- end = byte_get (start, pointer_size);
- start += pointer_size;
+ start = next;
- if (begin == 0 && end == 0)
- break;
+ while (1)
+ {
+ begin = byte_get (start, pointer_size);
+ start += pointer_size;
+ end = byte_get (start, pointer_size);
+ start += pointer_size;
- /* For now, skip any base address specifiers. */
- if (begin == 0xffffffff)
- continue;
+ if (begin == 0 && end == 0)
+ break;
- begin += addr;
- end += addr;
+ /* For now, skip any base address specifiers. */
+ if (begin == 0xffffffff)
+ continue;
- length = byte_get (start, 2);
- start += 2;
+ begin += addr;
+ end += addr;
- printf (" %8.8lx %8.8lx %8.8lx (", offset, begin, end);
- decode_location_expression (start, pointer_size, length, cu_offset);
- printf (")\n");
+ length = byte_get (start, 2);
+ start += 2;
+
+ printf (" %8.8lx %8.8lx %8.8lx (",
+ offset, begin, end);
+ decode_location_expression (start, pointer_size, length,
+ cu_offset);
+ printf (")\n");
+
+ if (begin >= end)
+ warn ("Bad location list at %8.8lx from %8.8lx to %8.8lx\n",
+ offset, begin, end);
+
+ start += length;
+ }
- start += length;
+ printf ("\n");
}
- printf ("\n");
}
return 1;
}
@@ -8828,7 +8839,9 @@ read_and_display_attr_value (unsigned lo
unsigned long cu_offset,
unsigned long pointer_size,
unsigned long offset_size,
- int dwarf_version)
+ int dwarf_version,
+ debug_info *debug_info_p,
+ int do_loc)
{
static unsigned long saved_DW_AT_low_pc = 0;
unsigned long uvalue = 0;
@@ -8899,78 +8912,113 @@ read_and_display_attr_value (unsigned lo
case DW_FORM_indirect:
form = read_leb128 (data, & bytes_read, 0);
data += bytes_read;
- printf (" %s", get_FORM_name (form));
- return read_and_display_attr_value (attribute, form, data, cu_offset,
- pointer_size, offset_size,
- dwarf_version);
+ if (!do_loc)
+ printf (" %s", get_FORM_name (form));
+ return read_and_display_attr_value (attribute, form, data,
+ cu_offset, pointer_size,
+ offset_size, dwarf_version,
+ debug_info_p, do_loc);
}
switch (form)
{
case DW_FORM_ref_addr:
- printf (" <#%lx>", uvalue);
+ if (!do_loc)
+ printf (" <#%lx>", uvalue);
break;
case DW_FORM_ref1:
case DW_FORM_ref2:
case DW_FORM_ref4:
case DW_FORM_ref_udata:
- printf (" <%lx>", uvalue + cu_offset);
+ if (!do_loc)
+ printf (" <%lx>", uvalue + cu_offset);
break;
case DW_FORM_addr:
- printf (" %#lx", uvalue);
+ if (!do_loc)
+ printf (" %#lx", uvalue);
break;
case DW_FORM_flag:
case DW_FORM_data1:
case DW_FORM_data2:
- case DW_FORM_data4:
case DW_FORM_sdata:
case DW_FORM_udata:
- printf (" %ld", uvalue);
+ if (!do_loc)
+ printf (" %ld", uvalue);
+ break;
+
+ case DW_FORM_data4:
+ if (!do_loc)
+ printf (" %lx", uvalue);
break;
case DW_FORM_ref8:
case DW_FORM_data8:
- uvalue = byte_get (data, 4);
- printf (" %lx", uvalue);
- printf (" %lx", (unsigned long) byte_get (data + 4, 4));
+ if (!do_loc)
+ {
+ uvalue = byte_get (data, 4);
+ printf (" %lx", uvalue);
+ printf (" %lx", (unsigned long) byte_get (data + 4, 4));
+ }
+ if ((do_loc || do_debug_loc)
+ && num_debug_info_entries == 0)
+ {
+ if (sizeof (uvalue) == 8)
+ uvalue = byte_get (data, 8);
+ else
+ error (_("DW_FORM_data8 is unsupported when sizeof (unsigned long) != 8\n"));
+ }
data += 8;
break;
case DW_FORM_string:
- printf (" %s", data);
+ if (!do_loc)
+ printf (" %s", data);
data += strlen ((char *) data) + 1;
break;
case DW_FORM_block:
uvalue = read_leb128 (data, & bytes_read, 0);
block_start = data + bytes_read;
- data = display_block (block_start, uvalue);
+ if (do_loc)
+ data = block_start + uvalue;
+ else
+ data = display_block (block_start, uvalue);
break;
case DW_FORM_block1:
uvalue = byte_get (data, 1);
block_start = data + 1;
- data = display_block (block_start, uvalue);
+ if (do_loc)
+ data = block_start + uvalue;
+ else
+ data = display_block (block_start, uvalue);
break;
case DW_FORM_block2:
uvalue = byte_get (data, 2);
block_start = data + 2;
- data = display_block (block_start, uvalue);
+ if (do_loc)
+ data = block_start + uvalue;
+ else
+ data = display_block (block_start, uvalue);
break;
case DW_FORM_block4:
uvalue = byte_get (data, 4);
block_start = data + 4;
- data = display_block (block_start, uvalue);
+ if (do_loc)
+ data = block_start + uvalue;
+ else
+ data = display_block (block_start, uvalue);
break;
case DW_FORM_strp:
- printf (_(" (indirect string, offset: 0x%lx): %s"),
- uvalue, fetch_indirect_string (uvalue));
+ if (!do_loc)
+ printf (_(" (indirect string, offset: 0x%lx): %s"),
+ uvalue, fetch_indirect_string (uvalue));
break;
case DW_FORM_indirect:
@@ -8984,6 +9032,47 @@ read_and_display_attr_value (unsigned lo
/* For some attributes we can display further information. */
+ if ((do_loc || do_debug_loc)
+ && num_debug_info_entries == 0)
+ {
+ switch (attribute)
+ {
+ case DW_AT_frame_base:
+ case DW_AT_location:
+ case DW_AT_data_member_location:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_data_location:
+ case DW_AT_stride:
+ case DW_AT_upper_bound:
+ case DW_AT_lower_bound:
+ if (form == DW_FORM_data4 || form == DW_FORM_data8)
+ {
+ /* Process location list. */
+ unsigned int max = debug_info_p->max_loc_offsets;
+ unsigned int num = debug_info_p->num_loc_offsets;
+ if (max == 0 || num >= max)
+ {
+ max += 1024;
+ debug_info_p->loc_offsets
+ = xrealloc (debug_info_p->loc_offsets,
+ max * sizeof (*debug_info_p->loc_offsets));
+ debug_info_p->max_loc_offsets = max;
+ }
+ debug_info_p->loc_offsets [num] = uvalue;
+ debug_info_p->num_loc_offsets++;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (do_loc)
+ return data;
+
printf ("\t");
switch (attribute)
@@ -9174,12 +9263,18 @@ read_and_display_attr (unsigned long att
unsigned long cu_offset,
unsigned long pointer_size,
unsigned long offset_size,
- int dwarf_version)
+ int dwarf_version,
+ debug_info *debug_info_p,
+ int do_loc)
{
- printf (" %-18s:", get_AT_name (attribute));
+ if (!do_loc)
+ printf (" %-18s:", get_AT_name (attribute));
data = read_and_display_attr_value (attribute, form, data, cu_offset,
- pointer_size, offset_size, dwarf_version);
- printf ("\n");
+ pointer_size, offset_size,
+ dwarf_version, debug_info_p,
+ do_loc);
+ if (!do_loc)
+ printf ("\n");
return data;
}
@@ -9273,20 +9368,66 @@ debug_apply_rela_addends (FILE *file,
}
static int
-display_debug_info (Elf_Internal_Shdr *section,
- unsigned char *start,
- FILE *file)
+process_debug_info (Elf_Internal_Shdr *section, unsigned char *start,
+ FILE *file, int do_loc)
{
unsigned char *end = start + section->sh_size;
- unsigned char *section_begin = start;
+ unsigned char *section_begin;
+ unsigned int unit;
+ unsigned int num_units = 0;
- printf (_("The section %s contains:\n\n"), SECTION_NAME (section));
+ if ((do_loc || do_debug_loc)
+ && num_debug_info_entries == 0)
+ {
+ unsigned long length;
+
+ /* First scan the section to get the number of comp units. */
+ for (section_begin = start, num_units = 0; section_begin < end;
+ num_units++)
+ {
+ /* Read the first 4 bytes. For a 32-bit DWARF section, this
+ will be the length. For a 64-bit DWARF section, it'll be
+ the escape code 0xffffffff followed by an 8 byte length.
+ */
+ length = byte_get (section_begin, 4);
+
+ if (length == 0xffffffff)
+ {
+ length = byte_get (section_begin + 4, 8);
+ section_begin += length + 12;
+ }
+ else
+ section_begin += length + 4;
+ }
- load_debug_str (file);
- load_debug_loc (file);
- load_debug_range (file);
+ if (num_units == 0)
+ {
+ error (_("No comp units in .debug_info section ?"));
+ return 0;
+ }
- while (start < end)
+ /* Then allocate an array to hold the information. */
+ debug_information = malloc (num_units *
+ sizeof (*debug_information));
+ if (debug_information == NULL)
+ {
+ error (_("Not enough memory for a debug info array of %u entries"),
+ num_units);
+ return 0;
+ }
+ }
+
+ if (!do_loc)
+ {
+ printf (_("The section %s contains:\n\n"),
+ SECTION_NAME (section));
+
+ load_debug_str (file);
+ load_debug_loc (file);
+ load_debug_range (file);
+ }
+
+ for (section_begin = start, unit = 0; start < end; unit++)
{
DWARF2_Internal_CompUnit compunit;
unsigned char *hdrptr;
@@ -9333,13 +9474,27 @@ display_debug_info (Elf_Internal_Shdr *s
compunit.cu_pointer_size = byte_get (hdrptr, 1);
hdrptr += 1;
+ if ((do_loc || do_debug_loc)
+ && num_debug_info_entries == 0)
+ {
+ debug_information [unit].cu_offset = cu_offset;
+ debug_information [unit].pointer_size
+ = compunit.cu_pointer_size;
+ debug_information [unit].loc_offsets = NULL;
+ debug_information [unit].max_loc_offsets = 0;
+ debug_information [unit].num_loc_offsets = 0;
+ }
+
tags = hdrptr;
- printf (_(" Compilation Unit @ %lx:\n"), cu_offset);
- printf (_(" Length: %ld\n"), compunit.cu_length);
- printf (_(" Version: %d\n"), compunit.cu_version);
- printf (_(" Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset);
- printf (_(" Pointer Size: %d\n"), compunit.cu_pointer_size);
+ if (!do_loc)
+ {
+ printf (_(" Compilation Unit @ %lx:\n"), cu_offset);
+ printf (_(" Length: %ld\n"), compunit.cu_length);
+ printf (_(" Version: %d\n"), compunit.cu_version);
+ printf (_(" Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset);
+ printf (_(" Pointer Size: %d\n"), compunit.cu_pointer_size);
+ }
if (compunit.cu_version != 2 && compunit.cu_version != 3)
{
@@ -9405,11 +9560,13 @@ display_debug_info (Elf_Internal_Shdr *s
return 0;
}
- printf (_(" <%d><%lx>: Abbrev Number: %lu (%s)\n"),
- level,
- (unsigned long) (tags - section_begin - bytes_read),
- abbrev_number,
- get_TAG_name (entry->tag));
+ if (!do_loc)
+ printf (_(" <%d><%lx>: Abbrev Number: %lu (%s)\n"),
+ level,
+ (unsigned long) (tags - section_begin
+ - bytes_read),
+ abbrev_number,
+ get_TAG_name (entry->tag));
for (attr = entry->first_attr; attr; attr = attr->next)
tags = read_and_display_attr (attr->attribute,
@@ -9417,23 +9574,42 @@ display_debug_info (Elf_Internal_Shdr *s
tags, cu_offset,
compunit.cu_pointer_size,
offset_size,
- compunit.cu_version);
+ compunit.cu_version,
+ &debug_information [unit],
+ do_loc);
if (entry->children)
++level;
}
}
- free_debug_range ();
- free_debug_str ();
- free_debug_loc ();
+ /* Set num_debug_info_entries here so that it can be used to check
+ if we need to proecess .debug_loc section. */
+ if ((do_loc || do_debug_loc)
+ && num_debug_info_entries == 0)
+ num_debug_info_entries = num_units;
+
+ if (!do_loc)
+ {
+ free_debug_range ();
+ free_debug_str ();
+ free_debug_loc ();
- printf ("\n");
+ printf ("\n");
+ }
return 1;
}
static int
+display_debug_info (Elf_Internal_Shdr *section,
+ unsigned char *start,
+ FILE *file)
+{
+ return process_debug_info (section, start, file, 0);
+}
+
+static int
display_debug_aranges (Elf_Internal_Shdr *section,
unsigned char *start,
FILE *file ATTRIBUTE_UNUSED)
@@ -11581,6 +11757,9 @@ process_object (char *file_name, FILE *f
if (debug_information)
{
+ for (i = 0; i < num_debug_info_entries; i++)
+ if (debug_information [i].loc_offsets != NULL)
+ free (debug_information [i].loc_offsets);
free (debug_information);
debug_information = NULL;
num_debug_info_entries = 0;