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 <linux/uaccess.h> 14#include <asm/compat.h> 15#include <asm/oprofile_impl.h> 16 17#define STACK_SP(STACK) *(STACK) 18 19#define STACK_LR64(STACK) *((unsigned long *)(STACK) + 2) 20#define STACK_LR32(STACK) *((unsigned int *)(STACK) + 1) 21 22#ifdef CONFIG_PPC64 23#define STACK_LR(STACK) STACK_LR64(STACK) 24#else 25#define STACK_LR(STACK) STACK_LR32(STACK) 26#endif 27 28static unsigned int user_getsp32(unsigned int sp, int is_first) 29{ 30 unsigned int stack_frame[2]; 31 void __user *p = compat_ptr(sp); 32 33 if (!access_ok(VERIFY_READ, p, sizeof(stack_frame))) 34 return 0; 35 36 /* 37 * The most likely reason for this is that we returned -EFAULT, 38 * which means that we've done all that we can do from 39 * interrupt context. 40 */ 41 if (__copy_from_user_inatomic(stack_frame, p, sizeof(stack_frame))) 42 return 0; 43 44 if (!is_first) 45 oprofile_add_trace(STACK_LR32(stack_frame)); 46 47 /* 48 * We do not enforce increasing stack addresses here because 49 * we may transition to a different stack, eg a signal handler. 50 */ 51 return STACK_SP(stack_frame); 52} 53 54#ifdef CONFIG_PPC64 55static unsigned long user_getsp64(unsigned long sp, int is_first) 56{ 57 unsigned long stack_frame[3]; 58 59 if (!access_ok(VERIFY_READ, (void __user *)sp, sizeof(stack_frame))) 60 return 0; 61 62 if (__copy_from_user_inatomic(stack_frame, (void __user *)sp, 63 sizeof(stack_frame))) 64 return 0; 65 66 if (!is_first) 67 oprofile_add_trace(STACK_LR64(stack_frame)); 68 69 return STACK_SP(stack_frame); 70} 71#endif 72 73static unsigned long kernel_getsp(unsigned long sp, int is_first) 74{ 75 unsigned long *stack_frame = (unsigned long *)sp; 76 77 if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD)) 78 return 0; 79 80 if (!is_first) 81 oprofile_add_trace(STACK_LR(stack_frame)); 82 83 /* 84 * We do not enforce increasing stack addresses here because 85 * we might be transitioning from an interrupt stack to a kernel 86 * stack. validate_sp() is designed to understand this, so just 87 * use it. 88 */ 89 return STACK_SP(stack_frame); 90} 91 92void op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth) 93{ 94 unsigned long sp = regs->gpr[1]; 95 int first_frame = 1; 96 97 /* We ditch the top stackframe so need to loop through an extra time */ 98 depth += 1; 99 100 if (!user_mode(regs)) { 101 while (depth--) { 102 sp = kernel_getsp(sp, first_frame); 103 if (!sp) 104 break; 105 first_frame = 0; 106 } 107 } else { 108 pagefault_disable(); 109#ifdef CONFIG_PPC64 110 if (!is_32bit_task()) { 111 while (depth--) { 112 sp = user_getsp64(sp, first_frame); 113 if (!sp) 114 break; 115 first_frame = 0; 116 } 117 pagefault_enable(); 118 return; 119 } 120#endif 121 122 while (depth--) { 123 sp = user_getsp32(sp, first_frame); 124 if (!sp) 125 break; 126 first_frame = 0; 127 } 128 pagefault_enable(); 129 } 130} 131