This is the mail archive of the gdb-patches@sourceware.org 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]
Other format: [Raw text]

RFC: fix DW_AT_data_member_location buglet


I would appreciate comments on this patch.
In the absence of comments I plan to check it in on the trunk and the
7.3 branch.

This comes from:

    https://bugzilla.redhat.com/show_bug.cgi?id=702427

The bug here is that gdb does not properly compute the field offsets of
some fields in a large structure.

The DWARF for one of the fields in question looks like:

 [  4428]      member
               name                 (strp) "nr_zones"
               decl_file            (data1) 47
               decl_line            (data2) 615
               type                 (ref4) [    ed]
               data_member_location (data4) location list [ 13e40]

In DWARF 3 and earlier, DW_FORM_data4 was ambiguous in some situations
-- so gdb rejects this as being "too complicated", because it assumes
that this is actually a section offset.  But, because
DW_AT_data_member_location is a DWARF 4 addition, we can assume in this
case that the value is actually a constant.  That is what this patch
does.

This patch also consolidates some repeated code into a single place.
The important bit is reordering the conditions to avoid erroring out too
eagerly.

Built and regtested by our internal buildbot.

Tom

2011-05-06  Tom Tromey  <tromey@redhat.com>

	* dwarf2read.c (handle_data_member_location): New function.
	(dwarf2_add_field): Use it.
	(read_common_block): Likewise.

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index fdab83d..fb7d468 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -6307,6 +6307,41 @@ dwarf2_default_access_attribute (struct die_info *die, struct dwarf2_cu *cu)
     }
 }
 
+/* Look for DW_AT_data_member_location.  Set *OFFSET to the byte
+   offset.  If the attribute was not found return 0, otherwise return
+   1.  If it was found but could not properly be handled, set *OFFSET
+   to 0.  */
+
+static int
+handle_data_member_location (struct die_info *die, struct dwarf2_cu *cu,
+			     int *offset)
+{
+  struct attribute *attr;
+
+  attr = dwarf2_attr (die, DW_AT_data_member_location, cu);
+  if (attr != NULL)
+    {
+      *offset = 0;
+
+      /* Note that we do not check for a section offset first here.
+	 This is because DW_AT_data_member_location is new in DWARF 4,
+	 so if we see it, we can assume that a constant form is really
+	 a constant and not a section offset.  */
+      if (attr_form_is_constant (attr))
+	*offset = dwarf2_get_attr_constant_value (attr, 0);
+      else if (attr_form_is_section_offset (attr))
+	dwarf2_complex_location_expr_complaint ();
+      else if (attr_form_is_block (attr))
+	*offset = decode_locdesc (DW_BLOCK (attr), cu);
+      else
+	dwarf2_complex_location_expr_complaint ();
+
+      return 1;
+    }
+
+  return 0;
+}
+
 /* Add an aggregate field to the field list.  */
 
 static void
@@ -6355,6 +6390,8 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die,
 
   if (die->tag == DW_TAG_member && ! die_is_declaration (die, cu))
     {
+      int offset;
+
       /* Data member other than a C++ static data member.  */
 
       /* Get type of field.  */
@@ -6374,22 +6411,8 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die,
 	}
 
       /* Get bit offset of field.  */
-      attr = dwarf2_attr (die, DW_AT_data_member_location, cu);
-      if (attr)
-	{
-          int byte_offset = 0;
-
-          if (attr_form_is_section_offset (attr))
-	    dwarf2_complex_location_expr_complaint ();
-          else if (attr_form_is_constant (attr))
-            byte_offset = dwarf2_get_attr_constant_value (attr, 0);
-          else if (attr_form_is_block (attr))
-            byte_offset = decode_locdesc (DW_BLOCK (attr), cu);
-	  else
-	    dwarf2_complex_location_expr_complaint ();
-
-          SET_FIELD_BITPOS (*fp, byte_offset * bits_per_byte);
-	}
+      if (handle_data_member_location (die, cu, &offset))
+	SET_FIELD_BITPOS (*fp, offset * bits_per_byte);
       attr = dwarf2_attr (die, DW_AT_bit_offset, cu);
       if (attr)
 	{
@@ -6492,23 +6515,11 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die,
     }
   else if (die->tag == DW_TAG_inheritance)
     {
-      /* C++ base class field.  */
-      attr = dwarf2_attr (die, DW_AT_data_member_location, cu);
-      if (attr)
-	{
-          int byte_offset = 0;
-
-          if (attr_form_is_section_offset (attr))
-	    dwarf2_complex_location_expr_complaint ();
-          else if (attr_form_is_constant (attr))
-            byte_offset = dwarf2_get_attr_constant_value (attr, 0);
-          else if (attr_form_is_block (attr))
-            byte_offset = decode_locdesc (DW_BLOCK (attr), cu);
-	  else
-	    dwarf2_complex_location_expr_complaint ();
+      int offset;
 
-          SET_FIELD_BITPOS (*fp, byte_offset * bits_per_byte);
-	}
+      /* C++ base class field.  */
+      if (handle_data_member_location (die, cu, &offset))
+	SET_FIELD_BITPOS (*fp, offset * bits_per_byte);
       FIELD_BITSIZE (*fp) = 0;
       FIELD_TYPE (*fp) = die_type (die, cu);
       FIELD_NAME (*fp) = type_name_no_tag (fp->type);
@@ -7618,22 +7629,13 @@ read_common_block (struct die_info *die, struct dwarf2_cu *cu)
       child_die = die->child;
       while (child_die && child_die->tag)
 	{
+	  int offset;
+
 	  sym = new_symbol (child_die, NULL, cu);
-	  attr = dwarf2_attr (child_die, DW_AT_data_member_location, cu);
-	  if (sym != NULL && attr != NULL)
+	  if (sym != NULL &&
+	      handle_data_member_location (child_die, cu, &offset))
 	    {
-	      CORE_ADDR byte_offset = 0;
-
-	      if (attr_form_is_section_offset (attr))
-		dwarf2_complex_location_expr_complaint ();
-	      else if (attr_form_is_constant (attr))
-		byte_offset = dwarf2_get_attr_constant_value (attr, 0);
-	      else if (attr_form_is_block (attr))
-		byte_offset = decode_locdesc (DW_BLOCK (attr), cu);
-	      else
-		dwarf2_complex_location_expr_complaint ();
-
-	      SYMBOL_VALUE_ADDRESS (sym) = base + byte_offset;
+	      SYMBOL_VALUE_ADDRESS (sym) = base + offset;
 	      add_symbol_to_list (sym, &global_symbols);
 	    }
 	  child_die = sibling_die (child_die);


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