mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 10:03:47 +08:00
Add support for new DWARF overlay operations
Another complex DWARF expression operations, that are usefull for SIMD/SIMT like architectures are: DW_OP_LLVM_overlay and DW_OP_LLVM_bit_overlay. These operations pop four stack entries, where the first must be an integral that represents an overlay size, the second must be an integral that represents a starting point of the overlay from the base location, the third must be a location description that represents the overlay location description and the forth must be a location description that represents the base location description. Resulting composite location description contains 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. A new test in gdb.dwarf2 called dw2-llvm-overlay has been also added to test the support for both operations.
This commit is contained in:
parent
a50f771b91
commit
b7383d64e7
@ -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:
|
||||
|
@ -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);
|
||||
@ -3278,6 +3293,38 @@ dwarf_expr_context::create_select_composite (const loc_offset &piece_size,
|
||||
push (std::move (composite));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
|
33
gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.c
Normal file
33
gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.c
Normal file
@ -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;
|
||||
}
|
213
gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.exp
Normal file
213
gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.exp
Normal file
@ -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"
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user