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>
This commit is contained in:

committed by
Will Deacon

parent
6cdf9c7ca6
commit
132cd887b5
@@ -20,6 +20,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/stacktrace.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/stacktrace.h>
|
||||
|
||||
/*
|
||||
@@ -39,17 +40,41 @@ int notrace unwind_frame(struct stackframe *frame)
|
||||
{
|
||||
unsigned long high, low;
|
||||
unsigned long fp = frame->fp;
|
||||
unsigned long irq_stack_ptr;
|
||||
|
||||
/*
|
||||
* Use raw_smp_processor_id() to avoid false-positives from
|
||||
* CONFIG_DEBUG_PREEMPT. get_wchan() calls unwind_frame() on sleeping
|
||||
* task stacks, we can be pre-empted in this case, so
|
||||
* {raw_,}smp_processor_id() may give us the wrong value. Sleeping
|
||||
* tasks can't ever be on an interrupt stack, so regardless of cpu,
|
||||
* the checks will always fail.
|
||||
*/
|
||||
irq_stack_ptr = IRQ_STACK_PTR(raw_smp_processor_id());
|
||||
|
||||
low = frame->sp;
|
||||
high = ALIGN(low, THREAD_SIZE);
|
||||
/* irq stacks are not THREAD_SIZE aligned */
|
||||
if (on_irq_stack(frame->sp, raw_smp_processor_id()))
|
||||
high = irq_stack_ptr;
|
||||
else
|
||||
high = ALIGN(low, THREAD_SIZE) - 0x20;
|
||||
|
||||
if (fp < low || fp > high - 0x18 || fp & 0xf)
|
||||
if (fp < low || fp > high || fp & 0xf)
|
||||
return -EINVAL;
|
||||
|
||||
frame->sp = fp + 0x10;
|
||||
frame->fp = *(unsigned long *)(fp);
|
||||
frame->pc = *(unsigned long *)(fp + 8);
|
||||
|
||||
/*
|
||||
* Check whether we are going to walk through from interrupt stack
|
||||
* to task stack.
|
||||
* If we reach the end of the stack - and its an interrupt stack,
|
||||
* read the original task stack pointer from the dummy frame.
|
||||
*/
|
||||
if (frame->sp == irq_stack_ptr)
|
||||
frame->sp = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user