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

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.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 482f7133
Loading
Loading
Loading
Loading
+79 −101
Original line number Diff line number Diff line
@@ -3494,33 +3494,28 @@ static int btf_get_field_type(const char *name, u32 field_mask, u32 *seen_mask,

#undef field_mask_test_name

static int btf_find_struct_field(const struct btf *btf,
				 const struct btf_type *t, u32 field_mask,
static int btf_find_field_one(const struct btf *btf,
			      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)
{
	int ret, idx = 0, align, sz, field_type;
	const struct btf_member *member;
	int ret, align, sz, field_type;
	struct btf_field_info tmp;
	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);

		field_type = btf_get_field_type(__btf_name_by_offset(btf, member_type->name_off),
						field_mask, &seen_mask, &align, &sz);
	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;
		return 0;
	if (field_type < 0)
		return field_type;

		off = __btf_member_bit_offset(t, member);
		if (off % 8)
			/* valid C code cannot generate such BTF */
			return -EINVAL;
		off /= 8;
	if (expected_size && expected_size != sz)
		return 0;
	if (off % align)
			continue;
		return 0;

	switch (field_type) {
	case BPF_SPIN_LOCK:
@@ -3529,24 +3524,24 @@ static int btf_find_struct_field(const struct btf *btf,
	case BPF_LIST_NODE:
	case BPF_RB_NODE:
	case BPF_REFCOUNT:
			ret = btf_find_struct(btf, member_type, off, sz, field_type,
					      idx < info_cnt ? &info[idx] : &tmp);
		ret = btf_find_struct(btf, var_type, off, sz, field_type,
				      info_cnt ? &info[0] : &tmp);
		if (ret < 0)
			return ret;
		break;
	case BPF_KPTR_UNREF:
	case BPF_KPTR_REF:
	case BPF_KPTR_PERCPU:
			ret = btf_find_kptr(btf, member_type, off, sz,
					    idx < info_cnt ? &info[idx] : &tmp);
		ret = btf_find_kptr(btf, var_type, off, sz,
				    info_cnt ? &info[0] : &tmp);
		if (ret < 0)
			return ret;
		break;
	case BPF_LIST_HEAD:
	case BPF_RB_ROOT:
			ret = btf_find_graph_root(btf, t, member_type,
						  i, off, sz,
						  idx < info_cnt ? &info[idx] : &tmp,
		ret = btf_find_graph_root(btf, var, var_type,
					  var_idx, off, sz,
					  info_cnt ? &info[0] : &tmp,
					  field_type);
		if (ret < 0)
			return ret;
@@ -3556,10 +3551,38 @@ static int btf_find_struct_field(const struct btf *btf,
	}

	if (ret == BTF_FIELD_IGNORE)
			continue;
		if (idx >= info_cnt)
		return 0;
	if (!info_cnt)
		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;
}
@@ -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,
				int info_cnt)
{
	int ret, idx = 0, align, sz, field_type;
	int ret, idx = 0;
	const struct btf_var_secinfo *vsi;
	struct btf_field_info tmp;
	u32 i, off, seen_mask = 0;

	for_each_vsi(i, t, vsi) {
		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);

		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;
		if (vsi->size != sz)
			continue;
		if (off % align)
			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);
		ret = btf_find_field_one(btf, var, var_type, -1, off, vsi->size,
					 field_mask, &seen_mask,
					 &info[idx], info_cnt - idx);
		if (ret < 0)
			return ret;
			break;
		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;
		idx += ret;
	}
	return idx;
}