Add valaddr support in dynamic property resolution.
authorJoel Brobecker <brobecker@adacore.com>
Wed, 1 Apr 2015 17:00:13 +0000 (10:00 -0700)
committerJoel Brobecker <brobecker@adacore.com>
Tue, 5 May 2015 17:43:35 +0000 (10:43 -0700)
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/ChangeLog
gdb/ada-lang.c
gdb/dwarf2loc.c
gdb/dwarf2loc.h
gdb/findvar.c
gdb/gdbtypes.c
gdb/gdbtypes.h
gdb/value.c

index 5c3ca8ff05a5ae66a7395b3b1bba0e6f7a13b94f..5233c6d297c798c8246296627dc8c1aa5a198a4c 100644 (file)
@@ -1,3 +1,20 @@
+2015-05-05  Joel Brobecker  <brobecker@adacore.com>
+
+       * 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.
+
 2015-05-05  Joel Brobecker  <brobecker@adacore.com>
 
        * gdbtypes.c (resolve_dynamic_array): Use
index d0340493b6bebd5f2b3b03fa8a00ad7264f822a3..26f2c52ed43198078bb53520be106b2625bdd4ae 100644 (file)
@@ -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:
index e674933193be0588c408423d0fbb4922de069028..d81110684e02091372317221e83310807651c811 100644 (file)
@@ -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;
       }
index 0932456977f0c94ce3900777ad0aa972596c7205..f3630ac0b273c6853115c8956a9240f4d3f5ec8d 100644 (file)
@@ -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;
 
index 128bf5ea5d3adbe4ac647be0eacb2e12b1d620f7..2079b4b2b183f14a2ff0b6027a25fdeba1b97bdb 100644 (file)
@@ -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),
index d91b5d542dc48b1915ed07f24b04b89f97107bd3..4bbfc753889a057bcd219230391d268323be3db4 100644 (file)
@@ -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;
 
@@ -2054,7 +2055,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);
@@ -2096,9 +2101,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);
 }
index a912c8c930f199d6a3affa58ea2c22c4d0287bef..4275ee09b93d00e373aec9516ebc4260f2867bda 100644 (file)
@@ -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);
index c36f7488a9107f6ea845d8e6f1f2a3cde2dd9bb2..2b3288185db0786dcf54571a809ca03159a6e3ff 100644 (file)
@@ -3509,7 +3509,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;