Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/cddl/dev/fbt/aarch64/fbt_isa.c
48375 views
1
/*
2
* CDDL HEADER START
3
*
4
* The contents of this file are subject to the terms of the
5
* Common Development and Distribution License (the "License").
6
* You may not use this file except in compliance with the License.
7
*
8
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9
* or http://www.opensolaris.org/os/licensing.
10
* See the License for the specific language governing permissions
11
* and limitations under the License.
12
*
13
* When distributing Covered Code, include this CDDL HEADER in each
14
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15
* If applicable, add the following below this CDDL HEADER, with the
16
* fields enclosed by brackets "[]" replaced with your own identifying
17
* information: Portions Copyright [yyyy] [name of copyright owner]
18
*
19
* CDDL HEADER END
20
*
21
* Portions Copyright 2006-2008 John Birrell [email protected]
22
* Portions Copyright 2013 Justin Hibbits [email protected]
23
* Portions Copyright 2013 Howard Su [email protected]
24
* Portions Copyright 2015 Ruslan Bukin <[email protected]>
25
*/
26
27
/*
28
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
29
* Use is subject to license terms.
30
*/
31
32
#include <sys/param.h>
33
34
#include <sys/dtrace.h>
35
36
#include "fbt.h"
37
38
#define FBT_PATCHVAL DTRACE_PATCHVAL
39
#define FBT_AFRAMES 4
40
41
int
42
fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval)
43
{
44
solaris_cpu_t *cpu;
45
fbt_probe_t *fbt;
46
47
cpu = &solaris_cpu[curcpu];
48
fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
49
50
for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
51
if ((uintptr_t)fbt->fbtp_patchpoint != addr)
52
continue;
53
54
cpu->cpu_dtrace_caller = addr;
55
56
if (fbt->fbtp_roffset == 0) {
57
dtrace_probe(fbt->fbtp_id, frame->tf_x[0],
58
frame->tf_x[1], frame->tf_x[2],
59
frame->tf_x[3], frame->tf_x[4]);
60
} else {
61
dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset, rval,
62
0, 0, 0);
63
}
64
cpu->cpu_dtrace_caller = 0;
65
return (fbt->fbtp_savedval);
66
}
67
68
return (0);
69
}
70
71
void
72
fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val)
73
{
74
void *addr;
75
76
if (!arm64_get_writable_addr(fbt->fbtp_patchpoint, &addr))
77
panic("%s: Unable to write new instruction", __func__);
78
79
*(fbt_patchval_t *)addr = val;
80
cpu_icache_sync_range(fbt->fbtp_patchpoint, 4);
81
}
82
83
int
84
fbt_provide_module_function(linker_file_t lf, int symindx,
85
linker_symval_t *symval, void *opaque)
86
{
87
fbt_probe_t *fbt, *retfbt;
88
uint32_t *target, *start;
89
uint32_t *instr, *limit;
90
const char *name;
91
char *modname;
92
int offs;
93
94
modname = opaque;
95
name = symval->name;
96
97
/* Check if function is excluded from instrumentation */
98
if (fbt_excluded(name))
99
return (0);
100
101
/*
102
* Instrumenting certain exception handling functions can lead to FBT
103
* recursion, so exclude from instrumentation.
104
*/
105
if (strcmp(name, "handle_el1h_sync") == 0 ||
106
strcmp(name, "do_el1h_sync") == 0)
107
return (1);
108
109
instr = (uint32_t *)(symval->value);
110
limit = (uint32_t *)(symval->value + symval->size);
111
112
/*
113
* Ignore any bti instruction at the start of the function
114
* we need to keep it there for any indirect branches calling
115
* the function on Armv8.5+
116
*/
117
if ((*instr & BTI_MASK) == BTI_INSTR)
118
instr++;
119
120
/*
121
* If the first instruction is a nop it's a specially marked
122
* asm function. We only support a nop first as it's not a normal
123
* part of the function prologue.
124
*/
125
if (*instr == NOP_INSTR)
126
goto found;
127
128
/* Look for stp (pre-indexed) or sub operation */
129
for (; instr < limit; instr++) {
130
/*
131
* Functions start with "stp xt1, xt2, [xn, <const>]!" or
132
* "sub sp, sp, <const>".
133
*
134
* Sometimes the compiler will have a sub instruction that is
135
* not of the above type so don't stop if we see one.
136
*/
137
if ((*instr & LDP_STP_MASK) == STP_64) {
138
/*
139
* Assume any other store of this type means we are
140
* past the function prologue.
141
*/
142
if (((*instr >> ADDR_SHIFT) & ADDR_MASK) == 31)
143
break;
144
} else if ((*instr & SUB_MASK) == SUB_INSTR &&
145
((*instr >> SUB_RD_SHIFT) & SUB_R_MASK) == 31 &&
146
((*instr >> SUB_RN_SHIFT) & SUB_R_MASK) == 31)
147
break;
148
}
149
found:
150
if (instr >= limit)
151
return (0);
152
153
fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
154
fbt->fbtp_name = name;
155
fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
156
name, FBT_ENTRY, FBT_AFRAMES, fbt);
157
fbt->fbtp_patchpoint = instr;
158
fbt->fbtp_ctl = lf;
159
fbt->fbtp_loadcnt = lf->loadcnt;
160
fbt->fbtp_savedval = *instr;
161
fbt->fbtp_patchval = FBT_PATCHVAL;
162
if ((*instr & SUB_MASK) == SUB_INSTR)
163
fbt->fbtp_rval = DTRACE_INVOP_SUB;
164
else
165
fbt->fbtp_rval = DTRACE_INVOP_STP;
166
fbt->fbtp_symindx = symindx;
167
168
fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
169
fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
170
171
lf->fbt_nentries++;
172
173
retfbt = NULL;
174
again:
175
for (; instr < limit; instr++) {
176
if (*instr == RET_INSTR)
177
break;
178
else if ((*instr & B_MASK) == B_INSTR) {
179
offs = (*instr & B_DATA_MASK);
180
target = instr + offs;
181
start = (uint32_t *)symval->value;
182
if (target >= limit || target < start)
183
break;
184
}
185
}
186
187
if (instr >= limit)
188
return (0);
189
190
/*
191
* We have a winner!
192
*/
193
fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
194
fbt->fbtp_name = name;
195
if (retfbt == NULL) {
196
fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
197
name, FBT_RETURN, FBT_AFRAMES, fbt);
198
} else {
199
retfbt->fbtp_probenext = fbt;
200
fbt->fbtp_id = retfbt->fbtp_id;
201
}
202
retfbt = fbt;
203
204
fbt->fbtp_patchpoint = instr;
205
fbt->fbtp_ctl = lf;
206
fbt->fbtp_loadcnt = lf->loadcnt;
207
fbt->fbtp_symindx = symindx;
208
if ((*instr & B_MASK) == B_INSTR)
209
fbt->fbtp_rval = DTRACE_INVOP_B;
210
else
211
fbt->fbtp_rval = DTRACE_INVOP_RET;
212
fbt->fbtp_roffset = (uintptr_t)instr - (uintptr_t)symval->value;
213
fbt->fbtp_savedval = *instr;
214
fbt->fbtp_patchval = FBT_PATCHVAL;
215
fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
216
fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
217
218
lf->fbt_nentries++;
219
220
instr++;
221
goto again;
222
}
223
224