2008-09-30 13:12:14 +02:00
/*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
* Copyright ( C ) 2000 , 2001 , 2002 Andi Kleen , SuSE Labs
*/
# include <linux/kallsyms.h>
# include <linux/kprobes.h>
# include <linux/uaccess.h>
# include <linux/hardirq.h>
# include <linux/kdebug.h>
# include <linux/module.h>
# include <linux/ptrace.h>
# include <linux/kexec.h>
2009-11-26 08:17:31 +01:00
# include <linux/sysfs.h>
2008-09-30 13:12:14 +02:00
# include <linux/bug.h>
# include <linux/nmi.h>
# include <asm/stacktrace.h>
2009-07-01 21:02:09 +02:00
2011-03-18 11:40:06 +09:00
void dump_trace ( struct task_struct * task , struct pt_regs * regs ,
unsigned long * stack , unsigned long bp ,
2008-09-30 13:12:14 +02:00
const struct stacktrace_ops * ops , void * data )
{
2008-12-02 23:50:04 -05:00
int graph = 0 ;
2008-09-30 13:12:14 +02:00
if ( ! task )
task = current ;
if ( ! stack ) {
unsigned long dummy ;
2009-11-26 08:17:31 +01:00
2008-09-30 13:12:14 +02:00
stack = & dummy ;
2008-10-04 23:12:46 +02:00
if ( task & & task ! = current )
2008-09-30 13:12:14 +02:00
stack = ( unsigned long * ) task - > thread . sp ;
}
2011-03-18 11:40:06 +09:00
if ( ! bp )
bp = stack_frame ( task , regs ) ;
2008-09-30 13:12:14 +02:00
for ( ; ; ) {
struct thread_info * context ;
context = ( struct thread_info * )
( ( unsigned long ) stack & ( ~ ( THREAD_SIZE - 1 ) ) ) ;
2009-12-17 05:40:33 +01:00
bp = ops - > walk_stack ( context , stack , bp , ops , data , NULL , & graph ) ;
2008-10-04 23:12:43 +02:00
2008-09-30 13:12:14 +02:00
stack = ( unsigned long * ) context - > previous_esp ;
if ( ! stack )
break ;
2008-10-04 23:12:43 +02:00
if ( ops - > stack ( data , " IRQ " ) < 0 )
break ;
2008-09-30 13:12:14 +02:00
touch_nmi_watchdog ( ) ;
}
}
EXPORT_SYMBOL ( dump_trace ) ;
2008-10-23 10:40:06 -04:00
void
2008-09-30 13:12:14 +02:00
show_stack_log_lvl ( struct task_struct * task , struct pt_regs * regs ,
2011-03-18 11:40:06 +09:00
unsigned long * sp , unsigned long bp , char * log_lvl )
2008-09-30 13:12:14 +02:00
{
unsigned long * stack ;
int i ;
if ( sp = = NULL ) {
if ( task )
sp = ( unsigned long * ) task - > thread . sp ;
else
sp = ( unsigned long * ) & sp ;
}
stack = sp ;
for ( i = 0 ; i < kstack_depth_to_print ; i + + ) {
if ( kstack_end ( stack ) )
break ;
2008-10-04 23:12:46 +02:00
if ( i & & ( ( i % STACKSLOTS_PER_LINE ) = = 0 ) )
2010-10-20 16:48:51 +02:00
printk ( KERN_CONT " \n " ) ;
printk ( KERN_CONT " %08lx " , * stack + + ) ;
2008-10-04 23:12:44 +02:00
touch_nmi_watchdog ( ) ;
2008-09-30 13:12:14 +02:00
}
2010-10-20 16:48:51 +02:00
printk ( KERN_CONT " \n " ) ;
2011-03-18 11:40:06 +09:00
show_trace_log_lvl ( task , regs , sp , bp , log_lvl ) ;
2008-09-30 13:12:14 +02:00
}
void show_registers ( struct pt_regs * regs )
{
int i ;
print_modules ( ) ;
__show_regs ( regs , 0 ) ;
2008-10-04 23:12:44 +02:00
printk ( KERN_EMERG " Process %.*s (pid: %d, ti=%p task=%p task.ti=%p) \n " ,
2008-09-30 13:12:14 +02:00
TASK_COMM_LEN , current - > comm , task_pid_nr ( current ) ,
current_thread_info ( ) , current , task_thread_info ( current ) ) ;
/*
* When in - kernel , we also print out the stack and code at the
* time of the fault . .
*/
if ( ! user_mode_vm ( regs ) ) {
unsigned int code_prologue = code_bytes * 43 / 64 ;
unsigned int code_len = code_bytes ;
unsigned char c ;
u8 * ip ;
2008-10-04 23:12:44 +02:00
printk ( KERN_EMERG " Stack: \n " ) ;
2011-03-18 11:40:06 +09:00
show_stack_log_lvl ( NULL , regs , & regs - > sp , 0 , KERN_EMERG ) ;
2008-09-30 13:12:14 +02:00
printk ( KERN_EMERG " Code: " ) ;
ip = ( u8 * ) regs - > ip - code_prologue ;
if ( ip < ( u8 * ) PAGE_OFFSET | | probe_kernel_address ( ip , c ) ) {
2008-10-04 23:12:46 +02:00
/* try starting at IP */
2008-09-30 13:12:14 +02:00
ip = ( u8 * ) regs - > ip ;
code_len = code_len - code_prologue + 1 ;
}
for ( i = 0 ; i < code_len ; i + + , ip + + ) {
if ( ip < ( u8 * ) PAGE_OFFSET | |
probe_kernel_address ( ip , c ) ) {
2011-12-19 22:07:58 +01:00
printk ( KERN_CONT " Bad EIP value. " ) ;
2008-09-30 13:12:14 +02:00
break ;
}
if ( ip = = ( u8 * ) regs - > ip )
2011-12-19 22:07:58 +01:00
printk ( KERN_CONT " <%02x> " , c ) ;
2008-09-30 13:12:14 +02:00
else
2011-12-19 22:07:58 +01:00
printk ( KERN_CONT " %02x " , c ) ;
2008-09-30 13:12:14 +02:00
}
}
2011-12-19 22:07:58 +01:00
printk ( KERN_CONT " \n " ) ;
2008-09-30 13:12:14 +02:00
}
int is_valid_bugaddr ( unsigned long ip )
{
unsigned short ud2 ;
if ( ip < PAGE_OFFSET )
return 0 ;
if ( probe_kernel_address ( ( unsigned short * ) ip , ud2 ) )
return 0 ;
return ud2 = = 0x0b0f ;
}