Skip to content

Commit 302db0f

Browse files
committed
tracing/probes: Add a function to search a member of a struct/union
Add btf_find_struct_member() API to search a member of a given data structure or union from the member's name. Link: https://lore.kernel.org/all/169272156248.160970.8868479822371129043.stgit@devnote2/ Signed-off-by: Masami Hiramatsu (Google) <[email protected]> Reviewed-by: Alan Maguire <[email protected]> Acked-by: Steven Rostedt (Google) <[email protected]>
1 parent ebeed8d commit 302db0f

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

kernel/trace/trace_btf.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0
22
#include <linux/btf.h>
33
#include <linux/kernel.h>
4+
#include <linux/slab.h>
45

56
#include "trace_btf.h"
67

@@ -51,3 +52,71 @@ const struct btf_param *btf_get_func_param(const struct btf_type *func_proto, s3
5152
return NULL;
5253
}
5354

55+
#define BTF_ANON_STACK_MAX 16
56+
57+
struct btf_anon_stack {
58+
u32 tid;
59+
u32 offset;
60+
};
61+
62+
/*
63+
* Find a member of data structure/union by name and return it.
64+
* Return NULL if not found, or -EINVAL if parameter is invalid.
65+
* If the member is an member of anonymous union/structure, the offset
66+
* of that anonymous union/structure is stored into @anon_offset. Caller
67+
* can calculate the correct offset from the root data structure by
68+
* adding anon_offset to the member's offset.
69+
*/
70+
const struct btf_member *btf_find_struct_member(struct btf *btf,
71+
const struct btf_type *type,
72+
const char *member_name,
73+
u32 *anon_offset)
74+
{
75+
struct btf_anon_stack *anon_stack;
76+
const struct btf_member *member;
77+
u32 tid, cur_offset = 0;
78+
const char *name;
79+
int i, top = 0;
80+
81+
anon_stack = kcalloc(BTF_ANON_STACK_MAX, sizeof(*anon_stack), GFP_KERNEL);
82+
if (!anon_stack)
83+
return ERR_PTR(-ENOMEM);
84+
85+
retry:
86+
if (!btf_type_is_struct(type)) {
87+
member = ERR_PTR(-EINVAL);
88+
goto out;
89+
}
90+
91+
for_each_member(i, type, member) {
92+
if (!member->name_off) {
93+
/* Anonymous union/struct: push it for later use */
94+
type = btf_type_skip_modifiers(btf, member->type, &tid);
95+
if (type && top < BTF_ANON_STACK_MAX) {
96+
anon_stack[top].tid = tid;
97+
anon_stack[top++].offset =
98+
cur_offset + member->offset;
99+
}
100+
} else {
101+
name = btf_name_by_offset(btf, member->name_off);
102+
if (name && !strcmp(member_name, name)) {
103+
if (anon_offset)
104+
*anon_offset = cur_offset;
105+
goto out;
106+
}
107+
}
108+
}
109+
if (top > 0) {
110+
/* Pop from the anonymous stack and retry */
111+
tid = anon_stack[--top].tid;
112+
cur_offset = anon_stack[top].offset;
113+
type = btf_type_by_id(btf, tid);
114+
goto retry;
115+
}
116+
member = NULL;
117+
118+
out:
119+
kfree(anon_stack);
120+
return member;
121+
}
122+

kernel/trace/trace_btf.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ const struct btf_type *btf_find_func_proto(const char *func_name,
55
struct btf **btf_p);
66
const struct btf_param *btf_get_func_param(const struct btf_type *func_proto,
77
s32 *nr);
8+
const struct btf_member *btf_find_struct_member(struct btf *btf,
9+
const struct btf_type *type,
10+
const char *member_name,
11+
u32 *anon_offset);

0 commit comments

Comments
 (0)