[PATCH v3 05/11] s390: Represent FP without RA saved in SFrame

Indu Bhagat indu.bhagat@oracle.com
Sat Jul 5 23:16:45 GMT 2025


On 6/27/25 4:08 AM, Jens Remus wrote:
> If an architecture uses both SFrame RA and FP tracking SFrame assumes
> that the RA offset is the 2nd offset and the FP offset is the 3rd offset
> following a SFrame FRE.  An architecture does not necessarily need to
> save both on the stack (or in register) at the same time or even at all.
> SFrame cannot represent FP without RA saved on stack (or in a register),
> since it cannot distinguish whether the 2nd offset is the RA or FP
> offset.
> 
> For s390x use an invalid SFrame RA offset from CFA value of zero as
> padding to represent the FP being saved when the RA is not saved.  This
> aligns with the existing invalid SFrame fixed RA offset from CFA value
> of zero.  In a stack tracer this then also naturally falls into place,
> as it can skip restoring the RA in the topmost frame, if both the fixed
> RA offset (from SFrame header) and the RA offset (from FDE) are zero,
> without any need to test architecture-specific flags.
> 
> include/
> 	* sframe.h (SFRAME_FRE_RA_OFFSET_INVALID): New define.  Used as
> 	padding offset.
> 	* sframe-api.h (sframe_fre_get_ra_offset): Add comment that for
> 	s390x an offset value of SFRAME_FRE_RA_OFFSET_INVALID indicates
> 	that the RA is not saved.
> 
> gas/
> 	* gen-sframe.c (get_fre_num_offsets): For s390x account padding
> 	RA offset, if FP without RA saved.
> 	(sframe_get_fre_offset_size): Likewise.
> 	(output_sframe_row_entry): For s390x write a padding RA offset,
> 	if FP without RA needs to be represented.
> 	(sframe_do_fde): Enable FP without RA saved to be represented
> 	on s390x.
> 
> libsframe/
> 	* sframe.c (sframe_fre_get_ra_offset): Add comment that for
> 	s390x an offset value of SFRAME_FRE_RA_OFFSET_INVALID indicates
> 	that the RA is not saved.
> 	* sframe-dump.c (dump_sframe_func_with_fres): Treat invalid
> 	RA offsets as if they were undefined.  Display them as "U"
> 	to distinguish them.
> 	* doc/sframe-spec.texi (s390x): Document s390x-specific use of
> 	SFRAME_FRE_RA_OFFSET_INVALID to represent FP without RA saved.
> 
> gas/testsuite/
> 	* gas/cfi-sframe/cfi-sframe.exp: Rename s390x-specific tests.
> 	* gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.s: Rename
> 	to ...
> 	* cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.d: Likewise.
> 	* gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-2.s: This.
> 	* gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-2.d: Likewise.
> 	Update test verification pattern accordingly.
> 	* cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.s: Rename
> 	to ...
> 	* cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d: Likewise.
> 	* gas/cfi-sframe/cfi-sframe-s390x-fpra-register-2.s: This.
> 	* gas/cfi-sframe/cfi-sframe-s390x-fpra-register-2.d: Likewise.
> 	Update test verification pattern accordingly.
> 
> Signed-off-by: Jens Remus <jremus@linux.ibm.com>

One comment below for the spec changes in V3.

Otherwise, looks good to me.
Reviewed-by: Indu Bhagat <indu.bhagat@oracle.com>


> ---
> 
> Notes (jremus):
>      Changes in V3:
>      - Update "Changes from Version 1 to Version 2" in SFrame spec. (Indu)
>      - Add comment on sframe_fre_get_ra_offset that for s390x the offset may
>        be SFRAME_FRE_RA_OFFSET_INVALID when FP without RA saved.
>      - Correct "a RA offset" to "an RA offset". (Indu)
>      - Reword comment on "SFRAME_FRE_RA_OFFSET_INVALID". (Indu)
>      
>      Changes in V2:
>      - Reword commit message (s390 to s390x). (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.
>      - Display padding RA offsets as "U" instead of "u*". (Indu)
>      
>      An alternative approach would have been to redefine the 4-bit offset
>      count field in the FDE info word into a bit field as proposed with
>      "[RFC PATCH 0/1] sframe: Represent FP without RA on stack (bitmap)" [1].
>      With the current 4-bit count up to 15+1 offsets can be represented (+1
>      if the CFA offset would be considered mandatory, so that it does not
>      need to be explicitly accounted).  With a 4 bit bit field only up to
>      4+1 offsets could be represented.
>      
>      [1]: Path series "[RFC PATCH 0/1] sframe: Represent FP without RA on
>           stack (bitmap)",
>           https://inbox.sourceware.org/binutils/20240422155905.2497883-1-jremus@linux.ibm.com/
>      
>      A test build of Glibc tag 2.41 on s390x libc.so shows 342 padding
>      RA offsets.  With a total of 29792 offsets the padding RA offsets
>      account for only ~1.15% of the offsets, which seems acceptable.
>      
>      Statistics for libc.so:
>      
>        VALUE        TOTAL      MIN        MAX        AVG
>        FDEs:        3652       -          -          -
>        FREs/FDE:    15236      1          20         4
>        Offsets/FDE: 29792      1          38         8
>           8-bit:    0          0          0          0
>          16-bit:    29792      1          38         8
>          32-bit:    0          0          0          0
>        Offsets/FRE: 29792      1          3          1
>           8-bit:    -          0          0          0
>          16-bit:    -          1          3          1
>          32-bit:    -          0          0          0
>        O_Padd/FDE:  342        -          -          0
>           8-bit:    0
>          16-bit:    342
>          32-bit:    0
>      
>      Note that on s390x the offsets are at minimum 16-bits in size, due to
>      the mandatory CFA offset being at least 160, which does not fit into
>      an 8-bit signed integer.  This is addressed by a following patch.
> 
>   gas/gen-sframe.c                              | 38 ++++++++++++++-----
>   .../cfi-sframe-s390x-fpra-offset-2.d          | 22 +++++++++++
>   ...r-1.s => cfi-sframe-s390x-fpra-offset-2.s} |  0
>   .../cfi-sframe-s390x-fpra-offset-err-1.d      | 15 --------
>   .../cfi-sframe-s390x-fpra-register-2.d        | 22 +++++++++++
>   ...1.s => cfi-sframe-s390x-fpra-register-2.s} |  0
>   .../cfi-sframe-s390x-fpra-register-err-1.d    | 15 --------
>   gas/testsuite/gas/cfi-sframe/cfi-sframe.exp   |  4 +-
>   include/sframe-api.h                          |  2 +
>   include/sframe.h                              | 22 +++++++++++
>   libsframe/doc/sframe-spec.texi                | 17 ++++++---
>   libsframe/sframe-dump.c                       |  4 ++
>   libsframe/sframe.c                            |  2 +
>   13 files changed, 116 insertions(+), 47 deletions(-)
>   create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-2.d
>   rename gas/testsuite/gas/cfi-sframe/{cfi-sframe-s390x-fpra-offset-err-1.s => cfi-sframe-s390x-fpra-offset-2.s} (100%)
>   delete 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-register-2.d
>   rename gas/testsuite/gas/cfi-sframe/{cfi-sframe-s390x-fpra-register-err-1.s => cfi-sframe-s390x-fpra-register-2.s} (100%)
>   delete mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d
> 
> diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
> index a170c5b67e0d..3c7db6cf458e 100644
> --- a/gas/gen-sframe.c
> +++ b/gas/gen-sframe.c
> @@ -339,7 +339,10 @@ get_fre_num_offsets (struct sframe_row_entry *sframe_fre)
>     if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
>       fre_num_offsets++;
>     if (sframe_ra_tracking_p ()
> -      && sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
> +      && (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK
> +	  /* For s390x account padding RA offset, if FP without RA saved.  */
> +	  || (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG
> +	      && sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)))
>       fre_num_offsets++;
>     return fre_num_offsets;
>   }
> @@ -361,9 +364,15 @@ sframe_get_fre_offset_size (struct sframe_row_entry *sframe_fre)
>     cfa_offset_size = get_offset_size_in_bytes (sframe_fre->cfa_offset);
>     if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
>       bp_offset_size = get_offset_size_in_bytes (sframe_fre->bp_offset);
> -  if (sframe_ra_tracking_p ()
> -      && sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
> -    ra_offset_size = get_offset_size_in_bytes (sframe_fre->ra_offset);
> +  if (sframe_ra_tracking_p ())
> +    {
> +      if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
> +	ra_offset_size = get_offset_size_in_bytes (sframe_fre->ra_offset);
> +      /* For s390x account padding RA offset, if FP without RA saved.  */
> +      else if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG
> +	       && sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
> +	ra_offset_size = get_offset_size_in_bytes (SFRAME_FRE_RA_OFFSET_INVALID);
> +    }
>   
>     /* Get the maximum size needed to represent the offsets.  */
>     max_offset_size = cfa_offset_size;
> @@ -569,11 +578,20 @@ output_sframe_row_entry (symbolS *fde_start_addr,
>     fre_offset_func_map[idx].out_func (sframe_fre->cfa_offset);
>     fre_write_offsets++;
>   
> -  if (sframe_ra_tracking_p ()
> -      && sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
> +  if (sframe_ra_tracking_p ())
>       {
> -      fre_offset_func_map[idx].out_func (sframe_fre->ra_offset);
> -      fre_write_offsets++;
> +      if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
> +	{
> +	  fre_offset_func_map[idx].out_func (sframe_fre->ra_offset);
> +	  fre_write_offsets++;
> +	}
> +      /* For s390x write padding RA offset, if FP without RA saved.  */
> +      else if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG
> +	       && sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
> +	{
> +	  fre_offset_func_map[idx].out_func (SFRAME_FRE_RA_OFFSET_INVALID);
> +	  fre_write_offsets++;
> +	}
>       }
>     if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
>       {
> @@ -1798,7 +1816,9 @@ sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx,
>   	= get_dw_fde_end_addrS (xlate_ctx->dw_fde);
>       }
>   
> -  if (sframe_ra_tracking_p ())
> +  /* ABI/arch except s390x cannot represent FP without RA saved.  */
> +  if (sframe_ra_tracking_p ()
> +      && sframe_get_abi_arch () != SFRAME_ABI_S390X_ENDIAN_BIG)
>       {
>         struct sframe_row_entry *fre;
>   
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-2.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-2.d
> new file mode 100644
> index 000000000000..dba325317cef
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-2.d
> @@ -0,0 +1,22 @@
> +#name: SFrame generation on s390x - FP and then RA 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 +c\-72 +U +
> +    0+000c +sp\+160 +c\-72 +c\-48 +
> +    0+001a +sp\+160 +c-72 +U +
> +    0+0020 +sp\+160 +u +u +
> +#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-2.s
> similarity index 100%
> rename from gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.s
> rename to gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-2.s
> 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
> deleted file mode 100644
> index cb88417b009a..000000000000
> --- a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.d
> +++ /dev/null
> @@ -1,15 +0,0 @@
> -#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-register-2.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-2.d
> new file mode 100644
> index 000000000000..c413114e67d4
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-2.d
> @@ -0,0 +1,22 @@
> +#name: SFrame generation on s390x - FP and then RA saved in FPR registers
> +#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 = 26 bytes
> +    STARTPC +CFA +FP +RA +
> +    0+0000 +sp\+160 +u +u +
> +    0+0004 +sp\+160 +r17 +U +
> +    0+0008 +sp\+160 +r17 +r16 +
> +    0+0014 +sp\+160 +r17 +U +
> +    0+0018 +sp\+160 +u +u +
> +#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-2.s
> similarity index 100%
> rename from gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.s
> rename to gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-2.s
> 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
> deleted file mode 100644
> index 23e0411d8a2c..000000000000
> --- a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d
> +++ /dev/null
> @@ -1,15 +0,0 @@
> -#name: SFrame generation on s390x - FP without RA saved in registers
> -#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.exp b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
> index 1e7fc9e03cad..b26ce60c6e59 100644
> --- a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
> @@ -119,7 +119,7 @@ if { [istarget "s390x*-*-*"] && [gas_sframe_check] } then {
>       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-offset-2"
>       run_dump_test "cfi-sframe-s390x-fpra-register-1"
> -    run_dump_test "cfi-sframe-s390x-fpra-register-err-1"
> +    run_dump_test "cfi-sframe-s390x-fpra-register-2"
>   }
> diff --git a/include/sframe-api.h b/include/sframe-api.h
> index f47afff1fd5e..ca8f679e0f55 100644
> --- a/include/sframe-api.h
> +++ b/include/sframe-api.h
> @@ -208,6 +208,8 @@ sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx,
>   
>   /* Get the RA offset from the FRE.  If the offset is invalid, sets errp.
>   
> +   For s390x an RA offset value of SFRAME_FRE_RA_OFFSET_INVALID indicates
> +   that the RA is not saved, which is only valid in the topmost frame.
>      For s390x the offset may be an encoded register number, indicated by
>      LSB set to one, which is only valid in the topmost frame.  */
>   extern int32_t
> diff --git a/include/sframe.h b/include/sframe.h
> index 393748bcd2ad..e6933129e63b 100644
> --- a/include/sframe.h
> +++ b/include/sframe.h
> @@ -237,6 +237,10 @@ typedef struct sframe_func_desc_entry
>      may or may not be tracked.  */
>   #define SFRAME_FRE_FP_OFFSET_IDX    2
>   
> +/* Invalid RA offset.  Currently used for s390x as padding to represent FP
> +   without RA saved.  */
> +#define SFRAME_FRE_RA_OFFSET_INVALID 0
> +
>   typedef struct sframe_fre_info
>   {
>     /* Information about
> @@ -299,6 +303,24 @@ typedef struct sframe_fre_info
>        fi
>        Note that in AAPCS64, a frame record, if created, will save both FP and
>        LR on stack.
> +
> +   s390x:
> +     offset1 (interpreted as CFA = BASE_REG + offset1)
> +     if RA is being tracked
> +       offset2 (interpreted as RA = CFA + offset2; an offset value of
> +	       SFRAME_FRE_RA_OFFSET_INVALID indicates a dummy padding RA offset
> +	       to represent FP without RA saved on stack)
> +       if FP is being tracked
> +	 offset3 (intrepreted as FP = CFA + offset3)
> +       fi
> +     else
> +      if FP is being tracked
> +	offset2 (intrepreted as FP = CFA + offset2)
> +      fi
> +    fi
> +    Note that in s390x, if a FP/RA offset2/offset3 value has the least-
> +    significant bit set it represents a DWARF register number shifted to the
> +    left by 1 to restore the FP/RA value from.
>   */
>   
>   /* Used when SFRAME_FRE_TYPE_ADDR1 is specified as FRE type.  */
> diff --git a/libsframe/doc/sframe-spec.texi b/libsframe/doc/sframe-spec.texi
> index 98c056c213d2..35df00859bad 100644
> --- a/libsframe/doc/sframe-spec.texi
> +++ b/libsframe/doc/sframe-spec.texi
> @@ -141,6 +141,9 @@ DWARF register number.
>   FP/RA offset.
>   @item SFRAME_S390X_OFFSET_DECODE_REGNUM: Decode a DWARF register number from
>   an FP/RA offset.
> +@item SFRAME_FRE_RA_OFFSET_INVALID: Invalid RA offset value (like
> +SFRAME_CFA_FIXED_RA_INVALID).  Used on s390x as padding offset to represent
> +FP without RA saved.
>   @end itemize
>   @end itemize
>   
> @@ -870,12 +873,13 @@ 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.
> +stack slot, by interpreting it as: RA = CFA + offset2, unless the offset has a
> +value of @code{SFRAME_FRE_RA_OFFSET_INVALID}.  RA remains unchanged, if the
> +offset is not available or has a value of @code{SFRAME_FRE_RA_OFFSET_INVALID}.
> +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

Two 'only' in one sentence look off.  Remove one.  Or if you find the 
following reads better:

Stack tracers are recommended to validate that the "unchanged RA" 
pattern, when present, is seen only for the topmost stack frame.


> +used to locate the FP stack slot, by interpreting it as: FP = CFA + offset3.
> +FP remains unchanged, if the offset is not available.
>   
>   In leaf functions the RA and FP may be saved in other registers, such as
>   floating-point registers (FPRs), instead of on the stack.  To represent this
> @@ -899,6 +903,7 @@ Hence, in summary:
>   @item 1 @tab CFA = @code{BASE_REG} + offset1
>   @item 2 @tab RA stack slot = CFA + offset2, if (offset2 & 1 == 0)
>              @*RA register number = offset2 >> 1, if (offset2 & 1 == 1)
> +           @*RA not saved if (offset2 == @code{SFRAME_FRE_RA_OFFSET_INVALID})
>   @item 3 @tab FP stack slot = CFA + offset3, if (offset3 & 1 == 0)
>              @*FP register number = offset3 >> 1, if (offset3 & 1 == 1)
>   @end multitable
> diff --git a/libsframe/sframe-dump.c b/libsframe/sframe-dump.c
> index 09ecd4faab54..4baaf9eeb129 100644
> --- a/libsframe/sframe-dump.c
> +++ b/libsframe/sframe-dump.c
> @@ -200,6 +200,10 @@ dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_ctx,
>         if (sframe_decoder_get_fixed_ra_offset (sfd_ctx)
>   	  != SFRAME_CFA_FIXED_RA_INVALID)
>   	strcpy (temp, "f");
> +      /* If an ABI does track RA offset, e.g. s390x, it can be a padding
> +	 to represent FP without RA being saved on stack.  */
> +      else if (err[2] == 0 && ra_offset == SFRAME_FRE_RA_OFFSET_INVALID)
> +	sprintf (temp, "U");
>         else if (err[2] == 0)
>   	{
>   	  if (is_sframe_abi_arch_s390x (sfd_ctx)
> diff --git a/libsframe/sframe.c b/libsframe/sframe.c
> index e5f9b198402d..47f027c27e1a 100644
> --- a/libsframe/sframe.c
> +++ b/libsframe/sframe.c
> @@ -711,6 +711,8 @@ sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx,
>   
>   /* Get the RA offset from the FRE.  If the offset is invalid, sets errp.
>   
> +   For s390x an RA offset value of SFRAME_FRE_RA_OFFSET_INVALID indicates
> +   that the RA is not saved, which is only valid in the topmost frame.
>      For s390x the offset may be an encoded register number, indicated by
>      LSB set to one, which is only valid in the topmost frame.  */
>   



More information about the Binutils mailing list