2007-11-30 14:11:29 +01:00
/*
2005-04-16 15:20:36 -07:00
* linux / arch / cris / traps . c
*
2007-11-30 14:11:29 +01:00
* Here we handle the break vectors not used by the system call
* mechanism , as well as some general stack / register dumping
2005-04-16 15:20:36 -07:00
* things .
2007-11-30 14:11:29 +01:00
*
* Copyright ( C ) 2000 - 2007 Axis Communications AB
2005-04-16 15:20:36 -07:00
*
* Authors : Bjorn Wesen
2007-11-30 14:11:29 +01:00
* Hans - Peter Nilsson
2005-04-16 15:20:36 -07:00
*
*/
# include <linux/init.h>
# include <linux/module.h>
2007-11-30 14:11:29 +01:00
2005-04-16 15:20:36 -07:00
# include <asm/pgtable.h>
# include <asm/uaccess.h>
2007-11-30 14:11:29 +01:00
extern void arch_enable_nmi ( void ) ;
extern void stop_watchdog ( void ) ;
extern void reset_watchdog ( void ) ;
extern void show_registers ( struct pt_regs * regs ) ;
# ifdef CONFIG_DEBUG_BUGVERBOSE
extern void handle_BUG ( struct pt_regs * regs ) ;
# else
# define handle_BUG(regs)
# endif
2005-04-16 15:20:36 -07:00
static int kstack_depth_to_print = 24 ;
2007-11-30 14:11:29 +01:00
void ( * nmi_handler ) ( struct pt_regs * ) ;
2005-07-27 11:44:32 -07:00
2007-11-30 14:11:29 +01:00
void
show_trace ( unsigned long * stack )
2005-04-16 15:20:36 -07:00
{
unsigned long addr , module_start , module_end ;
extern char _stext , _etext ;
int i ;
2007-11-30 14:11:29 +01:00
printk ( " \n Call Trace: " ) ;
2005-04-16 15:20:36 -07:00
2007-11-30 14:11:29 +01:00
i = 1 ;
module_start = VMALLOC_START ;
module_end = VMALLOC_END ;
2005-04-16 15:20:36 -07:00
2007-11-30 14:11:29 +01:00
while ( ( ( long ) stack & ( THREAD_SIZE - 1 ) ) ! = 0 ) {
if ( __get_user ( addr , stack ) ) {
2005-04-16 15:20:36 -07:00
/* This message matches "failing address" marked
s390 in ksymoops , so lines containing it will
not be filtered out by ksymoops . */
2007-11-30 14:11:29 +01:00
printk ( " Failing address 0x%lx \n " , ( unsigned long ) stack ) ;
2005-04-16 15:20:36 -07:00
break ;
}
stack + + ;
2007-11-30 14:11:29 +01:00
/*
* If the address is either in the text segment of the
* kernel , or in the region which contains vmalloc ' ed
* memory , it * may * be the address of a calling
* routine ; if so , print it so that someone tracing
* down the cause of the crash will be able to figure
* out the call path that was taken .
*/
if ( ( ( addr > = ( unsigned long ) & _stext ) & &
( addr < = ( unsigned long ) & _etext ) ) | |
( ( addr > = module_start ) & & ( addr < = module_end ) ) ) {
if ( i & & ( ( i % 8 ) = = 0 ) )
printk ( " \n " ) ;
printk ( " [<%08lx>] " , addr ) ;
i + + ;
}
}
2005-04-16 15:20:36 -07:00
}
/*
* These constants are for searching for possible module text
* segments . MODULE_RANGE is a guess of how much space is likely
* to be vmalloced .
*/
# define MODULE_RANGE (8*1024*1024)
/*
* The output ( format , strings and order ) is adjusted to be usable with
* ksymoops - 2.4 .1 with some necessary CRIS - specific patches . Please don ' t
* change it unless you ' re serious about adjusting ksymoops and syncing
* with the ksymoops maintainer .
*/
2007-11-30 14:11:29 +01:00
void
2005-04-16 15:20:36 -07:00
show_stack ( struct task_struct * task , unsigned long * sp )
{
2007-11-30 14:11:29 +01:00
unsigned long * stack , addr ;
int i ;
2005-04-16 15:20:36 -07:00
/*
* debugging aid : " show_stack(NULL); " prints a
* back trace .
*/
2007-11-30 14:11:29 +01:00
if ( sp = = NULL ) {
2005-04-16 15:20:36 -07:00
if ( task )
sp = ( unsigned long * ) task - > thread . ksp ;
else
sp = ( unsigned long * ) rdsp ( ) ;
}
2007-11-30 14:11:29 +01:00
stack = sp ;
2005-04-16 15:20:36 -07:00
2007-11-30 14:11:29 +01:00
printk ( " \n Stack from %08lx: \n " , ( unsigned long ) stack ) ;
for ( i = 0 ; i < kstack_depth_to_print ; i + + ) {
if ( ( ( long ) stack & ( THREAD_SIZE - 1 ) ) = = 0 )
break ;
if ( i & & ( ( i % 8 ) = = 0 ) )
printk ( " \n " ) ;
if ( __get_user ( addr , stack ) ) {
2005-04-16 15:20:36 -07:00
/* This message matches "failing address" marked
s390 in ksymoops , so lines containing it will
not be filtered out by ksymoops . */
2007-11-30 14:11:29 +01:00
printk ( " Failing address 0x%lx \n " , ( unsigned long ) stack ) ;
2005-04-16 15:20:36 -07:00
break ;
}
stack + + ;
2007-11-30 14:11:29 +01:00
printk ( " %08lx " , addr ) ;
}
2005-04-16 15:20:36 -07:00
show_trace ( sp ) ;
}
2007-11-30 14:11:29 +01:00
#if 0
/* displays a short stack trace */
2005-07-27 11:44:32 -07:00
2007-11-30 14:11:29 +01:00
int
show_stack ( void )
2005-07-27 11:44:32 -07:00
{
2007-11-30 14:11:29 +01:00
unsigned long * sp = ( unsigned long * ) rdusp ( ) ;
int i ;
printk ( " Stack dump [0x%08lx]: \n " , ( unsigned long ) sp ) ;
for ( i = 0 ; i < 16 ; i + + )
printk ( " sp + %d: 0x%08lx \n " , i * 4 , sp [ i ] ) ;
return 0 ;
2005-07-27 11:44:32 -07:00
}
2007-11-30 14:11:29 +01:00
# endif
2005-07-27 11:44:32 -07:00
2007-11-30 14:11:29 +01:00
void
dump_stack ( void )
2005-07-27 11:44:32 -07:00
{
2007-11-30 14:11:29 +01:00
show_stack ( NULL , NULL ) ;
}
EXPORT_SYMBOL ( dump_stack ) ;
void
set_nmi_handler ( void ( * handler ) ( struct pt_regs * ) )
{
nmi_handler = handler ;
arch_enable_nmi ( ) ;
2005-07-27 11:44:32 -07:00
}
# ifdef CONFIG_DEBUG_NMI_OOPS
2007-11-30 14:11:29 +01:00
void
oops_nmi_handler ( struct pt_regs * regs )
2005-07-27 11:44:32 -07:00
{
2007-11-30 14:11:29 +01:00
stop_watchdog ( ) ;
oops_in_progress = 1 ;
printk ( " NMI! \n " ) ;
show_registers ( regs ) ;
oops_in_progress = 0 ;
2005-07-27 11:44:32 -07:00
}
2007-11-30 14:11:29 +01:00
static int __init
oops_nmi_register ( void )
2005-07-27 11:44:32 -07:00
{
2007-11-30 14:11:29 +01:00
set_nmi_handler ( oops_nmi_handler ) ;
return 0 ;
2005-07-27 11:44:32 -07:00
}
__initcall ( oops_nmi_register ) ;
# endif
2007-11-30 14:11:29 +01:00
/*
* This gets called from entry . S when the watchdog has bitten . Show something
2011-03-30 22:57:33 -03:00
* similar to an Oops dump , and if the kernel is configured to be a nice
2007-11-30 14:11:29 +01:00
* doggy , then halt instead of reboot .
*/
void
watchdog_bite_hook ( struct pt_regs * regs )
2005-04-16 15:20:36 -07:00
{
2007-11-30 14:11:29 +01:00
# ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
local_irq_disable ( ) ;
stop_watchdog ( ) ;
show_registers ( regs ) ;
while ( 1 )
; /* Do nothing. */
# else
show_registers ( regs ) ;
2005-04-16 15:20:36 -07:00
# endif
2007-11-30 14:11:29 +01:00
}
2005-04-16 15:20:36 -07:00
2007-11-30 14:11:29 +01:00
/* This is normally the Oops function. */
void
die_if_kernel ( const char * str , struct pt_regs * regs , long err )
2005-04-16 15:20:36 -07:00
{
2007-11-30 14:11:29 +01:00
if ( user_mode ( regs ) )
return ;
2005-04-16 15:20:36 -07:00
2007-11-30 14:11:29 +01:00
# ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
/*
* This printout might take too long and could trigger
* the watchdog normally . If NICE_DOGGY is set , simply
* stop the watchdog during the printout .
*/
stop_watchdog ( ) ;
# endif
2005-04-16 15:20:36 -07:00
2007-11-30 14:11:29 +01:00
handle_BUG ( regs ) ;
printk ( " %s: %04lx \n " , str , err & 0xffff ) ;
show_registers ( regs ) ;
oops_in_progress = 0 ;
# ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
reset_watchdog ( ) ;
# endif
do_exit ( SIGSEGV ) ;
2005-04-16 15:20:36 -07:00
}
2005-07-27 11:44:32 -07:00
2007-11-30 14:11:29 +01:00
void __init
trap_init ( void )
2005-07-27 11:44:32 -07:00
{
2007-11-30 14:11:29 +01:00
/* Nothing needs to be done */
2005-07-27 11:44:32 -07:00
}