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
*
* 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.
*/
return 0;
}
+ if (DTRACE_PROBE_ENABLED(sdt__test)) {
+ DTRACE_PROBE(sdt__test__is__enabled)
+ }
+
DTRACE_PROBE(sdt__test);
/*
#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)
*
* 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.
*/
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;
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);
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;
}
}
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;
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 */
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 */
* 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.
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;
}
*
* 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.
*/
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;
}
}