From patchwork Tue Apr 21 15:44:20 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joel Brobecker X-Patchwork-Id: 6343 Received: (qmail 41621 invoked by alias); 21 Apr 2015 15:44:37 -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 41450 invoked by uid 89); 21 Apr 2015 15:44:35 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.0 required=5.0 tests=AWL, BAYES_00, KAM_STOCKGEN, SPF_PASS, T_RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: rock.gnat.com Received: from rock.gnat.com (HELO rock.gnat.com) (205.232.38.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Tue, 21 Apr 2015 15:44:34 +0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id 2D847116535 for ; Tue, 21 Apr 2015 11:44:31 -0400 (EDT) Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id G6vR8dqujve0 for ; Tue, 21 Apr 2015 11:44:31 -0400 (EDT) Received: from joel.gnat.com (localhost.localdomain [127.0.0.1]) by rock.gnat.com (Postfix) with ESMTP id E693311648E for ; Tue, 21 Apr 2015 11:44:30 -0400 (EDT) Received: by joel.gnat.com (Postfix, from userid 1000) id E37F540EAD; Tue, 21 Apr 2015 08:44:30 -0700 (PDT) From: Joel Brobecker To: gdb-patches@sourceware.org Subject: [RFA/commit 2/6] Add valaddr support in dynamic property resolution. Date: Tue, 21 Apr 2015 08:44:20 -0700 Message-Id: <1429631064-4196-3-git-send-email-brobecker@adacore.com> In-Reply-To: <1429631064-4196-1-git-send-email-brobecker@adacore.com> References: <1429631064-4196-1-git-send-email-brobecker@adacore.com> This is the second part of enhancing the debugger to print the value of arrays of records whose size is variable when only standard DWARF info is available (no GNAT encoding). For instance: subtype Small_Type is Integer range 0 .. 10; type Record_Type (I : Small_Type := 0) is record S : String (1 .. I); end record; type Array_Type is array (Integer range <>) of Record_Type; A1 : Array_Type := (1 => (I => 0, S => <>), 2 => (I => 1, S => "A"), 3 => (I => 2, S => "AB")); Currently, GDB prints the following output: (gdb) p a1 $1 = ( The error happens while the ada-valprint module is trying to print the value of an element of our array. Because of the fact that the array's element (type Record_Type) has a variant size, the DWARF info for our array provide the array's stride: <1><749>: Abbrev Number: 10 (DW_TAG_array_type) <74a> DW_AT_name : (indirect string, offset: 0xb6d): pck__T18s <74e> DW_AT_byte_stride : 16 <74f> DW_AT_type : <0x6ea> And because our array has a stride, ada-valprint treats it the same way as packed arrays (see ada-valprint.c::ada_val_print_array): if (TYPE_FIELD_BITSIZE (type, 0) > 0) val_print_packed_array_elements (type, valaddr, offset_aligned, 0, stream, recurse, original_value, options); The first thing that we should notice in the call above is that the "valaddr" buffer and the associated offset (OFFSET_ALIGNED) is passed, but that the corresponding array's address is not. This can be explained by looking inside val_print_packed_array_elements, where we see that the function unpacks each element of our array from the buffer alone (ada_value_primitive_packed_val), and then prints the resulting artificial value instead: v0 = ada_value_primitive_packed_val (NULL, valaddr + offset, (i0 * bitsize) / HOST_CHAR_BIT, (i0 * bitsize) % HOST_CHAR_BIT, bitsize, elttype); [...] val_print (elttype, value_contents_for_printing (v0), value_embedded_offset (v0), 0, stream, recurse + 1, v0, &opts, current_language); Of particular interest, here, is the fact that we call val_print with a null address, which is OK, since we're providing a buffer instead (value_contents_for_printing). Also, providing an address might not always possible, since packing could place elements at boundaries that are not byte-aligned. Things go south when val_print tries to see if there is a pretty-printer that could be applied. In particular, one of the first things that the Python pretty-printer does is to create a value using our buffer, and the given address, which in this case is null (see call to value_from_contents_and_address in gdbpy_apply_val_pretty_printer). value_from_contents_and_address, in turn immediately tries to resolve the type, using the given address, which is null. But, because our array element is a record containing an array whose bound is the value of one of its elements (the "s" component), the debugging info for the array's upper bound is a reference... <3><71a>: Abbrev Number: 7 (DW_TAG_subrange_type) <71b> DW_AT_type : <0x724> <71f> DW_AT_upper_bound : <0x703> ... to component "i" of our record... <2><703>: Abbrev Number: 5 (DW_TAG_member) <704> DW_AT_name : i <706> DW_AT_decl_file : 2 <707> DW_AT_decl_line : 6 <708> DW_AT_type : <0x6d1> <70c> DW_AT_data_member_location: 0 ... where that component is located at offset 0 of the start of the record. dwarf2_evaluate_property correctly determines the offset where to load the value of the bound from, but then tries to read that value from inferior memory using the address that was given, which is null. See case PROP_ADDR_OFFSET in dwarf2_evaluate_property: val = value_at (baton->offset_info.type, pinfo->addr + baton->offset_info.offset); This triggers a memory error, which then causes the printing to terminate. Since there are going to be situations where providing an address alone is not going to be sufficient (packed arrays where array elements are not stored at byte boundaries), this patch fixes the issue by enhancing the type resolution to take both address and data. This follows the same principle as the val_print module, where both address and buffer ("valaddr") can be passed as arguments. If the data has already been fetched from inferior memory (or provided by the debugging info in some form -- Eg a constant), then use that data instead of reading it from inferior memory. Note that this should also be a good step towards being able to handle dynamic types whose value is stored outside of inferior memory (Eg: in a register). With this patch, GDB isn't able to print all of A1, but does perform a little better: (gdb) p a1 $1 = ((i => 0, s => , (i => 1, s => , (i => 2, s => ) There is another issue which is independent of this one, and will therefore be patched separately. gdb/ChangeLog: * dwarf2loc.h (struct property_addr_info): Add "valaddr" field. * dwarf2loc.c (dwarf2_evaluate_property): Add handling of pinfo->valaddr. * gdbtypes.h (resolve_dynamic_type): Add "valaddr" parameter. * gdbtypes.c (resolve_dynamic_struct): Set pinfo.valaddr. (resolve_dynamic_type_internal): Set pinfo.valaddr. Add handling of addr_stack->valaddr. (resolve_dynamic_type): Add "valaddr" parameter. Set pinfo.valaddr field. * ada-lang.c (ada_discrete_type_high_bound): Update call to resolve_dynamic_type. (ada_discrete_type_low_bound): Likewise. * findvar.c (default_read_var_value): Likewise. * value.c (value_from_contents_and_address): Likewise. --- gdb/ada-lang.c | 4 ++-- gdb/dwarf2loc.c | 9 +++++++-- gdb/dwarf2loc.h | 3 +++ gdb/findvar.c | 4 ++-- gdb/gdbtypes.c | 13 ++++++++++--- gdb/gdbtypes.h | 4 +++- gdb/value.c | 2 +- 7 files changed, 28 insertions(+), 11 deletions(-) diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 124e370..9926cfb 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -794,7 +794,7 @@ min_of_type (struct type *t) LONGEST ada_discrete_type_high_bound (struct type *type) { - type = resolve_dynamic_type (type, 0); + type = resolve_dynamic_type (type, NULL, 0); switch (TYPE_CODE (type)) { case TYPE_CODE_RANGE: @@ -815,7 +815,7 @@ ada_discrete_type_high_bound (struct type *type) LONGEST ada_discrete_type_low_bound (struct type *type) { - type = resolve_dynamic_type (type, 0); + type = resolve_dynamic_type (type, NULL, 0); switch (TYPE_CODE (type)) { case TYPE_CODE_RANGE: diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index e674933..d811106 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -2526,8 +2526,13 @@ dwarf2_evaluate_property (const struct dynamic_prop *prop, break; if (pinfo == NULL) error (_("cannot find reference address for offset property")); - val = value_at (baton->offset_info.type, - pinfo->addr + baton->offset_info.offset); + if (pinfo->valaddr != NULL) + val = value_from_contents + (baton->offset_info.type, + pinfo->valaddr + baton->offset_info.offset); + else + val = value_at (baton->offset_info.type, + pinfo->addr + baton->offset_info.offset); *value = value_as_address (val); return 1; } diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h index 0932456..f3630ac 100644 --- a/gdb/dwarf2loc.h +++ b/gdb/dwarf2loc.h @@ -111,6 +111,9 @@ struct property_addr_info being resolved. */ struct type *type; + /* If not NULL, a buffer containing the object's value. */ + const gdb_byte *valaddr; + /* The address of that object. */ CORE_ADDR addr; diff --git a/gdb/findvar.c b/gdb/findvar.c index 128bf5e..2079b4b 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -438,7 +438,7 @@ default_read_var_value (struct symbol *var, struct frame_info *frame) if (is_dynamic_type (type)) { /* Value is a constant byte-sequence and needs no memory access. */ - type = resolve_dynamic_type (type, /* Unused address. */ 0); + type = resolve_dynamic_type (type, NULL, /* Unused address. */ 0); } /* Put the constant back in target format. */ v = allocate_value (type); @@ -470,7 +470,7 @@ default_read_var_value (struct symbol *var, struct frame_info *frame) if (is_dynamic_type (type)) { /* Value is a constant byte-sequence and needs no memory access. */ - type = resolve_dynamic_type (type, /* Unused address. */ 0); + type = resolve_dynamic_type (type, NULL, /* Unused address. */ 0); } v = allocate_value (type); memcpy (value_contents_raw (v), SYMBOL_VALUE_BYTES (var), diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index fe00ea7..7bcc9e7 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -1984,6 +1984,7 @@ resolve_dynamic_struct (struct type *type, " (invalid location kind)")); pinfo.type = check_typedef (TYPE_FIELD_TYPE (type, i)); + pinfo.valaddr = addr_stack->valaddr; pinfo.addr = addr_stack->addr; pinfo.next = addr_stack; @@ -2050,7 +2051,11 @@ resolve_dynamic_type_internal (struct type *type, struct property_addr_info pinfo; pinfo.type = check_typedef (TYPE_TARGET_TYPE (type)); - pinfo.addr = read_memory_typed_address (addr_stack->addr, type); + pinfo.valaddr = NULL; + if (addr_stack->valaddr != NULL) + pinfo.addr = extract_typed_address (addr_stack->valaddr, type); + else + pinfo.addr = read_memory_typed_address (addr_stack->addr, type); pinfo.next = addr_stack; resolved_type = copy_type (type); @@ -2092,9 +2097,11 @@ resolve_dynamic_type_internal (struct type *type, /* See gdbtypes.h */ struct type * -resolve_dynamic_type (struct type *type, CORE_ADDR addr) +resolve_dynamic_type (struct type *type, const gdb_byte *valaddr, + CORE_ADDR addr) { - struct property_addr_info pinfo = {check_typedef (type), addr, NULL}; + struct property_addr_info pinfo + = {check_typedef (type), valaddr, addr, NULL}; return resolve_dynamic_type_internal (type, &pinfo, 1); } diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 883418f..abb1a09 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -1791,7 +1791,9 @@ extern void get_signed_type_minmax (struct type *, LONGEST *, LONGEST *); ADDR specifies the location of the variable the type is bound to. If TYPE has no dynamic properties return TYPE; otherwise a new type with static properties is returned. */ -extern struct type *resolve_dynamic_type (struct type *type, CORE_ADDR addr); +extern struct type *resolve_dynamic_type (struct type *type, + const gdb_byte *valaddr, + CORE_ADDR addr); /* * Predicate if the type has dynamic values, which are not resolved yet. */ extern int is_dynamic_type (struct type *type); diff --git a/gdb/value.c b/gdb/value.c index cb56849..6ad2643 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -3497,7 +3497,7 @@ value_from_contents_and_address (struct type *type, const gdb_byte *valaddr, CORE_ADDR address) { - struct type *resolved_type = resolve_dynamic_type (type, address); + struct type *resolved_type = resolve_dynamic_type (type, valaddr, address); struct type *resolved_type_no_typedef = check_typedef (resolved_type); struct value *v;