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

eugene.loh at oracle.com eugene.loh at oracle.com
Mon Jan 30 21:36:15 UTC 2023


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>
---
 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




More information about the DTrace-devel mailing list