mirror of
https://github.com/torvalds/linux.git
synced 2024-11-01 13:03:25 +01:00
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) <mhiramat@kernel.org> Reviewed-by: Alan Maguire <alan.maguire@oracle.com> Acked-by: Steven Rostedt (Google) <rostedt@goodmis.org>
This commit is contained in:
parent
ebeed8d4a5
commit
302db0f5b3
2 changed files with 73 additions and 0 deletions
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/btf.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "trace_btf.h"
|
||||
|
||||
|
@ -51,3 +52,71 @@ const struct btf_param *btf_get_func_param(const struct btf_type *func_proto, s3
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#define BTF_ANON_STACK_MAX 16
|
||||
|
||||
struct btf_anon_stack {
|
||||
u32 tid;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
/*
|
||||
* Find a member of data structure/union by name and return it.
|
||||
* Return NULL if not found, or -EINVAL if parameter is invalid.
|
||||
* If the member is an member of anonymous union/structure, the offset
|
||||
* of that anonymous union/structure is stored into @anon_offset. Caller
|
||||
* can calculate the correct offset from the root data structure by
|
||||
* adding anon_offset to the member's offset.
|
||||
*/
|
||||
const struct btf_member *btf_find_struct_member(struct btf *btf,
|
||||
const struct btf_type *type,
|
||||
const char *member_name,
|
||||
u32 *anon_offset)
|
||||
{
|
||||
struct btf_anon_stack *anon_stack;
|
||||
const struct btf_member *member;
|
||||
u32 tid, cur_offset = 0;
|
||||
const char *name;
|
||||
int i, top = 0;
|
||||
|
||||
anon_stack = kcalloc(BTF_ANON_STACK_MAX, sizeof(*anon_stack), GFP_KERNEL);
|
||||
if (!anon_stack)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
retry:
|
||||
if (!btf_type_is_struct(type)) {
|
||||
member = ERR_PTR(-EINVAL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for_each_member(i, type, member) {
|
||||
if (!member->name_off) {
|
||||
/* Anonymous union/struct: push it for later use */
|
||||
type = btf_type_skip_modifiers(btf, member->type, &tid);
|
||||
if (type && top < BTF_ANON_STACK_MAX) {
|
||||
anon_stack[top].tid = tid;
|
||||
anon_stack[top++].offset =
|
||||
cur_offset + member->offset;
|
||||
}
|
||||
} else {
|
||||
name = btf_name_by_offset(btf, member->name_off);
|
||||
if (name && !strcmp(member_name, name)) {
|
||||
if (anon_offset)
|
||||
*anon_offset = cur_offset;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (top > 0) {
|
||||
/* Pop from the anonymous stack and retry */
|
||||
tid = anon_stack[--top].tid;
|
||||
cur_offset = anon_stack[top].offset;
|
||||
type = btf_type_by_id(btf, tid);
|
||||
goto retry;
|
||||
}
|
||||
member = NULL;
|
||||
|
||||
out:
|
||||
kfree(anon_stack);
|
||||
return member;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,3 +5,7 @@ const struct btf_type *btf_find_func_proto(const char *func_name,
|
|||
struct btf **btf_p);
|
||||
const struct btf_param *btf_get_func_param(const struct btf_type *func_proto,
|
||||
s32 *nr);
|
||||
const struct btf_member *btf_find_struct_member(struct btf *btf,
|
||||
const struct btf_type *type,
|
||||
const char *member_name,
|
||||
u32 *anon_offset);
|
||||
|
|
Loading…
Reference in a new issue