[DTrace-devel] [PATCH v3 2/3] Add support for strjoin() subroutine

Kris Van Hees kris.van.hees at oracle.com
Fri Sep 3 12:52:59 PDT 2021


Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
Reviewed-by: Eugene Loh <eugene.loh at oracle.com>
---
 bpf/Build                                     |  1 +
 bpf/strjoin.S                                 | 55 +++++++++++++++
 libdtrace/dt_cg.c                             | 68 +++++++++++++++++--
 libdtrace/dt_dlibs.c                          |  1 +
 test/unittest/codegen/tst.dfunc_reg_leak.d    | 36 ++++++++++
 test/unittest/codegen/tst.dfunc_reg_leak.r    |  1 +
 test/unittest/codegen/tst.tstring_leak.d      | 36 ++++++++++
 test/unittest/codegen/tst.tstring_leak.r      |  1 +
 test/unittest/codegen/tst.tstring_leak2.d     | 36 ++++++++++
 test/unittest/codegen/tst.tstring_leak2.r     |  1 +
 test/unittest/dif/strjoin.d                   |  6 +-
 .../funcs/strjoin/tst.strjoin-nested.d        | 34 ++++++++++
 .../funcs/strjoin/tst.strjoin-nested.r        |  1 +
 .../funcs/{ => strjoin}/tst.strjoin.d         |  3 +-
 .../funcs/{ => strjoin}/tst.strjoin.r         |  0
 15 files changed, 272 insertions(+), 8 deletions(-)
 create mode 100644 bpf/strjoin.S
 create mode 100644 test/unittest/codegen/tst.dfunc_reg_leak.d
 create mode 100644 test/unittest/codegen/tst.dfunc_reg_leak.r
 create mode 100644 test/unittest/codegen/tst.tstring_leak.d
 create mode 100644 test/unittest/codegen/tst.tstring_leak.r
 create mode 100644 test/unittest/codegen/tst.tstring_leak2.d
 create mode 100644 test/unittest/codegen/tst.tstring_leak2.r
 create mode 100644 test/unittest/funcs/strjoin/tst.strjoin-nested.d
 create mode 100644 test/unittest/funcs/strjoin/tst.strjoin-nested.r
 rename test/unittest/funcs/{ => strjoin}/tst.strjoin.d (80%)
 rename test/unittest/funcs/{ => strjoin}/tst.strjoin.r (100%)

diff --git a/bpf/Build b/bpf/Build
index e7682bc7..d7dbbd5a 100644
--- a/bpf/Build
+++ b/bpf/Build
@@ -26,6 +26,7 @@ bpf_dlib_SOURCES = \
 	get_bvar.c \
 	get_tvar.c set_tvar.c \
 	probe_error.c \
+	strjoin.S \
 	strlen.c
 
 bpf-check: $(objdir)/include/.dir.stamp
diff --git a/bpf/strjoin.S b/bpf/strjoin.S
new file mode 100644
index 00000000..2a19f2eb
--- /dev/null
+++ b/bpf/strjoin.S
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#define DT_STRLEN_BYTES		2
+
+#define BPF_FUNC_probe_read_str	45
+
+/*
+ * void dt_strjoin(char *dst, const char *s1, const char *s2)
+ */
+	.text
+	.align	4
+	.global	dt_strjoin
+	.type	dt_strjoin, @function
+dt_strjoin:
+	mov	%r9, %r1
+	mov	%r7, %r2
+	mov	%r8, %r3
+
+	mov	%r1, %r7
+	call	dt_strlen
+	mov	%r6, %r0
+	add	%r7, DT_STRLEN_BYTES
+
+	mov	%r1, %r8
+	call	dt_strlen
+	add	%r6, %r0
+	add	%r8, DT_STRLEN_BYTES
+
+	mov	%r1, %r6
+	mov	%r2, %r9
+	call	dt_strlen_store
+	add	%r9, DT_STRLEN_BYTES
+
+	lddw	%r6, STRSZ
+	and	%r6, 0xffffffff
+
+	mov	%r1, %r9
+	mov	%r2, %r6
+	mov	%r3, %r7
+	call	BPF_FUNC_probe_read_str
+	jslt	%r0, 0, .L1
+	jslt	%r0, 1, .L2
+	add	%r9, %r0
+	sub	%r9, 1
+.L2:
+	mov	%r1, %r9
+	mov	%r2, %r6
+	mov	%r3, %r8
+	call	BPF_FUNC_probe_read_str
+.L1:
+	exit
+	.size	dt_strjoin, .-dt_strjoin
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index e2af322a..9941ce5b 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -753,20 +753,30 @@ dt_cg_strlen(dt_irlist_t *dlp, dt_regset_t *drp, int dst, int src)
 	size_t		size = yypcb->pcb_hdl->dt_options[DTRACEOPT_STRSIZE];
 	uint_t		lbl_ok = dt_irlist_label(dlp);
 
+	TRACE_REGSET("        strlen:Begin");
+
 	assert(idp != NULL);
 	if (dt_regset_xalloc_args(drp) == -1)
 		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
 
-	emit(dlp,  BPF_MOV_REG(BPF_REG_1, src));
-	dt_regset_xalloc(drp, BPF_REG_0);
+	if (src != BPF_REG_1)
+		emit(dlp,  BPF_MOV_REG(BPF_REG_1, src));
+	if (dst != BPF_REG_0)
+		dt_regset_xalloc(drp, BPF_REG_0);
 
 	emite(dlp, BPF_CALL_FUNC(idp->di_id), idp);
 	dt_regset_free_args(drp);
 	emit(dlp,  BPF_BRANCH_IMM(BPF_JLE, BPF_REG_0, size, lbl_ok));
 	emit(dlp,  BPF_MOV_IMM(BPF_REG_0, size));
 	emitl(dlp, lbl_ok,
-		   BPF_MOV_REG(dst, BPF_REG_0));
-	dt_regset_free(drp, BPF_REG_0);
+		   BPF_NOP());
+
+	if (dst != BPF_REG_0) {
+		emit(dlp, BPF_MOV_REG(dst, BPF_REG_0));
+		dt_regset_free(drp, BPF_REG_0);
+	}
+
+	TRACE_REGSET("        strlen:End  ");
 }
 
 static void
@@ -3095,6 +3105,54 @@ dt_cg_subr_strlen(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 	TRACE_REGSET("    subr-strlen:End  ");
 }
 
+static void
+dt_cg_subr_strjoin(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+	dt_node_t	*s1 = dnp->dn_args;
+	dt_node_t	*s2 = s1->dn_list;
+	dt_ident_t	*idp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_strjoin");
+
+	assert(idp != NULL);
+
+	TRACE_REGSET("    subr-strjoin:Begin");
+
+	dt_cg_node(s1, dlp, drp);
+	dt_cg_check_notnull(dlp, drp, s1->dn_reg);
+	dt_cg_node(s2, dlp, drp);
+	dt_cg_check_notnull(dlp, drp, s2->dn_reg);
+
+	/*
+	 * The result needs be be a temporary string, so we request one.
+	 */
+	dnp->dn_reg = dt_regset_alloc(drp);
+	if (dnp->dn_reg == -1)
+		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+	dt_cg_tstring_alloc(yypcb, dnp);
+
+	emit(dlp,  BPF_LOAD(BPF_DW, dnp->dn_reg, BPF_REG_FP, DT_STK_DCTX));
+	emit(dlp,  BPF_LOAD(BPF_DW, dnp->dn_reg, dnp->dn_reg, DCTX_MEM));
+	emit(dlp,  BPF_ALU64_IMM(BPF_ADD, dnp->dn_reg, dnp->dn_tstring->dn_value));
+
+	if (dt_regset_xalloc_args(drp) == -1)
+		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+
+	emit(dlp,  BPF_MOV_REG(BPF_REG_1, dnp->dn_reg));
+	emit(dlp,  BPF_MOV_REG(BPF_REG_2, s1->dn_reg));
+	dt_regset_free(drp, s1->dn_reg);
+	if (s1->dn_tstring)
+		dt_cg_tstring_free(yypcb, s1);
+	emit(dlp,  BPF_MOV_REG(BPF_REG_3, s2->dn_reg));
+	dt_regset_free(drp, s2->dn_reg);
+	if (s2->dn_tstring)
+		dt_cg_tstring_free(yypcb, s2);
+	dt_regset_xalloc(drp, BPF_REG_0);
+	emite(dlp, BPF_CALL_FUNC(idp->di_id), idp);
+	dt_regset_free_args(drp);
+	dt_regset_free(drp, BPF_REG_0);
+
+	TRACE_REGSET("    subr-strjoin:End  ");
+}
+
 typedef void dt_cg_subr_f(dt_node_t *, dt_irlist_t *, dt_regset_t *);
 
 static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
@@ -3121,7 +3179,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
 	[DIF_SUBR_GETMAJOR]		= NULL,
 	[DIF_SUBR_GETMINOR]		= NULL,
 	[DIF_SUBR_DDI_PATHNAME]		= NULL,
-	[DIF_SUBR_STRJOIN]		= NULL,
+	[DIF_SUBR_STRJOIN]		= dt_cg_subr_strjoin,
 	[DIF_SUBR_LLTOSTR]		= NULL,
 	[DIF_SUBR_BASENAME]		= NULL,
 	[DIF_SUBR_DIRNAME]		= NULL,
diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c
index 04becfa6..771b7fe0 100644
--- a/libdtrace/dt_dlibs.c
+++ b/libdtrace/dt_dlibs.c
@@ -59,6 +59,7 @@ static const dt_ident_t		dt_bpf_symbols[] = {
 	DT_BPF_SYMBOL(dt_get_string, DT_IDENT_SYMBOL),
 	DT_BPF_SYMBOL(dt_get_tvar, DT_IDENT_SYMBOL),
 	DT_BPF_SYMBOL(dt_set_tvar, DT_IDENT_SYMBOL),
+	DT_BPF_SYMBOL(dt_strjoin, DT_IDENT_SYMBOL),
 	DT_BPF_SYMBOL(dt_strnlen, DT_IDENT_SYMBOL),
 	/* BPF maps */
 	DT_BPF_SYMBOL(aggs, DT_IDENT_PTR),
diff --git a/test/unittest/codegen/tst.dfunc_reg_leak.d b/test/unittest/codegen/tst.dfunc_reg_leak.d
new file mode 100644
index 00000000..29747d26
--- /dev/null
+++ b/test/unittest/codegen/tst.dfunc_reg_leak.d
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+/*
+ * Ensure that we do not leak registers with void expressions.
+ */
+
+#pragma D option quiet
+
+BEGIN {
+	strlen("a");
+	strlen("a");
+	strlen("a");
+	strlen("a");
+	strlen("a");
+	strlen("a");
+	strlen("a");
+	strlen("a");
+	strlen("a");
+	strlen("a");
+	strlen("a");
+	strlen("a");
+	strlen("a");
+	strlen("a");
+	strlen("a");
+	strlen("a");
+	exit(0);
+}
+
+ERROR {
+	exit(1);
+}
diff --git a/test/unittest/codegen/tst.dfunc_reg_leak.r b/test/unittest/codegen/tst.dfunc_reg_leak.r
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/unittest/codegen/tst.dfunc_reg_leak.r
@@ -0,0 +1 @@
+
diff --git a/test/unittest/codegen/tst.tstring_leak.d b/test/unittest/codegen/tst.tstring_leak.d
new file mode 100644
index 00000000..3d8dee2e
--- /dev/null
+++ b/test/unittest/codegen/tst.tstring_leak.d
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+/*
+ * Ensure that we do not leak tstrings with void expressions.
+ */
+
+#pragma D option quiet
+
+BEGIN {
+	strjoin("a", "b");
+	strjoin("a", "b");
+	strjoin("a", "b");
+	strjoin("a", "b");
+	strjoin("a", "b");
+	strjoin("a", "b");
+	strjoin("a", "b");
+	strjoin("a", "b");
+	strjoin("a", "b");
+	strjoin("a", "b");
+	strjoin("a", "b");
+	strjoin("a", "b");
+	strjoin("a", "b");
+	strjoin("a", "b");
+	strjoin("a", "b");
+	strjoin("a", "b");
+	exit(0);
+}
+
+ERROR {
+	exit(1);
+}
diff --git a/test/unittest/codegen/tst.tstring_leak.r b/test/unittest/codegen/tst.tstring_leak.r
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/unittest/codegen/tst.tstring_leak.r
@@ -0,0 +1 @@
+
diff --git a/test/unittest/codegen/tst.tstring_leak2.d b/test/unittest/codegen/tst.tstring_leak2.d
new file mode 100644
index 00000000..92d5c00f
--- /dev/null
+++ b/test/unittest/codegen/tst.tstring_leak2.d
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+/*
+ * Ensure that we do not leak tstrings with variable assignments.
+ */
+
+#pragma D option quiet
+
+BEGIN {
+	x = strjoin("a", "b");
+	x = strjoin("a", "b");
+	x = strjoin("a", "b");
+	x = strjoin("a", "b");
+	x = strjoin("a", "b");
+	x = strjoin("a", "b");
+	x = strjoin("a", "b");
+	x = strjoin("a", "b");
+	x = strjoin("a", "b");
+	x = strjoin("a", "b");
+	x = strjoin("a", "b");
+	x = strjoin("a", "b");
+	x = strjoin("a", "b");
+	x = strjoin("a", "b");
+	x = strjoin("a", "b");
+	x = strjoin("a", "b");
+	exit(0);
+}
+
+ERROR {
+	exit(1);
+}
diff --git a/test/unittest/codegen/tst.tstring_leak2.r b/test/unittest/codegen/tst.tstring_leak2.r
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/unittest/codegen/tst.tstring_leak2.r
@@ -0,0 +1 @@
+
diff --git a/test/unittest/dif/strjoin.d b/test/unittest/dif/strjoin.d
index e7834eb9..ee70dec8 100644
--- a/test/unittest/dif/strjoin.d
+++ b/test/unittest/dif/strjoin.d
@@ -1,6 +1,10 @@
-/* @@xfail: dtv2 */
 BEGIN
 {
 	trace(strjoin(probeprov, probename));
 	exit(0);
 }
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/strjoin/tst.strjoin-nested.d b/test/unittest/funcs/strjoin/tst.strjoin-nested.d
new file mode 100644
index 00000000..84ba459c
--- /dev/null
+++ b/test/unittest/funcs/strjoin/tst.strjoin-nested.d
@@ -0,0 +1,34 @@
+/*
+ * 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: Nested strjoin() works
+ *
+ * SECTION: Actions and Subroutines/strjoin()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	trace(strjoin(
+		strjoin(
+			strjoin(probeprov, ":"),
+			strjoin(probemod, ":")
+		),
+		strjoin(
+			strjoin(probefunc, ":"),
+			probename
+		)
+	      ));
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/strjoin/tst.strjoin-nested.r b/test/unittest/funcs/strjoin/tst.strjoin-nested.r
new file mode 100644
index 00000000..748852fb
--- /dev/null
+++ b/test/unittest/funcs/strjoin/tst.strjoin-nested.r
@@ -0,0 +1 @@
+dtrace:::BEGIN
diff --git a/test/unittest/funcs/tst.strjoin.d b/test/unittest/funcs/strjoin/tst.strjoin.d
similarity index 80%
rename from test/unittest/funcs/tst.strjoin.d
rename to test/unittest/funcs/strjoin/tst.strjoin.d
index beec500c..f52443bd 100644
--- a/test/unittest/funcs/tst.strjoin.d
+++ b/test/unittest/funcs/strjoin/tst.strjoin.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 */
 
 #pragma D option quiet
 
diff --git a/test/unittest/funcs/tst.strjoin.r b/test/unittest/funcs/strjoin/tst.strjoin.r
similarity index 100%
rename from test/unittest/funcs/tst.strjoin.r
rename to test/unittest/funcs/strjoin/tst.strjoin.r
-- 
2.33.0




More information about the DTrace-devel mailing list