stack backtrace
hi Ralf,
The dwarf unwinding code is too complex and I have no time to port
it. And I doubt it will be important enough to deserve the space costs, the -gdwarf-2 kernel is more than 20MB.
Instead for my need I just hack up a simple version of way 1, with
frame pointer kept on: CONFIG_FRAME_POINTER.
BTW:It seems nobody use this option for MIPS? Is it dangerous? The size and performance overhead should be barable at most time for debugging?
here is the code patch(just for reference), it depends on CONFIG_KALLSYMS too.
traps.c renamed from traps.c.orig +128 -4
@@ -116,8 +116,129 @@printk ("\n" ); } -void show_trace (struct task_struct *task,unsigned long *stack) +#include <asm/inst.h> + +static struct mips_frame_info { +void *func; +int omit_fp;/* compiled without fno-omit-frame-pointer */ +int frame_offset; +int pc_offset; +} tmp_frame; + +static int get_frame_info (void *func,struct mips_frame_info *info) +{ +int i; +union mips_instruction *ip = (union mips_instruction *)func; + info->pc_offset =-1 ; + info->frame_offset =-1 ; +for (i =0 ; i <128 ; i++, ip++) { +/* if jal, jalr, jr, stop. */ +if (ip->j_format.opcode == jal_op || + (ip->r_format.opcode == spec_op && + (ip->r_format.func == jalr_op || + ip->r_format.func == jr_op))) +break ; + + if ( +#ifdef CONFIG_32BIT + ip->i_format.opcode == sw_op && +#endif +#ifdef CONFIG_64BIT + ip->i_format.opcode == sd_op && +#endif + ip->i_format.rs == 29) + { +/* sw / sd $ra, offset($sp) */ +if (ip->i_format.rt ==31 ) { +if (info->pc_offset !=-1 ) +continue ; + info->pc_offset = + ip->i_format.simmediate /sizeof (long ); + } +/* sw / sd $s8, offset($sp) */ +if (ip->i_format.rt ==30 ) { +//#if 0 /* gcc 3.4 does aggressive optimization... */ +if (info->frame_offset !=-1 ) +continue ; +//#endif + info->frame_offset = + ip->i_format.simmediate /sizeof (long ); + } + } + } +if (info->pc_offset ==-1 || info->frame_offset ==-1 ) { +printk ("Can't analyze prologue code at %p\n" , func); + info->pc_offset =-1 ; + info->frame_offset =-1 ; +return -1 ; + } + +return 0 ; +} + +static void show_trace (struct task_struct *task,void *regs_in) { +unsigned long prev_sp,stack_top; +unsigned long count =0 ; +unsigned long frame, pc; +char namebuf[KSYM_NAME_LEN +1 ]; +const char *name; +char *modname; +unsigned long size,offset; +struct pt_regs *regs; +int in_exception =0 ; + +if (regs_in)/* called from show_registers */ + regs = (struct pt_regs *) regs_in; +else + regs = (struct pt_regs *) ((unsigned long ) task->thread_info + +THREAD_SIZE -32 -sizeof (struct pt_regs )); + +printk ("Call Trace:\n" ); + + prev_sp = (unsigned long ) (task->thread_info +1 ); + stack_top = (unsigned long ) task->thread_info +THREAD_SIZE ; + + pc = (unsigned long )show_trace; + +if (get_frame_info ((void *)pc,&tmp_frame)) +return ; + + __asm__volatile ("addu %0,$0,$30" :"=r" (frame)); + +do { + pc = ((unsigned long *)frame)[tmp_frame.pc_offset]; + frame = ((unsigned long *)frame)[tmp_frame.frame_offset]; +if (frame < prev_sp || frame > stack_top) { +printk ("out of range sp %08lx,give up!\n" ,frame); +break ; + } + + retry_pc: +if (!__kernel_text_address (pc)) { +printk ("out of text addr %08lx,give up!\n" ,pc); +break ; + } + + name =kallsyms_lookup (pc, &size, &offset, &modname, namebuf); +if (!name) { +printk ("no function found at %08lx\n" ,pc); +return ; + } +printk ("%s at %08lx,frame=%08lx" ,name,pc,frame); + + pc = pc - offset; +if (get_frame_info ((void *)pc,&tmp_frame) && !in_exception) { +printk ("get frame information failed, assume exceptions\n" ); + in_exception =1 ; + pc = regs->cp0_epc; + frame = regs->regs[30 ]; +printk ("epc = %08lx,frame=%08lx\n" ,pc,frame); + goto retry_pc; + } + }while (count++ <16 ); + +#if 0 const int field =2 *sizeof (unsigned long );unsigned long addr;
@@ -140,6 +261,7 @@ } }printk ("\n" ); +#endif }/*
@@ -147,9 +269,10 @@*/ void dump_stack (void ) { -unsigned long stack; +//unsigned long stack; -show_trace (current, &stack); +//show_trace(current, &stack); +show_trace (current,NULL ); }EXPORT_SYMBOL (dump_stack);
@@ -269,7 +392,8 @@printk ("Process %s (pid: %d, threadinfo=%p, task=%p)\n" , current->comm, current->pid,current_thread_info (), current);show_stack (current, (long *) regs->regs[29 ]); -show_trace (current, (long *) regs->regs[29 ]); +//show_trace(current, (long *) regs->regs[29]); +show_trace (current,(void *) regs);show_code ((unsigned int *) regs->cp0_epc);printk ("\n" ); }
process.c renamed from process.c.orig +3 -0
@@ -314,6 +314,9 @@int i;void *func = info->func;union mips_instruction *ip = (union mips_instruction *)func; +#ifdef CONFIG_FRAME_POINTER + info->omit_fp =0 ; +#endif info->pc_offset =-1 ; info->frame_offset = info->omit_fp ?0 :-1 ;for (i =0 ; i <128 ; i++, ip++) {
Quoted 10 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Fuxin Zhang
Instead for my need I just hack up a simple version of way 1, with
frame pointer kept on:CONFIG_FRAME_POINTER.BTW:It seems nobody use this option for MIPS? Is it dangerous? The size and performance overhead should be barable at most time for debugging?
here is the code patch(just for reference), it depends on
CONFIG_KALLSYMStoo.
The get_frame_info() in process.c in kernel 2.6.16 no longer depends on a frame pointer. It would fit your needs better. I think you can use it with slight modifications.
BTW, Is there any point using -fno-omit-frame-pointer on MIPS now? CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y is better for MIPS, isn't it?
---
Atsushi Nemoto
Quoted 3 lines
The
get_frame_info()inprocess.cin kernel 2.6.16 no longer depends on a frame pointer. It would fit your needs better. I think you can use it with slight modifications.
good news
Quoted 9 lines
BTW, Is there any point using -fno-omit-frame-pointer on MIPS now?
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=yis better for MIPS, isn't it?---
Atsushi Nemoto