]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Add DWARF operations for byte and bit offset
authorZoran Zaric <Zoran.Zaric@amd.com>
Mon, 7 Dec 2020 19:00:29 +0000 (19:00 +0000)
committerSimon Marchi <simon.marchi@polymtl.ca>
Tue, 8 Dec 2020 16:16:21 +0000 (11:16 -0500)
Currently in DWARF, there are only two ways to specify an offset for a
location description.

For a memory location description, the location description can be
first converted to a DWARF value, after which an arithmetic operation
can be applied to it. This however, only works while there are no
address spaces involved, that are not mapped to a general address space
(CORE_ADDR). Another limitation is that there is no way to specify a
bit offset to that location description.

Second way of specifying an offset to a location description is more
universal and involves wrapping that location description in a
composite piece, where piece itself has a bit/byte offset defined. The
problem with this approach is that both DW_OP_piece and DW_OP_bit_piece
define an offset as a DWARF operation operand, which means that an
offset needs to be a constant value encoded into the DWARF expression.

By adding three new operations (DW_OP_LLVM_offset,
DW_OP_LLVM_offset_constu and DW_OP_LLVM_bit_offset) these restrictions
are now lifted.

Detailed descriptions of these new operations can be found here:

https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html

The same document also explores an idea of extending the
DW_OP_push_object_address operation to allow pushing any location
description on the DWARF stack. This together with the new bit/byte
offset operations, generalizes DWARF to work with bit fields and could
replace the odd passed-in buffer mechanics in a more elegant way.

There seem to be a difference in views on what the big endian machine
register byte ordering should be. On one hand, some would expect for
a register to behave in the same way as memory, but on another, there
seems to be an existing implementation for (IBM big endian based
machines) which seems to be viewing registers differently, depending
if the register location description is part of a composite piece or
not. More on this topic can be found here:

https://sourceware.org/legacy-ml/gdb-patches/2017-04/msg00177.html

Unfortunately, the gdb current implementation favors the second option,
which feels like a target specific implementation.

Because of this, I've decided to not favor a specific implementation
in the added test for new DWARF operations (dw2-llvm-offset.exp), so
the test is restricted to only run on little endian platforms.

gdb/ChangeLog:

* ada-lang.c (coerce_unspec_val_to_type): Add source bit offset
argument to the value_contents_copy_raw call.
* compile/compile-loc2c.c (compute_stack_depth_worker): Add new
DWARF operations support.
* dwarf2/expr.c (rw_closure_value): Add bit offset support.
(dwarf_expr_context::dwarf_entry_to_gdb_value): Add source bit
offset argument to the value_contents_copy_raw call.
(dwarf_expr_context::execute_stack_op): Add new DWARF
operations support.
* dwarf2/loc.c (dwarf2_get_symbol_read_needs): Add new DWARF
  operations support.
* findvar.c (read_frame_register_value): Add source bit offset
argument to the value_contents_copy_raw call.
* valops.c (read_value_memory): Add bit offset support.
(value_assign): Add bit offset support.
(value_repeat): Add bit offset support.
(value_array): Add source bit offset argument to the
value_contents_copy_raw call.
(value_slice): Add source bit offset argument to the
value_contents_copy_raw call.
* value.c (value_contents_copy_raw): Add source bit offset
support.
(value_contents_copy): Add source bit offset argument to
value_contents_copy_raw call.
(value_primitive_field): Add source bit offset argument to the
value_contents_copy_raw call.
(value_from_component): Add source bit offset argument to the
value_contents_copy_raw call.
(value_fetch_lazy_memory): Add bit offset argument to the
read_value_memory call.
(value_fetch_lazy_register): Add source bit offset argument to
the value_contents_copy call.
* value.h (value_contents_copy): Add source bit offset
argument.

include/ChangeLog:

* dwarf2.def (DW_OP_DUP): New DWARF operations enumeration.

gdb/testsuite/ChangeLog:

* lib/dwarf.exp: Add support for new DW_OP_LLVM_offset_constu
DWARF operation.
* gdb.dwarf2/dw2-llvm-offset.exp: New test.

Change-Id: I2a6928c2a647debe50c59756be2197d60b6bc2df

12 files changed:
gdb/ada-lang.c
gdb/compile/compile-loc2c.c
gdb/dwarf2/expr.c
gdb/dwarf2/loc.c
gdb/f-lang.c
gdb/findvar.c
gdb/testsuite/gdb.dwarf2/dw2-llvm-offset.exp [new file with mode: 0644]
gdb/testsuite/lib/dwarf.exp
gdb/valops.c
gdb/value.c
gdb/value.h
include/dwarf2.def

index 8a1d9df5411fe5be54876f7016aabd108472ebc6..2f0a517d642d2713a8820088e656bb63415c48d6 100644 (file)
@@ -606,7 +606,7 @@ coerce_unspec_val_to_type (struct value *val, struct type *type)
       else
        {
          result = allocate_value (type);
-         value_contents_copy_raw (result, 0, val, 0, TYPE_LENGTH (type));
+         value_contents_copy_raw (result, 0, val, 0, 0, TYPE_LENGTH (type));
        }
       set_value_component_location (result, val);
       set_value_bitsize (result, value_bitsize (val));
index 2fd1810759cc56946295539f194d539588733146..037b6433bc8bcc15a244d76ca90779c84dabfa0a 100644 (file)
@@ -356,6 +356,12 @@ compute_stack_depth_worker (int start, int *need_tempvar,
          (*info)[offset].label = 1;
          break;
 
+       case DW_OP_LLVM_offset:
+       case DW_OP_LLVM_bit_offset:
+         --stack_depth;
+         break;
+
+       case DW_OP_LLVM_offset_constu:
        case DW_OP_nop:
          break;
 
index 1f07502059e023ca7e5b9b360f512506ab816003..dfe34f877a7afa52456cf1de4a3d786eed5fd51d 100644 (file)
@@ -1442,6 +1442,9 @@ rw_closure_value (struct value *v, struct value *from)
   unsigned int i;
   unsigned int pieces_num = composite_entry->get_pieces_num ();
 
+  bits_to_skip += HOST_CHAR_BIT * composite_entry->get_offset ()
+                 + composite_entry->get_bit_suboffset ();
+
   for (i = 0; i < pieces_num; i++)
     {
       ULONGEST bit_size = composite_entry->get_bit_size_at (i);
@@ -2363,6 +2366,7 @@ dwarf_expr_context::dwarf_entry_to_gdb_value (dwarf_entry *entry,
       address = value_as_address (value_from_pointer (ptr_type, address));
       retval = value_at_lazy (subobj_type, address + subobj_offset);
       set_value_stack (retval, memory_entry->in_stack ());
+      set_value_bitpos (retval, memory_entry->get_bit_suboffset ());
     }
   else if (auto register_entry = dynamic_cast<dwarf_register *> (entry))
     {
@@ -2373,6 +2377,18 @@ dwarf_expr_context::dwarf_entry_to_gdb_value (dwarf_entry *entry,
       retval = gdbarch_value_from_register (gdbarch, type,
                                            gdb_regnum, get_frame_id (frame));
 
+      LONGEST reg_offset = register_entry->get_offset ();
+      LONGEST retval_offset = value_offset (retval);
+
+      if (type_byte_order (type) == BFD_ENDIAN_BIG
+         && (TYPE_LENGTH (type) + reg_offset) < retval_offset)
+       /* Big-endian, and we want less than full size.  */
+       set_value_offset (retval, retval_offset - reg_offset);
+      else
+       set_value_offset (retval, retval_offset + reg_offset);
+
+      set_value_bitpos (retval, register_entry->get_bit_suboffset ());
+
       /* Get the data.  */
       read_frame_register_value (retval, frame);
 
@@ -2384,7 +2400,8 @@ dwarf_expr_context::dwarf_entry_to_gdb_value (dwarf_entry *entry,
             return a generic optimized out value instead, so that we show
             <optimized out> instead of <not saved>.  */
          struct value *temp = allocate_value (subobj_type);
-         value_contents_copy (temp, 0, retval, 0, TYPE_LENGTH (subobj_type));
+         value_contents_copy (temp, 0, retval, 0, 0,
+                              TYPE_LENGTH (subobj_type));
          retval = temp;
        }
     }
@@ -3672,6 +3689,55 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
            = entry_factory->create_memory (this->addr_info->addr);
          break;
 
+       case DW_OP_LLVM_offset:
+         {
+           dwarf_value *offset_value
+             = entry_factory->entry_to_value (fetch (0), address_type);
+           pop ();
+
+           dwarf_require_integral (offset_value->get_type ());
+
+           dwarf_location *location
+             = entry_factory->entry_to_location (fetch (0));
+           pop ();
+
+           location->add_bit_offset
+             (offset_value->to_long () * HOST_CHAR_BIT);
+           result_entry = location;
+         }
+         break;
+
+       case DW_OP_LLVM_offset_constu:
+         {
+           op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
+           result = uoffset;
+
+           dwarf_location *location
+             = entry_factory->entry_to_location (fetch (0));
+           pop ();
+
+           location->add_bit_offset (result * HOST_CHAR_BIT);
+           result_entry = location;
+         }
+         break;
+
+       case DW_OP_LLVM_bit_offset:
+         {
+           dwarf_value *offset_value
+             = entry_factory->entry_to_value (fetch (0), address_type);
+           pop ();
+
+           dwarf_require_integral (offset_value->get_type ());
+
+           dwarf_location *location
+             = entry_factory->entry_to_location (fetch (0));
+           pop ();
+
+           location->add_bit_offset (offset_value->to_long ());
+           result_entry = location;
+         }
+         break;
+
        default:
          error (_("Unhandled dwarf expression opcode 0x%x"), op);
        }
index d2aa1eddc974a94ac4f6072532e01199a40b3c70..fe2174ab14a70a1c481cd3317ef83cd19f4992e8 100644 (file)
@@ -1829,6 +1829,8 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
        case DW_OP_nop:
        case DW_OP_GNU_uninit:
        case DW_OP_push_object_address:
+       case DW_OP_LLVM_offset:
+       case DW_OP_LLVM_bit_offset:
          break;
 
        case DW_OP_form_tls_address:
@@ -1846,6 +1848,7 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
        case DW_OP_constu:
        case DW_OP_plus_uconst:
        case DW_OP_piece:
+       case DW_OP_LLVM_offset_constu:
          op_ptr = safe_read_uleb128 (op_ptr, expr_end, &uoffset);
          break;
 
index 6771758bacb2765a53a52a4322b723a7a31eedaf..51215156651877cc7fe5207beda827c7fcd5ad08 100644 (file)
@@ -196,7 +196,7 @@ protected:
      available offset.  */
   void copy_element_to_dest (struct value *elt)
   {
-    value_contents_copy (m_dest, m_dest_offset, elt, 0,
+    value_contents_copy (m_dest, m_dest_offset, elt, 0, 0,
                         TYPE_LENGTH (value_type (elt)));
     m_dest_offset += TYPE_LENGTH (value_type (elt));
   }
index 95d0ff03a276dff47bd174eef17122a5fd9a490f..9fefe1e822c87d4885415ed2aa080c121ab506e5 100644 (file)
@@ -871,6 +871,7 @@ read_frame_register_value (struct value *value, struct frame_info *frame)
   struct gdbarch *gdbarch = get_frame_arch (frame);
   LONGEST offset = 0;
   LONGEST reg_offset = value_offset (value);
+  LONGEST bit_offset = value_bitpos (value);
   int regnum = VALUE_REGNUM (value);
   int len = type_length_units (check_typedef (value_type (value)));
 
@@ -894,7 +895,8 @@ read_frame_register_value (struct value *value, struct frame_info *frame)
       if (reg_len > len)
        reg_len = len;
 
-      value_contents_copy (value, offset, regval, reg_offset, reg_len);
+      value_contents_copy (value, offset, regval, reg_offset,
+                          bit_offset, reg_len);
 
       offset += reg_len;
       len -= reg_len;
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-llvm-offset.exp b/gdb/testsuite/gdb.dwarf2/dw2-llvm-offset.exp
new file mode 100644 (file)
index 0000000..afbd123
--- /dev/null
@@ -0,0 +1,328 @@
+# Copyright 2017-2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test DWARF operation that allow adding byte and bit offset to any
+# location description.
+#
+# In particular, the test uses memory and register location
+# descriptions (both as standalone and parts of the composite
+# location), and applies different byte and bit offsets to them.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+# Choose suitable integer registers for the test.
+
+set dwarf_regnum 0
+
+if { [is_aarch64_target] } {
+    set regname x0
+} elseif { [is_aarch32_target]
+          || [istarget "s390*-*-*" ]
+          || [istarget "powerpc*-*-*"]
+          || [istarget "rs6000*-*-aix*"] } {
+    set regname r0
+} elseif { [is_x86_like_target] } {
+    set regname eax
+} elseif { [is_amd64_regs_target] } {
+    set regname rax
+} else {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+standard_testfile var-access.c ${gdb_test_file_name}-dw.S
+
+# Make some DWARF for the test.
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    global dwarf_regnum regname srcdir subdir srcfile
+    set buf_var [gdb_target_symbol buf]
+
+    set main_result [function_range main ${srcdir}/${subdir}/${srcfile}]
+    set main_start [lindex $main_result 0]
+    set main_length [lindex $main_result 1]
+
+    cu {} {
+       DW_TAG_compile_unit {
+           {DW_AT_name var-access.c}
+           {DW_AT_comp_dir /tmp}
+       } {
+           declare_labels char_type_label int_type_label
+           declare_labels array_size_4_type_label array_size_8_type_label
+
+           # define char type.
+           char_type_label: DW_TAG_base_type {
+               {DW_AT_name "char"}
+               {DW_AT_encoding @DW_ATE_signed}
+               {DW_AT_byte_size 1 DW_FORM_sdata}
+           }
+
+           # define int type.
+           int_type_label: DW_TAG_base_type {
+               {DW_AT_name "int"}
+               {DW_AT_encoding @DW_ATE_signed}
+               {DW_AT_byte_size 4 DW_FORM_sdata}
+           }
+
+           # define 4 byte size array type.
+           array_size_4_type_label: DW_TAG_array_type {
+               {DW_AT_type :$char_type_label}
+           } {
+               DW_TAG_subrange_type {
+                   {DW_AT_type :$int_type_label}
+                   {DW_AT_upper_bound 3 DW_FORM_udata}
+               }
+           }
+
+           # define 8 byte size array type.
+           array_size_8_type_label: DW_TAG_array_type {
+               {DW_AT_type :$char_type_label}
+           } {
+               DW_TAG_subrange_type {
+                   {DW_AT_type :$int_type_label}
+                   {DW_AT_upper_bound 7 DW_FORM_udata}
+               }
+           }
+
+           DW_TAG_subprogram {
+               {DW_AT_name main}
+               {DW_AT_low_pc $main_start addr}
+               {DW_AT_high_pc $main_length data8}
+           } {
+               # define original buf variable.
+               DW_TAG_variable {
+                   {DW_AT_name buf}
+                   {DW_AT_type :$array_size_4_type_label}
+                   {DW_AT_location {
+                       DW_OP_addr $buf_var
+                   } SPECIAL_expr}
+               }
+
+               # defined a variable located in
+               # a third byte of the buf variable.
+               DW_TAG_variable {
+                   {DW_AT_name buf_byte_3}
+                   {DW_AT_type :$char_type_label}
+                   {DW_AT_location {
+                       DW_OP_addr $buf_var
+                       DW_OP_LLVM_offset_constu 2
+                   } SPECIAL_expr}
+                   {external 1 flag}
+               }
+
+               # defined a variable located in a second byte
+               # of the buf variable with a bit offset of one.
+               DW_TAG_variable {
+                   {DW_AT_name buf_byte_2_bit_1}
+                   {DW_AT_type :$char_type_label}
+                   {DW_AT_location {
+                       DW_OP_addr $buf_var
+                       DW_OP_lit9
+                       DW_OP_LLVM_bit_offset
+                   } SPECIAL_expr}
+                   {external 1 flag}
+               }
+
+               # defined a variable located in a
+               # third byte of the REGNAME register.
+               DW_TAG_variable {
+                   {DW_AT_name reg_byte_3}
+                   {DW_AT_type :$char_type_label}
+                   {DW_AT_location {
+                       DW_OP_regx $dwarf_regnum
+                       DW_OP_lit2
+                       DW_OP_LLVM_offset
+                   } SPECIAL_expr}
+                   {external 1 flag}
+               }
+
+               # defined a variable located in a second byte of
+               # the REGNAME register with a bit offset of one.
+               DW_TAG_variable {
+                   {DW_AT_name reg_byte_2_bit_1}
+                   {DW_AT_type :$char_type_label}
+                   {DW_AT_location {
+                       DW_OP_regx $dwarf_regnum
+                       DW_OP_lit1
+                       DW_OP_LLVM_offset
+                       DW_OP_lit1
+                       DW_OP_LLVM_bit_offset
+                   } SPECIAL_expr}
+                   {external 1 flag}
+               }
+
+               # Define an array variable spread in different
+               # pieces of buf variable and REGNAME register.
+               DW_TAG_variable {
+                   {DW_AT_name mix_array}
+                   {DW_AT_type :$array_size_8_type_label}
+                   {DW_AT_location {
+
+                       # a byte piece located in a
+                       # fourth byte of the buf variable.
+                       DW_OP_addr $buf_var
+                       DW_OP_LLVM_offset_constu 3
+                       DW_OP_piece 0x1
+
+                       # a byte piece located in a
+                       # third byte of the buf variable.
+                       DW_OP_addr $buf_var
+                       DW_OP_lit2
+                       DW_OP_LLVM_offset
+                       DW_OP_piece 0x1
+
+                       # a byte piece located in a second byte of
+                       # the buf variable with a bit offset of one.
+                       DW_OP_addr $buf_var
+                       DW_OP_lit1
+                       DW_OP_LLVM_offset
+                       DW_OP_lit1
+                       DW_OP_LLVM_bit_offset
+                       DW_OP_piece 0x1
+
+                       # a four bit piece located in a first byte
+                       # of the buf variable with a bit offset of one.
+                       DW_OP_addr $buf_var
+                       DW_OP_LLVM_offset_constu 0
+                       DW_OP_bit_piece 0x4 0x1
+
+                       # a four bit piece located in a first byte of
+                       # the buf variable with a bit offset of eight.
+                       DW_OP_addr $buf_var
+                       DW_OP_lit1
+                       DW_OP_LLVM_bit_offset
+                       DW_OP_LLVM_offset_constu 0
+                       DW_OP_bit_piece 0x4 0x7
+
+                       # a byte piece located in a fourth
+                       # byte of the REGNAME register.
+                       DW_OP_regx $dwarf_regnum
+                       DW_OP_LLVM_offset_constu 3
+                       DW_OP_piece 0x1
+
+                       # a byte piece located in a third
+                       # byte of the REGNAME register.
+                       DW_OP_regx $dwarf_regnum
+                       DW_OP_lit2
+                       DW_OP_LLVM_offset
+                       DW_OP_piece 0x1
+
+                       # a byte piece located in a second byte of the
+                       # REGNAME register with a bit offset of one.
+                       DW_OP_regx $dwarf_regnum
+                       DW_OP_lit1
+                       DW_OP_LLVM_offset
+                       DW_OP_lit1
+                       DW_OP_LLVM_bit_offset
+                       DW_OP_piece 0x1
+
+                       # a four bit piece located in a first byte of
+                       # the REGNAME register with a bit offset of one.
+                       DW_OP_regx $dwarf_regnum
+                       DW_OP_LLVM_offset_constu 0
+                       DW_OP_bit_piece 0x4 0x1
+
+                       # a four bit piece located in a first byte of the
+                       # REGNAME register with a bit offset of eight.
+                       DW_OP_regx $dwarf_regnum
+                       DW_OP_lit1
+                       DW_OP_LLVM_bit_offset
+                       DW_OP_LLVM_offset_constu 0
+                       DW_OP_bit_piece 0x4 0x7
+
+                   } SPECIAL_expr}
+                   {external 1 flag}
+               }
+           }
+       }
+    }
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} \
+     [list $srcfile $asm_file] {nodebug}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+# Determine byte order.
+set endian [get_endianness]
+
+if { $endian != "little" } then {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+gdb_test_no_output "set var \$$regname = 0x04030201" "init reg"
+gdb_test_no_output "set var *\(\(unsigned int *\) buf\) = 0x04030201" \
+                  "init buf"
+
+gdb_test "print/x buf_byte_3" " = 0x3" "buf_byte_3 == 0x3"
+gdb_test "print/x buf_byte_2_bit_1" " = 0x81" \
+        "print buf_byte_2_bit_1"
+gdb_test "print/x reg_byte_3" " = 0x3" "reg_byte_3 == 0x3"
+gdb_test "print/x reg_byte_2_bit_1" " = 0x81" \
+        "print reg_byte_2_bit_1"
+
+gdb_test_no_output "set var buf_byte_3 = 0x4" "init buf_byte_3 to 0x4"
+gdb_test "print/x buf_byte_3" " = 0x4" "buf_byte_3 == 0x4"
+
+gdb_test_no_output "set var buf_byte_2_bit_1 = 0x4" \
+                  "init buf_byte_2_bit_1 to 0x4"
+gdb_test "print/x buf_byte_2_bit_1" " = 0x4" "buf_byte_2_bit_1 == 0x4"
+
+gdb_test "print/x buf" " = \\{0x1, 0x8, 0x4, 0x4\\}" "buf print"
+
+gdb_test_no_output "set var reg_byte_3 = 0x4" "init reg_byte_3 to 0x4"
+gdb_test "print/x reg_byte_3" " = 0x4" "reg_byte_3 == 0x4"
+
+gdb_test_no_output "set var reg_byte_2_bit_1 = 0x4" \
+                  "init reg_byte_2_bit_1 to 0x4"
+gdb_test "print/x reg_byte_2_bit_1" " = 0x4" "reg_byte_2_bit_1 == 0x4"
+
+gdb_test "print/x \$$regname" " = 0x4040801" "\$$regname print"
+
+gdb_test_no_output "set var \$$regname = 0x04030201" "reset reg"
+gdb_test_no_output "set var *\(\(unsigned int *\) buf\) = 0x04030201" \
+                  "reset buf"
+
+gdb_test "print/x mix_array" \
+        " = \\{0x4, 0x3, 0x81, 0x20, 0x4, 0x3, 0x81, 0x20\\}" \
+        "mix_array print"
+
+gdb_test_no_output "set var mix_array\[1\] = 0x4" \
+                  "set mix_array second byte"
+gdb_test_no_output "set var mix_array\[2\] = 0x4" \
+                  "set mix_array third byte"
+gdb_test_no_output "set var mix_array\[5\] = 0x4" \
+                  "set mix_array fifth byte"
+gdb_test_no_output "set var mix_array\[6\] = 0x4" \
+                  "set mix_array sixth byte"
+
+gdb_test "print/x mix_array" \
+        " = \\{0x4, 0x4, 0x4, 0x80, 0x4, 0x4, 0x4, 0x80\\}" \
+        "mix_array second print"
+
+gdb_test "print/x buf" " = \\{0x1, 0x8, 0x4, 0x4\\}" "buf second print"
+
+gdb_test "print/x \$$regname" " = 0x4040801" "\$$regname second print"
index 223e0b15becb522978cf313b152f0c85da42a981..b29e8917c0ca6efd2116f68b2600120a3e5aa857 100644 (file)
@@ -1022,6 +1022,10 @@ namespace eval Dwarf {
                    _op .sleb128 [lindex $line 1]
                }
 
+               DW_OP_LLVM_offset_constu {
+                   _op .uleb128 [lindex $line 1]
+               }
+
                default {
                    if {[llength $line] > 1} {
                        error "Unimplemented: operands in location for $opcode"
index 4d0e002b20d618c0e146d54c70e570aa942c6447..057c5968f2de171afc053810dae64199e0925575 100644 (file)
@@ -1018,20 +1018,31 @@ read_value_memory (struct value *val, LONGEST bit_offset,
   ULONGEST xfered_total = 0;
   struct gdbarch *arch = get_value_arch (val);
   int unit_size = gdbarch_addressable_memory_unit_size (arch);
+  bool big_endian = type_byte_order (value_type (val)) == BFD_ENDIAN_BIG;
   enum target_object object;
+  size_t extended_length
+    = length + (bit_offset + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+  gdb_byte *buffer_ptr = buffer;
+  gdb::byte_vector temp_buffer;
+
+  if (bit_offset)
+    {
+      temp_buffer.resize (extended_length);
+      buffer_ptr = temp_buffer.data ();
+    }
 
   object = stack ? TARGET_OBJECT_STACK_MEMORY : TARGET_OBJECT_MEMORY;
 
-  while (xfered_total < length)
+  while (xfered_total < extended_length)
     {
       enum target_xfer_status status;
       ULONGEST xfered_partial;
 
       status = target_xfer_partial (current_top_target (),
                                    object, NULL,
-                                   buffer + xfered_total * unit_size, NULL,
+                                   buffer_ptr + xfered_total * unit_size, NULL,
                                    memaddr + xfered_total,
-                                   length - xfered_total,
+                                   extended_length - xfered_total,
                                    &xfered_partial);
 
       if (status == TARGET_XFER_OK)
@@ -1048,6 +1059,10 @@ read_value_memory (struct value *val, LONGEST bit_offset,
       xfered_total += xfered_partial;
       QUIT;
     }
+
+  if (bit_offset)
+    copy_bitwise (buffer, 0, temp_buffer.data (),
+                 bit_offset, length * HOST_CHAR_BIT, big_endian);
 }
 
 /* Store the contents of FROMVAL into the location of TOVAL.
@@ -1119,7 +1134,7 @@ value_assign (struct value *toval, struct value *fromval)
        const gdb_byte *dest_buffer;
        CORE_ADDR changed_addr;
        int changed_len;
-       gdb_byte buffer[sizeof (LONGEST)];
+       gdb::byte_vector buffer;
 
        if (value_bitsize (toval))
          {
@@ -1145,10 +1160,25 @@ value_assign (struct value *toval, struct value *fromval)
                       "don't fit in a %d bit word."),
                     (int) sizeof (LONGEST) * HOST_CHAR_BIT);
 
-           read_memory (changed_addr, buffer, changed_len);
-           modify_field (type, buffer, value_as_long (fromval),
+           buffer.resize (changed_len);
+
+           read_memory (changed_addr, buffer.data (), changed_len);
+           modify_field (type, buffer.data (), value_as_long (fromval),
                          value_bitpos (toval), value_bitsize (toval));
-           dest_buffer = buffer;
+           dest_buffer = buffer.data ();
+         }
+       else if (value_bitpos (toval))
+         {
+           int bitpos = value_bitpos (toval);
+           bool big_endian = type_byte_order (type) == BFD_ENDIAN_BIG;
+           changed_addr = value_address (toval);
+           changed_len = TYPE_LENGTH (type)
+                         + (bitpos + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+           buffer.resize (changed_len);
+           read_memory (changed_addr, buffer.data (), changed_len);
+           copy_bitwise (buffer.data (), bitpos, value_contents (fromval),
+                         0, TYPE_LENGTH (type) * HOST_CHAR_BIT, big_endian);
+           dest_buffer = buffer.data();
          }
        else
          {
@@ -1163,10 +1193,6 @@ value_assign (struct value *toval, struct value *fromval)
 
     case lval_register:
       {
-       struct frame_info *frame;
-       struct gdbarch *gdbarch;
-       int value_reg;
-
        /* Figure out which frame this is in currently.
        
           We use VALUE_FRAME_ID for obtaining the value's frame id instead of
@@ -1174,35 +1200,45 @@ value_assign (struct value *toval, struct value *fromval)
           put_frame_register_bytes() below.  That function will (eventually)
           perform the necessary unwind operation by first obtaining the next
           frame.  */
-       frame = frame_find_by_id (VALUE_FRAME_ID (toval));
-
-       value_reg = VALUE_REGNUM (toval);
+       struct frame_info *frame = frame_find_by_id (VALUE_FRAME_ID (toval));
 
        if (!frame)
          error (_("Value being assigned to is no longer active."));
 
-       gdbarch = get_frame_arch (frame);
+       struct gdbarch *gdbarch = get_frame_arch (frame);
+       int value_reg = VALUE_REGNUM (toval);
+       LONGEST bitpos = value_bitpos (toval);
+       LONGEST bitsize = value_bitsize (toval);
+       LONGEST offset = value_offset (toval);
 
-       if (value_bitsize (toval))
+       if (bitpos || bitsize)
          {
-           struct value *parent = value_parent (toval);
-           LONGEST offset = value_offset (parent) + value_offset (toval);
            int changed_len;
-           gdb_byte buffer[sizeof (LONGEST)];
-           int optim, unavail;
+           bool big_endian = type_byte_order (type) == BFD_ENDIAN_BIG;
 
-           changed_len = (value_bitpos (toval)
-                          + value_bitsize (toval)
-                          + HOST_CHAR_BIT - 1)
-                         / HOST_CHAR_BIT;
+           if (bitsize)
+             {
+               changed_len = (bitpos + bitsize + HOST_CHAR_BIT - 1)
+                             / HOST_CHAR_BIT;
 
-           if (changed_len > (int) sizeof (LONGEST))
-             error (_("Can't handle bitfields which "
-                      "don't fit in a %d bit word."),
-                    (int) sizeof (LONGEST) * HOST_CHAR_BIT);
+               if (changed_len > (int) sizeof (LONGEST))
+                 error (_("Can't handle bitfields which "
+                          "don't fit in a %d bit word."),
+                          (int) sizeof (LONGEST) * HOST_CHAR_BIT);
+             }
+           else
+             {
+               changed_len = TYPE_LENGTH (type)
+                             + (bitpos + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+
+               bitsize = TYPE_LENGTH (type) * HOST_CHAR_BIT;
+             }
+
+           gdb::byte_vector buffer (changed_len);
+           int optim, unavail;
 
            if (!get_frame_register_bytes (frame, value_reg, offset,
-                                          changed_len, buffer,
+                                          changed_len, buffer.data (),
                                           &optim, &unavail))
              {
                if (optim)
@@ -1213,11 +1249,11 @@ value_assign (struct value *toval, struct value *fromval)
                               _("value is not available"));
              }
 
-           modify_field (type, buffer, value_as_long (fromval),
-                         value_bitpos (toval), value_bitsize (toval));
+           copy_bitwise (buffer.data (), bitpos, value_contents (fromval),
+                         0, bitsize, big_endian);
 
            put_frame_register_bytes (frame, value_reg, offset,
-                                     changed_len, buffer);
+                                     changed_len, buffer.data ());
          }
        else
          {
@@ -1234,8 +1270,7 @@ value_assign (struct value *toval, struct value *fromval)
            else
              {
                put_frame_register_bytes (frame, value_reg,
-                                         value_offset (toval),
-                                         TYPE_LENGTH (type),
+                                         offset, TYPE_LENGTH (type),
                                          value_contents (fromval));
              }
          }
@@ -1337,21 +1372,22 @@ value_assign (struct value *toval, struct value *fromval)
 struct value *
 value_repeat (struct value *arg1, int count)
 {
-  struct value *val;
-
   if (VALUE_LVAL (arg1) != lval_memory)
     error (_("Only values in memory can be extended with '@'."));
   if (count < 1)
     error (_("Invalid number %d of repetitions."), count);
 
-  val = allocate_repeat_value (value_enclosing_type (arg1), count);
+  struct value *val
+    = allocate_repeat_value (value_enclosing_type (arg1), count);
 
   VALUE_LVAL (val) = lval_memory;
   set_value_address (val, value_address (arg1));
+  set_value_bitpos (val, value_bitpos (arg1));
+  struct type *enclosing_type = value_enclosing_type (val);
 
-  read_value_memory (val, 0, value_stack (val), value_address (val),
-                    value_contents_all_raw (val),
-                    type_length_units (value_enclosing_type (val)));
+  read_value_memory (val, value_bitpos (val), value_stack (val),
+                    value_address (val), value_contents_all_raw (val),
+                    type_length_units (enclosing_type));
 
   return val;
 }
@@ -1700,7 +1736,7 @@ value_array (int lowbound, int highbound, struct value **elemvec)
     {
       val = allocate_value (arraytype);
       for (idx = 0; idx < nelem; idx++)
-       value_contents_copy (val, idx * typelength, elemvec[idx], 0,
+       value_contents_copy (val, idx * typelength, elemvec[idx], 0, 0,
                             typelength);
       return val;
     }
@@ -1710,7 +1746,8 @@ value_array (int lowbound, int highbound, struct value **elemvec)
 
   val = allocate_value (arraytype);
   for (idx = 0; idx < nelem; idx++)
-    value_contents_copy (val, idx * typelength, elemvec[idx], 0, typelength);
+    value_contents_copy (val, idx * typelength, elemvec[idx], 0, 0,
+                        typelength);
   return val;
 }
 
@@ -3977,7 +4014,7 @@ value_slice (struct value *array, int lowbound, int length)
     else
       {
        slice = allocate_value (slice_type);
-       value_contents_copy (slice, 0, array, offset,
+       value_contents_copy (slice, 0, array, offset, 0,
                             type_length_units (slice_type));
       }
 
index 5f52c2d566d523f7bf9083affd0bb51331f56abb..60054d3b34cfece299b9c69a637887e1e58eec24 100644 (file)
@@ -1306,9 +1306,10 @@ value_ranges_copy_adjusted (struct value *dst, int dst_bit_offset,
 
 void
 value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
-                        struct value *src, LONGEST src_offset, LONGEST length)
+                        struct value *src, LONGEST src_offset,
+                        LONGEST src_bit_offset, LONGEST length)
 {
-  LONGEST src_bit_offset, dst_bit_offset, bit_length;
+  LONGEST src_total_bit_offset, dst_total_bit_offset, bit_length;
   struct gdbarch *arch = get_value_arch (src);
   int unit_size = gdbarch_addressable_memory_unit_size (arch);
 
@@ -1327,17 +1328,29 @@ value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
                                             TARGET_CHAR_BIT * length));
 
   /* Copy the data.  */
-  memcpy (value_contents_all_raw (dst) + dst_offset * unit_size,
-         value_contents_all_raw (src) + src_offset * unit_size,
-         length * unit_size);
+  bit_length = length * unit_size * HOST_CHAR_BIT;
+
+  if (src_bit_offset)
+    {
+      bool big_endian = type_byte_order (value_type (dst)) == BFD_ENDIAN_BIG;
+
+      copy_bitwise (value_contents_all_raw (dst) + dst_offset * unit_size, 0,
+                   value_contents_all_raw (src) + src_offset * unit_size,
+                   src_bit_offset, bit_length, big_endian);
+    }
+  else
+    memcpy (value_contents_all_raw (dst) + dst_offset * unit_size,
+           value_contents_all_raw (src) + src_offset * unit_size,
+           length * unit_size);
 
   /* Copy the meta-data, adjusted.  */
-  src_bit_offset = src_offset * unit_size * HOST_CHAR_BIT;
-  dst_bit_offset = dst_offset * unit_size * HOST_CHAR_BIT;
-  bit_length = length * unit_size * HOST_CHAR_BIT;
+  src_total_bit_offset = src_offset * unit_size * HOST_CHAR_BIT
+                        + src_bit_offset;
+  dst_total_bit_offset = dst_offset * unit_size * HOST_CHAR_BIT;
+
 
-  value_ranges_copy_adjusted (dst, dst_bit_offset,
-                             src, src_bit_offset,
+  value_ranges_copy_adjusted (dst, dst_total_bit_offset,
+                             src, src_total_bit_offset,
                              bit_length);
 }
 
@@ -1353,12 +1366,14 @@ value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
 
 void
 value_contents_copy (struct value *dst, LONGEST dst_offset,
-                    struct value *src, LONGEST src_offset, LONGEST length)
+                    struct value *src, LONGEST src_offset,
+                    LONGEST src_bit_offset, LONGEST length)
 {
   if (src->lazy)
     value_fetch_lazy (src);
 
-  value_contents_copy_raw (dst, dst_offset, src, src_offset, length);
+  value_contents_copy_raw (dst, dst_offset, src, src_offset,
+                          src_bit_offset, length);
 }
 
 int
@@ -3015,7 +3030,7 @@ value_primitive_field (struct value *arg1, LONGEST offset,
       else
        {
          v = allocate_value (value_enclosing_type (arg1));
-         value_contents_copy_raw (v, 0, arg1, 0,
+         value_contents_copy_raw (v, 0, arg1, 0, 0,
                                   TYPE_LENGTH (value_enclosing_type (arg1)));
        }
       v->type = type;
@@ -3050,7 +3065,7 @@ value_primitive_field (struct value *arg1, LONGEST offset,
          v = allocate_value (type);
          value_contents_copy_raw (v, value_embedded_offset (v),
                                   arg1, value_embedded_offset (arg1) + offset,
-                                  type_length_units (type));
+                                  0, type_length_units (type));
        }
       v->offset = (value_offset (arg1) + offset
                   + value_embedded_offset (arg1));
@@ -3644,7 +3659,7 @@ value_from_component (struct value *whole, struct type *type, LONGEST offset)
       v = allocate_value (type);
       value_contents_copy (v, value_embedded_offset (v),
                           whole, value_embedded_offset (whole) + offset,
-                          type_length_units (type));
+                          0, type_length_units (type));
     }
   v->offset = value_offset (whole) + offset + value_embedded_offset (whole);
   set_value_component_location (v, whole);
@@ -3827,9 +3842,9 @@ value_fetch_lazy_memory (struct value *val)
   struct type *type = check_typedef (value_enclosing_type (val));
 
   if (TYPE_LENGTH (type))
-      read_value_memory (val, 0, value_stack (val),
-                        addr, value_contents_all_raw (val),
-                        type_length_units (type));
+    read_value_memory (val, value_bitpos (val), value_stack (val),
+                      addr, value_contents_all_raw (val),
+                      type_length_units (type));
 }
 
 /* Helper for value_fetch_lazy when the value is in a register.  */
@@ -3842,10 +3857,6 @@ value_fetch_lazy_register (struct value *val)
   struct type *type = check_typedef (value_type (val));
   struct value *new_val = val, *mark = value_mark ();
 
-  /* Offsets are not supported here; lazy register values must
-     refer to the entire register.  */
-  gdb_assert (value_offset (val) == 0);
-
   while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val))
     {
       struct frame_id next_frame_id = VALUE_NEXT_FRAME_ID (new_val);
@@ -3888,6 +3899,11 @@ value_fetch_lazy_register (struct value *val)
                        _("infinite loop while fetching a register"));
     }
 
+  /* Check if NEW_VALUE is big enough to cover
+     the expected VAL type with an offset.  */
+  gdb_assert ((TYPE_LENGTH (type) + value_offset (val))
+             <= TYPE_LENGTH (value_type (new_val)));
+
   /* If it's still lazy (for instance, a saved register on the
      stack), fetch it.  */
   if (value_lazy (new_val))
@@ -3896,9 +3912,9 @@ value_fetch_lazy_register (struct value *val)
   /* Copy the contents and the unavailability/optimized-out
      meta-data from NEW_VAL to VAL.  */
   set_value_lazy (val, 0);
-  value_contents_copy (val, value_embedded_offset (val),
-                      new_val, value_embedded_offset (new_val),
-                      type_length_units (type));
+  value_contents_copy (val, value_embedded_offset (val), new_val,
+                      value_embedded_offset (new_val) + value_offset (val),
+                      value_bitpos (val), type_length_units (type));
 
   if (frame_debug)
     {
index 2eaba5748751c7092916f70c1b4da209dee3055f..d1c8ced67cc5868c44152ec91a76dafc50274fab 100644 (file)
@@ -739,10 +739,10 @@ extern struct value *allocate_value (struct type *type);
 extern struct value *allocate_value_lazy (struct type *type);
 extern void value_contents_copy (struct value *dst, LONGEST dst_offset,
                                 struct value *src, LONGEST src_offset,
-                                LONGEST length);
+                                LONGEST src_bit_offset, LONGEST length);
 extern void value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
                                     struct value *src, LONGEST src_offset,
-                                    LONGEST length);
+                                    LONGEST src_bit_offset, LONGEST length);
 
 extern struct value *allocate_repeat_value (struct type *type, int count);
 
index 13825a3eef7ea5ce3aac790e1082c571cad340ad..4880a2268f63d0bb183d91950d9cf27a814a3e7f 100644 (file)
@@ -704,6 +704,10 @@ DW_OP (DW_OP_PGI_omp_thread_num, 0xf8)
    to 0 except explicitly documented for one action.  Please refer AArch64 DWARF
    ABI documentation for details.  */
 DW_OP (DW_OP_AARCH64_operation, 0xea)
+/* LLVM extensions for heterogeneous targets */
+DW_OP_DUP (DW_OP_LLVM_offset, 0xe3)
+DW_OP_DUP (DW_OP_LLVM_offset_constu, 0xe4)
+DW_OP_DUP (DW_OP_LLVM_bit_offset, 0xe5)
 DW_END_OP
 
 DW_FIRST_ATE (DW_ATE_void, 0x0)