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

Message ID 20250111084519.4469-1-tdevries@suse.de
State New
Headers
Series [gdb/tdep] Fix gdb.ada/O2_float_param.exp on s390x-linux |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Test passed

Commit Message

Tom de Vries Jan. 11, 2025, 8:45 a.m. UTC
  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 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
---
 gdb/s390-tdep.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)


base-commit: e564115c8a0e8f9b993cf0add01fa34548005d20
  

Patch

diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c
index 36a70d8642c..c57b6119e63 100644
--- a/gdb/s390-tdep.c
+++ b/gdb/s390-tdep.c
@@ -2310,6 +2310,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);
 }