Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[MIPS] Stacktrace build-fix and improvement

Fix build error due to stacktrace API change. Now save_stack_trace()
tries to save all kernel context, including interrupts and exception.
Also some asm code are changed a bit so that we can detect the end of
current context easily.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Atsushi Nemoto and committed by
Ralf Baechle
23126692 c8cc9618

+29 -35
+4 -4
arch/mips/kernel/genex.S
··· 220 220 CLI 221 221 TRACE_IRQS_OFF 222 222 move a0, sp 223 - jalr v0 224 - j ret_from_irq 223 + PTR_LA ra, ret_from_irq 224 + jr v0 225 225 END(except_vec_vi_handler) 226 226 227 227 /* ··· 349 349 .set at 350 350 __BUILD_\verbose \exception 351 351 move a0, sp 352 - jal do_\handler 353 - j ret_from_exception 352 + PTR_LA ra, ret_from_exception 353 + j do_\handler 354 354 END(handle_\exception) 355 355 .endm 356 356
+23 -29
arch/mips/kernel/stacktrace.c
··· 13 13 * Save stack-backtrace addresses into a stack_trace buffer: 14 14 */ 15 15 static void save_raw_context_stack(struct stack_trace *trace, 16 - unsigned int skip, unsigned long reg29) 16 + unsigned long reg29) 17 17 { 18 18 unsigned long *sp = (unsigned long *)reg29; 19 19 unsigned long addr; ··· 21 21 while (!kstack_end(sp)) { 22 22 addr = *sp++; 23 23 if (__kernel_text_address(addr)) { 24 - if (!skip) 25 - trace->entries[trace->nr_entries++] = addr; 24 + if (trace->skip > 0) 25 + trace->skip--; 26 26 else 27 - skip--; 27 + trace->entries[trace->nr_entries++] = addr; 28 28 if (trace->nr_entries >= trace->max_entries) 29 29 break; 30 30 } ··· 32 32 } 33 33 34 34 static struct pt_regs * save_context_stack(struct stack_trace *trace, 35 - unsigned int skip, struct task_struct *task, struct pt_regs *regs) 35 + struct task_struct *task, struct pt_regs *regs) 36 36 { 37 37 unsigned long sp = regs->regs[29]; 38 38 #ifdef CONFIG_KALLSYMS 39 39 unsigned long ra = regs->regs[31]; 40 40 unsigned long pc = regs->cp0_epc; 41 + unsigned long stack_page = 42 + (unsigned long)task_stack_page(task); 41 43 extern void ret_from_irq(void); 44 + extern void ret_from_exception(void); 42 45 43 46 if (raw_show_trace || !__kernel_text_address(pc)) { 44 - save_raw_context_stack(trace, skip, sp); 47 + if (stack_page && sp >= stack_page && 48 + sp <= stack_page + THREAD_SIZE - 32) 49 + save_raw_context_stack(trace, sp); 45 50 return NULL; 46 51 } 47 52 do { 48 - if (!skip) 49 - trace->entries[trace->nr_entries++] = pc; 53 + if (trace->skip > 0) 54 + trace->skip--; 50 55 else 51 - skip--; 56 + trace->entries[trace->nr_entries++] = pc; 52 57 if (trace->nr_entries >= trace->max_entries) 53 58 break; 54 59 /* 55 60 * If we reached the bottom of interrupt context, 56 61 * return saved pt_regs. 57 62 */ 58 - if (pc == (unsigned long)ret_from_irq) { 59 - unsigned long stack_page = 60 - (unsigned long)task_stack_page(task); 61 - if (!stack_page || 62 - sp < stack_page || 63 - sp > stack_page + THREAD_SIZE - 32) 64 - break; 65 - return (struct pt_regs *)sp; 63 + if (pc == (unsigned long)ret_from_irq || 64 + pc == (unsigned long)ret_from_exception) { 65 + if (stack_page && sp >= stack_page && 66 + sp <= stack_page + THREAD_SIZE - 32) 67 + return (struct pt_regs *)sp; 68 + break; 66 69 } 67 70 pc = unwind_stack(task, &sp, pc, ra); 68 71 ra = 0; ··· 79 76 80 77 /* 81 78 * Save stack-backtrace addresses into a stack_trace buffer. 82 - * If all_contexts is set, all contexts (hardirq, softirq and process) 83 - * are saved. If not set then only the current context is saved. 84 79 */ 85 - void save_stack_trace(struct stack_trace *trace, 86 - struct task_struct *task, int all_contexts, 87 - unsigned int skip) 80 + void save_stack_trace(struct stack_trace *trace, struct task_struct *task) 88 81 { 89 82 struct pt_regs dummyregs; 90 83 struct pt_regs *regs = &dummyregs; ··· 98 99 } 99 100 100 101 while (1) { 101 - regs = save_context_stack(trace, skip, task, regs); 102 - if (!all_contexts || !regs || 103 - trace->nr_entries >= trace->max_entries) 102 + regs = save_context_stack(trace, task, regs); 103 + if (!regs || trace->nr_entries >= trace->max_entries) 104 104 break; 105 - trace->entries[trace->nr_entries++] = ULONG_MAX; 106 - if (trace->nr_entries >= trace->max_entries) 107 - break; 108 - skip = 0; 109 105 } 110 106 }
+2 -2
arch/mips/mm/tlbex-fault.S
··· 19 19 move a0, sp 20 20 REG_S a2, PT_BVADDR(sp) 21 21 li a1, \write 22 - jal do_page_fault 23 - j ret_from_exception 22 + PTR_LA ra, ret_from_exception 23 + j do_page_fault 24 24 END(tlb_do_page_fault_\write) 25 25 .endm 26 26