This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
RFC: fix DW_AT_data_member_location buglet
- From: Tom Tromey <tromey at redhat dot com>
- To: gdb-patches at sourceware dot org
- Date: Fri, 06 May 2011 12:52:15 -0600
- Subject: 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);