aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/traps.c
diff options
context:
space:
mode:
authorAKASHI Takahiro <takahiro.akashi@linaro.org>2015-12-04 06:02:26 -0500
committerWill Deacon <will.deacon@arm.com>2015-12-08 06:41:51 -0500
commit132cd887b5c54758d04bf25c52fa48f45e843a30 (patch)
tree5c911127a290dcd7a78c417ced4ae096dd93bd5c /arch/arm64/kernel/traps.c
parent6cdf9c7ca687e01840d0215437620a20263012fc (diff)
arm64: Modify stack trace and dump for use with irq_stack
This patch allows unwind_frame() to traverse from interrupt stack to task stack correctly. It requires data from a dummy stack frame, created during irq_stack_entry(), added by a later patch. A similar approach is taken to modify dump_backtrace(), which expects to find struct pt_regs underneath any call to functions marked __exception. When on an irq_stack, the struct pt_regs is stored on the old task stack, the location of which is stored in the dummy stack frame. Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> [james.morse: merged two patches, reworked for per_cpu irq_stacks, and no alignment guarantees, added irq_stack definitions] Signed-off-by: James Morse <james.morse@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch/arm64/kernel/traps.c')
-rw-r--r--arch/arm64/kernel/traps.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index e9b9b5364393..8a0084541f84 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -146,6 +146,7 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
146static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) 146static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
147{ 147{
148 struct stackframe frame; 148 struct stackframe frame;
149 unsigned long irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id());
149 150
150 pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk); 151 pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
151 152
@@ -180,9 +181,20 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
180 if (ret < 0) 181 if (ret < 0)
181 break; 182 break;
182 stack = frame.sp; 183 stack = frame.sp;
183 if (in_exception_text(where)) 184 if (in_exception_text(where)) {
185 /*
186 * If we switched to the irq_stack before calling this
187 * exception handler, then the pt_regs will be on the
188 * task stack. The easiest way to tell is if the large
189 * pt_regs would overlap with the end of the irq_stack.
190 */
191 if (stack < irq_stack_ptr &&
192 (stack + sizeof(struct pt_regs)) > irq_stack_ptr)
193 stack = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr);
194
184 dump_mem("", "Exception stack", stack, 195 dump_mem("", "Exception stack", stack,
185 stack + sizeof(struct pt_regs), false); 196 stack + sizeof(struct pt_regs), false);
197 }
186 } 198 }
187} 199}
188 200