#ifdef KERNEL
#ifndef _KERNEL
#define _KERNEL
#endif
#endif
#define MACH__POSIX_C_SOURCE_PRIVATE 1
#include <kern/cpu_data.h>
#include <kern/thread.h>
#include <mach/thread_status.h>
#include <mach/vm_param.h>
#include <sys/dtrace.h>
#include <sys/dtrace_impl.h>
#include <sys/dtrace_glue.h>
#include <sys/sdt_impl.h>
extern sdt_probe_t **sdt_probetab;
#if defined(__i386__)
int
sdt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax)
{
#pragma unused(eax)
uintptr_t stack0 = 0, stack1 = 0, stack2 = 0, stack3 = 0, stack4 = 0;
sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(addr)];
for (; sdt != NULL; sdt = sdt->sdp_hashnext) {
if ((uintptr_t)sdt->sdp_patchpoint == addr) {
uintptr_t *stacktop;
if (CPU_ON_INTR(CPU))
stacktop = (uintptr_t *)dtrace_get_cpu_int_stack_top();
else
stacktop = (uintptr_t *)(dtrace_get_kernel_stack(current_thread()) + kernel_stack_size);
if (stack <= stacktop)
stack0 = *stack++;
if (stack <= stacktop)
stack1 = *stack++;
if (stack <= stacktop)
stack2 = *stack++;
if (stack <= stacktop)
stack3 = *stack++;
if (stack <= stacktop)
stack4 = *stack++;
dtrace_probe(sdt->sdp_id, stack0, stack1, stack2, stack3, stack4);
return (DTRACE_INVOP_NOP);
}
}
return (0);
}
#elif defined(__x86_64__)
int
sdt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax)
{
#pragma unused(eax)
sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(addr)];
for (; sdt != NULL; sdt = sdt->sdp_hashnext) {
if ((uintptr_t)sdt->sdp_patchpoint == addr) {
x86_saved_state64_t *regs = (x86_saved_state64_t *)stack;
dtrace_probe(sdt->sdp_id, regs->rdi, regs->rsi, regs->rdx, regs->rcx, regs->r8);
return (DTRACE_INVOP_NOP);
}
}
return (0);
}
#else
#error Unknown arch
#endif
struct frame {
struct frame *backchain;
uintptr_t retaddr;
};
uint64_t
sdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes)
{
#pragma unused(arg, id, parg)
uint64_t val;
struct frame *fp = (struct frame *)__builtin_frame_address(0);
uintptr_t *stack;
uintptr_t pc;
int i;
#if defined(__x86_64__)
int inreg = 5;
#endif
for (i = 1; i <= aframes; i++) {
fp = fp->backchain;
pc = fp->retaddr;
if (dtrace_invop_callsite_pre != NULL
&& pc > (uintptr_t)dtrace_invop_callsite_pre
&& pc <= (uintptr_t)dtrace_invop_callsite_post) {
#if defined(__i386__)
stack = (uintptr_t *)&fp[1];
fp = (struct frame *)stack[1];
stack = (uintptr_t *)&fp[0];
#elif defined(__x86_64__)
fp = fp->backchain;
fp = fp->backchain;
fp = fp->backchain;
x86_saved_state_t *tagged_regs = (x86_saved_state_t *)&fp[1];
x86_saved_state64_t *saved_state = saved_state64(tagged_regs);
if (argno <= inreg) {
stack = (uintptr_t *)&saved_state->rdi;
} else {
fp = (struct frame *)(saved_state->isf.rsp);
stack = (uintptr_t *)&fp[0];
argno -= (inreg +1);
}
#else
#error Unknown arch
#endif
goto load;
}
}
argno++;
#if defined(__x86_64__)
if (argno <= inreg) {
DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
return (0);
}
argno -= (inreg + 1);
#endif
stack = (uintptr_t *)&fp[1];
load:
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
val = (uint64_t)(*(((uintptr_t *)stack) + argno));
DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
return (val);
}