1/** 2 * Copyright (C) 2005 Brian Rogan <bcr6@cornell.edu>, IBM 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8**/ 9 10#include <linux/oprofile.h> 11#include <linux/sched.h> 12#include <asm/processor.h> 13#include <asm/uaccess.h> 14#include <asm/compat.h> 15 16#define STACK_SP(STACK) *(STACK) 17 18#define STACK_LR64(STACK) *((unsigned long *)(STACK) + 2) 19#define STACK_LR32(STACK) *((unsigned int *)(STACK) + 1) 20 21#ifdef CONFIG_PPC64 22#define STACK_LR(STACK) STACK_LR64(STACK) 23#else 24#define STACK_LR(STACK) STACK_LR32(STACK) 25#endif 26 27static unsigned int user_getsp32(unsigned int sp, int is_first) 28{ 29 unsigned int stack_frame[2]; 30 void __user *p = compat_ptr(sp); 31 32 if (!access_ok(VERIFY_READ, p, sizeof(stack_frame))) 33 return 0; 34 35 /* 36 * The most likely reason for this is that we returned -EFAULT, 37 * which means that we've done all that we can do from 38 * interrupt context. 39 */ 40 if (__copy_from_user_inatomic(stack_frame, p, sizeof(stack_frame))) 41 return 0; 42 43 if (!is_first) 44 oprofile_add_trace(STACK_LR32(stack_frame)); 45 46 /* 47 * We do not enforce increasing stack addresses here because 48 * we may transition to a different stack, eg a signal handler. 49 */ 50 return STACK_SP(stack_frame); 51} 52 53#ifdef CONFIG_PPC64 54static unsigned long user_getsp64(unsigned long sp, int is_first) 55{ 56 unsigned long stack_frame[3]; 57 58 if (!access_ok(VERIFY_READ, (void __user *)sp, sizeof(stack_frame))) 59 return 0; 60 61 if (__copy_from_user_inatomic(stack_frame, (void __user *)sp, 62 sizeof(stack_frame))) 63 return 0; 64 65 if (!is_first) 66 oprofile_add_trace(STACK_LR64(stack_frame)); 67 68 return STACK_SP(stack_frame); 69} 70#endif 71 72static unsigned long kernel_getsp(unsigned long sp, int is_first) 73{ 74 unsigned long *stack_frame = (unsigned long *)sp; 75 76 if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD)) 77 return 0; 78 79 if (!is_first) 80 oprofile_add_trace(STACK_LR(stack_frame)); 81 82 /* 83 * We do not enforce increasing stack addresses here because 84 * we might be transitioning from an interrupt stack to a kernel 85 * stack. validate_sp() is designed to understand this, so just 86 * use it. 87 */ 88 return STACK_SP(stack_frame); 89} 90 91void op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth) 92{ 93 unsigned long sp = regs->gpr[1]; 94 int first_frame = 1; 95 96 /* We ditch the top stackframe so need to loop through an extra time */ 97 depth += 1; 98 99 if (!user_mode(regs)) { 100 while (depth--) { 101 sp = kernel_getsp(sp, first_frame); 102 if (!sp) 103 break; 104 first_frame = 0; 105 } 106 } else { 107#ifdef CONFIG_PPC64 108 if (!test_thread_flag(TIF_32BIT)) { 109 while (depth--) { 110 sp = user_getsp64(sp, first_frame); 111 if (!sp) 112 break; 113 first_frame = 0; 114 } 115 116 return; 117 } 118#endif 119 120 while (depth--) { 121 sp = user_getsp32(sp, first_frame); 122 if (!sp) 123 break; 124 first_frame = 0; 125 } 126 } 127} 128