Deleted Added
full compact
fasttrap_isa.c (291961) fasttrap_isa.c (296479)
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 2013 Justin Hibbits */
22/*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <sys/fasttrap_isa.h>
28#include <sys/fasttrap_impl.h>
29#include <sys/dtrace.h>
30#include <sys/dtrace_impl.h>
31#include <cddl/dev/dtrace/dtrace_cddl.h>
32#include <sys/proc.h>
33#include <sys/types.h>
34#include <sys/uio.h>
35#include <sys/ptrace.h>
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 2013 Justin Hibbits */
22/*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <sys/fasttrap_isa.h>
28#include <sys/fasttrap_impl.h>
29#include <sys/dtrace.h>
30#include <sys/dtrace_impl.h>
31#include <cddl/dev/dtrace/dtrace_cddl.h>
32#include <sys/proc.h>
33#include <sys/types.h>
34#include <sys/uio.h>
35#include <sys/ptrace.h>
36#include <sys/rmlock.h>
36#include <sys/sysent.h>
37
38#define OP(x) ((x) >> 26)
39#define OPX(x) (((x) >> 2) & 0x3FF)
40#define OP_BO(x) (((x) & 0x03E00000) >> 21)
41#define OP_BI(x) (((x) & 0x001F0000) >> 16)
42#define OP_RS(x) (((x) & 0x03E00000) >> 21)
43#define OP_RA(x) (((x) & 0x001F0000) >> 16)
44#define OP_RB(x) (((x) & 0x0000F100) >> 11)
45
46static int
47uread(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
48{
49 ssize_t n;
50
51 PHOLD(p);
52 n = proc_readmem(curthread, p, uaddr, kaddr, len);
53 PRELE(p);
54 if (n <= 0 || n < len)
55 return (ENOMEM);
56 return (0);
57}
58
59static int
60uwrite(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
61{
62 ssize_t n;
63
64 PHOLD(p);
65 n = proc_writemem(curthread, p, uaddr, kaddr, len);
66 PRELE(p);
67 if (n <= 0 || n < len)
68 return (ENOMEM);
69 return (0);
70}
71
72int
73fasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp)
74{
75 fasttrap_instr_t instr = FASTTRAP_INSTR;
76
77 if (uwrite(p, &instr, 4, tp->ftt_pc) != 0)
78 return (-1);
79
80 return (0);
81}
82
83int
84fasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp)
85{
86 uint32_t instr;
87
88 /*
89 * Distinguish between read or write failures and a changed
90 * instruction.
91 */
92 if (uread(p, &instr, 4, tp->ftt_pc) != 0)
93 return (0);
94 if (instr != FASTTRAP_INSTR)
95 return (0);
96 if (uwrite(p, &tp->ftt_instr, 4, tp->ftt_pc) != 0)
97 return (-1);
98
99 return (0);
100}
101
102int
103fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, uintptr_t pc,
104 fasttrap_probe_type_t type)
105{
106 uint32_t instr;
107 //int32_t disp;
108
109 /*
110 * Read the instruction at the given address out of the process's
111 * address space. We don't have to worry about a debugger
112 * changing this instruction before we overwrite it with our trap
113 * instruction since P_PR_LOCK is set.
114 */
115 if (uread(p, &instr, 4, pc) != 0)
116 return (-1);
117
118 /*
119 * Decode the instruction to fill in the probe flags. We can have
120 * the process execute most instructions on its own using a pc/npc
121 * trick, but pc-relative control transfer present a problem since
122 * we're relocating the instruction. We emulate these instructions
123 * in the kernel. We assume a default type and over-write that as
124 * needed.
125 *
126 * pc-relative instructions must be emulated for correctness;
127 * other instructions (which represent a large set of commonly traced
128 * instructions) are emulated or otherwise optimized for performance.
129 */
130 tp->ftt_type = FASTTRAP_T_COMMON;
131 tp->ftt_instr = instr;
132
133 switch (OP(instr)) {
134 /* The following are invalid for trapping (invalid opcodes, tw/twi). */
135 case 0:
136 case 1:
137 case 2:
138 case 4:
139 case 5:
140 case 6:
141 case 30:
142 case 39:
143 case 58:
144 case 62:
145 case 3: /* twi */
146 return (-1);
147 case 31: /* tw */
148 if (OPX(instr) == 4)
149 return (-1);
150 else if (OPX(instr) == 444 && OP_RS(instr) == OP_RA(instr) &&
151 OP_RS(instr) == OP_RB(instr))
152 tp->ftt_type = FASTTRAP_T_NOP;
153 break;
154 case 16:
155 tp->ftt_type = FASTTRAP_T_BC;
156 tp->ftt_dest = instr & 0x0000FFFC; /* Extract target address */
157 if (instr & 0x00008000)
158 tp->ftt_dest |= 0xFFFF0000;
159 /* Use as offset if not absolute address. */
160 if (!(instr & 0x02))
161 tp->ftt_dest += pc;
162 tp->ftt_bo = OP_BO(instr);
163 tp->ftt_bi = OP_BI(instr);
164 break;
165 case 18:
166 tp->ftt_type = FASTTRAP_T_B;
167 tp->ftt_dest = instr & 0x03FFFFFC; /* Extract target address */
168 if (instr & 0x02000000)
169 tp->ftt_dest |= 0xFC000000;
170 /* Use as offset if not absolute address. */
171 if (!(instr & 0x02))
172 tp->ftt_dest += pc;
173 break;
174 case 19:
175 switch (OPX(instr)) {
176 case 528: /* bcctr */
177 tp->ftt_type = FASTTRAP_T_BCTR;
178 tp->ftt_bo = OP_BO(instr);
179 tp->ftt_bi = OP_BI(instr);
180 break;
181 case 16: /* bclr */
182 tp->ftt_type = FASTTRAP_T_BCTR;
183 tp->ftt_bo = OP_BO(instr);
184 tp->ftt_bi = OP_BI(instr);
185 break;
186 };
187 break;
188 case 24:
189 if (OP_RS(instr) == OP_RA(instr) &&
190 (instr & 0x0000FFFF) == 0)
191 tp->ftt_type = FASTTRAP_T_NOP;
192 break;
193 };
194
195 /*
196 * We don't know how this tracepoint is going to be used, but in case
197 * it's used as part of a function return probe, we need to indicate
198 * whether it's always a return site or only potentially a return
199 * site. If it's part of a return probe, it's always going to be a
200 * return from that function if it's a restore instruction or if
201 * the previous instruction was a return. If we could reliably
202 * distinguish jump tables from return sites, this wouldn't be
203 * necessary.
204 */
205#if 0
206 if (tp->ftt_type != FASTTRAP_T_RESTORE &&
207 (uread(p, &instr, 4, pc - sizeof (instr)) != 0 ||
208 !(OP(instr) == 2 && OP3(instr) == OP3_RETURN)))
209 tp->ftt_flags |= FASTTRAP_F_RETMAYBE;
210#endif
211
212 return (0);
213}
214
215static uint64_t
216fasttrap_anarg(struct reg *rp, int argno)
217{
218 uint64_t value;
219 proc_t *p = curproc;
220
221 /* The first 8 arguments are in registers. */
222 if (argno < 8)
223 return rp->fixreg[argno + 3];
224
225 /* Arguments on stack start after SP+LR (2 register slots). */
226 if (SV_PROC_FLAG(p, SV_ILP32)) {
227 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
228 value = dtrace_fuword32((void *)(rp->fixreg[1] + 8 +
229 ((argno - 8) * sizeof(uint32_t))));
230 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);
231 } else {
232 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
233 value = dtrace_fuword64((void *)(rp->fixreg[1] + 48 +
234 ((argno - 8) * sizeof(uint64_t))));
235 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);
236 }
237 return value;
238}
239
240uint64_t
241fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
242 int aframes)
243{
244 struct reg r;
245
246 fill_regs(curthread, &r);
247
248 return (fasttrap_anarg(&r, argno));
249}
250
251uint64_t
252fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
253 int aframes)
254{
255 struct reg r;
256
257 fill_regs(curthread, &r);
258
259 return (fasttrap_anarg(&r, argno));
260}
261
262static void
263fasttrap_usdt_args(fasttrap_probe_t *probe, struct reg *rp, int argc,
264 uintptr_t *argv)
265{
266 int i, x, cap = MIN(argc, probe->ftp_nargs);
267
268 for (i = 0; i < cap; i++) {
269 x = probe->ftp_argmap[i];
270
271 if (x < 8)
272 argv[i] = rp->fixreg[x];
273 else
274 if (SV_PROC_FLAG(curproc, SV_ILP32))
275 argv[i] = fuword32((void *)(rp->fixreg[1] + 8 +
276 (x * sizeof(uint32_t))));
277 else
278 argv[i] = fuword64((void *)(rp->fixreg[1] + 48 +
279 (x * sizeof(uint64_t))));
280 }
281
282 for (; i < argc; i++) {
283 argv[i] = 0;
284 }
285}
286
287static void
288fasttrap_return_common(struct reg *rp, uintptr_t pc, pid_t pid,
289 uintptr_t new_pc)
290{
37#include <sys/sysent.h>
38
39#define OP(x) ((x) >> 26)
40#define OPX(x) (((x) >> 2) & 0x3FF)
41#define OP_BO(x) (((x) & 0x03E00000) >> 21)
42#define OP_BI(x) (((x) & 0x001F0000) >> 16)
43#define OP_RS(x) (((x) & 0x03E00000) >> 21)
44#define OP_RA(x) (((x) & 0x001F0000) >> 16)
45#define OP_RB(x) (((x) & 0x0000F100) >> 11)
46
47static int
48uread(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
49{
50 ssize_t n;
51
52 PHOLD(p);
53 n = proc_readmem(curthread, p, uaddr, kaddr, len);
54 PRELE(p);
55 if (n <= 0 || n < len)
56 return (ENOMEM);
57 return (0);
58}
59
60static int
61uwrite(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
62{
63 ssize_t n;
64
65 PHOLD(p);
66 n = proc_writemem(curthread, p, uaddr, kaddr, len);
67 PRELE(p);
68 if (n <= 0 || n < len)
69 return (ENOMEM);
70 return (0);
71}
72
73int
74fasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp)
75{
76 fasttrap_instr_t instr = FASTTRAP_INSTR;
77
78 if (uwrite(p, &instr, 4, tp->ftt_pc) != 0)
79 return (-1);
80
81 return (0);
82}
83
84int
85fasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp)
86{
87 uint32_t instr;
88
89 /*
90 * Distinguish between read or write failures and a changed
91 * instruction.
92 */
93 if (uread(p, &instr, 4, tp->ftt_pc) != 0)
94 return (0);
95 if (instr != FASTTRAP_INSTR)
96 return (0);
97 if (uwrite(p, &tp->ftt_instr, 4, tp->ftt_pc) != 0)
98 return (-1);
99
100 return (0);
101}
102
103int
104fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, uintptr_t pc,
105 fasttrap_probe_type_t type)
106{
107 uint32_t instr;
108 //int32_t disp;
109
110 /*
111 * Read the instruction at the given address out of the process's
112 * address space. We don't have to worry about a debugger
113 * changing this instruction before we overwrite it with our trap
114 * instruction since P_PR_LOCK is set.
115 */
116 if (uread(p, &instr, 4, pc) != 0)
117 return (-1);
118
119 /*
120 * Decode the instruction to fill in the probe flags. We can have
121 * the process execute most instructions on its own using a pc/npc
122 * trick, but pc-relative control transfer present a problem since
123 * we're relocating the instruction. We emulate these instructions
124 * in the kernel. We assume a default type and over-write that as
125 * needed.
126 *
127 * pc-relative instructions must be emulated for correctness;
128 * other instructions (which represent a large set of commonly traced
129 * instructions) are emulated or otherwise optimized for performance.
130 */
131 tp->ftt_type = FASTTRAP_T_COMMON;
132 tp->ftt_instr = instr;
133
134 switch (OP(instr)) {
135 /* The following are invalid for trapping (invalid opcodes, tw/twi). */
136 case 0:
137 case 1:
138 case 2:
139 case 4:
140 case 5:
141 case 6:
142 case 30:
143 case 39:
144 case 58:
145 case 62:
146 case 3: /* twi */
147 return (-1);
148 case 31: /* tw */
149 if (OPX(instr) == 4)
150 return (-1);
151 else if (OPX(instr) == 444 && OP_RS(instr) == OP_RA(instr) &&
152 OP_RS(instr) == OP_RB(instr))
153 tp->ftt_type = FASTTRAP_T_NOP;
154 break;
155 case 16:
156 tp->ftt_type = FASTTRAP_T_BC;
157 tp->ftt_dest = instr & 0x0000FFFC; /* Extract target address */
158 if (instr & 0x00008000)
159 tp->ftt_dest |= 0xFFFF0000;
160 /* Use as offset if not absolute address. */
161 if (!(instr & 0x02))
162 tp->ftt_dest += pc;
163 tp->ftt_bo = OP_BO(instr);
164 tp->ftt_bi = OP_BI(instr);
165 break;
166 case 18:
167 tp->ftt_type = FASTTRAP_T_B;
168 tp->ftt_dest = instr & 0x03FFFFFC; /* Extract target address */
169 if (instr & 0x02000000)
170 tp->ftt_dest |= 0xFC000000;
171 /* Use as offset if not absolute address. */
172 if (!(instr & 0x02))
173 tp->ftt_dest += pc;
174 break;
175 case 19:
176 switch (OPX(instr)) {
177 case 528: /* bcctr */
178 tp->ftt_type = FASTTRAP_T_BCTR;
179 tp->ftt_bo = OP_BO(instr);
180 tp->ftt_bi = OP_BI(instr);
181 break;
182 case 16: /* bclr */
183 tp->ftt_type = FASTTRAP_T_BCTR;
184 tp->ftt_bo = OP_BO(instr);
185 tp->ftt_bi = OP_BI(instr);
186 break;
187 };
188 break;
189 case 24:
190 if (OP_RS(instr) == OP_RA(instr) &&
191 (instr & 0x0000FFFF) == 0)
192 tp->ftt_type = FASTTRAP_T_NOP;
193 break;
194 };
195
196 /*
197 * We don't know how this tracepoint is going to be used, but in case
198 * it's used as part of a function return probe, we need to indicate
199 * whether it's always a return site or only potentially a return
200 * site. If it's part of a return probe, it's always going to be a
201 * return from that function if it's a restore instruction or if
202 * the previous instruction was a return. If we could reliably
203 * distinguish jump tables from return sites, this wouldn't be
204 * necessary.
205 */
206#if 0
207 if (tp->ftt_type != FASTTRAP_T_RESTORE &&
208 (uread(p, &instr, 4, pc - sizeof (instr)) != 0 ||
209 !(OP(instr) == 2 && OP3(instr) == OP3_RETURN)))
210 tp->ftt_flags |= FASTTRAP_F_RETMAYBE;
211#endif
212
213 return (0);
214}
215
216static uint64_t
217fasttrap_anarg(struct reg *rp, int argno)
218{
219 uint64_t value;
220 proc_t *p = curproc;
221
222 /* The first 8 arguments are in registers. */
223 if (argno < 8)
224 return rp->fixreg[argno + 3];
225
226 /* Arguments on stack start after SP+LR (2 register slots). */
227 if (SV_PROC_FLAG(p, SV_ILP32)) {
228 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
229 value = dtrace_fuword32((void *)(rp->fixreg[1] + 8 +
230 ((argno - 8) * sizeof(uint32_t))));
231 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);
232 } else {
233 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
234 value = dtrace_fuword64((void *)(rp->fixreg[1] + 48 +
235 ((argno - 8) * sizeof(uint64_t))));
236 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);
237 }
238 return value;
239}
240
241uint64_t
242fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
243 int aframes)
244{
245 struct reg r;
246
247 fill_regs(curthread, &r);
248
249 return (fasttrap_anarg(&r, argno));
250}
251
252uint64_t
253fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
254 int aframes)
255{
256 struct reg r;
257
258 fill_regs(curthread, &r);
259
260 return (fasttrap_anarg(&r, argno));
261}
262
263static void
264fasttrap_usdt_args(fasttrap_probe_t *probe, struct reg *rp, int argc,
265 uintptr_t *argv)
266{
267 int i, x, cap = MIN(argc, probe->ftp_nargs);
268
269 for (i = 0; i < cap; i++) {
270 x = probe->ftp_argmap[i];
271
272 if (x < 8)
273 argv[i] = rp->fixreg[x];
274 else
275 if (SV_PROC_FLAG(curproc, SV_ILP32))
276 argv[i] = fuword32((void *)(rp->fixreg[1] + 8 +
277 (x * sizeof(uint32_t))));
278 else
279 argv[i] = fuword64((void *)(rp->fixreg[1] + 48 +
280 (x * sizeof(uint64_t))));
281 }
282
283 for (; i < argc; i++) {
284 argv[i] = 0;
285 }
286}
287
288static void
289fasttrap_return_common(struct reg *rp, uintptr_t pc, pid_t pid,
290 uintptr_t new_pc)
291{
292 struct rm_priotracker tracker;
291 fasttrap_tracepoint_t *tp;
292 fasttrap_bucket_t *bucket;
293 fasttrap_id_t *id;
294
293 fasttrap_tracepoint_t *tp;
294 fasttrap_bucket_t *bucket;
295 fasttrap_id_t *id;
296
297 rm_rlock(&fasttrap_tp_lock, &tracker);
295 bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
296
297 for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
298 if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
299 tp->ftt_proc->ftpc_acount != 0)
300 break;
301 }
302
303 /*
304 * Don't sweat it if we can't find the tracepoint again; unlike
305 * when we're in fasttrap_pid_probe(), finding the tracepoint here
306 * is not essential to the correct execution of the process.
307 */
308 if (tp == NULL) {
298 bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
299
300 for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
301 if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
302 tp->ftt_proc->ftpc_acount != 0)
303 break;
304 }
305
306 /*
307 * Don't sweat it if we can't find the tracepoint again; unlike
308 * when we're in fasttrap_pid_probe(), finding the tracepoint here
309 * is not essential to the correct execution of the process.
310 */
311 if (tp == NULL) {
312 rm_runlock(&fasttrap_tp_lock, &tracker);
309 return;
310 }
311
312 for (id = tp->ftt_retids; id != NULL; id = id->fti_next) {
313 /*
314 * If there's a branch that could act as a return site, we
315 * need to trace it, and check here if the program counter is
316 * external to the function.
317 */
318 /* Skip function-local branches. */
319 if ((new_pc - id->fti_probe->ftp_faddr) < id->fti_probe->ftp_fsize)
320 continue;
321
322 dtrace_probe(id->fti_probe->ftp_id,
323 pc - id->fti_probe->ftp_faddr,
324 rp->fixreg[3], rp->fixreg[4], 0, 0);
325 }
313 return;
314 }
315
316 for (id = tp->ftt_retids; id != NULL; id = id->fti_next) {
317 /*
318 * If there's a branch that could act as a return site, we
319 * need to trace it, and check here if the program counter is
320 * external to the function.
321 */
322 /* Skip function-local branches. */
323 if ((new_pc - id->fti_probe->ftp_faddr) < id->fti_probe->ftp_fsize)
324 continue;
325
326 dtrace_probe(id->fti_probe->ftp_id,
327 pc - id->fti_probe->ftp_faddr,
328 rp->fixreg[3], rp->fixreg[4], 0, 0);
329 }
330 rm_runlock(&fasttrap_tp_lock, &tracker);
326}
327
328
329static int
330fasttrap_branch_taken(int bo, int bi, struct reg *regs)
331{
332 int crzero = 0;
333
334 /* Branch always? */
335 if ((bo & 0x14) == 0x14)
336 return 1;
337
338 /* Handle decrementing ctr */
339 if (!(bo & 0x04)) {
340 --regs->ctr;
341 crzero = (regs->ctr == 0);
342 if (bo & 0x10) {
343 return (!(crzero ^ (bo >> 1)));
344 }
345 }
346
347 return (crzero | (((regs->cr >> (31 - bi)) ^ (bo >> 3)) ^ 1));
348}
349
350
351int
352fasttrap_pid_probe(struct reg *rp)
353{
331}
332
333
334static int
335fasttrap_branch_taken(int bo, int bi, struct reg *regs)
336{
337 int crzero = 0;
338
339 /* Branch always? */
340 if ((bo & 0x14) == 0x14)
341 return 1;
342
343 /* Handle decrementing ctr */
344 if (!(bo & 0x04)) {
345 --regs->ctr;
346 crzero = (regs->ctr == 0);
347 if (bo & 0x10) {
348 return (!(crzero ^ (bo >> 1)));
349 }
350 }
351
352 return (crzero | (((regs->cr >> (31 - bi)) ^ (bo >> 3)) ^ 1));
353}
354
355
356int
357fasttrap_pid_probe(struct reg *rp)
358{
359 struct rm_priotracker tracker;
354 proc_t *p = curproc;
355 uintptr_t pc = rp->pc;
356 uintptr_t new_pc = 0;
357 fasttrap_bucket_t *bucket;
358 fasttrap_tracepoint_t *tp, tp_local;
359 pid_t pid;
360 dtrace_icookie_t cookie;
361 uint_t is_enabled = 0;
362
363 /*
364 * It's possible that a user (in a veritable orgy of bad planning)
365 * could redirect this thread's flow of control before it reached the
366 * return probe fasttrap. In this case we need to kill the process
367 * since it's in a unrecoverable state.
368 */
369 if (curthread->t_dtrace_step) {
370 ASSERT(curthread->t_dtrace_on);
371 fasttrap_sigtrap(p, curthread, pc);
372 return (0);
373 }
374
375 /*
376 * Clear all user tracing flags.
377 */
378 curthread->t_dtrace_ft = 0;
379 curthread->t_dtrace_pc = 0;
380 curthread->t_dtrace_npc = 0;
381 curthread->t_dtrace_scrpc = 0;
382 curthread->t_dtrace_astpc = 0;
383
360 proc_t *p = curproc;
361 uintptr_t pc = rp->pc;
362 uintptr_t new_pc = 0;
363 fasttrap_bucket_t *bucket;
364 fasttrap_tracepoint_t *tp, tp_local;
365 pid_t pid;
366 dtrace_icookie_t cookie;
367 uint_t is_enabled = 0;
368
369 /*
370 * It's possible that a user (in a veritable orgy of bad planning)
371 * could redirect this thread's flow of control before it reached the
372 * return probe fasttrap. In this case we need to kill the process
373 * since it's in a unrecoverable state.
374 */
375 if (curthread->t_dtrace_step) {
376 ASSERT(curthread->t_dtrace_on);
377 fasttrap_sigtrap(p, curthread, pc);
378 return (0);
379 }
380
381 /*
382 * Clear all user tracing flags.
383 */
384 curthread->t_dtrace_ft = 0;
385 curthread->t_dtrace_pc = 0;
386 curthread->t_dtrace_npc = 0;
387 curthread->t_dtrace_scrpc = 0;
388 curthread->t_dtrace_astpc = 0;
389
384
385 PROC_LOCK(p);
390 rm_rlock(&fasttrap_tp_lock, &tracker);
386 pid = p->p_pid;
387 bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
388
389 /*
390 * Lookup the tracepoint that the process just hit.
391 */
392 for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
393 if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
394 tp->ftt_proc->ftpc_acount != 0)
395 break;
396 }
397
398 /*
399 * If we couldn't find a matching tracepoint, either a tracepoint has
400 * been inserted without using the pid<pid> ioctl interface (see
401 * fasttrap_ioctl), or somehow we have mislaid this tracepoint.
402 */
403 if (tp == NULL) {
391 pid = p->p_pid;
392 bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
393
394 /*
395 * Lookup the tracepoint that the process just hit.
396 */
397 for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
398 if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
399 tp->ftt_proc->ftpc_acount != 0)
400 break;
401 }
402
403 /*
404 * If we couldn't find a matching tracepoint, either a tracepoint has
405 * been inserted without using the pid<pid> ioctl interface (see
406 * fasttrap_ioctl), or somehow we have mislaid this tracepoint.
407 */
408 if (tp == NULL) {
404 PROC_UNLOCK(p);
409 rm_runlock(&fasttrap_tp_lock, &tracker);
405 return (-1);
406 }
407
408 if (tp->ftt_ids != NULL) {
409 fasttrap_id_t *id;
410
411 for (id = tp->ftt_ids; id != NULL; id = id->fti_next) {
412 fasttrap_probe_t *probe = id->fti_probe;
413
414 if (id->fti_ptype == DTFTP_ENTRY) {
415 /*
416 * We note that this was an entry
417 * probe to help ustack() find the
418 * first caller.
419 */
420 cookie = dtrace_interrupt_disable();
421 DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY);
422 dtrace_probe(probe->ftp_id, rp->fixreg[3],
423 rp->fixreg[4], rp->fixreg[5], rp->fixreg[6],
424 rp->fixreg[7]);
425 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY);
426 dtrace_interrupt_enable(cookie);
427 } else if (id->fti_ptype == DTFTP_IS_ENABLED) {
428 /*
429 * Note that in this case, we don't
430 * call dtrace_probe() since it's only
431 * an artificial probe meant to change
432 * the flow of control so that it
433 * encounters the true probe.
434 */
435 is_enabled = 1;
436 } else if (probe->ftp_argmap == NULL) {
437 dtrace_probe(probe->ftp_id, rp->fixreg[3],
438 rp->fixreg[4], rp->fixreg[5], rp->fixreg[6],
439 rp->fixreg[7]);
440 } else {
441 uintptr_t t[5];
442
443 fasttrap_usdt_args(probe, rp,
444 sizeof (t) / sizeof (t[0]), t);
445
446 dtrace_probe(probe->ftp_id, t[0], t[1],
447 t[2], t[3], t[4]);
448 }
449 }
450 }
451
452 /*
453 * We're about to do a bunch of work so we cache a local copy of
454 * the tracepoint to emulate the instruction, and then find the
455 * tracepoint again later if we need to light up any return probes.
456 */
457 tp_local = *tp;
410 return (-1);
411 }
412
413 if (tp->ftt_ids != NULL) {
414 fasttrap_id_t *id;
415
416 for (id = tp->ftt_ids; id != NULL; id = id->fti_next) {
417 fasttrap_probe_t *probe = id->fti_probe;
418
419 if (id->fti_ptype == DTFTP_ENTRY) {
420 /*
421 * We note that this was an entry
422 * probe to help ustack() find the
423 * first caller.
424 */
425 cookie = dtrace_interrupt_disable();
426 DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY);
427 dtrace_probe(probe->ftp_id, rp->fixreg[3],
428 rp->fixreg[4], rp->fixreg[5], rp->fixreg[6],
429 rp->fixreg[7]);
430 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY);
431 dtrace_interrupt_enable(cookie);
432 } else if (id->fti_ptype == DTFTP_IS_ENABLED) {
433 /*
434 * Note that in this case, we don't
435 * call dtrace_probe() since it's only
436 * an artificial probe meant to change
437 * the flow of control so that it
438 * encounters the true probe.
439 */
440 is_enabled = 1;
441 } else if (probe->ftp_argmap == NULL) {
442 dtrace_probe(probe->ftp_id, rp->fixreg[3],
443 rp->fixreg[4], rp->fixreg[5], rp->fixreg[6],
444 rp->fixreg[7]);
445 } else {
446 uintptr_t t[5];
447
448 fasttrap_usdt_args(probe, rp,
449 sizeof (t) / sizeof (t[0]), t);
450
451 dtrace_probe(probe->ftp_id, t[0], t[1],
452 t[2], t[3], t[4]);
453 }
454 }
455 }
456
457 /*
458 * We're about to do a bunch of work so we cache a local copy of
459 * the tracepoint to emulate the instruction, and then find the
460 * tracepoint again later if we need to light up any return probes.
461 */
462 tp_local = *tp;
458 PROC_UNLOCK(p);
463 rm_runlock(&fasttrap_tp_lock, &tracker);
459 tp = &tp_local;
460
461 /*
462 * If there's an is-enabled probe connected to this tracepoint it
463 * means that there was a 'xor r3, r3, r3'
464 * instruction that was placed there by DTrace when the binary was
465 * linked. As this probe is, in fact, enabled, we need to stuff 1
466 * into R3. Accordingly, we can bypass all the instruction
467 * emulation logic since we know the inevitable result. It's possible
468 * that a user could construct a scenario where the 'is-enabled'
469 * probe was on some other instruction, but that would be a rather
470 * exotic way to shoot oneself in the foot.
471 */
472 if (is_enabled) {
473 rp->fixreg[3] = 1;
474 new_pc = rp->pc + 4;
475 goto done;
476 }
477
478
479 switch (tp->ftt_type) {
480 case FASTTRAP_T_NOP:
481 new_pc = rp->pc + 4;
482 break;
483 case FASTTRAP_T_BC:
484 if (!fasttrap_branch_taken(tp->ftt_bo, tp->ftt_bi, rp))
485 break;
486 /* FALLTHROUGH */
487 case FASTTRAP_T_B:
488 if (tp->ftt_instr & 0x01)
489 rp->lr = rp->pc + 4;
490 new_pc = tp->ftt_dest;
491 break;
492 case FASTTRAP_T_BLR:
493 case FASTTRAP_T_BCTR:
494 if (!fasttrap_branch_taken(tp->ftt_bo, tp->ftt_bi, rp))
495 break;
496 /* FALLTHROUGH */
497 if (tp->ftt_type == FASTTRAP_T_BCTR)
498 new_pc = rp->ctr;
499 else
500 new_pc = rp->lr;
501 if (tp->ftt_instr & 0x01)
502 rp->lr = rp->pc + 4;
503 break;
504 case FASTTRAP_T_COMMON:
505 break;
506 };
507done:
508 /*
509 * If there were no return probes when we first found the tracepoint,
510 * we should feel no obligation to honor any return probes that were
511 * subsequently enabled -- they'll just have to wait until the next
512 * time around.
513 */
514 if (tp->ftt_retids != NULL) {
515 /*
516 * We need to wait until the results of the instruction are
517 * apparent before invoking any return probes. If this
518 * instruction was emulated we can just call
519 * fasttrap_return_common(); if it needs to be executed, we
520 * need to wait until the user thread returns to the kernel.
521 */
522 if (tp->ftt_type != FASTTRAP_T_COMMON) {
523 fasttrap_return_common(rp, pc, pid, new_pc);
524 } else {
525 ASSERT(curthread->t_dtrace_ret != 0);
526 ASSERT(curthread->t_dtrace_pc == pc);
527 ASSERT(curthread->t_dtrace_scrpc != 0);
528 ASSERT(new_pc == curthread->t_dtrace_astpc);
529 }
530 }
531
532 rp->pc = new_pc;
533 set_regs(curthread, rp);
534
535 return (0);
536}
537
538int
539fasttrap_return_probe(struct reg *rp)
540{
541 proc_t *p = curproc;
542 uintptr_t pc = curthread->t_dtrace_pc;
543 uintptr_t npc = curthread->t_dtrace_npc;
544
545 curthread->t_dtrace_pc = 0;
546 curthread->t_dtrace_npc = 0;
547 curthread->t_dtrace_scrpc = 0;
548 curthread->t_dtrace_astpc = 0;
549
550 /*
551 * We set rp->pc to the address of the traced instruction so
552 * that it appears to dtrace_probe() that we're on the original
553 * instruction, and so that the user can't easily detect our
554 * complex web of lies. dtrace_return_probe() (our caller)
555 * will correctly set %pc after we return.
556 */
557 rp->pc = pc;
558
559 fasttrap_return_common(rp, pc, p->p_pid, npc);
560
561 return (0);
562}
563
464 tp = &tp_local;
465
466 /*
467 * If there's an is-enabled probe connected to this tracepoint it
468 * means that there was a 'xor r3, r3, r3'
469 * instruction that was placed there by DTrace when the binary was
470 * linked. As this probe is, in fact, enabled, we need to stuff 1
471 * into R3. Accordingly, we can bypass all the instruction
472 * emulation logic since we know the inevitable result. It's possible
473 * that a user could construct a scenario where the 'is-enabled'
474 * probe was on some other instruction, but that would be a rather
475 * exotic way to shoot oneself in the foot.
476 */
477 if (is_enabled) {
478 rp->fixreg[3] = 1;
479 new_pc = rp->pc + 4;
480 goto done;
481 }
482
483
484 switch (tp->ftt_type) {
485 case FASTTRAP_T_NOP:
486 new_pc = rp->pc + 4;
487 break;
488 case FASTTRAP_T_BC:
489 if (!fasttrap_branch_taken(tp->ftt_bo, tp->ftt_bi, rp))
490 break;
491 /* FALLTHROUGH */
492 case FASTTRAP_T_B:
493 if (tp->ftt_instr & 0x01)
494 rp->lr = rp->pc + 4;
495 new_pc = tp->ftt_dest;
496 break;
497 case FASTTRAP_T_BLR:
498 case FASTTRAP_T_BCTR:
499 if (!fasttrap_branch_taken(tp->ftt_bo, tp->ftt_bi, rp))
500 break;
501 /* FALLTHROUGH */
502 if (tp->ftt_type == FASTTRAP_T_BCTR)
503 new_pc = rp->ctr;
504 else
505 new_pc = rp->lr;
506 if (tp->ftt_instr & 0x01)
507 rp->lr = rp->pc + 4;
508 break;
509 case FASTTRAP_T_COMMON:
510 break;
511 };
512done:
513 /*
514 * If there were no return probes when we first found the tracepoint,
515 * we should feel no obligation to honor any return probes that were
516 * subsequently enabled -- they'll just have to wait until the next
517 * time around.
518 */
519 if (tp->ftt_retids != NULL) {
520 /*
521 * We need to wait until the results of the instruction are
522 * apparent before invoking any return probes. If this
523 * instruction was emulated we can just call
524 * fasttrap_return_common(); if it needs to be executed, we
525 * need to wait until the user thread returns to the kernel.
526 */
527 if (tp->ftt_type != FASTTRAP_T_COMMON) {
528 fasttrap_return_common(rp, pc, pid, new_pc);
529 } else {
530 ASSERT(curthread->t_dtrace_ret != 0);
531 ASSERT(curthread->t_dtrace_pc == pc);
532 ASSERT(curthread->t_dtrace_scrpc != 0);
533 ASSERT(new_pc == curthread->t_dtrace_astpc);
534 }
535 }
536
537 rp->pc = new_pc;
538 set_regs(curthread, rp);
539
540 return (0);
541}
542
543int
544fasttrap_return_probe(struct reg *rp)
545{
546 proc_t *p = curproc;
547 uintptr_t pc = curthread->t_dtrace_pc;
548 uintptr_t npc = curthread->t_dtrace_npc;
549
550 curthread->t_dtrace_pc = 0;
551 curthread->t_dtrace_npc = 0;
552 curthread->t_dtrace_scrpc = 0;
553 curthread->t_dtrace_astpc = 0;
554
555 /*
556 * We set rp->pc to the address of the traced instruction so
557 * that it appears to dtrace_probe() that we're on the original
558 * instruction, and so that the user can't easily detect our
559 * complex web of lies. dtrace_return_probe() (our caller)
560 * will correctly set %pc after we return.
561 */
562 rp->pc = pc;
563
564 fasttrap_return_common(rp, pc, p->p_pid, npc);
565
566 return (0);
567}
568