[DTrace-devel] [PATCH] Add the precompiled BPF function library as a build component
Kris Van Hees
kris.van.hees at oracle.com
Wed Mar 4 07:49:09 PST 2020
The previously added BPF function library source code is being replaced
by the source code in the bpf/ directory. It makes use of the new build
system support for compiling BPF code, thereby providing a better
integration with the DTrace build infrastructure.
(The build system changes for BPF code and this replacement for the
previously monolithic bpf_dlib.c are inspired by a patch by Eugene Loh
providing build time compilation of bpf_dlib.c.)
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
bpf/Build | 22 ++++
bpf/GNUmakefile | 5 +
bpf/get_gvar.c | 21 ++++
bpf/get_tvar.c | 21 ++++
bpf/map_gvar.c | 14 +++
bpf/map_tvar.c | 14 +++
bpf/memcpy.c | 99 +++++++++++++++++
bpf/set_gvar.c | 18 +++
bpf/set_tvar.c | 18 +++
bpf/strnlen.c | 82 ++++++++++++++
libdtrace/bpf_dlib.c | 257 -------------------------------------------
11 files changed, 314 insertions(+), 257 deletions(-)
create mode 100644 bpf/Build
create mode 100644 bpf/GNUmakefile
create mode 100644 bpf/get_gvar.c
create mode 100644 bpf/get_tvar.c
create mode 100644 bpf/map_gvar.c
create mode 100644 bpf/map_tvar.c
create mode 100644 bpf/memcpy.c
create mode 100644 bpf/set_gvar.c
create mode 100644 bpf/set_tvar.c
create mode 100644 bpf/strnlen.c
delete mode 100644 libdtrace/bpf_dlib.c
diff --git a/bpf/Build b/bpf/Build
new file mode 100644
index 00000000..cda738b6
--- /dev/null
+++ b/bpf/Build
@@ -0,0 +1,22 @@
+# 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.
+
+
+$(objdir)/include/.dir.stamp:
+ mkdir -p $(objdir)/include
+ ln -sf /usr/include/asm $(objdir)/include
+ ln -sf /usr/include/asm-generic $(objdir)/include
+ ln -sf /usr/include/linux $(objdir)/include
+ @touch $(objdir)/include/.dir.stamp
+
+BPFLIBS += bpf_dlib
+bpf_dlib_CPPFLAGS = -Ilibdtrace -I$(objdir)/include
+bpf_dlib_TARGET = dlibs/bpf_dlib
+bpf_dlib_DIR := $(current-dir)
+bpf_dlib_SRCDEPS = $(objdir)/include/.dir.stamp
+bpf_dlib_SOURCES = \
+ map_gvar.c get_gvar.c set_gvar.c \
+ map_tvar.c get_tvar.c set_tvar.c \
+ memcpy.c strnlen.c
diff --git a/bpf/GNUmakefile b/bpf/GNUmakefile
new file mode 100644
index 00000000..4a27e08b
--- /dev/null
+++ b/bpf/GNUmakefile
@@ -0,0 +1,5 @@
+%:
+ $(MAKE) -C .. $@
+
+all::
+ $(MAKE) -C .. all
diff --git a/bpf/get_gvar.c b/bpf/get_gvar.c
new file mode 100644
index 00000000..04e283ec
--- /dev/null
+++ b/bpf/get_gvar.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
+ */
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <bpf-helpers.h>
+
+#ifndef noinline
+# define noinline __attribute__((noinline))
+#endif
+
+struct bpf_map_def gvars;
+
+noinline uint64_t dt_get_gvar(uint32_t id)
+{
+ uint64_t *val;
+
+ val = bpf_map_lookup_elem(&gvars, &id);
+ return val ? *val : 0;
+}
diff --git a/bpf/get_tvar.c b/bpf/get_tvar.c
new file mode 100644
index 00000000..c0fe447e
--- /dev/null
+++ b/bpf/get_tvar.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
+ */
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <bpf-helpers.h>
+
+#ifndef noinline
+# define noinline __attribute__((noinline))
+#endif
+
+struct bpf_map_def tvars;
+
+noinline uint64_t dt_get_tvar(uint32_t id)
+{
+ uint64_t *val;
+
+ val = bpf_map_lookup_elem(&tvars, &id);
+ return val ? *val : 0;
+}
diff --git a/bpf/map_gvar.c b/bpf/map_gvar.c
new file mode 100644
index 00000000..1a943f3f
--- /dev/null
+++ b/bpf/map_gvar.c
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
+ */
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <bpf-helpers.h>
+
+struct bpf_map_def SEC("maps") gvars = {
+ .type = BPF_MAP_TYPE_ARRAY,
+ .key_size = sizeof(uint32_t),
+ .value_size = sizeof(uint64_t),
+ .max_entries = 16,
+};
diff --git a/bpf/map_tvar.c b/bpf/map_tvar.c
new file mode 100644
index 00000000..b7ab637a
--- /dev/null
+++ b/bpf/map_tvar.c
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
+ */
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <bpf-helpers.h>
+
+struct bpf_map_def SEC("maps") tvars = {
+ .type = BPF_MAP_TYPE_ARRAY,
+ .key_size = sizeof(uint32_t),
+ .value_size = sizeof(uint64_t),
+ .max_entries = 16,
+};
diff --git a/bpf/memcpy.c b/bpf/memcpy.c
new file mode 100644
index 00000000..6e0d17f4
--- /dev/null
+++ b/bpf/memcpy.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
+ */
+#include <stddef.h>
+#include <stdint.h>
+
+#ifndef noinline
+# define noinline __attribute__((noinline))
+#endif
+
+noinline int dt_memcpy_int(void *dst, void *src, size_t n)
+{
+ uint64_t *d = dst;
+ uint64_t *s = src;
+ size_t r, i;
+
+ if (n > 128)
+ return -1;
+
+ switch (n / 8) {
+ case 16:
+ d[15] = s[15];
+ case 15:
+ d[14] = s[14];
+ case 14:
+ d[13] = s[13];
+ case 13:
+ d[12] = s[12];
+ case 12:
+ d[11] = s[11];
+ case 11:
+ d[10] = s[10];
+ case 10:
+ d[9] = s[9];
+ case 9:
+ d[8] = s[8];
+ case 8:
+ d[7] = s[7];
+ case 7:
+ d[6] = s[6];
+ case 6:
+ d[5] = s[5];
+ case 5:
+ d[4] = s[4];
+ case 4:
+ d[3] = s[3];
+ case 3:
+ d[2] = s[2];
+ case 2:
+ d[1] = s[1];
+ case 1:
+ d[0] = s[0];
+ }
+
+ r = n % 8;
+ if (r >= 4) {
+ i = (n / 4) - 1;
+ ((uint32_t *)dst)[i] = ((uint32_t *)src)[i];
+ r -= 4;
+ }
+ if (r >= 2) {
+ i = (n / 2) - 1;
+ ((uint16_t *)dst)[i] = ((uint16_t *)src)[i];
+ r -= 2;
+ }
+ if (r) {
+ i = n - 1;
+ ((uint8_t *)dst)[i] = ((uint8_t *)src)[i];
+ }
+
+ return 0;
+}
+
+/*
+ * Copy a byte sequence of length n from src to dst. The function returns 0
+ * upon success and -1 when n is greater than 256. Both src and dst must be on
+ * a 64-bit address boundary.
+ *
+ * The size (n) must be no more than 256.
+ */
+noinline int dt_memcpy(void *dst, void *src, size_t n)
+{
+ uint64_t *d = dst;
+ uint64_t *s = src;
+
+ if (n > 128) {
+ if (dt_memcpy_int(d, s, 128))
+ return -1;
+ n -= 128;
+ if (n == 0)
+ return 0;
+
+ d += 16;
+ s += 16;
+ }
+
+ return dt_memcpy_int(d, s, n);
+}
diff --git a/bpf/set_gvar.c b/bpf/set_gvar.c
new file mode 100644
index 00000000..6cb5ed95
--- /dev/null
+++ b/bpf/set_gvar.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
+ */
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <bpf-helpers.h>
+
+#ifndef noinline
+# define noinline __attribute__((noinline))
+#endif
+
+struct bpf_map_def gvars;
+
+noinline void dt_set_gvar(uint32_t id, uint64_t val)
+{
+ bpf_map_update_elem(&gvars, &id, &val, BPF_ANY);
+}
diff --git a/bpf/set_tvar.c b/bpf/set_tvar.c
new file mode 100644
index 00000000..297fba31
--- /dev/null
+++ b/bpf/set_tvar.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
+ */
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <bpf-helpers.h>
+
+#ifndef noinline
+# define noinline __attribute__((noinline))
+#endif
+
+struct bpf_map_def tvars;
+
+noinline void dt_set_tvar(uint32_t id, uint64_t val)
+{
+ bpf_map_update_elem(&tvars, &id, &val, BPF_ANY);
+}
diff --git a/bpf/strnlen.c b/bpf/strnlen.c
new file mode 100644
index 00000000..7fe905ce
--- /dev/null
+++ b/bpf/strnlen.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
+ */
+#include <stddef.h>
+#include <stdint.h>
+
+#ifndef noinline
+# define noinline __attribute__((noinline))
+#endif
+
+/*
+ * Determine the length of a string, no longer than a given size.
+ *
+ * Currently, only strings smaller than 256 characters are supported.
+ *
+ * Strings are expected to be allocated in 64-bit chunks, which guarantees that
+ * every string starts on a 64-bit boundary and that the string data can be
+ * read in chunks of 64-bit values.
+ *
+ * Algorithm based on the strlen() implementation in the GNU C Library, written
+ * by Torbjorn Granlund with help from Dan Sahlin.
+ */
+#define STRNLEN_SUBV 0x0101010101010101UL
+#define STRNLEN_MASK 0x8080808080808080UL
+noinline int dt_strnlen_dw(const uint64_t *p, size_t n)
+{
+ uint64_t v = *p;
+ char *s = (char *)p;
+
+ if (((v - STRNLEN_SUBV) & ~v & STRNLEN_MASK) != 0) {
+ if (s[0] == 0)
+ return 0;
+ if (s[1] == 0)
+ return 1;
+ if (s[2] == 0)
+ return 2;
+ if (s[3] == 0)
+ return 3;
+ if (s[4] == 0)
+ return 4;
+ if (s[5] == 0)
+ return 5;
+ if (s[6] == 0)
+ return 6;
+ if (s[7] == 0)
+ return 7;
+ }
+
+ return 8;
+}
+
+noinline int dt_strnlen(const char *s, size_t maxlen)
+{
+ uint64_t *p = (uint64_t *)s;
+ int l = 0;
+ int n;
+
+#define STRNLEN_1_DW(p, n, l) \
+ do { \
+ n = dt_strnlen_dw(p++, 1); \
+ l += n; \
+ if (n < 8) \
+ return l; \
+ if ((char *)p - s > maxlen) \
+ return -1; \
+ } while (0)
+#define STRNLEN_4_DW(p, n, l) \
+ do { \
+ STRNLEN_1_DW(p, n, l); \
+ STRNLEN_1_DW(p, n, l); \
+ STRNLEN_1_DW(p, n, l); \
+ STRNLEN_1_DW(p, n, l); \
+ } while (0)
+
+ STRNLEN_4_DW(p, n, l);
+ STRNLEN_4_DW(p, n, l);
+ STRNLEN_4_DW(p, n, l);
+ STRNLEN_4_DW(p, n, l);
+
+ return -1;
+}
diff --git a/libdtrace/bpf_dlib.c b/libdtrace/bpf_dlib.c
deleted file mode 100644
index 3957a1f8..00000000
--- a/libdtrace/bpf_dlib.c
+++ /dev/null
@@ -1,257 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * COMPILE ON x86_64 WITH:
- * bpf-unknown-none-gcc -D__amd64 -I./libdtrace -I/usr/include \
- * -o build/dlibs/bpf_dlib.o -c libdtrace/bpf_dlib.c
- *
- * COMPILE ON aarch64 WITH:
- * bpf-unknown-none-gcc -D__aarch64__ -I./libdtrace -I/usr/include \
- * -o build/dlibs/bpf_dlib.o -c libdtrace/bpf_dlib.c
- *
- * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
- */
-#include <linux/bpf.h>
-#include <asm/ptrace.h>
-#include <stddef.h>
-#include <bpf-helpers.h>
-
-typedef unsigned char u8;
-typedef unsigned short u16;
-typedef unsigned int u32;
-typedef unsigned int uint32_t;
-typedef unsigned long u64;
-typedef unsigned long uint64_t;
-#define memset(x, y, z) __builtin_memset((x), (y), (z))
-#ifndef noinline
-# define noinline __attribute__((noinline))
-#endif
-
-#include <dt_bpf_ctx.h>
-
-struct syscall_data {
- struct pt_regs *regs;
- long syscall_nr;
- long arg[6];
-};
-
-struct bpf_map_def SEC("maps") buffers = {
- .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
- .key_size = sizeof(u32),
- .value_size = sizeof(u32),
- .max_entries = 16,
-};
-
-struct bpf_map_def SEC("maps") ecbs = {
- .type = BPF_MAP_TYPE_ARRAY,
- .key_size = sizeof(u32),
- .value_size = sizeof(u32),
- .max_entries = 16,
-};
-
-struct bpf_map_def SEC("maps") mem = {
- .type = BPF_MAP_TYPE_PERCPU_ARRAY,
- .key_size = sizeof(u32),
- .value_size = 2048,
- .max_entries = 1,
-};
-
-struct bpf_map_def SEC("maps") gvars = {
- .type = BPF_MAP_TYPE_ARRAY,
- .key_size = sizeof(u32),
- .value_size = sizeof(u64),
- .max_entries = 16,
-};
-
-struct bpf_map_def SEC("maps") tvars = {
- .type = BPF_MAP_TYPE_ARRAY,
- .key_size = sizeof(u32),
- .value_size = sizeof(u64),
- .max_entries = 16,
-};
-
-noinline u64 dt_get_gvar(u32 id)
-{
- u32 *val;
-
- val = bpf_map_lookup_elem(&gvars, &id);
- return val ? *val : 0;
-}
-
-noinline void dt_set_gvar(u32 id, u64 val)
-{
- bpf_map_update_elem(&gvars, &id, &val, BPF_ANY);
-}
-
-noinline u64 dt_get_tvar(u32 id)
-{
- u32 *val;
-
- val = bpf_map_lookup_elem(&tvars, &id);
- return val ? *val : 0;
-}
-
-noinline void dt_set_tvar(u32 id, u64 val)
-{
- bpf_map_update_elem(&tvars, &id, &val, BPF_ANY);
-}
-
-noinline int dt_memcpy_int(void *dst, void *src, size_t n)
-{
- u64 *d = dst;
- u64 *s = src;
- size_t r, i;
-
- if (n > 128)
- return -1;
-
- switch (n / 8) {
- case 16:
- d[15] = s[15];
- case 15:
- d[14] = s[14];
- case 14:
- d[13] = s[13];
- case 13:
- d[12] = s[12];
- case 12:
- d[11] = s[11];
- case 11:
- d[10] = s[10];
- case 10:
- d[9] = s[9];
- case 9:
- d[8] = s[8];
- case 8:
- d[7] = s[7];
- case 7:
- d[6] = s[6];
- case 6:
- d[5] = s[5];
- case 5:
- d[4] = s[4];
- case 4:
- d[3] = s[3];
- case 3:
- d[2] = s[2];
- case 2:
- d[1] = s[1];
- case 1:
- d[0] = s[0];
- }
-
- r = n % 8;
- if (r >= 4) {
- i = (n / 4) - 1;
- ((u32 *)dst)[i] = ((u32 *)src)[i];
- r -= 4;
- }
- if (r >= 2) {
- i = (n / 2) - 1;
- ((u16 *)dst)[i] = ((u16 *)src)[i];
- r -= 2;
- }
- if (r) {
- i = n - 1;
- ((u8 *)dst)[i] = ((u8 *)src)[i];
- }
-
- return 0;
-}
-
-/*
- * Copy a byte sequence of length n from src to dst. The function returns 0
- * upon success and -1 when n is greater than 256. Both src and dst must be on
- * a 64-bit address boundary.
- *
- * The size (n) must be no more than 256.
- */
-noinline int dt_memcpy(void *dst, void *src, size_t n)
-{
- u64 *d = dst;
- u64 *s = src;
-
- if (n > 128) {
- if (dt_memcpy_int(d, s, 128))
- return -1;
- n -= 128;
- if (n == 0)
- return 0;
-
- d += 16;
- s += 16;
- }
-
- return dt_memcpy_int(d, s, n);
-}
-
-/*
- * Determine the length of a string, no longer than a given size.
- *
- * Currently, only strings smaller than 256 characters are supported.
- *
- * Strings are expected to be allocated in 64-bit chunks, which guarantees that
- * every string starts on a 64-bit boundary and that the string data can be
- * read in chunks of 64-bit values.
- *
- * Algorithm based on the strlen() implementation in the GNU C Library, written
- * by Torbjorn Granlund with help from Dan Sahlin.
- */
-#define STRNLEN_SUBV 0x0101010101010101UL
-#define STRNLEN_MASK 0x8080808080808080UL
-noinline int dt_strnlen_dw(const u64 *p, size_t n)
-{
- u64 v = *p;
- char *s = (char *)p;
-
- if (((v - STRNLEN_SUBV) & ~v & STRNLEN_MASK) != 0) {
- if (s[0] == 0)
- return 0;
- if (s[1] == 0)
- return 1;
- if (s[2] == 0)
- return 2;
- if (s[3] == 0)
- return 3;
- if (s[4] == 0)
- return 4;
- if (s[5] == 0)
- return 5;
- if (s[6] == 0)
- return 6;
- if (s[7] == 0)
- return 7;
- }
-
- return 8;
-}
-
-noinline int dt_strnlen(const char *s, size_t maxlen)
-{
- u64 *p = (u64 *)s;
- int l = 0;
- int n;
-
-#define STRNLEN_1_DW(p, n, l) \
- do { \
- n = dt_strnlen_dw(p++, 1); \
- l += n; \
- if (n < 8) \
- return l; \
- if ((char *)p - s > maxlen) \
- return -1; \
- } while (0)
-#define STRNLEN_4_DW(p, n, l) \
- do { \
- STRNLEN_1_DW(p, n, l); \
- STRNLEN_1_DW(p, n, l); \
- STRNLEN_1_DW(p, n, l); \
- STRNLEN_1_DW(p, n, l); \
- } while (0)
-
- STRNLEN_4_DW(p, n, l);
- STRNLEN_4_DW(p, n, l);
- STRNLEN_4_DW(p, n, l);
- STRNLEN_4_DW(p, n, l);
-
- return -1;
-}
--
2.25.0
More information about the DTrace-devel
mailing list