Big-endian targets: Don't ignore offset into DW_OP_stack_value
authorAndreas Arnez <arnez@linux.vnet.ibm.com>
Thu, 16 Mar 2017 18:50:24 +0000 (19:50 +0100)
committerAndreas Arnez <arnez@linux.vnet.ibm.com>
Thu, 16 Mar 2017 18:50:24 +0000 (19:50 +0100)
Recently I fixed a bug that caused a DW_OP_implicit_pointer with non-zero
offset into a DW_OP_implicit_value to be handled incorrectly on big-endian
targets.  GDB ignored the offset and copied the wrong bytes:

  https://sourceware.org/ml/gdb-patches/2017-01/msg00251.html

But there is still a similar issue when a DW_OP_implicit_pointer points
into a DW_OP_stack_value instead; and again, the offset is ignored.  There
is an important difference, though: While implicit values are treated like
blocks of data and anchored at the lowest-addressed byte, stack values
traditionally contain integer numbers and are anchored at the *least
significant* byte.  Also, stack values do not come in varying sizes, but
are cut down appropriately when used.  Thus, on big-endian targets the
scenario looks like this (higher addresses shown right):

  |<- - - - - Stack value - - - - - - ->|
                  |                     |
                  |<- original object ->|
                  |
                  | offset ->|####|
      ^^^^
                              de-referenced
      implicit pointer

(Note how the original object's size influences the position of the
de-referenced implicit pointer within the stack value.  This is not the
case for little-endian targets, where the original object starts at offset
zero within the stack value.)

This patch implements the logic indicated in the above diagram and adds an
appropriate test case.  A new function dwarf2_fetch_die_type_sect_off is
added; it is used for retrieving the original object's type, so its size
can be determined.  That type is passed to dwarf2_evaluate_loc_desc_full
via a new parameter.

gdb/ChangeLog:

* dwarf2loc.c (indirect_synthetic_pointer): Get data type of
pointed-to DIE and pass it to dwarf2_evaluate_loc_desc_full.
(dwarf2_evaluate_loc_desc_full): New parameter subobj_type; rename
byte_offset to subobj_byte_offset.  Fix the handling of
DWARF_VALUE_STACK on big-endian targets when coming via an
implicit pointer.
(dwarf2_evaluate_loc_desc): Adjust call to
dwarf2_evaluate_loc_desc_full.
* dwarf2loc.h (dwarf2_fetch_die_type_sect_off): New declaration.
* dwarf2read.c (dwarf2_fetch_die_type_sect_off): New function.

gdb/testsuite/ChangeLog:

* lib/dwarf.exp: Add support for DW_OP_implicit_pointer.
* gdb.dwarf2/nonvar-access.exp: Add test for stack value location
and implicit pointer into such a location.

gdb/ChangeLog
gdb/dwarf2loc.c
gdb/dwarf2loc.h
gdb/dwarf2read.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.dwarf2/nonvar-access.exp
gdb/testsuite/lib/dwarf.exp

index 8bc3aecb6db6c8e9b010bf54e446a2ac9340cf82..d0d0f72c87c68685c3d07d7d377a567db0dda9bd 100644 (file)
@@ -1,3 +1,16 @@
+2017-03-16  Andreas Arnez  <arnez@linux.vnet.ibm.com>
+
+       * dwarf2loc.c (indirect_synthetic_pointer): Get data type of
+       pointed-to DIE and pass it to dwarf2_evaluate_loc_desc_full.
+       (dwarf2_evaluate_loc_desc_full): New parameter subobj_type; rename
+       byte_offset to subobj_byte_offset.  Fix the handling of
+       DWARF_VALUE_STACK on big-endian targets when coming via an
+       implicit pointer.
+       (dwarf2_evaluate_loc_desc): Adjust call to
+       dwarf2_evaluate_loc_desc_full.
+       * dwarf2loc.h (dwarf2_fetch_die_type_sect_off): New declaration.
+       * dwarf2read.c (dwarf2_fetch_die_type_sect_off): New function.
+
 2017-03-16  Yao Qi  <yao.qi@linaro.org>
 
        * arm-tdep.c (thumb_record_misc): Decode CBNZ, CBZ, REV16,
index 4393c1f51d038cc1e312084b85f5a9073d7e65e3..bc7665f61e38ea541b3efe9cdf6d16165cae3133 100644 (file)
@@ -50,7 +50,8 @@ static struct value *dwarf2_evaluate_loc_desc_full (struct type *type,
                                                    const gdb_byte *data,
                                                    size_t size,
                                                    struct dwarf2_per_cu_data *per_cu,
-                                                   LONGEST byte_offset);
+                                                   struct type *subobj_type,
+                                                   LONGEST subobj_byte_offset);
 
 static struct call_site_parameter *dwarf_expr_reg_to_entry_parameter
     (struct frame_info *frame,
@@ -2163,12 +2164,18 @@ indirect_synthetic_pointer (sect_offset die, LONGEST byte_offset,
     = dwarf2_fetch_die_loc_sect_off (die, per_cu,
                                     get_frame_address_in_block_wrapper, frame);
 
+  /* Get type of pointed-to DIE.  */
+  struct type *orig_type = dwarf2_fetch_die_type_sect_off (die, per_cu);
+  if (orig_type == NULL)
+    invalid_synthetic_pointer ();
+
   /* If pointed-to DIE has a DW_AT_location, evaluate it and return the
      resulting value.  Otherwise, it may have a DW_AT_const_value instead,
      or it may've been optimized out.  */
   if (baton.data != NULL)
-    return dwarf2_evaluate_loc_desc_full (TYPE_TARGET_TYPE (type), frame,
-                                         baton.data, baton.size, baton.per_cu,
+    return dwarf2_evaluate_loc_desc_full (orig_type, frame, baton.data,
+                                         baton.size, baton.per_cu,
+                                         TYPE_TARGET_TYPE (type),
                                          byte_offset);
   else
     return fetch_const_value_from_synthetic_pointer (die, byte_offset, per_cu,
@@ -2327,23 +2334,30 @@ static const struct lval_funcs pieced_value_funcs = {
 
 /* Evaluate a location description, starting at DATA and with length
    SIZE, to find the current location of variable of TYPE in the
-   context of FRAME.  BYTE_OFFSET is applied after the contents are
-   computed.  */
+   context of FRAME.  If SUBOBJ_TYPE is non-NULL, return instead the
+   location of the subobject of type SUBOBJ_TYPE at byte offset
+   SUBOBJ_BYTE_OFFSET within the variable of type TYPE.  */
 
 static struct value *
 dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
                               const gdb_byte *data, size_t size,
                               struct dwarf2_per_cu_data *per_cu,
-                              LONGEST byte_offset)
+                              struct type *subobj_type,
+                              LONGEST subobj_byte_offset)
 {
   struct value *retval;
   struct objfile *objfile = dwarf2_per_cu_objfile (per_cu);
 
-  if (byte_offset < 0)
+  if (subobj_type == NULL)
+    {
+      subobj_type = type;
+      subobj_byte_offset = 0;
+    }
+  else if (subobj_byte_offset < 0)
     invalid_synthetic_pointer ();
 
   if (size == 0)
-    return allocate_optimized_out_value (type);
+    return allocate_optimized_out_value (subobj_type);
 
   dwarf_evaluate_loc_desc ctx;
   ctx.frame = frame;
@@ -2366,8 +2380,9 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
       if (ex.error == NOT_AVAILABLE_ERROR)
        {
          free_values.free_to_mark ();
-         retval = allocate_value (type);
-         mark_value_bytes_unavailable (retval, 0, TYPE_LENGTH (type));
+         retval = allocate_value (subobj_type);
+         mark_value_bytes_unavailable (retval, 0,
+                                       TYPE_LENGTH (subobj_type));
          return retval;
        }
       else if (ex.error == NO_ENTRY_VALUE_ERROR)
@@ -2375,7 +2390,7 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
          if (entry_values_debug)
            exception_print (gdb_stdout, ex);
          free_values.free_to_mark ();
-         return allocate_optimized_out_value (type);
+         return allocate_optimized_out_value (subobj_type);
        }
       else
        throw_exception (ex);
@@ -2390,7 +2405,7 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
 
       for (i = 0; i < ctx.num_pieces; ++i)
        bit_size += ctx.pieces[i].size;
-      if (8 * (byte_offset + TYPE_LENGTH (type)) > bit_size)
+      if (8 * (subobj_byte_offset + TYPE_LENGTH (subobj_type)) > bit_size)
        invalid_synthetic_pointer ();
 
       c = allocate_piece_closure (per_cu, ctx.num_pieces, ctx.pieces,
@@ -2398,8 +2413,9 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
       /* We must clean up the value chain after creating the piece
         closure but before allocating the result.  */
       free_values.free_to_mark ();
-      retval = allocate_computed_value (type, &pieced_value_funcs, c);
-      set_value_offset (retval, byte_offset);
+      retval = allocate_computed_value (subobj_type,
+                                       &pieced_value_funcs, c);
+      set_value_offset (retval, subobj_byte_offset);
     }
   else
     {
@@ -2412,10 +2428,10 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
              = longest_to_int (value_as_long (ctx.fetch (0)));
            int gdb_regnum = dwarf_reg_to_regnum_or_error (arch, dwarf_regnum);
 
-           if (byte_offset != 0)
+           if (subobj_byte_offset != 0)
              error (_("cannot use offset on synthetic pointer to register"));
            free_values.free_to_mark ();
-           retval = value_from_register (type, gdb_regnum, frame);
+           retval = value_from_register (subobj_type, gdb_regnum, frame);
            if (value_optimized_out (retval))
              {
                struct value *tmp;
@@ -2426,8 +2442,9 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
                   inspecting a register ($pc, $sp, etc.), return a
                   generic optimized out value instead, so that we show
                   <optimized out> instead of <not saved>.  */
-               tmp = allocate_value (type);
-               value_contents_copy (tmp, 0, retval, 0, TYPE_LENGTH (type));
+               tmp = allocate_value (subobj_type);
+               value_contents_copy (tmp, 0, retval, 0,
+                                    TYPE_LENGTH (subobj_type));
                retval = tmp;
              }
          }
@@ -2447,7 +2464,7 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
               the operation.  Therefore, we do the conversion here
               since the type is readily available.  */
 
-           switch (TYPE_CODE (type))
+           switch (TYPE_CODE (subobj_type))
              {
                case TYPE_CODE_FUNC:
                case TYPE_CODE_METHOD:
@@ -2460,7 +2477,8 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
            address = value_as_address (value_from_pointer (ptr_type, address));
 
            free_values.free_to_mark ();
-           retval = value_at_lazy (type, address + byte_offset);
+           retval = value_at_lazy (subobj_type,
+                                   address + subobj_byte_offset);
            if (in_stack_memory)
              set_value_stack (retval, 1);
          }
@@ -2469,18 +2487,15 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
        case DWARF_VALUE_STACK:
          {
            struct value *value = ctx.fetch (0);
-           gdb_byte *contents;
-           const gdb_byte *val_bytes;
            size_t n = TYPE_LENGTH (value_type (value));
+           size_t len = TYPE_LENGTH (subobj_type);
+           size_t max = TYPE_LENGTH (type);
+           struct gdbarch *objfile_gdbarch = get_objfile_arch (objfile);
            struct cleanup *cleanup;
 
-           if (byte_offset + TYPE_LENGTH (type) > n)
+           if (subobj_byte_offset + len > max)
              invalid_synthetic_pointer ();
 
-           val_bytes = value_contents_all (value);
-           val_bytes += byte_offset;
-           n -= byte_offset;
-
            /* Preserve VALUE because we are going to free values back
               to the mark, but we still need the value contents
               below.  */
@@ -2488,17 +2503,14 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
            free_values.free_to_mark ();
            cleanup = make_cleanup_value_free (value);
 
-           retval = allocate_value (type);
-           contents = value_contents_raw (retval);
-           if (n > TYPE_LENGTH (type))
-             {
-               struct gdbarch *objfile_gdbarch = get_objfile_arch (objfile);
+           retval = allocate_value (subobj_type);
 
-               if (gdbarch_byte_order (objfile_gdbarch) == BFD_ENDIAN_BIG)
-                 val_bytes += n - TYPE_LENGTH (type);
-               n = TYPE_LENGTH (type);
-             }
-           memcpy (contents, val_bytes, n);
+           /* The given offset is relative to the actual object.  */
+           if (gdbarch_byte_order (objfile_gdbarch) == BFD_ENDIAN_BIG)
+             subobj_byte_offset += n - max;
+
+           memcpy (value_contents_raw (retval),
+                   value_contents_all (value) + subobj_byte_offset, len);
 
            do_cleanups (cleanup);
          }
@@ -2507,21 +2519,21 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
        case DWARF_VALUE_LITERAL:
          {
            bfd_byte *contents;
-           size_t n = TYPE_LENGTH (type);
+           size_t n = TYPE_LENGTH (subobj_type);
 
-           if (byte_offset + n > ctx.len)
+           if (subobj_byte_offset + n > ctx.len)
              invalid_synthetic_pointer ();
 
            free_values.free_to_mark ();
-           retval = allocate_value (type);
+           retval = allocate_value (subobj_type);
            contents = value_contents_raw (retval);
-           memcpy (contents, ctx.data + byte_offset, n);
+           memcpy (contents, ctx.data + subobj_byte_offset, n);
          }
          break;
 
        case DWARF_VALUE_OPTIMIZED_OUT:
          free_values.free_to_mark ();
-         retval = allocate_optimized_out_value (type);
+         retval = allocate_optimized_out_value (subobj_type);
          break;
 
          /* DWARF_VALUE_IMPLICIT_POINTER was converted to a pieced
@@ -2547,7 +2559,8 @@ dwarf2_evaluate_loc_desc (struct type *type, struct frame_info *frame,
                          const gdb_byte *data, size_t size,
                          struct dwarf2_per_cu_data *per_cu)
 {
-  return dwarf2_evaluate_loc_desc_full (type, frame, data, size, per_cu, 0);
+  return dwarf2_evaluate_loc_desc_full (type, frame, data, size, per_cu,
+                                       NULL, 0);
 }
 
 /* Evaluates a dwarf expression and stores the result in VAL, expecting
index 1f3e20e49714d0970c04113f854cfb6586f1b53e..9063b6e18d953d6190b515fa002950531d0b0d2e 100644 (file)
@@ -79,6 +79,9 @@ extern const gdb_byte *dwarf2_fetch_constant_bytes (sect_offset,
                                                    struct obstack *,
                                                    LONGEST *);
 
+struct type *dwarf2_fetch_die_type_sect_off (sect_offset,
+                                            struct dwarf2_per_cu_data *);
+
 struct type *dwarf2_get_die_type (cu_offset die_offset,
                                  struct dwarf2_per_cu_data *per_cu);
 
index 40b99d9cca0e34f45482a9febfd7d0413b3d3991..da70884c48496053536109da8754b2c32cd36a05 100644 (file)
@@ -20775,6 +20775,31 @@ dwarf2_fetch_constant_bytes (sect_offset offset,
   return result;
 }
 
+/* Return the type of the die at OFFSET in PER_CU.  Return NULL if no
+   valid type for this die is found.  */
+
+struct type *
+dwarf2_fetch_die_type_sect_off (sect_offset offset,
+                               struct dwarf2_per_cu_data *per_cu)
+{
+  struct dwarf2_cu *cu;
+  struct die_info *die;
+
+  dw2_setup (per_cu->objfile);
+
+  if (per_cu->cu == NULL)
+    load_cu (per_cu);
+  cu = per_cu->cu;
+  if (!cu)
+    return NULL;
+
+  die = follow_die_offset (offset, per_cu->is_dwz, &cu);
+  if (!die)
+    return NULL;
+
+  return die_type (die, cu);
+}
+
 /* Return the type of the DIE at DIE_OFFSET in the CU named by
    PER_CU.  */
 
index 8a3096fe61278b43a1bcb73ef05bde909a6929c2..018104c219903842233c975e378a122c6f5da0fa 100644 (file)
@@ -1,3 +1,9 @@
+2017-03-16  Andreas Arnez  <arnez@linux.vnet.ibm.com>
+
+       * lib/dwarf.exp: Add support for DW_OP_implicit_pointer.
+       * gdb.dwarf2/nonvar-access.exp: Add test for stack value location
+       and implicit pointer into such a location.
+
 2017-03-16  Doug Evans  <dje@google.com>
 
        * gdb.python/py-lazy-string (pointer): Really add new typedef.
index 3cb5c493bcda01e3ca8edc221531ec452e8ba785..99f63cca0f5492f97703d5a0c051e17f2de516f0 100644 (file)
@@ -33,7 +33,7 @@ Dwarf::assemble $asm_file {
        } {
            declare_labels int_type_label char_type_label \
                struct_s_label struct_t_label array_a9_label \
-               char_ptr_label implicit_a_label
+               char_ptr_label implicit_a_label stack_b_label
 
            int_type_label: base_type {
                {name "int"}
@@ -159,7 +159,24 @@ Dwarf::assemble $asm_file {
                    {name implicit_a_ptr}
                    {type :$char_ptr_label}
                    {location {
-                       GNU_implicit_pointer $implicit_a_label 5
+                       implicit_pointer $implicit_a_label 5
+                   } SPECIAL_expr}
+               }
+               # Stack-value location.
+               stack_b_label: DW_TAG_variable {
+                   {name def_stack_b}
+                   {type :$struct_t_label}
+                   {location {
+                       const4u 0x1a2b3c4d
+                       stack_value
+                   } SPECIAL_expr}
+               }
+               # Implicit pointer into stack value.
+               DW_TAG_variable {
+                   {name implicit_b_ptr}
+                   {type :$char_ptr_label}
+                   {location {
+                       implicit_pointer $stack_b_label 1
                    } SPECIAL_expr}
                }
            }
@@ -194,6 +211,13 @@ gdb_test "print/x def_implicit_a" \
 gdb_test "print/x def_implicit_a\[5\]" " = 0x56"
 gdb_test "print/x *(char (*)\[5\]) implicit_a_ptr" \
     " = \\{0x56, 0x67, 0x78, 0x89, 0x9a\\}"
+switch $endian {
+    big {set val "a = 52, b = 2833485"}
+    little {set val "a = 77, b = 857502"}
+}
+gdb_test "print def_stack_b" " = \\{$val\\}"
+switch $endian {big {set val 0x2b} little {set val 0x3c}}
+gdb_test "print/x *implicit_b_ptr" " = $val"
 
 # Byte-aligned fields, pieced together from DWARF stack values.
 gdb_test "print def_s" " = \\{a = 0, b = -1\\}"
index 1ccdc5dc1be8c9bf66d346a6f6acac8f7c57e13e..989a7170618a6d3a971e0afa21acb44ab2c5f3b1 100644 (file)
@@ -946,9 +946,10 @@ namespace eval Dwarf {
                    define_label $l2
                }
 
+               DW_OP_implicit_pointer -
                DW_OP_GNU_implicit_pointer {
                    if {[llength $line] != 3} {
-                       error "usage: DW_OP_GNU_implicit_pointer LABEL OFFSET"
+                       error "usage: $opcode LABEL OFFSET"
                    }
 
                    # Here label is a section offset.
This page took 0.043433 seconds and 4 git commands to generate.