[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