This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[PATCH RFA] DWARF v2.1 64-bit support
- To: Elena Zannoni <ezannoni at cygnus dot com>
- Subject: [PATCH RFA] DWARF v2.1 64-bit support
- From: Kevin Buettner <kevinb at cygnus dot com>
- Date: Thu, 3 Aug 2000 15:29:55 -0700
- Cc: gdb-patches at sourceware dot cygnus dot com
I request approval for committing the patch below.
I am working on a project which required me to add support for the
DWARF version 2.1 64-bit format. In a nutshell, the 64-bit format
makes certain offset and length fields 64 bits wide instead of merely
32 bits wide, thus making it possible to have DWARF2 sections that are
larger than 4GB in size. (Crazy, huh?) In order to tell which type of
format you have, the initial length field at the beginning of certain
sections will either have a normal 32-bit length, or an escape value
(0xffffffff) followed by a 64 bit length. Once you've seen one of
these 64 bit lengths, you know that certain other fields in the same
section (section lengths and section offsets) will also be 64-bit
values. Note that the initial length field with either occupy 4 or 12
bytes while the later length and offset fields will either occupy 4 or
8 bytes.
The DWARF 2 draft document that I based these changes on is at:
http://reality.sgi.com/dehnert_engr/dwarf/dwarf2p1-draft4-000720.pdf
Note that three hunks of the patch below deal with SECT_OFF_TEXT.
These hunks fix a separate problem which is that the code assumed that
index 0 is the .text section index into objfiles->section_offsets. If
desired, I can separate these three hunks out for separate
consideration. (But it'll be easier for me if these changes are
approved en masse, which is why I'm trying it this way first.)
* dwarf2read.c (struct comp_unit_head): Add fields offset_size
and initial_length_size. Change type of ``length'' field to long.
(read_initial_length, read_offset): New functions.
(dwarf2_build_psymtabs_easy): Call read_initial_length() instead
of just reading 4 bytes.
(read_comp_unit_head): Likewise; also, call read_offset() to
fetch the offset instead of just reading 4 bytes.
(dwarf_decode_lines): Likewise.
(read_comp_unit_head): Fix internal error message so it
accurately reflects the function in which the error occurred.
(dwarf2_build_psymtabs_hard): Properly account for size of the
initial length field in the section.
(read_attribute, dwarf2_get_ref_die_offset): Add a case for
DW_ORM_ref8.
(dwarf2_build_psymtabs_hard, psymtabs_to_symtab_1): Don't
assume that the .text section will have index 0 in the
section_offsets table.
Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.14
diff -u -p -r1.14 dwarf2read.c
--- dwarf2read.c 2000/07/30 01:48:25 1.14
+++ dwarf2read.c 2000/08/03 18:06:08
@@ -152,11 +152,14 @@ static unsigned int dwarf_str_size;
translation, looks like this. */
struct comp_unit_head
{
- unsigned int length;
+ unsigned long length;
short version;
unsigned int abbrev_offset;
unsigned char addr_size;
unsigned char signed_addr_p;
+ unsigned int offset_size; /* size of file offsets; either 4 or 8 */
+ unsigned int initial_length_size; /* size of the length field; either
+ 4 or 12 */
};
/* The data in the .debug_line statement prologue looks like this. */
@@ -604,6 +607,12 @@ static unsigned long read_8_bytes (bfd *
static CORE_ADDR read_address (bfd *, char *ptr, const struct comp_unit_head *,
int *bytes_read);
+static LONGEST read_offset (bfd *, char *, const struct comp_unit_head *,
+ int *bytes_read);
+
+static LONGEST read_initial_length (bfd *, char *,
+ struct comp_unit_head *, int *bytes_read);
+
static char *read_n_bytes (bfd *, char *, unsigned int);
static char *read_string (bfd *, char *, unsigned int *);
@@ -898,8 +907,12 @@ dwarf2_build_psymtabs_easy (struct objfi
pubnames_ptr = pubnames_buffer;
while ((pubnames_ptr - pubnames_buffer) < dwarf_pubnames_size)
{
- entry_length = read_4_bytes (abfd, pubnames_ptr);
- pubnames_ptr += 4;
+ struct comp_unit_head cu_header;
+ int bytes_read;
+
+ entry_length = read_initial_length (abfd, pubnames_ptr, &cu_header,
+ &bytes_read);
+ pubnames_ptr += bytes_read;
version = read_1_byte (abfd, pubnames_ptr);
pubnames_ptr += 1;
info_offset = read_4_bytes (abfd, pubnames_ptr);
@@ -923,17 +936,20 @@ read_comp_unit_head (struct comp_unit_he
char *info_ptr, bfd *abfd)
{
int signed_addr;
- cu_header->length = read_4_bytes (abfd, info_ptr);
- info_ptr += 4;
+ int bytes_read;
+ cu_header->length = read_initial_length (abfd, info_ptr, cu_header,
+ &bytes_read);
+ info_ptr += bytes_read;
cu_header->version = read_2_bytes (abfd, info_ptr);
info_ptr += 2;
- cu_header->abbrev_offset = read_4_bytes (abfd, info_ptr);
- info_ptr += 4;
+ cu_header->abbrev_offset = read_offset (abfd, info_ptr, cu_header,
+ &bytes_read);
+ info_ptr += bytes_read;
cu_header->addr_size = read_1_byte (abfd, info_ptr);
info_ptr += 1;
signed_addr = bfd_get_sign_extend_vma (abfd);
if (signed_addr < 0)
- internal_error ("dwarf2_build_psymtabs_hard: dwarf from non elf file");
+ internal_error ("read_comp_unit_head: dwarf from non elf file");
cu_header->signed_addr_p = signed_addr;
return info_ptr;
}
@@ -980,7 +996,7 @@ dwarf2_build_psymtabs_hard (struct objfi
(long) (beg_of_comp_unit - dwarf_info_buffer));
return;
}
- if (beg_of_comp_unit + cu_header.length + 4
+ if (beg_of_comp_unit + cu_header.length + cu_header.initial_length_size
> dwarf_info_buffer + dwarf_info_size)
{
error ("Dwarf Error: bad length (0x%lx) in compilation unit header (offset 0x%lx + 0).",
@@ -1014,7 +1030,7 @@ dwarf2_build_psymtabs_hard (struct objfi
DWARF_ABBREV_BUFFER (pst) = dwarf_abbrev_buffer;
DWARF_ABBREV_SIZE (pst) = dwarf_abbrev_size;
DWARF_LINE_BUFFER (pst) = dwarf_line_buffer;
- baseaddr = ANOFFSET (objfile->section_offsets, 0);
+ baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
/* Store the function that reads in the rest of the symbol table */
pst->read_symtab = dwarf2_psymtab_to_symtab;
@@ -1049,7 +1065,8 @@ dwarf2_build_psymtabs_hard (struct objfi
also happen.) This happens in VxWorks. */
free_named_symtabs (pst->filename);
- info_ptr = beg_of_comp_unit + cu_header.length + 4;
+ info_ptr = beg_of_comp_unit + cu_header.length
+ + cu_header.initial_length_size;
}
do_cleanups (back_to);
}
@@ -1314,7 +1331,7 @@ psymtab_to_symtab_1 (struct partial_symt
dwarf_abbrev_buffer = DWARF_ABBREV_BUFFER (pst);
dwarf_abbrev_size = DWARF_ABBREV_SIZE (pst);
dwarf_line_buffer = DWARF_LINE_BUFFER (pst);
- baseaddr = ANOFFSET (pst->section_offsets, 0);
+ baseaddr = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile));
cu_header_offset = offset;
info_ptr = dwarf_info_buffer + offset;
@@ -1362,7 +1379,7 @@ psymtab_to_symtab_1 (struct partial_symt
}
}
}
- symtab = end_symtab (highpc + baseaddr, objfile, 0);
+ symtab = end_symtab (highpc + baseaddr, objfile, SECT_OFF_TEXT (objfile));
/* Set symtab language to language from DW_AT_language.
If the compilation is from a C file generated by language preprocessors,
@@ -3370,6 +3387,10 @@ read_attribute (struct attribute *attr,
DW_UNSND (attr) = read_4_bytes (abfd, info_ptr);
info_ptr += 4;
break;
+ case DW_FORM_ref8:
+ DW_UNSND (attr) = read_8_bytes (abfd, info_ptr);
+ info_ptr += 8;
+ break;
case DW_FORM_ref_udata:
DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
@@ -3472,6 +3493,76 @@ read_address (bfd *abfd, char *buf, cons
return retval;
}
+/* Reads the initial length from a section. The DWARF 2.1 specification
+ allows the initial length to take up either 4 bytes or 12 bytes.
+ If the first 4 bytes are 0xffffffff, then the next 8 bytes describe
+ the length and all offsets will be 8 bytes in length instead of 4.
+
+ The value returned via bytes_read should be used to increment
+ the relevant pointer after calling read_initial_length().
+
+ As a side effect, this function sets the fields initial_length_size
+ and offset_size in cu_header to the values appropriate for the
+ length field. (The format of the initial length field determines
+ the width of file offsets to be fetched later with fetch_offset().) */
+
+static LONGEST
+read_initial_length (bfd *abfd, char *buf, struct comp_unit_head *cu_header,
+ int *bytes_read)
+{
+ LONGEST retval = 0;
+
+ retval = bfd_get_32 (abfd, (bfd_byte *) buf);
+
+ if (retval == 0xffffffff)
+ {
+ retval = bfd_get_64 (abfd, (bfd_byte *) buf + 4);
+ *bytes_read = 12;
+ if (cu_header != NULL)
+ {
+ cu_header->initial_length_size = 12;
+ cu_header->offset_size = 8;
+ }
+ }
+ else
+ {
+ *bytes_read = 4;
+ if (cu_header != NULL)
+ {
+ cu_header->initial_length_size = 4;
+ cu_header->offset_size = 4;
+ }
+ }
+
+ return retval;
+}
+
+/* Read an offset from the data stream. The size of the offset is
+ given by cu_header->offset_size. */
+
+static LONGEST
+read_offset (bfd *abfd, char *buf, const struct comp_unit_head *cu_header,
+ int *bytes_read)
+{
+ LONGEST retval = 0;
+
+ switch (cu_header->offset_size)
+ {
+ case 4:
+ retval = bfd_get_32 (abfd, (bfd_byte *) buf);
+ *bytes_read = 4;
+ break;
+ case 8:
+ retval = bfd_get_64 (abfd, (bfd_byte *) buf);
+ *bytes_read = 8;
+ break;
+ default:
+ internal_error ("read_offset: bad switch");
+ }
+
+ return retval;
+}
+
static char *
read_n_bytes (bfd *abfd, char *buf, unsigned int size)
{
@@ -3713,13 +3804,13 @@ dwarf_decode_lines (unsigned int offset,
line_ptr = dwarf_line_buffer + offset;
/* read in the prologue */
- lh.total_length = read_4_bytes (abfd, line_ptr);
- line_ptr += 4;
+ lh.total_length = read_initial_length (abfd, line_ptr, NULL, &bytes_read);
+ line_ptr += bytes_read;
line_end = line_ptr + lh.total_length;
lh.version = read_2_bytes (abfd, line_ptr);
line_ptr += 2;
- lh.prologue_length = read_4_bytes (abfd, line_ptr);
- line_ptr += 4;
+ lh.prologue_length = read_offset (abfd, line_ptr, cu_header, &bytes_read);
+ line_ptr += bytes_read;
lh.minimum_instruction_length = read_1_byte (abfd, line_ptr);
line_ptr += 1;
lh.default_is_stmt = read_1_byte (abfd, line_ptr);
@@ -5512,6 +5603,7 @@ dwarf2_get_ref_die_offset (struct attrib
case DW_FORM_ref1:
case DW_FORM_ref2:
case DW_FORM_ref4:
+ case DW_FORM_ref8:
case DW_FORM_ref_udata:
result = cu_header_offset + DW_UNSND (attr);
break;