Blob Blame History Raw
From 16277e3910c9281d807fc6d3b4ce41c62d7d265e Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Thu, 19 May 2022 16:37:40 +0200
Subject: [PATCH 3/3] libbpf: Allow kernel_struct_has_field to reach field in
 unnamed struct or union

Some fields can belong to unnamed struct or union (e.g. rcu and
rcu_users fields of task_struct). In C, they are accessed as if their
belong directly to the parent of the unnamed struct or union but this
is not the case for BTF.

When looking for a field, kernel_struct_has_field should also look
reccursively into unnamed structs or unions. That allows code such as
the following to work as expected:

BPF.kernel_struct_has_field('task_struct', 'rcu')

Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
---
 src/cc/libbpf.c | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/src/cc/libbpf.c b/src/cc/libbpf.c
index 5f7a3f68..bdfde1f5 100644
--- a/src/cc/libbpf.c
+++ b/src/cc/libbpf.c
@@ -1319,12 +1319,27 @@ bool bpf_has_kernel_btf(void)
   return true;
 }
 
+static int find_member_by_name(struct btf *btf, const struct btf_type *btf_type, const char *field_name) {
+  const struct btf_member *btf_member = btf_members(btf_type);
+  int i;
+
+  for (i = 0; i < btf_vlen(btf_type); i++, btf_member++) {
+    const char *name = btf__name_by_offset(btf, btf_member->name_off);
+    if (!strcmp(name, field_name)) {
+      return 1;
+    } else if (name[0] == '\0') {
+      if (find_member_by_name(btf, btf__type_by_id(btf, btf_member->type), field_name))
+        return 1;
+    }
+  }
+  return 0;
+}
+
 int kernel_struct_has_field(const char *struct_name, const char *field_name)
 {
   const struct btf_type *btf_type;
-  const struct btf_member *btf_member;
   struct btf *btf;
-  int i, ret, btf_id;
+  int ret, btf_id;
 
   btf = libbpf_find_kernel_btf();
   ret = libbpf_get_error(btf);
@@ -1338,14 +1353,7 @@ int kernel_struct_has_field(const char *struct_name, const char *field_name)
   }
 
   btf_type = btf__type_by_id(btf, btf_id);
-  btf_member = btf_members(btf_type);
-  for (i = 0; i < btf_vlen(btf_type); i++, btf_member++) {
-    if (!strcmp(btf__name_by_offset(btf, btf_member->name_off), field_name)) {
-      ret = 1;
-      goto cleanup;
-    }
-  }
-  ret = 0;
+  ret = find_member_by_name(btf, btf_type, field_name);
 
 cleanup:
   btf__free(btf);
-- 
2.38.1