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 <[email protected]> 8 */ 9 10 #include <linux/sched.h> 11 #include <linux/stacktrace.h> 12 #include <linux/kallsyms.h> 13 14 static inline 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 struct task_struct *task, int all_contexts, 64 unsigned int skip) 65 { 66 register unsigned long sp asm ("15"); 67 unsigned long orig_sp; 68 69 sp &= PSW_ADDR_INSN; 70 orig_sp = sp; 71 72 sp = save_context_stack(trace, &skip, sp, 73 S390_lowcore.panic_stack - PAGE_SIZE, 74 S390_lowcore.panic_stack); 75 if ((sp != orig_sp) && !all_contexts) 76 return; 77 sp = save_context_stack(trace, &skip, sp, 78 S390_lowcore.async_stack - ASYNC_SIZE, 79 S390_lowcore.async_stack); 80 if ((sp != orig_sp) && !all_contexts) 81 return; 82 if (task) 83 save_context_stack(trace, &skip, sp, 84 (unsigned long) task_stack_page(task), 85 (unsigned long) task_stack_page(task) + THREAD_SIZE); 86 else 87 save_context_stack(trace, &skip, sp, S390_lowcore.thread_info, 88 S390_lowcore.thread_info + THREAD_SIZE); 89 return; 90 } 91