X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/b0d623f7f2ae71ed96e60569f61f9a9a27016e80..0a7de7458d150b5d4dffc935ba399be265ef0a1a:/bsd/dev/i386/fasttrap_isa.c diff --git a/bsd/dev/i386/fasttrap_isa.c b/bsd/dev/i386/fasttrap_isa.c index be620b517..0e9e97849 100644 --- a/bsd/dev/i386/fasttrap_isa.c +++ b/bsd/dev/i386/fasttrap_isa.c @@ -45,6 +45,8 @@ extern dtrace_id_t dtrace_probeid_error; #include #include +#include + /* 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 */ @@ -195,21 +197,19 @@ extern dtrace_id_t dtrace_probeid_error; * * 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); @@ -361,13 +361,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 @@ -450,11 +448,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 { @@ -552,7 +548,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); /* @@ -562,7 +557,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; @@ -589,7 +583,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 @@ -635,7 +628,6 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc, } } } -#endif return (0); } @@ -648,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); } @@ -661,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); } @@ -677,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; @@ -716,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 @@ -723,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 @@ -735,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); } @@ -961,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()); @@ -991,12 +1002,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; @@ -1054,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); + } } /* @@ -1359,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; @@ -1403,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; @@ -1433,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; @@ -1520,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()); @@ -1550,12 +1577,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; @@ -1593,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); @@ -1632,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); } } @@ -1899,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; @@ -1987,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; @@ -2078,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; @@ -2182,13 +2223,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 @@ -2207,11 +2245,11 @@ fasttrap_return_probe(x86_saved_state_t *regs) return (0); } - 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)); } @@ -2220,6 +2258,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)); }