Big-endian targets: Don't ignore offset into DW_OP_implicit_value
authorAndreas Arnez <arnez@linux.vnet.ibm.com>
Wed, 1 Feb 2017 15:59:00 +0000 (16:59 +0100)
committerAndreas Arnez <arnez@linux.vnet.ibm.com>
Wed, 1 Feb 2017 15:59:00 +0000 (16:59 +0100)
When a variable's location is expressed as DW_OP_implicit_value, but the
given value is longer than needed, which bytes should be used?  GDB's
current logic was introduced with a patch from 2011 and uses the "least
significant" bytes:

  https://sourceware.org/ml/gdb-patches/2011-08/msg00123.html

Now consider a sub-value from such a location at a given offset, accessed
through DW_OP_implicit_pointer.  Which bytes should be used for that?  The
patch above *always* uses the last bytes on big-endian targets, ignoring
the offset.

E.g., given the code snippet

  const char foo[] = "Hello, world!";
  const char *a = &foo[0];
  const char *b = &foo[7];

assume that `foo' is described as DW_OP_implicit_value and `a' and `b'
each as DW_OP_implicit_pointer into that value.  Then with current GDB
`*a' and `*b' yield the same result -- the string's zero terminator.

This patch basically reverts the portion of the patch above that deals
with DW_OP_implicit_value.  This fixes the offset handling and also goes
back to dropping the last instead of the first bytes on big-endian targets
if the implicit value is longer than needed.  The latter aspect of the
change probably doesn't matter for actual programs, but simplifies the
logic.

The patch also cleans up the original code a bit and adds appropriate test
cases.

gdb/testsuite/ChangeLog:

* gdb.dwarf2/dw2-op-stack-value.exp: Adjust expected result of
taking a 2-byte value out of a 4-byte DWARF implicit value on
big-endian targets.
* gdb.dwarf2/nonvar-access.exp: Add more comments to existing
logic.  Add test cases for DW_OP_implicit.

gdb/ChangeLog:

* dwarf2loc.c (dwarf2_evaluate_loc_desc_full): For
DWARF_VALUE_LITERAL, no longer ignore the offset on big-endian
targets.  And if the implicit value is longer than needed, extract
the first bytes instead of the "least significant" ones.

gdb/ChangeLog
gdb/dwarf2loc.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.dwarf2/dw2-op-stack-value.exp
gdb/testsuite/gdb.dwarf2/nonvar-access.exp

index b2f7d73..8638eba 100644 (file)
@@ -1,3 +1,10 @@
+2017-02-01  Andreas Arnez  <arnez@linux.vnet.ibm.com>
+
+       * dwarf2loc.c (dwarf2_evaluate_loc_desc_full): For
+       DWARF_VALUE_LITERAL, no longer ignore the offset on big-endian
+       targets.  And if the implicit value is longer than needed, extract
+       the first bytes instead of the "least significant" ones.
+
 2017-02-01  Markus Metzger  <markus.t.metzger@intel.com>
 
        * btrace.c (btrace_enable): Do not call btrace_add_pc for
index 7fca76b..a592b66 100644 (file)
@@ -2442,28 +2442,15 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
        case DWARF_VALUE_LITERAL:
          {
            bfd_byte *contents;
-           const bfd_byte *ldata;
-           size_t n = ctx.len;
+           size_t n = TYPE_LENGTH (type);
 
-           if (byte_offset + TYPE_LENGTH (type) > n)
+           if (byte_offset + n > ctx.len)
              invalid_synthetic_pointer ();
 
            free_values.free_to_mark ();
            retval = allocate_value (type);
            contents = value_contents_raw (retval);
-
-           ldata = ctx.data + byte_offset;
-           n -= byte_offset;
-
-           if (n > TYPE_LENGTH (type))
-             {
-               struct gdbarch *objfile_gdbarch = get_objfile_arch (objfile);
-
-               if (gdbarch_byte_order (objfile_gdbarch) == BFD_ENDIAN_BIG)
-                 ldata += n - TYPE_LENGTH (type);
-               n = TYPE_LENGTH (type);
-             }
-           memcpy (contents, ldata, n);
+           memcpy (contents, ctx.data + byte_offset, n);
          }
          break;
 
index 0972db3..12fb3da 100644 (file)
@@ -1,3 +1,11 @@
+2017-02-01  Andreas Arnez  <arnez@linux.vnet.ibm.com>
+
+       * gdb.dwarf2/dw2-op-stack-value.exp: Adjust expected result of
+       taking a 2-byte value out of a 4-byte DWARF implicit value on
+       big-endian targets.
+       * gdb.dwarf2/nonvar-access.exp: Add more comments to existing
+       logic.  Add test cases for DW_OP_implicit.
+
 2017-02-01  Markus Metzger  <markus.t.metzger@intel.com>
 
        * lib/gdb.exp (gdb_skip_xml_tests): Error if GDB is running.
index c28dcca..808f983 100644 (file)
@@ -45,7 +45,7 @@ gdb_test_multiple $test $test {
     -re ":\[ \t\]*0xaa551234\r\n$gdb_prompt $" {
        # big endian
        pass $test
-       gdb_test "p/x implicit4to2" " = 0x3344"
+       gdb_test "p/x implicit4to2" " = 0x1122"
        gdb_test "p/x implicit4to4" " = 0x11223344"
     }
     -re ":\[ \t\]*0x\[0-9a-f\]{8}\r\n$gdb_prompt $" {
index 506ff9e..3cb5c49 100644 (file)
@@ -31,14 +31,23 @@ Dwarf::assemble $asm_file {
        compile_unit {
            {DW_AT_name main.c}
        } {
-           declare_labels int_type_label short_type_label
-           declare_labels struct_s_label struct_t_label
+           declare_labels int_type_label char_type_label \
+               struct_s_label struct_t_label array_a9_label \
+               char_ptr_label implicit_a_label
 
            int_type_label: base_type {
                {name "int"}
                {encoding @DW_ATE_signed}
                {byte_size 4 DW_FORM_sdata}
            }
+           char_type_label: base_type {
+               {name "char"}
+               {encoding @DW_ATE_unsigned}
+               {byte_size 1 DW_FORM_sdata}
+           }
+           char_ptr_label: pointer_type {
+               {type :$char_type_label}
+           }
 
            struct_s_label: structure_type {
                {name s}
@@ -76,20 +85,32 @@ Dwarf::assemble $asm_file {
                }
            }
 
+           array_a9_label: array_type {
+               {type :$char_type_label}
+           } {
+               subrange_type {
+                   {type :$int_type_label}
+                   {upper_bound 8 DW_FORM_udata}
+               }
+           }
+
            DW_TAG_subprogram {
                {name main}
                {DW_AT_external 1 flag}
                {low_pc [gdb_target_symbol main] DW_FORM_addr}
                {high_pc [gdb_target_symbol main]+0x10000 DW_FORM_addr}
            } {
+               # Simple variable without location.
                DW_TAG_variable {
                    {name undef_int}
                    {type :$int_type_label}
                }
+               # Struct variable without location.
                DW_TAG_variable {
                    {name undef_s}
                    {type :$struct_s_label}
                }
+               # Composite location: byte-aligned pieces.
                DW_TAG_variable {
                    {name def_s}
                    {type :$struct_s_label}
@@ -102,6 +123,7 @@ Dwarf::assemble $asm_file {
                        bit_piece 24 0
                    } SPECIAL_expr}
                }
+               # Composite location: non-byte-aligned pieces.
                DW_TAG_variable {
                    {name def_t}
                    {type :$struct_t_label}
@@ -114,6 +136,32 @@ Dwarf::assemble $asm_file {
                        bit_piece 23 0
                    } SPECIAL_expr}
                }
+               # Implicit location: immediate value.
+               DW_TAG_variable {
+                   {name def_implicit_s}
+                   {type :$struct_s_label}
+                   {location {
+                       implicit_value 0x12 0x34 0x56 0x78
+                   } SPECIAL_expr}
+               }
+               # Implicit location: immediate value for whole array, with
+               # excess bytes.
+               implicit_a_label: DW_TAG_variable {
+                   {name def_implicit_a}
+                   {type :$array_a9_label}
+                   {location {
+                       implicit_value 0x1 0x12 0x23 0x34 0x45 \
+                           0x56 0x67 0x78 0x89 0x9a 0xab
+                   } SPECIAL_expr}
+               }
+               # Implicit pointer into immediate value.
+               DW_TAG_variable {
+                   {name implicit_a_ptr}
+                   {type :$char_ptr_label}
+                   {location {
+                       GNU_implicit_pointer $implicit_a_label 5
+                   } SPECIAL_expr}
+               }
            }
        }
     }
@@ -128,7 +176,33 @@ if ![runto_main] {
     return -1
 }
 
+# Determine endianness.
+set endian "little"
+gdb_test_multiple "show endian" "determine endianness" {
+    -re ".* (big|little) endian.*$gdb_prompt $" {
+       set endian $expect_out(1,string)
+       pass "endianness: $endian"
+    }
+}
+
+# Byte-aligned objects with simple location descriptions.
+switch $endian { big {set val 0x345678} little {set val 0x785634} }
+gdb_test "print/x def_implicit_s" " = \\{a = 0x12, b = $val\\}"
+gdb_test "print/x def_implicit_s.b" " = $val"
+gdb_test "print/x def_implicit_a" \
+    " = \\{0x1, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89\\}"
+gdb_test "print/x def_implicit_a\[5\]" " = 0x56"
+gdb_test "print/x *(char (*)\[5\]) implicit_a_ptr" \
+    " = \\{0x56, 0x67, 0x78, 0x89, 0x9a\\}"
+
+# Byte-aligned fields, pieced together from DWARF stack values.
 gdb_test "print def_s" " = \\{a = 0, b = -1\\}"
+
+# Non-byte-aligned fields, pieced together from DWARF stack values.
 gdb_test "print def_t" " = \\{a = 0, b = -1\\}"
+
+# Simple variable without location.
 gdb_test "print undef_int" " = <optimized out>"
+
+# Member of a structure without location.
 gdb_test "print undef_s.a" " = <optimized out>"