[5/6] LoongArch: Fix up the prologue unwinder unwind exception frame

Message ID 20230224101013.26971-6-hejinyang@loongson.cn
State New
Headers
Series Drop the per-node-mode exception handlers |

Commit Message

Jinyang He Feb. 24, 2023, 10:10 a.m. UTC
  It is a simply way to correct the unwind info when the special functions
influence the normal prologue analysis. We find out the position where
should unwind by PT_REGS, and mark it UNW_NEED_RESET. Linkers will
collect them and the prologue unwinder will compare them to pc.

Signed-off-by: Jinyang He <hejinyang@loongson.cn>
---
 arch/loongarch/include/asm/traps.h      | 13 +++++++++
 arch/loongarch/include/asm/unwind.h     |  2 +-
 arch/loongarch/kernel/genex.S           |  1 +
 arch/loongarch/kernel/mcount_dyn.S      |  2 ++
 arch/loongarch/kernel/unwind_prologue.c | 37 +++++++++----------------
 arch/loongarch/kernel/vmlinux.lds.S     |  9 ++++++
 6 files changed, 39 insertions(+), 25 deletions(-)
  

Patch

diff --git a/arch/loongarch/include/asm/traps.h b/arch/loongarch/include/asm/traps.h
index 8f276253f145..0c30a024a9e5 100644
--- a/arch/loongarch/include/asm/traps.h
+++ b/arch/loongarch/include/asm/traps.h
@@ -5,6 +5,7 @@ 
 #ifndef _ASM_TRAPS_H
 #define _ASM_TRAPS_H
 
+#include <asm/asm.h>
 #include <asm/loongarch.h>		// For EXCCODES
 
 #ifdef __ASSEMBLY__
@@ -35,11 +36,23 @@ 
 	__VA_ARGS__;						\
 	.popsection;
 
+#ifdef CONFIG_UNWINDER_PROLOGUE
+#define UNW_NEED_RESET						\
+	668:							\
+	.pushsection .unw_need_reset, "a";			\
+	PTR 668b;						\
+	.popsection;
+#else /* CONFIG_UNWINDER_PROLOGUE */
+#define UNW_NEED_RESET
+#endif
+
 #else /* __ASSEMBLY__ */
 
 #define VECSIZE	0x200
 extern void *__ex_handlers;
 extern void *__tlbr_entry;
+extern void *__unw_need_reset;
+extern void *__unw_need_reset_end;
 
 static inline void set_eentry(void *entry)
 {
diff --git a/arch/loongarch/include/asm/unwind.h b/arch/loongarch/include/asm/unwind.h
index b9dce87afd2e..d9a10e264bdd 100644
--- a/arch/loongarch/include/asm/unwind.h
+++ b/arch/loongarch/include/asm/unwind.h
@@ -22,7 +22,7 @@  struct unwind_state {
 	char type; /* UNWINDER_XXX */
 	struct stack_info stack_info;
 	struct task_struct *task;
-	bool first, error, reset;
+	bool first, error, need_reset;
 	int graph_idx;
 	unsigned long sp, pc, ra;
 };
diff --git a/arch/loongarch/kernel/genex.S b/arch/loongarch/kernel/genex.S
index 256e2e5b83d4..8705a7661ce9 100644
--- a/arch/loongarch/kernel/genex.S
+++ b/arch/loongarch/kernel/genex.S
@@ -78,6 +78,7 @@  SYM_FUNC_START(handle_\exception)
 	move	a0, sp
 	la_abs	t0, do_\handler
 	jirl	ra, t0, 0
+	UNW_NEED_RESET
 	RESTORE_ALL_AND_RET
 SYM_FUNC_END(handle_\exception)
 	.endm
diff --git a/arch/loongarch/kernel/mcount_dyn.S b/arch/loongarch/kernel/mcount_dyn.S
index bbabf06244c2..3550bab52ff0 100644
--- a/arch/loongarch/kernel/mcount_dyn.S
+++ b/arch/loongarch/kernel/mcount_dyn.S
@@ -7,6 +7,7 @@ 
 #include <asm/ftrace.h>
 #include <asm/regdef.h>
 #include <asm/stackframe.h>
+#include <asm/traps.h>
 
 	.text
 /*
@@ -81,6 +82,7 @@  SYM_CODE_START(ftrace_common)
 
 SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
 	bl		ftrace_stub
+	UNW_NEED_RESET
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL)
 	nop				/* b ftrace_graph_caller */
diff --git a/arch/loongarch/kernel/unwind_prologue.c b/arch/loongarch/kernel/unwind_prologue.c
index de18335c6ba6..aa01c881481c 100644
--- a/arch/loongarch/kernel/unwind_prologue.c
+++ b/arch/loongarch/kernel/unwind_prologue.c
@@ -10,33 +10,22 @@ 
 #include <asm/loongson.h>
 #include <asm/ptrace.h>
 #include <asm/setup.h>
+#include <asm/traps.h>
 #include <asm/unwind.h>
 
-static inline bool fix_exception(unsigned long pc)
-{
-	return false;
-}
-
-/*
- * As we meet ftrace_regs_entry, reset first flag like first doing
- * tracing. Prologue analysis will stop soon because PC is at entry.
- */
-static inline bool fix_ftrace(unsigned long pc)
-{
-#ifdef CONFIG_DYNAMIC_FTRACE
-	return pc == (unsigned long)ftrace_call + LOONGARCH_INSN_SIZE;
-#else
-	return false;
-#endif
-}
-
 static inline bool unwind_state_fixup(struct unwind_state *state)
 {
-	if (!fix_exception(state->pc) && !fix_ftrace(state->pc))
-		return false;
+	unsigned long *p = (unsigned long *)&__unw_need_reset;
+	unsigned long *q = (unsigned long *)&__unw_need_reset_end;
 
-	state->reset = true;
-	return true;
+	for (; p < q; p++) {
+		if (*p != state->pc)
+			continue;
+		state->need_reset = true;
+		return true;
+	}
+
+	return false;
 }
 
 /*
@@ -59,10 +48,10 @@  static bool unwind_by_prologue(struct unwind_state *state)
 	if (state->sp >= info->end || state->sp < info->begin)
 		return false;
 
-	if (state->reset) {
+	if (state->need_reset) {
 		regs = (struct pt_regs *)state->sp;
 		state->first = true;
-		state->reset = false;
+		state->need_reset = false;
 		state->pc = regs->csr_era;
 		state->ra = regs->regs[1];
 		state->sp = regs->regs[3];
diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S
index e99b50359900..00f1f9061961 100644
--- a/arch/loongarch/kernel/vmlinux.lds.S
+++ b/arch/loongarch/kernel/vmlinux.lds.S
@@ -70,6 +70,15 @@  SECTIONS
 		*(.tlbrhandler)
 	}
 
+#ifdef CONFIG_UNWINDER_PROLOGUE
+	. = ALIGN(8);
+	.unw_need_reset : {
+		__unw_need_reset = .;
+		*(.unw_need_reset)
+		__unw_need_reset_end = .;
+	}
+#endif
+
 	/*
 	 * struct alt_inst entries. From the header (alternative.h):
 	 * "Alternative instructions for different CPU types or capabilities"