All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alan Maguire <alan.maguire@oracle.com>
To: ast@kernel.org, daniel@iogearbox.net, yhs@fb.com
Cc: kafai@fb.com, songliubraving@fb.com, andriin@fb.com,
	john.fastabend@gmail.com, kpsingh@chromium.org,
	linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
	bpf@vger.kernel.org, Alan Maguire <alan.maguire@oracle.com>
Subject: [RFC PATCH bpf-next 6/6] printk: extend test_printf to test %pT BTF-based format specifier
Date: Fri, 17 Apr 2020 11:42:40 +0100	[thread overview]
Message-ID: <1587120160-3030-7-git-send-email-alan.maguire@oracle.com> (raw)
In-Reply-To: <1587120160-3030-1-git-send-email-alan.maguire@oracle.com>

Add tests to verify basic types and to iterate through all
enums, structs, unions and typedefs ensuring expected behaviour
occurs.  Since test_printf can be built as a module we need to
export a BTF kind iterator function to allow us to iterate over
all names of a particular BTF kind.

These changes add up to approximately 10,000 new tests covering
all enum, struct, union and typedefs in vmlinux BTF.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
 include/linux/btf.h |  10 +++++
 kernel/bpf/btf.c    |  35 ++++++++++++++++
 lib/test_printf.c   | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 163 insertions(+)

diff --git a/include/linux/btf.h b/include/linux/btf.h
index 456bd8f..ef66d2e 100644
--- a/include/linux/btf.h
+++ b/include/linux/btf.h
@@ -177,4 +177,14 @@ static inline const char *btf_name_by_offset(const struct btf *btf,
 }
 #endif
 
+/* Following function used for testing BTF-based printk-family support */
+#ifdef CONFIG_BTF_PRINTF
+const char *btf_vmlinux_next_type_name(u8 kind, s32 *id);
+#else
+static inline const char *btf_vmlinux_next_type_name(u8 kind, s32 *id)
+{
+	return NULL;
+}
+#endif /* CONFIG_BTF_PRINTF */
+
 #endif
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index ae453f0..0703d1d 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -4867,3 +4867,38 @@ u32 btf_id(const struct btf *btf)
 {
 	return btf->id;
 }
+
+#ifdef CONFIG_BTF_PRINTF
+/*
+ * btf_vmlinux_next_type_name():  used in test_printf.c to
+ * iterate over types for testing.
+ * Exported as test_printf can be built as a module.
+ *
+ * @kind: BTF_KIND_* value
+ * @id: pointer to last id; value/result argument. When next
+ *      type name is found, we set *id to associated id.
+ * Returns:
+ *	Next type name, sets *id to associated id.
+ */
+const char *btf_vmlinux_next_type_name(u8 kind, s32 *id)
+{
+	const struct btf *btf = bpf_get_btf_vmlinux();
+	const struct btf_type *t;
+	const char *name;
+
+	if (!btf || !id)
+		return NULL;
+
+	for ((*id)++; *id <= btf->nr_types; (*id)++) {
+		t = btf->types[*id];
+		if (BTF_INFO_KIND(t->info) != kind)
+			continue;
+		name = btf_name_by_offset(btf, t->name_off);
+		if (name && strlen(name) > 0)
+			return name;
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(btf_vmlinux_next_type_name);
+#endif /* CONFIG_BTF_PRINTF */
diff --git a/lib/test_printf.c b/lib/test_printf.c
index 2d9f520..9743e96 100644
--- a/lib/test_printf.c
+++ b/lib/test_printf.c
@@ -23,6 +23,9 @@
 #include <linux/mm.h>
 
 #include <linux/property.h>
+#include <linux/bpf.h>
+#include <linux/btf.h>
+#include <linux/skbuff.h>
 
 #include "../tools/testing/selftests/kselftest_module.h"
 
@@ -644,6 +647,120 @@ static void __init fwnode_pointer(void)
 #endif
 }
 
+#define	__TEST_BTF(type, var, expected)	test(expected, "%pT<"#type">", &var)
+
+#define TEST_BTF(type, var, ...)					\
+	do {								\
+		type var = __VA_ARGS__;					\
+		pr_debug("type %s: %pT<" #type ">", #type, &var);	\
+		__TEST_BTF(type, var, #__VA_ARGS__);			\
+	} while (0)
+
+#define	BTF_MAX_DATA_SIZE	8192
+#define	BTF_MAX_BUF_SIZE	(BTF_MAX_DATA_SIZE * 8)
+
+static void __init
+btf_print_kind(u8 kind, const char *kind_name)
+{
+	char fmt1[256], fmt2[256];
+	int res1, res2, res3;
+	const char *name;
+	u64 *dummy_data;
+	s32 id = 0;
+	char *buf;
+
+	dummy_data = kzalloc(BTF_MAX_DATA_SIZE, GFP_KERNEL);
+	buf = kzalloc(BTF_MAX_BUF_SIZE, GFP_KERNEL);
+	for (;;) {
+		name = btf_vmlinux_next_type_name(kind, &id);
+		if (!name)
+			break;
+
+		total_tests++;
+
+		strncpy(fmt1, "%pT<", sizeof(fmt1));
+		strncat(fmt1, kind_name, sizeof(fmt1));
+		strncat(fmt1, name, sizeof(fmt1));
+		strncat(fmt1, ">", sizeof(fmt1));
+
+		strncpy(fmt2, "%pTN<", sizeof(fmt2));
+		strncat(fmt2, kind_name, sizeof(fmt2));
+		strncat(fmt2, name, sizeof(fmt2));
+		strncat(fmt2, ">", sizeof(fmt2));
+
+		res1 = snprintf(buf, BTF_MAX_BUF_SIZE, fmt1, dummy_data);
+		res2 = snprintf(buf, 0, fmt1, dummy_data);
+		res3 = snprintf(buf, BTF_MAX_BUF_SIZE, fmt2, dummy_data);
+
+		/*
+		 * Ensure return value is > 0 and identical irrespective
+		 * of whether we pass in a big enough buffer;
+		 * also ensure that printing names always results in as
+		 * long/longer buffer length.
+		 */
+		if (res1 <= 0 || res2 <= 0 || res3 <= 0) {
+			pr_warn("snprintf(%s%s); %d <= 0",
+				kind_name, name,
+				res1 <= 0 ? res1 : res2 <= 0 ? res2 : res3);
+			failed_tests++;
+		} else if (res1 != res2) {
+			pr_warn("snprintf(%s%s): %d != %d",
+				kind_name, name, res1, res2);
+			failed_tests++;
+		} else if (res3 < res2) {
+			pr_warn("snprintf(%s%s); %d < %d",
+				kind_name, name, res3, res2);
+			failed_tests++;
+		} else {
+			pr_debug("Printed %s%s (%d bytes, %d bytes with names)",
+				 kind_name, name, res1, res3);
+		}
+	}
+	kfree(dummy_data);
+	kfree(buf);
+}
+
+static void __init
+btf_pointer(void)
+{
+	struct sk_buff *skb = alloc_skb(64, GFP_KERNEL);
+#ifdef CONFIG_BTF_PRINTF
+	TEST_BTF(int, testint, 0);
+	TEST_BTF(int, testint, 1234);
+	TEST_BTF(int, testint, -4567);
+	TEST_BTF(bool, testbool, 0);
+	TEST_BTF(bool, testbool, 1);
+	TEST_BTF(int64_t, testint64, 0);
+	TEST_BTF(int64_t, testint64, 1234);
+	TEST_BTF(int64_t, testint64, -4567);
+	TEST_BTF(char, testchar, 100);
+	TEST_BTF(enum bpf_arg_type, testenum, ARG_CONST_MAP_PTR);
+#endif /* CONFIG_BTF_PRINTF */
+
+	/*
+	 * Iterate every instance of each kind, printing each associated type.
+	 * This constitutes around 10k tests.
+	 */
+	btf_print_kind(BTF_KIND_STRUCT, "struct ");
+	btf_print_kind(BTF_KIND_UNION, "union ");
+	btf_print_kind(BTF_KIND_ENUM, "enum ");
+	btf_print_kind(BTF_KIND_TYPEDEF, "");
+
+	/* verify unknown type falls back to hashed pointer display */
+	test_hashed("%pT<unknown_type>", NULL);
+	test_hashed("%pT<unknown_type>", skb);
+
+	/* verify use of unknown modifier X returns error string */
+	test("(%pT?)<unknown_type>", "%pTX<unknown_type>", skb);
+
+	/* No space separation is allowed other than for struct|enum|union */
+	test("(%pT?)", "%pT<invalid format>", skb);
+	/* Missing ">" format error */
+	test("(%pT?)", "%pT<struct sk_buff", skb);
+
+	kfree_skb(skb);
+}
+
 static void __init
 test_pointer(void)
 {
@@ -668,6 +785,7 @@ static void __init fwnode_pointer(void)
 	flags();
 	errptr();
 	fwnode_pointer();
+	btf_pointer();
 }
 
 static void __init selftest(void)
-- 
1.8.3.1


  parent reply	other threads:[~2020-04-17 10:43 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-17 10:42 [RFC PATCH bpf-next 0/6] bpf, printk: add BTF-based type printing Alan Maguire
2020-04-17 10:42 ` [RFC PATCH bpf-next 1/6] bpf: provide function to get vmlinux BTF information Alan Maguire
2020-04-17 10:42 ` [RFC PATCH bpf-next 2/6] bpf: btf->resolved_[ids,sizes] should not be used for vmlinux BTF Alan Maguire
2020-04-17 10:42 ` [RFC PATCH bpf-next 3/6] bpf: move to generic BTF show support, apply it to seq files/strings Alan Maguire
2020-04-17 10:42 ` [RFC PATCH bpf-next 4/6] checkpatch: add new BTF pointer format specifier Alan Maguire
2020-04-17 10:42 ` [RFC PATCH bpf-next 5/6] printk: add type-printing %pT<type> format specifier which uses BTF Alan Maguire
2020-04-29 12:09   ` Rasmus Villemoes
2020-04-17 10:42 ` Alan Maguire [this message]
2020-04-17 16:47 ` [RFC PATCH bpf-next 0/6] bpf, printk: add BTF-based type printing Arnaldo Carvalho de Melo
2020-04-17 17:06   ` Alan Maguire
2020-04-18 16:05 ` Alexei Starovoitov
2020-04-18 20:31   ` Arnaldo Melo
2020-04-20 15:29   ` Alan Maguire
2020-04-20 16:32     ` Joe Perches
2020-04-29 12:15       ` Rasmus Villemoes
2020-04-30 10:03       ` Alan Maguire
2020-05-02  0:25         ` Joe Perches
2020-04-20 20:54   ` Arnaldo Carvalho de Melo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1587120160-3030-7-git-send-email-alan.maguire@oracle.com \
    --to=alan.maguire@oracle.com \
    --cc=andriin@fb.com \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=john.fastabend@gmail.com \
    --cc=kafai@fb.com \
    --cc=kpsingh@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=songliubraving@fb.com \
    --cc=yhs@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.