[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