]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commit
[gdb/tdep] Fix gdb.base/store.exp on s390x
authorTom de Vries <tdevries@suse.de>
Wed, 15 Jan 2025 16:02:00 +0000 (17:02 +0100)
committerTom de Vries <tdevries@suse.de>
Wed, 15 Jan 2025 16:02:00 +0000 (17:02 +0100)
commit1722f289eea6f3db2a82aa577aedc87d7a215ead
tree8c12e55eec8f4ae06929672a1871e357dea92b90
parentb034bb38772a0e1c16153ee7c68b4206421548d0
[gdb/tdep] Fix gdb.base/store.exp on s390x

On s390x-linux, I get:
...
(gdb) print l^M
$29 = 0^M
(gdb) FAIL: gdb.base/store.exp: var doublest l; print old l, expecting -1
...

So, we're in wack_doublest trying to print l, which is a copy of parameter u:
...
  register doublest l = u, r = v;
...
which does have the expected value:
...
(gdb) p u
$1 = -1
...
which is a long double, 16 bytes and looks like this:
...
(gdb) p /x u
$3 = 0xbfff0000000000000000000000000000
...

Parameter u is passed in two registers:
...
 <2><6a5>: Abbrev Number: 15 (DW_TAG_formal_parameter)
    <6a6>   DW_AT_name        : v
    <69e>   DW_AT_location    : 6 byte block: 50 93 8 51 93 8 \
      (DW_OP_reg0 (r0); DW_OP_piece: 8; DW_OP_reg1 (r1); DW_OP_piece: 8)
...
and indeed we find the msw in r0 and the lsw in r1:
...
(gdb) p /x $r0
$4 = 0xbfff000000000000
(gdb) p /x $r1
$5 = 0x0
(gdb)
...

Likewise, variable l consists of two registers:
...
 <2><6b5>: Abbrev Number: 13 (DW_TAG_variable)
    <6b6>   DW_AT_name        : l
    <6be>   DW_AT_location    : 6 byte block: 68 93 8 69 93 8 \
      (DW_OP_reg24 (f8); DW_OP_piece: 8; DW_OP_reg25 (f10); DW_OP_piece: 8)
...
and we find the same values there:
...
(gdb) p /x $f8
$6 = 0xbfff000000000000
(gdb) p /x $f10
$7 = 0x0
...

So, we get the expected results when fetching the value from two gprs, but not
when fetching the value from two fprs.

When fetching the values from the two fprs, we stumble upon a particularity of
the DWARF register numbers as defined by the s390x ABI [1]: dwarf register 24
maps to both floating-point register f8 (8 bytes), and vector register v8
(16 bytes).

In s390_dwarf_reg_to_regnum, it's determined which of the two is chosen, and
if available vector registers are preferred over floating-point registers, so
v8 is chosen, and used to fetch the value.

Since the size of the DW_OP_piece is 8 bytes, and the register size is 16
bytes, this bit in rw_pieced_value is activated:
...
    /* If the piece is located in a register, but does not
       occupy the entire register, the placement of the piece
       within that register is defined by the ABI. */
    bits_to_skip
      += 8 * gdbarch_dwarf2_reg_piece_offset (arch, gdb_regnum,
      p->size / 8);
...
but since the default implemention default_dwarf2_reg_piece_offset does not
match the s390x ABI, we get the wrong answer.

This is a known problem, see FOSDEM 2018 presentation "DWARF Pieces And Other
DWARF Location Woes" [2].

Fix this by adding s390_dwarf2_reg_piece_offset, roughly implementing the same
logic as in s390_value_from_register.

Tested on s390x-linux.

Approved-By: Tom Tromey <tom@tromey.com>
[1] https://github.com/IBM/s390x-abi
[2] https://archive.fosdem.org/2018/schedule/event/dwarfpieces
gdb/s390-tdep.c