aboutsummaryrefslogtreecommitdiff
path: root/gdb/dwarf2-frame.c
diff options
context:
space:
mode:
authorJoel Brobecker <brobecker@adacore.com>2013-10-31 01:36:21 -0400
committerJoel Brobecker <brobecker@adacore.com>2013-11-14 22:38:48 -0500
commit0acf8b658c00c8a3cc922c69a2d7277cb5f1a572 (patch)
treed0955da99bb3b10889c7df7b9de3137e2b0f9a46 /gdb/dwarf2-frame.c
parent9055360d4a69313949c3535ec065080cb814367d (diff)
downloadfsf-binutils-gdb-0acf8b658c00c8a3cc922c69a2d7277cb5f1a572.zip
fsf-binutils-gdb-0acf8b658c00c8a3cc922c69a2d7277cb5f1a572.tar.gz
fsf-binutils-gdb-0acf8b658c00c8a3cc922c69a2d7277cb5f1a572.tar.bz2
Fix DW_OP_GNU_regval_type with FP registers
Consider the following code, compiled at -O2 on ppc-linux: procedure Increment (Val : in out Float; Msg : String); The implementation does not really matter in this case). In our example, this function is being called from a function with Param_1 set to 99.0. Trying to break inside that function, and running until reaching that breakpoint yields: (gdb) b increment Breakpoint 1 at 0x100014b4: file callee.adb, line 6. (gdb) run Starting program: /[...]/foo Breakpoint 1, callee.increment (val=99.0, val@entry=0.0, msg=...) at callee.adb:6 6 if Val > 200.0 then The @entry value for parameter "val" is incorrect, it should be 99.0. The associated call-site parameter DIE looks like this: .uleb128 0xc # (DIE (0x115) DW_TAG_GNU_call_site_parameter) .byte 0x2 # DW_AT_location .byte 0x90 # DW_OP_regx .uleb128 0x21 .byte 0x3 # DW_AT_GNU_call_site_value .byte 0xf5 # DW_OP_GNU_regval_type .uleb128 0x3f .uleb128 0x25 The DW_AT_GNU_call_site_value uses a DW_OP_GNU_regval_type operation, referencing register 0x3f=63, which is $f31, an 8-byte floating register. In that register, the value is stored using the usual 8-byte float format: (gdb) info float f31 99.0 (raw 0x4058c00000000000) The current code evaluating DW_OP_GNU_regval_type operations currently is (dwarf2expr.c:execute_stack_op): result = (ctx->funcs->read_reg) (ctx->baton, reg); result_val = value_from_ulongest (address_type, result); result_val = value_from_contents (type, value_contents_all (result_val)); What the ctx->funcs->read_reg function does is read the contents of the register as if it contained an address. The rest of the code continues that assumption, thinking it's OK to then use that to create an address/ulongest struct value, which we then re-type to the type specified by DW_OP_GNU_regval_type. We're getting 0.0 above because the read_reg implementations end up treating the contents of the FP register as an integral, reading only 4 out of the 8 bytes. Being a big-endian target, we read the high-order ones, which gives us zero. This patch fixes the problem by introducing a new callback to read the contents of a register as a given type, and then adjust the handling of DW_OP_GNU_regval_type to use that new callback. gdb/ChangeLog: * dwarf2expr.h (struct dwarf_expr_context_funcs) <read_reg>: Extend the documentation a bit. <get_reg_value>: New field. * dwarf2loc.c (dwarf_expr_get_reg_value) (needs_frame_get_reg_value): New functions. (dwarf_expr_ctx_funcs, needs_frame_ctx_funcs): Add "get_reg_value" callback. * dwarf2-frame.c (get_reg_value): New function. (dwarf2_frame_ctx_funcs): Add "get_reg_value" callback. * dwarf2expr.c (execute_stack_op) <DW_OP_GNU_regval_type>: Use new callback to compute result_val. gdb/testsuite/ChangeLog: * gdb.ada/O2_float_param: New testcase.
Diffstat (limited to 'gdb/dwarf2-frame.c')
-rw-r--r--gdb/dwarf2-frame.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c
index e05236f..b425d94 100644
--- a/gdb/dwarf2-frame.c
+++ b/gdb/dwarf2-frame.c
@@ -306,6 +306,18 @@ read_reg (void *baton, int reg)
return unpack_long (register_type (gdbarch, regnum), buf);
}
+/* Implement struct dwarf_expr_context_funcs' "get_reg_value" callback. */
+
+static struct value *
+get_reg_value (void *baton, struct type *type, int reg)
+{
+ struct frame_info *this_frame = (struct frame_info *) baton;
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ int regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
+
+ return value_from_register (type, regnum, this_frame);
+}
+
static void
read_mem (void *baton, gdb_byte *buf, CORE_ADDR addr, size_t len)
{
@@ -347,6 +359,7 @@ register %s (#%d) at %s"),
static const struct dwarf_expr_context_funcs dwarf2_frame_ctx_funcs =
{
read_reg,
+ get_reg_value,
read_mem,
ctx_no_get_frame_base,
ctx_no_get_frame_cfa,