The unwind user eh_frame implementation works well with GCC and Clang generated code on s390. Enable it.
Signed-off-by: Jens Remus <[email protected]> --- arch/s390/Kconfig | 1 + arch/s390/include/asm/unwind_user.h | 71 ++++++++++++++++++++ arch/s390/include/asm/unwind_user_eh_frame.h | 24 +++++++ 3 files changed, 96 insertions(+) create mode 100644 arch/s390/include/asm/unwind_user.h create mode 100644 arch/s390/include/asm/unwind_user_eh_frame.h diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 84404e6778d5..fa229ac92d5a 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -251,6 +251,7 @@ config S390 select HAVE_SOFTIRQ_ON_OWN_STACK select HAVE_STACKPROTECTOR if CC_HAS_STACKPROTECTOR_GLOBAL select HAVE_SYSCALL_TRACEPOINTS + select HAVE_UNWIND_USER_EH_FRAME select HAVE_VIRT_CPU_ACCOUNTING select HAVE_VIRT_CPU_ACCOUNTING_IDLE select HOTPLUG_SMT diff --git a/arch/s390/include/asm/unwind_user.h b/arch/s390/include/asm/unwind_user.h new file mode 100644 index 000000000000..41ff0b477626 --- /dev/null +++ b/arch/s390/include/asm/unwind_user.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_S390_UNWIND_USER_H +#define _ASM_S390_UNWIND_USER_H + +#include <linux/sched/task_stack.h> +#include <linux/types.h> +#include <asm/fpu.h> + +#ifdef CONFIG_UNWIND_USER + +static inline int unwind_user_word_size(struct pt_regs *regs) +{ + return 8; +} + +static inline int unwind_user_get_ra_reg(unsigned long *val) +{ + struct pt_regs *regs = task_pt_regs(current); + *val = regs->gprs[14]; + return 0; +} +#define unwind_user_get_ra_reg unwind_user_get_ra_reg + +static inline unsigned long __s390_dwarf_fpr_to_fpr(unsigned int regnum) +{ + unsigned int fpr; + + /* + * Convert from s390 DWARF floating-point register number (16..31) + * to floating-point register number (0..15): left rotate the least + * significant three bits and then return the least significant four + * bits. + */ + fpr = (regnum & 3) << 1; + fpr |= (regnum & 4) >> 2; + fpr |= (regnum & 8); + return fpr; +} + +static inline unsigned long __s390_get_dwarf_fpr(unsigned int regnum) +{ + struct fpu *fpu = ¤t->thread.ufpu; + + save_user_fpu_regs(); + return fpu->vxrs[__s390_dwarf_fpr_to_fpr(regnum)].high; +} + +static inline int unwind_user_get_reg(unsigned long *val, unsigned int regnum) +{ + if (regnum <= 15) { + /* DWARF register numbers 0..15 */ + struct pt_regs *regs = task_pt_regs(current); + *val = regs->gprs[regnum]; + return 0; + } else if (regnum <= 31) { + /* DWARF register numbers 16..31 */ + *val = __s390_get_dwarf_fpr(regnum); + return 0; + } + + pr_debug("%s (%d): %s(%u): unsupported register number\n", + current->comm, current->pid, __func__, regnum); + return -EINVAL; +} +#define unwind_user_get_reg unwind_user_get_reg + +#endif /* CONFIG_UNWIND_USER */ + +#include <asm-generic/unwind_user.h> + +#endif /* _ASM_S390_UNWIND_USER_H */ diff --git a/arch/s390/include/asm/unwind_user_eh_frame.h b/arch/s390/include/asm/unwind_user_eh_frame.h new file mode 100644 index 000000000000..842d9f7c3d80 --- /dev/null +++ b/arch/s390/include/asm/unwind_user_eh_frame.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_S390_UNWIND_USER_EH_FRAME_H +#define _ASM_S390_UNWIND_USER_EH_FRAME_H + +#define EH_FRAME_REG_SP 15 /* designated stack pointer register */ +#define EH_FRAME_REG_FP 11 /* "preferred" frame pointer register */ +#define EH_FRAME_REG_RA 14 /* designaged return address register */ + +/* Instructions must be 2-byte aligned */ +#define EH_FRAME_MAX_CODE_ALIGN 2 + +/* CFA is defined as SP at call site + 160, so that SP = CFA - 160 */ +#define EH_FRAME_SP_VAL_OFFSET -160 + +/* SP may be saved on the stack or in a register */ +static inline bool eh_frame_reject_sp_rule(void) +{ + return false; +} +#define eh_frame_reject_sp_rule eh_frame_reject_sp_rule + +#include <asm-generic/unwind_user_eh_frame.h> + +#endif /* _ASM_S390_UNWIND_USER_EH_FRAME_H */ -- 2.53.0
