RFC: add DWARF-4 features

Tom Tromey tromey@redhat.com
Tue Apr 13 20:28:00 GMT 2010


Following Jakub's patches for GCC and binutils, this adds support for
new DWARF-4 features to gdb.

I would appreciate some extra eyes on this.

The new features are:

* GCC will start emitting "4" as the DWARF version number
* CIE version 4 has two extra header fields
* New forms DW_FORM_flag_present, DW_FORM_sec_offset, DW_FORM_exprloc
* Line table version 4 has maximum_ops_per_instruction field in the
  header, plus a new state machine variable

Built and regtested on x86-64.  I also ran the test suite with -gdwarf-4
using svn gcc; the results looked sane, and at least some of the new
code is covered.  I think GCC still doesn't emit the DWARF 4-style CIE.

I was not completely sure how to handle the line table addition.  I
chose to have it only note a line when op_index==0, that is (IIUC).  GCC
doesn't emit maximum_ops_per_instruction!=1, so I have no way of testing
this in any case.

Let me know what you think.

Tom

2010-04-13  Tom Tromey  <tromey@redhat.com>

	* dwarf2-frame.c (decode_frame_entry_1): Handle CIE version 4.
	(struct dwarf2_cie) <segment_size>: New field.
	* dwarf2read.c (partial_read_comp_unit_head): Accept DWARF 4.
	(skip_one_die): Handle DW_FORM_flag_present, DW_FORM_sec_offset,
	DW_FORM_exprloc.
	(read_attribute_value): Handle DW_FORM_flag_present,
	DW_FORM_sec_offset, DW_FORM_exprloc.
	(dump_die_shallow): Likewise.
	(attr_form_is_section_offset): Handle DW_FORM_sec_offset.
	(dwarf2_const_value): Handle DW_FORM_exprloc.
	(attr_form_is_block): Likewise.
	(struct line_header) <maximum_ops_per_instruction>: New field.
	(dwarf_decode_line_header): Set new field.
	(dwarf_decode_lines): Handle new field.

diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c
index 47a2cf1..33d001c 100644
--- a/gdb/dwarf2-frame.c
+++ b/gdb/dwarf2-frame.c
@@ -85,6 +85,9 @@ struct dwarf2_cie
 
   /* The version recorded in the CIE.  */
   unsigned char version;
+
+  /* The segment size.  */
+  unsigned char segment_size;
 };
 
 struct dwarf2_cie_table
@@ -1714,7 +1717,7 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p,
 
       /* Check version number.  */
       cie_version = read_1_byte (unit->abfd, buf);
-      if (cie_version != 1 && cie_version != 3)
+      if (cie_version != 1 && cie_version != 3 && cie_version != 4)
 	return NULL;
       cie->version = cie_version;
       buf += 1;
@@ -1738,6 +1741,20 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p,
 	  augmentation += 2;
 	}
 
+      if (cie->version >= 4)
+	{
+	  /* FIXME: check that this is the same as from the CU header.  */
+	  cie->addr_size = read_1_byte (unit->abfd, buf);
+	  ++buf;
+	  cie->segment_size = read_1_byte (unit->abfd, buf);
+	  ++buf;
+	}
+      else
+	{
+	  cie->addr_size = gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT;
+	  cie->segment_size = 0;
+	}
+
       cie->code_alignment_factor =
 	read_unsigned_leb128 (unit->abfd, buf, &bytes_read);
       buf += bytes_read;
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 724016f..c2017e5 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -396,6 +396,7 @@ struct line_header
   unsigned short version;
   unsigned int header_length;
   unsigned char minimum_instruction_length;
+  unsigned char maximum_ops_per_instruction;
   unsigned char default_is_stmt;
   int line_base;
   unsigned char line_range;
@@ -1488,10 +1489,10 @@ partial_read_comp_unit_head (struct comp_unit_head *header, gdb_byte *info_ptr,
 
   info_ptr = read_comp_unit_head (header, info_ptr, abfd);
 
-  if (header->version != 2 && header->version != 3)
+  if (header->version != 2 && header->version != 3 && header->version != 4)
     error (_("Dwarf Error: wrong version in compilation unit header "
-	   "(is %d, should be %d) [in module %s]"), header->version,
-	   2, bfd_get_filename (abfd));
+	   "(is %d, should be 2, 3, or 4) [in module %s]"), header->version,
+	   bfd_get_filename (abfd));
 
   if (header->abbrev_offset >= dwarf2_per_objfile->abbrev.size)
     error (_("Dwarf Error: bad offset (0x%lx) in compilation unit header "
@@ -2776,6 +2777,8 @@ skip_one_die (gdb_byte *buffer, gdb_byte *info_ptr,
 	case DW_FORM_flag:
 	  info_ptr += 1;
 	  break;
+	case DW_FORM_flag_present:
+	  break;
 	case DW_FORM_data2:
 	case DW_FORM_ref2:
 	  info_ptr += 2;
@@ -2793,9 +2796,11 @@ skip_one_die (gdb_byte *buffer, gdb_byte *info_ptr,
 	  read_string (abfd, info_ptr, &bytes_read);
 	  info_ptr += bytes_read;
 	  break;
+	case DW_FORM_sec_offset:
 	case DW_FORM_strp:
 	  info_ptr += cu->header.offset_size;
 	  break;
+	case DW_FORM_exprloc:
 	case DW_FORM_block:
 	  info_ptr += read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
 	  info_ptr += bytes_read;
@@ -7129,6 +7134,10 @@ read_attribute_value (struct attribute *attr, unsigned form,
       DW_UNSND (attr) = read_8_bytes (abfd, info_ptr);
       info_ptr += 8;
       break;
+    case DW_FORM_sec_offset:
+      DW_ADDR (attr) = read_offset (abfd, info_ptr, &cu->header, &bytes_read);
+      info_ptr += bytes_read;
+      break;
     case DW_FORM_string:
       DW_STRING (attr) = read_string (abfd, info_ptr, &bytes_read);
       DW_STRING_IS_CANONICAL (attr) = 0;
@@ -7140,6 +7149,7 @@ read_attribute_value (struct attribute *attr, unsigned form,
       DW_STRING_IS_CANONICAL (attr) = 0;
       info_ptr += bytes_read;
       break;
+    case DW_FORM_exprloc:
     case DW_FORM_block:
       blk = dwarf_alloc_block (cu);
       blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
@@ -7164,6 +7174,9 @@ read_attribute_value (struct attribute *attr, unsigned form,
       DW_UNSND (attr) = read_1_byte (abfd, info_ptr);
       info_ptr += 1;
       break;
+    case DW_FORM_flag_present:
+      DW_UNSND (attr) = 1;
+      break;
     case DW_FORM_sdata:
       DW_SND (attr) = read_signed_leb128 (abfd, info_ptr, &bytes_read);
       info_ptr += bytes_read;
@@ -7680,7 +7693,7 @@ dwarf2_attr_no_follow (struct die_info *die, unsigned int name,
 
 /* Return non-zero iff the attribute NAME is defined for the given DIE,
    and holds a non-zero value.  This function should only be used for
-   DW_FORM_flag attributes.  */
+   DW_FORM_flag or DW_FORM_flag_present attributes.  */
 
 static int
 dwarf2_flag_true_p (struct die_info *die, unsigned name, struct dwarf2_cu *cu)
@@ -7862,6 +7875,21 @@ dwarf_decode_line_header (unsigned int offset, bfd *abfd,
   line_ptr += offset_size;
   lh->minimum_instruction_length = read_1_byte (abfd, line_ptr);
   line_ptr += 1;
+  if (lh->version >= 4)
+    {
+      lh->maximum_ops_per_instruction = read_1_byte (abfd, line_ptr);
+      line_ptr += 1;
+    }
+  else
+    lh->maximum_ops_per_instruction = 1;
+
+  if (lh->maximum_ops_per_instruction == 0)
+    {
+      lh->maximum_ops_per_instruction = 1;
+      complaint (&symfile_complaints,
+		 _("invalid maximum_ops_per_instruction in `.debug_line' section"));
+    }
+
   lh->default_is_stmt = read_1_byte (abfd, line_ptr);
   line_ptr += 1;
   lh->line_base = read_1_signed_byte (abfd, line_ptr);
@@ -8010,6 +8038,7 @@ dwarf_decode_lines (struct line_header *lh, char *comp_dir, bfd *abfd,
       int basic_block = 0;
       int end_sequence = 0;
       CORE_ADDR addr;
+      unsigned char op_index = 0;
 
       if (!decode_for_pst_p && lh->num_file_names >= file)
 	{
@@ -8041,12 +8070,17 @@ dwarf_decode_lines (struct line_header *lh, char *comp_dir, bfd *abfd,
 	    {		
 	      /* Special operand.  */
 	      adj_opcode = op_code - lh->opcode_base;
-	      address += (adj_opcode / lh->line_range)
-		* lh->minimum_instruction_length;
+	      address += ((op_index + (adj_opcode / lh->line_range)
+			   / lh->maximum_ops_per_instruction)
+			  * lh->minimum_instruction_length);
+	      op_index = (op_index + (adj_opcode / lh->line_range)
+			  % lh->maximum_ops_per_instruction);
 	      line += lh->line_base + (adj_opcode % lh->line_range);
 	      if (lh->num_file_names < file || file == 0)
 		dwarf2_debug_line_missing_file_complaint ();
-	      else
+	      /* For now we ignore lines not starting on an
+		 instruction boundary.  */
+	      else if (op_index == 0)
 		{
 		  lh->file_names[file - 1].included_p = 1;
 		  if (!decode_for_pst_p && is_stmt)
@@ -8081,6 +8115,7 @@ dwarf_decode_lines (struct line_header *lh, char *comp_dir, bfd *abfd,
 		  break;
 		case DW_LNE_set_address:
 		  address = read_address (abfd, line_ptr, cu, &bytes_read);
+		  op_index = 0;
 		  line_ptr += bytes_read;
 		  address += baseaddr;
 		  break;
@@ -8146,9 +8181,17 @@ dwarf_decode_lines (struct line_header *lh, char *comp_dir, bfd *abfd,
 	      basic_block = 0;
 	      break;
 	    case DW_LNS_advance_pc:
-	      address += lh->minimum_instruction_length
-		* read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
-	      line_ptr += bytes_read;
+	      {
+		CORE_ADDR adjust
+		  = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+
+		address += (((op_index + adjust)
+			     / lh->maximum_ops_per_instruction)
+			    * lh->minimum_instruction_length);
+		op_index = ((op_index + adjust)
+			    % lh->maximum_ops_per_instruction);
+		line_ptr += bytes_read;
+	      }
 	      break;
 	    case DW_LNS_advance_line:
 	      line += read_signed_leb128 (abfd, line_ptr, &bytes_read);
@@ -8195,11 +8238,19 @@ dwarf_decode_lines (struct line_header *lh, char *comp_dir, bfd *abfd,
 	       instruction length since special opcode 255 would have
 	       scaled the the increment.  */
 	    case DW_LNS_const_add_pc:
-	      address += (lh->minimum_instruction_length
-			  * ((255 - lh->opcode_base) / lh->line_range));
+	      {
+		CORE_ADDR adjust = (255 - lh->opcode_base) / lh->line_range;
+
+		address += (lh->minimum_instruction_length
+			    * ((op_index + adjust)
+			       / lh->maximum_ops_per_instruction));
+		op_index = ((op_index + adjust)
+			    % lh->maximum_ops_per_instruction);
+	      }
 	      break;
 	    case DW_LNS_fixed_advance_pc:
 	      address += read_2_bytes (abfd, line_ptr);
+	      op_index = 0;
 	      line_ptr += 2;
 	      break;
 	    default:
@@ -8761,6 +8812,7 @@ dwarf2_const_value (struct attribute *attr, struct symbol *sym,
     case DW_FORM_block2:
     case DW_FORM_block4:
     case DW_FORM_block:
+    case DW_FORM_exprloc:
       blk = DW_BLOCK (attr);
       if (TYPE_LENGTH (SYMBOL_TYPE (sym)) != blk->size)
 	dwarf2_const_value_length_mismatch_complaint (SYMBOL_PRINT_NAME (sym),
@@ -10308,6 +10360,10 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die)
 	case DW_FORM_block1:
 	  fprintf_unfiltered (f, "block: size %d", DW_BLOCK (&die->attrs[i])->size);
 	  break;
+	case DW_FORM_exprloc:
+	  fprintf_unfiltered (f, "expression: size %d",
+			      DW_BLOCK (&die->attrs[i])->size);
+	  break;
 	case DW_FORM_ref1:
 	case DW_FORM_ref2:
 	case DW_FORM_ref4:
@@ -10323,6 +10379,10 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die)
 	  fprintf_unfiltered (f, "constant: %s",
 			      pulongest (DW_UNSND (&die->attrs[i])));
 	  break;
+	case DW_FORM_sec_offset:
+	  fprintf_unfiltered (f, "section offset: %s",
+			      pulongest (DW_UNSND (&die->attrs[i])));
+	  break;
 	case DW_FORM_sig8:
 	  if (DW_SIGNATURED_TYPE (&die->attrs[i]) != NULL)
 	    fprintf_unfiltered (f, "signatured type, offset: 0x%x",
@@ -10343,6 +10403,9 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die)
 	  else
 	    fprintf_unfiltered (f, "flag: FALSE");
 	  break;
+	case DW_FORM_flag_present:
+	  fprintf_unfiltered (f, "flag: TRUE");
+	  break;
 	case DW_FORM_indirect:
 	  /* the reader will have reduced the indirect form to
 	     the "base form" so this form should not occur */
@@ -11520,7 +11583,8 @@ attr_form_is_block (struct attribute *attr)
       attr->form == DW_FORM_block1
       || attr->form == DW_FORM_block2
       || attr->form == DW_FORM_block4
-      || attr->form == DW_FORM_block);
+      || attr->form == DW_FORM_block
+      || attr->form == DW_FORM_exprloc);
 }
 
 /* Return non-zero if ATTR's value is a section offset --- classes
@@ -11535,7 +11599,8 @@ static int
 attr_form_is_section_offset (struct attribute *attr)
 {
   return (attr->form == DW_FORM_data4
-          || attr->form == DW_FORM_data8);
+          || attr->form == DW_FORM_data8
+	  || attr->form == DW_FORM_sec_offset);
 }
 
 



More information about the Gdb-patches mailing list