The x86-64 .eh_frame implementation works well with GCC and Clang generated code. Enable it.
Signed-off-by: Jens Remus <[email protected]> --- arch/x86/Kconfig | 1 + arch/x86/include/asm/unwind_user.h | 40 +++++++++++++++++++++ arch/x86/include/asm/unwind_user_eh_frame.h | 22 ++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 arch/x86/include/asm/unwind_user_eh_frame.h diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index bdad90f210e4..fe7919915084 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -300,6 +300,7 @@ config X86 select HAVE_SYSCALL_TRACEPOINTS select HAVE_UACCESS_VALIDATION if HAVE_OBJTOOL select HAVE_UNSTABLE_SCHED_CLOCK + select HAVE_UNWIND_USER_EH_FRAME if X86_64 select HAVE_UNWIND_USER_FP if X86_64 select HAVE_USER_RETURN_NOTIFIER select HAVE_GENERIC_VDSO diff --git a/arch/x86/include/asm/unwind_user.h b/arch/x86/include/asm/unwind_user.h index c96645c824d1..df1966bcb0f6 100644 --- a/arch/x86/include/asm/unwind_user.h +++ b/arch/x86/include/asm/unwind_user.h @@ -4,6 +4,7 @@ #ifdef CONFIG_UNWIND_USER +#include <linux/sched/task_stack.h> #include <asm/ptrace.h> #include <asm/uprobes.h> @@ -15,6 +16,45 @@ static inline int unwind_user_word_size(struct pt_regs *regs) return user_64bit_mode(regs) ? 8 : 4; } +#ifdef CONFIG_X86_64 + +static inline int unwind_user_get_reg(unsigned long *val, unsigned int regnum) +{ + struct pt_regs *regs = task_pt_regs(current); + + /* TODO: eh_frame is currently limited to x86-64 */ + if (!user_64bit_mode(regs)) + return -EINVAL; + + switch (regnum) { + /* DWARF register numbers 0..15 */ + case 0: *val = regs->ax; break; + case 1: *val = regs->dx; break; + case 2: *val = regs->cx; break; + case 3: *val = regs->bx; break; + case 4: *val = regs->si; break; + case 5: *val = regs->di; break; + case 6: *val = regs->bp; break; + case 7: *val = regs->sp; break; + case 8: *val = regs->r8; break; + case 9: *val = regs->r9; break; + case 10: *val = regs->r10; break; + case 11: *val = regs->r11; break; + case 12: *val = regs->r12; break; + case 13: *val = regs->r13; break; + case 14: *val = regs->r14; break; + case 15: *val = regs->r15; break; + default: + pr_debug("%s (%d): %s(%u): unsupported register number\n", + current->comm, current->pid, __func__, regnum); + return -EINVAL; + } + return 0; +} +#define unwind_user_get_reg unwind_user_get_reg + +#endif /* CONFIG_X86_64 */ + #endif /* CONFIG_UNWIND_USER */ #ifdef CONFIG_HAVE_UNWIND_USER_FP diff --git a/arch/x86/include/asm/unwind_user_eh_frame.h b/arch/x86/include/asm/unwind_user_eh_frame.h new file mode 100644 index 000000000000..fdccbda2fe4b --- /dev/null +++ b/arch/x86/include/asm/unwind_user_eh_frame.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_X86_UNWIND_USER_EH_FRAME_H +#define _ASM_X86_UNWIND_USER_EH_FRAME_H + +#ifdef CONFIG_X86_64 + +#define EH_FRAME_REG_SP 7 /* designated stack pointer register */ +#define EH_FRAME_REG_FP 6 /* designated frame pointer register */ +#define EH_FRAME_REG_RA 16 /* (pseudo) return address register */ + +/* Instructions must be 1-byte aligned */ +#define EH_FRAME_MAX_CODE_ALIGN 1 + +/* Stack grows towards lower addresses and SP must be 8-byte aligned */ +#define EH_FRAME_MIN_DATA_ALIGN -8 +#define EH_FRAME_MAX_DATA_ALIGN -1 + +#endif + +#include <asm-generic/unwind_user_eh_frame.h> + +#endif /* _ASM_X86_UNWIND_USER_EH_FRAME_H */ -- 2.53.0
