[review] gdb: Dynamic string length support
Andrew Burgess (Code Review)
gerrit@gnutoolchain-gerrit.osci.io
Fri Nov 29 23:32:00 GMT 2019
Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/737
......................................................................
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_bye_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
---
M gdb/ChangeLog
M gdb/dwarf2read.c
M gdb/gdbtypes.c
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.fortran/array-slices.exp
5 files changed, 129 insertions(+), 24 deletions(-)
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 011cdb5..145c33d 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,16 @@
+2019-11-29 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-11-18 Andrew Burgess <andrew.burgess@embecosm.com>
* dwarf2read.c (dwarf2_per_cu_int_type): New function, takes most
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 4c01e84..a2766e4 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -17318,29 +17318,90 @@
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);
@@ -17801,7 +17862,15 @@
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);
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index fbc1a5b..515e8d3 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -988,6 +988,7 @@
sure it is TYPE_CODE_UNDEF before we bash it into a range type? */
struct type *
+
create_static_range_type (struct type *result_type, struct type *index_type,
LONGEST low_bound, LONGEST high_bound)
{
@@ -1969,6 +1970,9 @@
|| 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);
@@ -2089,13 +2093,13 @@
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;
@@ -2104,7 +2108,10 @@
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);
@@ -2130,7 +2137,7 @@
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);
@@ -2333,8 +2340,11 @@
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:
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index ae63519..32ab494 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2019-11-29 Andrew Burgess <andrew.burgess@embecosm.com>
+
+ * gdb.fortran/array-slices.exp: Add test for dynamic strings.
+
2019-11-18 Richard Bunt <richard.bunt@arm.com>
Andrew Burgess <andrew.burgess@embecosm.com>
diff --git a/gdb/testsuite/gdb.fortran/array-slices.exp b/gdb/testsuite/gdb.fortran/array-slices.exp
index afd030b..c15ddff 100644
--- a/gdb/testsuite/gdb.fortran/array-slices.exp
+++ b/gdb/testsuite/gdb.fortran/array-slices.exp
@@ -43,12 +43,21 @@
" = \\(\\( 1, 4, 7, 10\\) \\( 21, 24, 27, 30\\) \\( 41, 44, 47, 50\\) \\( 61, 64, 67, 70\\) \\( 81, 84, 87, 90\\) \\)" \
" = \\(\\( 1, 5, 9\\) \\( 31, 35, 39\\) \\( 61, 65, 69\\) \\( 91, 95, 99\\) \\)" ]
+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"
}
}
--
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I03f2d181b26156f48f27a03c8a59f9bd4d71ac17
Gerrit-Change-Number: 737
Gerrit-PatchSet: 1
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-MessageType: newchange
More information about the Gdb-patches
mailing list