Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/cddl/dev/fbt/arm/fbt_isa.c
48378 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
*
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
#include <machine/stack.h>
36
#include <machine/trap.h>
37
38
#include "fbt.h"
39
40
#define FBT_PUSHM 0xe92d0000
41
#define FBT_POPM 0xe8bd0000
42
#define FBT_JUMP 0xea000000
43
#define FBT_SUBSP 0xe24dd000
44
45
int
46
fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval)
47
{
48
solaris_cpu_t *cpu = &solaris_cpu[curcpu];
49
fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
50
register_t fifthparam;
51
52
for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
53
if ((uintptr_t)fbt->fbtp_patchpoint != addr)
54
continue;
55
56
cpu->cpu_dtrace_caller = addr;
57
58
if (fbt->fbtp_roffset == 0) {
59
/* Get 5th parameter from stack */
60
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
61
fifthparam = *(register_t *)frame->tf_svc_sp;
62
DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);
63
64
dtrace_probe(fbt->fbtp_id, frame->tf_r0,
65
frame->tf_r1, frame->tf_r2,
66
frame->tf_r3, fifthparam);
67
} else {
68
dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset, rval,
69
0, 0, 0);
70
}
71
72
cpu->cpu_dtrace_caller = 0;
73
return (fbt->fbtp_rval | (fbt->fbtp_savedval << DTRACE_INVOP_SHIFT));
74
}
75
76
return (0);
77
}
78
79
void
80
fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val)
81
{
82
83
*fbt->fbtp_patchpoint = val;
84
icache_sync((vm_offset_t)fbt->fbtp_patchpoint, sizeof(val));
85
}
86
87
int
88
fbt_provide_module_function(linker_file_t lf, int symindx,
89
linker_symval_t *symval, void *opaque)
90
{
91
char *modname = opaque;
92
const char *name = symval->name;
93
fbt_probe_t *fbt, *retfbt;
94
uint32_t *instr, *limit;
95
int popm;
96
97
if (fbt_excluded(name))
98
return (0);
99
100
instr = (uint32_t *)symval->value;
101
limit = (uint32_t *)(symval->value + symval->size);
102
103
/*
104
* va_arg functions has first instruction of
105
* sub sp, sp, #?
106
*/
107
if ((*instr & 0xfffff000) == FBT_SUBSP)
108
instr++;
109
110
/*
111
* check if insn is a pushm with LR
112
*/
113
if ((*instr & 0xffff0000) != FBT_PUSHM ||
114
(*instr & (1 << LR)) == 0)
115
return (0);
116
117
fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
118
fbt->fbtp_name = name;
119
fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
120
name, FBT_ENTRY, 2, fbt);
121
fbt->fbtp_patchpoint = instr;
122
fbt->fbtp_ctl = lf;
123
fbt->fbtp_loadcnt = lf->loadcnt;
124
fbt->fbtp_savedval = *instr;
125
fbt->fbtp_patchval = FBT_BREAKPOINT;
126
fbt->fbtp_rval = DTRACE_INVOP_PUSHM;
127
fbt->fbtp_symindx = symindx;
128
129
fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
130
fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
131
132
lf->fbt_nentries++;
133
134
popm = FBT_POPM | ((*instr) & 0x3FFF) | 0x8000;
135
136
retfbt = NULL;
137
again:
138
for (; instr < limit; instr++) {
139
if (*instr == popm)
140
break;
141
else if ((*instr & 0xff000000) == FBT_JUMP) {
142
uint32_t *target, *start;
143
int offset;
144
145
offset = (*instr & 0xffffff);
146
offset <<= 8;
147
offset /= 64;
148
target = instr + (2 + offset);
149
start = (uint32_t *)symval->value;
150
if (target >= limit || target < start)
151
break;
152
}
153
}
154
155
if (instr >= limit)
156
return (0);
157
158
/*
159
* We have a winner!
160
*/
161
fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
162
fbt->fbtp_name = name;
163
if (retfbt == NULL) {
164
fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
165
name, FBT_RETURN, 2, fbt);
166
} else {
167
retfbt->fbtp_probenext = fbt;
168
fbt->fbtp_id = retfbt->fbtp_id;
169
}
170
retfbt = fbt;
171
172
fbt->fbtp_patchpoint = instr;
173
fbt->fbtp_ctl = lf;
174
fbt->fbtp_loadcnt = lf->loadcnt;
175
fbt->fbtp_symindx = symindx;
176
if ((*instr & 0xff000000) == FBT_JUMP)
177
fbt->fbtp_rval = DTRACE_INVOP_B;
178
else
179
fbt->fbtp_rval = DTRACE_INVOP_POPM;
180
fbt->fbtp_roffset = (uintptr_t)instr - (uintptr_t)symval->value;
181
fbt->fbtp_savedval = *instr;
182
fbt->fbtp_patchval = FBT_BREAKPOINT;
183
fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
184
fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
185
186
lf->fbt_nentries++;
187
188
instr++;
189
goto again;
190
}
191
192