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