summaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/kernel')
-rw-r--r--arch/arm64/kernel/entry.S12
-rw-r--r--arch/arm64/kernel/stacktrace.c19
2 files changed, 23 insertions, 8 deletions
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 2284c296e3f7..0667fb7d8bb1 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -178,7 +178,7 @@ alternative_endif
mrs \rd, sp_el0
.endm
- .macro irq_stack_entry, dummy_lr
+ .macro irq_stack_entry
mov x19, sp // preserve the original sp
this_cpu_ptr irq_stack, x25, x26
@@ -196,10 +196,12 @@ alternative_endif
add x26, x25, x26
mov sp, x26
- /* Add a dummy stack frame */
- stp x29, \dummy_lr, [sp, #-16]! // dummy stack frame
+ /*
+ * Add a dummy stack frame, this non-standard format is fixed up
+ * by unwind_frame()
+ */
+ stp x29, x19, [sp, #-16]!
mov x29, sp
- stp x19, xzr, [sp, #-16]!
9998:
.endm
@@ -229,7 +231,7 @@ tsk .req x28 // current thread_info
.macro irq_handler
ldr_l x1, handle_arch_irq
mov x0, sp
- irq_stack_entry x22
+ irq_stack_entry
blr x1
irq_stack_exit
.endm
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index d916d5b6aef6..b9fd3a8abfc1 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -70,17 +70,30 @@ int notrace unwind_frame(struct stackframe *frame)
* 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.
+ * unpack the dummy frame to find the original elr.
*
* Check the frame->fp we read from the bottom of the irq_stack,
* and the original task stack pointer are both in current->stack.
*/
if (frame->sp == irq_stack_ptr) {
+ struct pt_regs *irq_args;
unsigned long orig_sp = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr);
- if(object_is_on_stack((void *)orig_sp) &&
- object_is_on_stack((void *)frame->fp))
+ if (object_is_on_stack((void *)orig_sp) &&
+ object_is_on_stack((void *)frame->fp)) {
frame->sp = orig_sp;
+
+ /* orig_sp is the saved pt_regs, find the elr */
+ irq_args = (struct pt_regs *)orig_sp;
+ frame->pc = irq_args->pc;
+ } else {
+ /*
+ * This frame has a non-standard format, and we
+ * didn't fix it, because the data looked wrong.
+ * Refuse to output this frame.
+ */
+ return -EINVAL;
+ }
}
return 0;