This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
[PATCH]: readelf: Per comp-unit pointer sizes
- From: Nick Clifton <nickc at redhat dot com>
- To: binutils at sources dot redhat dot com
- Date: Mon, 29 Dec 2003 11:51:08 +0000
- Subject: [PATCH]: readelf: Per comp-unit pointer sizes
Hi Guys,
Currently readelf assumes that the pointer size in the DWARF debug
information for a given executable is fixed. This does not have to
be the case, and indeed some toolchains (eg mipsisa64-elf) can
produce executables with multiple pointer sizes.
The patch below fixes readelf so that it computes an array of
pointer sizes from the contents of the .debug.info sections and then
uses these sizes when displaying the .debug.line and .debug.loc
sections.
Cheers
Nick
binutils/ChangeLog
2003-12-29 Nick Clifton <nickc@redhat.com>
* readelf.c (debug_line_pointer_size): Replace with an array
called 'debug_line_pointer_sizes'.
(num_debug_line_pointer_sizes): New variable.
(display_debug_lines): Extract pointer size from the
debug_line_pointer_sizes array.
(display_debug_loc): Likewise.
(prescan_debug_info): Fill in the debug_line_pointer_sizes
array.
Index: binutils/readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.227
diff -c -3 -p -r1.227 readelf.c
*** binutils/readelf.c 19 Dec 2003 11:43:47 -0000 1.227
--- binutils/readelf.c 29 Dec 2003 11:52:14 -0000
*************** process_extended_line_op (unsigned char
*** 6274,6280 ****
/* Size of pointers in the .debug_line section. This information is not
really present in that section. It's obtained before dumping the debug
sections by doing some pre-scan of the .debug_info section. */
! static int debug_line_pointer_size = 4;
static int
display_debug_lines (Elf_Internal_Shdr *section,
--- 6274,6281 ----
/* Size of pointers in the .debug_line section. This information is not
really present in that section. It's obtained before dumping the debug
sections by doing some pre-scan of the .debug_info section. */
! static unsigned int * debug_line_pointer_sizes = NULL;
! static unsigned int num_debug_line_pointer_sizes = 0;
static int
display_debug_lines (Elf_Internal_Shdr *section,
*************** display_debug_lines (Elf_Internal_Shdr *
*** 6290,6301 ****
--- 6291,6305 ----
int i;
int offset_size;
int initial_length_size;
+ unsigned int comp_unit = 0;
printf (_("\nDump of debug contents of section %s:\n\n"),
SECTION_NAME (section));
while (data < end)
{
+ unsigned int pointer_size;
+
hdrptr = data;
/* Check the length of the block. */
*************** display_debug_lines (Elf_Internal_Shdr *
*** 6349,6354 ****
--- 6353,6371 ----
info.li_line_base <<= 24;
info.li_line_base >>= 24;
+ /* Get the pointer size from the comp unit associated
+ with this block of line number information. */
+ if (comp_unit >= num_debug_line_pointer_sizes)
+ {
+ error (_("Not enough comp units for .debug_lines section\n"));
+ return 0;
+ }
+ else
+ {
+ pointer_size = debug_line_pointer_sizes [comp_unit];
+ comp_unit ++;
+ }
+
printf (_(" Length: %ld\n"), info.li_length);
printf (_(" DWARF Version: %d\n"), info.li_version);
printf (_(" Prologue Length: %d\n"), info.li_prologue_length);
*************** display_debug_lines (Elf_Internal_Shdr *
*** 6357,6362 ****
--- 6374,6380 ----
printf (_(" Line Base: %d\n"), info.li_line_base);
printf (_(" Line Range: %d\n"), info.li_line_range);
printf (_(" Opcode Base: %d\n"), info.li_opcode_base);
+ printf (_(" (Pointer size: %u)\n"), pointer_size);
end_of_sequence = data + info.li_length + initial_length_size;
*************** display_debug_lines (Elf_Internal_Shdr *
*** 6449,6455 ****
{
case DW_LNS_extended_op:
data += process_extended_line_op (data, info.li_default_is_stmt,
! debug_line_pointer_size);
break;
case DW_LNS_copy:
--- 6467,6473 ----
{
case DW_LNS_extended_op:
data += process_extended_line_op (data, info.li_default_is_stmt,
! pointer_size);
break;
case DW_LNS_copy:
*************** display_debug_loc (Elf_Internal_Shdr *se
*** 7531,7536 ****
--- 7549,7555 ----
unsigned long bytes;
unsigned char *section_begin = start;
bfd_vma addr;
+ unsigned int comp_unit = 0;
addr = section->sh_addr;
bytes = section->sh_size;
*************** display_debug_loc (Elf_Internal_Shdr *se
*** 7551,7571 ****
unsigned long end;
unsigned short length;
unsigned long offset;
offset = start - section_begin;
while (1)
{
! /* Normally, the lists in the debug_loc section are related to a
! given compilation unit, and thus, we would use the pointer size
! of that compilation unit. However, since we are displaying it
! separately here, we either have to store pointer sizes of all
! compilation units, or assume they don't change. We assume,
! like the debug_line display, that it doesn't change. */
! begin = byte_get (start, debug_line_pointer_size);
! start += debug_line_pointer_size;
! end = byte_get (start, debug_line_pointer_size);
! start += debug_line_pointer_size;
if (begin == 0 && end == 0)
break;
--- 7570,7598 ----
unsigned long end;
unsigned short length;
unsigned long offset;
+ unsigned int pointer_size;
offset = start - section_begin;
+ /* Get the pointer size from the comp unit associated
+ with this block of location information. */
+ if (comp_unit >= num_debug_line_pointer_sizes)
+ {
+ error (_("Not enough comp units for .debug_loc section\n"));
+ return 0;
+ }
+ else
+ {
+ pointer_size = debug_line_pointer_sizes [comp_unit];
+ comp_unit ++;
+ }
+
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;
*************** display_debug_loc (Elf_Internal_Shdr *se
*** 7581,7587 ****
start += 2;
printf (" %8.8lx %8.8lx %8.8lx (", offset, begin, end);
! decode_location_expression (start, debug_line_pointer_size, length);
printf (")\n");
start += length;
--- 7608,7614 ----
start += 2;
printf (" %8.8lx %8.8lx %8.8lx (", offset, begin, end);
! decode_location_expression (start, pointer_size, length);
printf (")\n");
start += length;
*************** display_debug_not_supported (Elf_Interna
*** 9167,9222 ****
return 1;
}
! /* Pre-scan the .debug_info section to record the size of address.
! When dumping the .debug_line, we use that size information, assuming
! that all compilation units have the same address size. */
! static int
! prescan_debug_info (Elf_Internal_Shdr *section ATTRIBUTE_UNUSED,
! unsigned char *start,
FILE *file ATTRIBUTE_UNUSED)
{
! unsigned long length;
! /* 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. For the purposes
! of this prescan, we don't care about the actual length, but the
! presence of the escape bytes does affect the location of the byte
! which describes the address size. */
! length = byte_get (start, 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_line_pointer_size = byte_get (start + 22, 1);
}
! 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_line_pointer_size = byte_get (start + 10, 1);
! }
! return 0;
! }
!
! /* A structure containing the name of a debug section and a pointer
! to a function that can decode it. The third field is a prescan
! function to be run over the section before displaying any of the
! sections. */
struct
{
const char *const name;
--- 9194,9290 ----
return 1;
}
! /* Pre-scan the .debug_info section to record the pointer sizes for the
! compilation units. Usually an executable will have just one pointer
! size, but this is not guaranteed, and so we try not to make any
! assumptions. Returns zero upon failure, or the number of compilation
! units upon success. */
!
! static unsigned int
! prescan_debug_info (Elf_Internal_Shdr *section, unsigned char *start,
FILE *file ATTRIBUTE_UNUSED)
{
! unsigned char *begin;
! unsigned char *end = start + section->sh_size;
! unsigned long length;
! unsigned int num_units;
! unsigned int unit;
!
! /* First scan the section to compute 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 ?"));
! return 0;
! }
! /* Then allocate an array to hold the pointer sizes. */
! debug_line_pointer_sizes = malloc (num_units * sizeof * debug_line_pointer_sizes);
! if (debug_line_pointer_sizes == NULL)
! {
! error (_("Not enough memory for a pointer size array of %u entries"),
! num_units);
! return 0;
}
!
! /* Populate the array. */
! for (begin = start, unit = 0; begin < end; unit++)
{
! 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_line_pointer_sizes [unit] = 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_line_pointer_sizes [unit] = byte_get (begin + 10, 1);
! begin += length + 4;
! }
! }
!
! num_debug_line_pointer_sizes = num_units;
! return num_units;
! }
!
! /* A structure containing the name of a debug section and a pointer
! to a function that can decode it. The third field is a prescan
! function to be run over the section before displaying any of the
! sections. */
struct
{
const char *const name;