2006-09-26 23:44:01 +09:00
/*
* arch / mips / kernel / stacktrace . c
*
* Stack trace management functions
*
* Copyright ( C ) 2006 Atsushi Nemoto < anemo @ mba . ocn . ne . jp >
*/
# include <linux/sched.h>
# include <linux/stacktrace.h>
# include <asm/stacktrace.h>
/*
* Save stack - backtrace addresses into a stack_trace buffer :
*/
static void save_raw_context_stack ( struct stack_trace * trace ,
2006-09-28 19:15:33 +09:00
unsigned long reg29 )
2006-09-26 23:44:01 +09:00
{
unsigned long * sp = ( unsigned long * ) reg29 ;
unsigned long addr ;
while ( ! kstack_end ( sp ) ) {
addr = * sp + + ;
if ( __kernel_text_address ( addr ) ) {
2006-09-28 19:15:33 +09:00
if ( trace - > skip > 0 )
trace - > skip - - ;
2006-09-26 23:44:01 +09:00
else
2006-09-28 19:15:33 +09:00
trace - > entries [ trace - > nr_entries + + ] = addr ;
2006-09-26 23:44:01 +09:00
if ( trace - > nr_entries > = trace - > max_entries )
break ;
}
}
}
2007-05-08 00:23:29 -07:00
static void save_context_stack ( struct stack_trace * trace , struct pt_regs * regs )
2006-09-26 23:44:01 +09:00
{
unsigned long sp = regs - > regs [ 29 ] ;
# ifdef CONFIG_KALLSYMS
unsigned long ra = regs - > regs [ 31 ] ;
unsigned long pc = regs - > cp0_epc ;
if ( raw_show_trace | | ! __kernel_text_address ( pc ) ) {
2006-09-29 18:02:51 +09:00
unsigned long stack_page =
2007-05-08 00:23:29 -07:00
( unsigned long ) task_stack_page ( current ) ;
2006-09-28 19:15:33 +09:00
if ( stack_page & & sp > = stack_page & &
sp < = stack_page + THREAD_SIZE - 32 )
save_raw_context_stack ( trace , sp ) ;
2006-09-29 18:02:51 +09:00
return ;
2006-09-26 23:44:01 +09:00
}
do {
2006-09-28 19:15:33 +09:00
if ( trace - > skip > 0 )
trace - > skip - - ;
2006-09-26 23:44:01 +09:00
else
2006-09-28 19:15:33 +09:00
trace - > entries [ trace - > nr_entries + + ] = pc ;
2006-09-26 23:44:01 +09:00
if ( trace - > nr_entries > = trace - > max_entries )
break ;
2007-05-08 00:23:29 -07:00
pc = unwind_stack ( current , & sp , pc , & ra ) ;
2006-09-26 23:44:01 +09:00
} while ( pc ) ;
# else
2006-10-16 22:48:49 +09:00
save_raw_context_stack ( trace , sp ) ;
2006-09-26 23:44:01 +09:00
# endif
}
/*
* Save stack - backtrace addresses into a stack_trace buffer .
*/
2007-05-08 00:23:29 -07:00
void save_stack_trace ( struct stack_trace * trace )
2006-09-26 23:44:01 +09:00
{
struct pt_regs dummyregs ;
struct pt_regs * regs = & dummyregs ;
WARN_ON ( trace - > nr_entries | | ! trace - > max_entries ) ;
2007-05-08 00:23:29 -07:00
prepare_frametrace ( regs ) ;
save_context_stack ( trace , regs ) ;
2006-09-26 23:44:01 +09:00
}