diff --git a/gas/NEWS b/gas/NEWS index cbca8fe8656..71d9c9cdd76 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). + * All SFrame sections generated by gas have the header flag SFRAME_F_FDE_FUNC_START_PCREL set. gas was already emitting SFrame sections with the applicable encoding. Setting the flag ensures compliance with the diff --git a/gas/config/tc-s390.c b/gas/config/tc-s390.c index d5d3976d5fc..b073d8edbd2 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 */ @@ -2865,6 +2878,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 9206c029a1c..c92769e507b 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 diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c index 3cba5085e1c..3d727b6475d 100644 --- a/gas/gen-sframe.c +++ b/gas/gen-sframe.c @@ -714,7 +714,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. */ @@ -1117,7 +1117,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 00000000000..df315df23f2 --- /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: SFRAME_F_FDE_FUNC_START_PCREL + 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 00000000000..7d132a4a963 --- /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 00000000000..a772c2bd055 --- /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: SFRAME_F_FDE_FUNC_START_PCREL + 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 00000000000..6d52037613d --- /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 00000000000..14f2382e145 --- /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: SFRAME_F_FDE_FUNC_START_PCREL + 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 00000000000..8b724df40ff --- /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 00000000000..0d3b47573c2 --- /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: SFRAME_F_FDE_FUNC_START_PCREL + 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 00000000000..dbcf439c156 --- /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 00000000000..519c2353059 --- /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: SFRAME_F_FDE_FUNC_START_PCREL + 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 00000000000..7cea16520da --- /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 00000000000..e5eac75d3f2 --- /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: 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 +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 00000000000..3d9c8cbdb77 --- /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 00000000000..7d71874111b --- /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: SFRAME_F_FDE_FUNC_START_PCREL + 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 00000000000..a84c39105f2 --- /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 00000000000..ad83f650cd6 --- /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: SFRAME_F_FDE_FUNC_START_PCREL + 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 00000000000..48b01ac5f57 --- /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 00000000000..7dde59c8c07 --- /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: SFRAME_F_FDE_FUNC_START_PCREL + 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 00000000000..1d4497178ad --- /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 341a56a9eab..d17cd767cc6 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 c0375ba6b7c..0278a8dc47c 100644 --- a/include/sframe.h +++ b/include/sframe.h @@ -104,6 +104,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 @@ -201,7 +202,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; @@ -259,7 +260,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 @@ -285,7 +286,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 @@ -353,6 +354,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 e5bfb511ff6..c41acf10ca1 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 00000000000..f7075697d1e --- /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 00000000000..75657e93e33 --- /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 00000000000..353dbce6ee2 --- /dev/null +++ b/ld/testsuite/ld-s390/sframe-simple-1.d @@ -0,0 +1,31 @@ +#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, + SFRAME_F_FDE_FUNC_START_PCREL + 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 69fe873b9ec..57e116356a1 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 @@ -139,6 +139,14 @@ bytes to the start PC of the associated function from the field itself. bytes to the start PC of the associated function from the start of the SFrame section. @end itemize +@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 @minus + @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. @@ -421,6 +429,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 @@ -794,6 +806,7 @@ auxiliary SFrame header, etc., if used, must also be outlined here. @menu * AMD64:: * AArch64:: +* s390x:: @end menu @node AMD64 @@ -850,6 +863,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. 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. + +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 @@ -913,7 +970,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 977abf5ef0a..ba01f06a09b 100644 --- a/libsframe/sframe.c +++ b/libsframe/sframe.c @@ -166,6 +166,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;