2007-05-15 23:37:20 +04:00
# include <linux/module.h>
2007-04-28 12:59:37 +04:00
# include <linux/sched.h>
# include <linux/stacktrace.h>
# include "stacktrace.h"
int walk_stackframe ( unsigned long fp , unsigned long low , unsigned long high ,
int ( * fn ) ( struct stackframe * , void * ) , void * data )
{
struct stackframe * frame ;
do {
/*
* Check current frame pointer is within bounds
*/
2007-05-26 15:04:17 +04:00
if ( fp < ( low + 12 ) | | fp + 4 > = high )
2007-04-28 12:59:37 +04:00
break ;
frame = ( struct stackframe * ) ( fp - 12 ) ;
if ( fn ( frame , data ) )
break ;
/*
* Update the low bound - the next frame must always
* be at a higher address than the current frame .
*/
low = fp + 4 ;
fp = frame - > fp ;
} while ( fp ) ;
return 0 ;
}
2007-05-15 23:37:20 +04:00
EXPORT_SYMBOL ( walk_stackframe ) ;
2007-04-28 12:59:37 +04:00
# ifdef CONFIG_STACKTRACE
struct stack_trace_data {
struct stack_trace * trace ;
unsigned int skip ;
} ;
static int save_trace ( struct stackframe * frame , void * d )
{
struct stack_trace_data * data = d ;
struct stack_trace * trace = data - > trace ;
if ( data - > skip ) {
data - > skip - - ;
return 0 ;
}
trace - > entries [ trace - > nr_entries + + ] = frame - > lr ;
return trace - > nr_entries > = trace - > max_entries ;
}
2007-05-11 09:33:05 +04:00
void save_stack_trace ( struct stack_trace * trace )
2007-04-28 12:59:37 +04:00
{
struct stack_trace_data data ;
unsigned long fp , base ;
data . trace = trace ;
data . skip = trace - > skip ;
2007-05-11 09:33:05 +04:00
base = ( unsigned long ) task_stack_page ( current ) ;
asm ( " mov %0, fp " : " =r " ( fp ) ) ;
2007-04-28 12:59:37 +04:00
walk_stackframe ( fp , base , base + THREAD_SIZE , save_trace , & data ) ;
}
# endif