fasttrap_isa.c revision 299003
120253Sjoerg/*
220302Sjoerg * CDDL HEADER START
320302Sjoerg *
420253Sjoerg * The contents of this file are subject to the terms of the
520253Sjoerg * Common Development and Distribution License (the "License").
620253Sjoerg * You may not use this file except in compliance with the License.
720253Sjoerg *
820253Sjoerg * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
920302Sjoerg * or http://www.opensolaris.org/os/licensing.
1020253Sjoerg * See the License for the specific language governing permissions
1120253Sjoerg * and limitations under the License.
1220253Sjoerg *
1320253Sjoerg * When distributing Covered Code, include this CDDL HEADER in each
1420302Sjoerg * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1520253Sjoerg * If applicable, add the following below this CDDL HEADER, with the
1620253Sjoerg * fields enclosed by brackets "[]" replaced with your own identifying
1720302Sjoerg * information: Portions Copyright [yyyy] [name of copyright owner]
1820253Sjoerg *
1920253Sjoerg * CDDL HEADER END
2020253Sjoerg */
2120253Sjoerg/* Portions Copyright 2013 Justin Hibbits */
2220253Sjoerg/*
2320253Sjoerg * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2420253Sjoerg * Use is subject to license terms.
2520253Sjoerg */
2620253Sjoerg
2730259Scharnier#include <sys/fasttrap_isa.h>
2830259Scharnier#include <sys/fasttrap_impl.h>
2950479Speter#include <sys/dtrace.h>
3030259Scharnier#include <sys/dtrace_impl.h>
3130259Scharnier#include <cddl/dev/dtrace/dtrace_cddl.h>
3230259Scharnier#include <sys/proc.h>
3338112Snate#include <sys/types.h>
3461957Sache#include <sys/uio.h>
3521330Sdavidn#include <sys/ptrace.h>
3621330Sdavidn#include <sys/rmlock.h>
3744229Sdavidn#include <sys/sysent.h>
3820253Sjoerg
3956000Sdavidn#define OP(x)	((x) >> 26)
4056000Sdavidn#define OPX(x)	(((x) >> 2) & 0x3FF)
4156000Sdavidn#define OP_BO(x) (((x) & 0x03E00000) >> 21)
4252512Sdavidn#define OP_BI(x) (((x) & 0x001F0000) >> 16)
4352512Sdavidn#define OP_RS(x) (((x) & 0x03E00000) >> 21)
4452512Sdavidn#define OP_RA(x) (((x) & 0x001F0000) >> 16)
4520253Sjoerg#define OP_RB(x) (((x) & 0x0000F100) >> 11)
4620267Sjoerg
4720267Sjoerg
4852512Sdavidnstatic int
4920267Sjoergproc_ops(int op, proc_t *p, void *kaddr, off_t uaddr, size_t len)
5020267Sjoerg{
5120267Sjoerg	struct iovec iov;
5220267Sjoerg	struct uio uio;
5352512Sdavidn
5420267Sjoerg	iov.iov_base = kaddr;
5552512Sdavidn	iov.iov_len = len;
5620253Sjoerg	uio.uio_offset = uaddr;
5744229Sdavidn	uio.uio_iov = &iov;
5844229Sdavidn	uio.uio_resid = len;
5944229Sdavidn	uio.uio_iovcnt = 1;
6044229Sdavidn	uio.uio_segflg = UIO_SYSSPACE;
6144229Sdavidn	uio.uio_td = curthread;
6244229Sdavidn	uio.uio_rw = op;
6344229Sdavidn	PHOLD(p);
6444229Sdavidn	if (proc_rwmem(p, &uio) != 0) {
6544229Sdavidn		PRELE(p);
6644229Sdavidn		return (-1);
6744229Sdavidn	}
6844229Sdavidn	PRELE(p);
6944229Sdavidn
7044229Sdavidn	return (0);
7144229Sdavidn}
7244229Sdavidn
7344229Sdavidnstatic int
7444229Sdavidnuread(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
7544229Sdavidn{
7644229Sdavidn
7744229Sdavidn	return (proc_ops(UIO_READ, p, kaddr, uaddr, len));
7844229Sdavidn}
7944229Sdavidn
8044229Sdavidnstatic int
8144229Sdavidnuwrite(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
8244229Sdavidn{
8344229Sdavidn
8444229Sdavidn	return (proc_ops(UIO_WRITE, p, kaddr, uaddr, len));
8544229Sdavidn}
8644229Sdavidn
8744229Sdavidnint
8844229Sdavidnfasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp)
8944229Sdavidn{
9044229Sdavidn	fasttrap_instr_t instr = FASTTRAP_INSTR;
9120253Sjoerg
9220253Sjoerg	if (uwrite(p, &instr, 4, tp->ftt_pc) != 0)
9320253Sjoerg		return (-1);
9420253Sjoerg
9520253Sjoerg	return (0);
9620253Sjoerg}
9720253Sjoerg
9820253Sjoergint
9920253Sjoergfasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp)
10020253Sjoerg{
10120253Sjoerg	uint32_t instr;
10220253Sjoerg
10344229Sdavidn	/*
10420253Sjoerg	 * Distinguish between read or write failures and a changed
10520253Sjoerg	 * instruction.
10620253Sjoerg	 */
10720253Sjoerg	if (uread(p, &instr, 4, tp->ftt_pc) != 0)
10820267Sjoerg		return (0);
10944231Sdavidn	if (instr != FASTTRAP_INSTR)
11044231Sdavidn		return (0);
11144231Sdavidn	if (uwrite(p, &tp->ftt_instr, 4, tp->ftt_pc) != 0)
11244386Sdavidn		return (-1);
11352512Sdavidn
11452512Sdavidn	return (0);
11544231Sdavidn}
11620267Sjoerg
11720267Sjoergint
11844231Sdavidnfasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, uintptr_t pc,
11944231Sdavidn    fasttrap_probe_type_t type)
12044231Sdavidn{
12144231Sdavidn	uint32_t instr;
12244231Sdavidn	//int32_t disp;
12320267Sjoerg
12420253Sjoerg	/*
12520253Sjoerg	 * Read the instruction at the given address out of the process's
12620253Sjoerg	 * address space. We don't have to worry about a debugger
12720253Sjoerg	 * changing this instruction before we overwrite it with our trap
12820253Sjoerg	 * instruction since P_PR_LOCK is set.
12920253Sjoerg	 */
13020253Sjoerg	if (uread(p, &instr, 4, pc) != 0)
13120253Sjoerg		return (-1);
13220253Sjoerg
13320253Sjoerg	/*
13420253Sjoerg	 * Decode the instruction to fill in the probe flags. We can have
13562034Sache	 * the process execute most instructions on its own using a pc/npc
13661957Sache	 * trick, but pc-relative control transfer present a problem since
13720253Sjoerg	 * we're relocating the instruction. We emulate these instructions
13820253Sjoerg	 * in the kernel. We assume a default type and over-write that as
13920253Sjoerg	 * needed.
14020253Sjoerg	 *
14144229Sdavidn	 * pc-relative instructions must be emulated for correctness;
14220253Sjoerg	 * other instructions (which represent a large set of commonly traced
14320253Sjoerg	 * instructions) are emulated or otherwise optimized for performance.
14444229Sdavidn	 */
14544229Sdavidn	tp->ftt_type = FASTTRAP_T_COMMON;
14644229Sdavidn	tp->ftt_instr = instr;
14744229Sdavidn
14844229Sdavidn	switch (OP(instr)) {
14944229Sdavidn	/* The following are invalid for trapping (invalid opcodes, tw/twi). */
15044229Sdavidn	case 0:
15144229Sdavidn	case 1:
15244229Sdavidn	case 2:
15344229Sdavidn	case 4:
15444229Sdavidn	case 5:
15544229Sdavidn	case 6:
15644231Sdavidn	case 30:
15744231Sdavidn	case 39:
15844229Sdavidn	case 58:
15961760Sdavidn	case 62:
16020253Sjoerg	case 3:	/* twi */
16161760Sdavidn		return (-1);
16220253Sjoerg	case 31:	/* tw */
16361760Sdavidn		if (OPX(instr) == 4)
16461760Sdavidn			return (-1);
16561760Sdavidn		else if (OPX(instr) == 444 && OP_RS(instr) == OP_RA(instr) &&
16620253Sjoerg		    OP_RS(instr) == OP_RB(instr))
16720253Sjoerg			tp->ftt_type = FASTTRAP_T_NOP;
16861760Sdavidn		break;
16920253Sjoerg	case 16:
17044232Sdavidn		tp->ftt_type = FASTTRAP_T_BC;
17120253Sjoerg		tp->ftt_dest = instr & 0x0000FFFC; /* Extract target address */
17220253Sjoerg		if (instr & 0x00008000)
17330259Scharnier			tp->ftt_dest |= 0xFFFF0000;
17420253Sjoerg		/* Use as offset if not absolute address. */
17520253Sjoerg		if (!(instr & 0x02))
17620253Sjoerg			tp->ftt_dest += pc;
17720253Sjoerg		tp->ftt_bo = OP_BO(instr);
17820253Sjoerg		tp->ftt_bi = OP_BI(instr);
17920253Sjoerg		break;
18020253Sjoerg	case 18:
18120253Sjoerg		tp->ftt_type = FASTTRAP_T_B;
18220253Sjoerg		tp->ftt_dest = instr & 0x03FFFFFC; /* Extract target address */
18320253Sjoerg		if (instr & 0x02000000)
18420253Sjoerg			tp->ftt_dest |= 0xFC000000;
18520253Sjoerg		/* Use as offset if not absolute address. */
18620253Sjoerg		if (!(instr & 0x02))
18720253Sjoerg			tp->ftt_dest += pc;
18820253Sjoerg		break;
18920253Sjoerg	case 19:
19020253Sjoerg		switch (OPX(instr)) {
19120253Sjoerg		case 528:	/* bcctr */
19256000Sdavidn			tp->ftt_type = FASTTRAP_T_BCTR;
19320253Sjoerg			tp->ftt_bo = OP_BO(instr);
19420253Sjoerg			tp->ftt_bi = OP_BI(instr);
19520253Sjoerg			break;
19620253Sjoerg		case 16:	/* bclr */
19720253Sjoerg			tp->ftt_type = FASTTRAP_T_BCTR;
19820253Sjoerg			tp->ftt_bo = OP_BO(instr);
19920267Sjoerg			tp->ftt_bi = OP_BI(instr);
20020267Sjoerg			break;
20127474Sdavidn		};
20230259Scharnier		break;
20320267Sjoerg	case 24:
20420267Sjoerg		if (OP_RS(instr) == OP_RA(instr) &&
20520253Sjoerg		    (instr & 0x0000FFFF) == 0)
20620253Sjoerg			tp->ftt_type = FASTTRAP_T_NOP;
20720253Sjoerg		break;
20820253Sjoerg	};
20969793Sobrien
21020253Sjoerg	/*
21120253Sjoerg	 * We don't know how this tracepoint is going to be used, but in case
21244229Sdavidn	 * it's used as part of a function return probe, we need to indicate
21344229Sdavidn	 * whether it's always a return site or only potentially a return
21444229Sdavidn	 * site. If it's part of a return probe, it's always going to be a
21544229Sdavidn	 * return from that function if it's a restore instruction or if
21644229Sdavidn	 * the previous instruction was a return. If we could reliably
21744229Sdavidn	 * distinguish jump tables from return sites, this wouldn't be
21844229Sdavidn	 * necessary.
21944229Sdavidn	 */
22044229Sdavidn#if 0
22144229Sdavidn	if (tp->ftt_type != FASTTRAP_T_RESTORE &&
22244229Sdavidn	    (uread(p, &instr, 4, pc - sizeof (instr)) != 0 ||
22344229Sdavidn	    !(OP(instr) == 2 && OP3(instr) == OP3_RETURN)))
22444229Sdavidn		tp->ftt_flags |= FASTTRAP_F_RETMAYBE;
22544229Sdavidn#endif
22644229Sdavidn
22744229Sdavidn	return (0);
22844229Sdavidn}
22944229Sdavidn
23044229Sdavidnstatic uint64_t
23120253Sjoergfasttrap_anarg(struct reg *rp, int argno)
23220253Sjoerg{
23344229Sdavidn	uint64_t value;
23438112Snate	proc_t  *p = curproc;
23538110Snate
23621330Sdavidn	/* The first 8 arguments are in registers. */
23721330Sdavidn	if (argno < 8)
23821330Sdavidn		return rp->fixreg[argno + 3];
23921330Sdavidn
24021330Sdavidn	/* Arguments on stack start after SP+LR (2 register slots). */
24121330Sdavidn	if (SV_PROC_FLAG(p, SV_ILP32)) {
24221330Sdavidn		DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
24321330Sdavidn		value = dtrace_fuword32((void *)(rp->fixreg[1] + 8 +
24421330Sdavidn		    ((argno - 8) * sizeof(uint32_t))));
24521330Sdavidn		DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);
24630259Scharnier	} else {
24721330Sdavidn		DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
24830259Scharnier		value = dtrace_fuword64((void *)(rp->fixreg[1] + 16 +
24921330Sdavidn		    ((argno - 8) * sizeof(uint32_t))));
25021330Sdavidn		DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);
25121330Sdavidn	}
25221330Sdavidn	return value;
25321330Sdavidn}
25421330Sdavidn
25521330Sdavidnuint64_t
25621330Sdavidnfasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
25730259Scharnier    int aframes)
25821330Sdavidn{
25921330Sdavidn	struct reg r;
26021330Sdavidn
26121330Sdavidn	fill_regs(curthread, &r);
26221330Sdavidn
26320253Sjoerg	return (fasttrap_anarg(&r, argno));
26420253Sjoerg}
26538112Snate
26620253Sjoerguint64_t
26720253Sjoergfasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
26820253Sjoerg    int aframes)
26920253Sjoerg{
27020253Sjoerg	struct reg r;
27120253Sjoerg
27220253Sjoerg	fill_regs(curthread, &r);
27320253Sjoerg
27420253Sjoerg	return (fasttrap_anarg(&r, argno));
27520253Sjoerg}
27620253Sjoerg
27720253Sjoergstatic void
27820253Sjoergfasttrap_usdt_args(fasttrap_probe_t *probe, struct reg *rp, int argc,
27920253Sjoerg    uintptr_t *argv)
28020253Sjoerg{
28120253Sjoerg	int i, x, cap = MIN(argc, probe->ftp_nargs);
28220253Sjoerg
28320253Sjoerg	for (i = 0; i < cap; i++) {
28420253Sjoerg		x = probe->ftp_argmap[i];
28520253Sjoerg
28620253Sjoerg		if (x < 8)
28720253Sjoerg			argv[i] = rp->fixreg[x];
28820253Sjoerg		else
28952512Sdavidn			if (SV_PROC_FLAG(curproc, SV_ILP32))
29020253Sjoerg				argv[i] = fuword32((void *)(rp->fixreg[1] + 8 +
29152512Sdavidn				    (x * sizeof(uint32_t))));
29220253Sjoerg			else
29320253Sjoerg				argv[i] = fuword32((void *)(rp->fixreg[1] + 16 +
29420253Sjoerg				    (x * sizeof(uint64_t))));
29520253Sjoerg	}
29620253Sjoerg
29720253Sjoerg	for (; i < argc; i++) {
29820253Sjoerg		argv[i] = 0;
29920253Sjoerg	}
30030259Scharnier}
30144229Sdavidn
30220253Sjoergstatic void
30320253Sjoergfasttrap_return_common(struct reg *rp, uintptr_t pc, pid_t pid,
30420253Sjoerg    uintptr_t new_pc)
30520253Sjoerg{
30620253Sjoerg	struct rm_priotracker tracker;
30720253Sjoerg	fasttrap_tracepoint_t *tp;
30820253Sjoerg	fasttrap_bucket_t *bucket;
30920253Sjoerg	fasttrap_id_t *id;
31020253Sjoerg
31120253Sjoerg	rm_rlock(&fasttrap_tp_lock, &tracker);
31220253Sjoerg	bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
31320253Sjoerg
31420253Sjoerg	for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
31520253Sjoerg		if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
31620253Sjoerg		    tp->ftt_proc->ftpc_acount != 0)
31720253Sjoerg			break;
31821330Sdavidn	}
31920267Sjoerg
32020253Sjoerg	/*
32144229Sdavidn	 * Don't sweat it if we can't find the tracepoint again; unlike
32244229Sdavidn	 * when we're in fasttrap_pid_probe(), finding the tracepoint here
32320253Sjoerg	 * is not essential to the correct execution of the process.
32420253Sjoerg	 */
32520253Sjoerg	if (tp == NULL) {
32620253Sjoerg		rm_runlock(&fasttrap_tp_lock, &tracker);
32720253Sjoerg		return;
32820253Sjoerg	}
32920253Sjoerg
33020253Sjoerg	for (id = tp->ftt_retids; id != NULL; id = id->fti_next) {
33120253Sjoerg		/*
33220253Sjoerg		 * If there's a branch that could act as a return site, we
33321330Sdavidn		 * need to trace it, and check here if the program counter is
33421330Sdavidn		 * external to the function.
33530259Scharnier		 */
33644229Sdavidn		/* Skip function-local branches. */
33720253Sjoerg		if ((new_pc - id->fti_probe->ftp_faddr) < id->fti_probe->ftp_fsize)
33820253Sjoerg			continue;
33921330Sdavidn
34020253Sjoerg		dtrace_probe(id->fti_probe->ftp_id,
34130259Scharnier		    pc - id->fti_probe->ftp_faddr,
34244229Sdavidn		    rp->fixreg[3], rp->fixreg[4], 0, 0);
34320253Sjoerg	}
34420253Sjoerg	rm_runlock(&fasttrap_tp_lock, &tracker);
34520253Sjoerg}
34620253Sjoerg
34720253Sjoerg
34820253Sjoergstatic int
34920253Sjoergfasttrap_branch_taken(int bo, int bi, struct reg *regs)
35020253Sjoerg{
35120253Sjoerg	int crzero = 0;
35220253Sjoerg
35320253Sjoerg	/* Branch always? */
35420253Sjoerg	if ((bo & 0x14) == 0x14)
35520253Sjoerg		return 1;
35620253Sjoerg
35720253Sjoerg	/* Handle decrementing ctr */
35820267Sjoerg	if (!(bo & 0x04)) {
35920267Sjoerg		--regs->ctr;
36021330Sdavidn		crzero = (regs->ctr == 0);
36120267Sjoerg		if (bo & 0x10) {
36230259Scharnier			return (!(crzero ^ (bo >> 1)));
36344229Sdavidn		}
36420253Sjoerg	}
36520253Sjoerg
36620253Sjoerg	return (crzero | (((regs->cr >> (31 - bi)) ^ (bo >> 3)) ^ 1));
36720267Sjoerg}
36844386Sdavidn
36944386Sdavidn
37030259Scharnierint
37144229Sdavidnfasttrap_pid_probe(struct reg *rp)
37220267Sjoerg{
37374226Sdd	struct rm_priotracker tracker;
37474226Sdd	proc_t *p = curproc;
37574226Sdd	uintptr_t pc = rp->pc;
37674226Sdd	uintptr_t new_pc = 0;
37774226Sdd	fasttrap_bucket_t *bucket;
37874226Sdd	fasttrap_tracepoint_t *tp, tp_local;
37974226Sdd	pid_t pid;
38074226Sdd	dtrace_icookie_t cookie;
38174226Sdd	uint_t is_enabled = 0;
38220253Sjoerg
38320253Sjoerg	/*
38430259Scharnier	 * It's possible that a user (in a veritable orgy of bad planning)
38544229Sdavidn	 * could redirect this thread's flow of control before it reached the
38620253Sjoerg	 * return probe fasttrap. In this case we need to kill the process
38720253Sjoerg	 * since it's in a unrecoverable state.
38820253Sjoerg	 */
38920253Sjoerg	if (curthread->t_dtrace_step) {
39020267Sjoerg		ASSERT(curthread->t_dtrace_on);
39120267Sjoerg		fasttrap_sigtrap(p, curthread, pc);
39221330Sdavidn		return (0);
39320267Sjoerg	}
39430259Scharnier
39544229Sdavidn	/*
39620253Sjoerg	 * Clear all user tracing flags.
39721330Sdavidn	 */
39821330Sdavidn	curthread->t_dtrace_ft = 0;
39930259Scharnier	curthread->t_dtrace_pc = 0;
40044229Sdavidn	curthread->t_dtrace_npc = 0;
40120253Sjoerg	curthread->t_dtrace_scrpc = 0;
40220253Sjoerg	curthread->t_dtrace_astpc = 0;
40320253Sjoerg
40420253Sjoerg	rm_rlock(&fasttrap_tp_lock, &tracker);
40520253Sjoerg	pid = p->p_pid;
40620267Sjoerg	bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
40720267Sjoerg
40820267Sjoerg	/*
40921330Sdavidn	 * Lookup the tracepoint that the process just hit.
41020267Sjoerg	 */
41130259Scharnier	for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
41244229Sdavidn		if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
41320253Sjoerg		    tp->ftt_proc->ftpc_acount != 0)
41420253Sjoerg			break;
41520253Sjoerg	}
41620267Sjoerg
41720267Sjoerg	/*
41830259Scharnier	 * If we couldn't find a matching tracepoint, either a tracepoint has
41944229Sdavidn	 * been inserted without using the pid<pid> ioctl interface (see
42020267Sjoerg	 * fasttrap_ioctl), or somehow we have mislaid this tracepoint.
42174226Sdd	 */
42220253Sjoerg	if (tp == NULL) {
42320253Sjoerg		rm_runlock(&fasttrap_tp_lock, &tracker);
42420253Sjoerg		return (-1);
42579292Skris	}
42620253Sjoerg
42720267Sjoerg	if (tp->ftt_ids != NULL) {
42820253Sjoerg		fasttrap_id_t *id;
42920253Sjoerg
43020253Sjoerg		for (id = tp->ftt_ids; id != NULL; id = id->fti_next) {
43120253Sjoerg			fasttrap_probe_t *probe = id->fti_probe;
43220253Sjoerg
43370486Sben			if (id->fti_ptype == DTFTP_ENTRY) {
43420253Sjoerg				/*
43520253Sjoerg				 * We note that this was an entry
43670486Sben				 * probe to help ustack() find the
43720253Sjoerg				 * first caller.
43820253Sjoerg				 */
43920253Sjoerg				cookie = dtrace_interrupt_disable();
44020253Sjoerg				DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY);
44120253Sjoerg				dtrace_probe(probe->ftp_id, rp->fixreg[3],
44220253Sjoerg						rp->fixreg[4], rp->fixreg[5], rp->fixreg[6],
44320253Sjoerg						rp->fixreg[7]);
44420253Sjoerg				DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY);
44520253Sjoerg				dtrace_interrupt_enable(cookie);
44630259Scharnier			} else if (id->fti_ptype == DTFTP_IS_ENABLED) {
44720253Sjoerg				/*
44820253Sjoerg				 * Note that in this case, we don't
44920253Sjoerg				 * call dtrace_probe() since it's only
45020253Sjoerg				 * an artificial probe meant to change
45120253Sjoerg				 * the flow of control so that it
452				 * encounters the true probe.
453				 */
454				is_enabled = 1;
455			} else if (probe->ftp_argmap == NULL) {
456				dtrace_probe(probe->ftp_id, rp->fixreg[3],
457				    rp->fixreg[4], rp->fixreg[5], rp->fixreg[6],
458				    rp->fixreg[7]);
459			} else {
460				uintptr_t t[5];
461
462				fasttrap_usdt_args(probe, rp,
463				    sizeof (t) / sizeof (t[0]), t);
464
465				dtrace_probe(probe->ftp_id, t[0], t[1],
466				    t[2], t[3], t[4]);
467			}
468		}
469	}
470
471	/*
472	 * We're about to do a bunch of work so we cache a local copy of
473	 * the tracepoint to emulate the instruction, and then find the
474	 * tracepoint again later if we need to light up any return probes.
475	 */
476	tp_local = *tp;
477	rm_runlock(&fasttrap_tp_lock, &tracker);
478	tp = &tp_local;
479
480	/*
481	 * If there's an is-enabled probe connected to this tracepoint it
482	 * means that there was a 'xor r3, r3, r3'
483	 * instruction that was placed there by DTrace when the binary was
484	 * linked. As this probe is, in fact, enabled, we need to stuff 1
485	 * into R3. Accordingly, we can bypass all the instruction
486	 * emulation logic since we know the inevitable result. It's possible
487	 * that a user could construct a scenario where the 'is-enabled'
488	 * probe was on some other instruction, but that would be a rather
489	 * exotic way to shoot oneself in the foot.
490	 */
491	if (is_enabled) {
492		rp->fixreg[3] = 1;
493		new_pc = rp->pc + 4;
494		goto done;
495	}
496
497
498	switch (tp->ftt_type) {
499	case FASTTRAP_T_NOP:
500		new_pc = rp->pc + 4;
501		break;
502	case FASTTRAP_T_BC:
503		if (!fasttrap_branch_taken(tp->ftt_bo, tp->ftt_bi, rp))
504			break;
505		/* FALLTHROUGH */
506	case FASTTRAP_T_B:
507		if (tp->ftt_instr & 0x01)
508			rp->lr = rp->pc + 4;
509		new_pc = tp->ftt_dest;
510		break;
511	case FASTTRAP_T_BLR:
512	case FASTTRAP_T_BCTR:
513		if (!fasttrap_branch_taken(tp->ftt_bo, tp->ftt_bi, rp))
514			break;
515		/* FALLTHROUGH */
516		if (tp->ftt_type == FASTTRAP_T_BCTR)
517			new_pc = rp->ctr;
518		else
519			new_pc = rp->lr;
520		if (tp->ftt_instr & 0x01)
521			rp->lr = rp->pc + 4;
522		break;
523	case FASTTRAP_T_COMMON:
524		break;
525	};
526done:
527	/*
528	 * If there were no return probes when we first found the tracepoint,
529	 * we should feel no obligation to honor any return probes that were
530	 * subsequently enabled -- they'll just have to wait until the next
531	 * time around.
532	 */
533	if (tp->ftt_retids != NULL) {
534		/*
535		 * We need to wait until the results of the instruction are
536		 * apparent before invoking any return probes. If this
537		 * instruction was emulated we can just call
538		 * fasttrap_return_common(); if it needs to be executed, we
539		 * need to wait until the user thread returns to the kernel.
540		 */
541		if (tp->ftt_type != FASTTRAP_T_COMMON) {
542			fasttrap_return_common(rp, pc, pid, new_pc);
543		} else {
544			ASSERT(curthread->t_dtrace_ret != 0);
545			ASSERT(curthread->t_dtrace_pc == pc);
546			ASSERT(curthread->t_dtrace_scrpc != 0);
547			ASSERT(new_pc == curthread->t_dtrace_astpc);
548		}
549	}
550
551	rp->pc = new_pc;
552	set_regs(curthread, rp);
553
554	return (0);
555}
556
557int
558fasttrap_return_probe(struct reg *rp)
559{
560	proc_t *p = curproc;
561	uintptr_t pc = curthread->t_dtrace_pc;
562	uintptr_t npc = curthread->t_dtrace_npc;
563
564	curthread->t_dtrace_pc = 0;
565	curthread->t_dtrace_npc = 0;
566	curthread->t_dtrace_scrpc = 0;
567	curthread->t_dtrace_astpc = 0;
568
569	/*
570	 * We set rp->pc to the address of the traced instruction so
571	 * that it appears to dtrace_probe() that we're on the original
572	 * instruction, and so that the user can't easily detect our
573	 * complex web of lies. dtrace_return_probe() (our caller)
574	 * will correctly set %pc after we return.
575	 */
576	rp->pc = pc;
577
578	fasttrap_return_common(rp, pc, p->p_pid, npc);
579
580	return (0);
581}
582
583