]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: is-enabled probes for SDT
authorKris Van Hees <kris.van.hees@oracle.com>
Wed, 23 Nov 2016 18:24:10 +0000 (18:24 +0000)
committerKris Van Hees <kris.van.hees@oracle.com>
Sat, 24 Dec 2016 06:26:56 +0000 (01:26 -0500)
This is the module side of the is-enabled probe implementation.  SDT
distinguishes is-enabled probes from normal probes by the leading ? in
their sdpd_name; at probe-firing time, the arch-dependent code arranges
to return 1 appropriately.

On x86, also arrange to jump past the probe's NOP region.  There was no
need to do this before now, because a trap followed by a bunch of NOPs
is a perfectly valid instruction stream: but is-enabled probes have a
three-byte sequence implementing "xor %rax, %rax", and overwriting only
the first byte of that leaves us with a couple of bytes that must be
skipped.  On SPARC, we drop the necessary return-value-changing
instruction into the delay slot of the call that used to be there
before we overwrote it with NOPs;: the instruction already there
is setting up the function argument-and-return-value, which is 0
when the probe is disabled, so we can overwrite it safely.

(We make minor adjustments to allow sdt_provide_probe_arch() to
safely modify the sdp_patchpoint.)

Finally, add a test use of an is-enabled probe to dt_test, used by the
DTrace testsuite.

[nca: sparc implementation, ip address adjustment, commit msg]
Signed-off-by: Nick Alcock <nick.alcock@oracle.com>
Acked-by: Kris Van Hees <kris.van.hees@oracle.com>
Orabug: 25143173

dtrace/dt_test_dev.c
dtrace/include/dtrace/dtrace_impl_defines.h
dtrace/sdt_dev.c
dtrace/sdt_impl.h
dtrace/sdt_sparc64.c
dtrace/sdt_x86_64.c

index f833fe9b26df07d1bc25b7dc0e13f37f7270ca26..1a6405c892a20ef4e4ca6fbb4f5555209ab17850 100644 (file)
@@ -21,7 +21,7 @@
  *
  * CDDL HEADER END
  *
- * Copyright 2011-2014 Oracle, Inc.  All rights reserved.
+ * Copyright 2011-2016 Oracle, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -99,6 +99,10 @@ static long dt_test_ioctl(struct file *file,
                return 0;
        }
 
+       if (DTRACE_PROBE_ENABLED(sdt__test)) {
+               DTRACE_PROBE(sdt__test__is__enabled)
+       }
+
        DTRACE_PROBE(sdt__test);
 
        /*
index 737dd50fb8c35ef11afde97c848bb3840978375b..54d5b2518a9cf36fbf8bd1bf254b0e9231e0b2c1 100644 (file)
@@ -157,14 +157,6 @@ typedef enum dtrace_speculation_state {
 
 #define KERNELBASE     (uintptr_t)_text
 
-#if defined(__i386__) || defined(__x86_64__)
-# define DTRACE_INVOP_PUSHL_EBP        1
-# define DTRACE_INVOP_POPL_EBP 2
-# define DTRACE_INVOP_LEAVE    3
-# define DTRACE_INVOP_NOP      4
-# define DTRACE_INVOP_RET      5
-#endif
-
 #ifdef CONFIG_DT_DEBUG_MUTEX
 # define real_mutex_lock(x)            mutex_lock(x)
 # define real_mutex_unlock(x)          mutex_unlock(x)
index ad6557ce456d3f21a0867f6e72da5eeb4f09b3f8..4b29b66d2ed178672796afea22331eb696cfcc33 100644 (file)
@@ -21,7 +21,7 @@
  *
  * CDDL HEADER END
  *
- * Copyright 2010-2014 Oracle, Inc.  All rights reserved.
+ * Copyright 2010-2016 Oracle, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -297,6 +297,13 @@ void sdt_provide_module(void *arg, struct module *mp)
                int                     i, j;
                dtrace_mprovider_t      *prov;
                dtrace_id_t             id;
+               sdt_probe_type_t        ptype;
+
+               if (name[0] == '?') {
+                       ptype = SDTPT_IS_ENABLED;
+                       name++;
+               } else
+                       ptype = SDTPT_OFFSETS;
 
                for (prov = sdt_providers; prov->dtmp_pref != NULL; prov++) {
                        char    *prefix = prov->dtmp_pref;
@@ -337,6 +344,7 @@ void sdt_provide_module(void *arg, struct module *mp)
                sdp->sdp_name = nname;
                sdp->sdp_namelen = len;
                sdp->sdp_provider = prov;
+               sdp->sdp_ptype = ptype;
 
                sdp->sdp_argdesc = sdt_setup_args(sdpd, &sdp->sdp_nargdesc);
 
@@ -358,13 +366,13 @@ void sdt_provide_module(void *arg, struct module *mp)
                        PDATA(mp)->sdt_probe_cnt++;
                }
 
-               sdp->sdp_hashnext = sdt_probetab[
-                                       SDT_ADDR2NDX(sdpd->sdpd_offset)];
-               sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)] = sdp;
-
                sdp->sdp_patchpoint = (asm_instr_t *)sdpd->sdpd_offset;
 
                sdt_provide_probe_arch(sdp, mp, idx);
+
+               sdp->sdp_hashnext = sdt_probetab[
+                                       SDT_ADDR2NDX(sdp->sdp_patchpoint)];
+               sdt_probetab[SDT_ADDR2NDX(sdp->sdp_patchpoint)] = sdp;
        }
 }
 
@@ -423,6 +431,10 @@ void sdt_getargdesc(void *arg, dtrace_id_t id, void *parg,
        desc->dtargd_native[0] = '\0';
        desc->dtargd_xlate[0] = '\0';
 
+       while ((sdp->sdp_ptype == SDTPT_IS_ENABLED) &&
+              (sdp->sdp_next != NULL))
+               sdp = sdp->sdp_next;
+
        if (sdp->sdp_nargdesc <= desc->dtargd_ndx) {
                desc->dtargd_ndx = DTRACE_ARGNONE;
                return;
index 2b03eee30e5f626871fa1b083792115e70c4523e..785dc4fd02af3ef2e1b413285681034de4d10263 100644 (file)
@@ -9,6 +9,12 @@ extern struct module           *dtrace_kmod;
 
 struct sdt_argdesc;
 
+typedef enum fasttrap_probe_type {
+        SDTPT_NONE = 0,
+        SDTPT_OFFSETS,
+        SDTPT_IS_ENABLED
+} sdt_probe_type_t;
+
 typedef struct sdt_probe {
        dtrace_mprovider_t      *sdp_provider;  /* provider */
        char                    *sdp_name;      /* name of probe */
@@ -17,6 +23,7 @@ typedef struct sdt_probe {
        struct module           *sdp_module;    /* modctl for module */
        int                     sdp_loadcnt;    /* load count for module */
        int                     sdp_primary;    /* non-zero if primary mod */
+       sdt_probe_type_t        sdp_ptype;      /* probe type */
        asm_instr_t             *sdp_patchpoint;/* patch point */
        asm_instr_t             sdp_patchval;   /* instruction to patch */
        asm_instr_t             sdp_savedval;   /* saved instruction value */
index a1f77431d4b614775de8bb9b6428212a23e4d10f..65bc8d07ca41c12a056919c843a5d72786be1c0e 100644 (file)
@@ -60,6 +60,9 @@
  *      mov    %i4, %o5
  *     ret
  *      restore
+ *
+ * For is-enabled probes, we just drop an "or %g0, 1, %o0"
+ * directly into the delay slot.
  */
 #if SDT_TRAMP_SIZE < 11
 # error SDT_TRAMP_SIZE is less than the required 11 instructions.
@@ -124,27 +127,40 @@ void sdt_provide_probe_arch(sdt_probe_t *sdp, struct module *mp, int idx)
                                                           SDT_TRAMP_SIZE]);
        asm_instr_t     *instr = trampoline;
 
-       *instr++ = SDT_SAVE;
-
-       if (sdp->sdp_id > (uint32_t)SDT_SIMM13_MAX)  {
-               *instr++ = SDT_SETHI(sdp->sdp_id, SDT_REG_O0);
-               *instr++ = SDT_ORLO(SDT_REG_O0, sdp->sdp_id, SDT_REG_O0);
-       } else {
-               *instr++ = SDT_ORSIMM13(SDT_REG_G0, sdp->sdp_id, SDT_REG_O0);
+       if (sdp->sdp_ptype == SDTPT_OFFSETS) {
+               *instr++ = SDT_SAVE;
+
+               if (sdp->sdp_id > (uint32_t)SDT_SIMM13_MAX)  {
+                       *instr++ = SDT_SETHI(sdp->sdp_id, SDT_REG_O0);
+                       *instr++ = SDT_ORLO(SDT_REG_O0, sdp->sdp_id,
+                                           SDT_REG_O0);
+               } else {
+                       *instr++ = SDT_ORSIMM13(SDT_REG_G0, sdp->sdp_id,
+                                               SDT_REG_O0);
+               }
+
+               *instr++ = SDT_MOV(SDT_REG_I0, SDT_REG_O1);
+               *instr++ = SDT_MOV(SDT_REG_I1, SDT_REG_O2);
+               *instr++ = SDT_MOV(SDT_REG_I2, SDT_REG_O3);
+               *instr++ = SDT_MOV(SDT_REG_I3, SDT_REG_O4);
+               *instr = SDT_CALL(instr, dtrace_probe);
+               instr++;
+               *instr++ = SDT_MOV(SDT_REG_I4, SDT_REG_O5);
+
+               *instr++ = SDT_RET;
+               *instr++ = SDT_RESTORE;
+
+               sdp->sdp_patchval = SDT_CALL(sdp->sdp_patchpoint, trampoline);
+       } else {                                /* SDTPT_IS_ENABLED */
+               /*
+                * We want to change the insn in the delay slot,
+                * which will be the arg setup.  There is no
+                * trampoline.
+                */
+               sdp->sdp_patchpoint++; /* next insn */
+               sdp->sdp_patchval = SDT_ORSIMM13(SDT_REG_G0, 1, SDT_REG_O0);
        }
 
-       *instr++ = SDT_MOV(SDT_REG_I0, SDT_REG_O1);
-       *instr++ = SDT_MOV(SDT_REG_I1, SDT_REG_O2);
-       *instr++ = SDT_MOV(SDT_REG_I2, SDT_REG_O3);
-       *instr++ = SDT_MOV(SDT_REG_I3, SDT_REG_O4);
-       *instr = SDT_CALL(instr, dtrace_probe);
-       instr++;
-       *instr++ = SDT_MOV(SDT_REG_I4, SDT_REG_O5);
-
-       *instr++ = SDT_RET;
-       *instr++ = SDT_RESTORE;
-
-       sdp->sdp_patchval = SDT_CALL(sdp->sdp_patchpoint, trampoline);
        sdp->sdp_savedval = *sdp->sdp_patchpoint;
 }
 
index ac0226c7079da8636964663b65f5af21360a1bad..69440d2ce2e86a54befe6bb00e703e5df2e07aba 100644 (file)
@@ -21,7 +21,7 @@
  *
  * CDDL HEADER END
  *
- * Copyright 2010-2014 Oracle, Inc.  All rights reserved.
+ * Copyright 2010-2016 Oracle, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -42,14 +42,18 @@ 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;
+                       if (sdt->sdp_ptype == SDTPT_IS_ENABLED)
+                               regs->ax = 1;
+                       else {
+                               this_cpu_core->cpu_dtrace_regs = regs;
 
-                       dtrace_probe(sdt->sdp_id, regs->di, regs->si,
-                                    regs->dx, regs->cx, regs->r8);
+                               dtrace_probe(sdt->sdp_id, regs->di, regs->si,
+                                            regs->dx, regs->cx, regs->r8);
 
-                       this_cpu_core->cpu_dtrace_regs = NULL;
+                               this_cpu_core->cpu_dtrace_regs = NULL;
+                       }
 
-                       return DTRACE_INVOP_NOP;
+                       return ASM_CALL_SIZE;
                }
        }