aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/traps.c
diff options
context:
space:
mode:
authorAtsushi Nemoto <anemo@mba.ocn.ne.jp>2006-07-29 10:27:20 -0400
committerRalf Baechle <ralf@linux-mips.org>2006-09-27 08:37:06 -0400
commitf66686f70a2a61e53ee8c2284f75ca342e4c0dc8 (patch)
tree881e98d7255770314dde60109a316cf9f84522b2 /arch/mips/kernel/traps.c
parent79495d876c2074af5552a0c4b7aea600c2320e83 (diff)
[MIPS] dump_stack() based on prologue code analysis
Instead of dump all possible address in the stack, unwind the stack frame based on prologue code analysis, as like as get_wchan() does. While the code analysis might fail for some reason, there is a new kernel option "raw_show_trace" to disable this feature. 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/traps.c')
-rw-r--r--arch/mips/kernel/traps.c98
1 files changed, 86 insertions, 12 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index c6f70467e750..7aa9dfc57b81 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -98,24 +98,53 @@ static void show_trace(unsigned long *stack)
98 printk("\n"); 98 printk("\n");
99} 99}
100 100
101#ifdef CONFIG_KALLSYMS
102static int raw_show_trace;
103static int __init set_raw_show_trace(char *str)
104{
105 raw_show_trace = 1;
106 return 1;
107}
108__setup("raw_show_trace", set_raw_show_trace);
109
110extern unsigned long unwind_stack(struct task_struct *task,
111 unsigned long **sp, unsigned long pc);
112static void show_frametrace(struct task_struct *task, struct pt_regs *regs)
113{
114 const int field = 2 * sizeof(unsigned long);
115 unsigned long *stack = (long *)regs->regs[29];
116 unsigned long pc = regs->cp0_epc;
117 int top = 1;
118
119 if (raw_show_trace || !__kernel_text_address(pc)) {
120 show_trace(stack);
121 return;
122 }
123 printk("Call Trace:\n");
124 while (__kernel_text_address(pc)) {
125 printk(" [<%0*lx>] ", field, pc);
126 print_symbol("%s\n", pc);
127 pc = unwind_stack(task, &stack, pc);
128 if (top && pc == 0)
129 pc = regs->regs[31]; /* leaf? */
130 top = 0;
131 }
132 printk("\n");
133}
134#else
135#define show_frametrace(task, r) show_trace((long *)(r)->regs[29]);
136#endif
137
101/* 138/*
102 * This routine abuses get_user()/put_user() to reference pointers 139 * This routine abuses get_user()/put_user() to reference pointers
103 * with at least a bit of error checking ... 140 * with at least a bit of error checking ...
104 */ 141 */
105void show_stack(struct task_struct *task, unsigned long *sp) 142static void show_stacktrace(struct task_struct *task, struct pt_regs *regs)
106{ 143{
107 const int field = 2 * sizeof(unsigned long); 144 const int field = 2 * sizeof(unsigned long);
108 long stackdata; 145 long stackdata;
109 int i; 146 int i;
110 unsigned long *stack; 147 unsigned long *sp = (unsigned long *)regs->regs[29];
111
112 if (!sp) {
113 if (task && task != current)
114 sp = (unsigned long *) task->thread.reg29;
115 else
116 sp = (unsigned long *) &sp;
117 }
118 stack = sp;
119 148
120 printk("Stack :"); 149 printk("Stack :");
121 i = 0; 150 i = 0;
@@ -136,7 +165,44 @@ void show_stack(struct task_struct *task, unsigned long *sp)
136 i++; 165 i++;
137 } 166 }
138 printk("\n"); 167 printk("\n");
139 show_trace(stack); 168 show_frametrace(task, regs);
169}
170
171static noinline void prepare_frametrace(struct pt_regs *regs)
172{
173 __asm__ __volatile__(
174 "1: la $2, 1b\n\t"
175#ifdef CONFIG_64BIT
176 "sd $2, %0\n\t"
177 "sd $29, %1\n\t"
178 "sd $31, %2\n\t"
179#else
180 "sw $2, %0\n\t"
181 "sw $29, %1\n\t"
182 "sw $31, %2\n\t"
183#endif
184 : "=m" (regs->cp0_epc),
185 "=m" (regs->regs[29]), "=m" (regs->regs[31])
186 : : "memory");
187}
188
189void show_stack(struct task_struct *task, unsigned long *sp)
190{
191 struct pt_regs regs;
192 if (sp) {
193 regs.regs[29] = (unsigned long)sp;
194 regs.regs[31] = 0;
195 regs.cp0_epc = 0;
196 } else {
197 if (task && task != current) {
198 regs.regs[29] = task->thread.reg29;
199 regs.regs[31] = 0;
200 regs.cp0_epc = task->thread.reg31;
201 } else {
202 prepare_frametrace(&regs);
203 }
204 }
205 show_stacktrace(task, &regs);
140} 206}
141 207
142/* 208/*
@@ -146,6 +212,14 @@ void dump_stack(void)
146{ 212{
147 unsigned long stack; 213 unsigned long stack;
148 214
215#ifdef CONFIG_KALLSYMS
216 if (!raw_show_trace) {
217 struct pt_regs regs;
218 prepare_frametrace(&regs);
219 show_frametrace(current, &regs);
220 return;
221 }
222#endif
149 show_trace(&stack); 223 show_trace(&stack);
150} 224}
151 225
@@ -265,7 +339,7 @@ void show_registers(struct pt_regs *regs)
265 print_modules(); 339 print_modules();
266 printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n", 340 printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n",
267 current->comm, current->pid, current_thread_info(), current); 341 current->comm, current->pid, current_thread_info(), current);
268 show_stack(current, (long *) regs->regs[29]); 342 show_stacktrace(current, regs);
269 show_code((unsigned int *) regs->cp0_epc); 343 show_code((unsigned int *) regs->cp0_epc);
270 printk("\n"); 344 printk("\n");
271} 345}