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 int *skip, 16 unsigned long sp, 17 unsigned long low, 18 unsigned long high) 19 { 20 struct stack_frame *sf; 21 struct pt_regs *regs; 22 unsigned long addr; 23 24 while(1) { 25 sp &= PSW_ADDR_INSN; 26 if (sp < low || sp > high) 27 return sp; 28 sf = (struct stack_frame *)sp; 29 while(1) { 30 addr = sf->gprs[8] & PSW_ADDR_INSN; 31 if (!(*skip)) 32 trace->entries[trace->nr_entries++] = addr; 33 else 34 (*skip)--; 35 if (trace->nr_entries >= trace->max_entries) 36 return sp; 37 low = sp; 38 sp = sf->back_chain & PSW_ADDR_INSN; 39 if (!sp) 40 break; 41 if (sp <= low || sp > high - sizeof(*sf)) 42 return sp; 43 sf = (struct stack_frame *)sp; 44 } 45 /* Zero backchain detected, check for interrupt frame. */ 46 sp = (unsigned long)(sf + 1); 47 if (sp <= low || sp > high - sizeof(*regs)) 48 return sp; 49 regs = (struct pt_regs *)sp; 50 addr = regs->psw.addr & PSW_ADDR_INSN; 51 if (!(*skip)) 52 trace->entries[trace->nr_entries++] = addr; 53 else 54 (*skip)--; 55 if (trace->nr_entries >= trace->max_entries) 56 return sp; 57 low = sp; 58 sp = regs->gprs[15]; 59 } 60 } 61 62 void save_stack_trace(struct stack_trace *trace) 63 { 64 register unsigned long sp asm ("15"); 65 unsigned long orig_sp, new_sp; 66 67 orig_sp = sp & PSW_ADDR_INSN; 68 69 new_sp = save_context_stack(trace, &trace->skip, orig_sp, 70 S390_lowcore.panic_stack - PAGE_SIZE, 71 S390_lowcore.panic_stack); 72 if (new_sp != orig_sp) 73 return; 74 new_sp = save_context_stack(trace, &trace->skip, new_sp, 75 S390_lowcore.async_stack - ASYNC_SIZE, 76 S390_lowcore.async_stack); 77 if (new_sp != orig_sp) 78 return; 79 80 save_context_stack(trace, &trace->skip, new_sp, 81 S390_lowcore.thread_info, 82 S390_lowcore.thread_info + THREAD_SIZE); 83 return; 84 } 85