Path: blob/master/arch/powerpc/oprofile/backtrace.c
10817 views
/**1* Copyright (C) 2005 Brian Rogan <[email protected]>, IBM2*3* This program is free software; you can redistribute it and/or4* modify it under the terms of the GNU General Public License5* as published by the Free Software Foundation; either version6* 2 of the License, or (at your option) any later version.7**/89#include <linux/oprofile.h>10#include <linux/sched.h>11#include <asm/processor.h>12#include <asm/uaccess.h>13#include <asm/compat.h>1415#define STACK_SP(STACK) *(STACK)1617#define STACK_LR64(STACK) *((unsigned long *)(STACK) + 2)18#define STACK_LR32(STACK) *((unsigned int *)(STACK) + 1)1920#ifdef CONFIG_PPC6421#define STACK_LR(STACK) STACK_LR64(STACK)22#else23#define STACK_LR(STACK) STACK_LR32(STACK)24#endif2526static unsigned int user_getsp32(unsigned int sp, int is_first)27{28unsigned int stack_frame[2];29void __user *p = compat_ptr(sp);3031if (!access_ok(VERIFY_READ, p, sizeof(stack_frame)))32return 0;3334/*35* The most likely reason for this is that we returned -EFAULT,36* which means that we've done all that we can do from37* interrupt context.38*/39if (__copy_from_user_inatomic(stack_frame, p, sizeof(stack_frame)))40return 0;4142if (!is_first)43oprofile_add_trace(STACK_LR32(stack_frame));4445/*46* We do not enforce increasing stack addresses here because47* we may transition to a different stack, eg a signal handler.48*/49return STACK_SP(stack_frame);50}5152#ifdef CONFIG_PPC6453static unsigned long user_getsp64(unsigned long sp, int is_first)54{55unsigned long stack_frame[3];5657if (!access_ok(VERIFY_READ, (void __user *)sp, sizeof(stack_frame)))58return 0;5960if (__copy_from_user_inatomic(stack_frame, (void __user *)sp,61sizeof(stack_frame)))62return 0;6364if (!is_first)65oprofile_add_trace(STACK_LR64(stack_frame));6667return STACK_SP(stack_frame);68}69#endif7071static unsigned long kernel_getsp(unsigned long sp, int is_first)72{73unsigned long *stack_frame = (unsigned long *)sp;7475if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))76return 0;7778if (!is_first)79oprofile_add_trace(STACK_LR(stack_frame));8081/*82* We do not enforce increasing stack addresses here because83* we might be transitioning from an interrupt stack to a kernel84* stack. validate_sp() is designed to understand this, so just85* use it.86*/87return STACK_SP(stack_frame);88}8990void op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth)91{92unsigned long sp = regs->gpr[1];93int first_frame = 1;9495/* We ditch the top stackframe so need to loop through an extra time */96depth += 1;9798if (!user_mode(regs)) {99while (depth--) {100sp = kernel_getsp(sp, first_frame);101if (!sp)102break;103first_frame = 0;104}105} else {106#ifdef CONFIG_PPC64107if (!is_32bit_task()) {108while (depth--) {109sp = user_getsp64(sp, first_frame);110if (!sp)111break;112first_frame = 0;113}114115return;116}117#endif118119while (depth--) {120sp = user_getsp32(sp, first_frame);121if (!sp)122break;123first_frame = 0;124}125}126}127128129