mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
btf: Extend UAPI to support BTF location (inline site) info
Add BTF_KIND_LOC_PARAM, BTF_KIND_LOC_PROTO and BTF_KIND_LOCSEC to help represent location information for functions. BTF_KIND_LOC_PARAM is used to represent how we retrieve data at a location; either via register(s), or register+offset, a dereference of a register+offset or a constant value. BTF_KIND_LOC_PROTO represents location information about a location with multiple BTF_KIND_LOC_PARAMs. And finally BTF_KIND_LOCSEC is a set of location sites, each of which has - a BTF_KIND_FUNC function associated with the inline site - a location prototype specifying where to find the function parameters - an address offset relative to the kernel base address This can be used to support representing - a fully-inlined function at potentially multiple inline sites with potentially different parameter availability - a partially-inlined function where some _LOC_PROTOs represent inlined sites as above and others have normal _FUNC representations Also BTF_KIND_LOCSEC struct btf_loc will have two type id references; one for the associated func, the other for the loc_proto. Accordingly increase the number of m_offs references in btf_field_desc to 2. Signed-off-by: Alan Maguire <alan.maguire@oracle.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://patch.msgid.link/20260924111428.75957-2-alan.maguire@oracle.com
This commit is contained in:
parent
4f3a5eae89
commit
33c5a3278b
|
|
@ -261,6 +261,11 @@ const char *btf_type_str(const struct btf_type *t);
|
|||
i < btf_type_vlen(datasec_type); \
|
||||
i++, member++)
|
||||
|
||||
#define for_each_loc(i, locsec_type, member) \
|
||||
for (i = 0, member = btf_type_loc_secinfo(locsec_type); \
|
||||
i < btf_type_vlen(locsec_type); \
|
||||
i++, member++)
|
||||
|
||||
static inline bool btf_type_is_ptr(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KIND(t->info) == BTF_KIND_PTR;
|
||||
|
|
@ -329,6 +334,21 @@ static inline u64 btf_enum64_value(const struct btf_enum64 *e)
|
|||
return ((u64)e->val_hi32 << 32) | e->val_lo32;
|
||||
}
|
||||
|
||||
static inline struct btf_loc_param *btf_loc_param(const struct btf_type *t)
|
||||
{
|
||||
return (struct btf_loc_param *)(t + 1);
|
||||
}
|
||||
|
||||
static inline __u32 *btf_loc_proto_params(const struct btf_type *t)
|
||||
{
|
||||
return (__u32 *)(t + 1);
|
||||
}
|
||||
|
||||
static inline struct btf_loc *btf_type_loc_secinfo(const struct btf_type *t)
|
||||
{
|
||||
return (struct btf_loc *)(t + 1);
|
||||
}
|
||||
|
||||
static inline bool btf_is_composite(const struct btf_type *t)
|
||||
{
|
||||
u16 kind = btf_kind(t);
|
||||
|
|
@ -559,7 +579,7 @@ struct btf_field_desc {
|
|||
/* member struct size, or zero, if no members */
|
||||
int m_sz;
|
||||
/* repeated per-member offsets */
|
||||
int m_off_cnt, m_offs[1];
|
||||
int m_off_cnt, m_offs[2];
|
||||
};
|
||||
|
||||
struct btf_field_iter {
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ struct btf_type {
|
|||
* decl_tag and type_tag
|
||||
*/
|
||||
__u32 info;
|
||||
/* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC and ENUM64.
|
||||
* "size" tells the size of the type it is describing.
|
||||
/* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC, ENUM64
|
||||
* and LOC_PARAM. "size" tells the size of the type it is describing.
|
||||
*
|
||||
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
|
||||
* FUNC, FUNC_PROTO, VAR, DECL_TAG and TYPE_TAG.
|
||||
|
|
@ -92,7 +92,9 @@ enum {
|
|||
BTF_KIND_DECL_TAG = 17, /* Decl Tag */
|
||||
BTF_KIND_TYPE_TAG = 18, /* Type Tag */
|
||||
BTF_KIND_ENUM64 = 19, /* Enumeration up to 64-bit values */
|
||||
|
||||
BTF_KIND_LOC_PARAM = 20, /* Location parameter information */
|
||||
BTF_KIND_LOC_PROTO = 21, /* Location prototype for site */
|
||||
BTF_KIND_LOCSEC = 22, /* Location section */
|
||||
NR_BTF_KINDS,
|
||||
BTF_KIND_MAX = NR_BTF_KINDS - 1,
|
||||
};
|
||||
|
|
@ -212,4 +214,79 @@ struct btf_enum64 {
|
|||
__u32 val_hi32;
|
||||
};
|
||||
|
||||
/*
|
||||
* BTF_KIND_LOC_PARAM is followed by a single "struct btf_loc_param"
|
||||
* that contains flags specifying the contents of the vlen-specified
|
||||
* number of 4-byte values that follow.
|
||||
*/
|
||||
struct btf_loc_param {
|
||||
__u32 flags;
|
||||
__u32 values[];
|
||||
};
|
||||
|
||||
/*
|
||||
* The combination of size, vlen and flags gives us the means to interpret
|
||||
* the following vlen-specified set of 4-byte values:
|
||||
*
|
||||
* - a BTF_LOC_PARAM_CONST is a constant value; combination
|
||||
* of size, vlen and _SIGNED flag determines it. If the value requires
|
||||
* 64 bits it is stored in {lo,hi} order.
|
||||
* - a BTF_LOC_PARAM_ADDR|BTF_LOC_PARAM_CONST is an address that should be
|
||||
* normalized with respect to kernel/module base address.
|
||||
* - a BTF_LOC_PARAM_REG with vlen 1 is a simple register number;
|
||||
* with vlen 2 it is a multi-register parameter. Register numbers are
|
||||
* numbers derived from DW_OP_reg values, i.e. 0 is DW_OP_reg0; since
|
||||
* DW_OP_fbreg has its own special DW_OP_value and DW_OP_regx can refer
|
||||
* to an arbitrary register number, we reserve BTF_LOC_PARAM_FBREG for
|
||||
* the frame base register to avoid collisions.
|
||||
* - a _REG | OFFSET describes an address without dereferencing it.
|
||||
* - a _REG | DEREF with vlen 1 dereferences the value in the register
|
||||
* number specified.
|
||||
* - a REG | DEREF | OFFSET with vlen > 1 specifies the register number
|
||||
* in the first 4-byte value and the offset in the remainder.
|
||||
* In the case of REG and OFFSET combinations, the OFFSET has the width
|
||||
* of the value words while the type size describes the represented parameter,
|
||||
* so for example a REG | DEREF | OFFSET with size 8 and vlen 2 would be
|
||||
* an 8-byte register dereference with signed 4-byte offset, since the vlen 2
|
||||
* values consist of a register value and the signed value.
|
||||
*/
|
||||
enum btf_loc_param_flags {
|
||||
BTF_LOC_PARAM_SIGNED = 0x1,
|
||||
BTF_LOC_PARAM_CONST = 0x2,
|
||||
BTF_LOC_PARAM_ADDR = 0x4,
|
||||
BTF_LOC_PARAM_REG = 0x8,
|
||||
BTF_LOC_PARAM_DEREF = 0x10,
|
||||
BTF_LOC_PARAM_OFFSET = 0x20,
|
||||
};
|
||||
|
||||
enum {
|
||||
BTF_LOC_PARAM_FBREG = 0xffffffff
|
||||
};
|
||||
|
||||
/*
|
||||
* BTF_KIND_LOC_PROTO specifies location prototypes; i.e. how locations relate
|
||||
* to parameters; a struct btf_type of BTF_KIND_LOC_PROTO is followed by a
|
||||
* vlen-specified number of __u32 BTF type ids which specify the associated
|
||||
* BTF_KIND_LOC_PARAM for each function parameter associated with the
|
||||
* location. The type should either be 0 (no location info) or point at
|
||||
* a BTF_KIND_LOC_PARAM.
|
||||
*/
|
||||
|
||||
/*
|
||||
* BTF_KIND_LOCSEC consists of vlen-specified number of "struct btf_loc"
|
||||
* containing location site-specific information for a specific ELF section;
|
||||
* for example locations in ".text" are in a LOCSEC named "inline.text".
|
||||
*
|
||||
* - function (func)
|
||||
* - location prototype type id (loc_proto)
|
||||
* - address offset (offset) relative to the runtime base address of the
|
||||
* ELF section associated with the LOCSEC
|
||||
*/
|
||||
|
||||
struct btf_loc {
|
||||
__u32 func;
|
||||
__u32 loc_proto;
|
||||
__u32 offset;
|
||||
};
|
||||
|
||||
#endif /* _UAPI__LINUX_BTF_H__ */
|
||||
|
|
|
|||
322
kernel/bpf/btf.c
322
kernel/bpf/btf.c
|
|
@ -346,6 +346,9 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = {
|
|||
[BTF_KIND_DECL_TAG] = "DECL_TAG",
|
||||
[BTF_KIND_TYPE_TAG] = "TYPE_TAG",
|
||||
[BTF_KIND_ENUM64] = "ENUM64",
|
||||
[BTF_KIND_LOC_PARAM] = "LOC_PARAM",
|
||||
[BTF_KIND_LOC_PROTO] = "LOC_PROTO",
|
||||
[BTF_KIND_LOCSEC] = "LOCSEC",
|
||||
};
|
||||
|
||||
const char *btf_type_str(const struct btf_type *t)
|
||||
|
|
@ -518,11 +521,27 @@ static bool btf_type_is_decl_tag(const struct btf_type *t)
|
|||
return BTF_INFO_KIND(t->info) == BTF_KIND_DECL_TAG;
|
||||
}
|
||||
|
||||
static bool btf_type_is_loc_param(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KIND(t->info) == BTF_KIND_LOC_PARAM;
|
||||
}
|
||||
|
||||
static bool btf_type_is_loc_proto(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KIND(t->info) == BTF_KIND_LOC_PROTO;
|
||||
}
|
||||
|
||||
static bool btf_type_is_locsec(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KIND(t->info) == BTF_KIND_LOCSEC;
|
||||
}
|
||||
|
||||
static bool btf_type_nosize(const struct btf_type *t)
|
||||
{
|
||||
return btf_type_is_void(t) || btf_type_is_fwd(t) ||
|
||||
btf_type_is_func(t) || btf_type_is_func_proto(t) ||
|
||||
btf_type_is_decl_tag(t);
|
||||
btf_type_is_decl_tag(t) || btf_type_is_loc_param(t) ||
|
||||
btf_type_is_loc_proto(t) || btf_type_is_locsec(t);
|
||||
}
|
||||
|
||||
static bool btf_type_nosize_or_null(const struct btf_type *t)
|
||||
|
|
@ -769,7 +788,9 @@ static bool btf_type_is_resolve_source_only(const struct btf_type *t)
|
|||
{
|
||||
return btf_type_is_var(t) ||
|
||||
btf_type_is_decl_tag(t) ||
|
||||
btf_type_is_datasec(t);
|
||||
btf_type_is_datasec(t) ||
|
||||
btf_type_is_loc_proto(t) ||
|
||||
btf_type_is_locsec(t);
|
||||
}
|
||||
|
||||
/* What types need to be resolved?
|
||||
|
|
@ -797,7 +818,9 @@ static bool btf_type_needs_resolve(const struct btf_type *t)
|
|||
btf_type_is_var(t) ||
|
||||
btf_type_is_func(t) ||
|
||||
btf_type_is_decl_tag(t) ||
|
||||
btf_type_is_datasec(t);
|
||||
btf_type_is_datasec(t) ||
|
||||
btf_type_is_loc_proto(t) ||
|
||||
btf_type_is_locsec(t);
|
||||
}
|
||||
|
||||
/* t->size can be used */
|
||||
|
|
@ -4737,6 +4760,293 @@ static const struct btf_kind_operations enum64_ops = {
|
|||
.show = btf_enum64_show,
|
||||
};
|
||||
|
||||
static s32 btf_loc_param_check_meta(struct btf_verifier_env *env,
|
||||
const struct btf_type *t,
|
||||
u32 meta_left)
|
||||
{
|
||||
const struct btf_loc_param *p = btf_loc_param(t);
|
||||
u32 size, meta_needed, vlen = btf_vlen(t);
|
||||
|
||||
meta_needed = sizeof(*p) + sizeof(__u32) * vlen;
|
||||
if (meta_left < meta_needed) {
|
||||
btf_verifier_log_basic(env, t,
|
||||
"meta_left:%u meta_needed:%u",
|
||||
meta_left, meta_needed);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (t->name_off) {
|
||||
btf_verifier_log_type(env, t, "Invalid name");
|
||||
return -EINVAL;
|
||||
}
|
||||
size = t->size;
|
||||
if (!size || size > 16) {
|
||||
btf_verifier_log_type(env, t, "Unexpected size");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (btf_type_kflag(t)) {
|
||||
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
btf_verifier_log_type(env, t, NULL);
|
||||
|
||||
return meta_needed;
|
||||
}
|
||||
|
||||
static void btf_loc_param_log(struct btf_verifier_env *env,
|
||||
const struct btf_type *t)
|
||||
{
|
||||
const struct btf_loc_param *p = btf_loc_param(t);
|
||||
u32 i, vlen = btf_vlen(t);
|
||||
|
||||
btf_verifier_log(env, "size=%u vlen=%u flags=0x%x", t->size, vlen, p->flags);
|
||||
for (i = 0; i < vlen; i++)
|
||||
btf_verifier_log(env, ", %u", p->values[i]);
|
||||
}
|
||||
|
||||
static const struct btf_kind_operations loc_param_ops = {
|
||||
.check_meta = btf_loc_param_check_meta,
|
||||
.resolve = btf_df_resolve,
|
||||
.check_member = btf_df_check_member,
|
||||
.check_kflag_member = btf_df_check_kflag_member,
|
||||
.log_details = btf_loc_param_log,
|
||||
.show = btf_df_show,
|
||||
};
|
||||
|
||||
static s32 btf_loc_proto_check_meta(struct btf_verifier_env *env,
|
||||
const struct btf_type *t,
|
||||
u32 meta_left)
|
||||
{
|
||||
u32 meta_needed;
|
||||
|
||||
meta_needed = sizeof(__u32) * btf_type_vlen(t);
|
||||
|
||||
if (meta_left < meta_needed) {
|
||||
btf_verifier_log_basic(env, t,
|
||||
"meta_left:%u meta_needed:%u",
|
||||
meta_left, meta_needed);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (t->name_off) {
|
||||
btf_verifier_log_type(env, t, "Invalid name");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (btf_type_kflag(t)) {
|
||||
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
btf_verifier_log_type(env, t, NULL);
|
||||
|
||||
return meta_needed;
|
||||
}
|
||||
|
||||
static void btf_loc_proto_log(struct btf_verifier_env *env,
|
||||
const struct btf_type *t)
|
||||
{
|
||||
const __u32 *params = btf_loc_proto_params(t);
|
||||
u32 i, nr_params = btf_type_vlen(t);
|
||||
|
||||
btf_verifier_log(env, "vlen=%u", nr_params);
|
||||
for (i = 0; i < nr_params; i++, params++)
|
||||
btf_verifier_log(env, ", %u", *params);
|
||||
}
|
||||
|
||||
static int btf_loc_proto_resolve(struct btf_verifier_env *env,
|
||||
const struct resolve_vertex *v)
|
||||
{
|
||||
const struct btf_type *t = v->t;
|
||||
const __u32 *params = btf_loc_proto_params(t);
|
||||
u32 i, nr_params = btf_type_vlen(t);
|
||||
struct btf *btf = env->btf;
|
||||
|
||||
if (t->type) {
|
||||
btf_verifier_log_type(env, t, "Invalid loc_proto type");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_params; i++) {
|
||||
const struct btf_type *param_type;
|
||||
u32 param_type_id = params[i];
|
||||
|
||||
if (!param_type_id)
|
||||
continue;
|
||||
|
||||
param_type = btf_type_by_id(btf, param_type_id);
|
||||
if (!param_type || !btf_type_is_loc_param(param_type)) {
|
||||
btf_verifier_log_type(env, t,
|
||||
"Invalid loc_param#%u", i + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
env_stack_pop_resolved(env, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct btf_kind_operations loc_proto_ops = {
|
||||
.check_meta = btf_loc_proto_check_meta,
|
||||
.resolve = btf_loc_proto_resolve,
|
||||
.check_member = btf_df_check_member,
|
||||
.check_kflag_member = btf_df_check_kflag_member,
|
||||
.log_details = btf_loc_proto_log,
|
||||
.show = btf_df_show,
|
||||
};
|
||||
|
||||
__printf(4, 5)
|
||||
static void btf_verifier_log_loc(struct btf_verifier_env *env,
|
||||
const struct btf_type *locsec_type,
|
||||
const struct btf_loc *loc,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
struct bpf_verifier_log *log = &env->log;
|
||||
va_list args;
|
||||
|
||||
if (!bpf_verifier_log_needed(log))
|
||||
return;
|
||||
if (log->level == BPF_LOG_KERNEL && !fmt)
|
||||
return;
|
||||
if (env->phase != CHECK_META)
|
||||
btf_verifier_log_type(env, locsec_type, NULL);
|
||||
|
||||
__btf_verifier_log(log, "\t func=%u loc_proto=%u offset=%u",
|
||||
loc->func, loc->loc_proto, loc->offset);
|
||||
if (fmt && *fmt) {
|
||||
__btf_verifier_log(log, " ");
|
||||
va_start(args, fmt);
|
||||
bpf_verifier_vlog(log, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
__btf_verifier_log(log, "\n");
|
||||
}
|
||||
|
||||
static s32 btf_locsec_check_meta(struct btf_verifier_env *env,
|
||||
const struct btf_type *t,
|
||||
u32 meta_left)
|
||||
{
|
||||
u32 i, meta_needed, vlen = btf_type_vlen(t);
|
||||
const struct btf_loc *loc;
|
||||
|
||||
meta_needed = sizeof(struct btf_loc) * vlen;
|
||||
|
||||
if (meta_left < meta_needed) {
|
||||
btf_verifier_log_basic(env, t,
|
||||
"meta_left:%u meta_needed:%u",
|
||||
meta_left, meta_needed);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (btf_type_kflag(t)) {
|
||||
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!t->name_off ||
|
||||
!btf_name_valid_section(env->btf, t->name_off)) {
|
||||
btf_verifier_log_type(env, t, "Invalid name");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for_each_loc(i, t, loc) {
|
||||
/* A loc func, loc proto cannot be in type void */
|
||||
if (!loc->func || !BTF_TYPE_ID_VALID(loc->func)) {
|
||||
btf_verifier_log_loc(env, t, loc, "Invalid func");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!loc->loc_proto || !BTF_TYPE_ID_VALID(loc->loc_proto)) {
|
||||
btf_verifier_log_loc(env, t, loc, "Invalid loc_proto");
|
||||
return -EINVAL;
|
||||
}
|
||||
btf_verifier_log_loc(env, t, loc, NULL);
|
||||
}
|
||||
|
||||
return meta_needed;
|
||||
}
|
||||
|
||||
static void btf_locsec_log(struct btf_verifier_env *env,
|
||||
const struct btf_type *t)
|
||||
{
|
||||
btf_verifier_log(env, "vlen=%u", btf_type_vlen(t));
|
||||
}
|
||||
|
||||
static int btf_locsec_resolve(struct btf_verifier_env *env,
|
||||
const struct resolve_vertex *v)
|
||||
{
|
||||
const struct btf_type *t = v->t;
|
||||
const struct btf_loc *loc;
|
||||
struct btf *btf = env->btf;
|
||||
u32 i;
|
||||
|
||||
if (t->type) {
|
||||
btf_verifier_log_type(env, t, "Invalid locsec type");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
env->resolve_mode = RESOLVE_TBD;
|
||||
for (i = v->next_member, loc = btf_type_loc_secinfo(t) + i;
|
||||
i < btf_type_vlen(t); i++, loc++) {
|
||||
const struct btf_type *func_type, *func_proto_type;
|
||||
const struct btf_type *loc_proto_type;
|
||||
u32 func_type_id = loc->func;
|
||||
u32 loc_proto_type_id = loc->loc_proto;
|
||||
u32 proto_vlen;
|
||||
|
||||
func_type = btf_type_by_id(btf, func_type_id);
|
||||
if (!func_type || !btf_type_is_func(func_type)) {
|
||||
btf_verifier_log_type(env, t,
|
||||
"Invalid func#%u", i + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
func_proto_type = btf_type_by_id(btf, func_type->type);
|
||||
if (!func_proto_type || !btf_type_is_func_proto(func_proto_type)) {
|
||||
btf_verifier_log_type(env, t,
|
||||
"Invalid func#%u", i + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
proto_vlen = btf_vlen(func_proto_type);
|
||||
|
||||
if (!env_type_is_resolved(env, func_type_id)) {
|
||||
env_stack_set_next_member(env, i);
|
||||
return env_stack_push(env, func_type, func_type_id);
|
||||
}
|
||||
|
||||
loc_proto_type = btf_type_by_id(btf, loc_proto_type_id);
|
||||
if (!loc_proto_type || !btf_type_is_loc_proto(loc_proto_type)) {
|
||||
btf_verifier_log_type(env, t,
|
||||
"Invalid loc_proto#%u", i + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (proto_vlen != btf_vlen(loc_proto_type)) {
|
||||
btf_verifier_log_type(env, t,
|
||||
"Mismatched vlen for loc_proto#%u", i + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!env_type_is_resolved(env, loc_proto_type_id)) {
|
||||
env_stack_set_next_member(env, i + 1);
|
||||
return env_stack_push(env, loc_proto_type,
|
||||
loc_proto_type_id);
|
||||
}
|
||||
}
|
||||
|
||||
env_stack_pop_resolved(env, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct btf_kind_operations locsec_ops = {
|
||||
.check_meta = btf_locsec_check_meta,
|
||||
.resolve = btf_locsec_resolve,
|
||||
.check_member = btf_df_check_member,
|
||||
.check_kflag_member = btf_df_check_kflag_member,
|
||||
.log_details = btf_locsec_log,
|
||||
.show = btf_df_show,
|
||||
};
|
||||
|
||||
static s32 btf_func_proto_check_meta(struct btf_verifier_env *env,
|
||||
const struct btf_type *t,
|
||||
u32 meta_left)
|
||||
|
|
@ -5406,6 +5716,9 @@ static const struct btf_kind_operations * const kind_ops[NR_BTF_KINDS] = {
|
|||
[BTF_KIND_DECL_TAG] = &decl_tag_ops,
|
||||
[BTF_KIND_TYPE_TAG] = &modifier_ops,
|
||||
[BTF_KIND_ENUM64] = &enum64_ops,
|
||||
[BTF_KIND_LOC_PARAM] = &loc_param_ops,
|
||||
[BTF_KIND_LOC_PROTO] = &loc_proto_ops,
|
||||
[BTF_KIND_LOCSEC] = &locsec_ops,
|
||||
};
|
||||
|
||||
static s32 btf_check_meta(struct btf_verifier_env *env,
|
||||
|
|
@ -5480,7 +5793,8 @@ static bool btf_resolve_valid(struct btf_verifier_env *env,
|
|||
if (!env_type_is_resolved(env, type_id))
|
||||
return false;
|
||||
|
||||
if (btf_type_is_struct(t) || btf_type_is_datasec(t))
|
||||
if (btf_type_is_struct(t) || btf_type_is_datasec(t) ||
|
||||
btf_type_is_loc_proto(t) || btf_type_is_locsec(t))
|
||||
return !btf_resolved_type_id(btf, type_id) &&
|
||||
!btf_resolved_type_size(btf, type_id);
|
||||
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ struct btf_type {
|
|||
* decl_tag and type_tag
|
||||
*/
|
||||
__u32 info;
|
||||
/* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC and ENUM64.
|
||||
* "size" tells the size of the type it is describing.
|
||||
/* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC, ENUM64
|
||||
* and LOC_PARAM. "size" tells the size of the type it is describing.
|
||||
*
|
||||
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
|
||||
* FUNC, FUNC_PROTO, VAR, DECL_TAG and TYPE_TAG.
|
||||
|
|
@ -92,7 +92,9 @@ enum {
|
|||
BTF_KIND_DECL_TAG = 17, /* Decl Tag */
|
||||
BTF_KIND_TYPE_TAG = 18, /* Type Tag */
|
||||
BTF_KIND_ENUM64 = 19, /* Enumeration up to 64-bit values */
|
||||
|
||||
BTF_KIND_LOC_PARAM = 20, /* Location parameter information */
|
||||
BTF_KIND_LOC_PROTO = 21, /* Location prototype for site */
|
||||
BTF_KIND_LOCSEC = 22, /* Location section */
|
||||
NR_BTF_KINDS,
|
||||
BTF_KIND_MAX = NR_BTF_KINDS - 1,
|
||||
};
|
||||
|
|
@ -212,4 +214,79 @@ struct btf_enum64 {
|
|||
__u32 val_hi32;
|
||||
};
|
||||
|
||||
/*
|
||||
* BTF_KIND_LOC_PARAM is followed by a single "struct btf_loc_param"
|
||||
* that contains flags specifying the contents of the vlen-specified
|
||||
* number of 4-byte values that follow.
|
||||
*/
|
||||
struct btf_loc_param {
|
||||
__u32 flags;
|
||||
__u32 values[];
|
||||
};
|
||||
|
||||
/*
|
||||
* The combination of size, vlen and flags gives us the means to interpret
|
||||
* the following vlen-specified set of 4-byte values:
|
||||
*
|
||||
* - a BTF_LOC_PARAM_CONST is a constant value; combination
|
||||
* of size, vlen and _SIGNED flag determines it. If the value requires
|
||||
* 64 bits it is stored in {lo,hi} order.
|
||||
* - a BTF_LOC_PARAM_ADDR|BTF_LOC_PARAM_CONST is an address that should be
|
||||
* normalized with respect to kernel/module base address.
|
||||
* - a BTF_LOC_PARAM_REG with vlen 1 is a simple register number;
|
||||
* with vlen 2 it is a multi-register parameter. Register numbers are
|
||||
* numbers derived from DW_OP_reg values, i.e. 0 is DW_OP_reg0; since
|
||||
* DW_OP_fbreg has its own special DW_OP_value and DW_OP_regx can refer
|
||||
* to an arbitrary register number, we reserve BTF_LOC_PARAM_FBREG for
|
||||
* the frame base register to avoid collisions.
|
||||
* - a _REG | OFFSET describes an address without dereferencing it.
|
||||
* - a _REG | DEREF with vlen 1 dereferences the value in the register
|
||||
* number specified.
|
||||
* - a REG | DEREF | OFFSET with vlen > 1 specifies the register number
|
||||
* in the first 4-byte value and the offset in the remainder.
|
||||
* In the case of REG and OFFSET combinations, the OFFSET has the width
|
||||
* of the value words while the type size describes the represented parameter,
|
||||
* so for example a REG | DEREF | OFFSET with size 8 and vlen 2 would be
|
||||
* an 8-byte register dereference with signed 4-byte offset, since the vlen 2
|
||||
* values consist of a register value and the signed value.
|
||||
*/
|
||||
enum btf_loc_param_flags {
|
||||
BTF_LOC_PARAM_SIGNED = 0x1,
|
||||
BTF_LOC_PARAM_CONST = 0x2,
|
||||
BTF_LOC_PARAM_ADDR = 0x4,
|
||||
BTF_LOC_PARAM_REG = 0x8,
|
||||
BTF_LOC_PARAM_DEREF = 0x10,
|
||||
BTF_LOC_PARAM_OFFSET = 0x20,
|
||||
};
|
||||
|
||||
enum {
|
||||
BTF_LOC_PARAM_FBREG = 0xffffffff
|
||||
};
|
||||
|
||||
/*
|
||||
* BTF_KIND_LOC_PROTO specifies location prototypes; i.e. how locations relate
|
||||
* to parameters; a struct btf_type of BTF_KIND_LOC_PROTO is followed by a
|
||||
* vlen-specified number of __u32 BTF type ids which specify the associated
|
||||
* BTF_KIND_LOC_PARAM for each function parameter associated with the
|
||||
* location. The type should either be 0 (no location info) or point at
|
||||
* a BTF_KIND_LOC_PARAM.
|
||||
*/
|
||||
|
||||
/*
|
||||
* BTF_KIND_LOCSEC consists of vlen-specified number of "struct btf_loc"
|
||||
* containing location site-specific information for a specific ELF section;
|
||||
* for example locations in ".text" are in a LOCSEC named "inline.text".
|
||||
*
|
||||
* - function (func)
|
||||
* - location prototype type id (loc_proto)
|
||||
* - address offset (offset) relative to the runtime base address of the
|
||||
* ELF section associated with the LOCSEC
|
||||
*/
|
||||
|
||||
struct btf_loc {
|
||||
__u32 func;
|
||||
__u32 loc_proto;
|
||||
__u32 offset;
|
||||
};
|
||||
|
||||
#endif /* _UAPI__LINUX_BTF_H__ */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user