This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
[RFA] elfread.c: Add 64-bit DWARF support
- From: Kevin Buettner <kevinb at redhat dot com>
- To: binutils at sources dot redhat dot com
- Date: Wed, 26 Mar 2003 10:45:02 -0700
- Subject: [RFA] elfread.c: Add 64-bit DWARF support
The patch below adds 64-bit DWARF 2/3 support to readelf.c.
Some of the fields in the DWARF2_Internal_* structs in
include/elf/dwarf2.h will eventually need to be widened to truly
(and portably) handle large DWARF sections. Here is the list:
DWARF2_Internal_LineInfo: li_length
DWARF2_Internal_PubNames: pn_length, pn_offset
DWARF2_Internal_CompUnit: cu_length, cu_abbrev_offset
DWARF2_Internal_ARange: ar_length, ar_info_offset
I considered changing these from ``unsigned long'' to ``bfd_vma'', but
it's not clear to me if ``bfd_vma'' should be used in this header file.
If it turns out that the DWARF2_Internal_* structs cannot or should not
be changed for some reason, it shouldn't be hard to dispense with these
structs in readelf.c. (Note that the patch below eliminates the use
of the DWARF2_External_* structs from readelf.c.)
Is the part below okay?
* readelf.c (read_and_display_attr, read_and_display_attr_value):
Add new arguments ``offset_size'' and ``dwarf_version''. Adjust
all callers.
(display_debug_lines, display_debug_pubnames, display_debug_info)
(display_debug_aranges, display_debug_frames, read_and_display_attr)
(read_and_display_attr_value): Add 64-bit DWARF support.
Index: readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.196
diff -u -p -r1.196 readelf.c
--- readelf.c 21 Feb 2003 12:17:51 -0000 1.196
+++ readelf.c 26 Mar 2003 16:51:31 -0000
@@ -348,10 +348,10 @@ static void add_abbrev_attr
PARAMS ((unsigned long, unsigned long));
static unsigned char *read_and_display_attr
PARAMS ((unsigned long, unsigned long, unsigned char *, unsigned long,
- unsigned long));
+ unsigned long, unsigned long, int));
static unsigned char *read_and_display_attr_value
PARAMS ((unsigned long, unsigned long, unsigned char *, unsigned long,
- unsigned long));
+ unsigned long, unsigned long, int));
static unsigned char *display_block
PARAMS ((unsigned char *, unsigned long));
static void decode_location_expression
@@ -6420,31 +6420,42 @@ display_debug_lines (section, start, fil
unsigned char * start;
FILE *file ATTRIBUTE_UNUSED;
{
- DWARF2_External_LineInfo *external;
+ unsigned char *hdrptr;
DWARF2_Internal_LineInfo info;
unsigned char *standard_opcodes;
unsigned char *data = start;
unsigned char *end = start + section->sh_size;
unsigned char *end_of_sequence;
int i;
+ int offset_size;
+ int initial_length_size;
printf (_("\nDump of debug contents of section %s:\n\n"),
SECTION_NAME (section));
while (data < end)
{
- external = (DWARF2_External_LineInfo *) data;
+ hdrptr = data;
/* Check the length of the block. */
- info.li_length = BYTE_GET (external->li_length);
+ info.li_length = byte_get (hdrptr, 4);
+ hdrptr += 4;
if (info.li_length == 0xffffffff)
{
- warn (_("64-bit DWARF line info is not supported yet.\n"));
- break;
+ /* This section is 64-bit DWARF 3. */
+ info.li_length = byte_get (hdrptr, 8);
+ hdrptr += 8;
+ offset_size = 8;
+ initial_length_size = 12;
+ }
+ else
+ {
+ offset_size = 4;
+ initial_length_size = 4;
}
- if (info.li_length + sizeof (external->li_length) > section->sh_size)
+ if (info.li_length + initial_length_size > section->sh_size)
{
warn
(_("The line info appears to be corrupt - the section is too small\n"));
@@ -6452,19 +6463,26 @@ display_debug_lines (section, start, fil
}
/* Check its version number. */
- info.li_version = BYTE_GET (external->li_version);
- if (info.li_version != 2)
+ info.li_version = byte_get (hdrptr, 2);
+ hdrptr += 2;
+ if (info.li_version != 2 && info.li_version != 3)
{
- warn (_("Only DWARF version 2 line info is currently supported.\n"));
+ warn (_("Only DWARF version 2 and 3 line info is currently supported.\n"));
return 0;
}
- info.li_prologue_length = BYTE_GET (external->li_prologue_length);
- info.li_min_insn_length = BYTE_GET (external->li_min_insn_length);
- info.li_default_is_stmt = BYTE_GET (external->li_default_is_stmt);
- info.li_line_base = BYTE_GET (external->li_line_base);
- info.li_line_range = BYTE_GET (external->li_line_range);
- info.li_opcode_base = BYTE_GET (external->li_opcode_base);
+ info.li_prologue_length = byte_get (hdrptr, offset_size);
+ hdrptr += offset_size;
+ info.li_min_insn_length = byte_get (hdrptr, 1);
+ hdrptr++;
+ info.li_default_is_stmt = byte_get (hdrptr, 1);
+ hdrptr++;
+ info.li_line_base = byte_get (hdrptr, 1);
+ hdrptr++;
+ info.li_line_range = byte_get (hdrptr, 1);
+ hdrptr++;
+ info.li_opcode_base = byte_get (hdrptr, 1);
+ hdrptr++;
/* Sign extend the line base field. */
info.li_line_base <<= 24;
@@ -6479,12 +6497,12 @@ display_debug_lines (section, start, fil
printf (_(" Line Range: %d\n"), info.li_line_range);
printf (_(" Opcode Base: %d\n"), info.li_opcode_base);
- end_of_sequence = data + info.li_length + sizeof (external->li_length);
+ end_of_sequence = data + info.li_length + initial_length_size;
reset_state_machine (info.li_default_is_stmt);
/* Display the contents of the Opcodes table. */
- standard_opcodes = data + sizeof (*external);
+ standard_opcodes = hdrptr;
printf (_("\n Opcodes:\n"));
@@ -6677,7 +6695,6 @@ display_debug_pubnames (section, start,
unsigned char *start;
FILE *file ATTRIBUTE_UNUSED;
{
- DWARF2_External_PubNames *external;
DWARF2_Internal_PubNames pubnames;
unsigned char *end;
@@ -6689,30 +6706,41 @@ display_debug_pubnames (section, start,
{
unsigned char *data;
unsigned long offset;
+ int offset_size, initial_length_size;
- external = (DWARF2_External_PubNames *) start;
-
- pubnames.pn_length = BYTE_GET (external->pn_length);
- pubnames.pn_version = BYTE_GET (external->pn_version);
- pubnames.pn_offset = BYTE_GET (external->pn_offset);
- pubnames.pn_size = BYTE_GET (external->pn_size);
-
- data = start + sizeof (*external);
- start += pubnames.pn_length + sizeof (external->pn_length);
+ data = start;
+ pubnames.pn_length = byte_get (data, 4);
+ data += 4;
if (pubnames.pn_length == 0xffffffff)
{
- warn (_("64-bit DWARF pubnames are not supported yet.\n"));
- break;
+ pubnames.pn_length = byte_get (data, 8);
+ data += 8;
+ offset_size = 8;
+ initial_length_size = 12;
+ }
+ else
+ {
+ offset_size = 4;
+ initial_length_size = 4;
}
- if (pubnames.pn_version != 2)
+ pubnames.pn_version = byte_get (data, 2);
+ data += 2;
+ pubnames.pn_offset = byte_get (data, offset_size);
+ data += offset_size;
+ pubnames.pn_size = byte_get (data, offset_size);
+ data += offset_size;
+
+ start += pubnames.pn_length + initial_length_size;
+
+ if (pubnames.pn_version != 2 && pubnames.pn_version != 3)
{
static int warned = 0;
if (! warned)
{
- warn (_("Only DWARF 2 pubnames are currently supported\n"));
+ warn (_("Only DWARF 2 and 3 pubnames are currently supported\n"));
warned = 1;
}
@@ -6732,11 +6760,11 @@ display_debug_pubnames (section, start,
do
{
- offset = byte_get (data, 4);
+ offset = byte_get (data, offset_size);
if (offset != 0)
{
- data += 4;
+ data += offset_size;
printf (" %ld\t\t%s\n", offset, data);
data += strlen ((char *) data) + 1;
}
@@ -7836,12 +7864,15 @@ display_debug_str (section, start, file)
}
static unsigned char *
-read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size)
+read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size,
+ offset_size, dwarf_version)
unsigned long attribute;
unsigned long form;
unsigned char *data;
unsigned long cu_offset;
unsigned long pointer_size;
+ unsigned long offset_size;
+ int dwarf_version;
{
unsigned long uvalue = 0;
unsigned char *block_start = NULL;
@@ -7853,14 +7884,30 @@ read_and_display_attr_value (attribute,
break;
case DW_FORM_ref_addr:
+ if (dwarf_version == 2)
+ {
+ uvalue = byte_get (data, pointer_size);
+ data += pointer_size;
+ }
+ else if (dwarf_version == 3)
+ {
+ uvalue = byte_get (data, offset_size);
+ data += offset_size;
+ }
+ else
+ {
+ error (_("Internal error: DWARF version is not 2 or 3.\n"));
+ }
+ break;
+
case DW_FORM_addr:
uvalue = byte_get (data, pointer_size);
data += pointer_size;
break;
case DW_FORM_strp:
- uvalue = byte_get (data, /* offset_size */ 4);
- data += /* offset_size */ 4;
+ uvalue = byte_get (data, offset_size);
+ data += offset_size;
break;
case DW_FORM_ref1:
@@ -7897,7 +7944,8 @@ read_and_display_attr_value (attribute,
data += bytes_read;
printf (" %s", get_FORM_name (form));
return read_and_display_attr_value (attribute, form, data, cu_offset,
- pointer_size);
+ pointer_size, offset_size,
+ dwarf_version);
}
switch (form)
@@ -8137,7 +8185,7 @@ read_and_display_attr_value (attribute,
decode_location_expression (block_start, pointer_size, uvalue);
printf (")");
}
- else if (form == DW_FORM_data4)
+ else if (form == DW_FORM_data4 || form == DW_FORM_data8)
{
printf ("(");
printf ("location list");
@@ -8153,16 +8201,19 @@ read_and_display_attr_value (attribute,
}
static unsigned char *
-read_and_display_attr (attribute, form, data, cu_offset, pointer_size)
+read_and_display_attr (attribute, form, data, cu_offset, pointer_size,
+ offset_size, dwarf_version)
unsigned long attribute;
unsigned long form;
unsigned char *data;
unsigned long cu_offset;
unsigned long pointer_size;
+ unsigned long offset_size;
+ int dwarf_version;
{
printf (" %-18s:", get_AT_name (attribute));
data = read_and_display_attr_value (attribute, form, data, cu_offset,
- pointer_size);
+ pointer_size, offset_size, dwarf_version);
printf ("\n");
return data;
}
@@ -8183,27 +8234,45 @@ display_debug_info (section, start, file
while (start < end)
{
- DWARF2_External_CompUnit *external;
DWARF2_Internal_CompUnit compunit;
Elf_Internal_Shdr *relsec;
+ unsigned char *hdrptr;
+ unsigned char *cu_abbrev_offset_ptr;
unsigned char *tags;
unsigned int i;
int level;
unsigned long cu_offset;
+ int offset_size;
+ int initial_length_size;
- external = (DWARF2_External_CompUnit *) start;
+ hdrptr = start;
- compunit.cu_length = BYTE_GET (external->cu_length);
- compunit.cu_version = BYTE_GET (external->cu_version);
- compunit.cu_abbrev_offset = BYTE_GET (external->cu_abbrev_offset);
- compunit.cu_pointer_size = BYTE_GET (external->cu_pointer_size);
+ compunit.cu_length = byte_get (hdrptr, 4);
+ hdrptr += 4;
if (compunit.cu_length == 0xffffffff)
{
- warn (_("64-bit DWARF debug info is not supported yet.\n"));
- break;
+ compunit.cu_length = byte_get (hdrptr, 8);
+ hdrptr += 8;
+ offset_size = 8;
+ initial_length_size = 12;
+ }
+ else
+ {
+ offset_size = 4;
+ initial_length_size = 4;
}
+ compunit.cu_version = byte_get (hdrptr, 2);
+ hdrptr += 2;
+
+ cu_abbrev_offset_ptr = hdrptr;
+ compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size);
+ hdrptr += offset_size;
+
+ compunit.cu_pointer_size = byte_get (hdrptr, 1);
+ hdrptr += 1;
+
/* Check for RELA relocations in the
abbrev_offset address, and apply them. */
for (relsec = section_headers;
@@ -8231,8 +8300,7 @@ display_debug_info (section, start, file
for (rp = rela; rp < rela + nrelas; ++rp)
{
if (rp->r_offset
- != (bfd_vma) ((unsigned char *) &external->cu_abbrev_offset
- - section_begin))
+ != (bfd_vma) (cu_abbrev_offset_ptr - section_begin))
continue;
if (is_32bit_elf)
@@ -8268,9 +8336,9 @@ display_debug_info (section, start, file
break;
}
- tags = start + sizeof (*external);
+ tags = hdrptr;
cu_offset = start - section_begin;
- start += compunit.cu_length + sizeof (external->cu_length);
+ start += compunit.cu_length + initial_length_size;
printf (_(" Compilation Unit @ %lx:\n"), cu_offset);
printf (_(" Length: %ld\n"), compunit.cu_length);
@@ -8278,9 +8346,9 @@ display_debug_info (section, start, file
printf (_(" Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset);
printf (_(" Pointer Size: %d\n"), compunit.cu_pointer_size);
- if (compunit.cu_version != 2)
+ if (compunit.cu_version != 2 && compunit.cu_version != 3)
{
- warn (_("Only version 2 DWARF debug information is currently supported.\n"));
+ warn (_("Only version 2 and 3 DWARF debug information is currently supported.\n"));
continue;
}
@@ -8358,7 +8426,9 @@ display_debug_info (section, start, file
tags = read_and_display_attr (attr->attribute,
attr->form,
tags, cu_offset,
- compunit.cu_pointer_size);
+ compunit.cu_pointer_size,
+ offset_size,
+ compunit.cu_version);
if (entry->children)
++level;
@@ -8385,30 +8455,48 @@ display_debug_aranges (section, start, f
while (start < end)
{
- DWARF2_External_ARange *external;
+ unsigned char *hdrptr;
DWARF2_Internal_ARange arange;
unsigned char *ranges;
unsigned long length;
unsigned long address;
int excess;
+ int offset_size;
+ int initial_length_size;
- external = (DWARF2_External_ARange *) start;
+ hdrptr = start;
- arange.ar_length = BYTE_GET (external->ar_length);
- arange.ar_version = BYTE_GET (external->ar_version);
- arange.ar_info_offset = BYTE_GET (external->ar_info_offset);
- arange.ar_pointer_size = BYTE_GET (external->ar_pointer_size);
- arange.ar_segment_size = BYTE_GET (external->ar_segment_size);
+ arange.ar_length = byte_get (hdrptr, 4);
+ hdrptr += 4;
if (arange.ar_length == 0xffffffff)
{
- warn (_("64-bit DWARF aranges are not supported yet.\n"));
- break;
+ arange.ar_length = byte_get (hdrptr, 8);
+ hdrptr += 8;
+ offset_size = 8;
+ initial_length_size = 12;
+ }
+ else
+ {
+ offset_size = 4;
+ initial_length_size = 4;
}
- if (arange.ar_version != 2)
+ arange.ar_version = byte_get (hdrptr, 2);
+ hdrptr += 2;
+
+ arange.ar_info_offset = byte_get (hdrptr, offset_size);
+ hdrptr += offset_size;
+
+ arange.ar_pointer_size = byte_get (hdrptr, 1);
+ hdrptr += 1;
+
+ arange.ar_segment_size = byte_get (hdrptr, 1);
+ hdrptr += 1;
+
+ if (arange.ar_version != 2 && arange.ar_version != 3)
{
- warn (_("Only DWARF 2 aranges are currently supported.\n"));
+ warn (_("Only DWARF 2 and 3 aranges are currently supported.\n"));
break;
}
@@ -8420,10 +8508,10 @@ display_debug_aranges (section, start, f
printf (_("\n Address Length\n"));
- ranges = start + sizeof (*external);
+ ranges = hdrptr;
/* Must pad to an alignment boundary that is twice the pointer size. */
- excess = sizeof (*external) % (2 * arange.ar_pointer_size);
+ excess = (hdrptr - start) % (2 * arange.ar_pointer_size);
if (excess)
ranges += (2 * arange.ar_pointer_size) - excess;
@@ -8444,7 +8532,7 @@ display_debug_aranges (section, start, f
printf (" %8.8lx %lu\n", address, length);
}
- start += arange.ar_length + sizeof (external->ar_length);
+ start += arange.ar_length + initial_length_size;
}
printf ("\n");
@@ -8614,6 +8702,8 @@ display_debug_frames (section, start, fi
unsigned char *augmentation_data = NULL;
unsigned long augmentation_data_len = 0;
int encoded_ptr_size = addr_size;
+ int offset_size;
+ int initial_length_size;
saved_start = start;
length = byte_get (start, 4); start += 4;
@@ -8627,12 +8717,19 @@ display_debug_frames (section, start, fi
if (length == 0xffffffff)
{
- warn (_("64-bit DWARF format frames are not supported yet.\n"));
- break;
+ length = byte_get (start, 8);
+ start += 8;
+ offset_size = 8;
+ initial_length_size = 12;
+ }
+ else
+ {
+ offset_size = 4;
+ initial_length_size = 4;
}
- block_end = saved_start + length + 4;
- cie_id = byte_get (start, 4); start += 4;
+ block_end = saved_start + length + initial_length_size;
+ cie_id = byte_get (start, offset_size); start += offset_size;
if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID))
{
@@ -9195,11 +9292,41 @@ prescan_debug_info (section, start, file
unsigned char *start;
FILE *file ATTRIBUTE_UNUSED;
{
- DWARF2_External_CompUnit *external;
+ unsigned long length;
- external = (DWARF2_External_CompUnit *) start;
+ /* 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 (external->cu_pointer_size);
+ 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;
}