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));
(*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;
= 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;
}
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);
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;
}
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);
}
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:
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;
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");
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);
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));
}
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);
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)));
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;
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);
}
/* 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;
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);
--- /dev/null
+# 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"
_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"
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)
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.
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))
{
"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
{
case lval_register:
{
struct frame_info *frame;
- struct gdbarch *gdbarch;
int value_reg;
/* Figure out which frame this register value is in. The value
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,
_("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
{
= gdb::make_array_view (value_contents (fromval).data (),
TYPE_LENGTH (type));
put_frame_register_bytes (frame, value_reg,
- value_offset (toval),
- contents);
+ offset, contents);
}
}
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;
}
{
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;
}
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;
}
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));
}
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);
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);
}
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
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;
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));
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);
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. */
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);
_("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))
/* 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)
{
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);
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)