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;
}
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;
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)
{
= 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;
--- /dev/null
+#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: SFRAME_F_FDE_FUNC_START_PCREL
+ 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
+++ /dev/null
-#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: SFRAME_F_FDE_FUNC_START_PCREL
- Num FDEs: 0
- Num FREs: 0
-
-#pass
--- /dev/null
+#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: SFRAME_F_FDE_FUNC_START_PCREL
+ 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
+++ /dev/null
-#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: SFRAME_F_FDE_FUNC_START_PCREL
- Num FDEs: 0
- Num FREs: 0
-
-#pass
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"
}
/* 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
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
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. */
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
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
@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
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)
/* 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. */