diff options
Diffstat (limited to 'arch/arm64/kernel/traps.c')
-rw-r--r-- | arch/arm64/kernel/traps.c | 52 |
1 files changed, 39 insertions, 13 deletions
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index e9b9b5364393..cbedd724f48e 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c | |||
@@ -146,17 +146,15 @@ static void dump_instr(const char *lvl, struct pt_regs *regs) | |||
146 | static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) | 146 | static 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()); | ||
150 | int skip; | ||
149 | 151 | ||
150 | pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk); | 152 | pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk); |
151 | 153 | ||
152 | if (!tsk) | 154 | if (!tsk) |
153 | tsk = current; | 155 | tsk = current; |
154 | 156 | ||
155 | if (regs) { | 157 | if (tsk == current) { |
156 | frame.fp = regs->regs[29]; | ||
157 | frame.sp = regs->sp; | ||
158 | frame.pc = regs->pc; | ||
159 | } else if (tsk == current) { | ||
160 | frame.fp = (unsigned long)__builtin_frame_address(0); | 158 | frame.fp = (unsigned long)__builtin_frame_address(0); |
161 | frame.sp = current_stack_pointer; | 159 | frame.sp = current_stack_pointer; |
162 | frame.pc = (unsigned long)dump_backtrace; | 160 | frame.pc = (unsigned long)dump_backtrace; |
@@ -168,21 +166,49 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) | |||
168 | frame.sp = thread_saved_sp(tsk); | 166 | frame.sp = thread_saved_sp(tsk); |
169 | frame.pc = thread_saved_pc(tsk); | 167 | frame.pc = thread_saved_pc(tsk); |
170 | } | 168 | } |
169 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
170 | frame.graph = tsk->curr_ret_stack; | ||
171 | #endif | ||
171 | 172 | ||
172 | pr_emerg("Call trace:\n"); | 173 | skip = !!regs; |
174 | printk("Call trace:\n"); | ||
173 | while (1) { | 175 | while (1) { |
174 | unsigned long where = frame.pc; | 176 | unsigned long where = frame.pc; |
175 | unsigned long stack; | 177 | unsigned long stack; |
176 | int ret; | 178 | int ret; |
177 | 179 | ||
178 | dump_backtrace_entry(where); | 180 | /* skip until specified stack frame */ |
179 | ret = unwind_frame(&frame); | 181 | if (!skip) { |
182 | dump_backtrace_entry(where); | ||
183 | } else if (frame.fp == regs->regs[29]) { | ||
184 | skip = 0; | ||
185 | /* | ||
186 | * Mostly, this is the case where this function is | ||
187 | * called in panic/abort. As exception handler's | ||
188 | * stack frame does not contain the corresponding pc | ||
189 | * at which an exception has taken place, use regs->pc | ||
190 | * instead. | ||
191 | */ | ||
192 | dump_backtrace_entry(regs->pc); | ||
193 | } | ||
194 | ret = unwind_frame(tsk, &frame); | ||
180 | if (ret < 0) | 195 | if (ret < 0) |
181 | break; | 196 | break; |
182 | stack = frame.sp; | 197 | stack = frame.sp; |
183 | if (in_exception_text(where)) | 198 | if (in_exception_text(where)) { |
199 | /* | ||
200 | * If we switched to the irq_stack before calling this | ||
201 | * exception handler, then the pt_regs will be on the | ||
202 | * task stack. The easiest way to tell is if the large | ||
203 | * pt_regs would overlap with the end of the irq_stack. | ||
204 | */ | ||
205 | if (stack < irq_stack_ptr && | ||
206 | (stack + sizeof(struct pt_regs)) > irq_stack_ptr) | ||
207 | stack = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr); | ||
208 | |||
184 | dump_mem("", "Exception stack", stack, | 209 | dump_mem("", "Exception stack", stack, |
185 | stack + sizeof(struct pt_regs), false); | 210 | stack + sizeof(struct pt_regs), false); |
211 | } | ||
186 | } | 212 | } |
187 | } | 213 | } |
188 | 214 | ||
@@ -456,22 +482,22 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr) | |||
456 | 482 | ||
457 | void __pte_error(const char *file, int line, unsigned long val) | 483 | void __pte_error(const char *file, int line, unsigned long val) |
458 | { | 484 | { |
459 | pr_crit("%s:%d: bad pte %016lx.\n", file, line, val); | 485 | pr_err("%s:%d: bad pte %016lx.\n", file, line, val); |
460 | } | 486 | } |
461 | 487 | ||
462 | void __pmd_error(const char *file, int line, unsigned long val) | 488 | void __pmd_error(const char *file, int line, unsigned long val) |
463 | { | 489 | { |
464 | pr_crit("%s:%d: bad pmd %016lx.\n", file, line, val); | 490 | pr_err("%s:%d: bad pmd %016lx.\n", file, line, val); |
465 | } | 491 | } |
466 | 492 | ||
467 | void __pud_error(const char *file, int line, unsigned long val) | 493 | void __pud_error(const char *file, int line, unsigned long val) |
468 | { | 494 | { |
469 | pr_crit("%s:%d: bad pud %016lx.\n", file, line, val); | 495 | pr_err("%s:%d: bad pud %016lx.\n", file, line, val); |
470 | } | 496 | } |
471 | 497 | ||
472 | void __pgd_error(const char *file, int line, unsigned long val) | 498 | void __pgd_error(const char *file, int line, unsigned long val) |
473 | { | 499 | { |
474 | pr_crit("%s:%d: bad pgd %016lx.\n", file, line, val); | 500 | pr_err("%s:%d: bad pgd %016lx.\n", file, line, val); |
475 | } | 501 | } |
476 | 502 | ||
477 | /* GENERIC_BUG traps */ | 503 | /* GENERIC_BUG traps */ |