diff options
author | Joel Brobecker <brobecker@adacore.com> | 2015-01-05 14:32:36 +0400 |
---|---|---|
committer | Joel Brobecker <brobecker@adacore.com> | 2015-01-29 12:08:47 +0400 |
commit | df25ebbd091aebc132f97ffd6ce9cf7964a57981 (patch) | |
tree | 85422e183eef04a63ebf40305230ea281b16c304 /gdb/dwarf2read.c | |
parent | 4a0ca9ec1ee3bc18da72ce42cdd7c2959e58aa76 (diff) | |
download | gdb-df25ebbd091aebc132f97ffd6ce9cf7964a57981.zip gdb-df25ebbd091aebc132f97ffd6ce9cf7964a57981.tar.gz gdb-df25ebbd091aebc132f97ffd6ce9cf7964a57981.tar.bz2 |
gdb/DWARF: Support for arrays whose bound is a discriminant.
Consider the following declarations:
type Array_Type is array (Integer range <>) of Integer;
type Record_Type (N : Integer) is record
A : Array_Type (1 .. N);
end record;
R : Record_Type := Get (10);
It defines what Ada programers call a "discriminated record", where
"N" is a component of that record called a "discriminant", and where
"A" is a component defined as an array type whose upper bound is
equal to the value of the discriminant.
So far, we rely on a number of fairly complex GNAT-specific encodings
to handle this situation. This patch is to enhance GDB to be able to
print this record in the case where the compiler has been modified
to replace those encodings by pure DWARF constructs.
In particular, the debugging information generated for the record above
looks like the following. "R" is a record..
.uleb128 0x10 # (DIE (0x13e) DW_TAG_structure_type)
.long .LASF17 # DW_AT_name: "foo__record_type"
... whose is is of course dynamic (not our concern here)...
.uleb128 0xd # DW_AT_byte_size
.byte 0x97 # DW_OP_push_object_address
.byte 0x94 # DW_OP_deref_size
.byte 0x4
.byte 0x99 # DW_OP_call4
.long 0x19b
.byte 0x23 # DW_OP_plus_uconst
.uleb128 0x7
.byte 0x9 # DW_OP_const1s
.byte 0xfc
.byte 0x1a # DW_OP_and
.byte 0x1 # DW_AT_decl_file (foo.adb)
.byte 0x6 # DW_AT_decl_line
... and then has 2 members, fist "n" (our discriminant);
.uleb128 0x11 # (DIE (0x153) DW_TAG_member)
.ascii "n\0" # DW_AT_name
.byte 0x1 # DW_AT_decl_file (foo.adb)
.byte 0x6 # DW_AT_decl_line
.long 0x194 # DW_AT_type
.byte 0 # DW_AT_data_member_location
... and "A"...
.uleb128 0x11 # (DIE (0x181) DW_TAG_member)
.ascii "a\0" # DW_AT_name
.long 0x15d # DW_AT_type
.byte 0x4 # DW_AT_data_member_location
... which is an array ...
.uleb128 0x12 # (DIE (0x15d) DW_TAG_array_type)
.long .LASF18 # DW_AT_name: "foo__record_type__T4b"
.long 0x194 # DW_AT_type
... whose lower bound is implicitly 1, and the upper bound
a reference to DIE 0x153 = "N":
.uleb128 0x13 # (DIE (0x16a) DW_TAG_subrange_type)
.long 0x174 # DW_AT_type
.long 0x153 # DW_AT_upper_bound
This patch enhanced GDB to understand references to other DIEs
where the DIE's address is at an offset of its enclosing type.
The difficulty was that the address used to resolve the array's
type (R's address + 4 bytes) is different from the address used
as the base to compute N's address (an offset to R's address).
We're solving this issue by using a stack of addresses rather
than a single address when trying to resolve a type. Each address
in the stack corresponds to each containing level. For instance,
if resolving the field of a struct, the stack should contain
the address of the field at the top, and then the address of
the struct. That way, if the field makes a reference to an object
of the struct, we can retrieve the address of that struct, and
properly resolve the dynamic property references that struct.
gdb/ChangeLog:
* gdbtypes.h (struct dynamic_prop): New PROP_ADDR_OFFSET enum
kind.
* gdbtypes.c (resolve_dynamic_type_internal): Replace "addr"
parameter by "addr_stack" parameter.
(resolve_dynamic_range): Replace "addr" parameter by
"stack_addr" parameter. Update function documentation.
Update code accordingly.
(resolve_dynamic_array, resolve_dynamic_union)
(resolve_dynamic_struct, resolve_dynamic_type_internal): Likewise.
(resolve_dynamic_type): Update code, following the changes made
to resolve_dynamic_type_internal's interface.
* dwarf2loc.h (struct property_addr_info): New.
(dwarf2_evaluate_property): Replace "address" parameter
by "addr_stack" parameter. Adjust function documentation.
(struct dwarf2_offset_baton): New.
(struct dwarf2_property_baton): Update documentation of
field "referenced_type" to be more general. New field
"offset_info" in union data field.
* dwarf2loc.c (dwarf2_evaluate_property): Replace "address"
parameter by "addr_stack" parameter. Adjust code accordingly.
Add support for PROP_ADDR_OFFSET properties.
* dwarf2read.c (attr_to_dynamic_prop): Add support for
DW_AT_data_member_location attributes as well. Use case
statements instead of if/else condition.
gdb/testsuite/ChangeLog:
* gdb.ada/disc_arr_bound: New testcase.
Tested on x86_64-linux, no regression.
Diffstat (limited to 'gdb/dwarf2read.c')
-rw-r--r-- | gdb/dwarf2read.c | 73 |
1 files changed, 49 insertions, 24 deletions
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 715b090..ccbaede 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -14733,33 +14733,58 @@ attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die, target_die = follow_die_ref (die, attr, &target_cu); target_attr = dwarf2_attr (target_die, DW_AT_location, target_cu); if (target_attr == NULL) + target_attr = dwarf2_attr (target_die, DW_AT_data_member_location, + target_cu); + if (target_attr == NULL) return 0; - if (attr_form_is_section_offset (target_attr)) - { - baton = obstack_alloc (obstack, sizeof (*baton)); - baton->referenced_type = die_type (target_die, target_cu); - fill_in_loclist_baton (cu, &baton->loclist, target_attr); - prop->data.baton = baton; - prop->kind = PROP_LOCLIST; - gdb_assert (prop->data.baton != NULL); - } - else if (attr_form_is_block (target_attr)) - { - baton = obstack_alloc (obstack, sizeof (*baton)); - baton->referenced_type = die_type (target_die, target_cu); - baton->locexpr.per_cu = cu->per_cu; - baton->locexpr.size = DW_BLOCK (target_attr)->size; - baton->locexpr.data = DW_BLOCK (target_attr)->data; - prop->data.baton = baton; - prop->kind = PROP_LOCEXPR; - gdb_assert (prop->data.baton != NULL); - } - else + switch (target_attr->name) { - dwarf2_invalid_attrib_class_complaint ("DW_AT_location", - "dynamic property"); - return 0; + case DW_AT_location: + if (attr_form_is_section_offset (target_attr)) + { + baton = obstack_alloc (obstack, sizeof (*baton)); + baton->referenced_type = die_type (target_die, target_cu); + fill_in_loclist_baton (cu, &baton->loclist, target_attr); + prop->data.baton = baton; + prop->kind = PROP_LOCLIST; + gdb_assert (prop->data.baton != NULL); + } + else if (attr_form_is_block (target_attr)) + { + baton = obstack_alloc (obstack, sizeof (*baton)); + baton->referenced_type = die_type (target_die, target_cu); + baton->locexpr.per_cu = cu->per_cu; + baton->locexpr.size = DW_BLOCK (target_attr)->size; + baton->locexpr.data = DW_BLOCK (target_attr)->data; + prop->data.baton = baton; + prop->kind = PROP_LOCEXPR; + gdb_assert (prop->data.baton != NULL); + } + else + { + dwarf2_invalid_attrib_class_complaint ("DW_AT_location", + "dynamic property"); + return 0; + } + break; + case DW_AT_data_member_location: + { + LONGEST offset; + + if (!handle_data_member_location (target_die, target_cu, + &offset)) + return 0; + + baton = obstack_alloc (obstack, sizeof (*baton)); + baton->referenced_type = get_die_type (target_die->parent, + target_cu); + baton->offset_info.offset = offset; + baton->offset_info.type = die_type (target_die, target_cu); + prop->data.baton = baton; + prop->kind = PROP_ADDR_OFFSET; + break; + } } } else if (attr_form_is_constant (attr)) |