[binutils-gdb] [gdb/tdep] Fix gdb.ada/O2_float_param.exp on s390x-linux

Tom de Vries vries@sourceware.org
Fri Jan 24 15:43:30 GMT 2025


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=fb570a6fe3b74fa230fcbb94a60c56abebb953be

commit fb570a6fe3b74fa230fcbb94a60c56abebb953be
Author: Tom de Vries <tdevries@suse.de>
Date:   Fri Jan 24 16:43:52 2025 +0100

    [gdb/tdep] Fix gdb.ada/O2_float_param.exp on s390x-linux
    
    With test-case gdb.ada/O2_float_param.exp on s390x-linux, I get:
    ...
     (gdb) frame^M
     #0  callee.increment (val=99.0, val@entry=<error reading variable: \
       register has not been saved in frame>, msg=...) at callee.adb:19^M
     19         procedure Increment (Val : in out Float; Msg: String) is^M
     (gdb) FAIL: $exp: scenario=all: frame
    ...
    
    The frame command calls read_frame_arg to get:
    - the current value of val, and
    - the value of val at function entry.
    
    The first scenario succeeds, and the second scenario fails.
    
    For context and contrast, let's also investigate the first scenario: getting
    the current value of val.
    
    Function parameter val:
    ...
     <2><b51>: Abbrev Number: 4 (DW_TAG_formal_parameter)
        <b52>   DW_AT_name        : val
        <b58>   DW_AT_type        : <0xb86>
        <b5c>   DW_AT_location    : 0xab (location list)
    ...
    has location list:
    ...
        000000ab 0000000001002928 0000000001002967
          (DW_OP_reg16 (f0))
        000000be 0000000001002967 0000000001002968
          (DW_OP_reg24 (f8))
        000000d1 0000000001002968 0000000001002974
          (DW_OP_GNU_regval_type: 24 (f8) <0xb29>;
           DW_OP_GNU_const_type: <0xb29>  4 byte block: 3f 80 0 0 ; DW_OP_plus;
           DW_OP_stack_value)
        000000ef 0000000001002974 0000000001002982
          (DW_OP_GNU_entry_value: (DW_OP_GNU_regval_type: 16 (f0) <0xb29>);
           DW_OP_GNU_const_type: <0xb29>  4 byte block: 3f 80 0 0 ; DW_OP_plus;
           DW_OP_stack_value)
        0000010f <End of list>
    ...
    and since we're stopped at address 0x1002928:
    ...
    (gdb) print $pc
    $1 = (access procedure) 0x1002928 <callee.increment>
    ...
    we get the value from dwarf register 16.
    
    The s390x ABI [1] specifies that dwarf register 16 maps onto 8-byte register
    f0 or 16-byte register v0 (where f0 is part of v0), and in this case (because
    the v0 register is available) s390_dwarf_reg_to_regnum maps it to v0.
    
    Val is only 4 bytes:
    ...
    (gdb) ptype val
    type = <4-byte float>
    ...
    and s390_value_from_register takes care to get the value from the correct part
    of v0.
    
    The value of v0 is found in the prologue cache, and the value of parameter val
    is printed.
    
    Now the second scenario: getting the value of val at function entry.
    
    FWIW, since we're stopped at function entry, we could simply return the same
    value, reading the same register, but that's currently not implemented [2].
    
    Instead we start from the fact that val is in dwarf reg 16 at function entry,
    and then use call site information:
    ...
     <4><cf7>: Abbrev Number: 13 (DW_TAG_GNU_call_site)
        <cf8>   DW_AT_low_pc      : 0x1002a46
        <d00>   DW_AT_abstract_origin: <0xdda>
     <5><d04>: Abbrev Number: 12 (DW_TAG_GNU_call_site_parameter)
        <d05>   DW_AT_location    : 1 byte block: 60        (DW_OP_reg16 (f0))
        <d07>   DW_AT_GNU_call_site_value: 3 byte block: f5 18 2d   \
                  (DW_OP_GNU_regval_type: 24 (f8) <0xc42>)
     <5><d0b>: Abbrev Number: 12 (DW_TAG_GNU_call_site_parameter)
    ...
    to conclude that the value we're looking for is in dwarf reg 24, which
    s390_dwarf_reg_to_regnum maps to v8.
    
    As before, s390_value_from_register takes care to get the value from the
    correct part of v8.
    
    However, v8 is not available in the prologue cache, and we take a different
    path and end up in s390_unwind_pseudo_register, where v8 and similar
    (regnum_is_vxr_full) is unhandled, and we get:
    ...
       return value::allocate_optimized_out (type);
    ...
    which eventually causes the "error reading variable: register has not been
    saved in frame".
    
    Fix this by handling the regnum_is_vxr_full case in
    s390_unwind_pseudo_register, similar to how that is done in
    s390_pseudo_register_read.
    
    Tested on s390x-linux.
    
    This also fixes test-case gdb.base/savedregs.exp.
    
    [1] https://github.com/IBM/s390x-abi
    [2] https://sourceware.org/pipermail/gdb-patches/2024-September/211589.html

Diff:
---
 gdb/s390-tdep.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c
index 223cb20ebe5..41faf93c423 100644
--- a/gdb/s390-tdep.c
+++ b/gdb/s390-tdep.c
@@ -2332,6 +2332,22 @@ s390_unwind_pseudo_register (const frame_info_ptr &this_frame, int regnum)
 	return value_cast (type, val);
     }
 
+  if (regnum_is_vxr_full (tdep, regnum))
+    {
+      struct value *val = value::allocate_register (this_frame, regnum);
+
+      int reg = regnum - tdep->v0_full_regnum;
+      struct value *val1
+	= frame_unwind_register_value (this_frame, S390_F0_REGNUM + reg);
+      struct value *val2
+	= frame_unwind_register_value (this_frame, S390_V0_LOWER_REGNUM + reg);
+
+      val1->contents_copy (val, 0, 0, 8);
+      val2->contents_copy (val, 8, 0, 8);
+
+      return value_cast (type, val);
+    }
+
   return value::allocate_optimized_out (type);
 }


More information about the Gdb-cvs mailing list