Files
binutils-gdb/gdb/testsuite/gdb.dwarf2/dw2-llvm-offset.exp
Zoran Zaric a85f75281a Add DWARF operations for byte and bit offset
Currently in DWARF, there are only two ways to specify an offset for a
location description.

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

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

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

Detailed descriptions of these new operations can be found here:

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

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

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

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

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

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

gdb/ChangeLog:

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

include/ChangeLog:

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

gdb/testsuite/ChangeLog:

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

Change-Id: I2a6928c2a647debe50c59756be2197d60b6bc2df
2020-12-08 11:16:21 -05:00

329 lines
8.8 KiB
Plaintext

# Copyright 2017-2020 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Test DWARF operation that allow adding byte and bit offset to any
# location description.
#
# In particular, the test uses memory and register location
# descriptions (both as standalone and parts of the composite
# location), and applies different byte and bit offsets to them.
load_lib dwarf.exp
# This test can only be run on targets which support DWARF-2 and use gas.
if {![dwarf2_support]} {
return 0
}
# Choose suitable integer registers for the test.
set dwarf_regnum 0
if { [is_aarch64_target] } {
set regname x0
} elseif { [is_aarch32_target]
|| [istarget "s390*-*-*" ]
|| [istarget "powerpc*-*-*"]
|| [istarget "rs6000*-*-aix*"] } {
set regname r0
} elseif { [is_x86_like_target] } {
set regname eax
} elseif { [is_amd64_regs_target] } {
set regname rax
} else {
verbose "Skipping ${gdb_test_file_name}."
return
}
standard_testfile var-access.c ${gdb_test_file_name}-dw.S
# Make some DWARF for the test.
set asm_file [standard_output_file $srcfile2]
Dwarf::assemble $asm_file {
global dwarf_regnum regname srcdir subdir srcfile
set buf_var [gdb_target_symbol buf]
set main_result [function_range main ${srcdir}/${subdir}/${srcfile}]
set main_start [lindex $main_result 0]
set main_length [lindex $main_result 1]
cu {} {
DW_TAG_compile_unit {
{DW_AT_name var-access.c}
{DW_AT_comp_dir /tmp}
} {
declare_labels char_type_label int_type_label
declare_labels array_size_4_type_label array_size_8_type_label
# define char type.
char_type_label: DW_TAG_base_type {
{DW_AT_name "char"}
{DW_AT_encoding @DW_ATE_signed}
{DW_AT_byte_size 1 DW_FORM_sdata}
}
# define int type.
int_type_label: DW_TAG_base_type {
{DW_AT_name "int"}
{DW_AT_encoding @DW_ATE_signed}
{DW_AT_byte_size 4 DW_FORM_sdata}
}
# define 4 byte size array type.
array_size_4_type_label: DW_TAG_array_type {
{DW_AT_type :$char_type_label}
} {
DW_TAG_subrange_type {
{DW_AT_type :$int_type_label}
{DW_AT_upper_bound 3 DW_FORM_udata}
}
}
# define 8 byte size array type.
array_size_8_type_label: DW_TAG_array_type {
{DW_AT_type :$char_type_label}
} {
DW_TAG_subrange_type {
{DW_AT_type :$int_type_label}
{DW_AT_upper_bound 7 DW_FORM_udata}
}
}
DW_TAG_subprogram {
{DW_AT_name main}
{DW_AT_low_pc $main_start addr}
{DW_AT_high_pc $main_length data8}
} {
# define original buf variable.
DW_TAG_variable {
{DW_AT_name buf}
{DW_AT_type :$array_size_4_type_label}
{DW_AT_location {
DW_OP_addr $buf_var
} SPECIAL_expr}
}
# defined a variable located in
# a third byte of the buf variable.
DW_TAG_variable {
{DW_AT_name buf_byte_3}
{DW_AT_type :$char_type_label}
{DW_AT_location {
DW_OP_addr $buf_var
DW_OP_LLVM_offset_constu 2
} SPECIAL_expr}
{external 1 flag}
}
# defined a variable located in a second byte
# of the buf variable with a bit offset of one.
DW_TAG_variable {
{DW_AT_name buf_byte_2_bit_1}
{DW_AT_type :$char_type_label}
{DW_AT_location {
DW_OP_addr $buf_var
DW_OP_lit9
DW_OP_LLVM_bit_offset
} SPECIAL_expr}
{external 1 flag}
}
# defined a variable located in a
# third byte of the REGNAME register.
DW_TAG_variable {
{DW_AT_name reg_byte_3}
{DW_AT_type :$char_type_label}
{DW_AT_location {
DW_OP_regx $dwarf_regnum
DW_OP_lit2
DW_OP_LLVM_offset
} SPECIAL_expr}
{external 1 flag}
}
# defined a variable located in a second byte of
# the REGNAME register with a bit offset of one.
DW_TAG_variable {
{DW_AT_name reg_byte_2_bit_1}
{DW_AT_type :$char_type_label}
{DW_AT_location {
DW_OP_regx $dwarf_regnum
DW_OP_lit1
DW_OP_LLVM_offset
DW_OP_lit1
DW_OP_LLVM_bit_offset
} SPECIAL_expr}
{external 1 flag}
}
# Define an array variable spread in different
# pieces of buf variable and REGNAME register.
DW_TAG_variable {
{DW_AT_name mix_array}
{DW_AT_type :$array_size_8_type_label}
{DW_AT_location {
# a byte piece located in a
# fourth byte of the buf variable.
DW_OP_addr $buf_var
DW_OP_LLVM_offset_constu 3
DW_OP_piece 0x1
# a byte piece located in a
# third byte of the buf variable.
DW_OP_addr $buf_var
DW_OP_lit2
DW_OP_LLVM_offset
DW_OP_piece 0x1
# a byte piece located in a second byte of
# the buf variable with a bit offset of one.
DW_OP_addr $buf_var
DW_OP_lit1
DW_OP_LLVM_offset
DW_OP_lit1
DW_OP_LLVM_bit_offset
DW_OP_piece 0x1
# a four bit piece located in a first byte
# of the buf variable with a bit offset of one.
DW_OP_addr $buf_var
DW_OP_LLVM_offset_constu 0
DW_OP_bit_piece 0x4 0x1
# a four bit piece located in a first byte of
# the buf variable with a bit offset of eight.
DW_OP_addr $buf_var
DW_OP_lit1
DW_OP_LLVM_bit_offset
DW_OP_LLVM_offset_constu 0
DW_OP_bit_piece 0x4 0x7
# a byte piece located in a fourth
# byte of the REGNAME register.
DW_OP_regx $dwarf_regnum
DW_OP_LLVM_offset_constu 3
DW_OP_piece 0x1
# a byte piece located in a third
# byte of the REGNAME register.
DW_OP_regx $dwarf_regnum
DW_OP_lit2
DW_OP_LLVM_offset
DW_OP_piece 0x1
# a byte piece located in a second byte of the
# REGNAME register with a bit offset of one.
DW_OP_regx $dwarf_regnum
DW_OP_lit1
DW_OP_LLVM_offset
DW_OP_lit1
DW_OP_LLVM_bit_offset
DW_OP_piece 0x1
# a four bit piece located in a first byte of
# the REGNAME register with a bit offset of one.
DW_OP_regx $dwarf_regnum
DW_OP_LLVM_offset_constu 0
DW_OP_bit_piece 0x4 0x1
# a four bit piece located in a first byte of the
# REGNAME register with a bit offset of eight.
DW_OP_regx $dwarf_regnum
DW_OP_lit1
DW_OP_LLVM_bit_offset
DW_OP_LLVM_offset_constu 0
DW_OP_bit_piece 0x4 0x7
} SPECIAL_expr}
{external 1 flag}
}
}
}
}
}
if { [prepare_for_testing ${testfile}.exp ${testfile} \
[list $srcfile $asm_file] {nodebug}] } {
return -1
}
if ![runto_main] {
return -1
}
# Determine byte order.
set endian [get_endianness]
if { $endian != "little" } then {
verbose "Skipping ${gdb_test_file_name}."
return
}
gdb_test_no_output "set var \$$regname = 0x04030201" "init reg"
gdb_test_no_output "set var *\(\(unsigned int *\) buf\) = 0x04030201" \
"init buf"
gdb_test "print/x buf_byte_3" " = 0x3" "buf_byte_3 == 0x3"
gdb_test "print/x buf_byte_2_bit_1" " = 0x81" \
"print buf_byte_2_bit_1"
gdb_test "print/x reg_byte_3" " = 0x3" "reg_byte_3 == 0x3"
gdb_test "print/x reg_byte_2_bit_1" " = 0x81" \
"print reg_byte_2_bit_1"
gdb_test_no_output "set var buf_byte_3 = 0x4" "init buf_byte_3 to 0x4"
gdb_test "print/x buf_byte_3" " = 0x4" "buf_byte_3 == 0x4"
gdb_test_no_output "set var buf_byte_2_bit_1 = 0x4" \
"init buf_byte_2_bit_1 to 0x4"
gdb_test "print/x buf_byte_2_bit_1" " = 0x4" "buf_byte_2_bit_1 == 0x4"
gdb_test "print/x buf" " = \\{0x1, 0x8, 0x4, 0x4\\}" "buf print"
gdb_test_no_output "set var reg_byte_3 = 0x4" "init reg_byte_3 to 0x4"
gdb_test "print/x reg_byte_3" " = 0x4" "reg_byte_3 == 0x4"
gdb_test_no_output "set var reg_byte_2_bit_1 = 0x4" \
"init reg_byte_2_bit_1 to 0x4"
gdb_test "print/x reg_byte_2_bit_1" " = 0x4" "reg_byte_2_bit_1 == 0x4"
gdb_test "print/x \$$regname" " = 0x4040801" "\$$regname print"
gdb_test_no_output "set var \$$regname = 0x04030201" "reset reg"
gdb_test_no_output "set var *\(\(unsigned int *\) buf\) = 0x04030201" \
"reset buf"
gdb_test "print/x mix_array" \
" = \\{0x4, 0x3, 0x81, 0x20, 0x4, 0x3, 0x81, 0x20\\}" \
"mix_array print"
gdb_test_no_output "set var mix_array\[1\] = 0x4" \
"set mix_array second byte"
gdb_test_no_output "set var mix_array\[2\] = 0x4" \
"set mix_array third byte"
gdb_test_no_output "set var mix_array\[5\] = 0x4" \
"set mix_array fifth byte"
gdb_test_no_output "set var mix_array\[6\] = 0x4" \
"set mix_array sixth byte"
gdb_test "print/x mix_array" \
" = \\{0x4, 0x4, 0x4, 0x80, 0x4, 0x4, 0x4, 0x80\\}" \
"mix_array second print"
gdb_test "print/x buf" " = \\{0x1, 0x8, 0x4, 0x4\\}" "buf second print"
gdb_test "print/x \$$regname" " = 0x4040801" "\$$regname second print"