diff options
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r-- | arch/mips/kernel/genex.S | 8 | ||||
-rw-r--r-- | arch/mips/kernel/stacktrace.c | 52 |
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 | */ |
15 | static void save_raw_context_stack(struct stack_trace *trace, | 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 | 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 | ||
34 | static struct pt_regs * save_context_stack(struct stack_trace *trace, | 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 | 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 | */ |
82 | void save_stack_trace(struct stack_trace *trace, | 83 | void 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 | } |