* Use is subject to license terms.
*/
-/*
- * #pragma ident "@(#)fasttrap_isa.c 1.27 08/04/09 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>
if (p_model == DATAMODEL_LP64) {
user_addr_t stack;
-
+
/*
* In 64-bit mode, the first six arguments are stored in
* registers.
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:
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) {
+ if (os_atomic_xchg(&probe->ftp_triggered, 1, relaxed)) {
+ /* already triggered */
continue;
}
}
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.
if (tp->ftt_ids != NULL) {
fasttrap_id_t *id;
-
+
uint32_t s0, s1, s2, s3, s4, s5;
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
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 (ISSET(current_proc()->p_lflag, P_LNOATTACH)) {
- dtrace_probe(dtrace_probeid_error, 0 /* state */, probe->ftp_id,
+ 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) {
- uint8_t already_triggered = atomic_or_8(&probe->ftp_triggered, 1);
- if (already_triggered) {
+ if (os_atomic_xchg(&probe->ftp_triggered, 1, relaxed)) {
+ /* already triggered */
continue;
}
}
new_pc = pc;
break;
}
-
+
if (tp->ftt_type == FASTTRAP_T_RET16)
addr += tp->ftt_dest;
-
+
regs32->uesp = addr;
new_pc = dst;
break;
case FASTTRAP_T_JCC:
{
uint_t taken;
-
+
switch (tp->ftt_code) {
case FASTTRAP_JO:
taken = (regs32->efl & FASTTRAP_EFLAGS_OF) != 0;
default:
taken = FALSE;
}
-
+
if (taken)
new_pc = tp->ftt_dest;
else
default:
taken = FALSE;
}
-
+
if (taken)
new_pc = tp->ftt_dest;
else
case FASTTRAP_T_JCXZ:
{
greg_t cx = regs32->ecx;
-
+
if (cx == 0)
new_pc = tp->ftt_dest;
else
{
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;
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
new_pc = pc;
break;
}
-
+
uint32_t value32;
addr = (user_addr_t)(uint32_t)addr;
if (fasttrap_fuword32(addr, &value32) == -1) {
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;
+ 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;
i += tp->ftt_size;
scratch[i++] = FASTTRAP_INT;
scratch[i++] = T_DTRACE_RET;
-
+
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;
}
-
+
if (tp->ftt_retids != NULL) {
uthread->t_dtrace_step = 1;
uthread->t_dtrace_ret = 1;
} 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:
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) {
+ if (os_atomic_xchg(&probe->ftp_triggered, 1, relaxed)) {
+ /* already triggered */
continue;
}
}
retire_tp = 0;
}
if (ISSET(current_proc()->p_lflag, P_LNOATTACH)) {
- dtrace_probe(dtrace_probeid_error, 0 /* state */, probe->ftp_id,
+ dtrace_probe(dtrace_probeid_error, 0 /* state */, probe->ftp_id,
1 /* ndx */, -1 /* offset */, DTRACEFLT_UPRIV);
} else if (id->fti_ptype == DTFTP_ENTRY) {
/*
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]);
}
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
*/
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;
default:
taken = FALSE;
}
-
+
if (taken)
new_pc = tp->ftt_dest;
else
{
uint_t taken;
uint64_t cx = regs64->rcx--;
-
+
switch (tp->ftt_code) {
case FASTTRAP_LOOPNZ:
taken = (regs64->isf.rflags & FASTTRAP_EFLAGS_ZF) == 0 &&
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;
{
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;
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
new_pc = pc;
break;
}
-
+
if (fasttrap_fuword64(addr, &value) == -1) {
fasttrap_sigsegv(p, uthread, addr);
new_pc = pc;
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;
+ user_addr_t addr, write_addr;
uint8_t scratch[2 * FASTTRAP_MAX_INSTR_SIZE + 22];
uint_t i = 0;
-
+
/*
* Generic Instruction Tracing
* ---------------------------
*/
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;
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
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 = ®s64->rax;
reg = NULL;
panic("unhandled ripmode in fasttrap_pid_probe64");
}
-
+
/* LINTED - alignment */
*(uint64_t *)&scratch[i] = *reg;
uthread->t_dtrace_regv = *reg;
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;
} 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: