6f347fa29f41ef179f3e65f0f0499040962107ff
[platform/kernel/linux-starfive.git] / arch / powerpc / oprofile / backtrace.c
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 <linux/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         /*
32          * The most likely reason for this is that we returned -EFAULT,
33          * which means that we've done all that we can do from
34          * interrupt context.
35          */
36         if (probe_user_read(stack_frame, (void __user *)p, sizeof(stack_frame)))
37                 return 0;
38
39         if (!is_first)
40                 oprofile_add_trace(STACK_LR32(stack_frame));
41
42         /*
43          * We do not enforce increasing stack addresses here because
44          * we may transition to a different stack, eg a signal handler.
45          */
46         return STACK_SP(stack_frame);
47 }
48
49 #ifdef CONFIG_PPC64
50 static unsigned long user_getsp64(unsigned long sp, int is_first)
51 {
52         unsigned long stack_frame[3];
53
54         if (probe_user_read(stack_frame, (void __user *)sp, sizeof(stack_frame)))
55                 return 0;
56
57         if (!is_first)
58                 oprofile_add_trace(STACK_LR64(stack_frame));
59
60         return STACK_SP(stack_frame);
61 }
62 #endif
63
64 static unsigned long kernel_getsp(unsigned long sp, int is_first)
65 {
66         unsigned long *stack_frame = (unsigned long *)sp;
67
68         if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
69                 return 0;
70
71         if (!is_first)
72                 oprofile_add_trace(STACK_LR(stack_frame));
73
74         /*
75          * We do not enforce increasing stack addresses here because
76          * we might be transitioning from an interrupt stack to a kernel
77          * stack. validate_sp() is designed to understand this, so just
78          * use it.
79          */
80         return STACK_SP(stack_frame);
81 }
82
83 void op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth)
84 {
85         unsigned long sp = regs->gpr[1];
86         int first_frame = 1;
87
88         /* We ditch the top stackframe so need to loop through an extra time */
89         depth += 1;
90
91         if (!user_mode(regs)) {
92                 while (depth--) {
93                         sp = kernel_getsp(sp, first_frame);
94                         if (!sp)
95                                 break;
96                         first_frame = 0;
97                 }
98         } else {
99 #ifdef CONFIG_PPC64
100                 if (!is_32bit_task()) {
101                         while (depth--) {
102                                 sp = user_getsp64(sp, first_frame);
103                                 if (!sp)
104                                         break;
105                                 first_frame = 0;
106                         }
107                         return;
108                 }
109 #endif
110
111                 while (depth--) {
112                         sp = user_getsp32(sp, first_frame);
113                         if (!sp)
114                                 break;
115                         first_frame = 0;
116                 }
117         }
118 }