1 /* 2 * arch/s390/kernel/stacktrace.c 3 * 4 * Stack trace management functions 5 * 6 * Copyright (C) IBM Corp. 2006 7 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> 8 */ 9 10 #include <linux/sched.h> 11 #include <linux/stacktrace.h> 12 #include <linux/kallsyms.h> 13 14 static unsigned long save_context_stack(struct stack_trace *trace, 15 unsigned long sp, 16 unsigned long low, 17 unsigned long high) 18 { 19 struct stack_frame *sf; 20 struct pt_regs *regs; 21 unsigned long addr; 22 23 while(1) { 24 sp &= PSW_ADDR_INSN; 25 if (sp < low || sp > high) 26 return sp; 27 sf = (struct stack_frame *)sp; 28 while(1) { 29 addr = sf->gprs[8] & PSW_ADDR_INSN; 30 if (!trace->skip) 31 trace->entries[trace->nr_entries++] = addr; 32 else 33 trace->skip--; 34 if (trace->nr_entries >= trace->max_entries) 35 return sp; 36 low = sp; 37 sp = sf->back_chain & PSW_ADDR_INSN; 38 if (!sp) 39 break; 40 if (sp <= low || sp > high - sizeof(*sf)) 41 return sp; 42 sf = (struct stack_frame *)sp; 43 } 44 /* Zero backchain detected, check for interrupt frame. */ 45 sp = (unsigned long)(sf + 1); 46 if (sp <= low || sp > high - sizeof(*regs)) 47 return sp; 48 regs = (struct pt_regs *)sp; 49 addr = regs->psw.addr & PSW_ADDR_INSN; 50 if (!trace->skip) 51 trace->entries[trace->nr_entries++] = addr; 52 else 53 trace->skip--; 54 if (trace->nr_entries >= trace->max_entries) 55 return sp; 56 low = sp; 57 sp = regs->gprs[15]; 58 } 59 } 60 61 void save_stack_trace(struct stack_trace *trace) 62 { 63 register unsigned long sp asm ("15"); 64 unsigned long orig_sp, new_sp; 65 66 orig_sp = sp & PSW_ADDR_INSN; 67 new_sp = save_context_stack(trace, orig_sp, 68 S390_lowcore.panic_stack - PAGE_SIZE, 69 S390_lowcore.panic_stack); 70 if (new_sp != orig_sp) 71 return; 72 new_sp = save_context_stack(trace, new_sp, 73 S390_lowcore.async_stack - ASYNC_SIZE, 74 S390_lowcore.async_stack); 75 if (new_sp != orig_sp) 76 return; 77 save_context_stack(trace, new_sp, 78 S390_lowcore.thread_info, 79 S390_lowcore.thread_info + THREAD_SIZE); 80 } 81