From ee42cf8cc569b0ad926df63483075ccd868a10fa Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Mon, 31 Mar 2003 13:06:01 +0000 Subject: [PATCH] Add some initial 64-bit DWARF support --- binutils/ChangeLog | 9 ++ binutils/readelf.c | 287 ++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 217 insertions(+), 79 deletions(-) diff --git a/binutils/ChangeLog b/binutils/ChangeLog index dd9843f..7a93260 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,12 @@ +2003-03-31 Kevin Buettner + + * 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 * rcparse.y: Replace uses of 'optstringrc' with 'optresid'. diff --git a/binutils/readelf.c b/binutils/readelf.c index 00a6d33..af3b14b 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; } -- 2.7.4