[DTrace-devel] [PATCH] Ensure that all probes have a perf event ID

Kris Van Hees kris.van.hees at oracle.com
Wed Mar 4 07:36:54 PST 2020


The implementation up until now has only supported retrieving the perf
event ID for tracepoints that are used for SDT and syscall probes.
FBT probes are a bit different because there are no perf events for
the kprobes that implement them until they are explicitly registered.

The new code for processing perf event data centralizes more of the
processing (especially the skipping of fields that we do not need),
and allows for providers to not care abuot argument information for
the probe/event.  This is used for FBT probes because those do not
provide argument information anyway.

Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
 libdtrace/dt_probe.c        |  7 ++--
 libdtrace/dt_prov_fbt.c     | 67 +++++++++++++++++++++++++++++++++++--
 libdtrace/dt_prov_sdt.c     | 38 +++++++++++++++------
 libdtrace/dt_prov_syscall.c | 21 ++++++------
 4 files changed, 108 insertions(+), 25 deletions(-)

diff --git a/libdtrace/dt_probe.c b/libdtrace/dt_probe.c
index 015fe559..5918460f 100644
--- a/libdtrace/dt_probe.c
+++ b/libdtrace/dt_probe.c
@@ -691,6 +691,7 @@ dt_probe_insert(dtrace_hdl_t *dtp, dt_provider_t *prov, const char *prv,
 
 	prp->desc = desc;
 	prp->prov = prov;
+	prp->event_id = -1;
 
 	dt_htab_insert(dtp->dt_byprv, prp);
 	dt_htab_insert(dtp->dt_bymod, prp);
@@ -825,10 +826,10 @@ dt_probe_args_info(dtrace_hdl_t *dtp, dt_probe_t *prp)
 	dtrace_typeinfo_t	dtt;
 
 	/*
-	 * If we already have argument information for this probe, there is no
-	 * need to retrieve it again.
+	 * If we already have an event ID information for this probe, there is
+	 * no need to retrieve it again.
 	 */
-	if (prp->argv)
+	if (prp->event_id != -1)
 		return;
 
 	if (!prp->prov->impl->probe_info)
diff --git a/libdtrace/dt_prov_fbt.c b/libdtrace/dt_prov_fbt.c
index ec405d5e..cfaad8af 100644
--- a/libdtrace/dt_prov_fbt.c
+++ b/libdtrace/dt_prov_fbt.c
@@ -29,6 +29,7 @@
  *  modules.)
  */
 #include <assert.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -46,11 +47,13 @@
 #include "dt_probe.h"
 #include "dt_pt_regs.h"
 
+static const char		provname[] = "fbt";
+static const char		modname[] = "vmlinux";
+
 #define KPROBE_EVENTS		TRACEFS "kprobe_events"
 #define PROBE_LIST		TRACEFS "available_filter_functions"
 
-static const char		provname[] = "fbt";
-static const char		modname[] = "vmlinux";
+#define KPROBESFS		EVENTSFS "kprobes/"
 
 static const dtrace_pattr_t	pattr = {
 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
@@ -60,6 +63,65 @@ static const dtrace_pattr_t	pattr = {
 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
 };
 
+static int fbt_probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
+			  int *idp, int *argcp, dt_argdesc_t **argvp)
+{
+	FILE	*f;
+	char	fn[256];
+	int	rc = 0;
+
+	*idp = -1;
+
+	strcpy(fn, KPROBESFS);
+	strcat(fn, prp->desc->fun);
+	strcat(fn, "/format");
+
+	/*
+	 * We check to see if the kprobe 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:
+	f = fopen(fn, "r");
+	if (f == NULL) {
+		int	fd;
+		char	c = 'p';
+
+		if (rc)
+			goto out;
+
+		rc = -ENOENT;
+
+		/*
+		 * The probe name component is either "entry" or "return" for
+		 * FBT probes.
+		 */
+		if (prp->desc->prb[0] == 'r')
+			c = 'r';
+
+		/*
+		 * Register the kprobe with the tracing subsystem.  This will
+		 * create a tracepoint event.
+		 */
+		fd = open(KPROBE_EVENTS, O_WRONLY | O_APPEND);
+		if (fd == -1)
+			goto out;
+
+		dprintf(fd, "%c:%s %s\n", c, prp->desc->fun, prp->desc->fun);
+		close(fd);
+
+		goto again;
+	}
+
+	*argcp = 0;
+	*argvp = NULL;
+	rc = tp_event_info(dtp, f, 0, idp, NULL, NULL);
+	fclose(f);
+
+out:
+	return rc;
+}
+
 /*
  * Scan the PROBE_LIST file and add entry and return probes for every function
  * that is listed.
@@ -414,6 +476,7 @@ dt_provimpl_t	dt_fbt = {
 	.prog_type	= BPF_PROG_TYPE_KPROBE,
 	.populate	= &fbt_populate,
 	.trampoline	= &fbt_trampoline,
+	.probe_info	= &fbt_probe_info,
 #if 0
 	.resolve_event	= &fbt_resolve_event,
 	.attach		= &fbt_attach,
diff --git a/libdtrace/dt_prov_sdt.c b/libdtrace/dt_prov_sdt.c
index d012d237..1dcaf584 100644
--- a/libdtrace/dt_prov_sdt.c
+++ b/libdtrace/dt_prov_sdt.c
@@ -35,14 +35,6 @@
 #include "dt_probe.h"
 #include "dt_pt_regs.h"
 
-static const dtrace_pattr_t	pattr = {
-{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
-{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
-{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
-{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
-{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
-};
-
 static const char		provname[] = "sdt";
 static const char		modname[] = "vmlinux";
 
@@ -51,9 +43,22 @@ static const char		modname[] = "vmlinux";
 #define KPROBES			"kprobes:"
 #define SYSCALLS		"syscalls:"
 
+/*
+ * All tracing events (tracepoints) include a number of fields that we need to
+ * skip in the tracepoint format description.  These fields are: common_type,
+ * common_flags, common_preempt_coint, and common_pid.
+ */
+#define SKIP_FIELDS_COUNT	4
+
 #define FIELD_PREFIX		"field:"
 
-#define SKIP_FIELDS_COUNT	4
+static const dtrace_pattr_t	pattr = {
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
+};
 
 /*
  * Parse the EVENTSFS/<group>/<event>/format file to determine the event id and
@@ -71,6 +76,11 @@ static const char		modname[] = "vmlinux";
  * cope with because it expects just the type specification.  Getting rid of
  * the identifier isn't as easy because it may be suffixed by one or more
  * array dimension specifiers (and those are part of the type).
+ *
+ * All events include a number of fields that we are not interested and that
+ * need to be skipped (SKIP_FIELDS_COUNT).  Callers of this function can
+ * specify an additional numbe of fields to skip (using the 'skip' parameter)
+ * before we get to the actual arguments.
  */
 int tp_event_info(dtrace_hdl_t *dtp, FILE *f, int skip, int *idp, int *argcp,
 		  dt_argdesc_t **argvp)
@@ -83,6 +93,11 @@ int tp_event_info(dtrace_hdl_t *dtp, FILE *f, int skip, int *idp, int *argcp,
 
 	*idp = -1;
 
+	/*
+	 * Let skip be the total number of fields to skip.
+	 */
+	skip += SKIP_FIELDS_COUNT;
+
 	/*
 	 * Pass 1:
 	 * Determine the event id and the number of arguments (along with the
@@ -112,10 +127,13 @@ int tp_event_info(dtrace_hdl_t *dtp, FILE *f, int skip, int *idp, int *argcp,
 
 	/*
 	 * If we saw less fields than expected, we flag an error.
+	 * If we are not interested in arguments, we are done.
 	 * If there are no arguments, we are done.
 	 */
 	if (argc < 0)
 		return -EINVAL;
+	if (argcp == NULL)
+		return 0;
 	if (argc == 0)
 		goto done;
 
@@ -227,7 +245,7 @@ static int sdt_probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
 	if (!f)
 		return -ENOENT;
 
-	rc = tp_event_info(dtp, f, SKIP_FIELDS_COUNT, idp, argcp, argvp);
+	rc = tp_event_info(dtp, f, 0, idp, argcp, argvp);
 	fclose(f);
 
 	return rc;
diff --git a/libdtrace/dt_prov_syscall.c b/libdtrace/dt_prov_syscall.c
index bd3206ad..2cd9c6ef 100644
--- a/libdtrace/dt_prov_syscall.c
+++ b/libdtrace/dt_prov_syscall.c
@@ -40,6 +40,16 @@
 #include "dt_probe.h"
 #include "dt_pt_regs.h"
 
+static const char		provname[] = "syscall";
+static const char		modname[] = "vmlinux";
+
+#define SYSCALLSFS		EVENTSFS "syscalls/"
+
+/*
+ * We need to skip over an extra field: __syscall_nr.
+ */
+#define SKIP_EXTRA_FIELDS	1
+
 static const dtrace_pattr_t	pattr = {
 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
@@ -48,15 +58,6 @@ static const dtrace_pattr_t	pattr = {
 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
 };
 
-static const char		provname[] = "syscall";
-static const char		modname[] = "vmlinux";
-
-#define SYSCALLSFS		EVENTSFS "syscalls/"
-
-#define FIELD_PREFIX		"field:"
-
-#define SKIP_FIELDS_COUNT	5
-
 struct syscall_data {
 	dt_pt_regs	*regs;
 	long		syscall_nr;
@@ -90,7 +91,7 @@ static int syscall_probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
 	if (!f)
 		return -ENOENT;
 
-	rc = tp_event_info(dtp, f, SKIP_FIELDS_COUNT, idp, argcp, argvp);
+	rc = tp_event_info(dtp, f, SKIP_EXTRA_FIELDS, idp, argcp, argvp);
 	fclose(f);
 
 	return rc;
-- 
2.25.0




More information about the DTrace-devel mailing list