2006-07-03 11:24:41 +04:00
/*
* arch / s390 / kernel / stacktrace . c
*
* Stack trace management functions
*
* Copyright ( C ) IBM Corp . 2006
* Author ( s ) : Heiko Carstens < heiko . carstens @ de . ibm . com >
*/
# include <linux/sched.h>
# include <linux/stacktrace.h>
# include <linux/kallsyms.h>
2007-02-05 23:18:53 +03:00
static unsigned long save_context_stack ( struct stack_trace * trace ,
unsigned int * skip ,
unsigned long sp ,
unsigned long low ,
unsigned long high )
2006-07-03 11:24:41 +04:00
{
struct stack_frame * sf ;
struct pt_regs * regs ;
unsigned long addr ;
while ( 1 ) {
sp & = PSW_ADDR_INSN ;
if ( sp < low | | sp > high )
return sp ;
sf = ( struct stack_frame * ) sp ;
while ( 1 ) {
addr = sf - > gprs [ 8 ] & PSW_ADDR_INSN ;
if ( ! ( * skip ) )
trace - > entries [ trace - > nr_entries + + ] = addr ;
else
( * skip ) - - ;
if ( trace - > nr_entries > = trace - > max_entries )
return sp ;
low = sp ;
sp = sf - > back_chain & PSW_ADDR_INSN ;
if ( ! sp )
break ;
if ( sp < = low | | sp > high - sizeof ( * sf ) )
return sp ;
sf = ( struct stack_frame * ) sp ;
}
/* Zero backchain detected, check for interrupt frame. */
sp = ( unsigned long ) ( sf + 1 ) ;
if ( sp < = low | | sp > high - sizeof ( * regs ) )
return sp ;
regs = ( struct pt_regs * ) sp ;
addr = regs - > psw . addr & PSW_ADDR_INSN ;
if ( ! ( * skip ) )
trace - > entries [ trace - > nr_entries + + ] = addr ;
else
( * skip ) - - ;
if ( trace - > nr_entries > = trace - > max_entries )
return sp ;
low = sp ;
sp = regs - > gprs [ 15 ] ;
}
}
2007-05-08 11:23:29 +04:00
void save_stack_trace ( struct stack_trace * trace )
2006-07-03 11:24:41 +04:00
{
register unsigned long sp asm ( " 15 " ) ;
2006-10-11 17:31:52 +04:00
unsigned long orig_sp , new_sp ;
2006-07-03 11:24:41 +04:00
2006-10-11 17:31:52 +04:00
orig_sp = sp & PSW_ADDR_INSN ;
2006-07-03 11:24:41 +04:00
2006-10-11 17:31:52 +04:00
new_sp = save_context_stack ( trace , & trace - > skip , orig_sp ,
2006-07-03 11:24:41 +04:00
S390_lowcore . panic_stack - PAGE_SIZE ,
S390_lowcore . panic_stack ) ;
2007-05-08 11:23:29 +04:00
if ( new_sp ! = orig_sp )
2006-07-03 11:24:41 +04:00
return ;
2006-10-11 17:31:52 +04:00
new_sp = save_context_stack ( trace , & trace - > skip , new_sp ,
2006-07-03 11:24:41 +04:00
S390_lowcore . async_stack - ASYNC_SIZE ,
S390_lowcore . async_stack ) ;
2007-05-08 11:23:29 +04:00
if ( new_sp ! = orig_sp )
2006-07-03 11:24:41 +04:00
return ;
2007-05-08 11:23:29 +04:00
save_context_stack ( trace , & trace - > skip , new_sp ,
S390_lowcore . thread_info ,
S390_lowcore . thread_info + THREAD_SIZE ) ;
2006-07-03 11:24:41 +04:00
return ;
}