2008-02-04 22:31:14 -08:00
/*
* Copyright ( C ) 2001 - 2007 Jeff Dike ( jdike @ { addtoit , linux . intel } . com )
2013-09-23 17:38:01 +02:00
* Copyright ( C ) 2013 Richard Weinberger < richrd @ nod . at >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
2005-04-16 15:20:36 -07:00
*/
2008-02-04 22:31:14 -08:00
# include <linux/kallsyms.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/sched.h>
2012-10-08 03:26:54 +01:00
# include <asm/sysrq.h>
2013-09-23 17:38:02 +02:00
# include <os.h>
2005-04-16 15:20:36 -07:00
2013-09-23 17:38:01 +02:00
struct stack_frame {
struct stack_frame * next_frame ;
unsigned long return_address ;
} ;
2013-11-21 09:27:37 +01:00
static void do_stack_trace ( unsigned long * sp , unsigned long bp )
2005-04-16 15:20:36 -07:00
{
2013-09-23 17:38:01 +02:00
int reliable ;
2008-02-04 22:31:14 -08:00
unsigned long addr ;
2013-09-23 17:38:01 +02:00
struct stack_frame * frame = ( struct stack_frame * ) bp ;
2005-04-16 15:20:36 -07:00
2013-09-23 17:38:01 +02:00
printk ( KERN_INFO " Call Trace: \n " ) ;
while ( ( ( long ) sp & ( THREAD_SIZE - 1 ) ) ! = 0 ) {
addr = * sp ;
2005-04-16 15:20:36 -07:00
if ( __kernel_text_address ( addr ) ) {
2013-09-23 17:38:01 +02:00
reliable = 0 ;
if ( ( unsigned long ) sp = = bp + sizeof ( long ) ) {
frame = frame ? frame - > next_frame : NULL ;
bp = ( unsigned long ) frame ;
reliable = 1 ;
}
printk ( KERN_INFO " [<%08lx>] " , addr ) ;
printk ( KERN_CONT " %s " , reliable ? " " : " ? " ) ;
print_symbol ( KERN_CONT " %s " , addr ) ;
2008-02-04 22:31:14 -08:00
printk ( KERN_CONT " \n " ) ;
}
2013-09-23 17:38:01 +02:00
sp + + ;
2008-02-04 22:31:14 -08:00
}
printk ( KERN_INFO " \n " ) ;
2005-04-16 15:20:36 -07:00
}
2013-09-23 17:38:02 +02:00
static unsigned long get_frame_pointer ( struct task_struct * task ,
struct pt_regs * segv_regs )
2013-09-23 17:38:01 +02:00
{
if ( ! task | | task = = current )
2013-09-23 17:38:02 +02:00
return segv_regs ? PT_REGS_BP ( segv_regs ) : current_bp ( ) ;
2013-09-23 17:38:01 +02:00
else
return KSTK_EBP ( task ) ;
}
2013-09-23 17:38:02 +02:00
static unsigned long * get_stack_pointer ( struct task_struct * task ,
struct pt_regs * segv_regs )
{
if ( ! task | | task = = current )
return segv_regs ? ( unsigned long * ) PT_REGS_SP ( segv_regs ) : current_sp ( ) ;
else
return ( unsigned long * ) KSTK_ESP ( task ) ;
}
2013-09-23 17:38:01 +02:00
void show_stack ( struct task_struct * task , unsigned long * stack )
2005-04-16 15:20:36 -07:00
{
2013-09-23 17:38:01 +02:00
unsigned long * sp = stack , bp = 0 ;
2013-09-23 17:38:02 +02:00
struct pt_regs * segv_regs = current - > thread . segv_regs ;
2005-04-16 15:20:36 -07:00
int i ;
2013-09-23 17:38:02 +02:00
if ( ! segv_regs & & os_is_signal_stack ( ) ) {
printk ( KERN_ERR " Received SIGSEGV in SIGSEGV handler, "
" aborting stack trace! \n " ) ;
return ;
}
2013-09-23 17:38:01 +02:00
# ifdef CONFIG_FRAME_POINTER
2013-09-23 17:38:02 +02:00
bp = get_frame_pointer ( task , segv_regs ) ;
2013-09-23 17:38:01 +02:00
# endif
2013-09-23 17:38:02 +02:00
if ( ! stack )
sp = get_stack_pointer ( task , segv_regs ) ;
2005-04-16 15:20:36 -07:00
2013-09-23 17:38:01 +02:00
printk ( KERN_INFO " Stack: \n " ) ;
stack = sp ;
2013-09-23 17:38:04 +02:00
for ( i = 0 ; i < 3 * STACKSLOTS_PER_LINE ; i + + ) {
2005-04-16 15:20:36 -07:00
if ( kstack_end ( stack ) )
break ;
2013-09-23 17:38:01 +02:00
if ( i & & ( ( i % STACKSLOTS_PER_LINE ) = = 0 ) )
printk ( KERN_CONT " \n " ) ;
printk ( KERN_CONT " %08lx " , * stack + + ) ;
2005-04-16 15:20:36 -07:00
}
2013-09-23 17:38:01 +02:00
printk ( KERN_CONT " \n " ) ;
2005-04-16 15:20:36 -07:00
2013-11-21 09:27:37 +01:00
do_stack_trace ( sp , bp ) ;
2005-04-16 15:20:36 -07:00
}