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