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

Kris Van Hees kris.van.hees at oracle.com
Wed May 24 01:54:42 UTC 2023


On Fri, May 19, 2023 at 03:21:28PM -0400, eugene.loh--- via DTrace-devel wrote:
> From: Eugene Loh <eugene.loh at oracle.com>
> 
> Signed-off-by: Eugene Loh <eugene.loh at oracle.com>

Reviewed-by: Kris Van Hees <kris.van.hees 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
> 
> 
> _______________________________________________
> DTrace-devel mailing list
> DTrace-devel at oss.oracle.com
> https://oss.oracle.com/mailman/listinfo/dtrace-devel



More information about the DTrace-devel mailing list