Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libbpf: Support flexible arrays in CO-RE

Some data stuctures in kernel are defined with either zero-sized array or
flexible (dimensionless) array at the end of a struct. Actual data of such
array follows in memory immediately after the end of that struct, forming its
variable-sized "body" of elements. Support such access pattern in CO-RE
relocation handling.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20191215070844.1014385-2-andriin@fb.com

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
1b484b30 01c6f7aa

+29 -5
+29 -5
tools/lib/bpf/libbpf.c
··· 3108 3108 return !s || !s[0]; 3109 3109 } 3110 3110 3111 + static bool is_flex_arr(const struct btf *btf, 3112 + const struct bpf_core_accessor *acc, 3113 + const struct btf_array *arr) 3114 + { 3115 + const struct btf_type *t; 3116 + 3117 + /* not a flexible array, if not inside a struct or has non-zero size */ 3118 + if (!acc->name || arr->nelems > 0) 3119 + return false; 3120 + 3121 + /* has to be the last member of enclosing struct */ 3122 + t = btf__type_by_id(btf, acc->type_id); 3123 + return acc->idx == btf_vlen(t) - 1; 3124 + } 3125 + 3111 3126 /* 3112 3127 * Turn bpf_field_reloc into a low- and high-level spec representation, 3113 3128 * validating correctness along the way, as well as calculating resulting ··· 3160 3145 struct bpf_core_spec *spec) 3161 3146 { 3162 3147 int access_idx, parsed_len, i; 3148 + struct bpf_core_accessor *acc; 3163 3149 const struct btf_type *t; 3164 3150 const char *name; 3165 3151 __u32 id; ··· 3208 3192 return -EINVAL; 3209 3193 3210 3194 access_idx = spec->raw_spec[i]; 3195 + acc = &spec->spec[spec->len]; 3211 3196 3212 3197 if (btf_is_composite(t)) { 3213 3198 const struct btf_member *m; ··· 3226 3209 if (str_is_empty(name)) 3227 3210 return -EINVAL; 3228 3211 3229 - spec->spec[spec->len].type_id = id; 3230 - spec->spec[spec->len].idx = access_idx; 3231 - spec->spec[spec->len].name = name; 3212 + acc->type_id = id; 3213 + acc->idx = access_idx; 3214 + acc->name = name; 3232 3215 spec->len++; 3233 3216 } 3234 3217 3235 3218 id = m->type; 3236 3219 } else if (btf_is_array(t)) { 3237 3220 const struct btf_array *a = btf_array(t); 3221 + bool flex; 3238 3222 3239 3223 t = skip_mods_and_typedefs(btf, a->type, &id); 3240 - if (!t || access_idx >= a->nelems) 3224 + if (!t) 3225 + return -EINVAL; 3226 + 3227 + flex = is_flex_arr(btf, acc - 1, a); 3228 + if (!flex && access_idx >= a->nelems) 3241 3229 return -EINVAL; 3242 3230 3243 3231 spec->spec[spec->len].type_id = id; ··· 3547 3525 */ 3548 3526 if (i > 0) { 3549 3527 const struct btf_array *a; 3528 + bool flex; 3550 3529 3551 3530 if (!btf_is_array(targ_type)) 3552 3531 return 0; 3553 3532 3554 3533 a = btf_array(targ_type); 3555 - if (local_acc->idx >= a->nelems) 3534 + flex = is_flex_arr(targ_btf, targ_acc - 1, a); 3535 + if (!flex && local_acc->idx >= a->nelems) 3556 3536 return 0; 3557 3537 if (!skip_mods_and_typedefs(targ_btf, a->type, 3558 3538 &targ_id))