]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/dev/i386/fasttrap_isa.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / dev / i386 / fasttrap_isa.c
index 478429efc051e99ffe90545a64cc034a4a1ca8f0..3577b3109143e5271e833dfe2c3ff823aa9fbfe4 100644 (file)
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-/*
- * #pragma ident       "@(#)fasttrap_isa.c     1.23    06/09/19 SMI"
- */
-
-#ifdef KERNEL
-#ifndef _KERNEL
-#define _KERNEL /* Solaris vs. Darwin */
-#endif
-#endif
-
 #include <sys/fasttrap_isa.h>
 #include <sys/fasttrap_impl.h>
 #include <sys/dtrace.h>
 #include <sys/dtrace_impl.h>
+extern dtrace_id_t dtrace_probeid_error;
 
 #include "fasttrap_regset.h"
 
 #include <sys/dtrace_ptss.h>
 #include <kern/debug.h>
 
-#define proc_t struct proc
+#include <machine/pal_routines.h>
+
+/* Solaris proc_t is the struct. Darwin's proc_t is a pointer to it. */
+#define proc_t struct proc /* Steer clear of the Darwin typedef for proc_t */
 
 /*
  * Lossless User-Land Tracing on x86
  *
  * REG_RAX -> EAX
  * REG_RCX -> ECX
- * ...
+ * REG_RDX -> EDX
+ * REG_RBX -> EBX
+ * REG_RSP -> UESP
+ * REG_RBP -> EBP
+ * REG_RSI -> ESI
  * REG_RDI -> EDI
  *
  * The fasttrap_getreg function knows how to make the correct transformation.
  */
-#if __sol64 || defined(__APPLE__)
 static const uint8_t regmap[16] = {
        REG_RAX, REG_RCX, REG_RDX, REG_RBX, REG_RSP, REG_RBP, REG_RSI, REG_RDI,
        REG_R8, REG_R9, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15,
 };
-#else
-static const uint8_t regmap[8] = {
-       EAX, ECX, EDX, EBX, UESP, EBP, ESI, EDI
-};
-#endif
 
 static user_addr_t fasttrap_getreg(x86_saved_state_t *, uint_t);
 
@@ -233,7 +225,7 @@ fasttrap_anarg(x86_saved_state_t *regs, int function_entry, int argno)
 
        if (p_model == DATAMODEL_LP64) {
                user_addr_t stack;
-               
+
                /*
                 * In 64-bit mode, the first six arguments are stored in
                 * registers.
@@ -246,7 +238,7 @@ fasttrap_anarg(x86_saved_state_t *regs, int function_entry, int argno)
                value = dtrace_fuword64(stack);
                DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);
        } else {
-               uint32_t *stack = (uint32_t *)regs32->uesp;
+               uint32_t *stack = (uint32_t *)(uintptr_t)(regs32->uesp);
                DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
                value = dtrace_fuword32((user_addr_t)(unsigned long)&stack[argno + shift]);
                DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);
@@ -321,22 +313,22 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc,
                switch (instr[start]) {
                case FASTTRAP_PREFIX_SS:
                        seg++;
-                       /*FALLTHRU*/
+                       OS_FALLTHROUGH;
                case FASTTRAP_PREFIX_GS:
                        seg++;
-                       /*FALLTHRU*/
+                       OS_FALLTHROUGH;
                case FASTTRAP_PREFIX_FS:
                        seg++;
-                       /*FALLTHRU*/
+                       OS_FALLTHROUGH;
                case FASTTRAP_PREFIX_ES:
                        seg++;
-                       /*FALLTHRU*/
+                       OS_FALLTHROUGH;
                case FASTTRAP_PREFIX_DS:
                        seg++;
-                       /*FALLTHRU*/
+                       OS_FALLTHROUGH;
                case FASTTRAP_PREFIX_CS:
                        seg++;
-                       /*FALLTHRU*/
+                       OS_FALLTHROUGH;
                case FASTTRAP_PREFIX_OPERAND:
                case FASTTRAP_PREFIX_ADDRESS:
                case FASTTRAP_PREFIX_LOCK:
@@ -359,13 +351,11 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc,
                break;
        }
 
-#if __sol64 || defined(__APPLE__)
        /*
         * Identify the REX prefix on 64-bit processes.
         */
        if (p_model == DATAMODEL_LP64 && (instr[start] & 0xf0) == 0x40)
                rex = instr[start++];
-#endif
 
        /*
         * Now that we're pretty sure that the instruction is okay, copy the
@@ -395,6 +385,7 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc,
                        tp->ftt_type = FASTTRAP_T_JCC;
                        tp->ftt_code = (instr[start + 1] & 0x0f) | FASTTRAP_JO;
                        tp->ftt_dest = pc + tp->ftt_size +
+                           /* LINTED - alignment */
                            *(int32_t *)&instr[start + 2];
                        break;
                }
@@ -447,11 +438,9 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc,
                                 * modes, there is a 32-bit operand.
                                 */
                                if (mod == 0 && rm == 5) {
-#if __sol64 || defined(__APPLE__)
                                        if (p_model == DATAMODEL_LP64)
                                                tp->ftt_base = REG_RIP;
                                        else
-#endif
                                                tp->ftt_base = FASTTRAP_NOREG;
                                        sz = 4;
                                } else  {
@@ -465,12 +454,14 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc,
                                i = 2;
                        }
 
-                       if (sz == 1)
+                       if (sz == 1) {
                                tp->ftt_dest = *(int8_t *)&instr[start + i];
-                       else if (sz == 4)
+                       } else if (sz == 4) {
+                               /* LINTED - alignment */
                                tp->ftt_dest = *(int32_t *)&instr[start + i];
-                       else
+                       } else {
                                tp->ftt_dest = 0;
+                       }
                }
        } else {
                switch (instr[start]) {
@@ -480,6 +471,7 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc,
 
                case FASTTRAP_RET16:
                        tp->ftt_type = FASTTRAP_T_RET16;
+                       /* LINTED - alignment */
                        tp->ftt_dest = *(uint16_t *)&instr[start + 1];
                        break;
 
@@ -523,6 +515,7 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc,
                case FASTTRAP_CALL:
                        tp->ftt_type = FASTTRAP_T_CALL;
                        tp->ftt_dest = pc + tp->ftt_size +
+                           /* LINTED - alignment */
                            *(int32_t *)&instr[start + 1];
                        tp->ftt_code = 0;
                        break;
@@ -530,6 +523,7 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc,
                case FASTTRAP_JMP32:
                        tp->ftt_type = FASTTRAP_T_JMP;
                        tp->ftt_dest = pc + tp->ftt_size +
+                               /* LINTED - alignment */
                            *(int32_t *)&instr[start + 1];
                        break;
                case FASTTRAP_JMP8:
@@ -544,7 +538,6 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc,
                        break;
 
                case FASTTRAP_NOP:
-#if __sol64 || defined(__APPLE__)
                        ASSERT(p_model == DATAMODEL_LP64 || rex == 0);
 
                        /*
@@ -554,7 +547,6 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc,
                         * (e.g. xchgl %r8d, %eax or xcghq %r8, %rax).
                         */
                        if (FASTTRAP_REX_B(rex) == 0)
-#endif
                                tp->ftt_type = FASTTRAP_T_NOP;
                        break;
 
@@ -581,7 +573,6 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc,
                }
        }
 
-#if __sol64 || defined(__APPLE__)
        if (p_model == DATAMODEL_LP64 && tp->ftt_type == FASTTRAP_T_COMMON) {
                /*
                 * If the process is 64-bit and the instruction type is still
@@ -627,7 +618,6 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc,
                        }
                }
        }
-#endif
 
        return (0);
 }
@@ -640,6 +630,8 @@ fasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp)
        if (uwrite(p, &instr, 1, tp->ftt_pc) != 0)
                return (-1);
 
+       tp->ftt_installed = 1;
+
        return (0);
 }
 
@@ -653,11 +645,13 @@ fasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp)
         * instruction.
         */
        if (uread(p, &instr, 1, tp->ftt_pc) != 0)
-               return (0);
+               goto end;
        if (instr != FASTTRAP_INSTR)
-               return (0);
+               goto end;
        if (uwrite(p, &tp->ftt_instr[0], 1, tp->ftt_pc) != 0)
                return (-1);
+end:
+       tp->ftt_installed = 0;
 
        return (0);
 }
@@ -669,6 +663,9 @@ fasttrap_return_common(x86_saved_state_t *regs, user_addr_t pc, pid_t pid,
        x86_saved_state64_t *regs64;
        x86_saved_state32_t *regs32;
        unsigned int p_model;
+       int retire_tp = 1;
+
+       dtrace_icookie_t cookie;
 
         if (is_saved_state64(regs)) {
                 regs64 = saved_state64(regs);
@@ -691,7 +688,7 @@ fasttrap_return_common(x86_saved_state_t *regs, user_addr_t pc, pid_t pid,
 
        for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
                if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
-                   !tp->ftt_proc->ftpc_defunct)
+                   tp->ftt_proc->ftpc_acount != 0)
                        break;
        }
 
@@ -706,6 +703,7 @@ fasttrap_return_common(x86_saved_state_t *regs, user_addr_t pc, pid_t pid,
        }
 
        for (id = tp->ftt_retids; id != NULL; id = id->fti_next) {
+               fasttrap_probe_t *probe = id->fti_probe;
                /*
                 * If there's a branch that could act as a return site, we
                 * need to trace it, and check here if the program counter is
@@ -713,19 +711,45 @@ fasttrap_return_common(x86_saved_state_t *regs, user_addr_t pc, pid_t pid,
                 */
                if (tp->ftt_type != FASTTRAP_T_RET &&
                    tp->ftt_type != FASTTRAP_T_RET16 &&
-                   new_pc - id->fti_probe->ftp_faddr <
-                   id->fti_probe->ftp_fsize)
+                   new_pc - probe->ftp_faddr < probe->ftp_fsize)
                        continue;
 
-               if (p_model == DATAMODEL_LP64) {
-                       dtrace_probe(id->fti_probe->ftp_id,
+               if (probe->ftp_prov->ftp_provider_type == DTFTP_PROVIDER_ONESHOT) {
+                       if (os_atomic_xchg(&probe->ftp_triggered, 1, relaxed)) {
+                               /* already triggered */
+                               continue;
+                       }
+               }
+               /*
+                * If we have at least one probe associated that
+                * is not a oneshot probe, don't remove the
+                * tracepoint
+                */
+               else {
+                       retire_tp = 0;
+               }
+               /*
+                * Provide a hint to the stack trace functions to add the
+                * following pc to the top of the stack since it's missing
+                * on a return probe yet highly desirable for consistency.
+                */
+               cookie = dtrace_interrupt_disable();
+               cpu_core[CPU->cpu_id].cpuc_missing_tos = pc;
+               if (ISSET(current_proc()->p_lflag, P_LNOATTACH)) {
+                       dtrace_probe(dtrace_probeid_error, 0 /* state */, probe->ftp_id,
+                                    1 /* ndx */, -1 /* offset */, DTRACEFLT_UPRIV);
+               } else if (p_model == DATAMODEL_LP64) {
+                       dtrace_probe(probe->ftp_id,
                                     pc - id->fti_probe->ftp_faddr,
                                     regs64->rax, regs64->rdx, 0, 0);
                } else {
-                       dtrace_probe(id->fti_probe->ftp_id,
+                       dtrace_probe(probe->ftp_id,
                                     pc - id->fti_probe->ftp_faddr,
                                     regs32->eax, regs32->edx, 0, 0);
                }
+               /* remove the hint */
+               cpu_core[CPU->cpu_id].cpuc_missing_tos = 0;
+               dtrace_interrupt_enable(cookie);
        }
 
        lck_mtx_unlock(pid_mtx);
@@ -733,14 +757,14 @@ fasttrap_return_common(x86_saved_state_t *regs, user_addr_t pc, pid_t pid,
 
 static void
 fasttrap_sigsegv(proc_t *p, uthread_t t, user_addr_t addr)
-{      
+{
        proc_lock(p);
 
        /* Set fault address and mark signal */
        t->uu_code = addr;
        t->uu_siglist |= sigmask(SIGSEGV);
 
-       /* 
+       /*
          * XXX These two line may be redundant; if not, then we need
         * XXX to potentially set the data address in the machine
         * XXX specific thread state structure to indicate the address.
@@ -782,7 +806,7 @@ fasttrap_usdt_args32(fasttrap_probe_t *probe, x86_saved_state32_t *regs32, int a
     uint32_t *argv)
 {
        int i, x, cap = MIN(argc, probe->ftp_nargs);
-       uint32_t *stack = (uint32_t *)regs32->uesp;
+       uint32_t *stack = (uint32_t *)(uintptr_t)(regs32->uesp);
 
        for (i = 0; i < cap; i++) {
                x = probe->ftp_argmap[i];
@@ -938,7 +962,7 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
        fasttrap_tracepoint_t *tp, tp_local;
        pid_t pid;
        dtrace_icookie_t cookie;
-       uint_t is_enabled = 0;
+       uint_t is_enabled = 0, retire_tp = 1;
 
        uthread_t uthread = (uthread_t)get_bsdthread_info(current_thread());
 
@@ -968,12 +992,12 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
         * parent. We know that there's only one thread of control in such a
         * process: this one.
         */
-       /*
-        * APPLE NOTE: Terry says: "You need to hold the process locks (currently: kernel funnel) for this traversal"
-        * FIXME: How do we assert this?
-        */
-       while (p->p_lflag & P_LINVFORK)
-               p = p->p_pptr;
+       if (p->p_lflag & P_LINVFORK) {
+               proc_list_lock();
+               while (p->p_lflag & P_LINVFORK)
+                       p = p->p_pptr;
+               proc_list_unlock();
+       }
 
        pid = p->p_pid;
        pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock;
@@ -985,7 +1009,7 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
         */
        for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
                if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
-                   !tp->ftt_proc->ftpc_defunct)
+                   tp->ftt_proc->ftpc_acount != 0)
                        break;
        }
 
@@ -1007,10 +1031,10 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
 
        if (tp->ftt_ids != NULL) {
                fasttrap_id_t *id;
-               
+
                uint32_t s0, s1, s2, s3, s4, s5;
-               uint32_t *stack = (uint32_t *)regs32->uesp;
-               
+               uint32_t *stack = (uint32_t *)(uintptr_t)(regs32->uesp);
+
                /*
                 * In 32-bit mode, all arguments are passed on the
                 * stack. If this is a function entry probe, we need
@@ -1024,49 +1048,66 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                fasttrap_fuword32_noerr((user_addr_t)(unsigned long)&stack[3], &s3);
                fasttrap_fuword32_noerr((user_addr_t)(unsigned long)&stack[4], &s4);
                fasttrap_fuword32_noerr((user_addr_t)(unsigned long)&stack[5], &s5);
-               
+
                for (id = tp->ftt_ids; id != NULL; id = id->fti_next) {
                        fasttrap_probe_t *probe = id->fti_probe;
-                       
-                       if (id->fti_ptype == DTFTP_ENTRY) {
-                               /*
-                                * We note that this was an entry
-                                * probe to help ustack() find the
-                                * first caller.
-                                */
-                               cookie = dtrace_interrupt_disable();
-                               DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY);
-                               dtrace_probe(probe->ftp_id, s1, s2,
-                                            s3, s4, s5);
-                               DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY);
-                               dtrace_interrupt_enable(cookie);
-                       } else if (id->fti_ptype == DTFTP_IS_ENABLED) {
+
+                       if (ISSET(current_proc()->p_lflag, P_LNOATTACH)) {
+                               dtrace_probe(dtrace_probeid_error, 0 /* state */, probe->ftp_id,
+                                            1 /* ndx */, -1 /* offset */, DTRACEFLT_UPRIV);
+                       } else {
+                               if (probe->ftp_prov->ftp_provider_type == DTFTP_PROVIDER_ONESHOT) {
+                                       if (os_atomic_xchg(&probe->ftp_triggered, 1, relaxed)) {
+                                               /* already triggered */
+                                               continue;
+                                       }
+                               }
                                /*
-                                * Note that in this case, we don't
-                                * call dtrace_probe() since it's only
-                                * an artificial probe meant to change
-                                * the flow of control so that it
-                                * encounters the true probe.
+                                * If we have at least one probe associated that
+                                * is not a oneshot probe, don't remove the
+                                * tracepoint
                                 */
-                               is_enabled = 1;
-                       } else if (probe->ftp_argmap == NULL) {
-                               dtrace_probe(probe->ftp_id, s0, s1,
-                                            s2, s3, s4);
-                       } else {
-                               uint32_t t[5];
-                               
-                               fasttrap_usdt_args32(probe, regs32,
-                                                    sizeof (t) / sizeof (t[0]), t);
-                               
-                               dtrace_probe(probe->ftp_id, t[0], t[1],
-                                            t[2], t[3], t[4]);
-                       }
+                               else {
+                                       retire_tp = 0;
+                               }
+                               if (id->fti_ptype == DTFTP_ENTRY) {
+                                       /*
+                                        * We note that this was an entry
+                                        * probe to help ustack() find the
+                                        * first caller.
+                                        */
+                                       cookie = dtrace_interrupt_disable();
+                                       DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY);
+                                       dtrace_probe(probe->ftp_id, s1, s2,
+                                                    s3, s4, s5);
+                                       DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY);
+                                       dtrace_interrupt_enable(cookie);
+                               } else if (id->fti_ptype == DTFTP_IS_ENABLED) {
+                                       /*
+                                        * Note that in this case, we don't
+                                        * call dtrace_probe() since it's only
+                                        * an artificial probe meant to change
+                                        * the flow of control so that it
+                                        * encounters the true probe.
+                                        */
+                                       is_enabled = 1;
+                               } else if (probe->ftp_argmap == NULL) {
+                                       dtrace_probe(probe->ftp_id, s0, s1,
+                                                    s2, s3, s4);
+                               } else {
+                                       uint32_t t[5];
 
-                       /* APPLE NOTE: Oneshot probes get one and only one chance... */
-                       if (probe->ftp_prov->ftp_provider_type == DTFTP_PROVIDER_ONESHOT) {
-                               fasttrap_tracepoint_remove(p, tp);
+                                       fasttrap_usdt_args32(probe, regs32,
+                                                            sizeof (t) / sizeof (t[0]), t);
+
+                                       dtrace_probe(probe->ftp_id, t[0], t[1],
+                                                    t[2], t[3], t[4]);
+                               }
                        }
                }
+               if (retire_tp) {
+                       fasttrap_tracepoint_retire(p, tp);
+               }
        }
 
        /*
@@ -1131,10 +1172,10 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                                new_pc = pc;
                                break;
                        }
-                       
+
                        if (tp->ftt_type == FASTTRAP_T_RET16)
                                addr += tp->ftt_dest;
-                       
+
                        regs32->uesp = addr;
                        new_pc = dst;
                        break;
@@ -1143,7 +1184,7 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                case FASTTRAP_T_JCC:
                {
                        uint_t taken;
-                       
+
                        switch (tp->ftt_code) {
                                case FASTTRAP_JO:
                                        taken = (regs32->efl & FASTTRAP_EFLAGS_OF) != 0;
@@ -1204,7 +1245,7 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                                default:
                                        taken = FALSE;
                        }
-                       
+
                        if (taken)
                                new_pc = tp->ftt_dest;
                        else
@@ -1232,7 +1273,7 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                                default:
                                        taken = FALSE;
                        }
-                       
+
                        if (taken)
                                new_pc = tp->ftt_dest;
                        else
@@ -1243,7 +1284,7 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                case FASTTRAP_T_JCXZ:
                {
                        greg_t cx = regs32->ecx;
-                       
+
                        if (cx == 0)
                                new_pc = tp->ftt_dest;
                        else
@@ -1255,18 +1296,18 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                {
                        user_addr_t addr = regs32->uesp - sizeof (uint32_t);
                        int ret = fasttrap_suword32(addr, (uint32_t)regs32->ebp);
-                       
+
                        if (ret == -1) {
                                fasttrap_sigsegv(p, uthread, addr);
                                new_pc = pc;
                                break;
                        }
-                       
+
                        regs32->uesp = addr;
                        new_pc = pc + tp->ftt_size;
                        break;
                }
-               
+
                case FASTTRAP_T_NOP:
                        new_pc = pc + tp->ftt_size;
                        break;
@@ -1283,7 +1324,7 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                                if (tp->ftt_index != FASTTRAP_NOREG)
                                        addr += fasttrap_getreg(regs, tp->ftt_index) <<
                                                tp->ftt_scale;
-                               
+
                                if (tp->ftt_code == 1) {
                                        /*
                                         * If there's a segment prefix for this
@@ -1297,7 +1338,7 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                                                new_pc = pc;
                                                break;
                                        }
-                                       
+
                                        uint32_t value32;
                                        addr = (user_addr_t)(uint32_t)addr;
                                        if (fasttrap_fuword32(addr, &value32) == -1) {
@@ -1320,21 +1361,21 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                        if (tp->ftt_type == FASTTRAP_T_CALL) {
                                user_addr_t addr = regs32->uesp - sizeof (uint32_t);
                                int ret = fasttrap_suword32(addr, (uint32_t)(pc + tp->ftt_size));
-                               
+
                                if (ret == -1) {
                                        fasttrap_sigsegv(p, uthread, addr);
                                        new_pc = pc;
                                        break;
                                }
-                               
+
                                regs32->uesp = addr;
                        }
                        break;
 
                case FASTTRAP_T_COMMON:
                {
-                       user_addr_t addr;
-                       uint8_t scratch[2 * FASTTRAP_MAX_INSTR_SIZE + 5 + 2];
+                       user_addr_t addr, write_addr;
+                       uint8_t scratch[2 * FASTTRAP_MAX_INSTR_SIZE + 7];
                        uint_t i = 0;
 
                        /*
@@ -1377,8 +1418,9 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                         */
 
                        addr = uthread->t_dtrace_scratch->addr;
+                       write_addr = uthread->t_dtrace_scratch->write_addr;
 
-                       if (addr == 0LL) {
+                       if (addr == 0LL || write_addr == 0LL) {
                                fasttrap_sigtrap(p, uthread, pc); // Should be killing target proc
                                new_pc = pc;
                                break;
@@ -1395,6 +1437,7 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                         * the size of the traced instruction cancels out.
                         */
                        scratch[i++] = FASTTRAP_JMP32;
+                       /* LINTED - alignment */
                        *(uint32_t *)&scratch[i] = pc - addr - 5;
                        i += sizeof (uint32_t);
 
@@ -1403,13 +1446,15 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                        i += tp->ftt_size;
                        scratch[i++] = FASTTRAP_INT;
                        scratch[i++] = T_DTRACE_RET;
-                       
-                       if (fasttrap_copyout(scratch, addr, i)) {
+
+                       ASSERT(i <= sizeof (scratch));
+
+                       if (fasttrap_copyout(scratch, write_addr, i)) {
                                fasttrap_sigtrap(p, uthread, pc);
                                new_pc = pc;
                                break;
                        }
-                       
+
                        if (tp->ftt_retids != NULL) {
                                uthread->t_dtrace_step = 1;
                                uthread->t_dtrace_ret = 1;
@@ -1417,17 +1462,17 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                        } else {
                                new_pc = uthread->t_dtrace_scrpc;
                        }
-                       
+
                        uthread->t_dtrace_pc = pc;
                        uthread->t_dtrace_npc = pc + tp->ftt_size;
                        uthread->t_dtrace_on = 1;
                        break;
                }
-               
+
                default:
                        panic("fasttrap: mishandled an instruction");
        }
-       
+
 done:
        /*
         * APPLE NOTE:
@@ -1491,6 +1536,7 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
        pid_t pid;
        dtrace_icookie_t cookie;
        uint_t is_enabled = 0;
+       int retire_tp = 1;
 
        uthread_t uthread = (uthread_t)get_bsdthread_info(current_thread());
 
@@ -1521,12 +1567,12 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
         * parent. We know that there's only one thread of control in such a
         * process: this one.
         */
-       /*
-        * APPLE NOTE: Terry says: "You need to hold the process locks (currently: kernel funnel) for this traversal"
-        * FIXME: How do we assert this?
-        */
-       while (p->p_lflag & P_LINVFORK)
-               p = p->p_pptr;
+       if (p->p_lflag & P_LINVFORK) {
+               proc_list_lock();
+               while (p->p_lflag & P_LINVFORK)
+                       p = p->p_pptr;
+               proc_list_unlock();
+       }
 
        pid = p->p_pid;
        pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock;
@@ -1538,7 +1584,7 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
         */
        for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
                if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
-                   !tp->ftt_proc->ftpc_defunct)
+                   tp->ftt_proc->ftpc_acount != 0)
                        break;
        }
 
@@ -1563,8 +1609,25 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
 
                for (id = tp->ftt_ids; id != NULL; id = id->fti_next) {
                        fasttrap_probe_t *probe = id->fti_probe;
-                       
-                       if (id->fti_ptype == DTFTP_ENTRY) {
+
+                       if (probe->ftp_prov->ftp_provider_type == DTFTP_PROVIDER_ONESHOT) {
+                               if (os_atomic_xchg(&probe->ftp_triggered, 1, relaxed)) {
+                                       /* already triggered */
+                                       continue;
+                               }
+                       }
+                       /*
+                        * If we have at least probe associated that
+                        * is not a oneshot probe, don't remove the
+                        * tracepoint
+                        */
+                       else {
+                               retire_tp = 0;
+                       }
+                       if (ISSET(current_proc()->p_lflag, P_LNOATTACH)) {
+                               dtrace_probe(dtrace_probeid_error, 0 /* state */, probe->ftp_id,
+                                            1 /* ndx */, -1 /* offset */, DTRACEFLT_UPRIV);
+                       } else if (id->fti_ptype == DTFTP_ENTRY) {
                                /*
                                 * We note that this was an entry
                                 * probe to help ustack() find the
@@ -1592,18 +1655,17 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                                             regs64->r8);
                        } else {
                                uint64_t t[5];
-                               
+
                                fasttrap_usdt_args64(probe, regs64,
                                                     sizeof (t) / sizeof (t[0]), t);
-                               
+
                                dtrace_probe(probe->ftp_id, t[0], t[1],
                                             t[2], t[3], t[4]);
                        }
 
-                       /* APPLE NOTE: Oneshot probes get one and only one chance... */
-                       if (probe->ftp_prov->ftp_provider_type == DTFTP_PROVIDER_ONESHOT) {
-                               fasttrap_tracepoint_remove(p, tp);
-                       }
+               }
+               if (retire_tp) {
+                       fasttrap_tracepoint_retire(p, tp);
                }
        }
 
@@ -1653,7 +1715,7 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                        user_addr_t dst;
                        user_addr_t addr;
                        int ret;
-                       
+
                        /*
                         * We have to emulate _every_ facet of the behavior of a ret
                         * instruction including what happens if the load from %esp
@@ -1661,25 +1723,25 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                         */
                        ret = fasttrap_fuword64((user_addr_t)regs64->isf.rsp, &dst);
                        addr = regs64->isf.rsp + sizeof (uint64_t);
-                       
+
                        if (ret == -1) {
                                fasttrap_sigsegv(p, uthread, (user_addr_t)regs64->isf.rsp);
                                new_pc = pc;
                                break;
                        }
-                       
+
                        if (tp->ftt_type == FASTTRAP_T_RET16)
                                addr += tp->ftt_dest;
-                       
+
                        regs64->isf.rsp = addr;
                        new_pc = dst;
                        break;
                }
-               
+
                case FASTTRAP_T_JCC:
                {
                        uint_t taken;
-                       
+
                        switch (tp->ftt_code) {
                                case FASTTRAP_JO:
                                        taken = (regs64->isf.rflags & FASTTRAP_EFLAGS_OF) != 0;
@@ -1740,7 +1802,7 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                                default:
                                        taken = FALSE;
                        }
-                       
+
                        if (taken)
                                new_pc = tp->ftt_dest;
                        else
@@ -1752,7 +1814,7 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                {
                        uint_t taken;
                        uint64_t cx = regs64->rcx--;
-                       
+
                        switch (tp->ftt_code) {
                                case FASTTRAP_LOOPNZ:
                                        taken = (regs64->isf.rflags & FASTTRAP_EFLAGS_ZF) == 0 &&
@@ -1768,14 +1830,14 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                                default:
                                        taken = FALSE;
                        }
-                       
+
                        if (taken)
                                new_pc = tp->ftt_dest;
                        else
                                new_pc = pc + tp->ftt_size;
                        break;
                }
-               
+
                case FASTTRAP_T_JCXZ:
                {
                        uint64_t cx = regs64->rcx;
@@ -1791,18 +1853,18 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                {
                        user_addr_t addr = regs64->isf.rsp - sizeof (uint64_t);
                        int ret = fasttrap_suword64(addr, (uint64_t)regs64->rbp);
-                       
+
                        if (ret == -1) {
                                fasttrap_sigsegv(p, uthread, addr);
                                new_pc = pc;
                                break;
                        }
-                       
+
                        regs64->isf.rsp = addr;
                        new_pc = pc + tp->ftt_size;
                        break;
                }
-               
+
                case FASTTRAP_T_NOP:
                        new_pc = pc + tp->ftt_size;
                        break;
@@ -1813,13 +1875,13 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                                new_pc = tp->ftt_dest;
                        } else {
                                user_addr_t value, addr = tp->ftt_dest;
-                               
+
                                if (tp->ftt_base != FASTTRAP_NOREG)
                                        addr += fasttrap_getreg(regs, tp->ftt_base);
                                if (tp->ftt_index != FASTTRAP_NOREG)
                                        addr += fasttrap_getreg(regs, tp->ftt_index) <<
                                                tp->ftt_scale;
-                               
+
                                if (tp->ftt_code == 1) {
                                        /*
                                         * If there's a segment prefix for this
@@ -1833,7 +1895,7 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                                                new_pc = pc;
                                                break;
                                        }
-                                       
+
                                        if (fasttrap_fuword64(addr, &value) == -1) {
                                                fasttrap_sigsegv(p, uthread, addr);
                                                new_pc = pc;
@@ -1854,23 +1916,23 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                        if (tp->ftt_type == FASTTRAP_T_CALL) {
                                user_addr_t addr = regs64->isf.rsp - sizeof (uint64_t);
                                int ret = fasttrap_suword64(addr, pc + tp->ftt_size);
-                               
+
                                if (ret == -1) {
                                        fasttrap_sigsegv(p, uthread, addr);
                                        new_pc = pc;
                                        break;
                                }
-                               
+
                                regs64->isf.rsp = addr;
                        }
                        break;
 
                case FASTTRAP_T_COMMON:
                {
-                       user_addr_t addr;
-                       uint8_t scratch[2 * FASTTRAP_MAX_INSTR_SIZE + 5 + 2];
+                       user_addr_t addr, write_addr;
+                       uint8_t scratch[2 * FASTTRAP_MAX_INSTR_SIZE + 22];
                        uint_t i = 0;
-                       
+
                        /*
                         * Generic Instruction Tracing
                         * ---------------------------
@@ -1955,8 +2017,9 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                         */
 
                        addr = uthread->t_dtrace_scratch->addr;
+                       write_addr = uthread->t_dtrace_scratch->write_addr;
 
-                       if (addr == 0LL) {
+                       if (addr == 0LL || write_addr == 0LL) {
                                fasttrap_sigtrap(p, uthread, pc); // Should be killing target proc
                                new_pc = pc;
                                break;
@@ -1970,10 +2033,10 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
 
                        if (tp->ftt_ripmode != 0) {
                                uint64_t* reg;
-                               
+
                                ASSERT(tp->ftt_ripmode &
                                       (FASTTRAP_RIP_1 | FASTTRAP_RIP_2));
-                               
+
                                /*
                                 * If this was a %rip-relative instruction, we change
                                 * it to be either a %rax- or %rcx-relative
@@ -1987,12 +2050,12 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                                        scratch[i++] = FASTTRAP_REX(1, 0, 0, 1);
                                else
                                        scratch[i++] = FASTTRAP_REX(1, 0, 0, 0);
-                               
+
                                if (tp->ftt_ripmode & FASTTRAP_RIP_1)
                                        scratch[i++] = FASTTRAP_MOV_EAX;
                                else
                                        scratch[i++] = FASTTRAP_MOV_ECX;
-                               
+
                                switch (tp->ftt_ripmode) {
                                        case FASTTRAP_RIP_1:
                                                reg = &regs64->rax;
@@ -2014,7 +2077,8 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                                                reg = NULL;
                                                panic("unhandled ripmode in fasttrap_pid_probe64");
                                }
-                               
+
+                               /* LINTED - alignment */
                                *(uint64_t *)&scratch[i] = *reg;
                                uthread->t_dtrace_regv = *reg;
                                *reg = pc + tp->ftt_size;
@@ -2030,8 +2094,10 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                         */
                        scratch[i++] = FASTTRAP_GROUP5_OP;
                        scratch[i++] = FASTTRAP_MODRM(0, 4, 5);
+                       /* LINTED - alignment */
                        *(uint32_t *)&scratch[i] = 0;
                        i += sizeof (uint32_t);
+                       /* LINTED - alignment */
                        *(uint64_t *)&scratch[i] = pc + tp->ftt_size;
                        i += sizeof (uint64_t);
 
@@ -2041,7 +2107,9 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                        scratch[i++] = FASTTRAP_INT;
                        scratch[i++] = T_DTRACE_RET;
 
-                       if (fasttrap_copyout(scratch, addr, i)) {
+                       ASSERT(i <= sizeof (scratch));
+
+                       if (fasttrap_copyout(scratch, write_addr, i)) {
                                fasttrap_sigtrap(p, uthread, pc);
                                new_pc = pc;
                                break;
@@ -2054,17 +2122,17 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                        } else {
                                new_pc = uthread->t_dtrace_scrpc;
                        }
-                       
+
                        uthread->t_dtrace_pc = pc;
                        uthread->t_dtrace_npc = pc + tp->ftt_size;
                        uthread->t_dtrace_on = 1;
                        break;
                }
-               
+
                default:
                        panic("fasttrap: mishandled an instruction");
        }
-       
+
 done:
        /*
         * APPLE NOTE:
@@ -2145,13 +2213,10 @@ fasttrap_return_probe(x86_saved_state_t *regs)
         * parent. We know that there's only one thread of control in such a
         * process: this one.
         */
-       /*
-        * APPLE NOTE: Terry says: "You need to hold the process locks (currently: kernel funnel) for this traversal"
-        * How do we assert this?
-        */
-       while (p->p_lflag & P_LINVFORK) {
+       proc_list_lock();
+       while (p->p_lflag & P_LINVFORK)
                p = p->p_pptr;
-       }
+       proc_list_unlock();
 
        /*
         * We set rp->r_pc to the address of the traced instruction so
@@ -2174,6 +2239,7 @@ uint64_t
 fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
     int aframes)
 {
+       pal_register_cache_state(current_thread(), VALID);
 #pragma unused(arg, id, parg, aframes)
        return (fasttrap_anarg((x86_saved_state_t *)find_user_regs(current_thread()), 1, argno));
 }
@@ -2182,6 +2248,7 @@ uint64_t
 fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
     int aframes)
 {
+       pal_register_cache_state(current_thread(), VALID);
 #pragma unused(arg, id, parg, aframes)
        return (fasttrap_anarg((x86_saved_state_t *)find_user_regs(current_thread()), 0, argno));
 }
@@ -2213,6 +2280,20 @@ fasttrap_getreg(x86_saved_state_t *regs, uint_t reg)
                        case REG_R13:           return regs64->r13;
                        case REG_R14:           return regs64->r14;
                        case REG_R15:           return regs64->r15;
+                       case REG_TRAPNO:        return regs64->isf.trapno;
+                       case REG_ERR:           return regs64->isf.err;
+                       case REG_RIP:           return regs64->isf.rip;
+                       case REG_CS:            return regs64->isf.cs;
+                       case REG_RFL:           return regs64->isf.rflags;
+                       case REG_SS:            return regs64->isf.ss;
+                       case REG_FS:            return regs64->fs;
+                       case REG_GS:            return regs64->gs;
+                       case REG_ES:
+                       case REG_DS:
+                       case REG_FSBASE:
+                       case REG_GSBASE:
+                               // Important to distinguish these requests (which should be legal) from other values.
+                               panic("dtrace: unimplemented x86_64 getreg()");
                }
 
                panic("dtrace: unhandled x86_64 getreg() constant");