2009-08-07 19:11:19 +04:00
/*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
* Copyright ( C ) 2000 , 2001 , 2002 Andi Kleen , SuSE Labs
* Copyright ( C ) 2009 Matt Fleming
*/
# include <linux/kallsyms.h>
# include <linux/ftrace.h>
# include <linux/debug_locks.h>
2009-08-12 01:43:20 +04:00
# include <asm/unwinder.h>
2009-08-07 19:11:19 +04:00
# include <asm/stacktrace.h>
void printk_address ( unsigned long address , int reliable )
{
printk ( " [<%p>] %s%pS \n " , ( void * ) address ,
reliable ? " " : " ? " , ( void * ) address ) ;
}
# ifdef CONFIG_FUNCTION_GRAPH_TRACER
static void
print_ftrace_graph_addr ( unsigned long addr , void * data ,
const struct stacktrace_ops * ops ,
struct thread_info * tinfo , int * graph )
{
struct task_struct * task = tinfo - > task ;
unsigned long ret_addr ;
int index = task - > curr_ret_stack ;
if ( addr ! = ( unsigned long ) return_to_handler )
return ;
if ( ! task - > ret_stack | | index < * graph )
return ;
index - = * graph ;
ret_addr = task - > ret_stack [ index ] . ret ;
ops - > address ( data , ret_addr , 1 ) ;
( * graph ) + + ;
}
# else
static inline void
print_ftrace_graph_addr ( unsigned long addr , void * data ,
const struct stacktrace_ops * ops ,
struct thread_info * tinfo , int * graph )
{ }
# endif
2009-08-12 01:43:20 +04:00
void
stack_reader_dump ( struct task_struct * task , struct pt_regs * regs ,
unsigned long * sp , const struct stacktrace_ops * ops ,
void * data )
2009-08-07 19:11:19 +04:00
{
struct thread_info * context ;
int graph = 0 ;
context = ( struct thread_info * )
( ( unsigned long ) sp & ( ~ ( THREAD_SIZE - 1 ) ) ) ;
while ( ! kstack_end ( sp ) ) {
unsigned long addr = * sp + + ;
if ( __kernel_text_address ( addr ) ) {
ops - > address ( data , addr , 0 ) ;
print_ftrace_graph_addr ( addr , data , ops ,
context , & graph ) ;
}
}
}
static void
print_trace_warning_symbol ( void * data , char * msg , unsigned long symbol )
{
printk ( data ) ;
print_symbol ( msg , symbol ) ;
printk ( " \n " ) ;
}
static void print_trace_warning ( void * data , char * msg )
{
printk ( " %s%s \n " , ( char * ) data , msg ) ;
}
static int print_trace_stack ( void * data , char * name )
{
printk ( " %s <%s> " , ( char * ) data , name ) ;
return 0 ;
}
/*
* Print one address / symbol entries per line .
*/
static void print_trace_address ( void * data , unsigned long addr , int reliable )
{
printk ( data ) ;
printk_address ( addr , reliable ) ;
}
static const struct stacktrace_ops print_trace_ops = {
. warning = print_trace_warning ,
. warning_symbol = print_trace_warning_symbol ,
. stack = print_trace_stack ,
. address = print_trace_address ,
} ;
void show_trace ( struct task_struct * tsk , unsigned long * sp ,
struct pt_regs * regs )
{
if ( regs & & user_mode ( regs ) )
return ;
printk ( " \n Call trace: \n " ) ;
2009-08-12 01:43:20 +04:00
unwind_stack ( tsk , regs , sp , & print_trace_ops , " " ) ;
2009-08-07 19:11:19 +04:00
printk ( " \n " ) ;
if ( ! tsk )
tsk = current ;
debug_show_held_locks ( tsk ) ;
}