[DTrace-devel] [PATCH 3/3] add BEGIN and END probes

eugene.loh at oracle.com eugene.loh at oracle.com
Thu Mar 26 15:30:58 PDT 2020


From: Eugene Loh <eugene.loh at oracle.com>

Add BEGIN and END probes as uprobes on libdtrace functions
BEGIN_probe() and END_probe(), which were added as part of
an earlier patch.  Name the probes with the consumer's PID
so that multiple consumers, with distinct or changing libdtrace,
can coexist.  So we try to clean up uprobe_events at close.

Note two naming conventions:
*)  We prefix many general functions with "dtrace".
*)  We prefix dt_provimpl_t functions with the provider name.
So two functions would expect to have the name dtrace_probe_info().
To resolve this conflict, we prefix dt_provimpl_t functions with
"dtrace_prov" for the dtrace provider.

The trampoline code was added in an earlier patch;  here we
just clean up some associated comments.

Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
 libdtrace/dt_prov_dtrace.c | 144 ++++++++++++++++++++++++++++++++++---
 libdtrace/dt_prov_fbt.c    |   2 +-
 2 files changed, 135 insertions(+), 11 deletions(-)

diff --git a/libdtrace/dt_prov_dtrace.c b/libdtrace/dt_prov_dtrace.c
index b2327dc2..d57339bf 100644
--- a/libdtrace/dt_prov_dtrace.c
+++ b/libdtrace/dt_prov_dtrace.c
@@ -7,6 +7,7 @@
  * The core probe provider for DTrace for the BEGIN, END, and ERROR probes.
  */
 #include <assert.h>
+#include <errno.h>
 #include <string.h>
 
 #include <bpf_asm.h>
@@ -22,7 +23,95 @@ static const dtrace_pattr_t	pattr = {
 { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
 };
 
-static int dtrace_populate(dtrace_hdl_t *dtp)
+#define UPROBE_EVENTS		TRACEFS "uprobe_events"
+
+/*
+ * For a libdtrace function name, return path:offset.
+ */
+static int dt_get_path_off(char *func, char *path_off, int len) {
+	struct ps_prochandle *P;
+	int perr = 0, rc = 1;
+	GElf_Sym sym;
+	prsyminfo_t si;
+	const prmap_t *pmptr;
+
+	/* grab our process */
+	P = Pgrab(getpid(), 2, 0, NULL, &perr);
+	if (P == NULL)
+		return 1; /* FIXME: do something with perr? */
+
+	/* lookup the libdtrace function */
+	if (Pxlookup_by_name(P, -1, PR_OBJ_EVERY, func, &sym, &si))
+		goto done;
+
+	/* get the map */
+	pmptr = Paddr_to_map(P, sym.st_value);
+	if (pmptr == NULL)
+		goto done;
+
+	/* now put it all together */
+	if (snprintf(path_off, len, "%s:0x%lx", pmptr->pr_file->prf_mapname, sym.st_value - pmptr->pr_vaddr) >= len)
+		goto done;
+
+	rc = 0;
+
+done:
+	Prelease(P, PS_RELEASE_NORMAL);
+	Pfree(P);
+	return rc;
+}
+
+static int dtrace_prov_probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
+			     int *idp, int *argcp, dt_argdesc_t **argvp)
+{
+	FILE	*f;
+	int	rc, fd;
+	char	fname[16];	/* name of libdtrace function we will probe */
+	char	ename[16];	/* uprobe event name we will use */
+	char	pname[256];	/* some path name */
+
+	*idp = -1;
+	*argcp = 0;
+	*argvp = NULL;
+
+	/* form fname and ename for this probe */
+	if (strcmp(prp->desc->prb, "BEGIN") == 0) {
+		snprintf(fname, sizeof (fname), "BEGIN_probe");
+		snprintf(ename, sizeof (ename), "BEGIN_%d", getpid());
+	} else if (strcmp(prp->desc->prb, "END") == 0) {
+		snprintf(fname, sizeof (fname), "END_probe");
+		snprintf(ename, sizeof (ename), "END_%d", getpid());
+	} else if (strcmp(prp->desc->prb, "ERROR") == 0)
+		assert(0); /* FIXME: not yet supported */
+	else
+		assert(0); /* unknown probe */
+
+	/* form path:offset for the function */
+	if (dt_get_path_off(fname, pname, sizeof (pname)))
+		return -ENOENT;
+
+	/* add a uprobe for this function */
+	fd = open(UPROBE_EVENTS, O_WRONLY | O_APPEND);
+	if (fd == -1)
+		return -ENOENT;
+	rc = dprintf(fd, "p:uprobes/%s %s\n", ename, pname);
+	close(fd);
+	if (rc == -1)
+		return -ENOENT;
+
+	/* read the format file */
+	if (snprintf(pname, sizeof (pname), "%suprobes/%s/format", EVENTSFS, ename) >= sizeof (pname))
+		return -ENOENT;
+	f = fopen(pname, "r");
+	if (f == NULL)
+		return -ENOENT;
+	rc = tp_event_info(dtp, f, 0, idp, NULL, NULL);
+	fclose(f);
+
+	return rc;
+}
+
+static int dtrace_prov_populate(dtrace_hdl_t *dtp)
 {
 	dt_provider_t	*prv;
 	int		n = 0;
@@ -42,7 +131,7 @@ static int dtrace_populate(dtrace_hdl_t *dtp)
 }
 
 /*
-* Generate a BPF trampoline for a dtrace probe (BEGIN, END, or ERROR).
+ * Generate a BPF trampoline for a dtrace probe (BEGIN, END, or ERROR).
  *
  * The trampoline function is called when a dtrace probe triggers, and it must
  * satisfy the following prototype:
@@ -53,7 +142,7 @@ static int dtrace_populate(dtrace_hdl_t *dtp)
  * function that implements tha compiled D clause.  It returns the value that
  * it gets back from that function.
  */
-static void dtrace_trampoline(dt_pcb_t *pcb, int haspred)
+static void dtrace_prov_trampoline(dt_pcb_t *pcb, int haspred)
 {
 	int		i;
 	dt_irlist_t	*dlp = &pcb->pcb_ir;
@@ -183,7 +272,7 @@ static void dtrace_trampoline(dt_pcb_t *pcb, int haspred)
 	}
 
 	/*
-	 *     rc = dt_program(scd, dctx);
+	 *     rc = dt_program(regs, dctx);
 	 */
 	idp = dt_dlib_get_func(pcb->pcb_hdl, "dt_program");
 	assert(idp != NULL);
@@ -200,6 +289,39 @@ static void dtrace_trampoline(dt_pcb_t *pcb, int haspred)
 	dt_irlist_append(dlp, dt_cg_node_alloc(lbl_exit, instr));
 }
 
+static void dtrace_prov_cleanup(dtrace_hdl_t *dtp)
+{
+	char *probes[] = { "BEGIN", "END" };
+	dtrace_probedesc_t pdesc;
+	int i, fd;
+
+	/* start constructing a probe description */
+	pdesc.id = DTRACE_IDNONE;
+	pdesc.prv = "dtrace";
+	pdesc.mod = "";
+	pdesc.fun = "";
+
+	/* clear the BEGIN and END uprobes */
+	fd = open(UPROBE_EVENTS, O_WRONLY | O_APPEND);
+	if (fd == -1)
+		return;
+	for (i = 0; i < sizeof(probes) / sizeof(*probes); i++) {
+		dt_probe_t	*prb;
+
+		/* close the fd if possible */
+		pdesc.prb = probes[i];
+		prb = dt_probe_lookup(dtp, &pdesc);
+		if (prb && prb->event_fd != -1) {
+			close(prb->event_fd);
+			prb->event_fd = -1;
+		}
+
+		/* clear the UPROBE_EVENTS entry */
+		dprintf(fd, "-:uprobes/%s_%d\n", probes[i], getpid());
+	}
+	close(fd);
+}
+
 #if 0
 #define EVENT_PREFIX	"tracepoint/dtrace/"
 
@@ -208,7 +330,7 @@ static void dtrace_trampoline(dt_pcb_t *pcb, int haspred)
  * ELF section name).  We use an unused event group (dtrace) to be able to
  * fake a section name that libbpf will allow us to use.
  */
-static struct dt_probe *dtrace_resolve_event(const char *name)
+static struct dt_probe *dtrace_prov_resolve_event(const char *name)
 {
 	struct dt_probe	tmpl;
 	struct dt_probe	*probe;
@@ -232,7 +354,7 @@ static struct dt_probe *dtrace_resolve_event(const char *name)
 	return probe;
 }
 
-static int dtrace_attach(const char *name, int bpf_fd)
+static int dtrace_prov_attach(const char *name, int bpf_fd)
 {
 	return -1;
 }
@@ -241,10 +363,12 @@ static int dtrace_attach(const char *name, int bpf_fd)
 dt_provimpl_t	dt_dtrace = {
 	.name		= "dtrace",
 	.prog_type	= BPF_PROG_TYPE_KPROBE,
-	.populate	= &dtrace_populate,
-	.trampoline	= &dtrace_trampoline,
+	.populate	= &dtrace_prov_populate,
+	.trampoline	= &dtrace_prov_trampoline,
+	.probe_info	= &dtrace_prov_probe_info,
+	.cleanup	= &dtrace_prov_cleanup,
 #if 0
-	.resolve_event	= &dtrace_resolve_event,
-	.attach		= &dtrace_attach,
+	.resolve_event	= &dtrace_prov_resolve_event,
+	.attach		= &dtrace_prov_attach,
 #endif
 };
diff --git a/libdtrace/dt_prov_fbt.c b/libdtrace/dt_prov_fbt.c
index cfaad8af..3262449c 100644
--- a/libdtrace/dt_prov_fbt.c
+++ b/libdtrace/dt_prov_fbt.c
@@ -356,7 +356,7 @@ static void fbt_trampoline(dt_pcb_t *pcb, int haspred)
 	}
 
 	/*
-	 *     rc = dt_program(scd, dctx);
+	 *     rc = dt_program(regs, dctx);
 	 */
 	idp = dt_dlib_get_func(pcb->pcb_hdl, "dt_program");
 	assert(idp != NULL);
-- 
2.18.2




More information about the DTrace-devel mailing list