mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 12:34:43 +00:00
[gdb] Add gdbarch_dwarf2_reg_piece_offset hook
In rw_pieced_value, when reading/writing part of a register, DW_OP_piece and DW_OP_bit_piece are handled the same, but the standard tells us: - DW_OP_piece: if the piece is located in a register, but does not occupy the entire register, the placement of the piece within that register is defined by the ABI. - DW_OP_bit_piece: if the location is a register, the offset is from the least significant bit end of the register. Add a new hook gdbarch_dwarf2_reg_piece_offset that allows us to define the ABI-specific behaviour for DW_OP_piece. The default implementation of the hook is the behaviour of DW_OP_bit_piece, so there should not be any functional changes. Tested on s390x-linux. Approved-By: Tom Tromey <tom@tromey.com>
This commit is contained in:
@@ -211,14 +211,33 @@ rw_pieced_value (value *v, value *from, bool check_optimized)
|
||||
ULONGEST reg_bits = 8 * register_size (arch, gdb_regnum);
|
||||
int optim, unavail;
|
||||
|
||||
if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
|
||||
&& p->offset + p->size < reg_bits)
|
||||
if (p->offset + p->size < reg_bits)
|
||||
{
|
||||
/* Big-endian, and we want less than full size. */
|
||||
bits_to_skip += reg_bits - (p->offset + p->size);
|
||||
/* We want less than full size. */
|
||||
|
||||
if (p->op == DW_OP_piece)
|
||||
{
|
||||
gdb_assert (p->offset == 0);
|
||||
|
||||
/* If the piece is located in a register, but does not
|
||||
occupy the entire register, the placement of the piece
|
||||
within that register is defined by the ABI. */
|
||||
bits_to_skip
|
||||
+= 8 * gdbarch_dwarf2_reg_piece_offset (arch, gdb_regnum,
|
||||
p->size / 8);
|
||||
}
|
||||
else if (p->op == DW_OP_bit_piece)
|
||||
{
|
||||
/* If the location is a register, the offset is from the
|
||||
least significant bit end of the register. */
|
||||
if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG)
|
||||
bits_to_skip += reg_bits - (p->offset + p->size);
|
||||
else
|
||||
bits_to_skip += p->offset;
|
||||
}
|
||||
else
|
||||
error (_("Don't know how to get part of implicit pointer"));
|
||||
}
|
||||
else
|
||||
bits_to_skip += p->offset;
|
||||
|
||||
this_size = bits_to_bytes (bits_to_skip, this_size_bits);
|
||||
buffer.resize (this_size);
|
||||
|
||||
@@ -541,6 +541,24 @@ default_value_from_register (gdbarch *gdbarch, type *type, int regnum,
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Default implementation of gdbarch_dwarf2_reg_piece_offset. Implements
|
||||
DW_OP_bits_piece for DW_OP_piece. */
|
||||
|
||||
ULONGEST
|
||||
default_dwarf2_reg_piece_offset (gdbarch *gdbarch, int gdb_regnum, ULONGEST size)
|
||||
{
|
||||
ULONGEST reg_size = register_size (gdbarch, gdb_regnum);
|
||||
gdb_assert (size <= reg_size);
|
||||
if (reg_size == size)
|
||||
return 0;
|
||||
|
||||
if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
|
||||
return reg_size - size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* VALUE must be an lval_register value. If regnum is the value's
|
||||
associated register number, and len the length of the value's type,
|
||||
read one or more registers in VALUE's frame, starting with register REGNUM,
|
||||
|
||||
@@ -109,6 +109,7 @@ struct gdbarch
|
||||
gdbarch_register_to_value_ftype *register_to_value = nullptr;
|
||||
gdbarch_value_to_register_ftype *value_to_register = nullptr;
|
||||
gdbarch_value_from_register_ftype *value_from_register = default_value_from_register;
|
||||
gdbarch_dwarf2_reg_piece_offset_ftype *dwarf2_reg_piece_offset = default_dwarf2_reg_piece_offset;
|
||||
gdbarch_pointer_to_address_ftype *pointer_to_address = unsigned_pointer_to_address;
|
||||
gdbarch_address_to_pointer_ftype *address_to_pointer = unsigned_address_to_pointer;
|
||||
gdbarch_integer_to_address_ftype *integer_to_address = nullptr;
|
||||
@@ -372,6 +373,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
|
||||
/* Skip verify of register_to_value, invalid_p == 0. */
|
||||
/* Skip verify of value_to_register, invalid_p == 0. */
|
||||
/* Skip verify of value_from_register, invalid_p == 0. */
|
||||
/* Skip verify of dwarf2_reg_piece_offset, invalid_p == 0. */
|
||||
/* Skip verify of pointer_to_address, invalid_p == 0. */
|
||||
/* Skip verify of address_to_pointer, invalid_p == 0. */
|
||||
/* Skip verify of integer_to_address, has predicate. */
|
||||
@@ -789,6 +791,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
|
||||
gdb_printf (file,
|
||||
"gdbarch_dump: value_from_register = <%s>\n",
|
||||
host_address_to_string (gdbarch->value_from_register));
|
||||
gdb_printf (file,
|
||||
"gdbarch_dump: dwarf2_reg_piece_offset = <%s>\n",
|
||||
host_address_to_string (gdbarch->dwarf2_reg_piece_offset));
|
||||
gdb_printf (file,
|
||||
"gdbarch_dump: pointer_to_address = <%s>\n",
|
||||
host_address_to_string (gdbarch->pointer_to_address));
|
||||
@@ -2588,6 +2593,23 @@ set_gdbarch_value_from_register (struct gdbarch *gdbarch,
|
||||
gdbarch->value_from_register = value_from_register;
|
||||
}
|
||||
|
||||
ULONGEST
|
||||
gdbarch_dwarf2_reg_piece_offset (struct gdbarch *gdbarch, int regnum, ULONGEST size)
|
||||
{
|
||||
gdb_assert (gdbarch != NULL);
|
||||
gdb_assert (gdbarch->dwarf2_reg_piece_offset != NULL);
|
||||
if (gdbarch_debug >= 2)
|
||||
gdb_printf (gdb_stdlog, "gdbarch_dwarf2_reg_piece_offset called\n");
|
||||
return gdbarch->dwarf2_reg_piece_offset (gdbarch, regnum, size);
|
||||
}
|
||||
|
||||
void
|
||||
set_gdbarch_dwarf2_reg_piece_offset (struct gdbarch *gdbarch,
|
||||
gdbarch_dwarf2_reg_piece_offset_ftype dwarf2_reg_piece_offset)
|
||||
{
|
||||
gdbarch->dwarf2_reg_piece_offset = dwarf2_reg_piece_offset;
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
gdbarch_pointer_to_address (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf)
|
||||
{
|
||||
|
||||
@@ -430,6 +430,14 @@ typedef struct value * (gdbarch_value_from_register_ftype) (struct gdbarch *gdba
|
||||
extern struct value * gdbarch_value_from_register (struct gdbarch *gdbarch, struct type *type, int regnum, const frame_info_ptr &this_frame);
|
||||
extern void set_gdbarch_value_from_register (struct gdbarch *gdbarch, gdbarch_value_from_register_ftype *value_from_register);
|
||||
|
||||
/* For a DW_OP_piece located in a register, but not occupying the
|
||||
entire register, return the placement of the piece within that
|
||||
register as defined by the ABI. */
|
||||
|
||||
typedef ULONGEST (gdbarch_dwarf2_reg_piece_offset_ftype) (struct gdbarch *gdbarch, int regnum, ULONGEST size);
|
||||
extern ULONGEST gdbarch_dwarf2_reg_piece_offset (struct gdbarch *gdbarch, int regnum, ULONGEST size);
|
||||
extern void set_gdbarch_dwarf2_reg_piece_offset (struct gdbarch *gdbarch, gdbarch_dwarf2_reg_piece_offset_ftype *dwarf2_reg_piece_offset);
|
||||
|
||||
typedef CORE_ADDR (gdbarch_pointer_to_address_ftype) (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf);
|
||||
extern CORE_ADDR gdbarch_pointer_to_address (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf);
|
||||
extern void set_gdbarch_pointer_to_address (struct gdbarch *gdbarch, gdbarch_pointer_to_address_ftype *pointer_to_address);
|
||||
|
||||
@@ -829,6 +829,22 @@ allocate and return a struct value with all value attributes
|
||||
invalid=False,
|
||||
)
|
||||
|
||||
Method(
|
||||
comment="""
|
||||
For a DW_OP_piece located in a register, but not occupying the
|
||||
entire register, return the placement of the piece within that
|
||||
register as defined by the ABI.
|
||||
""",
|
||||
type="ULONGEST",
|
||||
name="dwarf2_reg_piece_offset",
|
||||
params=[
|
||||
("int", "regnum"),
|
||||
("ULONGEST", "size")
|
||||
],
|
||||
predefault="default_dwarf2_reg_piece_offset",
|
||||
invalid=False,
|
||||
)
|
||||
|
||||
Method(
|
||||
type="CORE_ADDR",
|
||||
name="pointer_to_address",
|
||||
|
||||
@@ -1128,6 +1128,8 @@ extern value *default_value_from_register (gdbarch *gdbarch, type *type,
|
||||
int regnum,
|
||||
const frame_info_ptr &this_frame);
|
||||
|
||||
extern ULONGEST default_dwarf2_reg_piece_offset (gdbarch *gdbarch, int regnum, ULONGEST size);
|
||||
|
||||
extern struct value *value_from_register (struct type *type, int regnum,
|
||||
const frame_info_ptr &frame);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user