Since get_frame_info() is more robust, unwind_stack() can returns ra value for leaf functions. Signed-off-by: Franck Bui-Huu <vagabon.xyz@xxxxxxxxx> --- arch/mips/kernel/process.c | 20 ++++++++++++-------- arch/mips/kernel/traps.c | 15 ++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 539b23b..6377b17 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -445,14 +445,15 @@ #endif #ifdef CONFIG_KALLSYMS /* used by show_frametrace() */ -unsigned long unwind_stack(struct task_struct *task, - unsigned long **sp, unsigned long pc) +unsigned long unwind_stack(struct task_struct *task, unsigned long **sp, + unsigned long pc, struct pt_regs *regs) { unsigned long stack_page; struct mips_frame_info info; char *modname; char namebuf[KSYM_NAME_LEN + 1]; unsigned long size, ofs; + int leaf; stack_page = (unsigned long)task_stack_page(task); if (!stack_page) @@ -465,18 +466,21 @@ unsigned long unwind_stack(struct task_s info.func = (void *)(pc - ofs); info.func_size = ofs; /* analyze from start to ofs */ - if (get_frame_info(&info)) { - /* leaf or unknown */ - *sp += info.frame_size / sizeof(long); + leaf = get_frame_info(&info); + if (leaf < 0) return 0; - } + if ((unsigned long)*sp < stack_page || (unsigned long)*sp + info.frame_size / sizeof(long) > stack_page + THREAD_SIZE - 32) return 0; - pc = (*sp)[info.pc_offset]; + if (leaf) + pc = regs->regs[31]; + else + pc = (*sp)[info.pc_offset]; + *sp += info.frame_size / sizeof(long); - return pc; + return __kernel_text_address(pc) ? pc : 0; } #endif diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 07191a6..78aed61 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -101,8 +101,9 @@ static int __init set_raw_show_trace(cha } __setup("raw_show_trace", set_raw_show_trace); -extern unsigned long unwind_stack(struct task_struct *task, - unsigned long **sp, unsigned long pc); +extern unsigned long unwind_stack(struct task_struct *task, unsigned long **sp, + unsigned long pc, struct pt_regs *regs); + static void show_backtrace(struct task_struct *task, struct pt_regs *regs) { unsigned long *sp = (long *)regs->regs[29]; @@ -114,14 +115,10 @@ static void show_backtrace(struct task_s return; } printk("Call Trace:\n"); - while (__kernel_text_address(pc)) { + do { printk(" [<%0*lx>] ", 2 * sizeof(unsigned long), pc); - print_symbol("%s\n", pc); - pc = unwind_stack(task, &sp, pc); - if (top && pc == 0) - pc = regs->regs[31]; /* leaf? */ - top = 0; - } + print_symbol("%s\n", pc); + } while ((pc = unwind_stack(task, &sp, pc, regs))); printk("\n"); } #else -- 1.4.2.rc2