#include <sys/dtrace_ptss.h>
#include <kern/debug.h>
+#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 */
*
* 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);
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
* 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 {
break;
case FASTTRAP_NOP:
-#if __sol64 || defined(__APPLE__)
ASSERT(p_model == DATAMODEL_LP64 || rex == 0);
/*
* (e.g. xchgl %r8d, %eax or xcghq %r8, %rax).
*/
if (FASTTRAP_REX_B(rex) == 0)
-#endif
tp->ftt_type = FASTTRAP_T_NOP;
break;
}
}
-#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
}
}
}
-#endif
return (0);
}
if (uwrite(p, &instr, 1, tp->ftt_pc) != 0)
return (-1);
+ tp->ftt_installed = 1;
+
return (0);
}
* 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);
}
x86_saved_state64_t *regs64;
x86_saved_state32_t *regs32;
unsigned int p_model;
+ int retire_tp = 1;
dtrace_icookie_t cookie;
}
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
*/
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
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);
}
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());
* 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;
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);
+ }
}
/*
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;
*/
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;
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;
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());
* 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;
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);
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);
}
}
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;
*/
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;
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;
* 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
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));
}
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));
}