2010-03-11 16:24:18 +00:00
/* Provide basic stack dumping functions
*
* Copyright 2004 - 2009 Analog Devices Inc .
*
* Licensed under the GPL - 2 or later
*/
# include <linux/kernel.h>
# include <linux/thread_info.h>
# include <linux/mm.h>
# include <linux/uaccess.h>
# include <linux/module.h>
# include <asm/trace.h>
/*
* Checks to see if the address pointed to is either a
* 16 - bit CALL instruction , or a 32 - bit CALL instruction
*/
static bool is_bfin_call ( unsigned short * addr )
{
2010-03-15 17:42:07 +00:00
unsigned int opcode ;
2010-03-11 16:24:18 +00:00
2010-03-15 17:42:07 +00:00
if ( ! get_instruction ( & opcode , addr ) )
2010-03-11 16:24:18 +00:00
return false ;
if ( ( opcode > = 0x0060 & & opcode < = 0x0067 ) | |
2010-03-15 17:42:07 +00:00
( opcode > = 0x0070 & & opcode < = 0x0077 ) | |
( opcode > = 0xE3000000 & & opcode < = 0xE3FFFFFF ) )
2010-03-11 16:24:18 +00:00
return true ;
return false ;
}
void show_stack ( struct task_struct * task , unsigned long * stack )
{
# ifdef CONFIG_PRINTK
unsigned int * addr , * endstack , * fp = 0 , * frame ;
unsigned short * ins_addr ;
char buf [ 150 ] ;
unsigned int i , j , ret_addr , frame_no = 0 ;
/*
* If we have been passed a specific stack , use that one otherwise
* if we have been passed a task structure , use that , otherwise
* use the stack of where the variable " stack " exists
*/
if ( stack = = NULL ) {
if ( task ) {
/* We know this is a kernel stack, so this is the start/end */
stack = ( unsigned long * ) task - > thread . ksp ;
endstack = ( unsigned int * ) ( ( ( unsigned int ) ( stack ) & ~ ( THREAD_SIZE - 1 ) ) + THREAD_SIZE ) ;
} else {
/* print out the existing stack info */
stack = ( unsigned long * ) & stack ;
endstack = ( unsigned int * ) PAGE_ALIGN ( ( unsigned int ) stack ) ;
}
} else
endstack = ( unsigned int * ) PAGE_ALIGN ( ( unsigned int ) stack ) ;
printk ( KERN_NOTICE " Stack info: \n " ) ;
decode_address ( buf , ( unsigned int ) stack ) ;
printk ( KERN_NOTICE " SP: [0x%p] %s \n " , stack , buf ) ;
if ( ! access_ok ( VERIFY_READ , stack , ( unsigned int ) endstack - ( unsigned int ) stack ) ) {
printk ( KERN_NOTICE " Invalid stack pointer \n " ) ;
return ;
}
/* First thing is to look for a frame pointer */
for ( addr = ( unsigned int * ) ( ( unsigned int ) stack & ~ 0xF ) ; addr < endstack ; addr + + ) {
if ( * addr & 0x1 )
continue ;
ins_addr = ( unsigned short * ) * addr ;
ins_addr - - ;
if ( is_bfin_call ( ins_addr ) )
fp = addr - 1 ;
if ( fp ) {
/* Let's check to see if it is a frame pointer */
while ( fp > = ( addr - 1 ) & & fp < endstack
& & fp & & ( ( unsigned int ) fp & 0x3 ) = = 0 )
fp = ( unsigned int * ) * fp ;
if ( fp = = 0 | | fp = = endstack ) {
fp = addr - 1 ;
break ;
}
fp = 0 ;
}
}
if ( fp ) {
frame = fp ;
printk ( KERN_NOTICE " FP: (0x%p) \n " , fp ) ;
} else
frame = 0 ;
/*
* Now that we think we know where things are , we
* walk the stack again , this time printing things out
* incase there is no frame pointer , we still look for
* valid return addresses
*/
/* First time print out data, next time, print out symbols */
for ( j = 0 ; j < = 1 ; j + + ) {
if ( j )
printk ( KERN_NOTICE " Return addresses in stack: \n " ) ;
else
printk ( KERN_NOTICE " Memory from 0x%08lx to %p " , ( ( long unsigned int ) stack & ~ 0xF ) , endstack ) ;
fp = frame ;
frame_no = 0 ;
for ( addr = ( unsigned int * ) ( ( unsigned int ) stack & ~ 0xF ) , i = 0 ;
addr < endstack ; addr + + , i + + ) {
ret_addr = 0 ;
if ( ! j & & i % 8 = = 0 )
printk ( KERN_NOTICE " %p: " , addr ) ;
/* if it is an odd address, or zero, just skip it */
if ( * addr & 0x1 | | ! * addr )
goto print ;
ins_addr = ( unsigned short * ) * addr ;
/* Go back one instruction, and see if it is a CALL */
ins_addr - - ;
ret_addr = is_bfin_call ( ins_addr ) ;
print :
if ( ! j & & stack = = ( unsigned long * ) addr )
printk ( " [%08x] " , * addr ) ;
else if ( ret_addr )
if ( j ) {
decode_address ( buf , ( unsigned int ) * addr ) ;
if ( frame = = addr ) {
printk ( KERN_NOTICE " frame %2i : %s \n " , frame_no , buf ) ;
continue ;
}
printk ( KERN_NOTICE " address : %s \n " , buf ) ;
} else
printk ( " <%08x> " , * addr ) ;
else if ( fp = = addr ) {
if ( j )
frame = addr + 1 ;
else
printk ( " (%08x) " , * addr ) ;
fp = ( unsigned int * ) * addr ;
frame_no + + ;
} else if ( ! j )
printk ( " %08x " , * addr ) ;
}
if ( ! j )
printk ( " \n " ) ;
}
# endif
}
EXPORT_SYMBOL ( show_stack ) ;
void dump_stack ( void )
{
unsigned long stack ;
# ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
int tflags ;
# endif
trace_buffer_save ( tflags ) ;
dump_bfin_trace_buffer ( ) ;
2013-04-30 15:27:12 -07:00
dump_stack_print_info ( KERN_DEFAULT ) ;
2010-03-11 16:24:18 +00:00
show_stack ( current , & stack ) ;
trace_buffer_restore ( tflags ) ;
}
EXPORT_SYMBOL ( dump_stack ) ;