Commit 0849e102 authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

Merge branch 'support-flex-arrays'



Andrii Nakryiko says:

====================
Add support for flexible array accesses in a relocatable manner in BPF CO-RE.
It's a typical pattern in C, and kernel in particular, to provide
a fixed-length struct with zero-sized or dimensionless array at the end. In
such cases variable-sized array contents follows immediately after the end of
a struct. This patch set adds support for such access pattern by allowing
accesses to such arrays.

Patch #1 adds libbpf support. Patch #2 adds few test cases for validation.
====================

Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 01c6f7aa 5f2eecef
Loading
Loading
Loading
Loading
+29 −5
Original line number Diff line number Diff line
@@ -3108,6 +3108,21 @@ static bool str_is_empty(const char *s)
	return !s || !s[0];
}

static bool is_flex_arr(const struct btf *btf,
			const struct bpf_core_accessor *acc,
			const struct btf_array *arr)
{
	const struct btf_type *t;

	/* not a flexible array, if not inside a struct or has non-zero size */
	if (!acc->name || arr->nelems > 0)
		return false;

	/* has to be the last member of enclosing struct */
	t = btf__type_by_id(btf, acc->type_id);
	return acc->idx == btf_vlen(t) - 1;
}

/*
 * Turn bpf_field_reloc into a low- and high-level spec representation,
 * validating correctness along the way, as well as calculating resulting
@@ -3145,6 +3160,7 @@ static int bpf_core_spec_parse(const struct btf *btf,
			       struct bpf_core_spec *spec)
{
	int access_idx, parsed_len, i;
	struct bpf_core_accessor *acc;
	const struct btf_type *t;
	const char *name;
	__u32 id;
@@ -3192,6 +3208,7 @@ static int bpf_core_spec_parse(const struct btf *btf,
			return -EINVAL;

		access_idx = spec->raw_spec[i];
		acc = &spec->spec[spec->len];

		if (btf_is_composite(t)) {
			const struct btf_member *m;
@@ -3209,18 +3226,23 @@ static int bpf_core_spec_parse(const struct btf *btf,
				if (str_is_empty(name))
					return -EINVAL;

				spec->spec[spec->len].type_id = id;
				spec->spec[spec->len].idx = access_idx;
				spec->spec[spec->len].name = name;
				acc->type_id = id;
				acc->idx = access_idx;
				acc->name = name;
				spec->len++;
			}

			id = m->type;
		} else if (btf_is_array(t)) {
			const struct btf_array *a = btf_array(t);
			bool flex;

			t = skip_mods_and_typedefs(btf, a->type, &id);
			if (!t || access_idx >= a->nelems)
			if (!t)
				return -EINVAL;

			flex = is_flex_arr(btf, acc - 1, a);
			if (!flex && access_idx >= a->nelems)
				return -EINVAL;

			spec->spec[spec->len].type_id = id;
@@ -3525,12 +3547,14 @@ static int bpf_core_spec_match(struct bpf_core_spec *local_spec,
			 */
			if (i > 0) {
				const struct btf_array *a;
				bool flex;

				if (!btf_is_array(targ_type))
					return 0;

				a = btf_array(targ_type);
				if (local_acc->idx >= a->nelems)
				flex = is_flex_arr(targ_btf, targ_acc - 1, a);
				if (!flex && local_acc->idx >= a->nelems)
					return 0;
				if (!skip_mods_and_typedefs(targ_btf, a->type,
							    &targ_id))
+4 −0
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@
		.b123 = 2,						\
		.c1c  = 3,						\
		.d00d = 4,						\
		.f10c = 0,						\
	},								\
	.output_len = sizeof(struct core_reloc_arrays_output)		\
}
@@ -308,12 +309,15 @@ static struct core_reloc_test_case test_cases[] = {
	ARRAYS_CASE(arrays),
	ARRAYS_CASE(arrays___diff_arr_dim),
	ARRAYS_CASE(arrays___diff_arr_val_sz),
	ARRAYS_CASE(arrays___equiv_zero_sz_arr),
	ARRAYS_CASE(arrays___fixed_arr),

	ARRAYS_ERR_CASE(arrays___err_too_small),
	ARRAYS_ERR_CASE(arrays___err_too_shallow),
	ARRAYS_ERR_CASE(arrays___err_non_array),
	ARRAYS_ERR_CASE(arrays___err_wrong_val_type1),
	ARRAYS_ERR_CASE(arrays___err_wrong_val_type2),
	ARRAYS_ERR_CASE(arrays___err_bad_zero_sz_arr),

	/* enum/ptr/int handling scenarios */
	PRIMITIVES_CASE(primitives),
+3 −0
Original line number Diff line number Diff line
#include "core_reloc_types.h"

void f(struct core_reloc_arrays___equiv_zero_sz_arr x) {}
+3 −0
Original line number Diff line number Diff line
#include "core_reloc_types.h"

void f(struct core_reloc_arrays___err_bad_zero_sz_arr x) {}
+3 −0
Original line number Diff line number Diff line
#include "core_reloc_types.h"

void f(struct core_reloc_arrays___fixed_arr x) {}
Loading