*/
/*
- * 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);
if (p_model == DATAMODEL_LP64) {
user_addr_t stack;
-
+
/*
* In 64-bit mode, the first six arguments are stored in
* registers.
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);
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:
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
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;
}
* 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 {
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]) {
case FASTTRAP_RET16:
tp->ftt_type = FASTTRAP_T_RET16;
+ /* LINTED - alignment */
tp->ftt_dest = *(uint16_t *)&instr[start + 1];
break;
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;
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:
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;
if (is_saved_state64(regs)) {
regs64 = saved_state64(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;
}
}
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 (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);
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.
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];
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;
*/
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;
}
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
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);
+ }
}
/*
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;
- 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;
/*
*/
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;
* 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);
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;
} 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:
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 (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;
}
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
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);
}
}
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;
- 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
* ---------------------------
*/
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;
*reg = pc + tp->ftt_size;
*/
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);
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;
} 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:
* 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
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));
}
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");