]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Add DWARF operations for byte and bit offset
authorZoran Zaric <Zoran.Zaric@amd.com>
Wed, 4 Nov 2020 15:07:41 +0000 (15:07 +0000)
committerZoran Zaric <zoran.zaric@amd.com>
Fri, 5 Nov 2021 11:48:16 +0000 (11:48 +0000)
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 call.
* compile/compile-loc2c.c (compute_stack_depth_worker): Add new
DWARF operations support.
* dwarf2/expr.c (dwarf_register::to_gdb_value): Add bit offset
support.
        (dwarf_register::to_gdb_value): Add bit offset support.
(dwarf_register::to_gdb_value): Add source bit
offset argument to the value_contents_copy call.
(dwarf_expr_context::execute_stack_op): Add new DWARF
operations support.
        * dwarf2/loc.c (dwarf2_get_symbol_read_needs): Add new DWARF
        operation support.
        (disassemble_dwarf_expression): Add support for new
        DW_OP_LLVM_offset_constu operation.
* findvar.c (read_frame_register_value): Add source bit offset
argument to the value_contents_copy call.
        * frame.c (get_frame_register_bytes): Takes into account a
        potential unwound register struct value offset.
        (get_frame_register_bytes): Takes into account a potential
        unwound register struct value offset.
* 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 call.
(value_slice): Add source bit offset argument to the
value_contents_copy 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 call.
(value_from_component): Add source bit offset argument to the
value_contents_copy 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.

13 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/frame.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 d964dae42cf64c24637a0241585ad63f860c9e51..8a442e0f5c9c3f316f07bf02073e4c3219e08a85 100644 (file)
@@ -531,7 +531,7 @@ coerce_unspec_val_to_type (struct value *val, struct type *type)
       else
        {
          result = allocate_value (type);
-         value_contents_copy (result, 0, val, 0, TYPE_LENGTH (type));
+         value_contents_copy (result, 0, val, 0, 0, TYPE_LENGTH (type));
        }
       set_value_component_location (result, val);
       set_value_bitsize (result, value_bitsize (val));
index fb1a4ff02b6f45cc6a59d8549357d41e1212e1e6..77eb5a8e19dbba6b05938dd49316a69106935cf1 100644 (file)
@@ -357,6 +357,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 676e0bae8a703de05328c119ca3343f8da558f32..a0310fef7a4aea6811bf8055afe285b274627230 100644 (file)
@@ -1093,6 +1093,7 @@ dwarf_memory::to_gdb_value (frame_info *frame, struct type *type,
     = value_as_address (value_from_pointer (ptr_type, m_offset));
   value *retval = value_at_lazy (subobj_type, address + subobj_offset);
   set_value_stack (retval, m_stack);
+  set_value_bitpos (retval, m_bit_suboffset);
   return retval;
 }
 
@@ -1270,6 +1271,9 @@ dwarf_register::to_gdb_value (frame_info *frame, struct type *type,
   else
     set_value_offset (retval, (retval_offset + m_offset) / unit_size);
 
+  set_value_bitpos (retval,
+                   m_bit_suboffset + (m_offset % unit_size) * HOST_CHAR_BIT);
+
   /* Get the data.  */
   read_frame_register_value (retval, frame);
 
@@ -1281,7 +1285,7 @@ dwarf_register::to_gdb_value (frame_info *frame, struct type *type,
         return a generic optimized out value instead, so that we show
         <optimized out> instead of <not saved>.  */
       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;
     }
 
@@ -4013,6 +4017,40 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
          push (make_unique<dwarf_memory> (arch, this->m_addr_info->addr));
          break;
 
+       case DW_OP_LLVM_offset:
+         {
+           dwarf_value_up value = to_value (pop (), address_type);
+           dwarf_require_integral (value->type ());
+           dwarf_location_up location = to_location (pop (), arch);
+
+           location->add_bit_offset (value->to_long () * HOST_CHAR_BIT);
+           push (std::move (location));
+           break;
+         }
+
+       case DW_OP_LLVM_offset_constu:
+         {
+           uint64_t uoffset;
+           op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
+           ULONGEST result = uoffset;
+           dwarf_location_up location = to_location (pop (), arch);
+
+           location->add_bit_offset (result * HOST_CHAR_BIT);
+           push (std::move (location));
+           break;
+         }
+
+       case DW_OP_LLVM_bit_offset:
+         {
+           dwarf_value_up value = to_value (pop (), address_type);
+           dwarf_require_integral (value->type ());
+           dwarf_location_up location = to_location (pop (), arch);
+
+           location->add_bit_offset (value->to_long ());
+           push (std::move (location));
+           break;
+         }
+
        default:
          error (_("Unhandled dwarf expression opcode 0x%x"), op);
        }
index 753ebbbae6cd4dc919fced2b9b2680d526e530e3..7c0782404dd6f07acc5b9b4dc493d2241205128d 100644 (file)
@@ -1924,6 +1924,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:
@@ -1941,6 +1943,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_skip_leb128 (op_ptr, expr_end);
          break;
 
@@ -3657,6 +3660,11 @@ disassemble_dwarf_expression (struct ui_file *stream,
          data += offset_size;
          fprintf_filtered (stream, " offset %s", phex_nz (ul, offset_size));
          break;
+
+       case DW_OP_LLVM_offset_constu:
+         data = safe_read_uleb128 (data, end, &ul);
+         fprintf_filtered (stream, " %s", pulongest (ul));
+         break;
        }
 
       fprintf_filtered (stream, "\n");
index 230feb78e26ca07d741fc6455af7ae40ae5447f5..a50629a4427ce145f80bf1f9d983cf185c2c5ae0 100644 (file)
@@ -161,7 +161,7 @@ fortran_bounds_all_dims (bool lbound_p,
       gdb_assert (dst_offset + TYPE_LENGTH (value_type (v))
                  <= TYPE_LENGTH (value_type (result)));
       gdb_assert (TYPE_LENGTH (value_type (v)) == elm_len);
-      value_contents_copy (result, dst_offset, v, 0, elm_len);
+      value_contents_copy (result, dst_offset, v, 0, 0, elm_len);
 
       /* Peel another dimension of the array.  */
       array_type = TYPE_TARGET_TYPE (array_type);
@@ -289,7 +289,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));
   }
@@ -736,7 +736,7 @@ fortran_array_shape (struct gdbarch *gdbarch, const language_defn *lang,
       gdb_assert (dst_offset + TYPE_LENGTH (value_type (v))
                  <= TYPE_LENGTH (value_type (result)));
       gdb_assert (TYPE_LENGTH (value_type (v)) == elm_len);
-      value_contents_copy (result, dst_offset, v, 0, elm_len);
+      value_contents_copy (result, dst_offset, v, 0, 0, elm_len);
 
       /* Peel another dimension of the array.  */
       val_type = TYPE_TARGET_TYPE (val_type);
index d2b77133982acd07505c5044c66f82d6e2a5f83d..2f97b6079cb73e88e1cd5c3433b3c5828cdf0400 100644 (file)
@@ -869,6 +869,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)));
 
@@ -892,7 +893,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;
index 3dd6c799847ee14563b68c160c4a2f00baa87089..051d6f766ce90df23fd7524addf0b2174f130fc8 100644 (file)
@@ -1497,8 +1497,9 @@ get_frame_register_bytes (frame_info *frame, int regnum,
              return false;
            }
 
-         memcpy (myaddr, value_contents_all (value).data () + offset,
-                 curr_len);
+         memcpy (myaddr,
+                 value_contents_all (value).data ()
+                   + value_offset (value) + offset, curr_len);
          release_value (value);
        }
 
@@ -1532,10 +1533,19 @@ put_frame_register_bytes (struct frame_info *frame, int regnum,
   /* Copy the data.  */
   while (len > 0)
     {
-      int curr_len = register_size (gdbarch, regnum) - offset;
-
       struct value *value = frame_unwind_register_value (frame->next,
                                                         regnum);
+      /* Need to account the unwind register offset too.  */
+      offset += value == NULL ? 0 : value_offset (value);
+
+      if (offset >= register_size (gdbarch, regnum))
+       {
+         offset -= register_size (gdbarch, regnum);
+         regnum++;
+         continue;
+       }
+
+      int curr_len = register_size (gdbarch, regnum) - offset;
 
       if (curr_len > len)
        curr_len = len;
@@ -1555,7 +1565,7 @@ put_frame_register_bytes (struct frame_info *frame, int regnum,
          type * reg_type = register_type (gdbarch, regnum);
 
          struct value *from_value = allocate_value (reg_type);
-         memcpy (value_contents_raw (from_value), myaddr,
+         memcpy (value_contents_raw (from_value).data (), myaddr,
                  TYPE_LENGTH (reg_type));
 
          set_value_offset (value, offset);
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..734007e
--- /dev/null
@@ -0,0 +1,328 @@
+# Copyright 2017-2021 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 b48cfad3b9e5da97984607332cc204996d8cc907..48a10aedf26e22f9edbe432ebc2a37531ab4feb3 100644 (file)
@@ -1221,6 +1221,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 9787cdbb513c60eccd6b4a574d1a68c8a14305c2..a79afa354a7eee5b977c54abd6d21543d7fef9f1 100644 (file)
@@ -1040,20 +1040,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_inferior ()->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)
@@ -1070,6 +1081,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.
@@ -1141,7 +1156,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))
          {
@@ -1167,10 +1182,26 @@ 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).data (), 0,
+                         TYPE_LENGTH (type) * HOST_CHAR_BIT, big_endian);
+           dest_buffer = buffer.data();
          }
        else
          {
@@ -1186,7 +1217,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 register value is in.  The value
@@ -1204,29 +1234,41 @@ value_assign (struct value *toval, struct value *fromval)
        if (!frame)
          error (_("Value being assigned to is no longer active."));
 
-       gdbarch = get_frame_arch (frame);
+       gdbarch *arch = get_frame_arch (frame);
+       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);
-           size_t changed_len;
-           gdb_byte buffer[sizeof (LONGEST)];
-           int optim, unavail;
+           int changed_len;
+           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)
+             {
+               offset += value_offset (value_parent (toval));
 
-           if (changed_len > sizeof (LONGEST))
-             error (_("Can't handle bitfields which "
-                      "don't fit in a %d bit word."),
-                    (int) sizeof (LONGEST) * HOST_CHAR_BIT);
+               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);
+             }
+           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,
-                                          {buffer, changed_len},
-                                          &optim, &unavail))
+                                          buffer, &optim, &unavail))
              {
                if (optim)
                  throw_error (OPTIMIZED_OUT_ERROR,
@@ -1236,23 +1278,21 @@ 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).data (),
+                         0, bitsize, big_endian);
 
-           put_frame_register_bytes (frame, value_reg, offset,
-                                     {buffer, changed_len});
+           put_frame_register_bytes (frame, value_reg, offset, buffer);
          }
        else
          {
-           if (gdbarch_convert_register_p (gdbarch, VALUE_REGNUM (toval),
-                                           type))
+           if (gdbarch_convert_register_p (arch, VALUE_REGNUM (toval), type))
              {
                /* If TOVAL is a special machine register requiring
                   conversion of program values to a special raw
                   format.  */
-               gdbarch_value_to_register (gdbarch, frame,
-                                          VALUE_REGNUM (toval), type,
-                                          value_contents (fromval).data ());
+               gdbarch_value_to_register (arch, frame, VALUE_REGNUM (toval),
+                                          type, value_contents (fromval).data ());
              }
            else
              {
@@ -1260,8 +1300,7 @@ value_assign (struct value *toval, struct value *fromval)
                  = gdb::make_array_view (value_contents (fromval).data (),
                                          TYPE_LENGTH (type));
                put_frame_register_bytes (frame, value_reg,
-                                         value_offset (toval),
-                                         contents);
+                                         offset, contents);
              }
          }
 
@@ -1363,21 +1402,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);
+  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));
+  type *enclosing_type = value_enclosing_type (val);
 
-  read_value_memory (val, 0, value_stack (val), value_address (val),
-                    value_contents_all_raw (val).data (),
-                    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).data (),
+                    type_length_units (enclosing_type));
 
   return val;
 }
@@ -1726,7 +1766,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;
     }
@@ -1736,7 +1776,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;
 }
 
@@ -4005,7 +4046,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 7de858c708504aa278e46ad294ddbbacf92458cf..01af97141ef296d3288a0d084850ed9f41f88506 100644 (file)
@@ -1322,9 +1322,10 @@ value_ranges_copy_adjusted (struct value *dst, int dst_bit_offset,
 
 static 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);
 
@@ -1343,17 +1344,31 @@ value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
                                             TARGET_CHAR_BIT * length));
 
   /* Copy the data.  */
-  memcpy (value_contents_all_raw (dst).data () + dst_offset * unit_size,
-         value_contents_all_raw (src).data () + 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).data ()
+                     + dst_offset * unit_size, 0,
+                   value_contents_all_raw (src).data ()
+                     + src_offset * unit_size,
+                   src_bit_offset, bit_length, big_endian);
+    }
+  else
+    memcpy (value_contents_all_raw (dst).data () + dst_offset * unit_size,
+           value_contents_all_raw (src).data () + 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);
 }
 
@@ -1369,12 +1384,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
@@ -3089,7 +3106,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;
@@ -3124,7 +3141,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));
@@ -3731,7 +3748,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);
@@ -3913,9 +3930,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).data (),
-                        type_length_units (type));
+    read_value_memory (val, value_bitpos (val), value_stack (val),
+                      addr, value_contents_all_raw (val).data (),
+                      type_length_units (type));
 }
 
 /* Helper for value_fetch_lazy when the value is in a register.  */
@@ -3928,10 +3945,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);
@@ -3974,6 +3987,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))
@@ -3982,9 +4000,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 82b29c6292ee8149c466918d12694c7a31e6b84e..8468d3158d43c20cef472df4be38172cba8946d8 100644 (file)
@@ -740,7 +740,7 @@ 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 struct value *allocate_repeat_value (struct type *type, int count);
 
index 1ae6e1df298bcc3f1a0a08a3d5b266948d3baf65..5e622695d605f47e79f3109f8a2f49e82a27cfed 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)