[DTrace-devel] [PATCH v2 04/04] rawtp: retrieve probe arguments from CTF data

Kris Van Hees kris.van.hees at oracle.com
Thu Nov 30 15:59:09 UTC 2023


We were determining the number of arguments using a trial-and-error
approach with minimal BPF programs.  If there is CTF type data for
the raw tracepoints (in the form of a function prototype), we use
that because it also gives us the types of the arguments.

If no such CTF data is available, we fall back to the trial-and-error
approach.

The included test will fail if the fallback is used.  There is no way
to force the fallback to get triggered explicitly.

Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 libdtrace/dt_prov_rawtp.c                     | 95 +++++++++++++++++--
 .../rawtp/tst.lv-sched_process_fork.r         | 16 ++++
 .../rawtp/tst.lv-sched_process_fork.r.p       |  7 ++
 .../rawtp/tst.lv-sched_process_fork.sh        | 11 +++
 4 files changed, 119 insertions(+), 10 deletions(-)
 create mode 100644 test/unittest/providers/rawtp/tst.lv-sched_process_fork.r
 create mode 100755 test/unittest/providers/rawtp/tst.lv-sched_process_fork.r.p
 create mode 100755 test/unittest/providers/rawtp/tst.lv-sched_process_fork.sh

diff --git a/libdtrace/dt_prov_rawtp.c b/libdtrace/dt_prov_rawtp.c
index 93a30bb7..2d6d6eb5 100644
--- a/libdtrace/dt_prov_rawtp.c
+++ b/libdtrace/dt_prov_rawtp.c
@@ -157,18 +157,24 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
 	return 0;
 }
 
-static int probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
-		      int *argcp, dt_argdesc_t **argvp)
+/*
+ * If there is no btf_trace_* prototype available in CTF, we can still probe
+ * the number of available argument for a raw tracepoint by means of a trial
+ * and error loop to see what the highest argument index is that the BPF
+ * verifier allows us to load from.
+ */
+static int probe_info_bpf(dtrace_hdl_t *dtp, const dt_probe_t *prp,
+			  int *argcp, dt_argdesc_t **argvp)
 {
 	int		argc, i;
 	dt_argdesc_t	*argv = NULL;
 
 	/*
-	 * This is an unfortunate necessity.  The BPF verifier will not allow
-	 * us to access more argument values than are passed to the raw
-	 * tracepoint but the number of argument values for any given raw
-	 * tracepoint is not made available to userspace.  So we use a trial
-	 * and error loop to see what the BPF verifier accepts.
+	 * The BPF verifier will not allow us to access more argument values
+	 * than are passed to the raw tracepoint but the number of argument
+	 * values for any given raw tracepoint is not made available to
+	 * userspace.  So we use a trial and error loop to see what the BPF
+	 * verifier accepts.
 	 */
 	for (argc = ARRAY_SIZE(((dt_mstate_t *)0)->argv); argc > 0; argc--) {
 		int		bpf_fd, rtp_fd;
@@ -205,10 +211,79 @@ static int probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
 	}
 
 done:
-        *argcp = argc;
-        *argvp = argv;
+	*argcp = argc;
+	*argvp = argv;
+
+	return 0;
+}
+
+static int probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
+		      int *argcp, dt_argdesc_t **argvp)
+{
+#ifdef HAVE_LIBCTF
+	int			rc, i;
+	char			*str;
+	ctf_dict_t		*ctfp;
+	ctf_id_t		type;
+	int			argc = 0;
+	dt_argdesc_t		*argv = NULL;
+	ctf_funcinfo_t		fi;
+	dtrace_typeinfo_t	sym;
+	ctf_id_t		*argt;
+
+	if (asprintf(&str, "btf_trace_%s", prp->desc->prb) == -1)
+		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+	rc = dtrace_lookup_by_type(dtp, DTRACE_OBJ_EVERY, str, &sym);
+	free(str);
+	if (rc ||
+	    ctf_type_kind(sym.dtt_ctfp, sym.dtt_type) != CTF_K_TYPEDEF)
+		goto use_alt;
+
+	ctfp = sym.dtt_ctfp;
+	type = ctf_type_reference(ctfp, sym.dtt_type);
+	if (ctf_type_kind(ctfp, type) != CTF_K_POINTER)
+		goto use_alt;
+	type = ctf_type_reference(ctfp, type);
+	if (ctf_type_kind(ctfp, type) != CTF_K_FUNCTION)
+		goto use_alt;
+	if (ctf_func_type_info(ctfp, type, &fi) == -1)
+		goto use_alt;
+
+	/*
+	 * Raw tracepoints have an extra first argument for the context, so we
+	 * need to skip that.  (We also handle the case where fi.ctc_argc is 0
+	 * even though that is not supposed to happen.)
+	 */
+	if (fi.ctc_argc <= 1)
+		goto done;
+
+	argc = fi.ctc_argc;
+	argt = dt_calloc(dtp, argc, sizeof(ctf_id_t));
+	ctf_func_type_args(ctfp, type, argc, argt);
+
+	argc--;
+	argv = dt_zalloc(dtp, argc * sizeof(dt_argdesc_t));
+
+	for (i = 0; i < argc; i++) {
+		char	n[DT_TYPE_NAMELEN];
+
+		ctf_type_name(ctfp, argt[i + 1], n, sizeof(n));
+		argv[i].mapping = i;
+		argv[i].native = strdup(n);
+		argv[i].xlate = NULL;
+	}
+
+	free(argt);
+
+done:
+	*argcp = argc;
+	*argvp = argv;
+
+	return 0;
 
-        return 0;
+use_alt:
+#endif
+	return probe_info_bpf(dtp, prp, argcp, argvp);
 }
 
 dt_provimpl_t	dt_rawtp = {
diff --git a/test/unittest/providers/rawtp/tst.lv-sched_process_fork.r b/test/unittest/providers/rawtp/tst.lv-sched_process_fork.r
new file mode 100644
index 00000000..de9304ca
--- /dev/null
+++ b/test/unittest/providers/rawtp/tst.lv-sched_process_fork.r
@@ -0,0 +1,16 @@
+PROBE rawtp sched sched_process_fork
+
+	Probe Description Attributes
+		Identifier Names: Private
+		Data Semantics:   Private
+		Dependency Class: Unknown
+
+	Argument Attributes
+		Identifier Names: Private
+		Data Semantics:   Private
+		Dependency Class: ISA
+
+	Argument Types
+		args[0]: TYPE-OK
+		args[1]: TYPE-OK
+
diff --git a/test/unittest/providers/rawtp/tst.lv-sched_process_fork.r.p b/test/unittest/providers/rawtp/tst.lv-sched_process_fork.r.p
new file mode 100755
index 00000000..e83bac90
--- /dev/null
+++ b/test/unittest/providers/rawtp/tst.lv-sched_process_fork.r.p
@@ -0,0 +1,7 @@
+#!/usr/bin/awk -f
+NR == 1 { next; }
+NR == 2 { print "PROBE", $2, $3, $NF; next; }
+/args\[[0-9]+\]: uint64_t$/ { sub(/:.*$/, ": TYPE-OK"); }
+/args\[[0-9]+\]: struct task_struct \*$/ { sub(/:.*$/, ": TYPE-OK"); }
+/^ *[0-9]+/ { exit; }
+{ print; }
diff --git a/test/unittest/providers/rawtp/tst.lv-sched_process_fork.sh b/test/unittest/providers/rawtp/tst.lv-sched_process_fork.sh
new file mode 100755
index 00000000..bbfb7749
--- /dev/null
+++ b/test/unittest/providers/rawtp/tst.lv-sched_process_fork.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 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.
+
+dtrace=$1
+
+$dtrace $dt_flags -lvn rawtp:::sched_process_fork
+exit $?
-- 
2.42.0




More information about the DTrace-devel mailing list