diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/include/asm/stacktrace.h | 10 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 3 | ||||
-rw-r--r-- | arch/arm/kernel/unwind.c | 8 |
3 files changed, 19 insertions, 2 deletions
diff --git a/arch/arm/include/asm/stacktrace.h b/arch/arm/include/asm/stacktrace.h index 33ee1aa4b8c0..d87d60532b86 100644 --- a/arch/arm/include/asm/stacktrace.h +++ b/arch/arm/include/asm/stacktrace.h @@ -18,6 +18,16 @@ struct stackframe { struct llist_node *kr_cur; struct task_struct *tsk; #endif +#ifdef CONFIG_ARM_UNWIND + /* + * This field is used to track the stack pointer value when calling + * __entry routines. This is needed when IRQ stacks and overflow stacks + * are used, because in that case, the struct pt_regs passed to these + * __entry routines may be at the top of the task stack, while we are + * executing from another stack. + */ + unsigned long sp_low; +#endif }; static __always_inline diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index e4698605bb72..89be21ec3b52 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -74,7 +74,8 @@ void dump_backtrace_entry(unsigned long where, unsigned long from, loglvl, where, from); #endif - if (in_entry_text(from) && end <= ALIGN(frame, THREAD_SIZE)) + if (!IS_ENABLED(CONFIG_UNWINDER_ARM) && + in_entry_text(from) && end <= ALIGN(frame, THREAD_SIZE)) dump_mem(loglvl, "Exception stack", frame + 4, end); } diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c index 9cb9af3fc433..b7a6141c342f 100644 --- a/arch/arm/kernel/unwind.c +++ b/arch/arm/kernel/unwind.c @@ -29,6 +29,7 @@ #include <linux/spinlock.h> #include <linux/list.h> +#include <asm/sections.h> #include <asm/stacktrace.h> #include <asm/traps.h> #include <asm/unwind.h> @@ -459,6 +460,7 @@ int unwind_frame(struct stackframe *frame) frame->sp = ctrl.vrs[SP]; frame->lr = ctrl.vrs[LR]; frame->pc = ctrl.vrs[PC]; + frame->sp_low = ctrl.sp_low; return URC_OK; } @@ -502,7 +504,11 @@ void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk, urc = unwind_frame(&frame); if (urc < 0) break; - dump_backtrace_entry(where, frame.pc, frame.sp - 4, loglvl); + if (in_entry_text(where)) + dump_mem(loglvl, "Exception stack", frame.sp_low, + frame.sp_low + sizeof(struct pt_regs)); + + dump_backtrace_entry(where, frame.pc, 0, loglvl); } } |