[PATCH v3 03/11] s390: Initial support to generate .sframe from CFI directives in assembler
Indu Bhagat
indu.bhagat@oracle.com
Sat Jul 5 23:03:10 GMT 2025
On 6/27/25 4:08 AM, Jens Remus wrote:
> This introduces initial support to generate .sframe from CFI directives
> in assembler on s390 64-bit (s390x). Due to SFrame V2 format
> limitations it has the following limitations, some of them getting
> addressed by subsequent patches, which cause generation of SFrame FDE
> to be skipped:
>
> - SFrame FP/RA tracking only supports register contents being saved on
> the stack (i.e. .cfi_offset). It does not support FP/RA register
> contents being saved in other registers (i.e. .cfi_register). GCC on
> s390x can be observed to save the FP/RA register contents in floating-
> point registers, but only in leaf functions.
> This issue is detailed further and resolved in the subsequent commit
> "s390: Represent FP/RA saved in register in SFrame".
>
> - SFrame FP/RA tracking cannot represent FP without RA saved. This is
> because the format assumes SFrame FDE offset2 to be the RA offset, if
> there are two offsets, and offset3 to be the FP offset, if there are
> three offsets. There is no mean to distinguish whether offset2 is the
> RA or FP offset, if there are only two offsets.
> This issue is detailed further and resolved in the subsequent commit
> "s390: Represent FP without RA saved in SFrame".
>
> - SFrame assumes a dedicated FP register number. The s390x ELF ABI [1]
> does only designate register 11 as preferred FP register number. In
> general GCC and Clang on s390x use register 11 as frame pointer.
> GCC on s390x can be observed to use register 14 as frame pointer in
> the stack clash protector in the function prologue.
> glibc on s390x contains hand-written assembler code that uses
> register 12 as frame pointer.
>
> This s390x support is largely based on the AArch64 support from commit
> b52c4ee46657 ("gas: generate .sframe from CFI directives").
>
> The SFrame ABI/arch identifier SFRAME_ABI_S390X_ENDIAN_BIG is introduced
> for s390x and added to the SFrame format specification.
>
> The s390x ELF ABI [1] specifies the following C calling conventions for
> s390x architecture:
> - Register 15 is the stack pointer (SP).
> - Register 14 contains the return address (RA) at function entry.
> - There is no dedicated frame pointer register. Register 11 is the
> preferred frame pointer (FP). [2] GCC and Clang in general use
> register 11 as frame pointer.
> - The CFA is defined as SP at call site +160. [3] The SP at call site
> can therefore be derived from the CFA using a SP value offset from CFA
> of -160.
>
> The s390x ELF ABI [1] does not assign any standard save slot to each
> register in the register save area of a stack frame. Neither the
> return address (RA, r14) nor preferred frame pointer (FP, r11)
> necessarily need to be saved. Therefore SFrame RA and FP tracking is
> used.
>
> Support for SFrame on s390 is only enabled for the 64-bit s390x ELF ABI
> (z/Architecture with 64-bit addressing mode). It is disabled for the
> 32-bit s390 ELF ABI (ESA/390 or z/Architecture with 32-bit addressing
> mode).
>
> s390x-specific SFrame assembler and linker tests are added, including
> error tests for use of a non-preferred frame pointer (FP) register and
> specification of a non-default return address (RA) register.
>
> [1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases
> [2]: s390x ELF ABI, commit f00421825979 ("Add information about the frame
> pointer register"),
> https://github.com/IBM/s390x-abi/commit/f00421825979
> [3]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"),
> https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88
>
> include/
> * sframe.h: Add reference to s390x architecture in comments.
> (SFRAME_ABI_S390X_ENDIAN_BIG): Define SFrame ABI/arch identifier
> for s390x.
> (SFRAME_S390X_SP_VAL_OFFSET): Define s390x-specific SP value
> offset from CFA.
>
> libsframe/
> * sframe.c (need_swapping): Add SFRAME_ABI_S390X_ENDIAN_BIG.
> * doc/sframe-spec.texi (SFRAME_ABI_S390X_ENDIAN_BIG, s390x,
> SFRAME_S390X_SP_VAL_OFFSET): Document SFrame ABI/arch identifier
> for s390x, add references to s390x architecture, and document
> s390x-specifics, such as the SP value offset from CFA of -160.
>
> gas/
> * config/tc-s390.h: s390x support to generate .sframe from CFI
> directives in assembler.
> (support_sframe_p): Define.
> (SFRAME_CFA_SP_REG, SFRAME_CFA_FP_REG, SFRAME_CFA_RA_REG):
> Define.
> (sframe_ra_tracking_p): Define.
> (sframe_cfa_ra_offset): Define.
> (sframe_get_abi_arch): Define.
> * config/tc-s390.c: s390x support to generate .sframe from CFI
> directives in assembler.
> (s390_sframe_cfa_sp_reg, s390_sframe_cfa_fp_reg,
> s390_sframe_cfa_ra_reg): New. Initialize to DWARF register
> numbers of stack pointer (SP, r15), preferred frame pointer
> (FP, r11), and return address (RA, r14) registers.
> (s390_support_sframe_p): New function. Return true if s390x.
> (s390_sframe_ra_tracking_p): New function. Return true.
> (s390_sframe_cfa_ra_offset): New function. Return
> SFRAME_CFA_FIXED_RA_INVALID.
> (s390_sframe_get_abi_arch): New function. Return
> SFRAME_ABI_S390X_ENDIAN_BIG if s390x, otherwise zero.
> * gen-sframe.c: Add reference to s390x architecture in comments.
> (sframe_xlate_do_val_offset): Add support for s390x-specific
> SFRAME_S390X_SP_VAL_OFFSET.
> * NEWS: Add news entry.
>
> gas/testsuite/
> * gas/cfi-sframe/cfi-sframe.exp: Enable common SFrame tests for
> s390x. Add s390x-specific SFrame (error) tests.
> * gas/cfi-sframe/cfi-sframe-s390x-1.d: New s390x-specific SFrame
> test.
> * gas/cfi-sframe/cfi-sframe-s390x-1.s: Likewise.
> * gas/cfi-sframe/cfi-sframe-s390x-2.d: Likewise.
> * gas/cfi-sframe/cfi-sframe-s390x-2.s: Likewise.
> * gas/cfi-sframe/cfi-sframe-s390x-err-1.d: New s390x-specific
> SFrame error test that uses a non-default frame-pointer register
> as CFA base register.
> * gas/cfi-sframe/cfi-sframe-s390x-err-1.s: Likewise.
> * gas/cfi-sframe/cfi-sframe-s390x-err-2.d: Likewise.
> * gas/cfi-sframe/cfi-sframe-s390x-err-2.s: Likewise.
> * gas/cfi-sframe/cfi-sframe-s390x-err-3.d: New s390x-specific
> SFrame error test that uses a non-default return address
> register.
> * gas/cfi-sframe/cfi-sframe-s390x-err-3.s: Likewise.
> * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.d: New s390x-
> specific SFrame test that saves RA and FP individually on the
> stack.
> * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.s: Likewise.
> * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.d: New
> s390x-specific SFrame error test that saves FP and RA
> individually, to trigger FP without RA saved.
> * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.s: Likewise.
> * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d: New
> s390x-specific SFrame error test that saves FP and RA
> individually in registers.
> * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.s:
> Likewise.
> * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d: New
> s390x-specific SFrame error test that saves RA and FP
> individually in registers.
> * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.s:
> Likewise.
>
> ld/testsuite/
> * ld-s390/s390.exp: Add simple SFrame test.
> * ld-s390/sframe-simple-1.d: New simple SFrame test.
> * ld-s390/sframe-bar.s: Likewise.
> * ld-s390/sframe-foo.s: Likewise.
>
> Signed-off-by: Jens Remus <jremus@linux.ibm.com>
> ---
>
> Notes (jremus):
> Changes in V3:
> - Reword commit message, adding pointers to subsequent commits. (Indu)
> - Remove dash in terms "frame-pointer" and "return-address". (Indu)
> - Separate mnemonic from operand(s) in tests using tab. (Indu)
> - Follow the "No Trailing operator" rule in tests. (Indu)
> - Update "Changes from Version 1 to Version 2" in SFrame spec. (Indu)
> - Reword RA description in S390 section in SFrame spec. (Indu)
>
Thanks Jens.
This looks good to me.
Reviewed-by: Indu Bhagat <indu.bhagat@oracle.com>
One question below.
> Changes in V2:
> - Reword commit message (s390 to s390x). (Indu)
> - Fix typo in GNU ChangeLog. (Indu)
> - Reword comments on s390_sframe_cfa_{sp|fp|ra}_reg. (Indu)
> - Fix typo in comment on s390_sframe_get_abi_arch. (Indu)
> - Rename s390x-specific macros from *_S390_* to *_S390X_*. (Indu)
> - Use "s390x" instead of "S390" in comments and SFrame spec. (Indu)
> - Rename CFI SFrame test file names from s390 to s390x. (Indu)
> - Reword test names. Use s390x-default stack frame size of 160 bytes.
> - Adjust tests to commit bd9dc0a281a4 ("gas: sframe: reword diagnostic
> to address ambiguity")
> - Use const for s390_sframe_cfa_{sp|fp|ra}_reg. (Jan)
> - Mention SFRAME_S390X_SP_VAL_OFFSET in appendix "Generating Stack
> Traces using SFrame".
> - Reword SFrame specs for s390x. Mention when FP/RA may be unsaved.
> (Indu)
> - Reword NEWS ("s390 64-bit (s390x)").
>
> gas/NEWS | 3 +
> gas/config/tc-s390.c | 55 ++++++++++++++++
> gas/config/tc-s390.h | 31 +++++++++
> gas/gen-sframe.c | 8 ++-
> .../gas/cfi-sframe/cfi-sframe-s390x-1.d | 23 +++++++
> .../gas/cfi-sframe/cfi-sframe-s390x-1.s | 37 +++++++++++
> .../gas/cfi-sframe/cfi-sframe-s390x-2.d | 23 +++++++
> .../gas/cfi-sframe/cfi-sframe-s390x-2.s | 37 +++++++++++
> .../gas/cfi-sframe/cfi-sframe-s390x-err-1.d | 15 +++++
> .../gas/cfi-sframe/cfi-sframe-s390x-err-1.s | 37 +++++++++++
> .../gas/cfi-sframe/cfi-sframe-s390x-err-2.d | 15 +++++
> .../gas/cfi-sframe/cfi-sframe-s390x-err-2.s | 37 +++++++++++
> .../gas/cfi-sframe/cfi-sframe-s390x-err-3.d | 15 +++++
> .../gas/cfi-sframe/cfi-sframe-s390x-err-3.s | 5 ++
> .../cfi-sframe-s390x-fpra-offset-1.d | 22 +++++++
> .../cfi-sframe-s390x-fpra-offset-1.s | 15 +++++
> .../cfi-sframe-s390x-fpra-offset-err-1.d | 15 +++++
> .../cfi-sframe-s390x-fpra-offset-err-1.s | 15 +++++
> .../cfi-sframe-s390x-fpra-register-err-1.d | 15 +++++
> .../cfi-sframe-s390x-fpra-register-err-1.s | 15 +++++
> .../cfi-sframe-s390x-fpra-register-err-2.d | 15 +++++
> .../cfi-sframe-s390x-fpra-register-err-2.s | 15 +++++
> gas/testsuite/gas/cfi-sframe/cfi-sframe.exp | 18 +++++-
> include/sframe.h | 11 +++-
> ld/testsuite/ld-s390/s390.exp | 4 ++
> ld/testsuite/ld-s390/sframe-bar.s | 21 +++++++
> ld/testsuite/ld-s390/sframe-foo.s | 9 +++
> ld/testsuite/ld-s390/sframe-simple-1.d | 30 +++++++++
> libsframe/doc/sframe-spec.texi | 63 ++++++++++++++++++-
> libsframe/sframe.c | 1 +
> 30 files changed, 615 insertions(+), 10 deletions(-)
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-1.d
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-1.s
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-2.d
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-2.s
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-1.d
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-1.s
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-2.d
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-2.s
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-3.d
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-3.s
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.d
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.s
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.d
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.s
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.s
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d
> create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.s
> create mode 100644 ld/testsuite/ld-s390/sframe-bar.s
> create mode 100644 ld/testsuite/ld-s390/sframe-foo.s
> create mode 100644 ld/testsuite/ld-s390/sframe-simple-1.d
>
> diff --git a/gas/NEWS b/gas/NEWS
> index f0ffe2db54ba..a926e9761196 100644
> --- a/gas/NEWS
> +++ b/gas/NEWS
> @@ -1,5 +1,8 @@
> -*- text -*-
>
> +* Add initial support to generate SFrame stack trace information (.sframe)
> + from CFI directives on s390 64-bit (s390x).
> +
> * Support for x86 AVX10.2 256 bit rounding has been dropped, as all the
> hardware would directly support 512 bit vecotr width.
>
> diff --git a/gas/config/tc-s390.c b/gas/config/tc-s390.c
> index 6e9dca029842..605f7ffe6e1b 100644
> --- a/gas/config/tc-s390.c
> +++ b/gas/config/tc-s390.c
> @@ -24,6 +24,8 @@
> #include "subsegs.h"
> #include "dwarf2dbg.h"
> #include "dw2gencfi.h"
> +#include "sframe.h"
> +#include "gen-sframe.h"
>
> #include "opcode/s390.h"
> #include "elf/s390.h"
> @@ -97,6 +99,17 @@ const char FLT_CHARS[] = "dD";
> /* The dwarf2 data alignment, adjusted for 32 or 64 bit. */
> int s390_cie_data_alignment;
>
> +/* Register numbers used for SFrame stack trace info. */
> +
> +/* Designated stack pointer DWARF register number according to s390x ELF ABI. */
> +const unsigned int s390_sframe_cfa_sp_reg = 15;
> +
> +/* Preferred frame pointer DWARF register number according to s390x ELF ABI. */
> +const unsigned int s390_sframe_cfa_fp_reg = 11;
> +
> +/* Designated return address DWARF register number according to s390x ELF ABI. */
> +const unsigned int s390_sframe_cfa_ra_reg = DWARF2_DEFAULT_RETURN_COLUMN;
> +
> /* The target specific pseudo-ops which we support. */
>
> /* Define the prototypes for the pseudo-ops */
> @@ -2866,6 +2879,48 @@ tc_s390_regname_to_dw2regnum (char *regname)
> return regnum;
> }
>
> +/* Whether SFrame stack trace info is supported. */
> +
> +bool
> +s390_support_sframe_p (void)
> +{
> + /* At this time, SFrame is supported for s390x (64-bit) only. */
> + return (s390_arch_size == 64);
> +}
> +
> +/* Specify if RA tracking is needed. */
> +
> +bool
> +s390_sframe_ra_tracking_p (void)
> +{
> + return true;
> +}
> +
> +/* Specify the fixed offset to recover RA from CFA.
> + (useful only when RA tracking is not needed). */
> +
> +offsetT
> +s390_sframe_cfa_ra_offset (void)
> +{
> + return (offsetT) SFRAME_CFA_FIXED_RA_INVALID;
> +}
> +
> +/* Get the abi/arch identifier for SFrame. */
> +
> +unsigned char
> +s390_sframe_get_abi_arch (void)
> +{
> + unsigned char sframe_abi_arch = 0;
> +
> + if (s390_support_sframe_p ())
> + {
> + gas_assert (target_big_endian);
> + sframe_abi_arch = SFRAME_ABI_S390X_ENDIAN_BIG;
> + }
> +
> + return sframe_abi_arch;
> +}
> +
> void
> s390_elf_final_processing (void)
> {
> diff --git a/gas/config/tc-s390.h b/gas/config/tc-s390.h
> index 9206c029a1c1..c92769e507b3 100644
> --- a/gas/config/tc-s390.h
> +++ b/gas/config/tc-s390.h
> @@ -98,3 +98,34 @@ extern int s390_cie_data_alignment;
> extern void s390_elf_final_processing (void);
>
> #define elf_tc_final_processing s390_elf_final_processing
> +
> +/* SFrame. */
> +
> +/* Whether SFrame stack trace info is supported. */
> +extern bool s390_support_sframe_p (void);
> +#define support_sframe_p s390_support_sframe_p
> +
> +/* The stack pointer DWARF register number for SFrame CFA tracking. */
> +extern const unsigned int s390_sframe_cfa_sp_reg;
> +#define SFRAME_CFA_SP_REG s390_sframe_cfa_sp_reg
> +
> +/* The frame pointer DWARF register number for SFrame CFA and FP tracking. */
> +extern const unsigned int s390_sframe_cfa_fp_reg;
> +#define SFRAME_CFA_FP_REG s390_sframe_cfa_fp_reg
> +
> +/* The return address DWARF register number for SFrame RA tracking. */
> +extern const unsigned int s390_sframe_cfa_ra_reg;
> +#define SFRAME_CFA_RA_REG s390_sframe_cfa_ra_reg
> +
> +/* Whether SFrame return address tracking is needed. */
> +extern bool s390_sframe_ra_tracking_p (void);
> +#define sframe_ra_tracking_p s390_sframe_ra_tracking_p
> +
> +/* The fixed offset from CFA for SFrame to recover the return address.
> + (useful only when SFrame RA tracking is not needed). */
> +extern offsetT s390_sframe_cfa_ra_offset (void);
> +#define sframe_cfa_ra_offset s390_sframe_cfa_ra_offset
> +
> +/* The abi/arch identifier for SFrame. */
> +unsigned char s390_sframe_get_abi_arch (void);
> +#define sframe_get_abi_arch s390_sframe_get_abi_arch
With (IIUC) no non-ELF targets for s390x, then, apart from the obvious
(s390x-linux as supported, s390-linux as not supported), are there other
targets that you'd recommend for testing / building ?
(Endianness related testing: covered by some cross builds for aarch64
target should suffice for the endian swapping code that cross builds for
s390x may use).
> diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
> index 2d1c1961fd7e..89a61df4449e 100644
> --- a/gas/gen-sframe.c
> +++ b/gas/gen-sframe.c
> @@ -707,7 +707,7 @@ output_sframe_internal (void)
> }
> out_one (fixed_ra_offset);
>
> - /* None of the AMD64, or AARCH64 ABIs need the auxiliary header.
> + /* None of the AMD64, AARCH64, or s390x ABIs need the auxiliary header.
> When the need does arise to use this field, the appropriate backend
> must provide this information. */
> out_one (0); /* Auxiliary SFrame header length. */
> @@ -1110,7 +1110,11 @@ sframe_xlate_do_val_offset (const struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_U
> if (cfi_insn->u.ri.reg == SFRAME_CFA_FP_REG
> || (sframe_ra_tracking_p () && cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG)
> /* Ignore SP reg, if offset matches assumed default rule. */
> - || (cfi_insn->u.ri.reg == SFRAME_CFA_SP_REG && cfi_insn->u.ri.offset != 0))
> + || (cfi_insn->u.ri.reg == SFRAME_CFA_SP_REG
> + && ((sframe_get_abi_arch () != SFRAME_ABI_S390X_ENDIAN_BIG
> + && cfi_insn->u.ri.offset != 0)
> + || (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG
> + && cfi_insn->u.ri.offset != SFRAME_S390X_SP_VAL_OFFSET))))
> {
> as_warn (_("no SFrame FDE emitted; %s with %s reg %u"),
> cfi_esc_p ? ".cfi_escape DW_CFA_val_offset" : ".cfi_val_offset",
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-1.d
> new file mode 100644
> index 000000000000..df7513c49100
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-1.d
> @@ -0,0 +1,23 @@
> +#name: SFrame generation on s390x - .cfi_offset and .cfi_def_cfa_{offset,register}
> +#objdump: --sframe=.sframe
> +#...
> +Contents of the SFrame section .sframe:
> +
> + Header :
> +
> + Version: SFRAME_VERSION_2
> + Flags: NONE
> + Num FDEs: 1
> + Num FREs: 6
> +
> + Function Index :
> +
> + func idx \[0\]: pc = 0x0, size = 40 bytes
> + STARTPC +CFA +FP +RA +
> + 0+0000 +sp\+160 +u +u +
> + 0+0006 +sp\+160 +c\-72 +c\-48 +
> + 0+000c +sp\+320 +c\-72 +c\-48 +
> + 0+0010 +fp\+320 +c\-72 +c\-48 +
> + 0+001c +sp\+160 +u +u +
> + 0+001e +fp\+320 +c\-72 +c\-48 +
> +#pass
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-1.s
> new file mode 100644
> index 000000000000..7d132a4a9632
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-1.s
> @@ -0,0 +1,37 @@
> + .cfi_sections .sframe
> + .cfi_startproc
> + stmg %r6,%r15,48(%r15)
> + .cfi_offset 6, -112
> + .cfi_offset 7, -104
> + .cfi_offset 8, -96
> + .cfi_offset 9, -88
> + .cfi_offset 10, -80
> + .cfi_offset 11, -72
> + .cfi_offset 12, -64
> + .cfi_offset 13, -56
> + .cfi_offset 14, -48
> + .cfi_offset 15, -40
> + lay %r15,-160(%r15)
> + .cfi_def_cfa_offset 320
> + lgr %r11,%r15
> + .cfi_def_cfa_register 11
> + lay %r15,-128(%r15)
> +.Lreturn:
> + lmg %r6,%r15,160+48(%r11)
> + .cfi_remember_state
> + .cfi_restore 15
> + .cfi_restore 14
> + .cfi_restore 13
> + .cfi_restore 12
> + .cfi_restore 11
> + .cfi_restore 10
> + .cfi_restore 9
> + .cfi_restore 8
> + .cfi_restore 7
> + .cfi_restore 6
> + .cfi_def_cfa 15, 160
> + br %r14
> + .cfi_restore_state
> + lay %r15,-128(%r15)
> + j .Lreturn
> + .cfi_endproc
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-2.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-2.d
> new file mode 100644
> index 000000000000..78c77e780986
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-2.d
> @@ -0,0 +1,23 @@
> +#name: SFrame generation on s390x - .cfi_rel_offset and .cfi_def_cfa_{offset,register}
> +#objdump: --sframe=.sframe
> +#...
> +Contents of the SFrame section .sframe:
> +
> + Header :
> +
> + Version: SFRAME_VERSION_2
> + Flags: NONE
> + Num FDEs: 1
> + Num FREs: 6
> +
> + Function Index :
> +
> + func idx \[0\]: pc = 0x0, size = 40 bytes
> + STARTPC +CFA +FP +RA +
> + 0+0000 +sp\+160 +u +u +
> + 0+0006 +sp\+160 +c\-72 +c\-48 +
> + 0+000c +sp\+320 +c\-72 +c\-48 +
> + 0+0010 +fp\+320 +c\-72 +c\-48 +
> + 0+001c +sp\+160 +u +u +
> + 0+001e +fp\+320 +c\-72 +c\-48 +
> +#pass
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-2.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-2.s
> new file mode 100644
> index 000000000000..6d52037613d5
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-2.s
> @@ -0,0 +1,37 @@
> + .cfi_sections .sframe
> + .cfi_startproc
> + stmg %r6,%r15,48(%r15)
> + .cfi_rel_offset 6, 48
> + .cfi_rel_offset 7, 56
> + .cfi_rel_offset 8, 64
> + .cfi_rel_offset 9, 72
> + .cfi_rel_offset 10, 80
> + .cfi_rel_offset 11, 88
> + .cfi_rel_offset 12, 96
> + .cfi_rel_offset 13, 104
> + .cfi_rel_offset 14, 112
> + .cfi_rel_offset 15, 120
> + lay %r15,-160(%r15)
> + .cfi_def_cfa_offset 320
> + lgr %r11,%r15
> + .cfi_def_cfa_register 11
> + lay %r15,-128(%r15)
> +.Lreturn:
> + lmg %r6,%r15,160+48(%r11)
> + .cfi_remember_state
> + .cfi_restore 15
> + .cfi_restore 14
> + .cfi_restore 13
> + .cfi_restore 12
> + .cfi_restore 11
> + .cfi_restore 10
> + .cfi_restore 9
> + .cfi_restore 8
> + .cfi_restore 7
> + .cfi_restore 6
> + .cfi_def_cfa 15, 160
> + br %r14
> + .cfi_restore_state
> + lay %r15,-128(%r15)
> + j .Lreturn
> + .cfi_endproc
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-1.d
> new file mode 100644
> index 000000000000..00361d25a6ca
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-1.d
> @@ -0,0 +1,15 @@
> +#name: SFrame generation on s390x - .cfi_def_cfa_register with non-SP/FP register
> +#as: --gsframe
> +#warning: non-SP/FP register 10 in \.cfi_def_cfa_register
> +#objdump: --sframe=.sframe
> +#...
> +Contents of the SFrame section .sframe:
> +
> + Header :
> +
> + Version: SFRAME_VERSION_2
> + Flags: NONE
> + Num FDEs: 0
> + Num FREs: 0
> +
> +#pass
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-1.s
> new file mode 100644
> index 000000000000..8b724df40ff3
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-1.s
> @@ -0,0 +1,37 @@
> + .cfi_sections .sframe
> + .cfi_startproc
> + stmg %r6,%r15,48(%r15)
> + .cfi_offset 6, -112
> + .cfi_offset 7, -104
> + .cfi_offset 8, -96
> + .cfi_offset 9, -88
> + .cfi_offset 10, -80
> + .cfi_offset 11, -72
> + .cfi_offset 12, -64
> + .cfi_offset 13, -56
> + .cfi_offset 14, -48
> + .cfi_offset 15, -40
> + lay %r15,-160(%r15)
> + .cfi_def_cfa_offset 320
> + lgr %r10,%r15
> + .cfi_def_cfa_register 10 # non-default frame pointer register
> + lay %r15,-128(%r15)
> +.Lreturn:
> + lmg %r6,%r15,160+48(%r10)
> + .cfi_remember_state
> + .cfi_restore 15
> + .cfi_restore 14
> + .cfi_restore 13
> + .cfi_restore 12
> + .cfi_restore 11
> + .cfi_restore 10
> + .cfi_restore 9
> + .cfi_restore 8
> + .cfi_restore 7
> + .cfi_restore 6
> + .cfi_def_cfa 15, 160
> + br %r14
> + .cfi_restore_state
> + lay %r15,-128(%r15)
> + j .Lreturn
> + .cfi_endproc
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-2.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-2.d
> new file mode 100644
> index 000000000000..c2f8fca8ec9e
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-2.d
> @@ -0,0 +1,15 @@
> +#name: SFrame generation on s390x - .cfi_def_cfa with non-SP/FP register
> +#as: --gsframe
> +#warning: non-SP/FP register 10 in \.cfi_def_cfa
> +#objdump: --sframe=.sframe
> +#...
> +Contents of the SFrame section .sframe:
> +
> + Header :
> +
> + Version: SFRAME_VERSION_2
> + Flags: NONE
> + Num FDEs: 0
> + Num FREs: 0
> +
> +#pass
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-2.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-2.s
> new file mode 100644
> index 000000000000..dbcf439c1563
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-2.s
> @@ -0,0 +1,37 @@
> + .cfi_sections .sframe
> + .cfi_startproc
> + stmg %r6,%r15,48(%r15)
> + .cfi_offset 6, -112
> + .cfi_offset 7, -104
> + .cfi_offset 8, -96
> + .cfi_offset 9, -88
> + .cfi_offset 10, -80
> + .cfi_offset 11, -72
> + .cfi_offset 12, -64
> + .cfi_offset 13, -56
> + .cfi_offset 14, -48
> + .cfi_offset 15, -40
> + lay %r15,-160(%r15)
> + .cfi_def_cfa_offset 320
> + lgr %r10,%r15
> + .cfi_def_cfa 10, 320 # non-default frame pointer register
> + lay %r15,-128(%r15)
> +.Lreturn:
> + lmg %r6,%r15,160+48(%r10)
> + .cfi_remember_state
> + .cfi_restore 15
> + .cfi_restore 14
> + .cfi_restore 13
> + .cfi_restore 12
> + .cfi_restore 11
> + .cfi_restore 10
> + .cfi_restore 9
> + .cfi_restore 8
> + .cfi_restore 7
> + .cfi_restore 6
> + .cfi_def_cfa 15, 160
> + br %r14
> + .cfi_restore_state
> + lay %r15,-128(%r15)
> + j .Lreturn
> + .cfi_endproc
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-3.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-3.d
> new file mode 100644
> index 000000000000..db025ce23f16
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-3.d
> @@ -0,0 +1,15 @@
> +#name: SFrame generation on s390x - non-default RA register
> +#as: --gsframe
> +#warning: non-default RA register 7
> +#objdump: --sframe=.sframe
> +#...
> +Contents of the SFrame section .sframe:
> +
> + Header :
> +
> + Version: SFRAME_VERSION_2
> + Flags: NONE
> + Num FDEs: 0
> + Num FREs: 0
> +
> +#pass
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-3.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-3.s
> new file mode 100644
> index 000000000000..7cea16520da2
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-err-3.s
> @@ -0,0 +1,5 @@
> + .cfi_sections .sframe
> + .cfi_startproc
> + .cfi_return_column 7 # non-default return address register
> + br %r7
> + .cfi_endproc
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.d
> new file mode 100644
> index 000000000000..4ab6c5770d07
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.d
> @@ -0,0 +1,22 @@
> +#name: SFrame generation on s390x - RA and then FP saved on stack
> +#objdump: --sframe=.sframe
> +#...
> +Contents of the SFrame section .sframe:
> +
> + Header :
> +
> + Version: SFRAME_VERSION_2
> + Flags: NONE
> + Num FDEs: 1
> + Num FREs: 5
> +
> + Function Index :
> +
> + func idx \[0\]: pc = 0x0, size = 34 bytes
> + STARTPC +CFA +FP +RA +
> + 0+0000 +sp\+160 +u +u +
> + 0+0006 +sp\+160 +u +c\-48 +
> + 0+000c +sp\+160 +c\-72 +c\-48 +
> + 0+001a +sp\+160 +u +c\-48 +
> + 0+0020 +sp\+160 +u +u +
> +#pass
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.s
> new file mode 100644
> index 000000000000..3d9c8cbdb774
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.s
> @@ -0,0 +1,15 @@
> + .cfi_sections .sframe
> + .cfi_startproc
> + stg %r14,112(%r15)
> + .cfi_rel_offset 14, 112
> + stg %r11,88(%r15)
> + .cfi_rel_offset 11, 88
> + la %r11,0
> + la %r14,0
> +.Lreturn:
> + lg %r11,88(%r15)
> + .cfi_restore 11
> + lg %r14,112(%r15)
> + .cfi_restore 14
> + br %r14
> + .cfi_endproc
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.d
> new file mode 100644
> index 000000000000..cb88417b009a
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.d
> @@ -0,0 +1,15 @@
> +#name: SFrame generation on s390x - FP without RA saved on stack
> +#as: --gsframe
> +#warning: FP without RA on stack
> +#objdump: --sframe=.sframe
> +#...
> +Contents of the SFrame section .sframe:
> +
> + Header :
> +
> + Version: SFRAME_VERSION_2
> + Flags: NONE
> + Num FDEs: 0
> + Num FREs: 0
> +
> +#pass
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.s
> new file mode 100644
> index 000000000000..a84c39105f28
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.s
> @@ -0,0 +1,15 @@
> + .cfi_sections .sframe
> + .cfi_startproc
> + stg %r11,88(%r15)
> + .cfi_rel_offset 11, 88
> + stg %r14,112(%r15)
> + .cfi_rel_offset 14, 112
> + la %r11,0
> + la %r14,0
> +.Lreturn:
> + lg %r14,112(%r15)
> + .cfi_restore 14
> + lg %r11,88(%r15)
> + .cfi_restore 11
> + br %r14
> + .cfi_endproc
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d
> new file mode 100644
> index 000000000000..7f1acd8c5d05
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d
> @@ -0,0 +1,15 @@
> +#name: SFrame generation on s390x - FP and then RA saved in register
> +#as: --gsframe
> +#warning: FP register 11 in .cfi_register
> +#objdump: --sframe=.sframe
> +#...
> +Contents of the SFrame section .sframe:
> +
> + Header :
> +
> + Version: SFRAME_VERSION_2
> + Flags: NONE
> + Num FDEs: 0
> + Num FREs: 0
> +
> +#pass
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.s
> new file mode 100644
> index 000000000000..48b01ac5f57b
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.s
> @@ -0,0 +1,15 @@
> + .cfi_sections .sframe
> + .cfi_startproc
> + ldgr %f2,%r11
> + .cfi_register 11, 17
> + ldgr %f0,%r14
> + .cfi_register 14, 16
> + la %r11,0
> + la %r14,0
> +.Lreturn:
> + lgdr %r14,%f0
> + .cfi_restore 14
> + lgdr %r11,%f2
> + .cfi_restore 11
> + br %r14
> + .cfi_endproc
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d
> new file mode 100644
> index 000000000000..6573d01b997b
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d
> @@ -0,0 +1,15 @@
> +#name: SFrame generation on s390x - RA and then FP saved in register
> +#as: --gsframe
> +#warning: RA register 14 in .cfi_register
> +#objdump: --sframe=.sframe
> +#...
> +Contents of the SFrame section .sframe:
> +
> + Header :
> +
> + Version: SFRAME_VERSION_2
> + Flags: NONE
> + Num FDEs: 0
> + Num FREs: 0
> +
> +#pass
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.s
> new file mode 100644
> index 000000000000..1d4497178ada
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.s
> @@ -0,0 +1,15 @@
> + .cfi_sections .sframe
> + .cfi_startproc
> + ldgr %f0,%r14
> + .cfi_register 14, 16
> + ldgr %f2,%r11
> + .cfi_register 11, 17
> + la %r11,0
> + la %r14,0
> +.Lreturn:
> + lgdr %r11,%f2
> + .cfi_restore 11
> + lgdr %r14,%f0
> + .cfi_restore 14
> + br %r14
> + .cfi_endproc
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
> index 341a56a9eab2..d17cd767cc6e 100644
> --- a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
> @@ -64,8 +64,9 @@ proc gas_x86_64_check { } {
> }
>
> # common tests
> -if { ([istarget "x86_64-*-*"] || [istarget "aarch64*-*-*"]) \
> - && [gas_sframe_check] } then {
> +if { ([istarget "x86_64-*-*"] || [istarget "aarch64*-*-*"]
> + || [istarget "s390x-*-*"]) \
> + && [gas_sframe_check] } then {
>
> global ASFLAGS
> set old_ASFLAGS "$ASFLAGS"
> @@ -109,3 +110,16 @@ if { [istarget "aarch64*-*-*"] && [gas_sframe_check] } then {
> run_dump_test "cfi-sframe-aarch64-4"
> run_dump_test "cfi-sframe-aarch64-pac-ab-key-1"
> }
> +
> +# s390x specific tests
> +if { [istarget "s390x*-*-*"] && [gas_sframe_check] } then {
> + run_dump_test "cfi-sframe-s390x-1"
> + run_dump_test "cfi-sframe-s390x-2"
> + run_dump_test "cfi-sframe-s390x-err-1"
> + run_dump_test "cfi-sframe-s390x-err-2"
> + run_dump_test "cfi-sframe-s390x-err-3"
> + run_dump_test "cfi-sframe-s390x-fpra-offset-1"
> + run_dump_test "cfi-sframe-s390x-fpra-offset-err-1"
> + run_dump_test "cfi-sframe-s390x-fpra-register-err-1"
> + run_dump_test "cfi-sframe-s390x-fpra-register-err-2"
> +}
> diff --git a/include/sframe.h b/include/sframe.h
> index a965e23bdd18..a87d6d491a2f 100644
> --- a/include/sframe.h
> +++ b/include/sframe.h
> @@ -93,6 +93,7 @@ extern "C"
> #define SFRAME_ABI_AARCH64_ENDIAN_BIG 1 /* AARCH64 big endian. */
> #define SFRAME_ABI_AARCH64_ENDIAN_LITTLE 2 /* AARCH64 little endian. */
> #define SFRAME_ABI_AMD64_ENDIAN_LITTLE 3 /* AMD64 little endian. */
> +#define SFRAME_ABI_S390X_ENDIAN_BIG 4 /* s390x big endian. */
>
> /* SFrame FRE types. */
> #define SFRAME_FRE_TYPE_ADDR1 0
> @@ -190,7 +191,7 @@ typedef struct sframe_func_desc_entry
> - 2-bits: Unused.
> ------------------------------------------------------------------------
> | Unused | PAC auth A/B key (aarch64) | FDE type | FRE type |
> - | | Unused (amd64) | | |
> + | | Unused (amd64, s390x) | | |
> ------------------------------------------------------------------------
> 8 6 5 4 0 */
> uint8_t sfde_func_info;
> @@ -248,7 +249,7 @@ typedef struct sframe_fre_info
> - 1 bit: Mangled RA state bit (aarch64 only).
> ----------------------------------------------------------------------------------
> | Mangled-RA (aarch64) | Size of offsets | Number of offsets | base_reg |
> - | Unused (amd64) | | | |
> + | Unused (amd64, s390x)| | | |
> ----------------------------------------------------------------------------------
> 8 7 5 1 0
>
> @@ -274,7 +275,7 @@ typedef struct sframe_fre_info
>
> /* SFrame Frame Row Entry definitions.
>
> - Used for both AMD64 and AARCH64.
> + Used for AMD64, AARCH64, and s390x.
>
> An SFrame Frame Row Entry is a self-sufficient record which contains
> information on how to generate the stack trace for the specified range of
> @@ -342,6 +343,10 @@ typedef struct sframe_frame_row_entry_addr4
> #define SFRAME_FRE_TYPE_ADDR4_LIMIT \
> (1ULL << ((SFRAME_FRE_TYPE_ADDR4 * 2) * 8))
>
> +/* On s390x, the CFA is defined as SP at call site + 160. Therefore the
> + SP value offset from CFA is -160. */
> +#define SFRAME_S390X_SP_VAL_OFFSET (-160)
> +
> #ifdef __cplusplus
> }
> #endif
> diff --git a/ld/testsuite/ld-s390/s390.exp b/ld/testsuite/ld-s390/s390.exp
> index e5bfb511ff61..c41acf10ca1c 100644
> --- a/ld/testsuite/ld-s390/s390.exp
> +++ b/ld/testsuite/ld-s390/s390.exp
> @@ -146,4 +146,8 @@ if { [istarget "s390-*-*"] || [istarget "s390x-*-*"] } {
>
> if [istarget "s390x-*-*"] {
> run_ld_link_tests $s390xtests
> +
> + if { ![skip_sframe_tests] } {
> + run_dump_test "sframe-simple-1"
> + }
> }
> diff --git a/ld/testsuite/ld-s390/sframe-bar.s b/ld/testsuite/ld-s390/sframe-bar.s
> new file mode 100644
> index 000000000000..f7075697d1e3
> --- /dev/null
> +++ b/ld/testsuite/ld-s390/sframe-bar.s
> @@ -0,0 +1,21 @@
> + .text
> + .globl bar
> + .type bar, @function
> +bar:
> + .cfi_startproc
> + stmg %r14,%r15,112(%r15)
> + .cfi_rel_offset %r14, 112
> + .cfi_rel_offset %r15, 120
> + lay %r15,-160(%r15)
> + .cfi_adjust_cfa_offset 160
> + clgfi %r2,1000
> + jle .Lreturn
> + brasl %r14,foo@PLT
> +.Lreturn:
> + lay %r15,160(%r15)
> + .cfi_adjust_cfa_offset -160
> + lg %r14,112(%r15)
> + .cfi_restore %r14
> + br %r14
> + .cfi_endproc
> + .size bar, .-bar
> diff --git a/ld/testsuite/ld-s390/sframe-foo.s b/ld/testsuite/ld-s390/sframe-foo.s
> new file mode 100644
> index 000000000000..75657e93e33b
> --- /dev/null
> +++ b/ld/testsuite/ld-s390/sframe-foo.s
> @@ -0,0 +1,9 @@
> + .text
> + .globl foo
> + .type foo, @function
> +foo:
> + .cfi_startproc
> + msgfi %r2,42
> + br %r14
> + .cfi_endproc
> + .size foo, .-foo
> diff --git a/ld/testsuite/ld-s390/sframe-simple-1.d b/ld/testsuite/ld-s390/sframe-simple-1.d
> new file mode 100644
> index 000000000000..4df5d492f01e
> --- /dev/null
> +++ b/ld/testsuite/ld-s390/sframe-simple-1.d
> @@ -0,0 +1,30 @@
> +#as: --gsframe
> +#source: sframe-foo.s
> +#source: sframe-bar.s
> +#objdump: --sframe=.sframe
> +#ld: -shared --no-rosegment
> +#name: SFrame simple link
> +
> +.*: +file format .*
> +
> +Contents of the SFrame section .sframe:
> + Header :
> +
> + Version: SFRAME_VERSION_2
> + Flags: SFRAME_F_FDE_SORTED
> + Num FDEs: 2
> + Num FREs: 6
> +
> + Function Index :
> +
> + func idx \[0\]: pc = 0x228, size = 8 bytes
> + STARTPC +CFA +FP +RA +
> + 0+228 +sp\+160 +u +u +
> +
> + func idx \[1\]: pc = 0x230, size = 42 bytes
> + STARTPC +CFA +FP +RA +
> + 0+230 +sp\+160 +u +u +
> + 0+236 +sp\+160 +u +c-48 +
> + 0+23c +sp\+320 +u +c-48 +
> + 0+252 +sp\+160 +u +c-48 +
> + 0+258 +sp\+160 +u +u +
> diff --git a/libsframe/doc/sframe-spec.texi b/libsframe/doc/sframe-spec.texi
> index 6b8dfa806500..ce06e50e3d1f 100644
> --- a/libsframe/doc/sframe-spec.texi
> +++ b/libsframe/doc/sframe-spec.texi
> @@ -81,8 +81,8 @@ The SFrame stack trace information is provided in a loaded section, known as the
> @code{.sframe} section. When available, the @code{.sframe} section appears in
> a new segment of its own, PT_GNU_SFRAME.
>
> -The SFrame format is currently supported only for select ABIs, namely, AMD64
> -and AAPCS64.
> +The SFrame format is currently supported only for select ABIs, namely, AMD64,
> +AAPCS64, and s390x.
>
> A portion of the SFrame format follows an unaligned on-disk representation.
> Some data structures, however, (namely the SFrame header and the SFrame
> @@ -128,6 +128,14 @@ the data structure.
> @item
> The above two imply that each SFrame function descriptor entry has a fixed size
> of 20 bytes instead of its size of 17 bytes in SFrame format version 1.
> +@item
> +Add a new ABI/arch identifier SFRAME_ABI_S390X_ENDIAN_BIG for the s390
> +architecture (64-bit) s390x ABI. Other s390x-specific backward compatible
> +changes including the following helper definitions have been incrementally
> +added to SFrame version 2 only:
> +@itemize @bullet
> +@item SFRAME_S390X_SP_VAL_OFFSET: SP value offset from CFA.
> +@end itemize
> @end itemize
>
> SFrame version 1 is now obsolete and should not be used.
> @@ -403,6 +411,10 @@ in the format.
> @item @code{SFRAME_ABI_AMD64_ENDIAN_LITTLE}
> @tab 3 @tab AMD64 little-endian
>
> +@tindex SFRAME_ABI_S390X_ENDIAN_BIG
> +@item @code{SFRAME_ABI_S390X_ENDIAN_BIG}
> +@tab 4 @tab s390x big-endian
> +
> @end multitable
>
> The presence of an explicit identification of ABI/arch in SFrame may allow
> @@ -774,6 +786,7 @@ auxiliary SFrame header, etc., if used, must also be outlined here.
> @menu
> * AMD64::
> * AArch64::
> +* s390x::
> @end menu
>
> @node AMD64
> @@ -830,6 +843,50 @@ Hence, in summary:
> @item 3 @tab FP = CFA + offset3
> @end multitable
>
> +@node s390x
> +@section s390x
> +
> +A stack tracer implementation must initialize the SP to the designated SP
> +register value, the FP to the preferred FP register value, and the RA to the
> +designated RA register value in the topmost stack frame of the callchain. This
> +is required, as either the SP or FP is used as CFA base register and as the FP
> +and/or RA are not necessarily saved on the stack. For RA this may only be the
> +case in the topmost stack frame of the callchain. For FP this may be the case
> +in any stack frame.
> +
> +Irrespective of the ABI, the first stack offset is always used to locate the
> +CFA, by interpreting it as: CFA = @code{BASE_REG} + offset1.
> +The identification of the @code{BASE_REG} is done by using the
> +@code{fre_cfa_base_reg_id} field in the SFrame FRE info word.
> +
> +The (64-bit) s390x ELF ABI does not mandate the precise location in a function
> +where the return address (RA) and frame pointer (FP) are saved, if at all.
> +Hence the need to track RA in the SFrame stack trace format. As RA is being
> +tracked in this ABI, the second stack offset is always used to locate the RA
> +stack slot, by interpreting it as: RA = CFA + offset2. RA remains unchanged,
> +if the offset is not available. It is recommended that a stack tracer
> +implements a check to ensure that RA remains unchanged only for the topmost
> +frame only. The third stack offset is used to locate the FP stack slot, by
> +interpreting it as: FP = CFA + offset3. FP remains unchanged, if the offset is
> +not available.
> +
> +Given the nature of things, the number of stack offsets seen on s390x per
> +SFrame FRE is either 1, 2, or 3.
> +
> +Hence, in summary:
> +
> +@multitable {Offset ID} {Interpretation in s390x in X}
> +@headitem Offset ID @tab Interpretation in s390x
> +@item 1 @tab CFA = @code{BASE_REG} + offset1
> +@item 2 @tab RA = CFA + offset2
> +@item 3 @tab FP = CFA + offset3
> +@end multitable
> +
> +The s390x ELF ABI defines the CFA as stack pointer (SP) at call site +160. The
> +SP can therefore be obtained using the SP value offset from CFA
> +@code{SFRAME_S390X_SP_VAL_OFFSET} of -160 as follows:
> +SP = CFA + @code{SFRAME_S390X_SP_VAL_OFFSET}
> +
> @node Generating Stack Traces using SFrame
> @appendix Generating Stack Traces using SFrame
>
> @@ -893,7 +950,7 @@ SFrame section.
> fp_offset = sframe_fre_get_fp_offset (fre);
>
> cfa = base_reg_val + cfa_offset;
> - next_frame->sp = cfa;
> + next_frame->sp = cfa [+ SFRAME_S390X_SP_VAL_OFFSET on s390x];
>
> ra_stack_loc = cfa + ra_offset;
> // Get the address stored in the stack location.
> diff --git a/libsframe/sframe.c b/libsframe/sframe.c
> index 3982157f70ce..4a62b8bb2762 100644
> --- a/libsframe/sframe.c
> +++ b/libsframe/sframe.c
> @@ -165,6 +165,7 @@ need_swapping (int endian)
> case SFRAME_ABI_AMD64_ENDIAN_LITTLE:
> return !is_little;
> case SFRAME_ABI_AARCH64_ENDIAN_BIG:
> + case SFRAME_ABI_S390X_ENDIAN_BIG:
> return is_little;
> default:
> break;
More information about the Binutils
mailing list