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