[DTrace-devel] [PATCH v2 3/3] Add support for inet_ntoa() subroutine

eugene.loh at oracle.com eugene.loh at oracle.com
Fri Mar 18 19:36:44 UTC 2022


From: Eugene Loh <eugene.loh at oracle.com>

For the time being, there is no definition of ipaddr_t, which
traditionally has been defined in the kernel portion of DTrace.  So
for now, the prototype for the subroutine is not string(ipaddr_t*)
but string(void*) and the test defines ipaddr_t itself.

Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
 bpf/Build                           |   3 +-
 bpf/inet_ntoa.S                     | 220 ++++++++++++++++++++++++++++
 libdtrace/dt_cg.c                   |   8 +-
 libdtrace/dt_open.c                 |   2 +-
 test/unittest/funcs/tst.inet_ntoa.d |   5 +-
 5 files changed, 233 insertions(+), 5 deletions(-)
 create mode 100644 bpf/inet_ntoa.S

diff --git a/bpf/Build b/bpf/Build
index d2c19857..43f4b638 100644
--- a/bpf/Build
+++ b/bpf/Build
@@ -1,5 +1,5 @@
 # Oracle Linux DTrace.
-# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2020, 2022, 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.
 
@@ -28,6 +28,7 @@ bpf_dlib_SOURCES = \
 	get_bvar.c \
 	get_tvar.c \
 	index.S \
+	inet_ntoa.S \
 	lltostr.S \
 	mutex_owned.S \
 	mutex_owner.S \
diff --git a/bpf/inet_ntoa.S b/bpf/inet_ntoa.S
new file mode 100644
index 00000000..f8a3f112
--- /dev/null
+++ b/bpf/inet_ntoa.S
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ */
+
+	.text
+
+/*
+ * // This helper writes a uint8 as a string.
+ * // The output buffer is dst[STRSZ] and we start writing at &dst[off].
+ *
+ * uint64_t dt_inet_ntoa_write_uint8(uint64_t inp, char *dst, uint64_t off) {
+ *     uint64_t dig, nzr, len;
+ *
+ *     nzr = 0;         // nonzero if any nonzero digits have been written
+ *     len = STRSZ;
+ *     inp &= 0xff;
+ *
+ *     // write 100s digit
+ *     if (off >= len) return off;
+ *     dig = inp / 100;
+ *     nzr += dig;
+ *     dst[off] = '0' + dig;
+ *     if (nzr != 0) off++;
+ *
+ *     // write 10s digit
+ *     if (off >= len) return off;
+ *     inp -= 100 * dig;
+ *     dig = inp / 10;
+ *     nzr += dig;
+ *     dst[off] = '0' + dig;
+ *     if (nzr != 0) off++;
+ *
+ *     // write 1s digit
+ *     if (off >= len) return off;
+ *     inp -= 10 * dig;
+ *     dst[off] = '0' + inp;
+ *     off++;
+ *
+ *     return off;
+ * }
+ *
+ */
+
+	.align	4
+	.global	dt_inet_ntoa_write_uint8
+	.type	dt_inet_ntoa_write_uint8, @function
+dt_inet_ntoa_write_uint8:
+
+#define OFF %r0
+#define INP %r1
+#define DST %r2
+#define DIG %r5
+#define NZR %r6
+#define LEN %r7
+#define CHR %r8
+#define PTR %r9
+	mov	OFF, %r3
+
+	mov	NZR, 0
+	lddw	LEN, STRSZ
+	and	INP, 0xff
+
+	/* write 100s digit */
+	jlt	OFF, LEN, 1
+	exit
+	mov	DIG, INP
+	div	DIG, 100
+	add	NZR, DIG
+	mov	CHR, DIG
+	add	CHR, '0'
+	mov	PTR, DST
+	add	PTR, OFF
+	stxb	[PTR+0], CHR
+	jeq	NZR, 0, 1
+	add	OFF, 1
+
+	/* write 10s digit */
+	jlt	OFF, LEN, 1
+	exit
+	mul	DIG, 100
+	sub	INP, DIG
+	mov	DIG, INP
+	div	DIG, 10
+	add	NZR, DIG
+	mov	CHR, DIG
+	add	CHR, '0'
+	mov	PTR, DST
+	add	PTR, OFF
+	stxb	[PTR+0], CHR
+	jeq	NZR, 0, 1
+	add	OFF, 1
+
+	/* write 1s digit */
+	jlt	OFF, LEN, 1
+	exit
+	mul	DIG, 10
+	sub	INP, DIG
+	add	INP, '0'
+	add	DST, OFF
+	stxb	[DST+0], INP
+	add	OFF, 1
+	exit
+	.size	dt_inet_ntoa_write_uint8, .-dt_inet_ntoa_write_uint8
+#undef OFF
+#undef INP
+#undef DST
+#undef DIG
+#undef NZR
+#undef LEN
+#undef CHR
+#undef PTR
+
+/*
+ * void dt_inet_ntoa(uint8_t *src, char *dst) {
+ *     uint64_t off, inp, len;
+ *
+ *     off = 0
+ *     len = STRSZ;
+ *
+ *     inp = src[0];
+ *     off = dt_inet_ntoa_write_uint8(inp, dst, off);
+ *     if (off >= STRSZ) goto done:
+ *     dst[off++] = ':';
+ *
+ *     inp = src[1];
+ *     off = dt_inet_ntoa_write_uint8(inp, dst, off);
+ *     if (off >= STRSZ) goto done:
+ *     dst[off++] = ':';
+ *
+ *     inp = src[2];
+ *     off = dt_inet_ntoa_write_uint8(inp, dst, off);
+ *     if (off >= STRSZ) goto done:
+ *     dst[off++] = ':';
+ *
+ *     inp = src[3];
+ *     off = dt_inet_ntoa_write_uint8(inp, dst, off);
+ *
+ *     done:
+ *     dst[off] = '\0';
+ * }
+ *
+ */
+	.align	4
+	.global	dt_inet_ntoa
+	.type	dt_inet_ntoa, @function
+dt_inet_ntoa:
+
+/* off cycles between %r3 (input arg to subroutine) and %r0 (its return) */
+#define INP %r1
+#define SRC %r6
+#define DST %r7
+#define LEN %r8
+
+	mov	SRC, %r1
+	mov	DST, %r2
+
+#if 1
+#define BPF_FUNC_probe_read	4
+	/*
+	 * FIXME: copy src data over
+	 *
+	 * Currently, the code generator's handling of DT_CG_ALLOCA_NULLPTR
+	 * is such that there are scenarios where the BPF verifier thinks an
+	 * unsuitable value is being passed in as the "src" argument.  Until
+	 * this is fixed, simply use bpf_probe_read() to copy the src data
+	 * onto the BPF stack.  Reset the src argument to point to that
+	 * stack location.
+	 */
+	mov	%r3, %r1
+	mov	%r2, 4
+	mov	SRC, %fp
+	add	SRC, -4
+	mov	%r1, SRC
+	call	BPF_FUNC_probe_read
+#endif
+
+	mov	%r3, 0
+	lddw	LEN, STRSZ
+
+	ldxb	INP, [SRC+0]
+	mov	%r2, DST
+	call	dt_inet_ntoa_write_uint8
+	jge	%r0, LEN, .Ldone
+	mov	%r3, %r0
+	add	%r3, 1
+	add	%r0, DST
+	stb	[%r0+0], '.'
+
+	ldxb	INP, [SRC+1]
+	mov	%r2, DST
+	call	dt_inet_ntoa_write_uint8
+	jge	%r0, LEN, .Ldone
+	mov	%r3, %r0
+	add	%r3, 1
+	add	%r0, DST
+	stb	[%r0+0], '.'
+
+	ldxb	INP, [SRC+2]
+	mov	%r2, DST
+	call	dt_inet_ntoa_write_uint8
+	jge	%r0, LEN, .Ldone
+	mov	%r3, %r0
+	add	%r3, 1
+	add	%r0, DST
+	stb	[%r0+0], '.'
+
+	ldxb	INP, [SRC+3]
+	mov	%r2, DST
+	call	dt_inet_ntoa_write_uint8
+
+.Ldone:
+	add	DST, %r0
+	stb	[DST+0], 0
+	exit
+	.size	dt_inet_ntoa, .-dt_inet_ntoa
+#undef INP
+#undef SRC
+#undef DST
+#undef LEN
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 9bda35f3..88e0ed2b 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -4186,6 +4186,12 @@ dt_cg_subr_htonll(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 	emit(dlp, BPF_END_REG(BPF_DW, dnp->dn_reg, BPF_TO_BE));
 }
 
+static void
+dt_cg_subr_inet_ntoa(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+	dt_cg_subr_tstring1_helper(dnp, dlp, drp, "dt_inet_ntoa");
+}
+
 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] = {
@@ -4231,7 +4237,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
 	[DIF_SUBR_NTOHL]		= &dt_cg_subr_htonl,
 	[DIF_SUBR_NTOHLL]		= &dt_cg_subr_htonll,
 	[DIF_SUBR_INET_NTOP]		= NULL,
-	[DIF_SUBR_INET_NTOA]		= NULL,
+	[DIF_SUBR_INET_NTOA]		= &dt_cg_subr_inet_ntoa,
 	[DIF_SUBR_INET_NTOA6]		= NULL,
 	[DIF_SUBR_D_PATH]		= NULL,
 	[DIF_SUBR_LINK_NTOP]		= NULL,
diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
index 5bdc6037..1dcc5c7a 100644
--- a/libdtrace/dt_open.c
+++ b/libdtrace/dt_open.c
@@ -192,7 +192,7 @@ static const dt_ident_t _dtrace_globals[] = {
 { "index", DT_IDENT_FUNC, 0, DIF_SUBR_INDEX, DT_ATTR_STABCMN, DT_VERS_1_1,
 	&dt_idops_func, "int(const char *, const char *, [int])" },
 { "inet_ntoa", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOA, DT_ATTR_STABCMN,
-	DT_VERS_1_5, &dt_idops_func, "string(ipaddr_t *)" },
+	DT_VERS_1_5, &dt_idops_func, "string(void *)" }, /* FIXME should be ipaddr_t* */
 { "inet_ntoa6", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOA6, DT_ATTR_STABCMN,
 	DT_VERS_1_5, &dt_idops_func, "string(struct in6_addr *)" },
 { "inet_ntop", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOP, DT_ATTR_STABCMN,
diff --git a/test/unittest/funcs/tst.inet_ntoa.d b/test/unittest/funcs/tst.inet_ntoa.d
index 75161cf1..42ea7107 100644
--- a/test/unittest/funcs/tst.inet_ntoa.d
+++ b/test/unittest/funcs/tst.inet_ntoa.d
@@ -1,13 +1,14 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2022, 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
 
+typedef vmlinux`__be32 ipaddr_t;                  /* FIXME: how should this really be handled? */
+
 ipaddr_t *ip4a;
 ipaddr_t *ip4b;
 ipaddr_t *ip4c;
-- 
2.18.4




More information about the DTrace-devel mailing list