[DTrace-devel] [PATCH 2/3] Add tracemem support

Kris Van Hees kris.van.hees at oracle.com
Fri Feb 24 03:22:19 UTC 2023


On Mon, Jan 30, 2023 at 04:36:15PM -0500, eugene.loh--- via DTrace-devel wrote:
> From: Eugene Loh <eugene.loh at oracle.com>
> 
> Also, replace tst.three_arg.sh with tst.tracemem.d:
> - to avoid the problematic profile probe (fires irregularly)
> - for cleaner post processing
> - to check both 2-arg and 3-arg results
> 
> 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                             |  45 +++++-
>  libdtrace/dt_consume.c                        |  13 +-
>  .../tracemem/err.D_TRACEMEM_ADDR.badaddr.d    |   4 +-
>  .../tracemem/err.D_TRACEMEM_SIZE.negsize.d    |   4 +-
>  .../tracemem/err.D_TRACEMEM_SIZE.zerosize.d   |   4 +-
>  test/unittest/tracemem/tst.init_task.d        |   4 +-
>  test/unittest/tracemem/tst.three_arg.sh       | 136 ------------------
>  test/unittest/tracemem/tst.tracemem.d         |  65 +++++++++
>  test/unittest/tracemem/tst.tracemem.r         |   9 ++
>  test/unittest/tracemem/tst.tracemem.r.p       |  30 ++++
>  test/unittest/types/tst.complex.d             |   3 +-
>  11 files changed, 167 insertions(+), 150 deletions(-)
>  delete mode 100755 test/unittest/tracemem/tst.three_arg.sh
>  create mode 100644 test/unittest/tracemem/tst.tracemem.d
>  create mode 100644 test/unittest/tracemem/tst.tracemem.r
>  create mode 100755 test/unittest/tracemem/tst.tracemem.r.p
> 
> diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
> index a0ca8d50..17843415 100644
> --- a/libdtrace/dt_cg.c
> +++ b/libdtrace/dt_cg.c
> @@ -2003,8 +2003,49 @@ dt_cg_act_trace(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
>  static void
>  dt_cg_act_tracemem(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
>  {
> -	dnerror(dnp, D_UNKNOWN, "tracemem() is not implemented (yet)\n");
> -	/* FIXME: Needs implementation */
> +	char		n[DT_TYPE_NAMELEN];
> +	dt_node_t	*addr = dnp->dn_args;
> +	dt_node_t	*nsiz = addr->dn_list;
> +	dt_node_t	*dsiz = nsiz->dn_list;
> +	dtrace_hdl_t	*dtp = pcb->pcb_hdl;
> +	dt_irlist_t	*dlp = &pcb->pcb_ir;
> +	dt_regset_t	*drp = pcb->pcb_regs;
> +	uint_t		off;
> +
> +	if (dt_node_is_integer(addr) == 0 && dt_node_is_pointer(addr) == 0)
> +		dnerror(addr, D_TRACEMEM_ADDR,
> +		    "tracemem( ) argument #1 is incompatible with prototype:\n"
> +		    "\tprototype: pointer or integer\n"
> +		    "\t argument: %s\n", dt_node_type_name(addr, n, sizeof(n)));
> +
> +	if (dt_node_is_posconst(nsiz) == 0)
> +		dnerror(nsiz, D_TRACEMEM_SIZE,
> +		    "tracemem( ) argument #2 must be a non-zero positive integral constant expression\n");
> +
> +	dt_cg_node(addr, dlp, drp);
> +	dt_cg_node(nsiz, dlp, drp);
> +
> +	off = dt_rec_add(dtp, dt_cg_fill_gap, DTRACEACT_TRACEMEM, nsiz->dn_value, 1, NULL,
> +	    dsiz ? DTRACE_TRACEMEM_DYNAMIC : DTRACE_TRACEMEM_STATIC);
> +
> +	if (dsiz != NULL)
> +		dt_cg_store_val(pcb, dsiz, DTRACEACT_TRACEMEM, NULL,
> +		    dsiz->dn_flags & DT_NF_SIGNED ? DTRACE_TRACEMEM_SSIZE : DTRACE_TRACEMEM_SIZE);
> +
> +	if (dt_regset_xalloc_args(drp) == -1)
> +		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
> +
> +	emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_9));
> +	emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, off));
> +	emit(dlp, BPF_MOV_REG(BPF_REG_2, nsiz->dn_reg));
> +	dt_regset_free(drp, nsiz->dn_reg);
> +	emit(dlp, BPF_MOV_REG(BPF_REG_3, addr->dn_reg));
> +	dt_regset_free(drp, addr->dn_reg);
> +
> +	dt_regset_xalloc(drp, BPF_REG_0);
> +	emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_read));
> +	dt_regset_free_args(drp);
> +	dt_regset_free(drp, BPF_REG_0);
>  }
>  
>  static void
> diff --git a/libdtrace/dt_consume.c b/libdtrace/dt_consume.c
> index bc2c6285..37a117b4 100644
> --- a/libdtrace/dt_consume.c
> +++ b/libdtrace/dt_consume.c
> @@ -1005,7 +1005,6 @@ dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
>  	return dt_print_rawbytes(dtp, fp, addr, nbytes);
>  }
>  
> -#ifdef FIXME
>  static int
>  dt_print_tracemem(dtrace_hdl_t *dtp, FILE *fp, const dtrace_recdesc_t *rec,
>      uint_t nrecs, const caddr_t buf)
> @@ -1053,7 +1052,6 @@ dt_print_tracemem(dtrace_hdl_t *dtp, FILE *fp, const dtrace_recdesc_t *rec,
>  
>  	return nconsumed;
>  }
> -#endif
>  
>  int
>  dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
> @@ -2454,6 +2452,17 @@ dt_consume_one_probe(dtrace_hdl_t *dtp, FILE *fp, char *data, uint32_t size,
>  			if (dt_print_umod(dtp, fp, NULL, recdata) < 0)
>  				return -1;
>  			continue;
> +		case DTRACEACT_TRACEMEM: {
> +			int nrecs;
> +
> +			nrecs = epd->dtdd_nrecs - i;
> +			n = dt_print_tracemem(dtp, fp, rec, nrecs, data);
> +			if (n < 0)
> +				return -1;
> +
> +			i += n - 1;
> +			continue;
> +		}
>  		case DTRACEACT_PRINTF:
>  			func = dtrace_fprintf;
>  			break;
> diff --git a/test/unittest/tracemem/err.D_TRACEMEM_ADDR.badaddr.d b/test/unittest/tracemem/err.D_TRACEMEM_ADDR.badaddr.d
> index f03d6502..0ad7d4e4 100644
> --- a/test/unittest/tracemem/err.D_TRACEMEM_ADDR.badaddr.d
> +++ b/test/unittest/tracemem/err.D_TRACEMEM_ADDR.badaddr.d
> @@ -1,10 +1,10 @@
>  /*
>   * Oracle Linux DTrace.
> - * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2006, 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.
>   */
> -/* @@xfail: dtv2 */
> +
>  /*
>   * ASSERTION:
>   *  Test tracemem() with an invalid address argument.
> diff --git a/test/unittest/tracemem/err.D_TRACEMEM_SIZE.negsize.d b/test/unittest/tracemem/err.D_TRACEMEM_SIZE.negsize.d
> index da29e230..a49c2a77 100644
> --- a/test/unittest/tracemem/err.D_TRACEMEM_SIZE.negsize.d
> +++ b/test/unittest/tracemem/err.D_TRACEMEM_SIZE.negsize.d
> @@ -1,10 +1,10 @@
>  /*
>   * Oracle Linux DTrace.
> - * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2006, 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.
>   */
> -/* @@xfail: dtv2 */
> +
>  /*
>   * ASSERTION:
>   *  Test tracemem() with a negative size argument.
> diff --git a/test/unittest/tracemem/err.D_TRACEMEM_SIZE.zerosize.d b/test/unittest/tracemem/err.D_TRACEMEM_SIZE.zerosize.d
> index 1292b872..e73a2e08 100644
> --- a/test/unittest/tracemem/err.D_TRACEMEM_SIZE.zerosize.d
> +++ b/test/unittest/tracemem/err.D_TRACEMEM_SIZE.zerosize.d
> @@ -1,10 +1,10 @@
>  /*
>   * Oracle Linux DTrace.
> - * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2006, 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.
>   */
> -/* @@xfail: dtv2 */
> +
>  /*
>   * ASSERTION:
>   *  Test tracemem() with a zero size argument.
> diff --git a/test/unittest/tracemem/tst.init_task.d b/test/unittest/tracemem/tst.init_task.d
> index 2e630385..bd8ef6e2 100644
> --- a/test/unittest/tracemem/tst.init_task.d
> +++ b/test/unittest/tracemem/tst.init_task.d
> @@ -1,10 +1,10 @@
>  /*
>   * Oracle Linux DTrace.
> - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2006, 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.
>   */
> -/* @@xfail: dtv2 - requires tracemem() */
> +
>  
>  /*
>   * ASSERTION:
> diff --git a/test/unittest/tracemem/tst.three_arg.sh b/test/unittest/tracemem/tst.three_arg.sh
> deleted file mode 100755
> index 63153ffa..00000000
> --- a/test/unittest/tracemem/tst.three_arg.sh
> +++ /dev/null
> @@ -1,136 +0,0 @@
> -#!/bin/bash
> -#
> -# Oracle Linux DTrace.
> -# Copyright (c) 2017, 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.
> -#
> -# @@xfail: dtv2
> -
> -#
> -# ASSERTION:
> -# Compare tracemem() results for two- and three-argument forms.
> -#
> -# SECTION: Actions and Subroutines/tracemem()
> -#
> -# @@timeout: 60
> -#
> -
> -if [ $# != 1 ]; then
> -	echo expected one argument: '<'dtrace-path'>'
> -	exit 2
> -fi
> -dtrace=$1
> -
> -#
> -# 26223475 DTrace tracemem on Linux missing support for 3-argument form
> -#
> -
> -DIRNAME="$tmpdir/three_arg_tracemem.$$.$RANDOM"
> -mkdir -p $DIRNAME
> -cd $DIRNAME
> -
> -# find a CPU to use (use first one we have available)
> -cpu=`taskset -cp $$ | awk '{print $NF}' | tr ',' ' ' | tr '-' ' '  | awk '{print $1}'`
> -
> -# trigger: copy bytes from /dev/zero to /dev/null
> -# bind to a CPU so DTrace output from different CPUs will not be interwoven
> -CMD="taskset -c $cpu dd iflag=count_bytes count=8GB if=/dev/zero of=/dev/null status=none"
> -
> -# DTrace test
> -#   - tracemem(2 args) writes 8 bytes (to check the 3-arg data)
> -#   - tracemem(3 args) writes alternatively 5 or 3 bytes
> -$dtrace -q $dt_flags -c "$CMD" -o out.txt -s /dev/stdin <<EOF
> -BEGIN
> -{
> -  x = 3;
> -}
> -profile-3
> -/arg0 && pid==\$target/
> -{
> -  x = 8 - x;
> -  tracemem(arg0, 8);
> -  tracemem(arg0, 32, x);
> -}
> -EOF
> -
> -# check result
> -status=$?
> -if [ "$status" -ne 0 ]; then
> -        echo $tst: dtrace failed
> -        rm -f out.txt
> -        exit $status
> -fi
> -
> -# awk file to post-process the data
> -cat > out.awk <<EOF
> -BEGIN {
> -    state = 0;   # moves cyclically from 0 to 1 to 2 to 3 and back to 0
> -    nerrs = 0;   # number of errors
> -    nchks = 0;   # number of lines that are correct
> -}
> -{
> -    if (and(state, 1)) {       # state 1 and state 3
> -        n = 5;                   # number of bytes is 5 for state 1 and 3 for state 3
> -        if (state == 3) {
> -            n = 3;
> -            state = -1;          # cycle state back around
> -        }
> -        if (NF != n) {
> -            printf "ERROR expected %d bytes but got %d\n", n, NF;
> -            nerrs += 1;
> -            exit 1;
> -        }
> -        for (i = 0; i < n; i++) {
> -            if (x[i] != (\$i + 0)) {    # $i+0 to convert $i to number
> -                printf "ERROR expected byte %x but got %x\n", x[i], \$i;
> -                nerrs += 1;
> -                exit 1;
> -            }
> -        }
> -        nchks += 1;
> -    } else {                             # state 0 and state 2
> -        if (NF != 8) {                   # number of bytes is 8
> -            printf "ERROR expected 8 bytes but got %d\n", NF;
> -            nerrs += 1;
> -            exit 1;
> -        }
> -        for (i = 0; i < 8; i++) x[i] = (\$i + 0);  # $i+0 to convert $i to number
> -    }
> -    state += 1;
> -}
> -END {
> -    if (nerrs == 0) {
> -        if (nchks < 4)
> -            printf "insufficient number (only %d) of checks\n", nchks;
> -        else
> -            print "SUCCESS";
> -    }
> -}
> -EOF
> -
> -# now post-process
> -#   - cut header lines
> -#   - cut empty lines
> -#   - cut encoded tail
> -#   - cut prefix
> -#   - do the awk processing
> -grep -v "0123456789abcdef" out.txt \
> -| grep -v '^$' \
> -| cut -c-55 \
> -| sed 's/^ *0://' \
> -| awk -f out.awk > out.post
> -
> -if [ `grep -c SUCCESS out.post` -eq 0 ]; then
> -    echo $tst: TEST FAILED
> -    echo "==================== out.txt start"
> -    cat out.txt
> -    echo "==================== out.txt end"
> -    echo "==================== out.post start"
> -    cat out.post
> -    echo "==================== out.post end"
> -    status=1
> -fi
> -
> -exit $status
> -
> diff --git a/test/unittest/tracemem/tst.tracemem.d b/test/unittest/tracemem/tst.tracemem.d
> new file mode 100644
> index 00000000..41440518
> --- /dev/null
> +++ b/test/unittest/tracemem/tst.tracemem.d
> @@ -0,0 +1,65 @@
> +/*
> + * 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: Results for tracemem() are correct.
> + *
> + * SECTION: Actions and Subroutines/tracemem()
> + */
> +
> +#pragma D option quiet
> +
> +long long *p;
> +
> +BEGIN {
> +	/* pick some pointer to kernel memory */
> +	p = (long long *) curthread;
> +
> +	/* dump memory at this pointer */
> +	printf("%16.16x %16.16x\n", p[ 0], p[ 1]);
> +	printf("%16.16x %16.16x\n", p[ 2], p[ 3]);
> +	printf("%16.16x %16.16x\n", p[ 4], p[ 5]);
> +	printf("%16.16x %16.16x\n", p[ 6], p[ 7]);
> +	printf("%16.16x %16.16x\n", p[ 8], p[ 9]);
> +	printf("%16.16x %16.16x\n", p[10], p[11]);
> +	printf("%16.16x %16.16x\n", p[12], p[13]);
> +	printf("%16.16x %16.16x\n", p[14], p[15]);
> +	printf("%16.16x %16.16x\n", p[16], p[17]);
> +	printf("%16.16x %16.16x\n", p[18], p[19]);
> +	printf("%16.16x %16.16x\n", p[20], p[21]);
> +	printf("%16.16x %16.16x\n", p[22], p[23]);
> +	printf("%16.16x %16.16x\n", p[24], p[25]);
> +	printf("%16.16x %16.16x\n", p[26], p[27]);
> +	printf("%16.16x %16.16x\n", p[28], p[29]);
> +	printf("%16.16x %16.16x\n", p[30], p[31]);
> +
> +	/* try tracemem() with this same pointer but various sizes */
> +
> +	tracemem(p, 256);	/* 256 bytes */
> +
> +	tracemem(p, 256,  -1);	/* 256 bytes (arg2 < 0) */
> +
> +	tracemem(p, 256,   0);	/*   0 bytes */
> +
> +	tracemem(p, 256,  32);	/*  32 bytes */
> +
> +	tracemem(p, 256,  64);	/*  64 bytes */
> +
> +	tracemem(p, 256, 128);	/* 128 bytes */
> +
> +	tracemem(p, 256, 256);	/* 256 bytes */
> +
> +	tracemem(p, 256, 320);	/* 256 bytes (arg1 <= arg2) */
> +
> +	tracemem(p, 256, (unsigned char) 0x80);
> +				/* 128 bytes */
> +
> +	tracemem(p, 256, (signed char) 0x80);
> +				/* 256 bytes (arg2 < 0) */
> +
> +	exit(0);
> +}
> diff --git a/test/unittest/tracemem/tst.tracemem.r b/test/unittest/tracemem/tst.tracemem.r
> new file mode 100644
> index 00000000..1b24115f
> --- /dev/null
> +++ b/test/unittest/tracemem/tst.tracemem.r
> @@ -0,0 +1,9 @@
> +256 bytes
> +256 bytes
> +32 bytes
> +64 bytes
> +128 bytes
> +256 bytes
> +256 bytes
> +128 bytes
> +256 bytes
> diff --git a/test/unittest/tracemem/tst.tracemem.r.p b/test/unittest/tracemem/tst.tracemem.r.p
> new file mode 100755
> index 00000000..3f34b26b
> --- /dev/null
> +++ b/test/unittest/tracemem/tst.tracemem.r.p
> @@ -0,0 +1,30 @@
> +#!/usr/bin/gawk -f
> +
> +# read data against which we will check tracemem() results
> +BEGIN {
> +        n = 0;    # count check results
> +        m = 0;    # count tracemem() results
> +}
> +NF == 2 {
> +        check[n] = $1; n++;
> +        check[n] = $2; n++;
> +        next;
> +}
> +
> +# if we have a blank line, report number of bytes compared, if any
> +NF == 0 && m > 0 { print 8 * m, "bytes" }
> +
> +# restart counting tracemem() output
> +NF == 0 { m = 0; next; }
> +
> +# comparison function
> +function mycomp(expect, actual) {
> +        if ( expect != actual )
> +                print "ERROR: expect", expect, "actual", actual;
> +}
> +
> +# tracemem output has two sets of 8 bytes each; reverse bytes for comparison
> +/:/ {
> +        mycomp( check[m++], $9$8$7$6$5$4$3$2);
> +        mycomp( check[m++], $17$16$15$14$13$12$11$10);
> +}
> diff --git a/test/unittest/types/tst.complex.d b/test/unittest/types/tst.complex.d
> index b55f80ad..4afd71ad 100644
> --- a/test/unittest/types/tst.complex.d
> +++ b/test/unittest/types/tst.complex.d
> @@ -1,10 +1,9 @@
>  /*
>   * Oracle Linux DTrace.
> - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2006, 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.
>   */
> -/* @@xfail: dtv2 - requires tracemem() */
>  
>  /*
>   * ASSERTION:
> -- 
> 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