mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-29 09:12:07 +00: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
@ -1,6 +1,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#include <linux/btf.h>
|
#include <linux/btf.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "trace_btf.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;
|
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);
|
struct btf **btf_p);
|
||||||
const struct btf_param *btf_get_func_param(const struct btf_type *func_proto,
|
const struct btf_param *btf_get_func_param(const struct btf_type *func_proto,
|
||||||
s32 *nr);
|
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 New Issue
Block a user