[DTrace-devel] [PATCH 3/3] Add support for inet_ntoa() subroutine
eugene.loh at oracle.com
eugene.loh at oracle.com
Thu Mar 17 20:37:51 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..d635fdf3
--- /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
+
+/*
+ * uint64_t 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 02d9089c..163a75ac 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -4184,6 +4184,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", 1);
+}
+
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] = {
@@ -4229,7 +4235,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