aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/process.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/process.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/process.c')
-rw-r--r--arch/mips/kernel/process.c66
1 files changed, 55 insertions, 11 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