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:
Andrew Burgess 2019-11-29 00:14:35 +00:00
parent 11a8b1641e
commit 216a7e6b9e
5 changed files with 128 additions and 24 deletions

View File

@ -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

View File

@ -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);

View File

@ -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:

View File

@ -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>

View File

@ -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"
}
}