static long dt_test_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
+ /*
+ * Yes, this is not nice.
+ * Not at all.
+ * But we're doing it anyway...
+ */
+ void (*dt_test_probe)(dtrace_id_t, uintptr_t, uintptr_t, uintptr_t,
+ uintptr_t, uintptr_t, uintptr_t, uintptr_t,
+ uintptr_t, uintptr_t, uintptr_t);
+
if (enabled) {
- dtrace_probe(pid, cmd, arg, 2, 3, 4);
+ dt_test_probe = (void *)&dtrace_probe;
+ dt_test_probe(pid, cmd, arg, 2ULL, 3ULL, 4ULL, 5ULL,
+ 6ULL, 7ULL, 8ULL, 9ULL);
return 0;
}
if (ndx >=
sizeof(mstate->dtms_arg) / sizeof(mstate->dtms_arg[0])) {
int aframes =
- mstate->dtms_probe->dtpr_aframes + 2;
+ mstate->dtms_probe->dtpr_aframes + 3;
dtrace_provider_t *pv;
uint64_t val;
if (!dtrace_priv_kernel(state))
return 0;
if (!(mstate->dtms_present & DTRACE_MSTATE_STACKDEPTH)) {
- int aframes = mstate->dtms_probe->dtpr_aframes + 2;
+ int aframes = mstate->dtms_probe->dtpr_aframes + 3;
mstate->dtms_stackdepth = dtrace_getstackdepth(aframes);
mstate->dtms_present |= DTRACE_MSTATE_STACKDEPTH;
return 0;
if (!(mstate->dtms_present & DTRACE_MSTATE_CALLER)) {
- int aframes = mstate->dtms_probe->dtpr_aframes + 2;
+ int aframes = mstate->dtms_probe->dtpr_aframes + 3;
if (!DTRACE_ANCHORED(mstate->dtms_probe)) {
/*
DTRACE_FUWORD(32)
DTRACE_FUWORD(64)
-struct frame {
- struct frame *fr_savfp;
- unsigned long fr_savpc;
-} __attribute__((packed));
-
-static void dtrace_invop_callsite(void)
+uint64_t dtrace_getarg(int argno, int aframes)
{
-}
-
-uint64_t dtrace_getarg(int arg, int aframes)
-{
- struct frame *fp = (struct frame *)dtrace_getfp();
- uintptr_t *stack;
- int i;
+ unsigned long bp;
+ uint64_t *st;
uint64_t val;
- int regmap[] = {
- REG_RDI,
- REG_RSI,
- REG_RDX,
- REG_RCX,
- REG_R8,
- REG_R9
- };
- int nreg = sizeof(regmap) / sizeof(regmap[0]) - 1;
-
- for (i = 1; i <= aframes; i++) {
- fp = fp->fr_savfp;
-
- if (fp->fr_savpc == (uintptr_t)dtrace_invop_callsite) {
- /* FIXME */
-
- goto load;
- }
- }
-
- /*
- * We know that we did not get here through a trap to get into the
- * dtrace_probe() function, so this was a straight call into it from
- * a provider. In that case, we need to shift the argument that we
- * are looking for, because the probe ID will be the first argument to
- * dtrace_probe().
- */
- arg++;
+ int i;
- if (arg <= nreg) {
- /*
- * This should not happen. If the argument was passed in a
- * register then it should have been, ...passed in a register.
- */
- DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
- return 0;
- }
+ asm volatile("movq %%rbp,%0" : "=m"(bp));
- arg -= nreg + 1;
+ for (i = 0; i < aframes; i++)
+ bp = *((unsigned long *)bp);
- stack = (uintptr_t *)&fp[1];
+ ASSERT(argno >= 5);
-load:
+ /*
+ * The first 5 arguments (arg0 through arg4) are passed in registers
+ * to dtrace_probe(). The remaining arguments (arg5 through arg9) are
+ * passed on the stack.
+ *
+ * Stack layout:
+ * bp[0] = pushed bp from caller
+ * bp[1] = return address
+ * bp[2] = 6th argument (arg5 -> argno = 5)
+ * bp[3] = 7th argument (arg6 -> argno = 6)
+ * ...
+ */
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
- val = stack[arg];
+ st = (uint64_t *)bp;
+ val = st[2 + (argno - 5)];
DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
return val;
if (atomic64_read(&tp->ftt_proc->ftpc_acount) == 0)
return 0;
+ this_cpu_core->cpu_dtrace_regs = regs;
+
for (id = tp->ftt_ids; id != NULL; id = id->fti_next) {
fasttrap_probe_t *ftp = id->fti_probe;
}
}
+ this_cpu_core->cpu_dtrace_regs = NULL;
+
if (is_enabled)
regs->ax = 1;
static uint64_t fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg,
int argno, int aframes)
{
- return 0; /* FIXME */
+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs;
+ uint64_t *st;
+ uint64_t val;
+
+ if (regs == NULL)
+ return 0;
+
+ switch (argno) {
+ case 0:
+ return regs->di;
+ case 1:
+ return regs->si;
+ case 2:
+ return regs->dx;
+ case 3:
+ return regs->cx;
+ case 4:
+ return regs->r8;
+ case 5:
+ return regs->r9;
+ }
+
+ ASSERT(argno > 5);
+
+ st = (uint64_t *)regs->sp;
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
+ __copy_from_user_inatomic_nocache(&val, (void *)&st[argno - 6],
+ sizeof(st[0]));
+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
+
+ return val;
}
static void fasttrap_pid_destroy(void *arg, dtrace_id_t id, void *parg)
#include <linux/miscdevice.h>
#include <linux/sdt.h>
#include <linux/slab.h>
+#include <linux/uaccess.h>
#include "dtrace.h"
#include "dtrace_dev.h"
for (; sdt != NULL; sdt = sdt->sdp_hashnext) {
if ((uintptr_t)sdt->sdp_patchpoint == regs->ip) {
+ this_cpu_core->cpu_dtrace_regs = regs;
+
dtrace_probe(sdt->sdp_id, regs->di, regs->si,
regs->dx, regs->cx, regs->r8);
+
+ this_cpu_core->cpu_dtrace_regs = NULL;
+
return DTRACE_INVOP_NOP;
}
}
uint64_t sdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
int aframes)
{
- return 0;
+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs;
+ uint64_t *st;
+ uint64_t val;
+
+ if (regs == NULL)
+ return 0;
+
+ switch (argno) {
+ case 0:
+ return regs->di;
+ case 1:
+ return regs->si;
+ case 2:
+ return regs->dx;
+ case 3:
+ return regs->cx;
+ case 4:
+ return regs->r8;
+ case 5:
+ return regs->r9;
+ }
+
+ ASSERT(argno > 5);
+
+ st = (uint64_t *)regs->sp;
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
+ __copy_from_user_inatomic_nocache(&val, (void *)&st[argno - 6],
+ sizeof(st[0]));
+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
+
+ return val;
}
void sdt_destroy(void *arg, dtrace_id_t id, void *parg)
NULL,
NULL,
sdt_getargdesc,
- NULL /* sdt_getarg */,
+ sdt_getarg,
NULL,
sdt_destroy,
};