]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: fix retrieval of arg5 through arg9
authorKris Van Hees <kris.van.hees@oracle.com>
Tue, 27 Aug 2013 19:49:50 +0000 (15:49 -0400)
committerKris Van Hees <kris.van.hees@oracle.com>
Thu, 5 Sep 2013 20:57:02 +0000 (16:57 -0400)
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 <kris.van.hees@oracle.com>
dtrace/dt_test_dev.c
dtrace/dtrace_dif.c
dtrace/dtrace_isa.c
dtrace/fasttrap_dev.c
dtrace/sdt_dev.c
dtrace/sdt_mod.c

index c0c9abe4c42107939285ef3707971da8022b3f91..2a5f82973ea830b0f9088af85ecd175ae0eb195f 100644 (file)
@@ -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;
        }
index c1d56a2b154bf23efaf823fb5a899fd600d09f48..cd30f6fed80b2db0df8158848e28f3449d7e7aef 100644 (file)
@@ -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)) {
                                /*
index 698904f9faa9900e5e1d42270d5feeb2e248f656..189d170581697adb3c57336b2e6d1e3bf21f7c3e 100644 (file)
@@ -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;
index 5355d811c77ac8ec83275251b8a1598a02798a4e..833685f6f90813790ddba909042179ab1f5f55bd 100644 (file)
@@ -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)
index 44684b42e4752b57711dfbd4359447ab37d54aa9..4868db390505a919b4b85da58eb24701531259c3 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/miscdevice.h>
 #include <linux/sdt.h>
 #include <linux/slab.h>
+#include <linux/uaccess.h>
 
 #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)
index accf402f14f76193bd36dc9ded7b71c06536d41b..643b1539929f16f7137cf95146c4e91da6a7f66e 100644 (file)
@@ -119,7 +119,7 @@ static dtrace_pops_t sdt_pops = {
        NULL,
        NULL,
        sdt_getargdesc,
-       NULL /* sdt_getarg */,
+       sdt_getarg,
        NULL,
        sdt_destroy,
 };