[DTrace-devel] [PATCH v2 2/2] usdt: is-enabled probe support

Nick Alcock nick.alcock at oracle.com
Wed May 17 19:50:22 UTC 2023


This implementation is in many ways similar to v1's, but contains one
significant simplification: rather than is-enabled probes appearing to
the user as a function that returns a 1 or 0, they appear as a function
that returns void and takes the address of a local variable: the
_IS_ENABLED macros use the GCC statement-expression extension
to declare and initialize a distinct local for each use of the
is-enabled probe:

	({ uint32_t enabled = 0; \
	__dtraceenabled_foo___bar(&enabled); \
	   enabled; })

The is-enabled trampoline writes a 1 into this local variable.  This
allows the dt_link code to discard all the architecture-dependent code
dealing with return value handling and treat is-enabled probes just like
other USDT probes: it still tracks whether is-enabled probes are used,
but doesn't use the info for anything but setting the DOF version.

The downside of this approach, of course, is that users need the
statement-expression extension to work, and that old is-enabled probes
from DTrace v1 aren't going to work without regeneration with dtrace
-G. Neither of these seem likely to be serious problems in practice, and
the commit before this one should help.

We use #pragma system_header to suppress -pedantic warnings about
use of the extension.

Internally, there are tiny changes in the dtprobed and dt_pid
uprobe-registration-and-creation layers to put is-enabled probes in a
different uprobe group to prevent their names clashing with USDT probes
with the same name (dt_pid_is_enabled/ rather than dt_pid/). Normal USDT
probes enable the correspondinng is-enabled probe, if any, when they are
enabled: those probes have custom trampoline that copy a 64-bit-wide 1
into the first function parameter (and have truncated parameter-copying
code that avoids preserving any parameter but the first, because there
will never be any more).

Please ignore the code duplication between trampoline() and
trampoline_is_enabled(): this is temporary to make it easier to make
changes for getting globbed systemwide probing working later on.

Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
---
 dtprobed/dtprobed.c                    |   8 +-
 libcommon/uprobes.c                    |  27 ++--
 libcommon/uprobes.h                    |  22 +--
 libdtrace/dt_link.c                    | 188 +++++++--------------
 libdtrace/dt_pid.c                     |  31 ++--
 libdtrace/dt_program.c                 |  28 ++--
 libdtrace/dt_prov_fbt.c                |   2 +-
 libdtrace/dt_prov_uprobe.c             | 215 ++++++++++++++++++++++---
 test/unittest/usdt/tst.enable.d        |   3 +-
 test/unittest/usdt/tst.enable_and.d    |   3 +-
 test/unittest/usdt/tst.enable_and_2.d  |   3 +-
 test/unittest/usdt/tst.enable_or_2.d   |   3 +-
 test/unittest/usdt/tst.enable_return.d |   3 +-
 test/unittest/usdt/tst.enable_stmt.d   |   3 +-
 test/unittest/usdt/tst.enabled.sh      |   3 +-
 15 files changed, 324 insertions(+), 218 deletions(-)

diff --git a/dtprobed/dtprobed.c b/dtprobed/dtprobed.c
index af647d92d3355..3725dba2fe1c6 100644
--- a/dtprobed/dtprobed.c
+++ b/dtprobed/dtprobed.c
@@ -1,6 +1,6 @@
 /*
  * Oracle Linux DTrace; DOF-consumption and USDT-probe-creation daemon.
- * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
@@ -323,15 +323,13 @@ create_probe(pid_t pid, dof_parsed_t *provider, dof_parsed_t *probe,
 {
 	const char *mod, *fun, *prb;
 
-	if (tp->tracepoint.is_enabled)
-		return;				/* Not yet implemented.  */
-
 	mod = probe->probe.name;
 	fun = mod + strlen(mod) + 1;
 	prb = fun + strlen(fun) + 1;
 
 	free(uprobe_create_from_addr(pid, tp->tracepoint.addr,
-		provider->provider.name, mod, fun, prb));
+		tp->tracepoint.is_enabled, provider->provider.name,
+		mod, fun, prb));
 }
 
 /*
diff --git a/libcommon/uprobes.c b/libcommon/uprobes.c
index 8a45a1f2a2b9c..8c3cc6280e9a1 100644
--- a/libcommon/uprobes.c
+++ b/libcommon/uprobes.c
@@ -1,6 +1,6 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
@@ -209,13 +209,13 @@ uprobe_decode_name(const char *name)
 }
 
 char *
-uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int isret)
+uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int isret, int is_enabled)
 {
 	char	*name;
 
-	if (asprintf(&name, "dt_pid/%c_%llx_%llx_%lx", isret ? 'r' : 'p',
-		     (unsigned long long)dev, (unsigned long long)ino,
-		     (unsigned long)addr) < 0)
+	if (asprintf(&name, "dt_pid%s/%c_%llx_%llx_%lx", is_enabled?"_is_enabled":"",
+		     isret ? 'r' : 'p', (unsigned long long)dev,
+		     (unsigned long long)ino, (unsigned long)addr) < 0)
 		return NULL;
 
 	return name;
@@ -229,7 +229,7 @@ uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int isret)
  */
 char *
 uprobe_create_named(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int isret,
-		    const char *prv, const char *mod, const char *fun,
+		    int is_enabled, const char *prv, const char *mod, const char *fun,
 		    const char *prb)
 {
 	int	fd = -1;
@@ -261,7 +261,7 @@ uprobe_create_named(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int i
 			return NULL;
 	}
 
-	name = uprobe_name(dev, ino, addr, isret);
+	name = uprobe_name(dev, ino, addr, isret, is_enabled);
 	if (!name)
 		goto out;
 
@@ -292,9 +292,10 @@ out:
  * systemwide uprobe list.)
  */
 char *
-uprobe_create(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int isret)
+uprobe_create(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int isret,
+	int is_enabled)
 {
-	return uprobe_create_named(dev, ino, addr, spec, isret,
+	return uprobe_create_named(dev, ino, addr, spec, isret, is_enabled,
 				   NULL, NULL, NULL, NULL);
 }
 
@@ -304,7 +305,7 @@ uprobe_create(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int isret)
  * are set, they are passed down as the name of the corresponding DTrace probe.
  */
 char *
-uprobe_create_from_addr(pid_t pid, uint64_t addr, const char *prv,
+uprobe_create_from_addr(pid_t pid, uint64_t addr, int is_enabled, const char *prv,
 			const char *mod, const char *fun, const char *prb)
 {
 	char *spec;
@@ -316,7 +317,7 @@ uprobe_create_from_addr(pid_t pid, uint64_t addr, const char *prv,
 		return NULL;
 
 	name = uprobe_create_named(mapp.pr_dev, mapp.pr_inum, addr, spec, 0,
-				   prv, mod, fun, prb);
+				   is_enabled, prv, mod, fun, prb);
 	free(spec);
 	return name;
 }
@@ -325,13 +326,13 @@ uprobe_create_from_addr(pid_t pid, uint64_t addr, const char *prv,
  * Destroy a uprobe for a given device, address, and spec.
  */
 int
-uprobe_delete(dev_t dev, ino_t ino, uint64_t addr, int isret)
+uprobe_delete(dev_t dev, ino_t ino, uint64_t addr, int isret, int is_enabled)
 {
 	int	fd = -1;
 	int	rc = -1;
 	char	*name;
 
-	name = uprobe_name(dev, ino, addr, isret);
+	name = uprobe_name(dev, ino, addr, isret, is_enabled);
 	if (!name)
 		goto out;
 
diff --git a/libcommon/uprobes.h b/libcommon/uprobes.h
index fde6ba40235a2..bd5f79d1cc9b9 100644
--- a/libcommon/uprobes.h
+++ b/libcommon/uprobes.h
@@ -1,6 +1,6 @@
 /*
  * Oracle Linux DTrace; simple uprobe helper functions
- * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
@@ -15,17 +15,19 @@
 
 extern char *uprobe_spec_by_addr(pid_t pid, ps_prochandle *P, uint64_t addr,
 				 prmap_t *mapp);
-extern char *uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int isret);
+extern char *uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int isret,
+			 int is_enabled);
 extern char *uprobe_create_named(dev_t dev, ino_t ino, uint64_t addr,
-				 const char *spec, int isret, const char *prv,
-				 const char *mod, const char *fun,
-				 const char *prb);
+				 const char *spec, int isret, int is_enabled,
+				 const char *prv, const char *mod,
+				 const char *fun, const char *prb);
 extern char *uprobe_create(dev_t dev, ino_t ino, uint64_t addr, const char *spec,
-			   int isret);
-extern char *uprobe_create_from_addr(pid_t pid, uint64_t addr, const char *prv,
-				     const char *mod, const char *fun,
-				     const char *prb);
-extern int uprobe_delete(dev_t dev, ino_t ino, uint64_t addr, int isret);
+			   int isret, int is_enabled);
+extern char *uprobe_create_from_addr(pid_t pid, uint64_t addr, int is_enabled,
+				     const char *prv, const char *mod,
+				     const char *fun, const char *prb);
+extern int uprobe_delete(dev_t dev, ino_t ino, uint64_t addr, int isret,
+			 int is_enabled);
 extern char *uprobe_encode_name(const char *);
 extern char *uprobe_decode_name(const char *);
 
diff --git a/libdtrace/dt_link.c b/libdtrace/dt_link.c
index 2c7ac03ca1ee2..3346720fcf62e 100644
--- a/libdtrace/dt_link.c
+++ b/libdtrace/dt_link.c
@@ -1,6 +1,6 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
@@ -775,8 +775,7 @@ dt_elf_symtab_lookup(Elf_Data *data_sym, int nsym, uintptr_t addr, uint_t shn,
 
 /*ARGSUSED*/
 static int
-dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
-    uint32_t *off)
+dt_modtext(dtrace_hdl_t *dtp, char *p, GElf_Rela *rela, uint32_t *off)
 {
 	uint32_t *ip;
 
@@ -801,25 +800,18 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
 	 * invocation. Check to see if the present instruction sequence matches
 	 * the one we would install below.
 	 */
-	if (isenabled) {
-		if (ip[0] == DT_OP_NOP) {
+	if (DT_IS_RESTORE(ip[1])) {
+		if (ip[0] == DT_OP_RET) {
 			(*off) += sizeof(ip[0]);
 			return 0;
 		}
+	} else if (DT_IS_MOV_O7(ip[1])) {
+		if (DT_IS_RETL(ip[0]))
+			return 0;
 	} else {
-		if (DT_IS_RESTORE(ip[1])) {
-			if (ip[0] == DT_OP_RET) {
-				(*off) += sizeof(ip[0]);
-				return 0;
-			}
-		} else if (DT_IS_MOV_O7(ip[1])) {
-			if (DT_IS_RETL(ip[0]))
-				return 0;
-		} else {
-			if (ip[0] == DT_OP_NOP) {
-				(*off) += sizeof(ip[0]);
-				return 0;
-			}
+		if (ip[0] == DT_OP_NOP) {
+			(*off) += sizeof(ip[0]);
+			return 0;
 		}
 	}
 
@@ -832,58 +824,32 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
 		return -1;
 	}
 
-	if (isenabled) {
-		/*
-		 * It would necessarily indicate incorrect usage if an is-
-		 * enabled probe were tail-called so flag that as an error.
-		 * It's also potentially (very) tricky to handle gracefully,
-		 * but could be done if this were a desired use scenario.
-		 */
-		if (DT_IS_RESTORE(ip[1]) || DT_IS_MOV_O7(ip[1])) {
-			dt_dprintf("tail call to is-enabled probe at %llx\n",
-			    (unsigned long long)rela->r_offset);
-			return -1;
-		}
-
-
-		/*
-		 * On SPARC, we take advantage of the fact that the first
-		 * argument shares the same register as for the return value.
-		 * The macro handles the work of zeroing that register so we
-		 * don't need to do anything special here. We instrument the
-		 * instruction in the delay slot as we'll need to modify the
-		 * return register after that instruction has been emulated.
-		 */
-		ip[0] = DT_OP_NOP;
+	/*
+	 * If the call is followed by a restore, it's a tail call so
+	 * change the call to a ret. If the call if followed by a mov
+	 * of a register into %o7, it's a tail call in leaf context
+	 * so change the call to a retl-like instruction that returns
+	 * to that register value + 8 (rather than the typical %o7 +
+	 * 8); the delay slot instruction is left, but should have no
+	 * effect. Otherwise we change the call to be a nop. We
+	 * identify the subsequent instruction as the probe point in
+	 * all but the leaf tail-call case to ensure that arguments to
+	 * the probe are complete and consistent. An astute, though
+	 * largely hypothetical, observer would note that there is the
+	 * possibility of a false-positive probe firing if the function
+	 * contained a branch to the instruction in the delay slot of
+	 * the call. Fixing this would require significant in-kernel
+	 * modifications, and isn't worth doing until we see it in the
+	 * wild.
+	 */
+	if (DT_IS_RESTORE(ip[1])) {
+		ip[0] = DT_OP_RET;
 		(*off) += sizeof(ip[0]);
+	} else if (DT_IS_MOV_O7(ip[1])) {
+		ip[0] = DT_MAKE_RETL(DT_RS2(ip[1]));
 	} else {
-		/*
-		 * If the call is followed by a restore, it's a tail call so
-		 * change the call to a ret. If the call if followed by a mov
-		 * of a register into %o7, it's a tail call in leaf context
-		 * so change the call to a retl-like instruction that returns
-		 * to that register value + 8 (rather than the typical %o7 +
-		 * 8); the delay slot instruction is left, but should have no
-		 * effect. Otherwise we change the call to be a nop. We
-		 * identify the subsequent instruction as the probe point in
-		 * all but the leaf tail-call case to ensure that arguments to
-		 * the probe are complete and consistent. An astute, though
-		 * largely hypothetical, observer would note that there is the
-		 * possibility of a false-positive probe firing if the function
-		 * contained a branch to the instruction in the delay slot of
-		 * the call. Fixing this would require significant in-kernel
-		 * modifications, and isn't worth doing until we see it in the
-		 * wild.
-		 */
-		if (DT_IS_RESTORE(ip[1])) {
-			ip[0] = DT_OP_RET;
-			(*off) += sizeof(ip[0]);
-		} else if (DT_IS_MOV_O7(ip[1])) {
-			ip[0] = DT_MAKE_RETL(DT_RS2(ip[1]));
-		} else {
-			ip[0] = DT_OP_NOP;
-			(*off) += sizeof(ip[0]);
-		}
+		ip[0] = DT_OP_NOP;
+		(*off) += sizeof(ip[0]);
 	}
 
 	return 0;
@@ -895,13 +861,9 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
 #define	DT_OP_RET		0xc3
 #define	DT_OP_CALL		0xe8
 #define	DT_OP_JMP32		0xe9
-#define	DT_OP_REX_RAX		0x48
-#define	DT_OP_XOR_EAX_0		0x33
-#define	DT_OP_XOR_EAX_1		0xc0
 
 static int
-dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
-    uint32_t *off)
+dt_modtext(dtrace_hdl_t *dtp, char *p, GElf_Rela *rela, uint32_t *off)
 {
 	uint8_t *ip = (uint8_t *)(p + rela->r_offset - 1);
 	uint8_t ret;
@@ -924,37 +886,20 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
 	 */
 	if (GELF_R_TYPE(rela->r_info) != R_386_PC32 &&
 	    GELF_R_TYPE(rela->r_info) != R_386_PLT32 &&
-	    GELF_R_TYPE(rela->r_info) != R_386_NONE)
+	    GELF_R_TYPE(rela->r_info) != R_386_NONE) {
+		dt_dprintf("unexpected reloc type %li\n", GELF_R_TYPE(rela->r_info));
 		return -1;
+	}
 
 	/*
 	 * We may have already processed this object file in an earlier linker
 	 * invocation. Check to see if the present instruction sequence matches
-	 * the one we would install. For is-enabled probes, we advance the
-	 * offset to the first nop instruction in the sequence to match the
-	 * text modification code below.
+	 * the one we would install.
 	 */
-	if (!isenabled) {
-		if ((ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET) &&
-		    ip[1] == DT_OP_NOP && ip[2] == DT_OP_NOP &&
-		    ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP)
-			return 0;
-	} else if (dtp->dt_oflags & DTRACE_O_ILP32) {
-		if (ip[0] == DT_OP_XOR_EAX_0 && ip[1] == DT_OP_XOR_EAX_1 &&
-		    (ip[2] == DT_OP_NOP || ip[2] == DT_OP_RET) &&
-		    ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) {
-			(*off) += 2;
-			return 0;
-		}
-	} else {
-		if (ip[0] == DT_OP_REX_RAX &&
-		    ip[1] == DT_OP_XOR_EAX_0 && ip[2] == DT_OP_XOR_EAX_1 &&
-		    (ip[3] == DT_OP_NOP || ip[3] == DT_OP_RET) &&
-		    ip[4] == DT_OP_NOP) {
-			(*off) += 3;
-			return 0;
-		}
-	}
+	if ((ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET) &&
+	    ip[1] == DT_OP_NOP && ip[2] == DT_OP_NOP &&
+	    ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP)
+		return 0;
 
 	/*
 	 * We expect either a call instrution with a 32-bit displacement or a
@@ -969,33 +914,13 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
 	ret = (ip[0] == DT_OP_JMP32) ? DT_OP_RET : DT_OP_NOP;
 
 	/*
-	 * Establish the instruction sequence -- all nops for probes, and an
-	 * instruction to clear the return value register (%eax/%rax) followed
-	 * by nops for is-enabled probes. For is-enabled probes, we advance
-	 * the offset to the first nop. This isn't stricly necessary but makes
-	 * for more readable disassembly when the probe is enabled.
+	 * Establish the instruction sequence: all nops.
 	 */
-	if (!isenabled) {
-		ip[0] = ret;
-		ip[1] = DT_OP_NOP;
-		ip[2] = DT_OP_NOP;
-		ip[3] = DT_OP_NOP;
-		ip[4] = DT_OP_NOP;
-	} else if (dtp->dt_oflags & DTRACE_O_ILP32) {
-		ip[0] = DT_OP_XOR_EAX_0;
-		ip[1] = DT_OP_XOR_EAX_1;
-		ip[2] = ret;
-		ip[3] = DT_OP_NOP;
-		ip[4] = DT_OP_NOP;
-		(*off) += 2;
-	} else {
-		ip[0] = DT_OP_REX_RAX;
-		ip[1] = DT_OP_XOR_EAX_0;
-		ip[2] = DT_OP_XOR_EAX_1;
-		ip[3] = ret;
-		ip[4] = DT_OP_NOP;
-		(*off) += 3;
-	}
+	ip[0] = ret;
+	ip[1] = DT_OP_NOP;
+	ip[2] = DT_OP_NOP;
+	ip[3] = DT_OP_NOP;
+	ip[4] = DT_OP_NOP;
 
 	return 0;
 }
@@ -1008,8 +933,7 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
 #define	DT_OP_JUMP26		0x14000000
 
 static int
-dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
-    uint32_t *off)
+dt_modtext(dtrace_hdl_t *dtp, char *p, GElf_Rela *rela, uint32_t *off)
 {
 	uint32_t *ip;
 
@@ -1050,11 +974,9 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
 	}
 
 	/*
-	 * On arm64, we do not have to differentiate between regular probes and
-	 * is-enabled probes.  Both cases are encoded as a regular branch for
-	 * non-tail call locations, and a jump for tail call locations.  Calls
-	 * are to be converted into a no-op whereas jumps should become a
-	 * return.
+	 * On arm64, we encode all probes as a regular branch for non-tail call
+	 * locations, and a jump for tail call locations.  Calls are to be
+	 * converted into a no-op whereas jumps should become a return.
 	 */
 	if (ip[0] == DT_OP_CALL26)
 		ip[0] = DT_OP_NOP;
@@ -1502,10 +1424,8 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
 			assert(fsym.st_value <= rela.r_offset);
 
 			off = rela.r_offset - fsym.st_value;
-			if (dt_modtext(dtp, data_tgt->d_buf, eprobe,
-			    &rela, &off) != 0) {
+			if (dt_modtext(dtp, data_tgt->d_buf, &rela, &off) != 0)
 				goto err;
-			}
 
 			if (dt_probe_define(pvp, prp, s, r, off, eprobe) != 0)
 				return dt_link_error(dtp, elf, fd, bufs,
diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c
index fd9e0d1da62dd..06bd7a4dd24aa 100644
--- a/libdtrace/dt_pid.c
+++ b/libdtrace/dt_pid.c
@@ -1,6 +1,6 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
@@ -626,6 +626,8 @@ dt_pid_create_usdt_probes(dtrace_hdl_t *dtp, dt_proc_t *dpr,
 		dev_t dev;
 		ino_t inum;
 		uint64_t off;
+		int is_enabled;
+		const char *fmt;
 		unsigned long long dev_ll, inum_ll;
 		char *inum_str = NULL;
 		char *spec = NULL;
@@ -634,11 +636,23 @@ dt_pid_create_usdt_probes(dtrace_hdl_t *dtp, dt_proc_t *dpr,
 		pid_probespec_t psp;
 
 #define UPROBE_PREFIX "p:dt_pid/p_"
-		if (strncmp(buf, UPROBE_PREFIX, strlen(UPROBE_PREFIX)) != 0)
+#define UPROBE_IS_ENABLED_PREFIX "p:dt_pid_is_enabled/p_"
+#define UPROBE_PROBE_FMT "%llx_%llx_%lx %ms P%m[^= ]=\\1 M%m[^= ]=\\2 F%m[^= ]=\\3 N%m[^= ]=\\4"
+#define UPROBE_FMT UPROBE_PREFIX UPROBE_PROBE_FMT
+#define UPROBE_IS_ENABLED_FMT UPROBE_IS_ENABLED_PREFIX UPROBE_PROBE_FMT
+
+		if (strncmp(buf, UPROBE_PREFIX, strlen(UPROBE_PREFIX)) == 0) {
+			is_enabled = 0;
+			fmt = UPROBE_FMT;
+		} else if (strncmp(buf, UPROBE_IS_ENABLED_PREFIX,
+			strlen(UPROBE_IS_ENABLED_PREFIX)) == 0) {
+			is_enabled = 1;
+			fmt = UPROBE_IS_ENABLED_FMT;
+		}
+		else /* Not a DTrace uprobe. */
 			continue;
 
-		switch (sscanf(buf, "p:dt_pid/p_%llx_%llx_%lx %ms "
-			       "P%m[^= ]=\\1 M%m[^= ]=\\2 F%m[^= ]=\\3 N%m[^= ]=\\4", &dev_ll, &inum_ll,
+		switch (sscanf(buf, fmt, &dev_ll, &inum_ll,
 			       &off, &spec, &eprv, &emod, &efun, &eprb)) {
 		case 8: /* Includes dtrace probe names: decode them. */
 			prv = uprobe_decode_name(eprv);
@@ -664,9 +678,7 @@ dt_pid_create_usdt_probes(dtrace_hdl_t *dtp, dt_proc_t *dpr,
 		 * Make the underlying probe, if not already present.
 		 */
 		memset(&psp, 0, sizeof(pid_probespec_t));
-
-		/* FIXME: DTPPT_IS_ENABLED needs to be supported also.  */
-		psp.pps_type = DTPPT_OFFSETS;
+		psp.pps_type = is_enabled ? DTPPT_IS_ENABLED : DTPPT_OFFSETS;
 
 		/*
 		 * These components are only used for creation of an underlying
@@ -732,8 +744,9 @@ dt_pid_create_usdt_probes(dtrace_hdl_t *dtp, dt_proc_t *dpr,
 
 		if (pvp->impl->provide_probe(dtp, &psp) < 0 && pdp) {
 			dt_pid_error(dtp, pcb, dpr, D_PROC_USDT,
-				     "failed to instantiate probe %s for pid %d: %s",
-				     pdp->prb, dpr->dpr_pid,
+				     "failed to instantiate %sprobe %s for pid %d: %s",
+				     is_enabled ? "is-enabled ": "", pdp->prb,
+				     dpr->dpr_pid,
 				     dtrace_errmsg(dtp, dtrace_errno(dtp)));
 			ret = -1;
 		}
diff --git a/libdtrace/dt_program.c b/libdtrace/dt_program.c
index a95d0eefdb1a2..a4b052fc47603 100644
--- a/libdtrace/dt_program.c
+++ b/libdtrace/dt_program.c
@@ -1,6 +1,6 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
@@ -368,12 +368,8 @@ dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
 		return dt_set_errno(dtp, errno);
 
 	if (fprintf(infop->dthi_out,
-	    "#if !defined(__aarch64__) && !defined(__sparc)\n"
-	    "extern int __dtraceenabled_%s___%s(void);\n"
-	    "#else\n"
-	    "extern int __dtraceenabled_%s___%s(long);\n"
-	    "#endif\n",
-	    infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)
+	    "extern void __dtraceenabled_%s___%s(uint32_t *flag);\n",
+	    infop->dthi_pfname, fname) < 0)
 		return dt_set_errno(dtp, errno);
 
 	return 0;
@@ -436,17 +432,18 @@ dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
 
 	if (!infop->dthi_empty) {
 		if (fprintf(infop->dthi_out,
-		    "#if !defined(__aarch64__) && !defined(__sparc)\n"
+		    "#ifdef __GNUC__\n"
 		    "#define\t%s_%s_ENABLED() \\\n"
-		    "\t__dtraceenabled_%s___%s()\n"
+		    "\t({ uint32_t enabled = 0; \\\n"
+		    "\t__dtraceenabled_%s___%s(&enabled); \\\n"
+		    "\t   enabled; })\n"
 		    "#else\n"
-		    "#define\t%s_%s_ENABLED() \\\n"
-		    "\t__dtraceenabled_%s___%s(0)\n"
+		    "#define\t%s_%s_ENABLED() (1)\\n"
+		    "#endif\n"
 		    "#endif\n",
 		    infop->dthi_pmname, mname,
 		    infop->dthi_pfname, fname,
-		    infop->dthi_pmname, mname,
-		    infop->dthi_pfname, fname) < 0)
+		    infop->dthi_pmname, mname) < 0)
 			return dt_set_errno(dtp, errno);
 
 	} else {
@@ -536,6 +533,11 @@ dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
 	if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
 		return -1;
 
+	if (fprintf(out, "#ifdef\t__GNUC__\n"
+		"#pragma GCC system_header\n"
+		"#endif\n\n") < 0)
+		return -1;
+
 	while ((pvp = dt_htab_next(dtp->dt_provs, &it)) != NULL) {
 		if (dt_header_provider(dtp, pvp, out) != 0) {
 			dt_htab_next_destroy(it);
diff --git a/libdtrace/dt_prov_fbt.c b/libdtrace/dt_prov_fbt.c
index add76c55f3ae8..ee848b453e9af 100644
--- a/libdtrace/dt_prov_fbt.c
+++ b/libdtrace/dt_prov_fbt.c
@@ -1,6 +1,6 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  *
diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
index f85d15297e910..32b6996762b3f 100644
--- a/libdtrace/dt_prov_uprobe.c
+++ b/libdtrace/dt_prov_uprobe.c
@@ -1,6 +1,6 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  *
@@ -23,13 +23,15 @@
 #include "uprobes.h"
 
 /* Provider name for the underlying probes. */
-static const char		prvname[] = "uprobe";
+static const char	prvname[] = "uprobe";
+static const char	prvname_is_enabled[] = "uprobe__is_enabled";
 
-#define UPROBE_EVENTS		TRACEFS "uprobe_events"
+#define UPROBE_EVENTS	TRACEFS "uprobe_events"
 
 #define PP_IS_MINE	1
 #define PP_IS_RETURN	2
 #define PP_IS_FUNCALL	4
+#define PP_IS_ENABLED	8
 
 typedef struct dt_uprobe {
 	dev_t		dev;
@@ -54,12 +56,15 @@ static const dtrace_pattr_t	pattr = {
 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
 };
 
+dt_provimpl_t	dt_uprobe_is_enabled;
 dt_provimpl_t	dt_pid;
 dt_provimpl_t	dt_usdt;
 
 static int populate(dtrace_hdl_t *dtp)
 {
 	dt_provider_create(dtp, dt_uprobe.name, &dt_uprobe, &pattr);
+	dt_provider_create(dtp, dt_uprobe_is_enabled.name,
+			   &dt_uprobe_is_enabled, &pattr);
 	dt_provider_create(dtp, dt_pid.name, &dt_pid, &pattr);
 	dt_provider_create(dtp, dt_usdt.name, &dt_usdt, &pattr);
 
@@ -115,6 +120,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
 	dtrace_probedesc_t	pd;
 	dt_probe_t		*prp;
 	dt_uprobe_t		*upp;
+	int			is_enabled = 0;
 
 	/*
 	 * The underlying probes (uprobes) represent the tracepoints that pid
@@ -136,6 +142,9 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
 	case DTPPT_RETURN:
 		strcpy(prb, "return");
 		break;
+	case DTPPT_IS_ENABLED:
+		is_enabled = 1;
+		/* Fallthrough. */
 	case DTPPT_ENTRY:
 	case DTPPT_OFFSETS:
 		snprintf(prb, sizeof(prb), "%lx", psp->pps_off);
@@ -146,7 +155,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
 	}
 
 	pd.id = DTRACE_IDNONE;
-	pd.prv = prvname;
+	pd.prv = is_enabled ? prvname_is_enabled : prvname;
 	pd.mod = mod;
 	pd.fun = psp->pps_fun;
 	pd.prb = prb;
@@ -156,7 +165,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
 		dt_provider_t	*pvp;
 
 		/* Get the provider for underlying probes. */
-		pvp = dt_provider_lookup(dtp, prvname);
+		pvp = dt_provider_lookup(dtp, pd.prv);
 		if (pvp == NULL)
 			return NULL;
 
@@ -181,8 +190,18 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
 	} else
 		upp = prp->prv_data;
 
-	if (psp->pps_type == DTPPT_RETURN)
-		upp->flags |= PP_IS_RETURN;
+	switch (psp->pps_type) {
+	case DTPPT_RETURN:
+	    upp->flags |= PP_IS_RETURN;
+	    break;
+	case DTPPT_IS_ENABLED:
+	    upp->flags |= PP_IS_ENABLED;
+	    break;
+	default: ;
+	    /*
+	     * No flags needed for other types.
+	     */
+	}
 
 	return prp;
 
@@ -302,7 +321,8 @@ static int provide_pid_probe(dtrace_hdl_t *dtp, const pid_probespec_t *psp)
 
 static int provide_usdt_probe(dtrace_hdl_t *dtp, const pid_probespec_t *psp)
 {
-	if (psp->pps_type != DTPPT_OFFSETS) {
+	if (psp->pps_type != DTPPT_OFFSETS &&
+	    psp->pps_type != DTPPT_IS_ENABLED) {
 		dt_dprintf("pid: unknown USDT probe type %i\n", psp->pps_type);
 		return -1;
 	}
@@ -310,7 +330,7 @@ static int provide_usdt_probe(dtrace_hdl_t *dtp, const pid_probespec_t *psp)
 	return provide_probe(dtp, psp, psp->pps_prb, &dt_usdt, PP_IS_FUNCALL);
 }
 
-static void enable(dtrace_hdl_t *dtp, dt_probe_t *prp)
+static void enable(dtrace_hdl_t *dtp, dt_probe_t *prp, int is_usdt)
 {
 	const list_probe_t	*pup;
 
@@ -318,12 +338,26 @@ static void enable(dtrace_hdl_t *dtp, dt_probe_t *prp)
 
 	/*
 	 * We need to enable the underlying probes (if not enabled yet).
+	 *
+	 * If necessary, we need to enable is-enabled probes too (if they
+	 * exist).
 	 */
 	for (pup = prp->prv_data; pup != NULL; pup = dt_list_next(pup)) {
 		dt_probe_t *uprp = pup->probe;
 		dt_probe_enable(dtp, uprp);
 	}
 
+	if (is_usdt) {
+		dtrace_probedesc_t pd;
+		dt_probe_t *iep;
+
+		memcpy(&pd, &prp->desc, sizeof(pd));
+		pd.prv = prvname_is_enabled;
+		iep = dt_probe_lookup(dtp, &pd);
+		if (iep != NULL)
+			dt_probe_enable(dtp, iep);
+	}
+
 	/*
 	 * Finally, ensure we're in the list of enablings as well.
 	 * (This ensures that, among other things, the probes map
@@ -333,13 +367,26 @@ static void enable(dtrace_hdl_t *dtp, dt_probe_t *prp)
 		dt_list_append(&dtp->dt_enablings, prp);
 }
 
+static void enable_pid(dtrace_hdl_t *dtp, dt_probe_t *prp)
+{
+	enable(dtp, prp, 0);
+}
+
+/*
+ * USDT enabling has to enable any is-enabled probes as well.
+ */
+static void enable_usdt(dtrace_hdl_t *dtp, dt_probe_t *prp)
+{
+	enable(dtp, prp, 1);
+}
+
 /*
- * Generate a BPF trampoline for a pid probe.
+ * Generate a BPF trampoline for a pid or USDT probe.
  *
- * The trampoline function is called when a pid probe triggers, and it must
- * satisfy the following prototype:
+ * The trampoline function is called when one of these probes triggers, and it
+ * must satisfy the following prototype:
  *
- *	int dt_pid(dt_pt_regs *regs)
+ *	int dt_uprobe(dt_pt_regs *regs)
  *
  * The trampoline will first populate a dt_dctx_t struct.  It will then emulate
  * the firing of all dependent pid* probes and their clauses.
@@ -420,6 +467,120 @@ static void trampoline(dt_pcb_t *pcb, uint_t exitlbl)
 	dt_cg_tramp_return(pcb);
 }
 
+/*
+ * Copy the given immediate value into the address given by the specified probe
+ * argument.
+ */
+static void
+copyout_val(dt_pcb_t *pcb, uint_t lbl, uint32_t val, int arg)
+{
+	dt_regset_t	*drp = pcb->pcb_regs;
+	dt_irlist_t	*dlp = &pcb->pcb_ir;
+
+	emitl(dlp, lbl, BPF_STORE_IMM(BPF_DW, BPF_REG_FP, DT_TRAMP_SP_SLOT(0),
+		val));
+
+	if (dt_regset_xalloc_args(drp) == -1)
+		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+	emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_7, DMST_ARG(arg)));
+	emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_FP));
+	emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, DT_TRAMP_SP_SLOT(0)));
+	emit(dlp, BPF_MOV_IMM(BPF_REG_3, sizeof(uint32_t)));
+	dt_regset_xalloc(drp, BPF_REG_0);
+	emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_write_user));
+
+	/* XXX any point error-checking here? What can we possibly do? */
+	dt_regset_free(drp, BPF_REG_0);
+	dt_regset_free_args(drp);
+}
+
+/*
+ * Generate a BPF trampoline for an is-enabled probe.  The is-enabled probe
+ * prototype looks like:
+ *
+ *	int is_enabled(int *arg)
+ *
+ * The trampoline dereferences the passed-in arg and writes 1 into it if this is
+ * one of the processes for which the probe is enabled.
+ */
+static void trampoline_is_enabled(dt_pcb_t *pcb, uint_t exitlbl)
+{
+	dt_irlist_t		*dlp = &pcb->pcb_ir;
+	const dt_probe_t	*prp = pcb->pcb_probe;
+	const dt_uprobe_t	*upp = prp->prv_data;
+	const list_probe_t	*pop;
+	uint_t			lbl_assign = dt_irlist_label(dlp);
+	uint_t			lbl_exit = pcb->pcb_exitlbl;
+
+	dt_cg_tramp_prologue(pcb);
+
+	/*
+	 * After the dt_cg_tramp_prologue() call, we have:
+	 *				//     (%r7 = dctx->mst)
+	 *				//     (%r8 = dctx->ctx)
+	 */
+
+	dt_cg_tramp_copy_regs(pcb);
+
+	/*
+	 * Copy in the first function argument, a pointer value to which
+	 * the is-enabled state of the probe will be written (necessarily
+	 * 1 if this probe is running at all).
+	 */
+	emit(dlp,  BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_8, PT_REGS_ARG0));
+	emit(dlp,  BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_0));
+
+	/*
+	 * Retrieve the PID of the process that caused the probe to fire.
+	 */
+	emit(dlp,  BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid));
+	emit(dlp,  BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
+
+	/*
+	 * Generate a composite conditional clause, as above, except that rather
+	 * than emitting call_clauses, we emit copyouts instead, using
+	 * copyout_val() above:
+	 *
+	 *	if (pid == PID1) {
+	 *		goto assign;
+	 *	} else if (pid == PID2) {
+	 *		goto assign;
+	 *	} else if (pid == ...) {
+	 *		goto assign;
+	 *	}
+	 *	goto exit;
+	 *	assign:
+	 *	    *arg0 = 1;
+	 *	goto exit;
+	 *
+	 * It is valid and safe to use %r0 to hold the pid value because there
+	 * are no assignments to %r0 possible in between the conditional
+	 * statements.
+	 */
+	for (pop = dt_list_next(&upp->probes); pop != NULL;
+	     pop = dt_list_next(pop)) {
+		const dt_probe_t	*pprp = pop->probe;
+		pid_t			pid;
+		dt_ident_t		*idp;
+
+		pid = dt_pid_get_pid(pprp->desc, pcb->pcb_hdl, pcb, NULL);
+		assert(pid != -1);
+
+		idp = dt_dlib_add_probe_var(pcb->pcb_hdl, pprp);
+		assert(idp != NULL);
+
+		/*
+		 * Check whether this pid-provider probe serves the current
+		 * process, and copy out a 1 into arg 0 if so.
+		 */
+		emit(dlp,  BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_0, pid, lbl_assign));
+	}
+	emit(dlp,  BPF_JUMP(lbl_exit));
+	copyout_val(pcb, lbl_assign, 1, 0);
+
+	dt_cg_tramp_return(pcb);
+}
+
 static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
 {
 	dt_uprobe_t	*upp = prp->prv_data;
@@ -441,7 +602,7 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
 			return -ENOENT;
 
 		prb = uprobe_create(upp->dev, upp->inum, upp->off, spec,
-				    upp->flags & PP_IS_RETURN);
+				    upp->flags & PP_IS_RETURN, 0);
 		free(spec);
 
 		/*
@@ -453,7 +614,8 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
 
 	if (prb == NULL)
 		prb = uprobe_name(upp->dev, upp->inum, upp->off,
-				  upp->flags & PP_IS_RETURN);
+				  upp->flags & PP_IS_RETURN,
+				  upp->flags & PP_IS_ENABLED);
 
 	/* open format file */
 	rc = asprintf(&fn, "%s%s/format", EVENTSFS, prb);
@@ -509,8 +671,9 @@ static void detach(dtrace_hdl_t *dtp, const dt_probe_t *prp)
 	if (!(upp->flags & PP_IS_MINE))
 		return;
 
-	uprobe_delete(upp->dev, upp->inum, upp->off, upp->flags & PP_IS_RETURN);
-}
+	uprobe_delete(upp->dev, upp->inum, upp->off, upp->flags & PP_IS_RETURN,
+		      upp->flags & PP_IS_ENABLED);
+	}
 
 /*
  * Used for underlying probes (uprobes).
@@ -526,6 +689,20 @@ dt_provimpl_t	dt_uprobe = {
 	.probe_destroy	= &probe_destroy_underlying,
 };
 
+/*
+ * Used for underlying is-enabled uprobes.
+ */
+dt_provimpl_t	dt_uprobe_is_enabled = {
+	.name		= prvname_is_enabled,
+	.prog_type	= BPF_PROG_TYPE_KPROBE,
+	.populate	= &populate,
+	.trampoline	= &trampoline_is_enabled,
+	.attach		= &attach,
+	.probe_info	= &probe_info,
+	.detach		= &detach,
+	.probe_destroy	= &probe_destroy_underlying,
+};
+
 /*
  * Used for pid probes.
  */
@@ -533,7 +710,7 @@ dt_provimpl_t	dt_pid = {
 	.name		= "pid",
 	.prog_type	= BPF_PROG_TYPE_UNSPEC,
 	.provide_probe	= &provide_pid_probe,
-	.enable		= &enable,
+	.enable		= &enable_pid,
 	.probe_destroy	= &probe_destroy,
 };
 
@@ -544,6 +721,6 @@ dt_provimpl_t	dt_usdt = {
 	.name		= "usdt",
 	.prog_type	= BPF_PROG_TYPE_UNSPEC,
 	.provide_probe	= &provide_usdt_probe,
-	.enable		= &enable,
+	.enable		= &enable_usdt,
 	.probe_destroy	= &probe_destroy,
 };
diff --git a/test/unittest/usdt/tst.enable.d b/test/unittest/usdt/tst.enable.d
index 1211af97290ad..a95eee2009174 100644
--- a/test/unittest/usdt/tst.enable.d
+++ b/test/unittest/usdt/tst.enable.d
@@ -1,11 +1,10 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
 
-/* @@xfail: dtv2, no is-enabled probes yet */
 /* @@trigger: usdt-tst-special 2 */
 
 #pragma D option quiet
diff --git a/test/unittest/usdt/tst.enable_and.d b/test/unittest/usdt/tst.enable_and.d
index 94a053ef43bbb..9715c9c11eaa4 100644
--- a/test/unittest/usdt/tst.enable_and.d
+++ b/test/unittest/usdt/tst.enable_and.d
@@ -1,11 +1,10 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
 
-/* @@xfail: dtv2, no is-enabled probes yet */
 /* @@trigger: usdt-tst-special 5 */
 
 #pragma D option quiet
diff --git a/test/unittest/usdt/tst.enable_and_2.d b/test/unittest/usdt/tst.enable_and_2.d
index 3b2963f4330bc..47e8feb59825f 100644
--- a/test/unittest/usdt/tst.enable_and_2.d
+++ b/test/unittest/usdt/tst.enable_and_2.d
@@ -1,11 +1,10 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
 
-/* @@xfail: dtv2, no is-enabled probes yet */
 /* @@trigger: usdt-tst-special 6 */
 
 #pragma D option quiet
diff --git a/test/unittest/usdt/tst.enable_or_2.d b/test/unittest/usdt/tst.enable_or_2.d
index 6b599544fe9f4..c384cddfb8db4 100644
--- a/test/unittest/usdt/tst.enable_or_2.d
+++ b/test/unittest/usdt/tst.enable_or_2.d
@@ -1,11 +1,10 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
 
-/* @@xfail: dtv2, no is-enabled probes yet */
 /* @@trigger: usdt-tst-special 4 */
 
 #pragma D option quiet
diff --git a/test/unittest/usdt/tst.enable_return.d b/test/unittest/usdt/tst.enable_return.d
index 0d727b8a6d0c9..2e7b41f91c7b9 100644
--- a/test/unittest/usdt/tst.enable_return.d
+++ b/test/unittest/usdt/tst.enable_return.d
@@ -1,11 +1,10 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
 
-/* @@xfail: dtv2, no is-enabled probes yet */
 /* @@trigger: usdt-tst-special 8 */
 
 #pragma D option quiet
diff --git a/test/unittest/usdt/tst.enable_stmt.d b/test/unittest/usdt/tst.enable_stmt.d
index 5c26919f764d6..37e106bf6d1d1 100644
--- a/test/unittest/usdt/tst.enable_stmt.d
+++ b/test/unittest/usdt/tst.enable_stmt.d
@@ -1,11 +1,10 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
 
-/* @@xfail: dtv2, no is-enabled probes yet */
 /* @@trigger: usdt-tst-special 7 */
 
 #pragma D option quiet
diff --git a/test/unittest/usdt/tst.enabled.sh b/test/unittest/usdt/tst.enabled.sh
index 5363172fd8b4b..2c0a5b405e7a5 100755
--- a/test/unittest/usdt/tst.enabled.sh
+++ b/test/unittest/usdt/tst.enabled.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 #
 # Oracle Linux DTrace.
-# Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
 # Licensed under the Universal Permissive License v 1.0 as shown at
 # http://oss.oracle.com/licenses/upl.
 #
@@ -9,7 +9,6 @@ if [ $# != 1 ]; then
 	echo expected one argument: '<'dtrace-path'>'
 	exit 2
 fi
-# @@xfail: dtv2, no is-enabled probes yet
 
 dtrace=$1
 CC=/usr/bin/gcc
-- 
2.39.1.268.g9de2f9a303




More information about the DTrace-devel mailing list