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


Reply via email to