summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/compile/compile-loc2c.c5
-rw-r--r--gdb/dwarf2/expr.c78
-rw-r--r--gdb/dwarf2/loc.c2
-rw-r--r--gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.c33
-rw-r--r--gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.exp213
-rw-r--r--include/dwarf2.def2
6 files changed, 333 insertions, 0 deletions
diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
index 83863276b4c..c3de7e7980d 100644
--- a/gdb/compile/compile-loc2c.c
+++ b/gdb/compile/compile-loc2c.c
@@ -370,6 +370,11 @@ compute_stack_depth_worker (int start, int *need_tempvar,
stack_depth -= 2;
break;
+ case DW_OP_LLVM_overlay:
+ case DW_OP_LLVM_bit_overlay:
+ stack_depth -= 3;
+ break;
+
case DW_OP_LLVM_extend:
case DW_OP_LLVM_piece_end:
case DW_OP_LLVM_offset_constu:
diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 66bb8dd89b5..c9c8f3ad0a2 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -2837,6 +2837,21 @@ private:
void create_select_composite (const loc_offset &piece_size,
ULONGEST pieces_count);
+ /* It pops two stack entries. First must be a location description
+ that represents the overlay location description. The Second
+ must be a location description that represents the base location
+ description. The OVERLAY_SIZE represents the size of the overlay
+ piece of the composite and the OVERLAY_OFFSET represent a starting
+ point of the overlay from the base location.
+
+ A complete composite location description created with parts from
+ base location description, overlayed by the overlay location
+ description, starting from the overlay offset, ending at
+ a sum of the overlay offset and overlay size, is pushed
+ on top of the DWARF stack. */
+ void create_overlay_composite (loc_offset overlay_size,
+ loc_offset overlay_offset);
+
/* The engine for the expression evaluator. Using the context in this
object, evaluate the expression between OP_PTR and OP_END. */
void execute_stack_op (const gdb_byte *op_ptr, const gdb_byte *op_end);
@@ -3279,6 +3294,38 @@ dwarf_expr_context::create_select_composite (const loc_offset &piece_size,
}
void
+dwarf_expr_context::create_overlay_composite (loc_offset overlay_size,
+ loc_offset overlay_offset)
+{
+ gdbarch *arch = this->m_per_objfile->objfile->arch ();
+
+ if (stack_empty_p ())
+ ill_formed_expression ();
+
+ dwarf_location_up overlay = to_location (pop (), arch);
+
+ if (stack_empty_p ())
+ ill_formed_expression ();
+
+ dwarf_location_up base = to_location (pop (), arch);
+
+ std::unique_ptr<dwarf_composite> composite
+ = make_unique<dwarf_composite> (arch, this->m_per_cu);
+
+ composite->add_piece (std::move (base->slice (0, overlay_offset)),
+ overlay_offset);
+ composite->add_piece (std::move (overlay), overlay_size);
+
+ loc_offset end_offset = overlay_offset + overlay_size;
+ loc_offset end_size = base->size () - end_offset;
+
+ composite->add_piece
+ (std::move (base->slice (end_offset, end_size)), end_size);
+ composite->set_completed (true);
+ push (std::move (composite));
+}
+
+void
dwarf_expr_context::eval (const gdb_byte *addr, size_t len)
{
int old_recursion_depth = this->m_recursion_depth;
@@ -4540,6 +4587,37 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
break;
}
+ case DW_OP_LLVM_overlay:
+ case DW_OP_LLVM_bit_overlay:
+ {
+ if (stack_empty_p ())
+ ill_formed_expression ();
+
+ dwarf_value_up overlay_size_val
+ = to_value (pop (), address_type);
+ dwarf_require_integral (overlay_size_val->type ());
+ LONGEST overlay_size = overlay_size_val->to_long ();
+
+ if (stack_empty_p () || overlay_size < 0)
+ ill_formed_expression ();
+
+ dwarf_value_up overlay_offset_val
+ = to_value (pop (), address_type);
+ dwarf_require_integral (overlay_offset_val->type ());
+ LONGEST overlay_offset = overlay_offset_val->to_long ();
+
+ if (overlay_offset < 0)
+ ill_formed_expression ();
+
+ if (op == DW_OP_LLVM_overlay)
+ create_overlay_composite ({(ULONGEST) overlay_size, 0},
+ {(ULONGEST) overlay_offset, 0});
+ else
+ create_overlay_composite ((ULONGEST) overlay_size,
+ (ULONGEST) overlay_offset);
+ break;
+ }
+
default:
error (_("Unhandled dwarf expression opcode 0x%x"), op);
}
diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
index 071baad76d1..c7aa8ded118 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -1928,6 +1928,8 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
case DW_OP_LLVM_bit_offset:
case DW_OP_LLVM_undefined:
case DW_OP_LLVM_piece_end:
+ case DW_OP_LLVM_overlay:
+ case DW_OP_LLVM_bit_overlay:
break;
case DW_OP_form_tls_address:
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.c b/gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.c
new file mode 100644
index 00000000000..be496bd070c
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.c
@@ -0,0 +1,33 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2022 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/>. */
+
+unsigned buff[] = {0, 1, 2, 3, 4, 5, 6, 7};
+
+void foo (unsigned dst[], unsigned src[], int len)
+{
+ asm volatile ("foo_label: .globl foo_label");
+ for (int i = 0; i < len; ++i)
+ dst[i] += src[i];
+}
+
+int
+main (void)
+{
+ asm volatile ("main_label: .globl main_label");
+ foo (buff, buff, 1);
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.exp b/gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.exp
new file mode 100644
index 00000000000..c8407453abb
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.exp
@@ -0,0 +1,213 @@
+# Copyright (C) 2022 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 the new DW_OP_LLVM_overlay operation.
+#
+# The test uses a composite location description, where variable buff
+# address is used as a base location and a reg1 is used as an overlay
+# location.
+
+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 1}
+
+if { [is_aarch64_target] } {
+ set regname {x0 x1}
+} elseif { [is_aarch32_target]
+ || [istarget "s390*-*-*" ]
+ || [istarget "powerpc*-*-*"]
+ || [istarget "rs6000*-*-aix*"] } {
+ set regname {r0 r1}
+} elseif { [is_x86_like_target] } {
+ set regname {eax ecx}
+} elseif { [is_amd64_regs_target] } {
+ set regname {rax rdx}
+} else {
+ verbose "Skipping $gdb_test_file_name."
+ return
+}
+
+standard_testfile .c -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 buff_src [gdb_target_symbol buff]
+
+ set foo_result [function_range foo ${srcdir}/${subdir}/${srcfile}]
+ set foo_start [lindex $foo_result 0]
+ set foo_length [lindex $foo_result 1]
+
+ cu {} {
+ DW_TAG_compile_unit {
+ {DW_AT_name $srcfile}
+ {DW_AT_comp_dir /tmp}
+ } {
+ declare_labels int_type_label uint_type_label array_type_label
+
+ uint_type_label: DW_TAG_base_type {
+ {DW_AT_name "uint32_t"}
+ {DW_AT_encoding @DW_ATE_unsigned}
+ {DW_AT_byte_size 4 DW_FORM_sdata}
+ }
+
+ 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}
+ }
+
+ array_type_label: DW_TAG_array_type {
+ {DW_AT_type :$uint_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 foo}
+ {DW_AT_low_pc $foo_start addr}
+ {DW_AT_high_pc $foo_length data8}
+ } {
+
+ DW_TAG_variable {
+ {DW_AT_name dst_v1}
+ {DW_AT_type :$array_type_label}
+ {DW_AT_location {
+ # 1. Memory location description of dst elements located in memory:
+ DW_OP_addr $buff_src
+
+ # 2. Register location description of element dst\[i\] is located in a register:
+ DW_OP_regx [lindex $dwarf_regnum 1]
+
+ # 3. Offset of the register within the memory of dst:
+ DW_OP_bregx [lindex $dwarf_regnum 0] 0
+ DW_OP_lit4
+ DW_OP_mul
+
+ # 4. The size of the register element:
+ DW_OP_lit4
+
+ # 5. Make a composite location description for dst that is the memory #1 with
+ # the register #2 positioned as an overlay at offset #3 of size #4:
+ DW_OP_LLVM_overlay
+ } SPECIAL_expr}
+ }
+
+ DW_TAG_variable {
+ {DW_AT_name dst_v2}
+ {DW_AT_type :$array_type_label}
+ {DW_AT_location {
+ # 1. Memory location description of dst elements located in memory:
+ DW_OP_addr $buff_src
+
+ # 2. Register location description of element dst\[i\] is located in a register:
+ DW_OP_regx [lindex $dwarf_regnum 1]
+
+ # 3. Offset of the register within the memory of dst:
+ DW_OP_bregx [lindex $dwarf_regnum 0] 0
+ DW_OP_lit4
+ DW_OP_mul
+
+ # 4. The size of the register element:
+ DW_OP_lit4
+
+ # 5. Make a composite location description for dst that is the memory #1 with
+ # the register #2 positioned as an overlay at offset #3 of size #4:
+ DW_OP_LLVM_bit_overlay
+ } SPECIAL_expr}
+ }
+
+ DW_TAG_variable {
+ {DW_AT_name src}
+ {DW_AT_type :$array_type_label}
+ {DW_AT_location {
+ DW_OP_addr $buff_src
+ } SPECIAL_expr}
+ }
+
+ DW_TAG_variable {
+ {DW_AT_name i}
+ {DW_AT_type :$int_type_label}
+ {DW_AT_location {
+ DW_OP_regx [lindex $dwarf_regnum 0]
+ } SPECIAL_expr}
+ }
+ }
+ }
+ }
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} \
+ [list $srcfile $asm_file] {nodebug}] } {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+gdb_test "break foo" "Breakpoint.*at.*" "break at function foo"
+gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+,.*foo \\(\\).*" \
+ "continue to foo"
+
+gdb_test_no_output "set var \$[lindex $regname 0] = 0x0" "init reg 0"
+gdb_test_no_output "set var \$[lindex $regname 1] = 0xdeadbeef" "init reg 1"
+
+# gdb_interact
+
+# Determine byte order.
+set endian [get_endianness]
+
+switch $endian {
+ little {set val_v1 "0xdeadbeef, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7"}
+ big {set val_v1 "0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0xdeadbeef"}
+}
+
+gdb_test "print/x dst_v1" " = \\{${val_v1}\\}" "dst_v1 print i = 0"
+
+switch $endian {
+ little {set val_v2 "0xf, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7"}
+ big {set val_v2 "0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0xf"}
+}
+
+gdb_test "print/x dst_v2" " = \\{${val_v2}\\}" "dst_v2 print i = 0"
+
+gdb_test_no_output "set var i = 0x2" "init reg 0 to 2"
+
+switch $endian {
+ little {set val_v1 "0x0, 0x1, 0xdeadbeef, 0x3, 0x4, 0x5, 0x6, 0x7"}
+ big {set val_v1 "0x7, 0x6, 0x5, 0x4, 0x3, 0xdeadbeef, 0x1, 0x0"}
+}
+
+gdb_test "print/x dst_v1" " = \\{${val_v1}\\}" "dst_v1 print i = 2"
+
+switch $endian {
+ little {set val_v2 "0xf00, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7"}
+ big {set val_v2 "0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0xf00"}
+}
+
+gdb_test "print/x dst_v2" " = \\{${val_v2}\\}" "dst_v2 print i = 2"
diff --git a/include/dwarf2.def b/include/dwarf2.def
index abc1125df2c..df91a0e0fe9 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -712,6 +712,8 @@ DW_OP (DW_OP_LLVM_undefined, 0xe7)
DW_OP_DUP (DW_OP_LLVM_piece_end, 0xea)
DW_OP (DW_OP_LLVM_extend, 0xeb)
DW_OP (DW_OP_LLVM_select_bit_piece, 0xec)
+DW_OP (DW_OP_LLVM_bit_overlay, 0xed)
+DW_OP (DW_OP_LLVM_overlay, 0xee)
DW_END_OP
DW_FIRST_ATE (DW_ATE_void, 0x0)