aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/genex.S8
-rw-r--r--arch/mips/kernel/stacktrace.c52
2 files changed, 27 insertions, 33 deletions
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index 37fda3dcdfc5..af6ef2fd8300 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -220,8 +220,8 @@ NESTED(except_vec_vi_handler, 0, sp)
220 CLI 220 CLI
221 TRACE_IRQS_OFF 221 TRACE_IRQS_OFF
222 move a0, sp 222 move a0, sp
223 jalr v0 223 PTR_LA ra, ret_from_irq
224 j ret_from_irq 224 jr v0
225 END(except_vec_vi_handler) 225 END(except_vec_vi_handler)
226 226
227/* 227/*
@@ -349,8 +349,8 @@ NESTED(nmi_handler, PT_SIZE, sp)
349 .set at 349 .set at
350 __BUILD_\verbose \exception 350 __BUILD_\verbose \exception
351 move a0, sp 351 move a0, sp
352 jal do_\handler 352 PTR_LA ra, ret_from_exception
353 j ret_from_exception 353 j do_\handler
354 END(handle_\exception) 354 END(handle_\exception)
355 .endm 355 .endm
356 356
diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c
index f851d0cc245f..676e6f69d24b 100644
--- a/arch/mips/kernel/stacktrace.c
+++ b/arch/mips/kernel/stacktrace.c
@@ -13,7 +13,7 @@
13 * Save stack-backtrace addresses into a stack_trace buffer: 13 * Save stack-backtrace addresses into a stack_trace buffer:
14 */ 14 */
15static void save_raw_context_stack(struct stack_trace *trace, 15static void save_raw_context_stack(struct stack_trace *trace,
16 unsigned int skip, unsigned long reg29) 16 unsigned long reg29)
17{ 17{
18 unsigned long *sp = (unsigned long *)reg29; 18 unsigned long *sp = (unsigned long *)reg29;
19 unsigned long addr; 19 unsigned long addr;
@@ -21,10 +21,10 @@ static void save_raw_context_stack(struct stack_trace *trace,
21 while (!kstack_end(sp)) { 21 while (!kstack_end(sp)) {
22 addr = *sp++; 22 addr = *sp++;
23 if (__kernel_text_address(addr)) { 23 if (__kernel_text_address(addr)) {
24 if (!skip) 24 if (trace->skip > 0)
25 trace->entries[trace->nr_entries++] = addr; 25 trace->skip--;
26 else 26 else
27 skip--; 27 trace->entries[trace->nr_entries++] = addr;
28 if (trace->nr_entries >= trace->max_entries) 28 if (trace->nr_entries >= trace->max_entries)
29 break; 29 break;
30 } 30 }
@@ -32,37 +32,40 @@ static void save_raw_context_stack(struct stack_trace *trace,
32} 32}
33 33
34static struct pt_regs * save_context_stack(struct stack_trace *trace, 34static 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 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);
41 extern void ret_from_irq(void); 43 extern void ret_from_irq(void);
44 extern void ret_from_exception(void);
42 45
43 if (raw_show_trace || !__kernel_text_address(pc)) { 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 return NULL; 50 return NULL;
46 } 51 }
47 do { 52 do {
48 if (!skip) 53 if (trace->skip > 0)
49 trace->entries[trace->nr_entries++] = pc; 54 trace->skip--;
50 else 55 else
51 skip--; 56 trace->entries[trace->nr_entries++] = pc;
52 if (trace->nr_entries >= trace->max_entries) 57 if (trace->nr_entries >= trace->max_entries)
53 break; 58 break;
54 /* 59 /*
55 * If we reached the bottom of interrupt context, 60 * If we reached the bottom of interrupt context,
56 * return saved pt_regs. 61 * return saved pt_regs.
57 */ 62 */
58 if (pc == (unsigned long)ret_from_irq) { 63 if (pc == (unsigned long)ret_from_irq ||
59 unsigned long stack_page = 64 pc == (unsigned long)ret_from_exception) {
60 (unsigned long)task_stack_page(task); 65 if (stack_page && sp >= stack_page &&
61 if (!stack_page || 66 sp <= stack_page + THREAD_SIZE - 32)
62 sp < stack_page || 67 return (struct pt_regs *)sp;
63 sp > stack_page + THREAD_SIZE - 32) 68 break;
64 break;
65 return (struct pt_regs *)sp;
66 } 69 }
67 pc = unwind_stack(task, &sp, pc, ra); 70 pc = unwind_stack(task, &sp, pc, ra);
68 ra = 0; 71 ra = 0;
@@ -76,12 +79,8 @@ static struct pt_regs * save_context_stack(struct stack_trace *trace,
76 79
77/* 80/*
78 * Save stack-backtrace addresses into a stack_trace buffer. 81 * Save stack-backtrace addresses into a stack_trace buffer.
79 * If all_contexts is set, all contexts (hardirq, softirq and process)
80 * are saved. If not set then only the current context is saved.
81 */ 82 */
82void save_stack_trace(struct stack_trace *trace, 83void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
83 struct task_struct *task, int all_contexts,
84 unsigned int skip)
85{ 84{
86 struct pt_regs dummyregs; 85 struct pt_regs dummyregs;
87 struct pt_regs *regs = &dummyregs; 86 struct pt_regs *regs = &dummyregs;
@@ -99,13 +98,8 @@ void save_stack_trace(struct stack_trace *trace,
99 } 98 }
100 99
101 while (1) { 100 while (1) {
102 regs = save_context_stack(trace, skip, task, regs); 101 regs = save_context_stack(trace, task, regs);
103 if (!all_contexts || !regs || 102 if (!regs || trace->nr_entries >= trace->max_entries)
104 trace->nr_entries >= trace->max_entries)
105 break;
106 trace->entries[trace->nr_entries++] = ULONG_MAX;
107 if (trace->nr_entries >= trace->max_entries)
108 break; 103 break;
109 skip = 0;
110 } 104 }
111} 105}