[PATCH v3 04/11] s390: Represent FP/RA saved in register in SFrame

Indu Bhagat indu.bhagat@oracle.com
Sat Jul 5 23:03:30 GMT 2025


On 6/27/25 4:08 AM, Jens Remus wrote:
> GCC on s390x, when in a leaf function, can be observed to save the
> frame pointer (FP) and/or return address (RA) register in a floating-
> point registers (FPR) instead of on the stack.  This is declared using
> the following CFI directive:
> 
>    .cfi_register <fp/ra-regnum>, <fpr-regnum>
> 
> SFrame cannot represent the FP and/or RA being saved in another
> register.  It does only track the CFA base register (SP/FP), CFA offset
> from CFA base register, and FP and RA save area offsets from CFA.
> 
> On s390x the FP and/or RA are only saved in another FPR when in a leaf
> function.  That is a function that does not call any other function.
> Therefore it can ever only be the topmost function in a call chain.
> An unwinder by default has access to all registers of the function that
> is the topmost on the call stack.  Therefore no further information
> is required to restore FP/RA from the FPR.
> 
> Represent FP/RA saved in another register on s390x, by encoding the
> DWARF register number shifted by one to the left with the least-
> significant bit set in the offset as follows:
> 
>    offset = (regnum << 1) | 1
> 
> The use of the least-significant bit of the offset as indication is
> possible, as the stack pointer (SP), the CFA, and any register save
> area slots are 8-byte aligned according to the s390x ELF ABI:
> - The stack pointer (SP) "shall maintain an 8-byte alignment". [1]
> - The CFA is defined as SP at call site +160. [2]
> - Pointers and 8-byte integers, such as general register values, must
>    be 8-byte aligned. [3]
> SFrame FP and RA stack offsets must therefore always be a multiple of
> 8 on s390x.  Note that for the same reason the DWARF data alignment
> factor is -8 on s390x (see DWARF2_CIE_DATA_ALIGNMENT).
> 
> Add s390x-specific SFrame (error) tests for FP/RA saved in FPRs in leaf
> function.
> 
> [1]: s390x ELF ABI, sections "Register Roles" and "Stack Frame
>       Allocation", https://github.com/IBM/s390x-abi/releases
> [2]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"),
>       https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88
> [3]: s390x ELF ABI, section "Fundamental Types", table "Scalar types",
>       https://github.com/IBM/s390x-abi/releases
> 
> include/
> 	* sframe.h (SFRAME_S390X_OFFSET_IS_REGNUM): New s390x-specific
> 	macro to test whether an SFrame FP/RA offset is a DWARF register
> 	number.
> 	(SFRAME_S390X_OFFSET_ENCODE_REGNUM): New s390x-specific macro to
> 	encode a DWARF register number into an SFrame FP/RA offset.
> 	(SFRAME_S390X_OFFSET_DECODE_REGNUM): New s390x-specific macro to
> 	decode an SFrame FP/RA offset into a DWARF register number.
> 	* sframe-api.h (sframe_fre_get_fp_offset,
> 	sframe_fre_get_fp_offset): Add comment that for s390x the offset
> 	may be an encoded register number.
> 
> gas/
> 	* gen-sframe.c (s390_sframe_xlate_do_register): New S390-
> 	specific function.  Uses SFRAME_S390X_OFFSET_ENCODE_REGNUM to
> 	represent FP/RA saved in another register on s390x.
> 	(sframe_xlate_do_register): Invoke s390_sframe_xlate_do_register
> 	on s390x.
> 
> libsframe/
> 	* sframe.c (sframe_fre_get_fp_offset, sframe_fre_get_fp_offset):
> 	Add comment that for s390x the offset may be an encoded register
> 	number.
> 	* sframe-dump.c (is_sframe_abi_arch_s390x): New helper to test
> 	whether ABI/arch is s390x.
> 	(dump_sframe_func_with_fres): Use SFRAME_S390X_OFFSET_IS_REGNUM
> 	and SFRAME_S390X_OFFSET_DECODE_REGNUM to dump FP/RA saved in
> 	another register on s390x.
> 	* doc/sframe-spec.texi (s390x): Document s390x-specific
> 	representation of FP/RA saved in another register.
> 
> gas/testsuite/
> 	* gas/cfi-sframe/cfi-sframe.exp: Update s390x-specific SFrame
> 	(error) tests.
> 	* gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.s: Rename
> 	to ...
> 	* gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d:
> 	Likewise.
> 	* gas/cfi-sframe/cfi-sframe-s390x-fpra-register-1.s: This.  Test
> 	no longer triggers a warning, as SFrame can represent FP and RA
> 	saved in registers.
> 	* gas/cfi-sframe/cfi-sframe-s390x-fpra-register-1.d: Likewise.
> 	* gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d: Test
> 	now triggers a different warning, as SFrame can represent FP and
> 	RA saved in registers, but not FP without RA saved in register.
> 
> Signed-off-by: Jens Remus <jremus@linux.ibm.com>

Few nits below.

Otherwise, LGTM.
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)
>      - Reword use of "FRE bytes" in SFrame spec. (Indu)
>      - Add comment on sframe_fre_get_{fp|ra}_offset that for s390x the offset
>        may be an encoded register number.
>      - Move comment on sframe_fre_get_ra_offset that for s390x the offset may
>        be SFRAME_FRE_RA_OFFSET_INVALID to next patch.
>      
>      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)
>      - Add comment on sframe_fre_get_{fp|ra}_offset that for s390x the offset
>        may be an encoded register number. (Indu)
>      - Add documentation that for s390x stack tracers need to implement
>        checks when restoring FP and RA from registers. (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.
>      - Reword test names.
>      - Adjust tests to commit bd9dc0a281a4 ("gas: sframe: reword diagnostic
>        to address ambiguity")
>      - Rename CFI SFrame test file names from s390 to s390x. (Indu)
>      - Reword test names.
> 
>   gas/gen-sframe.c                              | 35 ++++++++++++++++
>   .../cfi-sframe-s390x-fpra-register-1.d        | 22 ++++++++++
>   ...2.s => cfi-sframe-s390x-fpra-register-1.s} |  0
>   .../cfi-sframe-s390x-fpra-register-err-1.d    |  4 +-
>   .../cfi-sframe-s390x-fpra-register-err-2.d    | 15 -------
>   gas/testsuite/gas/cfi-sframe/cfi-sframe.exp   |  2 +-
>   include/sframe-api.h                          | 10 ++++-
>   include/sframe.h                              | 13 ++++++
>   libsframe/doc/sframe-spec.texi                | 41 ++++++++++++++-----
>   libsframe/sframe-dump.c                       | 24 ++++++++++-
>   libsframe/sframe.c                            | 10 ++++-
>   11 files changed, 142 insertions(+), 34 deletions(-)
>   create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-1.d
>   rename gas/testsuite/gas/cfi-sframe/{cfi-sframe-s390x-fpra-register-err-2.s => cfi-sframe-s390x-fpra-register-1.s} (100%)
>   delete mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d
> 
> diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
> index 89a61df4449e..a170c5b67e0d 100644
> --- a/gas/gen-sframe.c
> +++ b/gas/gen-sframe.c
> @@ -1126,6 +1126,37 @@ sframe_xlate_do_val_offset (const struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_U
>     return SFRAME_XLATE_OK;
>   }
>   
> +/* S390-specific translate DW_CFA_register into SFrame context.
> +   Return SFRAME_XLATE_OK if success.  */
> +
> +static int
> +s390_sframe_xlate_do_register (struct sframe_xlate_ctx *xlate_ctx,
> +			       struct cfi_insn_data *cfi_insn)
> +{
> +  /* The scratchpad FRE currently being updated with each cfi_insn
> +     being interpreted.  This FRE eventually gets linked in into the
> +     list of FREs for the specific function.  */
> +  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
> +
> +  gas_assert (cur_fre);
> +
> +  /* Change the rule for the register indicated by the register number to
> +     be the specified register.  Encode the register number as offset by
> +     shifting it to the left by one and setting the least-significant bit
> +     (LSB).  The LSB can be used to differentiate offsets from register
> +     numbers, as offsets from CFA are always a multiple of -8 on s390x.  */
> +  if (cfi_insn->u.rr.reg1 == SFRAME_CFA_FP_REG)
> +    sframe_fre_set_bp_track (cur_fre,
> +			     SFRAME_S390X_OFFSET_ENCODE_REGNUM (cfi_insn->u.rr.reg2));
> +  else if (sframe_ra_tracking_p ()
> +	   && cfi_insn->u.rr.reg1 == SFRAME_CFA_RA_REG)
> +    sframe_fre_set_ra_track (cur_fre,
> +			     SFRAME_S390X_OFFSET_ENCODE_REGNUM (cfi_insn->u.rr.reg2));
> +
> +  /* Safe to skip.  */
> +  return SFRAME_XLATE_OK;

Remove comment "Safe to skip."

> +}
> +
>   /* Translate DW_CFA_register into SFrame context.
>      Return SFRAME_XLATE_OK if success.  */
>   
> @@ -1133,6 +1164,10 @@ static int
>   sframe_xlate_do_register (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
>   			  struct cfi_insn_data *cfi_insn)
>   {
> +  /* Conditionally invoke S390-specific implementation.  */
> +  if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG)
> +    return s390_sframe_xlate_do_register (xlate_ctx, cfi_insn);
> +
>     /* Previous value of register1 is register2.  However, if the specified
>        register1 is not interesting (FP or RA reg), the current DW_CFA_register
>        instruction can be safely skipped without sacrificing the asynchronicity of
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-1.d
> new file mode 100644
> index 000000000000..0a5c8eb579e3
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-1.d
> @@ -0,0 +1,22 @@
> +#name: SFrame generation on s390x - RA and then FP saved in 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 +u +r16 +
> +    0+0008 +sp\+160 +r17 +r16 +
> +    0+0014 +sp\+160 +u +r16 +
> +    0+0018 +sp\+160 +u +u +
> +#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-1.s
> similarity index 100%
> rename from gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.s
> rename to gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-1.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
> index 7f1acd8c5d05..23e0411d8a2c 100644
> --- 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
> @@ -1,6 +1,6 @@
> -#name: SFrame generation on s390x - FP and then RA saved in register
> +#name: SFrame generation on s390x - FP without RA saved in registers
>   #as: --gsframe
> -#warning: FP register 11 in .cfi_register
> +#warning: FP without RA on stack
>   #objdump: --sframe=.sframe
>   #...
>   Contents of the SFrame section .sframe:
> 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
> deleted file mode 100644
> index 6573d01b997b..000000000000
> --- a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d
> +++ /dev/null
> @@ -1,15 +0,0 @@
> -#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.exp b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
> index d17cd767cc6e..1e7fc9e03cad 100644
> --- a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
> @@ -120,6 +120,6 @@ if { [istarget "s390x*-*-*"] && [gas_sframe_check] } then {
>       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-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-api.h b/include/sframe-api.h
> index 77ba32b0f4b9..f47afff1fd5e 100644
> --- a/include/sframe-api.h
> +++ b/include/sframe-api.h
> @@ -198,12 +198,18 @@ extern int32_t
>   sframe_fre_get_cfa_offset (sframe_decoder_ctx *dtcx,
>   			   sframe_frame_row_entry *fre, int *errp);
>   
> -/* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
> +/* Get the FP offset from the FRE.  If the offset is invalid, sets errp.
> +
> +   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
>   sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx,
>   			  sframe_frame_row_entry *fre, int *errp);
>   
> -/* Get the RA offset from the FRE.  If the offset is invalid, sets errp.  */
> +/* Get the RA offset from the FRE.  If the offset is invalid, sets errp.
> +
> +   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
>   sframe_fre_get_ra_offset (sframe_decoder_ctx *dctx,
>   			  sframe_frame_row_entry *fre, int *errp);
> diff --git a/include/sframe.h b/include/sframe.h
> index a87d6d491a2f..393748bcd2ad 100644
> --- a/include/sframe.h
> +++ b/include/sframe.h
> @@ -347,6 +347,19 @@ typedef struct sframe_frame_row_entry_addr4
>      SP value offset from CFA is -160.  */
>   #define SFRAME_S390X_SP_VAL_OFFSET			(-160)
>   
> +/* On s390x, the FP and RA registers can be saved either on the stack or,
> +   in case of leaf functions, in registers.  Store DWARF register numbers
> +   encoded as offset by using the least-significant bit (LSB) as indicator:
> +   - LSB=0: Stack offset.  The s390x ELF ABI mandates that stack register
> +     slots must be 8-byte aligned.
> +   - LSB=1: DWARF register number shifted to the left by one.  */
> +#define SFRAME_S390X_OFFSET_IS_REGNUM(offset) \
> +  ((offset) & 1)
> +#define SFRAME_S390X_OFFSET_ENCODE_REGNUM(regnum) \
> +  (((regnum) << 1) | 1)
> +#define SFRAME_S390X_OFFSET_DECODE_REGNUM(offset) \
> +  ((offset) >> 1)
> +

Perhaps it wont hurt to also use "SFRAME_V2" as prefix in the names:
  - SFRAME_V2_S390X_OFFSET_IS_REGNUM
  - SFRAME_V2_S390X_OFFSET_ENCODE_REGNUM
  - SFRAME_V2_S390X_OFFSET_ENCODE_REGNUM

This also aligns well with the choice made in the rest of the series 
(SFRAME_V2_FRE_S390X_CFA_OFFSET_ENCODE, 
SFRAME_V2_FRE_S390X_CFA_OFFSET_DECODE).

>   #ifdef	__cplusplus
>   }
>   #endif
> diff --git a/libsframe/doc/sframe-spec.texi b/libsframe/doc/sframe-spec.texi
> index ce06e50e3d1f..98c056c213d2 100644
> --- a/libsframe/doc/sframe-spec.texi
> +++ b/libsframe/doc/sframe-spec.texi
> @@ -134,7 +134,13 @@ 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.
> +@item SFRAME_S390X_SP_VAL_OFFSET: SP value offset (from CFA).
> +@item SFRAME_S390X_OFFSET_IS_REGNUM: Test whether FP/RA offset is an encoded
> +DWARF register number.
> +@item SFRAME_S390X_OFFSET_ENCODE_REGNUM: Encode a DWARF register number as an
> +FP/RA offset.
> +@item SFRAME_S390X_OFFSET_DECODE_REGNUM: Decode a DWARF register number from
> +an FP/RA offset.
>   @end itemize
>   @end itemize
>   
> @@ -772,10 +778,11 @@ This section covers the ABI/arch-specific definition of the SFrame file format.
>   
>   Currently, the only part of the SFrame file format definition that is
>   ABI/arch-specific is the interpretation of the variable number of bytes at the
> -tail end of each SFrame FRE.  Currently, these bytes are only used for
> -representing stack offsets (for all the currently supported ABIs).  It is
> -recommended to peruse this section along with @xref{SFrame Frame Row Entries}
> -for clarity of context.
> +tail end of each SFrame FRE.  Currently, these bytes are used for representing
> +stack offsets (for AMD64 and AARCH64 ABIs).  For s390x ABI, the interpretation
> +of these bytes may be stack offsets or even register numbers.  It is recommended
> +to peruse this section along with @xref{SFrame Frame Row Entries} for clarity of
> +context.
>   
>   Future ABIs must specify the algorithm for identifying the appropriate SFrame
>   FRE stack offsets in this chapter.  This should inevitably include the
> @@ -870,16 +877,30 @@ 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.
> +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
> +in the SFrame stack trace format the DWARF register number is encoded as
> +RA/FP offset using the least-significant bit (LSB) as indication:
> +offset = (regnum << 1) | 1.  A LSB of zero indicates a stack slot offset.
> +A LSB of one indicates a DWARF register number, which is interpreted as:
> +regnum = offset >> 1.  Given the nature of leaf functions, this can only occur
> +in the topmost frame during stack tracing.  It is recommended that a stack
> +tracer implementation performs the required checks to ensure that restoring
> +FP and RA from the said register locations is done only for topmost stack
> +frame in the callchain.
> +
> +Given the nature of things, the number of stack offsets and/or register numbers
> +seen on s390x per SFrame FRE is either 1, 2, or 3.
>   
>   Hence, in summary:
>   
> -@multitable {Offset ID} {Interpretation in s390x in X}
> +@multitable @columnfractions .15 .85
>   @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
> +@item 2 @tab RA stack slot = CFA + offset2, if (offset2 & 1 == 0)
> +           @*RA register number = offset2 >> 1, if (offset2 & 1 == 1)
> +@item 3 @tab FP stack slot = CFA + offset3, if (offset3 & 1 == 0)
> +           @*FP register number = offset3 >> 1, if (offset3 & 1 == 1)
>   @end multitable
>   
>   The s390x ELF ABI defines the CFA as stack pointer (SP) at call site +160.  The
> diff --git a/libsframe/sframe-dump.c b/libsframe/sframe-dump.c
> index 1fa508d9bad2..09ecd4faab54 100644
> --- a/libsframe/sframe-dump.c
> +++ b/libsframe/sframe-dump.c
> @@ -40,6 +40,14 @@ is_sframe_abi_arch_aarch64 (sframe_decoder_ctx *sfd_ctx)
>     return aarch64_p;
>   }
>   
> +/* Return TRUE if the SFrame section is associated with the s390x ABI.  */
> +
> +static bool
> +is_sframe_abi_arch_s390x (sframe_decoder_ctx *sfd_ctx)
> +{
> +  return sframe_decoder_get_abi_arch (sfd_ctx) == SFRAME_ABI_S390X_ENDIAN_BIG;
> +}
> +
>   static void
>   dump_sframe_header (sframe_decoder_ctx *sfd_ctx)
>   {
> @@ -175,7 +183,13 @@ dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_ctx,
>   
>         /* Dump SP/FP info.  */
>         if (err[1] == 0)
> -	sprintf (temp, "c%+d", fp_offset);
> +	{
> +	  if (is_sframe_abi_arch_s390x (sfd_ctx)
> +	      && SFRAME_S390X_OFFSET_IS_REGNUM (fp_offset))
> +	    sprintf (temp, "r%d", SFRAME_S390X_OFFSET_DECODE_REGNUM (fp_offset));
> +	  else
> +	    sprintf (temp, "c%+d", fp_offset);
> +	}
>         else
>   	strcpy (temp, "u");
>         printf ("%-10s", temp);
> @@ -187,7 +201,13 @@ dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_ctx,
>   	  != SFRAME_CFA_FIXED_RA_INVALID)
>   	strcpy (temp, "f");
>         else if (err[2] == 0)
> -	sprintf (temp, "c%+d", ra_offset);
> +	{
> +	  if (is_sframe_abi_arch_s390x (sfd_ctx)
> +	      && SFRAME_S390X_OFFSET_IS_REGNUM (ra_offset))
> +	    sprintf (temp, "r%d", SFRAME_S390X_OFFSET_DECODE_REGNUM (ra_offset));
> +	  else
> +	    sprintf (temp, "c%+d", ra_offset);
> +	}
>         else
>   	strcpy (temp, "u");
>   
> diff --git a/libsframe/sframe.c b/libsframe/sframe.c
> index 4a62b8bb2762..e5f9b198402d 100644
> --- a/libsframe/sframe.c
> +++ b/libsframe/sframe.c
> @@ -679,7 +679,10 @@ sframe_fre_get_cfa_offset (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
>     return sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, errp);
>   }
>   
> -/* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
> +/* Get the FP offset from the FRE.  If the offset is invalid, sets errp.
> +
> +   For s390x the offset may be an encoded register number, indicated by
> +   LSB set to one, which is only valid in the topmost frame.  */
>   
>   int32_t
>   sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx,
> @@ -706,7 +709,10 @@ sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx,
>     return sframe_get_fre_offset (fre, fp_offset_idx, errp);
>   }
>   
> -/* Get the RA offset from the FRE.  If the offset is invalid, sets errp.  */
> +/* Get the RA offset from the FRE.  If the offset is invalid, sets errp.
> +
> +   For s390x the offset may be an encoded register number, indicated by
> +   LSB set to one, which is only valid in the topmost frame.  */
>   
>   int32_t
>   sframe_fre_get_ra_offset (sframe_decoder_ctx *dctx,



More information about the Binutils mailing list