Commit a7db0d4f authored by Kui-Feng Lee's avatar Kui-Feng Lee Committed by Alexei Starovoitov

bpf: refactor btf_find_struct_field() and btf_find_datasec_var().

Move common code of the two functions to btf_find_field_one().
Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
Signed-off-by: default avatarKui-Feng Lee <thinker.li@gmail.com>
Link: https://lore.kernel.org/r/20240523174202.461236-4-thinker.li@gmail.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 482f7133
...@@ -3494,33 +3494,28 @@ static int btf_get_field_type(const char *name, u32 field_mask, u32 *seen_mask, ...@@ -3494,33 +3494,28 @@ static int btf_get_field_type(const char *name, u32 field_mask, u32 *seen_mask,
#undef field_mask_test_name #undef field_mask_test_name
static int btf_find_struct_field(const struct btf *btf, static int btf_find_field_one(const struct btf *btf,
const struct btf_type *t, u32 field_mask, const struct btf_type *var,
const struct btf_type *var_type,
int var_idx,
u32 off, u32 expected_size,
u32 field_mask, u32 *seen_mask,
struct btf_field_info *info, int info_cnt) struct btf_field_info *info, int info_cnt)
{ {
int ret, idx = 0, align, sz, field_type; int ret, align, sz, field_type;
const struct btf_member *member;
struct btf_field_info tmp; struct btf_field_info tmp;
u32 i, off, seen_mask = 0;
for_each_member(i, t, member) { field_type = btf_get_field_type(__btf_name_by_offset(btf, var_type->name_off),
const struct btf_type *member_type = btf_type_by_id(btf, field_mask, seen_mask, &align, &sz);
member->type);
field_type = btf_get_field_type(__btf_name_by_offset(btf, member_type->name_off),
field_mask, &seen_mask, &align, &sz);
if (field_type == 0) if (field_type == 0)
continue; return 0;
if (field_type < 0) if (field_type < 0)
return field_type; return field_type;
off = __btf_member_bit_offset(t, member); if (expected_size && expected_size != sz)
if (off % 8) return 0;
/* valid C code cannot generate such BTF */
return -EINVAL;
off /= 8;
if (off % align) if (off % align)
continue; return 0;
switch (field_type) { switch (field_type) {
case BPF_SPIN_LOCK: case BPF_SPIN_LOCK:
...@@ -3529,24 +3524,24 @@ static int btf_find_struct_field(const struct btf *btf, ...@@ -3529,24 +3524,24 @@ static int btf_find_struct_field(const struct btf *btf,
case BPF_LIST_NODE: case BPF_LIST_NODE:
case BPF_RB_NODE: case BPF_RB_NODE:
case BPF_REFCOUNT: case BPF_REFCOUNT:
ret = btf_find_struct(btf, member_type, off, sz, field_type, ret = btf_find_struct(btf, var_type, off, sz, field_type,
idx < info_cnt ? &info[idx] : &tmp); info_cnt ? &info[0] : &tmp);
if (ret < 0) if (ret < 0)
return ret; return ret;
break; break;
case BPF_KPTR_UNREF: case BPF_KPTR_UNREF:
case BPF_KPTR_REF: case BPF_KPTR_REF:
case BPF_KPTR_PERCPU: case BPF_KPTR_PERCPU:
ret = btf_find_kptr(btf, member_type, off, sz, ret = btf_find_kptr(btf, var_type, off, sz,
idx < info_cnt ? &info[idx] : &tmp); info_cnt ? &info[0] : &tmp);
if (ret < 0) if (ret < 0)
return ret; return ret;
break; break;
case BPF_LIST_HEAD: case BPF_LIST_HEAD:
case BPF_RB_ROOT: case BPF_RB_ROOT:
ret = btf_find_graph_root(btf, t, member_type, ret = btf_find_graph_root(btf, var, var_type,
i, off, sz, var_idx, off, sz,
idx < info_cnt ? &info[idx] : &tmp, info_cnt ? &info[0] : &tmp,
field_type); field_type);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -3556,10 +3551,38 @@ static int btf_find_struct_field(const struct btf *btf, ...@@ -3556,10 +3551,38 @@ static int btf_find_struct_field(const struct btf *btf,
} }
if (ret == BTF_FIELD_IGNORE) if (ret == BTF_FIELD_IGNORE)
continue; return 0;
if (idx >= info_cnt) if (!info_cnt)
return -E2BIG; return -E2BIG;
++idx;
return 1;
}
static int btf_find_struct_field(const struct btf *btf,
const struct btf_type *t, u32 field_mask,
struct btf_field_info *info, int info_cnt)
{
int ret, idx = 0;
const struct btf_member *member;
u32 i, off, seen_mask = 0;
for_each_member(i, t, member) {
const struct btf_type *member_type = btf_type_by_id(btf,
member->type);
off = __btf_member_bit_offset(t, member);
if (off % 8)
/* valid C code cannot generate such BTF */
return -EINVAL;
off /= 8;
ret = btf_find_field_one(btf, t, member_type, i,
off, 0,
field_mask, &seen_mask,
&info[idx], info_cnt - idx);
if (ret < 0)
return ret;
idx += ret;
} }
return idx; return idx;
} }
...@@ -3568,66 +3591,21 @@ static int btf_find_datasec_var(const struct btf *btf, const struct btf_type *t, ...@@ -3568,66 +3591,21 @@ static int btf_find_datasec_var(const struct btf *btf, const struct btf_type *t,
u32 field_mask, struct btf_field_info *info, u32 field_mask, struct btf_field_info *info,
int info_cnt) int info_cnt)
{ {
int ret, idx = 0, align, sz, field_type; int ret, idx = 0;
const struct btf_var_secinfo *vsi; const struct btf_var_secinfo *vsi;
struct btf_field_info tmp;
u32 i, off, seen_mask = 0; u32 i, off, seen_mask = 0;
for_each_vsi(i, t, vsi) { for_each_vsi(i, t, vsi) {
const struct btf_type *var = btf_type_by_id(btf, vsi->type); const struct btf_type *var = btf_type_by_id(btf, vsi->type);
const struct btf_type *var_type = btf_type_by_id(btf, var->type); const struct btf_type *var_type = btf_type_by_id(btf, var->type);
field_type = btf_get_field_type(__btf_name_by_offset(btf, var_type->name_off),
field_mask, &seen_mask, &align, &sz);
if (field_type == 0)
continue;
if (field_type < 0)
return field_type;
off = vsi->offset; off = vsi->offset;
if (vsi->size != sz) ret = btf_find_field_one(btf, var, var_type, -1, off, vsi->size,
continue; field_mask, &seen_mask,
if (off % align) &info[idx], info_cnt - idx);
continue;
switch (field_type) {
case BPF_SPIN_LOCK:
case BPF_TIMER:
case BPF_WORKQUEUE:
case BPF_LIST_NODE:
case BPF_RB_NODE:
case BPF_REFCOUNT:
ret = btf_find_struct(btf, var_type, off, sz, field_type,
idx < info_cnt ? &info[idx] : &tmp);
if (ret < 0) if (ret < 0)
return ret; return ret;
break; idx += ret;
case BPF_KPTR_UNREF:
case BPF_KPTR_REF:
case BPF_KPTR_PERCPU:
ret = btf_find_kptr(btf, var_type, off, sz,
idx < info_cnt ? &info[idx] : &tmp);
if (ret < 0)
return ret;
break;
case BPF_LIST_HEAD:
case BPF_RB_ROOT:
ret = btf_find_graph_root(btf, var, var_type,
-1, off, sz,
idx < info_cnt ? &info[idx] : &tmp,
field_type);
if (ret < 0)
return ret;
break;
default:
return -EFAULT;
}
if (ret == BTF_FIELD_IGNORE)
continue;
if (idx >= info_cnt)
return -E2BIG;
++idx;
} }
return idx; return idx;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment