summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2003-03-31 13:06:01 +0000
committerNick Clifton <nickc@redhat.com>2003-03-31 13:06:01 +0000
commit1b3cc0cd477af7f3cfc1fc7fb558804accb728d3 (patch)
tree3f8bcf60c69d96c704ef047528a1cfbd261e2140
parentbd9b0ff9c1163e2f109f80cece5ff38c0ebde670 (diff)
downloadbinutils-redhat-1b3cc0cd477af7f3cfc1fc7fb558804accb728d3.tar.gz
Add some initial 64-bit DWARF support
-rw-r--r--binutils/ChangeLog9
-rw-r--r--binutils/readelf.c287
2 files changed, 217 insertions, 79 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index dd9843f99b..7a93260024 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,12 @@
+2003-03-31 Kevin Buettner <kevinb@redhat.com>
+
+ * 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.
+
2003-03-31 Ian Lance Taylor <ian@airs.com>
* rcparse.y: Replace uses of 'optstringrc' with 'optresid'.
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 00a6d330fe..af3b14b7d4 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -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
@@ -407,7 +407,7 @@ typedef int Elf32_Word;
#define SECTION_HEADER(I) (section_headers + SECTION_HEADER_INDEX (I))
-#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
+#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
#define BYTE_GET(field) byte_get (field, sizeof (field))
@@ -944,6 +944,7 @@ slurp_rel_relocs (file, rel_offset, rel_size, relsp, nrelsp)
}
/* Display the contents of the relocation data found at the specified offset. */
+
static int
dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela)
FILE *file;
@@ -2881,6 +2882,7 @@ get_osabi_name (osabi)
}
/* Decode the data held in 'elf_header'. */
+
static int
process_file_header ()
{
@@ -6420,31 +6422,42 @@ display_debug_lines (section, start, file)
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 +6465,26 @@ display_debug_lines (section, start, file)
}
/* 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 +6499,12 @@ display_debug_lines (section, start, file)
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 +6697,6 @@ display_debug_pubnames (section, start, file)
unsigned char *start;
FILE *file ATTRIBUTE_UNUSED;
{
- DWARF2_External_PubNames *external;
DWARF2_Internal_PubNames pubnames;
unsigned char *end;
@@ -6689,30 +6708,41 @@ display_debug_pubnames (section, start, file)
{
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 +6762,11 @@ display_debug_pubnames (section, start, file)
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 +7866,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 +7886,30 @@ read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size)
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 +7946,8 @@ read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size)
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 +8187,7 @@ read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size)
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 +8203,19 @@ read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size)
}
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 +8236,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 +8302,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 +8338,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 +8348,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 +8428,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 +8457,48 @@ display_debug_aranges (section, start, file)
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 +8510,10 @@ display_debug_aranges (section, start, file)
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 +8534,7 @@ display_debug_aranges (section, start, file)
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 +8704,8 @@ display_debug_frames (section, start, file)
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 +8719,19 @@ display_debug_frames (section, start, file)
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 +9294,41 @@ prescan_debug_info (section, start, file)
unsigned char *start;
FILE *file ATTRIBUTE_UNUSED;
{
- DWARF2_External_CompUnit *external;
+ 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);
- external = (DWARF2_External_CompUnit *) start;
+ 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:
- debug_line_pointer_size = BYTE_GET (external->cu_pointer_size);
+ 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;
}