Re: interface to partial support for DW_OP_piece in dwarf2expr.[ch]

Jim Blandy
2004-08-10T19:55:59Z

To put (part of) the discussion of the Dwarf piece support on a
concrete basis, here's a patch that adds the gdbarch method; it
depends on the dwarf2expr piece interface patch I posted earlier.

This change, or something like it, would allow immediate improvements
over GDB's current behavior, and I don't see that it has much
structural cost:

- It doesn't affect the design of full scattered values: when that is
implemented, dwarf2_evaluate_loc_desc will just become able to
construct 'struct value' objects for more kinds of Dwarf expression
results.

- When we do support full scattered values, the clause this patch adds
to dwarf2_evaluate_loc_desc, the gdbarch method, and whatever
arch-specific implementations people have written for it can be
simply deleted, with no change in user-visible behavior.

2004-08-09 Jim Blandy <jimb@redhat.com>

* gdbarch.sh (dwarf_simplify_register_pieces): New method.
Add forward declaration for 'struct dwarf_expr_piece'.
* gdbarch.c, gdbarch.h: Regenerated.
* dwarf2loc.c (dwarf2_evaluate_loc_desc): Try to simplify
multi-piece expression results before giving up.
* arch-utils.c (dwarf_never_simplify_pieces): New function.
* arch-utils.h (struct dwarf_expr_piece): Forward decl for struct
type, used in ...
(dwarf_never_simplify_pieces): New declaration.

diff -crp -x '*~' -x '.#*' -x CVS gdb/gdbarch.sh gdb/gdbarch.sh
*** gdb/gdbarch.sh 2004-08-09 19:29:28.000000000 -0500
--- gdb/gdbarch.sh 2004-08-10 11:31:22.000000000 -0500
*************** f:=:int:dwarf_reg_to_regnum:int dwarf_re
*** 451,456 ****
--- 451,480 ----
# Convert from an sdb register number to an internal gdb register number.
f:=:int:sdb_reg_to_regnum:int sdb_regnr:sdb_regnr::no_op_reg_to_regnum::0
f:=:int:dwarf2_reg_to_regnum:int dwarf2_regnr:dwarf2_regnr::no_op_reg_to_regnum::0
+
+ # On some architectures, GDB has registers that Dwarf treats as the
+ # concatenation of two separate registers. For example, PowerPC
+ # variants implementing the SPE APU have 64-bit general-purpose
+ # registers. GDB refers to the lower 32 bits of each register as 'r0'
+ # -- 'r31', and the full 64-bit registers as 'ev0' -- 'ev31'.
+ # However, the Dwarf register numbering treats the upper halves as
+ # separate registers.
+ #
+ # Dwarf location expressions describe variables allocated to such
+ # registers using a series of DW_OP_piece operations. In the case
+ # above, the expressions would have the form:
+ #
+ # <upper half> DW_OP_piece 4 <lower half> DW_OP_piece 4.
+ #
+ # However, since GDB does have a register that corresponds to the
+ # entire variable, it can simply say the variable lives in that
+ # register; it needn't use a complicated location description.
+ #
+ # Given an array of NUM_PIECES pieces PIECES, return the number of the
+ # register that is equivalent to those pieces, or -1 if there is no
+ # such register.
+ m::int:dwarf_simplify_register_pieces:int num_pieces, struct dwarf_expr_piece *pieces:num_pieces, pieces::dwarf_never_simplify_pieces
+
f:=:const char *:register_name:int regnr:regnr

# REGISTER_TYPE is a direct replacement for DEPRECATED_REGISTER_VIRTUAL_TYPE.
*************** struct regset;
*** 773,778 ****
--- 797,803 ----
struct disassemble_info;
struct target_ops;
struct obstack;
+ struct dwarf_expr_piece;

extern struct gdbarch *current_gdbarch;

diff -crp -x '*~' -x '.#*' -x CVS gdb/dwarf2loc.c gdb/dwarf2loc.c
*** gdb/dwarf2loc.c 2004-08-10 02:01:24.000000000 -0500
--- gdb/dwarf2loc.c 2004-08-10 11:34:39.000000000 -0500
*************** dwarf2_evaluate_loc_desc (struct symbol
*** 230,240 ****
dwarf_expr_eval (ctx, data, size);
if (ctx->num_pieces > 0)
{
! /* We haven't implemented splicing together pieces from
! arbitrary sources yet. */
! error ("The value of variable '%s' is distributed across several\n"
! "locations, and GDB cannot access its value.\n",
! SYMBOL_NATURAL_NAME (var));
}
else if (ctx->in_reg)
{
--- 230,247 ----
dwarf_expr_eval (ctx, data, size);
if (ctx->num_pieces > 0)
{
! CORE_ADDR simplified
! = gdbarch_dwarf_simplify_register_pieces (arch, ctx->num_pieces,
! ctx->pieces);
! if (simplified >= 0)
! retval = value_from_register (SYMBOL_TYPE (var), simplified, frame);
!
! /* We haven't implemented the more complex case of splicing
! together pieces from arbitrary sources yet. */
! else
! error ("The value of variable '%s' is distributed across several\n"
! "locations, and GDB cannot access its value.\n",
! SYMBOL_NATURAL_NAME (var));
}
else if (ctx->in_reg)
{
diff -crp -x '*~' -x '.#*' -x CVS gdb/arch-utils.h gdb/arch-utils.h
*** gdb/arch-utils.h 2004-08-09 19:29:27.000000000 -0500
--- gdb/arch-utils.h 2004-08-10 11:32:03.000000000 -0500
*************** struct frame_info;
*** 28,33 ****
--- 28,34 ----
struct minimal_symbol;
struct type;
struct gdbarch_info;
+ struct dwarf_expr_piece;

/* gdbarch trace variable */
extern int gdbarch_debug;
*************** extern gdbarch_convert_from_func_ptr_add
*** 72,77 ****
--- 73,82 ----

extern int no_op_reg_to_regnum (int reg);

+ /* Dwarf piece simplifier that never simplifies anything. */
+ extern int dwarf_never_simplify_pieces (int num_pieces,
+ struct dwarf_expr_piece *pieces);
+
/* Do nothing version of elf_make_msymbol_special. */

void default_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym);
diff -crp -x '*~' -x '.#*' -x CVS gdb/arch-utils.c gdb/arch-utils.c
*** gdb/arch-utils.c 2004-08-09 19:29:27.000000000 -0500
--- gdb/arch-utils.c 2004-08-10 11:32:17.000000000 -0500
*************** no_op_reg_to_regnum (int reg)
*** 228,233 ****
--- 228,240 ----
return reg;
}

+ int
+ dwarf_never_simplify_pieces (int num_pieces,
+ struct dwarf_expr_piece *pieces)
+ {
+ return -1;
+ }
+
void
default_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym)
{
diff -crp -x '*~' -x '.#*' -x CVS gdb/gdbarch.c gdb/gdbarch.c
*** gdb/gdbarch.c 2004-08-09 19:29:28.000000000 -0500
--- gdb/gdbarch.c 2004-08-10 11:28:42.000000000 -0500
*************** struct gdbarch
*** 155,160 ****
--- 155,161 ----
gdbarch_dwarf_reg_to_regnum_ftype *dwarf_reg_to_regnum;
gdbarch_sdb_reg_to_regnum_ftype *sdb_reg_to_regnum;
gdbarch_dwarf2_reg_to_regnum_ftype *dwarf2_reg_to_regnum;
+ gdbarch_dwarf_simplify_register_pieces_ftype *dwarf_simplify_register_pieces;
gdbarch_register_name_ftype *register_name;
gdbarch_register_type_ftype *register_type;
gdbarch_deprecated_register_byte_ftype *deprecated_register_byte;
*************** struct gdbarch startup_gdbarch =
*** 281,286 ****
--- 282,288 ----
0, /* dwarf_reg_to_regnum */
0, /* sdb_reg_to_regnum */
0, /* dwarf2_reg_to_regnum */
+ dwarf_never_simplify_pieces, /* dwarf_simplify_register_pieces */
0, /* register_name */
0, /* register_type */
generic_register_byte, /* deprecated_register_byte */
*************** gdbarch_alloc (const struct gdbarch_info
*** 414,419 ****
--- 416,422 ----
current_gdbarch->dwarf_reg_to_regnum = no_op_reg_to_regnum;
current_gdbarch->sdb_reg_to_regnum = no_op_reg_to_regnum;
current_gdbarch->dwarf2_reg_to_regnum = no_op_reg_to_regnum;
+ current_gdbarch->dwarf_simplify_register_pieces = dwarf_never_simplify_pieces;
current_gdbarch->deprecated_register_byte = generic_register_byte;
current_gdbarch->deprecated_fp_regnum = -1;
current_gdbarch->call_dummy_location = AT_ENTRY_POINT;
*************** verify_gdbarch (struct gdbarch *current_
*** 541,546 ****
--- 544,552 ----
/* Skip verify of dwarf_reg_to_regnum, invalid_p == 0 */
/* Skip verify of sdb_reg_to_regnum, invalid_p == 0 */
/* Skip verify of dwarf2_reg_to_regnum, invalid_p == 0 */
+ if ((GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL)
+ && (current_gdbarch->dwarf_simplify_register_pieces == dwarf_never_simplify_pieces))
+ fprintf_unfiltered (log, "\n\tdwarf_simplify_register_pieces");
/* Skip verify of register_type, has predicate */
/* Skip verify of deprecated_register_byte, has predicate */
/* Skip verify of unwind_dummy_id, has predicate */
*************** gdbarch_dump (struct gdbarch *current_gd
*** 1027,1032 ****
--- 1033,1041 ----
fprintf_unfiltered (file,
"gdbarch_dump: dwarf_reg_to_regnum = <0x%lx>\n",
(long) current_gdbarch->dwarf_reg_to_regnum);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: dwarf_simplify_register_pieces = <0x%lx>\n",
+ (long) current_gdbarch->dwarf_simplify_register_pieces);
#ifdef ECOFF_REG_TO_REGNUM
fprintf_unfiltered (file,
"gdbarch_dump: %s # %s\n",
*************** set_gdbarch_dwarf2_reg_to_regnum (struct
*** 2220,2225 ****
--- 2229,2251 ----
gdbarch->dwarf2_reg_to_regnum = dwarf2_reg_to_regnum;
}

+ int
+ gdbarch_dwarf_simplify_register_pieces (struct gdbarch *gdbarch, int num_pieces, struct dwarf_expr_piece *pieces)
+ {
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->dwarf_simplify_register_pieces != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_dwarf_simplify_register_pieces called\n");
+ return gdbarch->dwarf_simplify_register_pieces (gdbarch, num_pieces, pieces);
+ }
+
+ void
+ set_gdbarch_dwarf_simplify_register_pieces (struct gdbarch *gdbarch,
+ gdbarch_dwarf_simplify_register_pieces_ftype dwarf_simplify_register_pieces)
+ {
+ gdbarch->dwarf_simplify_register_pieces = dwarf_simplify_register_pieces;
+ }
+
const char *
gdbarch_register_name (struct gdbarch *gdbarch, int regnr)
{
diff -crp -x '*~' -x '.#*' -x CVS gdb/gdbarch.h gdb/gdbarch.h
*** gdb/gdbarch.h 2004-08-09 19:29:28.000000000 -0500
--- gdb/gdbarch.h 2004-08-10 11:28:42.000000000 -0500
*************** struct regset;
*** 49,54 ****
--- 49,55 ----
struct disassemble_info;
struct target_ops;
struct obstack;
+ struct dwarf_expr_piece;

extern struct gdbarch *current_gdbarch;

*************** extern void set_gdbarch_dwarf2_reg_to_re
*** 461,466 ****
--- 462,493 ----
#define DWARF2_REG_TO_REGNUM(dwarf2_regnr) (gdbarch_dwarf2_reg_to_regnum (current_gdbarch, dwarf2_regnr))
#endif

+ /* On some architectures, GDB has registers that Dwarf treats as the
+ concatenation of two separate registers. For example, PowerPC
+ variants implementing the SPE APU have 64-bit general-purpose
+ registers. GDB refers to the lower 32 bits of each register as 'r0'
+ -- 'r31', and the full 64-bit registers as 'ev0' -- 'ev31'.
+ However, the Dwarf register numbering treats the upper halves as
+ separate registers.
+
+ Dwarf location expressions describe variables allocated to such
+ registers using a series of DW_OP_piece operations. In the case
+ above, the expressions would have the form:
+
+ <upper half> DW_OP_piece 4 <lower half> DW_OP_piece 4.
+
+ However, since GDB does have a register that corresponds to the
+ entire variable, it can simply say the variable lives in that
+ register; it needn't use a complicated location description.
+
+ Given an array of NUM_PIECES pieces PIECES, return the number of the
+ register that is equivalent to those pieces, or -1 if there is no
+ such register. */
+
+ typedef int (gdbarch_dwarf_simplify_register_pieces_ftype) (struct gdbarch *gdbarch, int num_pieces, struct dwarf_expr_piece *pieces);
+ extern int gdbarch_dwarf_simplify_register_pieces (struct gdbarch *gdbarch, int num_pieces, struct dwarf_expr_piece *pieces);
+ extern void set_gdbarch_dwarf_simplify_register_pieces (struct gdbarch *gdbarch, gdbarch_dwarf_simplify_register_pieces_ftype *dwarf_simplify_register_pieces);
+
typedef const char * (gdbarch_register_name_ftype) (int regnr);
extern const char * gdbarch_register_name (struct gdbarch *gdbarch, int regnr);
extern void set_gdbarch_register_name (struct gdbarch *gdbarch, gdbarch_register_name_ftype *register_name);