1/* 2 * S390 Version 3 * Copyright IBM Corp. 2005 4 * Author(s): Andreas Krebbel <Andreas.Krebbel@de.ibm.com> 5 */ 6 7#include <linux/oprofile.h> 8 9#include <asm/processor.h> /* for struct stack_frame */ 10 11static unsigned long 12__show_trace(unsigned int *depth, unsigned long sp, 13 unsigned long low, unsigned long high) 14{ 15 struct stack_frame *sf; 16 struct pt_regs *regs; 17 18 while (*depth) { 19 sp = sp & PSW_ADDR_INSN; 20 if (sp < low || sp > high - sizeof(*sf)) 21 return sp; 22 sf = (struct stack_frame *) sp; 23 (*depth)--; 24 oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN); 25 26 /* Follow the backchain. */ 27 while (*depth) { 28 low = sp; 29 sp = sf->back_chain & PSW_ADDR_INSN; 30 if (!sp) 31 break; 32 if (sp <= low || sp > high - sizeof(*sf)) 33 return sp; 34 sf = (struct stack_frame *) sp; 35 (*depth)--; 36 oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN); 37 38 } 39 40 if (*depth == 0) 41 break; 42 43 /* Zero backchain detected, check for interrupt frame. */ 44 sp = (unsigned long) (sf + 1); 45 if (sp <= low || sp > high - sizeof(*regs)) 46 return sp; 47 regs = (struct pt_regs *) sp; 48 (*depth)--; 49 oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN); 50 low = sp; 51 sp = regs->gprs[15]; 52 } 53 return sp; 54} 55 56void s390_backtrace(struct pt_regs * const regs, unsigned int depth) 57{ 58 unsigned long head; 59 struct stack_frame* head_sf; 60 61 if (user_mode(regs)) 62 return; 63 64 head = regs->gprs[15]; 65 head_sf = (struct stack_frame*)head; 66 67 if (!head_sf->back_chain) 68 return; 69 70 head = head_sf->back_chain; 71 72 head = __show_trace(&depth, head, S390_lowcore.async_stack - ASYNC_SIZE, 73 S390_lowcore.async_stack); 74 75 __show_trace(&depth, head, S390_lowcore.thread_info, 76 S390_lowcore.thread_info + THREAD_SIZE); 77} 78