This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
PATCH: BZ 616: Fix dumping .debug_loc section
- From: "H. J. Lu" <hjl at lucon dot org>
- To: binutils at sources dot redhat dot com
- Date: Tue, 28 Dec 2004 16:59:26 -0800
- Subject: PATCH: BZ 616: Fix dumping .debug_loc section
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.
H.J.
----
2004-12-28 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): Better handle location list.
(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-28 16:48:30.710090225 -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
@@ -7073,6 +7075,11 @@ find_section (const char * name)
typedef struct
{
unsigned int pointer_size;
+ unsigned int num_loc_offsets;
+ /* This is an array of offsets to the location list table. */
+ unsigned long *loc_offsets;
+ /* Pointer to the one past the last element in the array. */
+ unsigned long *last_loc_offset_p;
unsigned long cu_offset;
}
debug_info;
@@ -7135,11 +7142,6 @@ 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;
/* 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;
- }
- }
-
+ num_debug_info_entries = process_debug_info (section, start, file, 1);
free (start);
-
- return num_debug_info_entries = num_units;
+ return num_debug_info_entries;
}
static int
@@ -8525,43 +8454,53 @@ display_debug_loc (Elf_Internal_Shdr *se
unsigned long offset;
unsigned int pointer_size;
unsigned long cu_offset;
-
- offset = start - section_begin;
+ unsigned long *offset_p;
/* 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);
- comp_unit ++;
-
- while (1)
- {
- begin = byte_get (start, pointer_size);
- start += pointer_size;
- end = byte_get (start, pointer_size);
- start += pointer_size;
+ for (offset_p = debug_information [comp_unit].loc_offsets;
+ offset_p < debug_information [comp_unit].last_loc_offset_p;
+ offset_p++)
+ {
+ offset = start - section_begin;
+
+ if (offset != *offset_p)
+ error (_(".debug_loc section doesn't match debug_info section\n"));
+
+ while (1)
+ {
+ begin = byte_get (start, pointer_size);
+ start += pointer_size;
+ end = byte_get (start, pointer_size);
+ start += pointer_size;
- if (begin == 0 && end == 0)
- break;
+ if (begin == 0 && end == 0)
+ break;
- /* For now, skip any base address specifiers. */
- if (begin == 0xffffffff)
- continue;
+ /* For now, skip any base address specifiers. */
+ if (begin == 0xffffffff)
+ continue;
- begin += addr;
- end += addr;
+ begin += addr;
+ end += addr;
- length = byte_get (start, 2);
- start += 2;
+ 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");
+ printf (" %8.8lx %8.8lx %8.8lx (",
+ offset, begin, end);
+ decode_location_expression (start, pointer_size, length,
+ cu_offset);
+ printf (")\n");
- start += length;
+ start += length;
+ }
+ printf ("\n");
}
- printf ("\n");
+ comp_unit ++;
}
return 1;
}
@@ -8822,6 +8761,168 @@ decode_range (unsigned long offset, bfd_
static unsigned char *
+read_and_process_attr_value (unsigned long attribute,
+ unsigned long form,
+ unsigned char *data,
+ unsigned long cu_offset,
+ unsigned long pointer_size,
+ unsigned long offset_size,
+ int dwarf_version,
+ debug_info *debug_info_p)
+{
+ unsigned long uvalue = 0;
+ int bytes_read;
+
+ switch (form)
+ {
+ case DW_FORM_ref8:
+ data += 8;
+ break;
+
+ case DW_FORM_data8:
+ if (sizeof (uvalue) == 8)
+ {
+ uvalue = byte_get (data, 8);
+ data += 8;
+ }
+ else
+ error (_("DW_FORM_data8 is unsupported when offset_size (%d) != 8\n"),
+ offset_size);
+ break;
+
+
+ case DW_FORM_string:
+ data += strlen ((char *) data) + 1;
+ break;
+
+ case DW_FORM_ref_addr:
+ if (dwarf_version == 2)
+ {
+ data += pointer_size;
+ }
+ else if (dwarf_version == 3)
+ {
+ data += offset_size;
+ }
+ else
+ {
+ error (_("Internal error: DWARF version is not 2 or 3.\n"));
+ }
+ break;
+
+ case DW_FORM_addr:
+ case DW_FORM_strp:
+ data += offset_size;
+ break;
+
+ case DW_FORM_ref1:
+ case DW_FORM_flag:
+ case DW_FORM_data1:
+ data++;
+ break;
+
+ case DW_FORM_ref2:
+ case DW_FORM_data2:
+ data += 2;
+ break;
+
+ case DW_FORM_ref4:
+ data += 4;
+ break;
+
+ case DW_FORM_data4:
+ uvalue = byte_get (data, 4);
+ data += 4;
+ break;
+
+ case DW_FORM_sdata:
+ uvalue = read_leb128 (data, & bytes_read, 1);
+ data += bytes_read;
+ break;
+
+ case DW_FORM_ref_udata:
+ case DW_FORM_udata:
+ uvalue = read_leb128 (data, & bytes_read, 0);
+ data += bytes_read;
+ break;
+
+ case DW_FORM_indirect:
+ form = read_leb128 (data, & bytes_read, 0);
+ data += bytes_read;
+ return read_and_process_attr_value (attribute, form, data,
+ cu_offset, pointer_size,
+ offset_size, dwarf_version,
+ debug_info_p);
+ break;
+
+ case DW_FORM_block:
+ uvalue = read_leb128 (data, & bytes_read, 0);
+ data += bytes_read + uvalue;
+ break;
+
+ case DW_FORM_block1:
+ uvalue = byte_get (data, 1);
+ data += 1 + uvalue;
+ break;
+
+ case DW_FORM_block2:
+ uvalue = byte_get (data, 2);
+ data += 2 + uvalue;
+ break;
+
+ case DW_FORM_block4:
+ uvalue = byte_get (data, 4);
+ data += 3 + uvalue;
+ break;
+
+ default:
+ warn (_("Unrecognized form: %d\n"), form);
+ break;
+ }
+
+ /* For some attributes we can display further information. */
+
+ 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->num_loc_offsets;
+ if (max == 0
+ || (debug_info_p->last_loc_offset_p
+ >= &debug_info_p->loc_offsets [max]))
+ {
+ max += 1024;
+ debug_info_p->loc_offsets
+ = xrealloc (debug_info_p->loc_offsets,
+ max * sizeof (*debug_info_p->loc_offsets));
+ debug_info_p->last_loc_offset_p
+ = &debug_info_p->loc_offsets [debug_info_p->num_loc_offsets];
+ debug_info_p->num_loc_offsets = max;
+ }
+ *debug_info_p->last_loc_offset_p = uvalue;
+ debug_info_p->last_loc_offset_p++;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return data;
+}
+
+static unsigned char *
read_and_display_attr_value (unsigned long attribute,
unsigned long form,
unsigned char *data,
@@ -8925,12 +9026,15 @@ read_and_display_attr_value (unsigned lo
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);
break;
+ case DW_FORM_data4:
+ printf (" %lx", uvalue);
+ break;
+
case DW_FORM_ref8:
case DW_FORM_data8:
uvalue = byte_get (data, 4);
@@ -9273,20 +9377,64 @@ 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)
+ {
+ unsigned long length;
- load_debug_str (file);
- load_debug_loc (file);
- load_debug_range (file);
+ /* 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);
- while (start < end)
+ if (length == 0xffffffff)
+ {
+ length = byte_get (section_begin + 4, 8);
+ section_begin += length + 12;
+ }
+ else
+ section_begin += length + 4;
+ }
+
+ if (num_units == 0)
+ {
+ error (_("No comp units in .debug_info section ?"));
+ 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);
+ return 0;
+ }
+ }
+ else
+ {
+ 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 +9481,26 @@ display_debug_info (Elf_Internal_Shdr *s
compunit.cu_pointer_size = byte_get (hdrptr, 1);
hdrptr += 1;
+ if (do_loc)
+ {
+ debug_information [unit].cu_offset = cu_offset;
+ debug_information [unit].pointer_size
+ = compunit.cu_pointer_size;
+ debug_information [unit].num_loc_offsets = 0;
+ debug_information [unit].loc_offsets = NULL;
+ debug_information [unit].last_loc_offset_p = NULL;
+ }
+
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,32 +9566,60 @@ 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));
-
- for (attr = entry->first_attr; attr; attr = attr->next)
- tags = read_and_display_attr (attr->attribute,
- attr->form,
- tags, cu_offset,
- compunit.cu_pointer_size,
- offset_size,
- compunit.cu_version);
+ if (do_loc)
+ {
+ for (attr = entry->first_attr; attr; attr = attr->next)
+ tags = read_and_process_attr_value (attr->attribute,
+ attr->form,
+ tags, cu_offset,
+ compunit.cu_pointer_size,
+ offset_size,
+ compunit.cu_version,
+ &debug_information [unit]);
+ }
+ else
+ {
+ 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,
+ attr->form,
+ tags, cu_offset,
+ compunit.cu_pointer_size,
+ offset_size,
+ compunit.cu_version);
+ }
if (entry->children)
++level;
}
}
- free_debug_range ();
- free_debug_str ();
- free_debug_loc ();
+ if (do_loc)
+ return num_units;
+ else
+ {
+ free_debug_range ();
+ free_debug_str ();
+ free_debug_loc ();
- printf ("\n");
+ printf ("\n");
+
+ return 1;
+ }
+}
- 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
@@ -11581,6 +11770,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;