diff mbox series

[bpf-next,v6,02/13] tools/resolve_btfids: Add support for resolving kfunc flags

Message ID 20220719132430.19993-3-memxor@gmail.com
State Handled Elsewhere
Delegated to: Pablo Neira
Headers show
Series New nf_conntrack kfuncs for insertion, changing timeout, status | expand

Commit Message

Kumar Kartikeya Dwivedi July 19, 2022, 1:24 p.m. UTC
A flag is a 4-byte symbol that may follow a BTF ID in a set8. This is
used in the kernel to tag kfuncs in BTF sets with certain flags. Add
support to resolve_btfids to resolve and patch these in so they are
available for lookup in the kernel by directly searching into the BTF
set.

Since we don't need lookup support for the flags, we can simply store
them in a list instead of rbtree.

Cc: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 tools/bpf/resolve_btfids/main.c | 115 ++++++++++++++++++++++++++++++--
 1 file changed, 108 insertions(+), 7 deletions(-)
diff mbox series

Patch

diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c
index 5d26f3c6f918..4d1b7224bc38 100644
--- a/tools/bpf/resolve_btfids/main.c
+++ b/tools/bpf/resolve_btfids/main.c
@@ -35,6 +35,10 @@ 
  *             __BTF_ID__typedef__pid_t__1:
  *             .zero 4
  *
+ *   flags   - store specified flag values after ORing them into the data:
+ *	       __BTF_ID__flags__0x0_0x0_0x0_0x0_0x0__1:
+ *	       .zero 4
+ *
  *   set     - store symbol size into first 4 bytes and sort following
  *             ID list
  *
@@ -45,6 +49,21 @@ 
  *             .zero 4
  *             __BTF_ID__func__vfs_fallocate__4:
  *             .zero 4
+ *
+ *   set8    - store symbol size into first 4 bytes and sort following
+ *             ID list
+ *
+ *             __BTF_ID__set8__list:
+ *             .zero 8
+ *             list:
+ *             __BTF_ID__func__vfs_getattr__3:
+ *             .zero 4
+ *	       __BTF_ID__flags__0x0_0x0_0x0_0x0_0x0__4:
+ *             .zero 4
+ *             __BTF_ID__func__vfs_fallocate__5:
+ *             .zero 4
+ *	       __BTF_ID__flags__0x0_0x0_0x0_0x0_0x0__6:
+ *             .zero 4
  */
 
 #define  _GNU_SOURCE
@@ -57,6 +76,7 @@ 
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <linux/list.h>
 #include <linux/rbtree.h>
 #include <linux/zalloc.h>
 #include <linux/err.h>
@@ -71,12 +91,17 @@ 
 #define BTF_UNION	"union"
 #define BTF_TYPEDEF	"typedef"
 #define BTF_FUNC	"func"
+#define BTF_FLAGS	"flags"
 #define BTF_SET		"set"
+#define BTF_SET8	"set8"
 
 #define ADDR_CNT	100
 
 struct btf_id {
-	struct rb_node	 rb_node;
+	union {
+		struct rb_node	 rb_node;
+		struct list_head ls_node;
+	};
 	char		*name;
 	union {
 		int	 id;
@@ -84,6 +109,8 @@  struct btf_id {
 	};
 	int		 addr_cnt;
 	bool		 is_set;
+	bool		 is_set8;
+	bool		 is_flag;
 	Elf64_Addr	 addr[ADDR_CNT];
 };
 
@@ -109,6 +136,8 @@  struct object {
 	struct rb_root	typedefs;
 	struct rb_root	funcs;
 
+	struct list_head flags;
+
 	int nr_funcs;
 	int nr_structs;
 	int nr_unions;
@@ -198,6 +227,20 @@  btf_id__add(struct rb_root *root, char *name, bool unique)
 	return id;
 }
 
+static struct btf_id *
+btf_id_flags__add(struct list_head *list, char *name)
+{
+	struct btf_id *id;
+
+	id = zalloc(sizeof(*id));
+	if (id) {
+		pr_debug("adding flags %s\n", name);
+		id->name = name;
+		list_add(&id->ls_node, list);
+	}
+	return id;
+}
+
 static char *get_id(const char *prefix_end)
 {
 	/*
@@ -231,14 +274,14 @@  static char *get_id(const char *prefix_end)
 	return id;
 }
 
-static struct btf_id *add_set(struct object *obj, char *name)
+static struct btf_id *add_set(struct object *obj, char *name, bool is_set8)
 {
 	/*
 	 * __BTF_ID__set__name
 	 * name =    ^
 	 * id   =         ^
 	 */
-	char *id = name + sizeof(BTF_SET "__") - 1;
+	char *id = name + (is_set8 ? sizeof(BTF_SET8 "__") : sizeof(BTF_SET "__")) - 1;
 	int len = strlen(name);
 
 	if (id >= name + len) {
@@ -262,6 +305,19 @@  static struct btf_id *add_symbol(struct rb_root *root, char *name, size_t size)
 	return btf_id__add(root, id, false);
 }
 
+static struct btf_id *add_flags(struct list_head *list, char *name, size_t size)
+{
+	char *id;
+
+	id = get_id(name + size);
+	if (!id) {
+		pr_err("FAILED to parse symbol name: %s\n", name);
+		return NULL;
+	}
+
+	return btf_id_flags__add(list, id);
+}
+
 /* Older libelf.h and glibc elf.h might not yet define the ELF compression types. */
 #ifndef SHF_COMPRESSED
 #define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */
@@ -444,9 +500,26 @@  static int symbols_collect(struct object *obj)
 		} else if (!strncmp(prefix, BTF_FUNC, sizeof(BTF_FUNC) - 1)) {
 			obj->nr_funcs++;
 			id = add_symbol(&obj->funcs, prefix, sizeof(BTF_FUNC) - 1);
+		/* flags */
+		} else if (!strncmp(prefix, BTF_FLAGS, sizeof(BTF_FLAGS) - 1)) {
+			id = add_flags(&obj->flags, prefix, sizeof(BTF_FLAGS) - 1);
+			if (id)
+				id->is_flag = true;
+		/* set8 */
+		} else if (!strncmp(prefix, BTF_SET8, sizeof(BTF_SET8) - 1)) {
+			id = add_set(obj, prefix, true);
+			/*
+			 * SET8 objects store list's count, which is encoded
+			 * in symbol's size, together with 'cnt' field hence
+			 * that - 1.
+			 */
+			if (id) {
+				id->cnt = sym.st_size / sizeof(uint64_t) - 1;
+				id->is_set8 = true;
+			}
 		/* set */
 		} else if (!strncmp(prefix, BTF_SET, sizeof(BTF_SET) - 1)) {
-			id = add_set(obj, prefix);
+			id = add_set(obj, prefix, false);
 			/*
 			 * SET objects store list's count, which is encoded
 			 * in symbol's size, together with 'cnt' field hence
@@ -482,6 +555,7 @@  static int symbols_resolve(struct object *obj)
 	int nr_unions   = obj->nr_unions;
 	int nr_funcs    = obj->nr_funcs;
 	struct btf *base_btf = NULL;
+	struct btf_id *flags_id;
 	int err, type_id;
 	struct btf *btf;
 	__u32 nr_types;
@@ -558,6 +632,17 @@  static int symbols_resolve(struct object *obj)
 		}
 	}
 
+	/* Resolve all the BTF ID flags */
+	list_for_each_entry(flags_id, &obj->flags, ls_node) {
+		int f1, f2, f3, f4, f5;
+
+		if (sscanf(flags_id->name, "0x%x_0x%x_0x%x_0x%x_0x%x", &f1, &f2, &f3, &f4, &f5) != 5) {
+			pr_err("FAILED: malformed flags, can't resolve: %s\n", flags_id->name);
+			goto out;
+		}
+		flags_id->id = f1 | f2 | f3 | f4 | f5;
+	}
+
 	err = 0;
 out:
 	btf__free(base_btf);
@@ -571,7 +656,8 @@  static int id_patch(struct object *obj, struct btf_id *id)
 	int *ptr = data->d_buf;
 	int i;
 
-	if (!id->id && !id->is_set)
+	/* For set, set8, and flags, id->id may be 0 */
+	if (!id->id && !id->is_set && !id->is_set8 && !id->is_flag)
 		pr_err("WARN: resolve_btfids: unresolved symbol %s\n", id->name);
 
 	for (i = 0; i < id->addr_cnt; i++) {
@@ -611,6 +697,17 @@  static int __symbols_patch(struct object *obj, struct rb_root *root)
 	return 0;
 }
 
+static int flags_patch(struct object *obj)
+{
+	struct btf_id *flags_id;
+
+	list_for_each_entry(flags_id, &obj->flags, ls_node) {
+		if (id_patch(obj, flags_id))
+			return -1;
+	}
+	return 0;
+}
+
 static int cmp_id(const void *pa, const void *pb)
 {
 	const int *a = pa, *b = pb;
@@ -643,13 +740,13 @@  static int sets_patch(struct object *obj)
 		}
 
 		idx = idx / sizeof(int);
-		base = &ptr[idx] + 1;
+		base = &ptr[idx] + (id->is_set8 ? 2 : 1);
 		cnt = ptr[idx];
 
 		pr_debug("sorting  addr %5lu: cnt %6d [%s]\n",
 			 (idx + 1) * sizeof(int), cnt, id->name);
 
-		qsort(base, cnt, sizeof(int), cmp_id);
+		qsort(base, cnt, id->is_set8 ? sizeof(uint64_t) : sizeof(int), cmp_id);
 
 		next = rb_next(next);
 	}
@@ -667,6 +764,9 @@  static int symbols_patch(struct object *obj)
 	    __symbols_patch(obj, &obj->sets))
 		return -1;
 
+	if (flags_patch(obj))
+		return -1;
+
 	if (sets_patch(obj))
 		return -1;
 
@@ -715,6 +815,7 @@  int main(int argc, const char **argv)
 	};
 	int err = -1;
 
+	INIT_LIST_HEAD(&obj.flags);
 	argc = parse_options(argc, argv, btfid_options, resolve_btfids_usage,
 			     PARSE_OPT_STOP_AT_NON_OPTION);
 	if (argc != 1)