[DTrace-devel] Add the precompiled BPF function library as a build component

Kris Van Hees kris.van.hees at oracle.com
Tue Mar 17 14:44:05 PDT 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..885100e2
--- /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 8a31854a..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