Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/powerpc/oprofile/backtrace.c
10817 views
1
/**
2
* Copyright (C) 2005 Brian Rogan <[email protected]>, 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
27
static 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
54
static 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
72
static 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
91
void 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 (!is_32bit_task()) {
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
129