From: Kris Van Hees Date: Tue, 27 Aug 2013 19:49:50 +0000 (-0400) Subject: dtrace: fix retrieval of arg5 through arg9 X-Git-Tag: v4.1.12-111.0.20170907_2225~3^2~3^2~132 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=c03e8ecb74bd4d16b1fa905327fd67249a0bc087;p=users%2Fjedix%2Flinux-maple.git dtrace: fix retrieval of arg5 through arg9 Fix the retrieval of arguments passed on the stack for SDT, USDT, and direct call probes. This commit also adds trivial support for testcases related to this fix. Orabug: 17368166 Signed-off-by: Kris Van Hees --- diff --git a/dtrace/dt_test_dev.c b/dtrace/dt_test_dev.c index c0c9abe4c4210..2a5f82973ea83 100644 --- a/dtrace/dt_test_dev.c +++ b/dtrace/dt_test_dev.c @@ -65,8 +65,19 @@ void dt_test_destroy(void *arg, dtrace_id_t id, void *parg) 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; } diff --git a/dtrace/dtrace_dif.c b/dtrace/dtrace_dif.c index c1d56a2b154bf..cd30f6fed80b2 100644 --- a/dtrace/dtrace_dif.c +++ b/dtrace/dtrace_dif.c @@ -1985,7 +1985,7 @@ static uint64_t dtrace_dif_variable(dtrace_mstate_t *mstate, 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; @@ -2070,7 +2070,7 @@ static uint64_t dtrace_dif_variable(dtrace_mstate_t *mstate, 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; @@ -2106,7 +2106,7 @@ static uint64_t dtrace_dif_variable(dtrace_mstate_t *mstate, 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)) { /* diff --git a/dtrace/dtrace_isa.c b/dtrace/dtrace_isa.c index 698904f9faa99..189d170581697 100644 --- a/dtrace/dtrace_isa.c +++ b/dtrace/dtrace_isa.c @@ -114,66 +114,35 @@ DTRACE_FUWORD(16) 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; diff --git a/dtrace/fasttrap_dev.c b/dtrace/fasttrap_dev.c index 5355d811c77ac..833685f6f9081 100644 --- a/dtrace/fasttrap_dev.c +++ b/dtrace/fasttrap_dev.c @@ -121,6 +121,8 @@ static int fasttrap_pid_probe(fasttrap_machtp_t *mtp, struct pt_regs *regs) { 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; @@ -139,6 +141,8 @@ static int fasttrap_pid_probe(fasttrap_machtp_t *mtp, struct pt_regs *regs) { } } + this_cpu_core->cpu_dtrace_regs = NULL; + if (is_enabled) regs->ax = 1; @@ -703,7 +707,37 @@ static void fasttrap_pid_getargdesc(void *arg, dtrace_id_t id, void *parg, 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) diff --git a/dtrace/sdt_dev.c b/dtrace/sdt_dev.c index 44684b42e4752..4868db390505a 100644 --- a/dtrace/sdt_dev.c +++ b/dtrace/sdt_dev.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "dtrace.h" #include "dtrace_dev.h" @@ -108,8 +109,13 @@ static uint8_t sdt_invop(struct pt_regs *regs) 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; } } @@ -267,7 +273,37 @@ void sdt_getargdesc(void *arg, dtrace_id_t id, void *parg, 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) diff --git a/dtrace/sdt_mod.c b/dtrace/sdt_mod.c index accf402f14f76..643b1539929f1 100644 --- a/dtrace/sdt_mod.c +++ b/dtrace/sdt_mod.c @@ -119,7 +119,7 @@ static dtrace_pops_t sdt_pops = { NULL, NULL, sdt_getargdesc, - NULL /* sdt_getarg */, + sdt_getarg, NULL, sdt_destroy, };