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