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