gdb: Dynamic string length support
Add support for strings with dynamic length using the DWARF attribute DW_AT_string_length. Currently gFortran generates DWARF for some strings that make use of DW_AT_string_length like this: <1><2cc>: Abbrev Number: 20 (DW_TAG_string_type) <2cd> DW_AT_string_length: 5 byte block: 99 bd 1 0 0 (DW_OP_call4: <0x1bd>) <2d3> DW_AT_byte_size : 4 <2d4> DW_AT_sibling : <0x2e2> In this type entry the DW_AT_string_length attribute references a second DW_TAG_formal_parameter that contains the string length. The DW_AT_byte_size indicates that the length is a 4-byte value. This commit extends GDB's DWARF parsing for strings so that we can create dynamic types as well as static types, based on the attribute the DWARF contains. I then extend the dynamic type resolution code in gdbtypes.c to add support for resolving dynamic strings. gdb/ChangeLog: * dwarf2read.c (read_tag_string_type): Read the fields required to make a dynamic string, and possibly create a dynamic range for the string. (attr_to_dynamic_prop): Setup is_reference based on the type of attribute being processed. * gdbtypes.c (is_dynamic_type_internal): Handle TYPE_CODE_STRING. (resolve_dynamic_array): Rename to... (resolve_dynamic_array_or_string): ...this, update header comment, and accept TYPE_CODE_STRING. (resolve_dynamic_type_internal): Handle TYPE_CODE_STRING. gdb/testsuite/ChangeLog: * gdb.fortran/array-slices.exp: Add test for dynamic strings. Change-Id: I03f2d181b26156f48f27a03c8a59f9bd4d71ac17
This commit is contained in:
parent
11a8b1641e
commit
216a7e6b9e
|
@ -1,3 +1,16 @@
|
|||
2019-12-01 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* dwarf2read.c (read_tag_string_type): Read the fields required to
|
||||
make a dynamic string, and possibly create a dynamic range for the
|
||||
string.
|
||||
(attr_to_dynamic_prop): Setup is_reference based on the type of
|
||||
attribute being processed.
|
||||
* gdbtypes.c (is_dynamic_type_internal): Handle TYPE_CODE_STRING.
|
||||
(resolve_dynamic_array): Rename to...
|
||||
(resolve_dynamic_array_or_string): ...this, update header comment,
|
||||
and accept TYPE_CODE_STRING.
|
||||
(resolve_dynamic_type_internal): Handle TYPE_CODE_STRING.
|
||||
|
||||
2019-12-01 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* dwarf2read.c (dwarf2_per_cu_int_type): New function, takes most
|
||||
|
|
|
@ -17323,29 +17323,90 @@ read_tag_string_type (struct die_info *die, struct dwarf2_cu *cu)
|
|||
struct gdbarch *gdbarch = get_objfile_arch (objfile);
|
||||
struct type *type, *range_type, *index_type, *char_type;
|
||||
struct attribute *attr;
|
||||
unsigned int length;
|
||||
struct dynamic_prop prop;
|
||||
bool length_is_constant = true;
|
||||
LONGEST length;
|
||||
|
||||
/* There are a couple of places where bit sizes might be made use of
|
||||
when parsing a DW_TAG_string_type, however, no producer that we know
|
||||
of make use of these. Handling bit sizes that are a multiple of the
|
||||
byte size is easy enough, but what about other bit sizes? Lets deal
|
||||
with that problem when we have to. Warn about these attributes being
|
||||
unsupported, then parse the type and ignore them like we always
|
||||
have. */
|
||||
if (dwarf2_attr (die, DW_AT_bit_size, cu) != nullptr
|
||||
|| dwarf2_attr (die, DW_AT_string_length_bit_size, cu) != nullptr)
|
||||
{
|
||||
static bool warning_printed = false;
|
||||
if (!warning_printed)
|
||||
{
|
||||
warning (_("DW_AT_bit_size and DW_AT_string_length_bit_size not "
|
||||
"currently supported on DW_TAG_string_type."));
|
||||
warning_printed = true;
|
||||
}
|
||||
}
|
||||
|
||||
attr = dwarf2_attr (die, DW_AT_string_length, cu);
|
||||
if (attr != nullptr)
|
||||
if (attr != nullptr && !attr_form_is_constant (attr))
|
||||
{
|
||||
length = DW_UNSND (attr);
|
||||
/* The string length describes the location at which the length of
|
||||
the string can be found. The size of the length field can be
|
||||
specified with one of the attributes below. */
|
||||
struct type *prop_type;
|
||||
struct attribute *len
|
||||
= dwarf2_attr (die, DW_AT_string_length_byte_size, cu);
|
||||
if (len == nullptr)
|
||||
len = dwarf2_attr (die, DW_AT_byte_size, cu);
|
||||
if (len != nullptr && attr_form_is_constant (len))
|
||||
{
|
||||
/* Pass 0 as the default as we know this attribute is constant
|
||||
and the default value will not be returned. */
|
||||
LONGEST sz = dwarf2_get_attr_constant_value (len, 0);
|
||||
prop_type = dwarf2_per_cu_int_type (cu->per_cu, sz, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the size is not specified then we assume it is the size of
|
||||
an address on this target. */
|
||||
prop_type = dwarf2_per_cu_addr_sized_int_type (cu->per_cu, true);
|
||||
}
|
||||
|
||||
/* Convert the attribute into a dynamic property. */
|
||||
if (!attr_to_dynamic_prop (attr, die, cu, &prop, prop_type))
|
||||
length = 1;
|
||||
else
|
||||
length_is_constant = false;
|
||||
}
|
||||
else if (attr != nullptr)
|
||||
{
|
||||
/* This DW_AT_string_length just contains the length with no
|
||||
indirection. There's no need to create a dynamic property in this
|
||||
case. Pass 0 for the default value as we know it will not be
|
||||
returned in this case. */
|
||||
length = dwarf2_get_attr_constant_value (attr, 0);
|
||||
}
|
||||
else if ((attr = dwarf2_attr (die, DW_AT_byte_size, cu)) != nullptr)
|
||||
{
|
||||
/* We don't currently support non-constant byte sizes for strings. */
|
||||
length = dwarf2_get_attr_constant_value (attr, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check for the DW_AT_byte_size attribute. */
|
||||
attr = dwarf2_attr (die, DW_AT_byte_size, cu);
|
||||
if (attr != nullptr)
|
||||
{
|
||||
length = DW_UNSND (attr);
|
||||
}
|
||||
else
|
||||
{
|
||||
length = 1;
|
||||
}
|
||||
/* Use 1 as a fallback length if we have nothing else. */
|
||||
length = 1;
|
||||
}
|
||||
|
||||
index_type = objfile_type (objfile)->builtin_int;
|
||||
range_type = create_static_range_type (NULL, index_type, 1, length);
|
||||
if (length_is_constant)
|
||||
range_type = create_static_range_type (NULL, index_type, 1, length);
|
||||
else
|
||||
{
|
||||
struct dynamic_prop low_bound;
|
||||
|
||||
low_bound.kind = PROP_CONST;
|
||||
low_bound.data.const_val = 1;
|
||||
range_type = create_range_type (NULL, index_type, &low_bound, &prop, 0);
|
||||
}
|
||||
char_type = language_string_char_type (cu->language_defn, gdbarch);
|
||||
type = create_string_type (NULL, char_type, range_type);
|
||||
|
||||
|
@ -17806,7 +17867,15 @@ attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
|
|||
baton->locexpr.per_cu = cu->per_cu;
|
||||
baton->locexpr.size = DW_BLOCK (attr)->size;
|
||||
baton->locexpr.data = DW_BLOCK (attr)->data;
|
||||
baton->locexpr.is_reference = false;
|
||||
switch (attr->name)
|
||||
{
|
||||
case DW_AT_string_length:
|
||||
baton->locexpr.is_reference = true;
|
||||
break;
|
||||
default:
|
||||
baton->locexpr.is_reference = false;
|
||||
break;
|
||||
}
|
||||
prop->data.baton = baton;
|
||||
prop->kind = PROP_LOCEXPR;
|
||||
gdb_assert (prop->data.baton != NULL);
|
||||
|
|
|
@ -1967,6 +1967,9 @@ is_dynamic_type_internal (struct type *type, int top_level)
|
|||
|| is_dynamic_type_internal (TYPE_TARGET_TYPE (type), 0));
|
||||
}
|
||||
|
||||
case TYPE_CODE_STRING:
|
||||
/* Strings are very much like an array of characters, and can be
|
||||
treated as one here. */
|
||||
case TYPE_CODE_ARRAY:
|
||||
{
|
||||
gdb_assert (TYPE_NFIELDS (type) == 1);
|
||||
|
@ -2088,13 +2091,13 @@ resolve_dynamic_range (struct type *dyn_range_type,
|
|||
return static_range_type;
|
||||
}
|
||||
|
||||
/* Resolves dynamic bound values of an array type TYPE to static ones.
|
||||
ADDR_STACK is a stack of struct property_addr_info to be used
|
||||
if needed during the dynamic resolution. */
|
||||
/* Resolves dynamic bound values of an array or string type TYPE to static
|
||||
ones. ADDR_STACK is a stack of struct property_addr_info to be used if
|
||||
needed during the dynamic resolution. */
|
||||
|
||||
static struct type *
|
||||
resolve_dynamic_array (struct type *type,
|
||||
struct property_addr_info *addr_stack)
|
||||
resolve_dynamic_array_or_string (struct type *type,
|
||||
struct property_addr_info *addr_stack)
|
||||
{
|
||||
CORE_ADDR value;
|
||||
struct type *elt_type;
|
||||
|
@ -2103,7 +2106,10 @@ resolve_dynamic_array (struct type *type,
|
|||
struct dynamic_prop *prop;
|
||||
unsigned int bit_stride = 0;
|
||||
|
||||
gdb_assert (TYPE_CODE (type) == TYPE_CODE_ARRAY);
|
||||
/* For dynamic type resolution strings can be treated like arrays of
|
||||
characters. */
|
||||
gdb_assert (TYPE_CODE (type) == TYPE_CODE_ARRAY
|
||||
|| TYPE_CODE (type) == TYPE_CODE_STRING);
|
||||
|
||||
type = copy_type (type);
|
||||
|
||||
|
@ -2129,7 +2135,7 @@ resolve_dynamic_array (struct type *type,
|
|||
ary_dim = check_typedef (TYPE_TARGET_TYPE (elt_type));
|
||||
|
||||
if (ary_dim != NULL && TYPE_CODE (ary_dim) == TYPE_CODE_ARRAY)
|
||||
elt_type = resolve_dynamic_array (ary_dim, addr_stack);
|
||||
elt_type = resolve_dynamic_array_or_string (ary_dim, addr_stack);
|
||||
else
|
||||
elt_type = TYPE_TARGET_TYPE (type);
|
||||
|
||||
|
@ -2332,8 +2338,11 @@ resolve_dynamic_type_internal (struct type *type,
|
|||
break;
|
||||
}
|
||||
|
||||
case TYPE_CODE_STRING:
|
||||
/* Strings are very much like an array of characters, and can be
|
||||
treated as one here. */
|
||||
case TYPE_CODE_ARRAY:
|
||||
resolved_type = resolve_dynamic_array (type, addr_stack);
|
||||
resolved_type = resolve_dynamic_array_or_string (type, addr_stack);
|
||||
break;
|
||||
|
||||
case TYPE_CODE_RANGE:
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2019-12-01 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* gdb.fortran/array-slices.exp: Add test for dynamic strings.
|
||||
|
||||
2019-12-01 Richard Bunt <richard.bunt@arm.com>
|
||||
Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
|
|
|
@ -46,12 +46,21 @@ set array_contents \
|
|||
" = \\(\\( -26, -25, -24, -23, -22, -21\\) \\( -19, -18, -17, -16, -15, -14\\) \\( -12, -11, -10, -9, -8, -7\\) \\)" \
|
||||
" = \\(\\( -26, -24, -22, -20, -18\\) \\( -5, -3, -1, 1, 3\\) \\( 16, 18, 20, 22, 24\\) \\( 37, 39, 41, 43, 45\\) \\)" ]
|
||||
|
||||
set message_strings \
|
||||
[list \
|
||||
" = 'array'" \
|
||||
" = 'array \\(1:5,1:5\\)'" \
|
||||
" = 'array \\(1:10:2,1:10:2\\)'" \
|
||||
" = 'array \\(1:10:3,1:10:2\\)'" \
|
||||
" = 'array \\(1:10:5,1:10:3\\)'" ]
|
||||
|
||||
set i 0
|
||||
foreach result $array_contents {
|
||||
foreach result $array_contents msg $message_strings {
|
||||
incr i
|
||||
with_test_prefix "test $i" {
|
||||
gdb_continue_to_breakpoint "show"
|
||||
gdb_test "p array" $result
|
||||
gdb_test "p message" "$msg"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue