aboutsummaryrefslogtreecommitdiffstats
path: root/arch
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
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')
-rw-r--r--arch/mips/kernel/process.c66
-rw-r--r--arch/mips/kernel/traps.c98
2 files changed, 141 insertions, 23 deletions
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 7ab67f786bfe..8709a46a45c1 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -281,7 +281,7 @@ static struct mips_frame_info {
281} *schedule_frame, mfinfo[64]; 281} *schedule_frame, mfinfo[64];
282static int mfinfo_num; 282static int mfinfo_num;
283 283
284static int __init get_frame_info(struct mips_frame_info *info) 284static int get_frame_info(struct mips_frame_info *info)
285{ 285{
286 int i; 286 int i;
287 void *func = info->func; 287 void *func = info->func;
@@ -329,14 +329,12 @@ static int __init get_frame_info(struct mips_frame_info *info)
329 ip->i_format.simmediate / sizeof(long); 329 ip->i_format.simmediate / sizeof(long);
330 } 330 }
331 } 331 }
332 if (info->pc_offset == -1 || info->frame_size == 0) { 332 if (info->frame_size && info->pc_offset >= 0) /* nested */
333 if (func == schedule) 333 return 0;
334 printk("Can't analyze prologue code at %p\n", func); 334 if (info->pc_offset < 0) /* leaf */
335 info->pc_offset = -1; 335 return 1;
336 info->frame_size = 0; 336 /* prologue seems boggus... */
337 } 337 return -1;
338
339 return 0;
340} 338}
341 339
342static int __init frame_info_init(void) 340static int __init frame_info_init(void)
@@ -367,8 +365,15 @@ static int __init frame_info_init(void)
367 mfinfo[0].func = schedule; 365 mfinfo[0].func = schedule;
368 schedule_frame = &mfinfo[0]; 366 schedule_frame = &mfinfo[0];
369#endif 367#endif
370 for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++) 368 for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++) {
371 get_frame_info(&mfinfo[i]); 369 struct mips_frame_info *info = &mfinfo[i];
370 if (get_frame_info(info)) {
371 /* leaf or unknown */
372 if (info->func == schedule)
373 printk("Can't analyze prologue code at %p\n",
374 info->func);
375 }
376 }
372 377
373 mfinfo_num = i; 378 mfinfo_num = i;
374 return 0; 379 return 0;
@@ -427,6 +432,8 @@ unsigned long get_wchan(struct task_struct *p)
427 if (i < 0) 432 if (i < 0)
428 break; 433 break;
429 434
435 if (mfinfo[i].pc_offset < 0)
436 break;
430 pc = ((unsigned long *)frame)[mfinfo[i].pc_offset]; 437 pc = ((unsigned long *)frame)[mfinfo[i].pc_offset];
431 if (!mfinfo[i].frame_size) 438 if (!mfinfo[i].frame_size)
432 break; 439 break;
@@ -437,3 +444,40 @@ unsigned long get_wchan(struct task_struct *p)
437 return pc; 444 return pc;
438} 445}
439 446
447#ifdef CONFIG_KALLSYMS
448/* used by show_frametrace() */
449unsigned long unwind_stack(struct task_struct *task,
450 unsigned long **sp, unsigned long pc)
451{
452 unsigned long stack_page;
453 struct mips_frame_info info;
454 char *modname;
455 char namebuf[KSYM_NAME_LEN + 1];
456 unsigned long size, ofs;
457
458 stack_page = (unsigned long)task_stack_page(task);
459 if (!stack_page)
460 return 0;
461
462 if (!kallsyms_lookup(pc, &size, &ofs, &modname, namebuf))
463 return 0;
464 if (ofs == 0)
465 return 0;
466
467 info.func = (void *)(pc - ofs);
468 info.func_size = ofs; /* analyze from start to ofs */
469 if (get_frame_info(&info)) {
470 /* leaf or unknown */
471 *sp += info.frame_size / sizeof(long);
472 return 0;
473 }
474 if ((unsigned long)*sp < stack_page ||
475 (unsigned long)*sp + info.frame_size / sizeof(long) >
476 stack_page + THREAD_SIZE - 32)
477 return 0;
478
479 pc = (*sp)[info.pc_offset];
480 *sp += info.frame_size / sizeof(long);
481 return pc;
482}
483#endif
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}