From 16277e3910c9281d807fc6d3b4ce41c62d7d265e Mon Sep 17 00:00:00 2001 From: Jerome Marchand 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 --- 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