Commit graph

1 commit

Author SHA1 Message Date
Joel Brobecker
0acf8b658c 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.
2013-11-14 22:38:48 -05:00