]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/dev/i386/fasttrap_isa.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / bsd / dev / i386 / fasttrap_isa.c
index 4eeb6d140f0b4060e13e28b1e52aefeb45111373..0e9e9784979cb718d9247983e17a00c2aef394fa 100644 (file)
@@ -640,6 +640,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 +655,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 +673,7 @@ 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;
 
@@ -708,6 +713,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
@@ -715,10 +721,23 @@ 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 (probe->ftp_prov->ftp_provider_type == DTFTP_PROVIDER_ONESHOT) {
+                       uint8_t already_triggered = atomic_or_8(&probe->ftp_triggered, 1);
+                       if (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
@@ -727,14 +746,14 @@ fasttrap_return_common(x86_saved_state_t *regs, user_addr_t pc, pid_t pid,
                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 */, id->fti_probe->ftp_id, 
+                       dtrace_probe(dtrace_probeid_error, 0 /* state */, probe->ftp_id,
                                     1 /* ndx */, -1 /* offset */, DTRACEFLT_UPRIV);
                } else if (p_model == DATAMODEL_LP64) {
-                       dtrace_probe(id->fti_probe->ftp_id,
+                       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);
                }
@@ -953,7 +972,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());
 
@@ -1046,45 +1065,59 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                        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
-                                * 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) {
+                       } else {
+                               if (probe->ftp_prov->ftp_provider_type == DTFTP_PROVIDER_ONESHOT) {
+                                       uint8_t already_triggered = atomic_or_8(&probe->ftp_triggered, 1);
+                                       if (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);
+               }
        }
 
        /*
@@ -1351,7 +1384,7 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
 
                case FASTTRAP_T_COMMON:
                {
-                       user_addr_t addr;
+                       user_addr_t addr, write_addr;
                        uint8_t scratch[2 * FASTTRAP_MAX_INSTR_SIZE + 7];
                        uint_t i = 0;
 
@@ -1395,8 +1428,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;
@@ -1425,7 +1459,7 @@ fasttrap_pid_probe32(x86_saved_state_t *regs)
                        
                        ASSERT(i <= sizeof (scratch));
 
-                       if (fasttrap_copyout(scratch, addr, i)) {
+                       if (fasttrap_copyout(scratch, write_addr, i)) {
                                fasttrap_sigtrap(p, uthread, pc);
                                new_pc = pc;
                                break;
@@ -1512,6 +1546,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());
 
@@ -1585,6 +1620,20 @@ 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 (probe->ftp_prov->ftp_provider_type == DTFTP_PROVIDER_ONESHOT) {
+                               uint8_t already_triggered = atomic_or_8(&probe->ftp_triggered, 1);
+                               if (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);
@@ -1624,10 +1673,9 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
                                             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);
                }
        }
 
@@ -1891,7 +1939,7 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
 
                case FASTTRAP_T_COMMON:
                {
-                       user_addr_t addr;
+                       user_addr_t addr, write_addr;
                        uint8_t scratch[2 * FASTTRAP_MAX_INSTR_SIZE + 22];
                        uint_t i = 0;
                        
@@ -1979,8 +2027,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;
@@ -2070,7 +2119,7 @@ fasttrap_pid_probe64(x86_saved_state_t *regs)
 
                        ASSERT(i <= sizeof (scratch));
 
-                       if (fasttrap_copyout(scratch, addr, i)) {
+                       if (fasttrap_copyout(scratch, write_addr, i)) {
                                fasttrap_sigtrap(p, uthread, pc);
                                new_pc = pc;
                                break;