[DTrace-devel] [PATCH 33/47] Fix value of post-increment expressions
Kris Van Hees
kris.van.hees at oracle.com
Sun May 3 20:17:54 PDT 2020
When using a post-increment (or post-decrement) on a variable of any
kind, the expression should evaluate to the old value.
E.g. trace(this->x++) generates (WRONG):
lddw %r8, [%fp-80] ! load old value
add %r8, 1 ! increment
stdw [%fp-80], %r8 ! store new value
(%r8 is used as value, which is old value + 1)
while instead it should generate (CORRECT):
lddw %r8, [%fp-80] ! load old value
mov %r7, 1 ! load increment
add %r7, %r8 ! add old value to increment
stdw [%fp-80], %r7 ! store new value
(%r8 is used as value, which is old value)
Tests are included in this patch for both pre-increment and
post-increment of each of the three variable kinds. Since the code
generator uses the same logic for increment and decrement, testing
just one is sufficient.
Orabug: 31220528
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
libdtrace/dt_cg.c | 19 ++++++++++++-------
test/unittest/codegen/tst.post_inc_gvar_val.d | 17 +++++++++++++++++
test/unittest/codegen/tst.post_inc_gvar_val.r | 5 +++++
test/unittest/codegen/tst.post_inc_lvar_val.d | 17 +++++++++++++++++
test/unittest/codegen/tst.post_inc_lvar_val.r | 5 +++++
test/unittest/codegen/tst.post_inc_tvar_val.d | 17 +++++++++++++++++
test/unittest/codegen/tst.post_inc_tvar_val.r | 5 +++++
test/unittest/codegen/tst.pre_inc_gvar_val.d | 17 +++++++++++++++++
test/unittest/codegen/tst.pre_inc_gvar_val.r | 5 +++++
test/unittest/codegen/tst.pre_inc_lvar_val.d | 17 +++++++++++++++++
test/unittest/codegen/tst.pre_inc_lvar_val.r | 5 +++++
test/unittest/codegen/tst.pre_inc_tvar_val.d | 17 +++++++++++++++++
test/unittest/codegen/tst.pre_inc_tvar_val.r | 5 +++++
13 files changed, 144 insertions(+), 7 deletions(-)
create mode 100644 test/unittest/codegen/tst.post_inc_gvar_val.d
create mode 100644 test/unittest/codegen/tst.post_inc_gvar_val.r
create mode 100644 test/unittest/codegen/tst.post_inc_lvar_val.d
create mode 100644 test/unittest/codegen/tst.post_inc_lvar_val.r
create mode 100644 test/unittest/codegen/tst.post_inc_tvar_val.d
create mode 100644 test/unittest/codegen/tst.post_inc_tvar_val.r
create mode 100644 test/unittest/codegen/tst.pre_inc_gvar_val.d
create mode 100644 test/unittest/codegen/tst.pre_inc_gvar_val.r
create mode 100644 test/unittest/codegen/tst.pre_inc_lvar_val.d
create mode 100644 test/unittest/codegen/tst.pre_inc_lvar_val.r
create mode 100644 test/unittest/codegen/tst.pre_inc_tvar_val.d
create mode 100644 test/unittest/codegen/tst.pre_inc_tvar_val.r
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 60037b9a..8f1120bd 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -1347,7 +1347,7 @@ dt_cg_prearith_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op)
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
/*
- * If we are modifying a variable, generate an stv instruction from
+ * If we are modifying a variable, generate a store instruction for
* the variable specified by the identifier. If we are storing to a
* memory address, generate code again for the left-hand side using
* DT_NF_REF to get the address, and then generate a store to it.
@@ -1382,7 +1382,7 @@ dt_cg_postarith_op(dt_node_t *dnp, dt_irlist_t *dlp,
struct bpf_insn instr;
ctf_id_t type;
ssize_t size = 1;
- int nreg;
+ int oreg, nreg;
if (dt_node_is_pointer(dnp)) {
type = ctf_type_resolve(ctfp, dnp->dn_type);
@@ -1392,27 +1392,32 @@ dt_cg_postarith_op(dt_node_t *dnp, dt_irlist_t *dlp,
dt_cg_node(dnp->dn_child, dlp, drp);
dnp->dn_reg = dnp->dn_child->dn_reg;
+ oreg = dnp->dn_reg;
- if ((nreg = dt_regset_alloc(drp)) == -1)
+ nreg = dt_regset_alloc(drp);
+ if (nreg == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
- instr = BPF_ALU64_IMM(op, dnp->dn_reg, size);
+ instr = BPF_MOV_IMM(nreg, size);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ instr = BPF_ALU64_REG(op, nreg, dnp->dn_reg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
/*
- * If we are modifying a variable, generate an stv instruction from
+ * If we are modifying a variable, generate a store instruction for
* the variable specified by the identifier. If we are storing to a
* memory address, generate code again for the left-hand side using
* DT_NF_REF to get the address, and then generate a store to it.
- * In both paths, we store the value from 'nreg' (the new value).
+ * In both paths, we store the value from %r0 (the new value).
*/
if (dnp->dn_child->dn_kind == DT_NODE_VAR) {
dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident);
+ dnp->dn_reg = nreg;
dt_cg_store_var(dnp, dlp, drp, idp);
+ dnp->dn_reg = oreg;
} else {
uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF;
- int oreg = dnp->dn_reg;
assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE);
assert(dnp->dn_child->dn_flags & DT_NF_LVALUE);
diff --git a/test/unittest/codegen/tst.post_inc_gvar_val.d b/test/unittest/codegen/tst.post_inc_gvar_val.d
new file mode 100644
index 00000000..6fa66b28
--- /dev/null
+++ b/test/unittest/codegen/tst.post_inc_gvar_val.d
@@ -0,0 +1,17 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 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.
+ */
+
+/*
+ * ASSERTION: Test that post-increment on an global variable evaluates to the
+ * old value of the global variable.
+ */
+
+BEGIN
+{
+ trace(x++);
+ exit(0);
+}
diff --git a/test/unittest/codegen/tst.post_inc_gvar_val.r b/test/unittest/codegen/tst.post_inc_gvar_val.r
new file mode 100644
index 00000000..dbd0b8da
--- /dev/null
+++ b/test/unittest/codegen/tst.post_inc_gvar_val.r
@@ -0,0 +1,5 @@
+ FUNCTION:NAME
+ :BEGIN 0
+
+-- @@stderr --
+dtrace: script 'test/unittest/codegen/tst.post_inc_gvar_val.d' matched 1 probe
diff --git a/test/unittest/codegen/tst.post_inc_lvar_val.d b/test/unittest/codegen/tst.post_inc_lvar_val.d
new file mode 100644
index 00000000..d340e578
--- /dev/null
+++ b/test/unittest/codegen/tst.post_inc_lvar_val.d
@@ -0,0 +1,17 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 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.
+ */
+
+/*
+ * ASSERTION: Test that post-increment on an local variable evaluates to the
+ * old value of the local variable.
+ */
+
+BEGIN
+{
+ trace(this->x++);
+ exit(0);
+}
diff --git a/test/unittest/codegen/tst.post_inc_lvar_val.r b/test/unittest/codegen/tst.post_inc_lvar_val.r
new file mode 100644
index 00000000..e6e33861
--- /dev/null
+++ b/test/unittest/codegen/tst.post_inc_lvar_val.r
@@ -0,0 +1,5 @@
+ FUNCTION:NAME
+ :BEGIN 0
+
+-- @@stderr --
+dtrace: script 'test/unittest/codegen/tst.post_inc_lvar_val.d' matched 1 probe
diff --git a/test/unittest/codegen/tst.post_inc_tvar_val.d b/test/unittest/codegen/tst.post_inc_tvar_val.d
new file mode 100644
index 00000000..f9c63910
--- /dev/null
+++ b/test/unittest/codegen/tst.post_inc_tvar_val.d
@@ -0,0 +1,17 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 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.
+ */
+
+/*
+ * ASSERTION: Test that post-increment on a TLS variable evaluates to the
+ * old value of the TLS variable.
+ */
+
+BEGIN
+{
+ trace(self->x++);
+ exit(0);
+}
diff --git a/test/unittest/codegen/tst.post_inc_tvar_val.r b/test/unittest/codegen/tst.post_inc_tvar_val.r
new file mode 100644
index 00000000..2d19b737
--- /dev/null
+++ b/test/unittest/codegen/tst.post_inc_tvar_val.r
@@ -0,0 +1,5 @@
+ FUNCTION:NAME
+ :BEGIN 0
+
+-- @@stderr --
+dtrace: script 'test/unittest/codegen/tst.post_inc_tvar_val.d' matched 1 probe
diff --git a/test/unittest/codegen/tst.pre_inc_gvar_val.d b/test/unittest/codegen/tst.pre_inc_gvar_val.d
new file mode 100644
index 00000000..0d7bca5e
--- /dev/null
+++ b/test/unittest/codegen/tst.pre_inc_gvar_val.d
@@ -0,0 +1,17 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 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.
+ */
+
+/*
+ * ASSERTION: Test that pre-increment on an global variable evaluates to the
+ * new value of the global variable.
+ */
+
+BEGIN
+{
+ trace(++x);
+ exit(0);
+}
diff --git a/test/unittest/codegen/tst.pre_inc_gvar_val.r b/test/unittest/codegen/tst.pre_inc_gvar_val.r
new file mode 100644
index 00000000..9625b369
--- /dev/null
+++ b/test/unittest/codegen/tst.pre_inc_gvar_val.r
@@ -0,0 +1,5 @@
+ FUNCTION:NAME
+ :BEGIN 1
+
+-- @@stderr --
+dtrace: script 'test/unittest/codegen/tst.pre_inc_gvar_val.d' matched 1 probe
diff --git a/test/unittest/codegen/tst.pre_inc_lvar_val.d b/test/unittest/codegen/tst.pre_inc_lvar_val.d
new file mode 100644
index 00000000..65a2ecfc
--- /dev/null
+++ b/test/unittest/codegen/tst.pre_inc_lvar_val.d
@@ -0,0 +1,17 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 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.
+ */
+
+/*
+ * ASSERTION: Test that pre-increment on an local variable evaluates to the
+ * new value of the local variable.
+ */
+
+BEGIN
+{
+ trace(++this->x);
+ exit(0);
+}
diff --git a/test/unittest/codegen/tst.pre_inc_lvar_val.r b/test/unittest/codegen/tst.pre_inc_lvar_val.r
new file mode 100644
index 00000000..1bca8c90
--- /dev/null
+++ b/test/unittest/codegen/tst.pre_inc_lvar_val.r
@@ -0,0 +1,5 @@
+ FUNCTION:NAME
+ :BEGIN 1
+
+-- @@stderr --
+dtrace: script 'test/unittest/codegen/tst.pre_inc_lvar_val.d' matched 1 probe
diff --git a/test/unittest/codegen/tst.pre_inc_tvar_val.d b/test/unittest/codegen/tst.pre_inc_tvar_val.d
new file mode 100644
index 00000000..ee671591
--- /dev/null
+++ b/test/unittest/codegen/tst.pre_inc_tvar_val.d
@@ -0,0 +1,17 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 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.
+ */
+
+/*
+ * ASSERTION: Test that pre-increment on an TLS variable evaluates to the
+ * new value of the TLS variable.
+ */
+
+BEGIN
+{
+ trace(++self->x);
+ exit(0);
+}
diff --git a/test/unittest/codegen/tst.pre_inc_tvar_val.r b/test/unittest/codegen/tst.pre_inc_tvar_val.r
new file mode 100644
index 00000000..d03ec6a2
--- /dev/null
+++ b/test/unittest/codegen/tst.pre_inc_tvar_val.r
@@ -0,0 +1,5 @@
+ FUNCTION:NAME
+ :BEGIN 1
+
+-- @@stderr --
+dtrace: script 'test/unittest/codegen/tst.pre_inc_tvar_val.d' matched 1 probe
--
2.26.0
More information about the DTrace-devel
mailing list