From patchwork Fri Nov 29 23:32:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Simon Marchi (Code Review)" X-Patchwork-Id: 36390 Received: (qmail 55576 invoked by alias); 29 Nov 2019 23:32:52 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 55486 invoked by uid 89); 29 Nov 2019 23:32:52 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-21.5 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3 autolearn=ham version=3.3.1 spammy=Dynamic, msg, sk:DW_AT_s, sk:dw_at_s X-HELO: mx1.osci.io Received: from polly.osci.io (HELO mx1.osci.io) (8.43.85.229) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 29 Nov 2019 23:32:49 +0000 Received: by mx1.osci.io (Postfix, from userid 994) id AD449202DF; Fri, 29 Nov 2019 18:32:46 -0500 (EST) Received: from gnutoolchain-gerrit.osci.io (gnutoolchain-gerrit.osci.io [8.43.85.239]) by mx1.osci.io (Postfix) with ESMTP id 524E0203AC for ; Fri, 29 Nov 2019 18:32:41 -0500 (EST) Received: from localhost (localhost [127.0.0.1]) by gnutoolchain-gerrit.osci.io (Postfix) with ESMTP id 3EB8220AF6 for ; Fri, 29 Nov 2019 18:32:41 -0500 (EST) X-Gerrit-PatchSet: 1 Date: Fri, 29 Nov 2019 18:32:41 -0500 From: "Andrew Burgess (Code Review)" To: gdb-patches@sourceware.org Message-ID: Auto-Submitted: auto-generated X-Gerrit-MessageType: newchange Subject: [review] gdb: Dynamic string length support X-Gerrit-Change-Id: I03f2d181b26156f48f27a03c8a59f9bd4d71ac17 X-Gerrit-Change-Number: 737 X-Gerrit-ChangeURL: X-Gerrit-Commit: 84edc45c345e5f0f3b563e5dfb84060fc64fb247 References: Reply-To: andrew.burgess@embecosm.com, gdb-patches@sourceware.org MIME-Version: 1.0 Content-Disposition: inline User-Agent: Gerrit/3.0.3-79-g83ff7f88f1 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 + + * 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 * 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 + + * gdb.fortran/array-slices.exp: Add test for dynamic strings. + 2019-11-18 Richard Bunt Andrew Burgess 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" } }