aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/stacktrace.c
diff options
context:
space:
mode:
authorAtsushi Nemoto <anemo@mba.ocn.ne.jp>2006-09-29 05:02:51 -0400
committerRalf Baechle <ralf@linux-mips.org>2006-10-01 18:16:59 -0400
commit1924600cdb3143cdcc32b6fa43325739503659b9 (patch)
tree002a03fe8e97db3f3a2b07d1d0d27381f80357b9 /arch/mips/kernel/stacktrace.c
parent23126692e30ec22760e0ef932c3c2fff00d440bb (diff)
[MIPS] Make unwind_stack() can dig into interrupted context
If the PC was ret_from_irq or ret_from_exception, there will be no more normal stackframe. Instead of stopping the unwinding, use PC and RA saved by an exception handler to continue unwinding into the interrupted context. This also simplifies the CONFIG_STACKTRACE code. Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/stacktrace.c')
-rw-r--r--arch/mips/kernel/stacktrace.c32
1 files changed, 6 insertions, 26 deletions
diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c
index 676e6f69d24b..4aabe526a68e 100644
--- a/arch/mips/kernel/stacktrace.c
+++ b/arch/mips/kernel/stacktrace.c
@@ -31,23 +31,21 @@ static void save_raw_context_stack(struct stack_trace *trace,
31 } 31 }
32} 32}
33 33
34static struct pt_regs * save_context_stack(struct stack_trace *trace, 34static void save_context_stack(struct stack_trace *trace,
35 struct task_struct *task, struct pt_regs *regs) 35 struct task_struct *task, struct pt_regs *regs)
36{ 36{
37 unsigned long sp = regs->regs[29]; 37 unsigned long sp = regs->regs[29];
38#ifdef CONFIG_KALLSYMS 38#ifdef CONFIG_KALLSYMS
39 unsigned long ra = regs->regs[31]; 39 unsigned long ra = regs->regs[31];
40 unsigned long pc = regs->cp0_epc; 40 unsigned long pc = regs->cp0_epc;
41 unsigned long stack_page =
42 (unsigned long)task_stack_page(task);
43 extern void ret_from_irq(void);
44 extern void ret_from_exception(void);
45 41
46 if (raw_show_trace || !__kernel_text_address(pc)) { 42 if (raw_show_trace || !__kernel_text_address(pc)) {
43 unsigned long stack_page =
44 (unsigned long)task_stack_page(task);
47 if (stack_page && sp >= stack_page && 45 if (stack_page && sp >= stack_page &&
48 sp <= stack_page + THREAD_SIZE - 32) 46 sp <= stack_page + THREAD_SIZE - 32)
49 save_raw_context_stack(trace, sp); 47 save_raw_context_stack(trace, sp);
50 return NULL; 48 return;
51 } 49 }
52 do { 50 do {
53 if (trace->skip > 0) 51 if (trace->skip > 0)
@@ -56,25 +54,11 @@ static struct pt_regs * save_context_stack(struct stack_trace *trace,
56 trace->entries[trace->nr_entries++] = pc; 54 trace->entries[trace->nr_entries++] = pc;
57 if (trace->nr_entries >= trace->max_entries) 55 if (trace->nr_entries >= trace->max_entries)
58 break; 56 break;
59 /* 57 pc = unwind_stack(task, &sp, pc, &ra);
60 * If we reached the bottom of interrupt context,
61 * return saved pt_regs.
62 */
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;
69 }
70 pc = unwind_stack(task, &sp, pc, ra);
71 ra = 0;
72 } while (pc); 58 } while (pc);
73#else 59#else
74 save_raw_context_stack(sp); 60 save_raw_context_stack(sp);
75#endif 61#endif
76
77 return NULL;
78} 62}
79 63
80/* 64/*
@@ -97,9 +81,5 @@ void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
97 prepare_frametrace(regs); 81 prepare_frametrace(regs);
98 } 82 }
99 83
100 while (1) { 84 save_context_stack(trace, task, regs);
101 regs = save_context_stack(trace, task, regs);
102 if (!regs || trace->nr_entries >= trace->max_entries)
103 break;
104 }
105} 85}