root/arch/powerpc/oprofile/backtrace.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. user_getsp32
  2. user_getsp64
  3. kernel_getsp
  4. op_powerpc_backtrace

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

/* [<][>][^][v][top][bottom][index][help] */