This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH RFA] DWARF v2.1 64-bit support


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;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]