[DTrace-devel] [PATCH 3/6] Change storage for local variables
eugene.loh at oracle.com
eugene.loh at oracle.com
Fri Mar 19 10:45:31 PDT 2021
From: Eugene Loh <eugene.loh at oracle.com>
Change how local variables are stored and accessed. Instead of
storing them as 8-byte quantities on the stack addressed by variable
ID, just use a monolithic, per-CPU BPF map addressed by a variable's
offset. This allows us to store local variables of "arbitrary" size
(e.g., > 8 bytes) and worry less about running out of stack space.
A pointer to the BPF map is kept on the stack in the DTrace context.
In general, local-variable access now greatly mimics global-variable
access.
A dtp field dt_maxlvaralloc tracks the largest local-variable
allocation that will be needed for any pcb.
This patch also backs out patch
"a4d5f5bda15d Ensure that local variables get a 0 value upon first load",
which changed dt_cg_load_var() to load a 0 when a clause-local variable
is read but not yet initialized in that clause. Note that:
x Such behavior is not needed for D language compliance -- see:
https://docs.oracle.com/en/operating-systems/oracle-linux
/dtrace-guide/dt_dlang.html#dt_clocal_dlang
which states, "Each clause-local variable is instantiated with an
undefined value the first time it is used in the script."
x The old patch was motivated by a BPF verifier issue when local
variables were kept on the stack, which is no longer the case.
x The old patch implemented this behavior for each clause, even though
clause-local variables should be persistent from clause to clause
(within the same probe firing). Thus, the old patch was faulty and
causing test/demo/vars/clause.d to fail.
Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
BPF-NOTES | 12 +-
libdtrace/dt_bpf.c | 12 +-
libdtrace/dt_cc.c | 6 +-
libdtrace/dt_cg.c | 56 +++---
libdtrace/dt_dctx.h | 76 ++------
libdtrace/dt_dis.c | 2 +-
libdtrace/dt_dlibs.c | 1 +
libdtrace/dt_impl.h | 1 +
libdtrace/dt_pcb.c | 3 +
test/demo/vars/clause.d | 3 +-
test/unittest/codegen/tst.stack_layout.r | 28 ++-
test/unittest/struct/tst.global_clauselocal.d | 163 ++++++++++++++++++
test/unittest/struct/tst.global_clauselocal.r | 7 +
.../variables/lvar/tst.load_before_store.d | 9 +-
test/unittest/variables/lvar/tst.struct.d | 5 +-
test/utils/print-stack-layout.c | 18 +-
16 files changed, 260 insertions(+), 142 deletions(-)
create mode 100644 test/unittest/struct/tst.global_clauselocal.d
create mode 100644 test/unittest/struct/tst.global_clauselocal.r
diff --git a/BPF-NOTES b/BPF-NOTES
index 27c2900e..20e2f204 100644
--- a/BPF-NOTES
+++ b/BPF-NOTES
@@ -32,15 +32,9 @@
add %rX, IMM stb [%rX+IMM], %rY
stb [%rX+0], %rY
-- Local variables can be stored on the stack, although that will limit us to
- 64 local variables (or 32, if we reserve half the stack as scratch space for
- constructing strings and map keys). That ought to be enough. Note that
- variables that store strings or structures that are larger than 8 bytes are
- stored by reference, i.e. the slot on the stack stores an offset into a
- memory block obtained as map value from an array map.
-
- This means that in its most basic form, local variable i can be loaded from
- [%fp-(i*8)-8].
+- Local variables can be stored in a per-CPU BPF map, which can be a large,
+ single block of memory. Access to local variables can be similar to how
+ we handle global variables.
- Global variables can be stored in a BPF map, which can be a large, single
block of memory. Variables can be accessed with three BPF instructions:
diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
index e33f6afd..f67764f3 100644
--- a/libdtrace/dt_bpf.c
+++ b/libdtrace/dt_bpf.c
@@ -173,6 +173,8 @@ set_task_offsets(dtrace_hdl_t *dtp)
* consumer handle (dt_strlen).
* - gvars: Global variables map. This is a global map with a singleton
* element (key 0) addressed by variable offset.
+ * - lvars: Local variables map. This is a per-CPU map with a singleton
+ * element (key 0) addressed by variable offset.
*
* FIXME: TLS variable storage is still being designed further so this is just
* a temporary placeholder and will most likely be replaced by something
@@ -195,7 +197,7 @@ set_task_offsets(dtrace_hdl_t *dtp)
int
dt_bpf_gmap_create(dtrace_hdl_t *dtp)
{
- int gvarsz, tvarc, aggsz;
+ int gvarsz, lvarsz, tvarc, aggsz;
int ci_mapfd;
uint32_t key = 0;
@@ -209,8 +211,9 @@ dt_bpf_gmap_create(dtrace_hdl_t *dtp)
/* Determine the aggregation buffer size. */
aggsz = dt_idhash_datasize(dtp->dt_aggs);
- /* Determine the number of global and TLS variables. */
+ /* Determine sizes for global, local, and TLS maps. */
gvarsz = (dt_idhash_datasize(dtp->dt_globals) + 7) & ~7;
+ lvarsz = (dtp->dt_maxlvaralloc + 7) & ~7;
tvarc = dt_idhash_peekid(dtp->dt_tls) - DIF_VAR_OTHER_UBASE;
/* Create global maps as long as there are no errors. */
@@ -257,6 +260,11 @@ dt_bpf_gmap_create(dtrace_hdl_t *dtp)
sizeof(uint32_t), gvarsz, 1) == -1)
return -1; /* dt_errno is set for us */
+ if (lvarsz > 0 &&
+ create_gmap(dtp, "lvars", BPF_MAP_TYPE_PERCPU_ARRAY,
+ sizeof(uint32_t), lvarsz, 1) == -1)
+ return -1; /* dt_errno is set for us */
+
if (tvarc > 0 &&
create_gmap(dtp, "tvars", BPF_MAP_TYPE_ARRAY,
sizeof(uint32_t), sizeof(uint64_t), tvarc) == -1)
diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
index b7362e4b..2fe91ae4 100644
--- a/libdtrace/dt_cc.c
+++ b/libdtrace/dt_cc.c
@@ -2082,8 +2082,8 @@ dt_compile(dtrace_hdl_t *dtp, int context, dtrace_probespec_t pspec, void *arg,
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
yypcb->pcb_idents = dt_idhash_create("ambiguous", NULL, 0, 0);
- yypcb->pcb_locals = dt_idhash_create("clause local", NULL,
- 0, DT_LVAR_MAX);
+ yypcb->pcb_locals = dt_idhash_create("clause local", NULL, 0,
+ UINT_MAX);
if (yypcb->pcb_idents == NULL || yypcb->pcb_locals == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
@@ -2244,7 +2244,7 @@ dt_construct(dtrace_hdl_t *dtp, dt_probe_t *prp, uint_t cflags, dt_ident_t *idp)
yypcb->pcb_idents = dt_idhash_create("ambiguous", NULL, 0, 0);
yypcb->pcb_locals = dt_idhash_create("clause local", NULL, 0,
- DT_LVAR_MAX);
+ UINT_MAX);
if (yypcb->pcb_idents == NULL || yypcb->pcb_locals == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index ab3fe761..da3e9ca6 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -165,6 +165,8 @@ dt_cg_tramp_prologue_act(dt_pcb_t *pcb, dt_activity_t act)
DT_CG_STORE_MAP_PTR("aggs", DCTX_AGG);
if (dt_idhash_datasize(dtp->dt_globals) > 0)
DT_CG_STORE_MAP_PTR("gvars", DCTX_GVARS);
+ if (dtp->dt_maxlvaralloc > 0)
+ DT_CG_STORE_MAP_PTR("lvars", DCTX_LVARS);
#undef DT_CG_STORE_MAP_PTR
}
@@ -1613,30 +1615,24 @@ static void
dt_cg_load_var(dt_node_t *dst, dt_irlist_t *dlp, dt_regset_t *drp)
{
dt_ident_t *idp = dt_ident_resolve(dst->dn_ident);
+ int map_ptr_offset = -1;
idp->di_flags |= DT_IDFLG_DIFR;
- if (idp->di_flags & DT_IDFLG_LOCAL) { /* local var */
- if ((dst->dn_reg = dt_regset_alloc(drp)) == -1)
- longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
- /*
- * If this is the first read for this local variable, we know
- * the value is 0. This avoids storing an initial 0 value in
- * the variable's stack location.
- */
- if (!(idp->di_flags & DT_IDFLG_DIFW))
- emit(dlp, BPF_MOV_IMM(dst->dn_reg, 0));
- else
- emit(dlp, BPF_LOAD(BPF_DW, dst->dn_reg, BPF_REG_FP, DT_STK_LVAR(idp->di_id)));
- return;
- }
-
- /* FIXME: need cleaner test for global var */
- if (!(idp->di_flags & DT_IDFLG_TLS) && idp->di_id >= DIF_VAR_OTHER_UBASE) {
+ /* first handle local and global variables */
+ if (idp->di_flags & DT_IDFLG_LOCAL)
+ map_ptr_offset = DCTX_LVARS;
+ else if (!(idp->di_flags & DT_IDFLG_TLS) && idp->di_id >= DIF_VAR_OTHER_UBASE)
+ map_ptr_offset = DCTX_GVARS;
+ if (map_ptr_offset != -1) {
if ((dst->dn_reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+
+ /* get the BPF map pointer */
emit(dlp, BPF_LOAD(BPF_DW, dst->dn_reg, BPF_REG_FP, DT_STK_DCTX));
- emit(dlp, BPF_LOAD(BPF_DW, dst->dn_reg, dst->dn_reg, DCTX_GVARS));
+ emit(dlp, BPF_LOAD(BPF_DW, dst->dn_reg, dst->dn_reg, map_ptr_offset));
+
+ /* load the variable value or address */
if ((dst->dn_flags & DT_NF_REF) == 0)
emit(dlp, BPF_LOAD(BPF_DW, dst->dn_reg, dst->dn_reg, idp->di_offset));
else
@@ -1645,6 +1641,7 @@ dt_cg_load_var(dt_node_t *dst, dt_irlist_t *dlp, dt_regset_t *drp)
return;
}
+ /* otherwise, handle thread-local and built-in variables */
if (dt_regset_xalloc_args(drp) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
@@ -1913,32 +1910,35 @@ dt_cg_store_var(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp,
uint_t varid;
idp->di_flags |= DT_IDFLG_DIFW;
- if (idp->di_flags & DT_IDFLG_LOCAL) { /* local var */
- emit(dlp, BPF_STORE(BPF_DW, BPF_REG_FP, DT_STK_LVAR(idp->di_id), src->dn_reg));
- return;
- }
-
- varid = idp->di_id - DIF_VAR_OTHER_UBASE;
- if (idp->di_flags & DT_IDFLG_TLS) /* TLS var */
- idp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_set_tvar");
- else { /* global var */
+ /* global and local variables (that is, not thread-local) */
+ if (!(idp->di_flags & DT_IDFLG_TLS)) {
int reg;
+ /* get pointer to BPF map (either lvars or gvars) */
if ((reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
emit(dlp, BPF_LOAD(BPF_DW, reg, BPF_REG_FP, DT_STK_DCTX));
- emit(dlp, BPF_LOAD(BPF_DW, reg, reg, DCTX_GVARS));
+ if (idp->di_flags & DT_IDFLG_LOCAL)
+ emit(dlp, BPF_LOAD(BPF_DW, reg, reg, DCTX_LVARS));
+ else
+ emit(dlp, BPF_LOAD(BPF_DW, reg, reg, DCTX_GVARS));
+
+ /* store by value or by reference */
if ((src->dn_flags & DT_NF_REF) == 0)
emit(dlp, BPF_STORE(BPF_DW, reg, idp->di_offset, src->dn_reg));
else {
emit(dlp, BPF_ALU64_IMM(BPF_ADD, reg, idp->di_offset));
dt_cg_memcpy(dlp, drp, reg, src->dn_reg, idp->di_size);
}
+
dt_regset_free(drp, reg);
return;
}
+ /* TLS var */
+ varid = idp->di_id - DIF_VAR_OTHER_UBASE;
+ idp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_set_tvar");
assert(idp != NULL);
if (dt_regset_xalloc_args(drp) == -1)
diff --git a/libdtrace/dt_dctx.h b/libdtrace/dt_dctx.h
index 2707f9fd..0873602c 100644
--- a/libdtrace/dt_dctx.h
+++ b/libdtrace/dt_dctx.h
@@ -40,6 +40,7 @@ typedef struct dt_dctx {
char *buf; /* Output buffer scratch memory */
char *agg; /* Aggregation data */
char *gvars; /* Global variables */
+ char *lvars; /* Local variables */
} dt_dctx_t;
#define DCTX_CTX offsetof(dt_dctx_t, ctx)
@@ -48,6 +49,7 @@ typedef struct dt_dctx {
#define DCTX_BUF offsetof(dt_dctx_t, buf)
#define DCTX_AGG offsetof(dt_dctx_t, agg)
#define DCTX_GVARS offsetof(dt_dctx_t, gvars)
+#define DCTX_LVARS offsetof(dt_dctx_t, lvars)
#define DCTX_SIZE ((int16_t)sizeof(dt_dctx_t))
/*
@@ -72,50 +74,27 @@ typedef struct dt_dctx {
*/
#define DT_STK_NREGS (MAX_BPF_REG - 2)
-/*
- * An area of 256 bytes is set aside on the stack as scratch area for things
- * like string operations. It extends from the end of the stack towards the
- * local variable storage area. DT_STK_LVAR_END is therefore the last byte
- * location on the stack that can be used for local variable storage.
- */
-#define DT_STK_SCRATCH_BASE (-MAX_BPF_STACK)
-#define DT_STK_SCRATCH_SZ (256)
-#define DT_STK_LVAR_END (DT_STK_SCRATCH_BASE + DT_STK_SCRATCH_SZ)
-
/*
* The stack layout for functions that implement a D clause is encoded with the
* following constants.
*
* Note: The BPF frame pointer points to the address of the first byte past the
- * end of the stack. If the stack size is 512 bytes, valid offsets are
- * -1 through -512 (inclusive), So, the first 64-bit value on the stack
- * occupies bytes at offsets -8 through -1. The second -16 through -9,
- * and so on... 64-bit values are properly aligned at offsets -n where
- * n is a multiple of 8 (sizeof(uint64_t)).
- *
- * The following diagram shows the stack layout for a size of 512 bytes.
+ * end of the stack. 8-byte values are properly aligned at offsets -8,
+ * -16, -24, -32, etc. -- that is, negative multiples of sizeof(uint64_t).
*
- * +----------------+
- * SCRATCH_BASE = -512 | Scratch Memory |
- * +----------------+
- * LVAR_END = LVAR(n) = -256 | LVAR n | (n = DT_LVAR_MAX = 17)
- * +----------------+
- * | ... |
- * +----------------+
- * LVAR(1) = -128 | LVAR 1 |
- * +----------------+
- * LVAR_BASE = LVAR(0) = -120 | LVAR 0 |
- * +----------------+
- * SPILL(n) = -112 | %r8 | (n = DT_STK_NREGS - 1 = 8)
- * +----------------+
- * | ... |
- * +----------------+
- * SPILL(1) = -56 | %r1 |
- * +----------------+
- * SPILL_BASE = SPILL(0) = -48 | %r0 |
- * +----------------+
- * DCTX = -40 | DTrace Context | -1
- * +----------------+
+ * +----------------+
+ * SCRATCH_BASE | Scratch Memory |
+ * +----------------+
+ * SPILL(n) | %r8 | (n = DT_STK_NREGS - 1 = 8)
+ * +----------------+
+ * | ... |
+ * +----------------+
+ * SPILL(1) | %r1 |
+ * +----------------+
+ * SPILL_BASE = SPILL(0) | %r0 |
+ * +----------------+
+ * DCTX | DTrace Context |
+ * +----------------+
*/
#define DT_STK_BASE ((int16_t)0)
#define DT_STK_SLOT_SZ ((int16_t)sizeof(uint64_t))
@@ -123,25 +102,8 @@ typedef struct dt_dctx {
#define DT_STK_DCTX (DT_STK_BASE - DCTX_SIZE)
#define DT_STK_SPILL_BASE (DT_STK_DCTX - DT_STK_SLOT_SZ)
#define DT_STK_SPILL(n) (DT_STK_SPILL_BASE - (n) * DT_STK_SLOT_SZ)
-#define DT_STK_LVAR_BASE (DT_STK_SPILL(DT_STK_NREGS - 1) - \
- DT_STK_SLOT_SZ)
-#define DT_STK_LVAR(n) (DT_STK_LVAR_BASE - (n) * DT_STK_SLOT_SZ)
-/*
- * Calculate a local variable ID based on a given stack offset. If the stack
- * offset is outside the valid range, this should evaluate as -1.
- */
-#define DT_LVAR_OFF2ID(n) (((n) > DT_STK_LVAR_BASE || \
- (n) < DT_STK_LVAR_END) ? -1 : \
- (-((n) - DT_STK_LVAR_BASE) / DT_STK_SLOT_SZ))
-
-/*
- * Maximum number of local variables stored by value (scalars). This is bound
- * by the choice to store them on the stack between the register spill space,
- * and 256 bytes set aside as string scratch space. We also use the fact that
- * the (current) maximum stack space for BPF programs is 512 bytes.
- */
-#define DT_LVAR_MAX (-(DT_STK_LVAR_END - DT_STK_LVAR_BASE) / \
- DT_STK_SLOT_SZ)
+#define DT_STK_SCRATCH_BASE (-MAX_BPF_STACK)
+#define DT_STK_SCRATCH_SZ (MAX_BPF_STACK + DT_STK_SPILL(DT_STK_NREGS - 1))
#endif /* _DT_DCTX_H */
diff --git a/libdtrace/dt_dis.c b/libdtrace/dt_dis.c
index d5ea79ca..d4f4ad67 100644
--- a/libdtrace/dt_dis.c
+++ b/libdtrace/dt_dis.c
@@ -68,7 +68,7 @@ dt_dis_lvarname(const dtrace_difo_t *dp, int reg, int var, uint_t addr,
char *buf, int len)
{
if (reg == BPF_REG_FP) {
- var = DT_LVAR_OFF2ID(var);
+ var = -1; /* FIXME: need to find variable offset */
if (var != -1) {
const char *vname;
diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c
index 2c293719..96f7c49a 100644
--- a/libdtrace/dt_dlibs.c
+++ b/libdtrace/dt_dlibs.c
@@ -66,6 +66,7 @@ static const dt_ident_t dt_bpf_symbols[] = {
DT_BPF_SYMBOL(buffers, DT_IDENT_PTR),
DT_BPF_SYMBOL(cpuinfo, DT_IDENT_PTR),
DT_BPF_SYMBOL(gvars, DT_IDENT_PTR),
+ DT_BPF_SYMBOL(lvars, DT_IDENT_PTR),
DT_BPF_SYMBOL(mem, DT_IDENT_PTR),
DT_BPF_SYMBOL(state, DT_IDENT_PTR),
DT_BPF_SYMBOL(strtab, DT_IDENT_PTR),
diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
index 5dee86e6..d782362f 100644
--- a/libdtrace/dt_impl.h
+++ b/libdtrace/dt_impl.h
@@ -252,6 +252,7 @@ struct dtrace_hdl {
char *dt_strtab; /* global string table (runtime) */
uint_t dt_strlen; /* global string table (runtime) size */
uint_t dt_maxreclen; /* largest record size across programs */
+ uint_t dt_maxlvaralloc; /* largest lvar alloc across pcbs */
dt_list_t dt_modlist; /* linked list of dt_module_t's */
dt_module_t **dt_mods; /* hash table of dt_module_t's */
uint_t dt_modbuckets; /* number of module hash buckets */
diff --git a/libdtrace/dt_pcb.c b/libdtrace/dt_pcb.c
index d2e8c3a7..b10c688e 100644
--- a/libdtrace/dt_pcb.c
+++ b/libdtrace/dt_pcb.c
@@ -158,6 +158,9 @@ dt_pcb_pop(dtrace_hdl_t *dtp, int err)
ctf_discard(dtp->dt_ddefs->dm_ctfp);
}
+ if (dtp->dt_maxlvaralloc < pcb->pcb_locals->dh_nextoff)
+ dtp->dt_maxlvaralloc = pcb->pcb_locals->dh_nextoff;
+
if (pcb->pcb_pragmas != NULL)
dt_idhash_destroy(pcb->pcb_pragmas);
if (pcb->pcb_locals != NULL)
diff --git a/test/demo/vars/clause.d b/test/demo/vars/clause.d
index bc332c50..7daa76f9 100644
--- a/test/demo/vars/clause.d
+++ b/test/demo/vars/clause.d
@@ -1,11 +1,10 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2021, 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 */
/* @@trigger: none */
int me; /* an integer global variable */
diff --git a/test/unittest/codegen/tst.stack_layout.r b/test/unittest/codegen/tst.stack_layout.r
index 78d41c82..3a23b689 100644
--- a/test/unittest/codegen/tst.stack_layout.r
+++ b/test/unittest/codegen/tst.stack_layout.r
@@ -1,17 +1,13 @@
Base: 0
-dctx: -40
-%r0: -48
-%r1: -56
-%r2: -64
-%r3: -72
-%r4: -80
-%r5: -88
-%r6: -96
-%r7: -104
-%r8: -112
-lvar[ -1]: -119 (ID -1)
-lvar[ 0]: -120 (ID 0)
-lvar[ 1]: -128 (ID 1)
-lvar[ 17]: -256 (ID 17)
-lvar[ -1]: -257 (ID -1)
-scratch: -257 .. -512
+dctx: -56
+%r0: -64
+%r1: -72
+%r2: -80
+%r3: -88
+%r4: -96
+%r5: -104
+%r6: -112
+%r7: -120
+%r8: -128
+DT_STK_SCRATCH_BASE: -512
+DT_STK_SCRATCH_SZ: 384
diff --git a/test/unittest/struct/tst.global_clauselocal.d b/test/unittest/struct/tst.global_clauselocal.d
new file mode 100644
index 00000000..6d45bc24
--- /dev/null
+++ b/test/unittest/struct/tst.global_clauselocal.d
@@ -0,0 +1,163 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2021, 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: Verify assignments between global and clause-local variables.
+ *
+ * SECTION: Structs and Unions/Structs
+ */
+
+#pragma D option quiet
+
+/*
+ * Declare some structs, including a struct of structs.
+ */
+
+struct coords {
+ int x, y;
+};
+struct particle {
+ struct coords position;
+ struct coords velocity;
+};
+
+/*
+ * Declare some global (uppercase) and clause-local (lowercase) variables.
+ * In each trio:
+ * - The first variable is ignored;
+ * it is declared just so we can test nonzero offsets.
+ * - The second variable is initialized.
+ * - The third variable is assigned to.
+ */
+ int K, L, M;
+this int k, l, m;
+ struct coords P, Q, R;
+this struct coords p, q, r;
+ struct particle A, B, C;
+this struct particle a, b, c;
+
+BEGIN {
+ /* Initialize the second variables. */
+ L = 11;
+ this->l = 12;
+ Q.x = 13;
+ Q.y = 14;
+ this->q.x = 15;
+ this->q.y = 16;
+ B.position.x = 17;
+ B.position.y = 18;
+ B.velocity.x = 19;
+ B.velocity.y = 20;
+ this->b.position.x = 21;
+ this->b.position.y = 22;
+ this->b.velocity.x = 23;
+ this->b.velocity.y = 24;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ L ,
+ this->l ,
+ Q.x ,
+ Q.y ,
+ this->q.x ,
+ this->q.y ,
+ B.position.x,
+ B.position.y,
+ B.velocity.x,
+ B.velocity.y,
+ this->b.position.x,
+ this->b.position.y,
+ this->b.velocity.x,
+ this->b.velocity.y);
+
+ /* assign scalars */
+
+ M = this->l + 1000;
+ this->m = Q.x + 1100;
+ R.x = Q.y + 1200;
+ R.y = this->q.x + 1300;
+ this->r.x = this->q.y + 1400;
+ this->r.y = B.velocity.x + 1500;
+ C.velocity.x = B.velocity.y + 1600;
+ C.velocity.y = this->b.velocity.x + 1700;
+ this->c.velocity.x = this->b.velocity.y + 1800;
+ this->c.velocity.y = L + 1900;
+
+ printf("%d %d %d %d %d %d %d %d %d %d\n",
+ M ,
+ this->m ,
+ R.x ,
+ R.y ,
+ this->r.x ,
+ this->r.y ,
+ C.velocity.x,
+ C.velocity.y,
+ this->c.velocity.x,
+ this->c.velocity.y);
+
+ /* assign struct (global-to-global or local-to-local) */
+
+ R = Q;
+ this->r = this->q;
+ C.velocity = B.velocity;
+ this->c.velocity = this->b.velocity;
+
+ printf("%d %d %d %d %d %d %d %d\n",
+ R.x,
+ R.y,
+ this->r.x,
+ this->r.y,
+ C.velocity.x,
+ C.velocity.y,
+ this->c.velocity.x,
+ this->c.velocity.y);
+
+ /* assign struct (global-to-local or local-to-global) */
+
+ R = this->q;
+ this->r = B.velocity;
+ C.velocity = this->b.velocity;
+ this->c.velocity = Q;
+
+ printf("%d %d %d %d %d %d %d %d\n",
+ R.x,
+ R.y,
+ this->r.x,
+ this->r.y,
+ C.velocity.x,
+ C.velocity.y,
+ this->c.velocity.x,
+ this->c.velocity.y);
+
+ /* assign struct of structs (global-to-global or local-to-local) */
+
+ C = B;
+ this->c = this->b;
+
+ printf("%d %d %d %d %d %d %d %d\n",
+ C.position.x, C.position.y,
+ C.velocity.x, C.velocity.y,
+ this->c.position.x, this->c.position.y,
+ this->c.velocity.x, this->c.velocity.y);
+
+ /* assign struct of structs (global-to-local or local-to-global) */
+
+ C = this->b;
+ this->c = B;
+
+ printf("%d %d %d %d %d %d %d %d\n",
+ C.position.x, C.position.y,
+ C.velocity.x, C.velocity.y,
+ this->c.position.x, this->c.position.y,
+ this->c.velocity.x, this->c.velocity.y);
+
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/struct/tst.global_clauselocal.r b/test/unittest/struct/tst.global_clauselocal.r
new file mode 100644
index 00000000..ef960c24
--- /dev/null
+++ b/test/unittest/struct/tst.global_clauselocal.r
@@ -0,0 +1,7 @@
+11 12 13 14 15 16 17 18 19 20 21 22 23 24
+1012 1113 1214 1315 1416 1519 1620 1723 1824 1911
+13 14 15 16 19 20 23 24
+15 16 19 20 23 24 13 14
+17 18 19 20 21 22 23 24
+21 22 23 24 17 18 19 20
+
diff --git a/test/unittest/variables/lvar/tst.load_before_store.d b/test/unittest/variables/lvar/tst.load_before_store.d
index 049719f3..98cdf120 100644
--- a/test/unittest/variables/lvar/tst.load_before_store.d
+++ b/test/unittest/variables/lvar/tst.load_before_store.d
@@ -1,16 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2021, 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 a load-before-store pattern for a local variable forces
- * the local variable to be initialized prior to loading.
- *
- * FAILURE: If the initialization is not done, the BPF verifier will reject
- * the program due to reading from an uninitialized stack location.
+ * ASSERTION: Test that a load-before-store pattern for a local variable
+ * does not cause the script to fail.
*
* SECTION: Variables/Clause-Local Variables
*/
diff --git a/test/unittest/variables/lvar/tst.struct.d b/test/unittest/variables/lvar/tst.struct.d
index 3309b487..c9530caf 100644
--- a/test/unittest/variables/lvar/tst.struct.d
+++ b/test/unittest/variables/lvar/tst.struct.d
@@ -1,10 +1,9 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2021, 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: Clause-local variables can be declared with a struct type.
@@ -21,7 +20,7 @@ this struct foo x;
BEGIN
{
this->x.a = 1;
- this->x.b = 1;
+ this->x.b = 5;
trace(this->x.a);
trace(this->x.b);
diff --git a/test/utils/print-stack-layout.c b/test/utils/print-stack-layout.c
index bb5da3af..1b5cdd54 100644
--- a/test/utils/print-stack-layout.c
+++ b/test/utils/print-stack-layout.c
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2021, 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.
*/
@@ -22,19 +22,7 @@ int main(void)
printf("%%r6: % 4d\n", DT_STK_SPILL(6));
printf("%%r7: % 4d\n", DT_STK_SPILL(7));
printf("%%r8: % 4d\n", DT_STK_SPILL(8));
- printf("lvar[% 3d]: % 4d (ID % 3d)\n", -1, DT_STK_LVAR(0) + 1,
- DT_LVAR_OFF2ID(DT_STK_LVAR(0) + 1));
- printf("lvar[% 3d]: % 4d (ID % 3d)\n", 0, DT_STK_LVAR(0),
- DT_LVAR_OFF2ID(DT_STK_LVAR(0)));
- printf("lvar[% 3d]: % 4d (ID % 3d)\n", 1, DT_STK_LVAR(1),
- DT_LVAR_OFF2ID(DT_STK_LVAR(1)));
- printf("lvar[% 3d]: % 4d (ID % 3d)\n", DT_LVAR_MAX,
- DT_STK_LVAR(DT_LVAR_MAX),
- DT_LVAR_OFF2ID(DT_STK_LVAR(DT_LVAR_MAX)));
- printf("lvar[% 3d]: % 4d (ID % 3d)\n", -1,
- DT_STK_LVAR(DT_LVAR_MAX) - 1,
- DT_LVAR_OFF2ID(DT_STK_LVAR(DT_LVAR_MAX) - 1));
- printf("scratch: % 4d .. % 4d\n", DT_STK_LVAR_END - 1,
- DT_STK_SCRATCH_BASE);
+ printf("DT_STK_SCRATCH_BASE: % 4d\n", DT_STK_SCRATCH_BASE);
+ printf("DT_STK_SCRATCH_SZ: % 4d\n", DT_STK_SCRATCH_SZ);
exit(0);
}
--
2.18.4
More information about the DTrace-devel
mailing list