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

eugene.loh at oracle.com eugene.loh at oracle.com
Sat Mar 21 13:39:16 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.

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

diff --git a/libdtrace/dt_prov_dtrace.c b/libdtrace/dt_prov_dtrace.c
index b2327dc2..699541c9 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,101 @@ 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"
+
+static int dt_get_uprobe(char *dtrace_probe_name, char *uprobe_name, int len) {
+	struct ps_prochandle *P;
+	int perr = 0, rc = 1;
+	GElf_Sym sym;
+	prsyminfo_t si;
+	prmap_t *pmptr;
+
+	P = Pgrab(getpid(), 2, 0, NULL, &perr);
+	if (P == NULL)
+		return 1; /* FIXME: do something with perr? */
+
+	if (Pxlookup_by_name(P, -1, PR_OBJ_EVERY, dtrace_probe_name, &sym, &si))
+		goto done;
+
+	pmptr = Paddr_to_map(P, sym.st_value);
+	if (pmptr == NULL)
+		goto done;
+
+	if (snprintf(uprobe_name, 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 = 0;
+	char	probe_name[256];
+	char	s[256];
+
+	*idp = -1;
+
+	if (snprintf(probe_name, sizeof (probe_name), "%s_probe", prp->desc->prb) >= sizeof (probe_name)) {
+		assert(0);
+	}
+
+	/*
+	 * We check to see if the event already exists in the tracing
+	 * sub-system.  If not, we try to register the probe with the tracing
+	 * sub-system, and try accessing it again.
+	 */
+again:
+	/*
+	 * FIXME: gcc complains:
+	 *     warning: ‘%s’ directive output may be truncated writing up to 255 bytes
+	 *         into a region of size 215 [-Wformat-truncation=]
+	 *     note: ‘snprintf’ output between 49 and 304 bytes into a destination of size 256
+	 * How do we make this complaint go away?  Checking the snprintf()
+	 * return value against the size of the buffer was supposed to do this.
+	 */
+	if (snprintf(s, sizeof (s), "%suprobes/%s/format", EVENTSFS, probe_name) >= sizeof (s)) {
+		/* FIXME: now what? */
+	}
+	f = fopen(s, "r");
+	if (f == NULL) {
+		int fd;
+		char uprobe_name[256];
+
+		if (rc)
+			goto out;
+
+		rc = -ENOENT;
+
+		/* FIXME: check return value */
+		dt_get_uprobe(probe_name, uprobe_name, sizeof (uprobe_name));
+
+		fd = open(UPROBE_EVENTS, O_WRONLY | O_APPEND);
+		if (fd == -1)
+			goto out;
+
+		dprintf(fd, "p:uprobes/%s %s\n", probe_name, uprobe_name);
+		close(fd);
+
+		goto again;
+	}
+
+	*argcp = 0;
+	*argvp = NULL;
+	rc = tp_event_info(dtp, f, 0, idp, NULL, NULL);
+	fclose(f);
+
+out:
+	return rc;
+}
+
+static int dtrace_prov_populate(dtrace_hdl_t *dtp)
 {
 	dt_provider_t	*prv;
 	int		n = 0;
@@ -42,7 +137,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 +148,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 +278,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);
@@ -208,7 +303,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 +327,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 +336,11 @@ 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,
 #if 0
-	.resolve_event	= &dtrace_resolve_event,
-	.attach		= &dtrace_attach,
+	.resolve_event	= &dtrace_prov_resolve_event,
+	.attach		= &dtrace_prov_attach,
 #endif
+	.probe_info	= &dtrace_prov_probe_info,
 };
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