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 int savesched) 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 (!trace->skip) 32 trace->entries[trace->nr_entries++] = addr; 33 else 34 trace->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 (savesched || !in_sched_functions(addr)) { 52 if (!trace->skip) 53 trace->entries[trace->nr_entries++] = addr; 54 else 55 trace->skip--; 56 } 57 if (trace->nr_entries >= trace->max_entries) 58 return sp; 59 low = sp; 60 sp = regs->gprs[15]; 61 } 62 } 63 64 void save_stack_trace(struct stack_trace *trace) 65 { 66 register unsigned long sp asm ("15"); 67 unsigned long orig_sp, new_sp; 68 69 orig_sp = sp & PSW_ADDR_INSN; 70 new_sp = save_context_stack(trace, orig_sp, 71 S390_lowcore.panic_stack - PAGE_SIZE, 72 S390_lowcore.panic_stack, 1); 73 if (new_sp != orig_sp) 74 return; 75 new_sp = save_context_stack(trace, new_sp, 76 S390_lowcore.async_stack - ASYNC_SIZE, 77 S390_lowcore.async_stack, 1); 78 if (new_sp != orig_sp) 79 return; 80 save_context_stack(trace, new_sp, 81 S390_lowcore.thread_info, 82 S390_lowcore.thread_info + THREAD_SIZE, 1); 83 } 84 85 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 86 { 87 unsigned long sp, low, high; 88 89 sp = tsk->thread.ksp & PSW_ADDR_INSN; 90 low = (unsigned long) task_stack_page(tsk); 91 high = (unsigned long) task_pt_regs(tsk); 92 save_context_stack(trace, sp, low, high, 0); 93 if (trace->nr_entries < trace->max_entries) 94 trace->entries[trace->nr_entries++] = ULONG_MAX; 95 } 96