[DTrace-devel] [PATCH v2 4/4] uregs: Support for older kernels (without BPF pt_regs helper functions)

eugene.loh at oracle.com eugene.loh at oracle.com
Fri May 19 19:21:28 UTC 2023


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

Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
 libdtrace/dt_cg.c                             | 128 +++++++++++++++++-
 .../err.D_UNKNOWN.uregs_badkernelversion.d    |  19 ---
 .../err.D_UNKNOWN.uregs_badkernelversion.r    |   2 -
 .../err.D_UNKNOWN.uregs_badkernelversion.x    |  13 --
 .../err.D_UNKNOWN.uregs_toobig.aarch64.x      |   9 --
 .../err.D_UNKNOWN.uregs_toobig.x86_64.x       |   9 --
 test/unittest/arrays/tst.uregsarray-check.x   |  13 --
 test/unittest/arrays/tst.uregsarray.arm64.x   |  17 +--
 test/unittest/arrays/tst.uregsarray.x         |  13 --
 test/unittest/arrays/tst.uregsarray.x86_64.x  |  17 +--
 test/unittest/disasm/tst.vartab-bvar-uregs0.x |  13 --
 11 files changed, 128 insertions(+), 125 deletions(-)
 delete mode 100644 test/unittest/arrays/err.D_UNKNOWN.uregs_badkernelversion.d
 delete mode 100644 test/unittest/arrays/err.D_UNKNOWN.uregs_badkernelversion.r
 delete mode 100755 test/unittest/arrays/err.D_UNKNOWN.uregs_badkernelversion.x
 delete mode 100755 test/unittest/arrays/tst.uregsarray-check.x
 delete mode 100755 test/unittest/arrays/tst.uregsarray.x
 delete mode 100755 test/unittest/disasm/tst.vartab-bvar-uregs0.x

diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 74eb4a31..b08d9a73 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -4123,11 +4123,6 @@ dt_cg_uregs(unsigned int idx, dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp
 {
 	dtrace_hdl_t	*dtp = yypcb->pcb_hdl;
 
-	/* ensure we can use  the BPF task_pt_regs() helper */
-	if (dtp->dt_bpfhelper[BPF_FUNC_get_current_task_btf] == BPF_FUNC_unspec
-	  || dtp->dt_bpfhelper[BPF_FUNC_task_pt_regs] == BPF_FUNC_unspec)
-		dnerror(dnp, D_UNKNOWN, "uregs[] is not supported on this kernel\n");
-
 	/* check if out-of-bounds */
 	if (idx >= sizeof(dt_pt_regs) / sizeof(uint64_t)) {
 
@@ -4178,7 +4173,128 @@ dt_cg_uregs(unsigned int idx, dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp
 		return;
 	}
 
-	/* if in-bounds, look up pt_regs[] */
+	/* If in-bounds, look up pt_regs[]. */
+
+	if (dtp->dt_bpfhelper[BPF_FUNC_get_current_task_btf] == BPF_FUNC_unspec ||
+	    dtp->dt_bpfhelper[BPF_FUNC_task_pt_regs] == BPF_FUNC_unspec) {
+
+		/*
+		 * To get pt_regs[], we try to use two BPF helper functions, but
+		 * they exist only on newer kernels.  Therefore, we check if they
+		 * exist.
+		 *
+		 * If they do not exist, we are forced to emulate them, which is
+		 * tricky since they depend on kernel configuration.
+		 *
+		 * In kernel/trace/bpf_trace.c, we see bpf_task_pt_regs() returns
+		 * task_pt_regs(task).
+		 *
+		 * In turn, task_pt_regs() is defined in files like
+		 *     arch/arm64/include/asm/processor.h
+		 *     arch/x86/include/asm/processor.h
+		 *
+		 * In essence, what we will do for these two architectures is:
+		 *     get task_stack_page(task) (that is, get task->stack)
+		 *     find the offset to add:
+		 *         add THREAD_SIZE
+		 *         subtract sizeof(struct pt_regs)
+		 *         add idx*sizeof(uint64_t) (for pt_regs[idx])
+		 *
+		 * For a wide range of kernels, the configuration parameters will
+		 * be identical to the values below.
+		 */
+
+		size_t offset;
+
+		/* Spill %r0 - %r5 (if necessary). */
+		if (dt_regset_xalloc_args(drp) == -1)
+			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+		dt_regset_xalloc(drp, BPF_REG_0);
+
+		/* %r0 = current stack */
+		emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_task));
+
+		/* Copy contents at task->stack to %fp+DT_STK_SP (scratch space). */
+		emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0));
+		emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3,
+		    dt_cg_ctf_offsetof("struct task_struct", "stack", NULL)));
+		emit(dlp, BPF_MOV_IMM(BPF_REG_2, sizeof(uint64_t)));
+		emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_FP, DT_STK_SP));
+		emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_kernel]));
+
+		/* Fill %r0 - %r5 (if necessary). */
+		dt_regset_free_args(drp);
+		dt_regset_free(drp, BPF_REG_0);
+
+		/* Get contents from %fp+DT_STK_SP.  Now we have task->stack. */
+		emit(dlp, BPF_LOAD(BPF_DW, dnp->dn_reg, BPF_REG_FP, DT_STK_SP));
+		emit(dlp, BPF_LOAD(BPF_DW, dnp->dn_reg, dnp->dn_reg, 0));
+
+		/* Start computing the offset to get to pt_regs[idx]. */
+		offset = 0;
+
+#if defined(__amd64)
+
+#define MY_PAGE_SIZE 4096
+
+/* arch/x86/include/asm/page_64_types.h */
+#define MY_KASAN_STACK_ORDER 0                              /* for CONFIG_KASAN not set */
+#define MY_THREAD_SIZE_ORDER (2 + MY_KASAN_STACK_ORDER)
+#define MY_THREAD_SIZE (MY_PAGE_SIZE << MY_THREAD_SIZE_ORDER)
+
+		offset += MY_THREAD_SIZE;
+
+#undef MY_PAGE_SIZE
+#undef MY_KASAN_STACK_ORDER
+#undef MY_THREAD_SIZE_ORDER
+#undef MY_THREAD_SIZE
+
+#elif defined(__aarch64__)
+
+/* arch/arm64/include/asm/memory.h */
+#define MY_KASAN_THREAD_SHIFT 0                             /* for CONFIG_KASAN not set */
+#define MY_MIN_THREAD_SHIFT (14 + MY_KASAN_THREAD_SHIFT)
+#define MY_THREAD_SHIFT MY_MIN_THREAD_SHIFT
+#define MY_THREAD_SIZE (1 << MY_THREAD_SHIFT)
+
+		offset += MY_THREAD_SIZE;
+
+#undef MY_KASAN_THREAD_SHIFT
+#undef MY_MIN_THREAD_SHIFT
+#undef MY_THREAD_SHIFT
+#undef MY_THREAD_SIZE
+
+#else
+# error ISA not supported
+#endif
+
+		/*
+		 * Subtract sizeof(struct pt_regs).  Do not use sizeof(dt_pt_regs)
+		 * since it can be smaller, at least on aarch64.
+		 */
+		{
+			ctf_file_t *cfp = yypcb->pcb_hdl->dt_shared_ctf;
+			ctf_id_t type;
+
+			type = ctf_lookup_by_name(cfp, "struct pt_regs");
+			if (type == CTF_ERR)
+				longjmp(yypcb->pcb_jmpbuf, EDT_NOCTF);
+
+			offset -= ctf_type_size(cfp, type);
+		}
+
+		/* Add the offset for our particular pt_regs[] index. */
+		offset += (idx * sizeof(uint64_t));
+
+		/* Add the fully computed offset to the pointer in the register. */
+		emit(dlp, BPF_ALU64_IMM(BPF_ADD, dnp->dn_reg, offset));
+
+		/* Dereference it safely (the BPF verifier has no idea what it is). */
+		dt_cg_load_scalar(dnp, BPF_DW, sizeof(uint64_t), dlp, drp);
+
+		return;
+	}
+
 	if (dt_regset_xalloc_args(drp) == -1)
 		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
 	dt_regset_xalloc(drp, BPF_REG_0);
diff --git a/test/unittest/arrays/err.D_UNKNOWN.uregs_badkernelversion.d b/test/unittest/arrays/err.D_UNKNOWN.uregs_badkernelversion.d
deleted file mode 100644
index ed375348..00000000
--- a/test/unittest/arrays/err.D_UNKNOWN.uregs_badkernelversion.d
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * ASSERTION: uregs[] not supported on old kernels.
- *
- * SECTION: User Process Tracing/uregs Array
- */
-
-BEGIN
-{
-	trace(uregs[R_SP]);
-	exit(1);
-}
-
diff --git a/test/unittest/arrays/err.D_UNKNOWN.uregs_badkernelversion.r b/test/unittest/arrays/err.D_UNKNOWN.uregs_badkernelversion.r
deleted file mode 100644
index 09024896..00000000
--- a/test/unittest/arrays/err.D_UNKNOWN.uregs_badkernelversion.r
+++ /dev/null
@@ -1,2 +0,0 @@
--- @@stderr --
-dtrace: failed to compile script test/unittest/arrays/err.D_UNKNOWN.uregs_badkernelversion.d: [D_UNKNOWN] line 16: uregs[] is not supported on this kernel
diff --git a/test/unittest/arrays/err.D_UNKNOWN.uregs_badkernelversion.x b/test/unittest/arrays/err.D_UNKNOWN.uregs_badkernelversion.x
deleted file mode 100755
index 0274240f..00000000
--- a/test/unittest/arrays/err.D_UNKNOWN.uregs_badkernelversion.x
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-read MAJOR MINOR <<< `uname -r | grep -Eo '^[0-9]+\.[0-9]+' | tr '.' ' '`
-
-if [ $MAJOR -lt 5 ]; then
-        exit 0
-fi
-if [ $MAJOR -eq 5 -a $MINOR -lt 15 ]; then
-        exit 0
-fi
-
-echo "no UNKNOWN-uregs problem on newer kernels"
-exit 2
diff --git a/test/unittest/arrays/err.D_UNKNOWN.uregs_toobig.aarch64.x b/test/unittest/arrays/err.D_UNKNOWN.uregs_toobig.aarch64.x
index 7b9e620f..36074cb2 100755
--- a/test/unittest/arrays/err.D_UNKNOWN.uregs_toobig.aarch64.x
+++ b/test/unittest/arrays/err.D_UNKNOWN.uregs_toobig.aarch64.x
@@ -1,13 +1,4 @@
 #!/bin/sh
 
-read MAJOR MINOR <<< `uname -r | grep -Eo '^[0-9]+\.[0-9]+' | tr '.' ' '`
-
-if [ $MAJOR -lt 5 ]; then
-	exit 2
-fi
-if [ $MAJOR -eq 5 -a $MINOR -lt 15 ]; then
-	exit 2
-fi
-
 [ `uname -m` = "aarch64" ] && exit 0
 exit 2
diff --git a/test/unittest/arrays/err.D_UNKNOWN.uregs_toobig.x86_64.x b/test/unittest/arrays/err.D_UNKNOWN.uregs_toobig.x86_64.x
index bce4d6b3..69e36e70 100755
--- a/test/unittest/arrays/err.D_UNKNOWN.uregs_toobig.x86_64.x
+++ b/test/unittest/arrays/err.D_UNKNOWN.uregs_toobig.x86_64.x
@@ -1,13 +1,4 @@
 #!/bin/sh
 
-read MAJOR MINOR <<< `uname -r | grep -Eo '^[0-9]+\.[0-9]+' | tr '.' ' '`
-
-if [ $MAJOR -lt 5 ]; then
-	exit 2
-fi
-if [ $MAJOR -eq 5 -a $MINOR -lt 15 ]; then
-	exit 2
-fi
-
 [ `uname -m` = "x86_64" ] && exit 0
 exit 2
diff --git a/test/unittest/arrays/tst.uregsarray-check.x b/test/unittest/arrays/tst.uregsarray-check.x
deleted file mode 100755
index 4fb7f8c1..00000000
--- a/test/unittest/arrays/tst.uregsarray-check.x
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-read MAJOR MINOR <<< `uname -r | grep -Eo '^[0-9]+\.[0-9]+' | tr '.' ' '`
-
-if [ $MAJOR -gt 5 ]; then
-        exit 0
-fi
-if [ $MAJOR -eq 5 -a $MINOR -ge 15 ]; then
-        exit 0
-fi
-
-echo "no uregs on older kernels"
-exit 1
diff --git a/test/unittest/arrays/tst.uregsarray.arm64.x b/test/unittest/arrays/tst.uregsarray.arm64.x
index 635c2a86..36074cb2 100755
--- a/test/unittest/arrays/tst.uregsarray.arm64.x
+++ b/test/unittest/arrays/tst.uregsarray.arm64.x
@@ -1,15 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 
-[ `uname -m` != "aarch64" ] && exit 2
-
-read MAJOR MINOR <<< `uname -r | grep -Eo '^[0-9]+\.[0-9]+' | tr '.' ' '`
-
-if [ $MAJOR -gt 5 ]; then
-	exit 0
-fi
-if [ $MAJOR -eq 5 -a $MINOR -ge 15 ]; then
-	exit 0
-fi
-
-echo "uregs[]: pt_regs[] lookup not implemented on older kernels"
-exit 1
+[ `uname -m` = "aarch64" ] && exit 0
+exit 2
diff --git a/test/unittest/arrays/tst.uregsarray.x b/test/unittest/arrays/tst.uregsarray.x
deleted file mode 100755
index e63a58bd..00000000
--- a/test/unittest/arrays/tst.uregsarray.x
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-read MAJOR MINOR <<< `uname -r | grep -Eo '^[0-9]+\.[0-9]+' | tr '.' ' '`
-
-if [ $MAJOR -gt 5 ]; then
-	exit 0
-fi
-if [ $MAJOR -eq 5 -a $MINOR -ge 15 ]; then
-	exit 0
-fi
-
-echo "uregs[]: pt_regs[] lookup not implemented on older kernels"
-exit 1
diff --git a/test/unittest/arrays/tst.uregsarray.x86_64.x b/test/unittest/arrays/tst.uregsarray.x86_64.x
index 5441e564..69e36e70 100755
--- a/test/unittest/arrays/tst.uregsarray.x86_64.x
+++ b/test/unittest/arrays/tst.uregsarray.x86_64.x
@@ -1,15 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 
-[ `uname -m` != "x86_64" ] && exit 2
-
-read MAJOR MINOR <<< `uname -r | grep -Eo '^[0-9]+\.[0-9]+' | tr '.' ' '`
-
-if [ $MAJOR -gt 5 ]; then
-	exit 0
-fi
-if [ $MAJOR -eq 5 -a $MINOR -ge 15 ]; then
-	exit 0
-fi
-
-echo "uregs[]: pt_regs[] lookup not implemented on older kernels"
-exit 1
+[ `uname -m` = "x86_64" ] && exit 0
+exit 2
diff --git a/test/unittest/disasm/tst.vartab-bvar-uregs0.x b/test/unittest/disasm/tst.vartab-bvar-uregs0.x
deleted file mode 100755
index 4fb7f8c1..00000000
--- a/test/unittest/disasm/tst.vartab-bvar-uregs0.x
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-read MAJOR MINOR <<< `uname -r | grep -Eo '^[0-9]+\.[0-9]+' | tr '.' ' '`
-
-if [ $MAJOR -gt 5 ]; then
-        exit 0
-fi
-if [ $MAJOR -eq 5 -a $MINOR -ge 15 ]; then
-        exit 0
-fi
-
-echo "no uregs on older kernels"
-exit 1
-- 
2.18.4




More information about the DTrace-devel mailing list