s390: Represent FP without RA saved in SFrame

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>
This commit is contained in:
Jens Remus
2025-07-11 10:29:40 +02:00
parent 61b808e087
commit 955570f097
13 changed files with 116 additions and 47 deletions

View File

@@ -152,6 +152,9 @@ DWARF register number.
FP/RA offset.
@item SFRAME_V2_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
@@ -890,12 +893,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. Stack tracers are recommended to validate that
the "unchanged RA" pattern, when present, is seen only for the topmost stack
frame. 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}.
Stack tracers are recommended to validate that the "unchanged RA" pattern, when
present, is seen only for the topmost stack frame. 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.
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
@@ -919,6 +923,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

View File

@@ -211,6 +211,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)

View File

@@ -733,6 +733,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. */