[DTrace-devel] [PATCH v3] Implement the ppid builtin D variable

eugene.loh at oracle.com eugene.loh at oracle.com
Thu Sep 17 13:14:34 PDT 2020


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

Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
 bpf/get_bvar.c                           | 36 ++++++++++++++++++++++++
 libdtrace/dt_bpf.c                       | 26 +++++++++++++++++
 libdtrace/dt_state.h                     |  5 ++++
 test/unittest/variables/bvar/tst.ppid.d  |  1 -
 test/unittest/variables/bvar/tst.ppid2.d | 20 +++++++++++++
 5 files changed, 87 insertions(+), 1 deletion(-)
 create mode 100644 test/unittest/variables/bvar/tst.ppid2.d

diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c
index 0cac46d5..8d595efb 100644
--- a/bpf/get_bvar.c
+++ b/bpf/get_bvar.c
@@ -9,12 +9,14 @@
 #include <dtrace/conf.h>
 #include <dtrace/dif_defines.h>
 #include <dt_dctx.h>
+#include <dt_state.h>
 
 #ifndef noinline
 # define noinline	__attribute__((noinline))
 #endif
 
 extern struct bpf_map_def cpuinfo;
+extern struct bpf_map_def state;
 
 noinline uint64_t dt_get_bvar(dt_mstate_t *mst, uint32_t id)
 {
@@ -47,6 +49,40 @@ noinline uint64_t dt_get_bvar(dt_mstate_t *mst, uint32_t id)
 
 		return val & 0x00000000ffffffffUL;
 	}
+	case DIF_VAR_PPID: {
+		uint64_t	ptr;
+		int32_t		val = -1;
+		uint32_t	key;
+		uint32_t	*parent_off;
+		uint32_t	*tgid_off;
+
+		/*
+		 * In the "state" map, look up the "struct task_struct" offsets
+		 * of real_parent and tgid.
+		 */
+		key = DT_STATE_TASK_PARENT_OFF;
+		parent_off = bpf_map_lookup_elem(&state, &key);
+		if (parent_off == NULL)
+			return -1;
+
+		key = DT_STATE_TASK_TGID_OFF;
+		tgid_off = bpf_map_lookup_elem(&state, &key);
+		if (tgid_off == NULL)
+			return -1;
+
+		/* Chase pointers val = current->real_parent->tgid. */
+		ptr = bpf_get_current_task();
+		if (ptr == 0)
+			return -1;
+		if (bpf_probe_read((void *) &ptr, 8,
+		    (const void *) (ptr + *parent_off)))
+			return -1;
+		if (bpf_probe_read((void *) &val, 4,
+		    (const void *) (ptr + *tgid_off)))
+			return -1;
+
+		return (uint64_t) val;
+	}
 	case DIF_VAR_UID: {
 		uint64_t	val = bpf_get_current_uid_gid();
 
diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
index 4e0cdc91..736b3318 100644
--- a/libdtrace/dt_bpf.c
+++ b/libdtrace/dt_bpf.c
@@ -115,6 +115,28 @@ create_gmap(dtrace_hdl_t *dtp, const char *name, enum bpf_map_type type,
 	return fd;
 }
 
+static int
+set_task_offsets(dtrace_hdl_t *dtp)
+{
+	ctf_id_t type;
+	ctf_membinfo_t ctm;
+	ctf_file_t *cfp = dtp->dt_shared_ctf;
+
+	type = ctf_lookup_by_name(cfp, "struct task_struct");
+	if (type == CTF_ERR)
+		return -1;
+
+	if (ctf_member_info(cfp, type, "real_parent", &ctm) == CTF_ERR)
+		return -1;
+	dt_state_set_offparent(dtp, ctm.ctm_offset / NBBY);
+
+	if (ctf_member_info(cfp, type, "tgid", &ctm) == CTF_ERR)
+		return -1;
+	dt_state_set_offtgid(dtp, ctm.ctm_offset / NBBY);
+
+	return 0;
+}
+
 /*
  * Create the global BPF maps that are shared between all BPF programs in a
  * single tracing session:
@@ -225,6 +247,10 @@ dt_bpf_gmap_create(dtrace_hdl_t *dtp)
 	/* Populate the 'cpuinfo' map. */
 	dt_bpf_map_update(ci_mapfd, &key, dtp->dt_conf.cpus);
 
+	/* Set some task_struct offsets in state. */
+	if (set_task_offsets(dtp))
+		return dt_set_errno(dtp, EDT_CTF);
+
 	return 0;
 }
 
diff --git a/libdtrace/dt_state.h b/libdtrace/dt_state.h
index c6500dca..ed6f2030 100644
--- a/libdtrace/dt_state.h
+++ b/libdtrace/dt_state.h
@@ -21,6 +21,8 @@ typedef enum dt_state_elem {
 	DT_STATE_ACTIVITY = 0,		/* activity state of the session */
 	DT_STATE_BEGANON,		/* cpu BEGIN probe executed on */
 	DT_STATE_ENDEDON,		/* cpu END probe executed on */
+	DT_STATE_TASK_PARENT_OFF,	/* offsetof(struct task_struct, real_parent) */
+	DT_STATE_TASK_TGID_OFF,		/* offsetof(struct task_struct, tgid) */
 	DT_STATE_NUM_ELEMS
 } dt_state_elem_t;
 
@@ -61,6 +63,9 @@ dt_state_set(dtrace_hdl_t *dtp, uint32_t key, uint32_t val)
 
 # define dt_state_get_beganon(dtp)	dt_state_get(dtp, DT_STATE_BEGANON)
 # define dt_state_get_endedon(dtp)	dt_state_get(dtp, DT_STATE_ENDEDON)
+
+# define dt_state_set_offparent(dtp, x)	dt_state_set(dtp, DT_STATE_TASK_PARENT_OFF, (x))
+# define dt_state_set_offtgid(dtp, x)	dt_state_set(dtp, DT_STATE_TASK_TGID_OFF, (x))
 #endif
 
 #endif /* _DT_STATE_H */
diff --git a/test/unittest/variables/bvar/tst.ppid.d b/test/unittest/variables/bvar/tst.ppid.d
index e406b36f..87bc52da 100644
--- a/test/unittest/variables/bvar/tst.ppid.d
+++ b/test/unittest/variables/bvar/tst.ppid.d
@@ -4,7 +4,6 @@
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * ASSERTION: The 'ppid' variable can be accessed and is not -1.
diff --git a/test/unittest/variables/bvar/tst.ppid2.d b/test/unittest/variables/bvar/tst.ppid2.d
new file mode 100644
index 00000000..7a50ac89
--- /dev/null
+++ b/test/unittest/variables/bvar/tst.ppid2.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, 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.
+ */
+
+/*
+ * ASSERTION: The 'ppid' variable matches the scripting variable for BEGIN.
+ *
+ * SECTION: Variables/Built-in Variables/ppid
+ */
+
+#pragma D option quiet
+
+BEGIN {
+       trace(ppid);
+       trace($ppid);
+       exit(ppid == $ppid ? 0 : 1);
+}
-- 
2.18.4




More information about the DTrace-devel mailing list