Message ID | 20210219022543.20893-3-iii@linux.ibm.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | BPF |
Headers | show |
Series | Add BTF_KIND_FLOAT support | expand |
Context | Check | Description |
---|---|---|
netdev/cover_letter | success | Link |
netdev/fixes_present | success | Link |
netdev/patch_count | success | Link |
netdev/tree_selection | success | Clearly marked for bpf-next |
netdev/subject_prefix | success | Link |
netdev/cc_maintainers | warning | 4 maintainers not CCed: songliubraving@fb.com kpsingh@kernel.org netdev@vger.kernel.org kafai@fb.com |
netdev/source_inline | success | Was 0 now: 0 |
netdev/verify_signedoff | success | Link |
netdev/module_param | success | Was 0 now: 0 |
netdev/build_32bit | success | Errors and warnings before: 0 this patch: 0 |
netdev/kdoc | success | Errors and warnings before: 0 this patch: 0 |
netdev/verify_fixes | success | Link |
netdev/checkpatch | warning | WARNING: line length of 81 exceeds 80 columns |
netdev/build_allmodconfig_warn | success | Errors and warnings before: 0 this patch: 0 |
netdev/header_inline | success | Link |
netdev/stable | success | Stable not CCed |
On 2/18/21 6:25 PM, Ilya Leoshkevich wrote: > The logic follows that of BTF_KIND_INT most of the time. Sanitization > replaces BTF_KIND_FLOATs with BTF_KIND_TYPEDEFs pointing to > equally-sized BTF_KIND_ARRAYs on older kernels. > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> > --- > tools/lib/bpf/btf.c | 44 ++++++++++++++++++++++++++++++++ > tools/lib/bpf/btf.h | 8 ++++++ > tools/lib/bpf/btf_dump.c | 4 +++ > tools/lib/bpf/libbpf.c | 45 ++++++++++++++++++++++++++++++++- > tools/lib/bpf/libbpf.map | 5 ++++ > tools/lib/bpf/libbpf_internal.h | 2 ++ > 6 files changed, 107 insertions(+), 1 deletion(-) > [...] > diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c > index 2f9d685bd522..5e957fcceee6 100644 > --- a/tools/lib/bpf/btf_dump.c > +++ b/tools/lib/bpf/btf_dump.c > @@ -279,6 +279,7 @@ static int btf_dump_mark_referenced(struct btf_dump *d) > case BTF_KIND_INT: > case BTF_KIND_ENUM: > case BTF_KIND_FWD: > + case BTF_KIND_FLOAT: > break; > > case BTF_KIND_VOLATILE: > @@ -453,6 +454,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr) > > switch (btf_kind(t)) { > case BTF_KIND_INT: > + case BTF_KIND_FLOAT: > tstate->order_state = ORDERED; > return 0; > > @@ -1133,6 +1135,7 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id, > case BTF_KIND_STRUCT: > case BTF_KIND_UNION: > case BTF_KIND_TYPEDEF: > + case BTF_KIND_FLOAT: > goto done; > default: > pr_warn("unexpected type in decl chain, kind:%u, id:[%u]\n", > @@ -1247,6 +1250,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d, > > switch (kind) { > case BTF_KIND_INT: > + case BTF_KIND_FLOAT: > btf_dump_emit_mods(d, decls); > name = btf_name_of(d, t->name_off); > btf_dump_printf(d, "%s", name); > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c > index d43cc3f29dae..3b170066d613 100644 > --- a/tools/lib/bpf/libbpf.c > +++ b/tools/lib/bpf/libbpf.c > @@ -178,6 +178,8 @@ enum kern_feature_id { > FEAT_PROG_BIND_MAP, > /* Kernel support for module BTFs */ > FEAT_MODULE_BTF, > + /* BTF_KIND_FLOAT support */ > + FEAT_BTF_FLOAT, > __FEAT_CNT, > }; > > @@ -1935,6 +1937,7 @@ static const char *btf_kind_str(const struct btf_type *t) > case BTF_KIND_FUNC_PROTO: return "func_proto"; > case BTF_KIND_VAR: return "var"; > case BTF_KIND_DATASEC: return "datasec"; > + case BTF_KIND_FLOAT: return "float"; > default: return "unknown"; > } > } > @@ -2384,18 +2387,22 @@ static bool btf_needs_sanitization(struct bpf_object *obj) > { > bool has_func_global = kernel_supports(FEAT_BTF_GLOBAL_FUNC); > bool has_datasec = kernel_supports(FEAT_BTF_DATASEC); > + bool has_float = kernel_supports(FEAT_BTF_FLOAT); > bool has_func = kernel_supports(FEAT_BTF_FUNC); > > - return !has_func || !has_datasec || !has_func_global; > + return !has_func || !has_datasec || !has_func_global || !has_float; > } > > static void bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf) > { > bool has_func_global = kernel_supports(FEAT_BTF_GLOBAL_FUNC); > bool has_datasec = kernel_supports(FEAT_BTF_DATASEC); > + bool has_float = kernel_supports(FEAT_BTF_FLOAT); > bool has_func = kernel_supports(FEAT_BTF_FUNC); > struct btf_type *t; > int i, j, vlen; > + int t_u32 = 0; > + int t_u8 = 0; > > for (i = 1; i <= btf__get_nr_types(btf); i++) { > t = (struct btf_type *)btf__type_by_id(btf, i); > @@ -2445,6 +2452,23 @@ static void bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf) > } else if (!has_func_global && btf_is_func(t)) { > /* replace BTF_FUNC_GLOBAL with BTF_FUNC_STATIC */ > t->info = BTF_INFO_ENC(BTF_KIND_FUNC, 0, 0); > + } else if (!has_float && btf_is_float(t)) { > + /* replace FLOAT with TYPEDEF(u8[]) */ > + int t_array; > + __u32 size; > + > + size = t->size; > + if (!t_u8) > + t_u8 = btf__add_int(btf, "u8", 1, 0); > + if (!t_u32) > + t_u32 = btf__add_int(btf, "u32", 4, 0); > + t_array = btf__add_array(btf, t_u32, t_u8, size); > + > + /* adding new types may have invalidated t */ > + t = (struct btf_type *)btf__type_by_id(btf, i); > + > + t->info = BTF_INFO_ENC(BTF_KIND_TYPEDEF, 0, 0); This won't work. The typedef must have a valid name. Otherwise, kernel will reject it. A const char array should be okay here. > + t->type = t_array; > } > } > } [...]
On Thu, 2021-02-18 at 20:22 -0800, Yonghong Song wrote: > > > On 2/18/21 6:25 PM, Ilya Leoshkevich wrote: > > The logic follows that of BTF_KIND_INT most of the time. > > Sanitization > > replaces BTF_KIND_FLOATs with BTF_KIND_TYPEDEFs pointing to > > equally-sized BTF_KIND_ARRAYs on older kernels. > > > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> > > --- > > tools/lib/bpf/btf.c | 44 > > ++++++++++++++++++++++++++++++++ > > tools/lib/bpf/btf.h | 8 ++++++ > > tools/lib/bpf/btf_dump.c | 4 +++ > > tools/lib/bpf/libbpf.c | 45 > > ++++++++++++++++++++++++++++++++- > > tools/lib/bpf/libbpf.map | 5 ++++ > > tools/lib/bpf/libbpf_internal.h | 2 ++ > > 6 files changed, 107 insertions(+), 1 deletion(-) > > > [...] > > diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c > > index 2f9d685bd522..5e957fcceee6 100644 > > --- a/tools/lib/bpf/btf_dump.c > > +++ b/tools/lib/bpf/btf_dump.c > > @@ -279,6 +279,7 @@ static int btf_dump_mark_referenced(struct > > btf_dump *d) > > case BTF_KIND_INT: > > case BTF_KIND_ENUM: > > case BTF_KIND_FWD: > > + case BTF_KIND_FLOAT: > > break; > > > > case BTF_KIND_VOLATILE: > > @@ -453,6 +454,7 @@ static int btf_dump_order_type(struct btf_dump > > *d, __u32 id, bool through_ptr) > > > > switch (btf_kind(t)) { > > case BTF_KIND_INT: > > + case BTF_KIND_FLOAT: > > tstate->order_state = ORDERED; > > return 0; > > > > @@ -1133,6 +1135,7 @@ static void btf_dump_emit_type_decl(struct > > btf_dump *d, __u32 id, > > case BTF_KIND_STRUCT: > > case BTF_KIND_UNION: > > case BTF_KIND_TYPEDEF: > > + case BTF_KIND_FLOAT: > > goto done; > > default: > > pr_warn("unexpected type in decl chain, > > kind:%u, id:[%u]\n", > > @@ -1247,6 +1250,7 @@ static void btf_dump_emit_type_chain(struct > > btf_dump *d, > > > > switch (kind) { > > case BTF_KIND_INT: > > + case BTF_KIND_FLOAT: > > btf_dump_emit_mods(d, decls); > > name = btf_name_of(d, t->name_off); > > btf_dump_printf(d, "%s", name); > > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c > > index d43cc3f29dae..3b170066d613 100644 > > --- a/tools/lib/bpf/libbpf.c > > +++ b/tools/lib/bpf/libbpf.c > > @@ -178,6 +178,8 @@ enum kern_feature_id { > > FEAT_PROG_BIND_MAP, > > /* Kernel support for module BTFs */ > > FEAT_MODULE_BTF, > > + /* BTF_KIND_FLOAT support */ > > + FEAT_BTF_FLOAT, > > __FEAT_CNT, > > }; > > > > @@ -1935,6 +1937,7 @@ static const char *btf_kind_str(const struct > > btf_type *t) > > case BTF_KIND_FUNC_PROTO: return "func_proto"; > > case BTF_KIND_VAR: return "var"; > > case BTF_KIND_DATASEC: return "datasec"; > > + case BTF_KIND_FLOAT: return "float"; > > default: return "unknown"; > > } > > } > > @@ -2384,18 +2387,22 @@ static bool btf_needs_sanitization(struct > > bpf_object *obj) > > { > > bool has_func_global = > > kernel_supports(FEAT_BTF_GLOBAL_FUNC); > > bool has_datasec = kernel_supports(FEAT_BTF_DATASEC); > > + bool has_float = kernel_supports(FEAT_BTF_FLOAT); > > bool has_func = kernel_supports(FEAT_BTF_FUNC); > > > > - return !has_func || !has_datasec || !has_func_global; > > + return !has_func || !has_datasec || !has_func_global || > > !has_float; > > } > > > > static void bpf_object__sanitize_btf(struct bpf_object *obj, > > struct btf *btf) > > { > > bool has_func_global = > > kernel_supports(FEAT_BTF_GLOBAL_FUNC); > > bool has_datasec = kernel_supports(FEAT_BTF_DATASEC); > > + bool has_float = kernel_supports(FEAT_BTF_FLOAT); > > bool has_func = kernel_supports(FEAT_BTF_FUNC); > > struct btf_type *t; > > int i, j, vlen; > > + int t_u32 = 0; > > + int t_u8 = 0; > > > > for (i = 1; i <= btf__get_nr_types(btf); i++) { > > t = (struct btf_type *)btf__type_by_id(btf, i); > > @@ -2445,6 +2452,23 @@ static void bpf_object__sanitize_btf(struct > > bpf_object *obj, struct btf *btf) > > } else if (!has_func_global && btf_is_func(t)) { > > /* replace BTF_FUNC_GLOBAL with > > BTF_FUNC_STATIC */ > > t->info = BTF_INFO_ENC(BTF_KIND_FUNC, 0, > > 0); > > + } else if (!has_float && btf_is_float(t)) { > > + /* replace FLOAT with TYPEDEF(u8[]) */ > > + int t_array; > > + __u32 size; > > + > > + size = t->size; > > + if (!t_u8) > > + t_u8 = btf__add_int(btf, "u8", 1, > > 0); > > + if (!t_u32) > > + t_u32 = btf__add_int(btf, "u32", 4, > > 0); > > + t_array = btf__add_array(btf, t_u32, t_u8, > > size); > > + > > + /* adding new types may have invalidated t > > */ > > + t = (struct btf_type *)btf__type_by_id(btf, > > i); > > + > > + t->info = BTF_INFO_ENC(BTF_KIND_TYPEDEF, 0, > > 0); > > This won't work. The typedef must have a valid name. Otherwise, > kernel > will reject it. A const char array should be okay here. Wouldn't it reuse the old t->name? At least in my testing with v5.7 kernel this was the case, and BTF wasn't rejected. And the original BTF_KIND_FLOAT always has a valid name, this is enforced in libbpf and in the verifier. For example: [1] PTR '(anon)' type_id=2 [2] STRUCT 'foo' size=4 vlen=1 'bar' type_id=3 bits_offset=0 [3] FLOAT 'float' size=4 [4] FUNC_PROTO '(anon)' ret_type_id=5 vlen=1 'f' type_id=1 [5] PTR '(anon)' type_id=0 [6] FUNC 'func' type_id=4 linkage=global becomes [1] PTR '(anon)' type_id=2 [2] STRUCT 'foo' size=4 vlen=1 'bar' type_id=3 bits_offset=0 [3] TYPEDEF 'float' type_id=9 [4] FUNC_PROTO '(anon)' ret_type_id=5 vlen=1 'f' type_id=1 [5] PTR '(anon)' type_id=0 [6] FUNC 'func' type_id=4 linkage=global [7] INT 'u8' size=1 bits_offset=0 nr_bits=8 encoding=(none) [8] INT 'u32' size=4 bits_offset=0 nr_bits=32 encoding=(none) [9] ARRAY '(anon)' type_id=7 index_type_id=8 nr_elems=4
On 2/19/21 3:01 PM, Ilya Leoshkevich wrote: > On Thu, 2021-02-18 at 20:22 -0800, Yonghong Song wrote: >> >> >> On 2/18/21 6:25 PM, Ilya Leoshkevich wrote: >>> The logic follows that of BTF_KIND_INT most of the time. >>> Sanitization >>> replaces BTF_KIND_FLOATs with BTF_KIND_TYPEDEFs pointing to >>> equally-sized BTF_KIND_ARRAYs on older kernels. >>> >>> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> >>> --- >>> tools/lib/bpf/btf.c | 44 >>> ++++++++++++++++++++++++++++++++ >>> tools/lib/bpf/btf.h | 8 ++++++ >>> tools/lib/bpf/btf_dump.c | 4 +++ >>> tools/lib/bpf/libbpf.c | 45 >>> ++++++++++++++++++++++++++++++++- >>> tools/lib/bpf/libbpf.map | 5 ++++ >>> tools/lib/bpf/libbpf_internal.h | 2 ++ >>> 6 files changed, 107 insertions(+), 1 deletion(-) >>> >> [...] >>> diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c >>> index 2f9d685bd522..5e957fcceee6 100644 >>> --- a/tools/lib/bpf/btf_dump.c >>> +++ b/tools/lib/bpf/btf_dump.c >>> @@ -279,6 +279,7 @@ static int btf_dump_mark_referenced(struct >>> btf_dump *d) >>> case BTF_KIND_INT: >>> case BTF_KIND_ENUM: >>> case BTF_KIND_FWD: >>> + case BTF_KIND_FLOAT: >>> break; >>> >>> case BTF_KIND_VOLATILE: >>> @@ -453,6 +454,7 @@ static int btf_dump_order_type(struct btf_dump >>> *d, __u32 id, bool through_ptr) >>> >>> switch (btf_kind(t)) { >>> case BTF_KIND_INT: >>> + case BTF_KIND_FLOAT: >>> tstate->order_state = ORDERED; >>> return 0; >>> >>> @@ -1133,6 +1135,7 @@ static void btf_dump_emit_type_decl(struct >>> btf_dump *d, __u32 id, >>> case BTF_KIND_STRUCT: >>> case BTF_KIND_UNION: >>> case BTF_KIND_TYPEDEF: >>> + case BTF_KIND_FLOAT: >>> goto done; >>> default: >>> pr_warn("unexpected type in decl chain, >>> kind:%u, id:[%u]\n", >>> @@ -1247,6 +1250,7 @@ static void btf_dump_emit_type_chain(struct >>> btf_dump *d, >>> >>> switch (kind) { >>> case BTF_KIND_INT: >>> + case BTF_KIND_FLOAT: >>> btf_dump_emit_mods(d, decls); >>> name = btf_name_of(d, t->name_off); >>> btf_dump_printf(d, "%s", name); >>> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c >>> index d43cc3f29dae..3b170066d613 100644 >>> --- a/tools/lib/bpf/libbpf.c >>> +++ b/tools/lib/bpf/libbpf.c >>> @@ -178,6 +178,8 @@ enum kern_feature_id { >>> FEAT_PROG_BIND_MAP, >>> /* Kernel support for module BTFs */ >>> FEAT_MODULE_BTF, >>> + /* BTF_KIND_FLOAT support */ >>> + FEAT_BTF_FLOAT, >>> __FEAT_CNT, >>> }; >>> >>> @@ -1935,6 +1937,7 @@ static const char *btf_kind_str(const struct >>> btf_type *t) >>> case BTF_KIND_FUNC_PROTO: return "func_proto"; >>> case BTF_KIND_VAR: return "var"; >>> case BTF_KIND_DATASEC: return "datasec"; >>> + case BTF_KIND_FLOAT: return "float"; >>> default: return "unknown"; >>> } >>> } >>> @@ -2384,18 +2387,22 @@ static bool btf_needs_sanitization(struct >>> bpf_object *obj) >>> { >>> bool has_func_global = >>> kernel_supports(FEAT_BTF_GLOBAL_FUNC); >>> bool has_datasec = kernel_supports(FEAT_BTF_DATASEC); >>> + bool has_float = kernel_supports(FEAT_BTF_FLOAT); >>> bool has_func = kernel_supports(FEAT_BTF_FUNC); >>> >>> - return !has_func || !has_datasec || !has_func_global; >>> + return !has_func || !has_datasec || !has_func_global || >>> !has_float; >>> } >>> >>> static void bpf_object__sanitize_btf(struct bpf_object *obj, >>> struct btf *btf) >>> { >>> bool has_func_global = >>> kernel_supports(FEAT_BTF_GLOBAL_FUNC); >>> bool has_datasec = kernel_supports(FEAT_BTF_DATASEC); >>> + bool has_float = kernel_supports(FEAT_BTF_FLOAT); >>> bool has_func = kernel_supports(FEAT_BTF_FUNC); >>> struct btf_type *t; >>> int i, j, vlen; >>> + int t_u32 = 0; >>> + int t_u8 = 0; >>> >>> for (i = 1; i <= btf__get_nr_types(btf); i++) { >>> t = (struct btf_type *)btf__type_by_id(btf, i); >>> @@ -2445,6 +2452,23 @@ static void bpf_object__sanitize_btf(struct >>> bpf_object *obj, struct btf *btf) >>> } else if (!has_func_global && btf_is_func(t)) { >>> /* replace BTF_FUNC_GLOBAL with >>> BTF_FUNC_STATIC */ >>> t->info = BTF_INFO_ENC(BTF_KIND_FUNC, 0, >>> 0); >>> + } else if (!has_float && btf_is_float(t)) { >>> + /* replace FLOAT with TYPEDEF(u8[]) */ >>> + int t_array; >>> + __u32 size; >>> + >>> + size = t->size; >>> + if (!t_u8) >>> + t_u8 = btf__add_int(btf, "u8", 1, >>> 0); >>> + if (!t_u32) >>> + t_u32 = btf__add_int(btf, "u32", 4, >>> 0); >>> + t_array = btf__add_array(btf, t_u32, t_u8, >>> size); >>> + >>> + /* adding new types may have invalidated t >>> */ >>> + t = (struct btf_type *)btf__type_by_id(btf, >>> i); >>> + >>> + t->info = BTF_INFO_ENC(BTF_KIND_TYPEDEF, 0, >>> 0); >> >> This won't work. The typedef must have a valid name. Otherwise, >> kernel >> will reject it. A const char array should be okay here. > > Wouldn't it reuse the old t->name? At least in my testing with v5.7 > kernel this was the case, and BTF wasn't rejected. And the original > BTF_KIND_FLOAT always has a valid name, this is enforced in libbpf and > in the verifier. For example: > > [1] PTR '(anon)' type_id=2 > [2] STRUCT 'foo' size=4 vlen=1 > 'bar' type_id=3 bits_offset=0 > [3] FLOAT 'float' size=4 > [4] FUNC_PROTO '(anon)' ret_type_id=5 vlen=1 > 'f' type_id=1 > [5] PTR '(anon)' type_id=0 > [6] FUNC 'func' type_id=4 linkage=global > > becomes > > [1] PTR '(anon)' type_id=2 > [2] STRUCT 'foo' size=4 vlen=1 > 'bar' type_id=3 bits_offset=0 > [3] TYPEDEF 'float' type_id=9 > [4] FUNC_PROTO '(anon)' ret_type_id=5 vlen=1 > 'f' type_id=1 > [5] PTR '(anon)' type_id=0 > [6] FUNC 'func' type_id=4 linkage=global > [7] INT 'u8' size=1 bits_offset=0 nr_bits=8 encoding=(none) > [8] INT 'u32' size=4 bits_offset=0 nr_bits=32 encoding=(none) > [9] ARRAY '(anon)' type_id=7 index_type_id=8 nr_elems=4 good point, the name is indeed there. I originally also thought about using "typedef" but worried whether new typedef may polute the existing type names. Could you try to dump the modified BTF to a C file and compile to see whether typedef mechanism works or not? I tried the following code and compilation failed. -bash-4.4$ cat t.c typedef char * float; -bash-4.4$ gcc -c t.c t.c:1:16: error: expected identifier or ‘(’ before ‘float’ typedef char * float; ^ -bash-4.4$ Changing to a different name may interfere with existing types. It may work with the kernel today because we didn't do strict type legality checking, but it would be still be good if we can avoid it. >
On Fri, 2021-02-19 at 15:35 -0800, Yonghong Song wrote: > > > On 2/19/21 3:01 PM, Ilya Leoshkevich wrote: > > On Thu, 2021-02-18 at 20:22 -0800, Yonghong Song wrote: > > > > > > > > > On 2/18/21 6:25 PM, Ilya Leoshkevich wrote: > > > > The logic follows that of BTF_KIND_INT most of the time. > > > > Sanitization > > > > replaces BTF_KIND_FLOATs with BTF_KIND_TYPEDEFs pointing to > > > > equally-sized BTF_KIND_ARRAYs on older kernels. > > > > > > > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> > > > > --- > > > > tools/lib/bpf/btf.c | 44 > > > > ++++++++++++++++++++++++++++++++ > > > > tools/lib/bpf/btf.h | 8 ++++++ > > > > tools/lib/bpf/btf_dump.c | 4 +++ > > > > tools/lib/bpf/libbpf.c | 45 > > > > ++++++++++++++++++++++++++++++++- > > > > tools/lib/bpf/libbpf.map | 5 ++++ > > > > tools/lib/bpf/libbpf_internal.h | 2 ++ > > > > 6 files changed, 107 insertions(+), 1 deletion(-) > > > > > > > [...] > > > > diff --git a/tools/lib/bpf/btf_dump.c > > > > b/tools/lib/bpf/btf_dump.c > > > > index 2f9d685bd522..5e957fcceee6 100644 > > > > --- a/tools/lib/bpf/btf_dump.c > > > > +++ b/tools/lib/bpf/btf_dump.c > > > > @@ -279,6 +279,7 @@ static int btf_dump_mark_referenced(struct > > > > btf_dump *d) > > > > case BTF_KIND_INT: > > > > case BTF_KIND_ENUM: > > > > case BTF_KIND_FWD: > > > > + case BTF_KIND_FLOAT: > > > > break; > > > > > > > > case BTF_KIND_VOLATILE: > > > > @@ -453,6 +454,7 @@ static int btf_dump_order_type(struct > > > > btf_dump > > > > *d, __u32 id, bool through_ptr) > > > > > > > > switch (btf_kind(t)) { > > > > case BTF_KIND_INT: > > > > + case BTF_KIND_FLOAT: > > > > tstate->order_state = ORDERED; > > > > return 0; > > > > > > > > @@ -1133,6 +1135,7 @@ static void > > > > btf_dump_emit_type_decl(struct > > > > btf_dump *d, __u32 id, > > > > case BTF_KIND_STRUCT: > > > > case BTF_KIND_UNION: > > > > case BTF_KIND_TYPEDEF: > > > > + case BTF_KIND_FLOAT: > > > > goto done; > > > > default: > > > > pr_warn("unexpected type in decl > > > > chain, > > > > kind:%u, id:[%u]\n", > > > > @@ -1247,6 +1250,7 @@ static void > > > > btf_dump_emit_type_chain(struct > > > > btf_dump *d, > > > > > > > > switch (kind) { > > > > case BTF_KIND_INT: > > > > + case BTF_KIND_FLOAT: > > > > btf_dump_emit_mods(d, decls); > > > > name = btf_name_of(d, t->name_off); > > > > btf_dump_printf(d, "%s", name); > > > > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c > > > > index d43cc3f29dae..3b170066d613 100644 > > > > --- a/tools/lib/bpf/libbpf.c > > > > +++ b/tools/lib/bpf/libbpf.c > > > > @@ -178,6 +178,8 @@ enum kern_feature_id { > > > > FEAT_PROG_BIND_MAP, > > > > /* Kernel support for module BTFs */ > > > > FEAT_MODULE_BTF, > > > > + /* BTF_KIND_FLOAT support */ > > > > + FEAT_BTF_FLOAT, > > > > __FEAT_CNT, > > > > }; > > > > > > > > @@ -1935,6 +1937,7 @@ static const char *btf_kind_str(const > > > > struct > > > > btf_type *t) > > > > case BTF_KIND_FUNC_PROTO: return "func_proto"; > > > > case BTF_KIND_VAR: return "var"; > > > > case BTF_KIND_DATASEC: return "datasec"; > > > > + case BTF_KIND_FLOAT: return "float"; > > > > default: return "unknown"; > > > > } > > > > } > > > > @@ -2384,18 +2387,22 @@ static bool > > > > btf_needs_sanitization(struct > > > > bpf_object *obj) > > > > { > > > > bool has_func_global = > > > > kernel_supports(FEAT_BTF_GLOBAL_FUNC); > > > > bool has_datasec = kernel_supports(FEAT_BTF_DATASEC); > > > > + bool has_float = kernel_supports(FEAT_BTF_FLOAT); > > > > bool has_func = kernel_supports(FEAT_BTF_FUNC); > > > > > > > > - return !has_func || !has_datasec || !has_func_global; > > > > + return !has_func || !has_datasec || !has_func_global || > > > > !has_float; > > > > } > > > > > > > > static void bpf_object__sanitize_btf(struct bpf_object *obj, > > > > struct btf *btf) > > > > { > > > > bool has_func_global = > > > > kernel_supports(FEAT_BTF_GLOBAL_FUNC); > > > > bool has_datasec = kernel_supports(FEAT_BTF_DATASEC); > > > > + bool has_float = kernel_supports(FEAT_BTF_FLOAT); > > > > bool has_func = kernel_supports(FEAT_BTF_FUNC); > > > > struct btf_type *t; > > > > int i, j, vlen; > > > > + int t_u32 = 0; > > > > + int t_u8 = 0; > > > > > > > > for (i = 1; i <= btf__get_nr_types(btf); i++) { > > > > t = (struct btf_type *)btf__type_by_id(btf, > > > > i); > > > > @@ -2445,6 +2452,23 @@ static void > > > > bpf_object__sanitize_btf(struct > > > > bpf_object *obj, struct btf *btf) > > > > } else if (!has_func_global && btf_is_func(t)) > > > > { > > > > /* replace BTF_FUNC_GLOBAL with > > > > BTF_FUNC_STATIC */ > > > > t->info = BTF_INFO_ENC(BTF_KIND_FUNC, > > > > 0, > > > > 0); > > > > + } else if (!has_float && btf_is_float(t)) { > > > > + /* replace FLOAT with TYPEDEF(u8[]) */ > > > > + int t_array; > > > > + __u32 size; > > > > + > > > > + size = t->size; > > > > + if (!t_u8) > > > > + t_u8 = btf__add_int(btf, "u8", > > > > 1, > > > > 0); > > > > + if (!t_u32) > > > > + t_u32 = btf__add_int(btf, > > > > "u32", 4, > > > > 0); > > > > + t_array = btf__add_array(btf, t_u32, > > > > t_u8, > > > > size); > > > > + > > > > + /* adding new types may have > > > > invalidated t > > > > */ > > > > + t = (struct btf_type > > > > *)btf__type_by_id(btf, > > > > i); > > > > + > > > > + t->info = > > > > BTF_INFO_ENC(BTF_KIND_TYPEDEF, 0, > > > > 0); > > > > > > This won't work. The typedef must have a valid name. Otherwise, > > > kernel > > > will reject it. A const char array should be okay here. > > > > Wouldn't it reuse the old t->name? At least in my testing with v5.7 > > kernel this was the case, and BTF wasn't rejected. And the original > > BTF_KIND_FLOAT always has a valid name, this is enforced in libbpf > > and > > in the verifier. For example: > > > > [1] PTR '(anon)' type_id=2 > > [2] STRUCT 'foo' size=4 vlen=1 > > 'bar' type_id=3 bits_offset=0 > > [3] FLOAT 'float' size=4 > > [4] FUNC_PROTO '(anon)' ret_type_id=5 vlen=1 > > 'f' type_id=1 > > [5] PTR '(anon)' type_id=0 > > [6] FUNC 'func' type_id=4 linkage=global > > > > becomes > > > > [1] PTR '(anon)' type_id=2 > > [2] STRUCT 'foo' size=4 vlen=1 > > 'bar' type_id=3 bits_offset=0 > > [3] TYPEDEF 'float' type_id=9 > > [4] FUNC_PROTO '(anon)' ret_type_id=5 vlen=1 > > 'f' type_id=1 > > [5] PTR '(anon)' type_id=0 > > [6] FUNC 'func' type_id=4 linkage=global > > [7] INT 'u8' size=1 bits_offset=0 nr_bits=8 encoding=(none) > > [8] INT 'u32' size=4 bits_offset=0 nr_bits=32 encoding=(none) > > [9] ARRAY '(anon)' type_id=7 index_type_id=8 nr_elems=4 > > good point, the name is indeed there. > > I originally also thought about using "typedef" but worried > whether new typedef may polute the existing type names. > Could you try to dump the modified BTF to a C file > and compile to see whether typedef mechanism works or not? > I tried the following code and compilation failed. > > -bash-4.4$ cat t.c > typedef char * float; > -bash-4.4$ gcc -c t.c > t.c:1:16: error: expected identifier or ‘(’ before ‘float’ > typedef char * float; > ^ > -bash-4.4$ > > Changing to a different name may interfere with existing types. > > It may work with the kernel today because we didn't do strict type > legality checking, but it would be still be good if we can > avoid it. Yeah, the following generated C code does not compile: typedef u8 float[4]; struct foo { float bar; }; I'll go with const. Thanks for the hint!
diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index d9c10830d749..07a30e98c3de 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -291,6 +291,7 @@ static int btf_type_size(const struct btf_type *t) case BTF_KIND_PTR: case BTF_KIND_TYPEDEF: case BTF_KIND_FUNC: + case BTF_KIND_FLOAT: return base_size; case BTF_KIND_INT: return base_size + sizeof(__u32); @@ -338,6 +339,7 @@ static int btf_bswap_type_rest(struct btf_type *t) case BTF_KIND_PTR: case BTF_KIND_TYPEDEF: case BTF_KIND_FUNC: + case BTF_KIND_FLOAT: return 0; case BTF_KIND_INT: *(__u32 *)(t + 1) = bswap_32(*(__u32 *)(t + 1)); @@ -578,6 +580,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id) case BTF_KIND_UNION: case BTF_KIND_ENUM: case BTF_KIND_DATASEC: + case BTF_KIND_FLOAT: size = t->size; goto done; case BTF_KIND_PTR: @@ -621,6 +624,7 @@ int btf__align_of(const struct btf *btf, __u32 id) switch (kind) { case BTF_KIND_INT: case BTF_KIND_ENUM: + case BTF_KIND_FLOAT: return min(btf_ptr_sz(btf), (size_t)t->size); case BTF_KIND_PTR: return btf_ptr_sz(btf); @@ -2373,6 +2377,42 @@ int btf__add_datasec(struct btf *btf, const char *name, __u32 byte_sz) return btf_commit_type(btf, sz); } +/* + * Append new BTF_KIND_FLOAT type with: + * - *name* - non-empty, non-NULL type name; + * - *sz* - size of the type, in bytes; + * Returns: + * - >0, type ID of newly added BTF type; + * - <0, on error. + */ +int btf__add_float(struct btf *btf, const char *name, size_t byte_sz) +{ + struct btf_type *t; + int sz, name_off; + + /* non-empty name */ + if (!name || !name[0]) + return -EINVAL; + + if (btf_ensure_modifiable(btf)) + return -ENOMEM; + + sz = sizeof(struct btf_type); + t = btf_add_type_mem(btf, sz); + if (!t) + return -ENOMEM; + + name_off = btf__add_str(btf, name); + if (name_off < 0) + return name_off; + + t->name_off = name_off; + t->info = btf_type_info(BTF_KIND_FLOAT, 0, 0); + t->size = byte_sz; + + return btf_commit_type(btf, sz); +} + /* * Append new data section variable information entry for current DATASEC type: * - *var_type_id* - type ID, describing type of the variable; @@ -3626,6 +3666,7 @@ static int btf_dedup_prep(struct btf_dedup *d) case BTF_KIND_FWD: case BTF_KIND_TYPEDEF: case BTF_KIND_FUNC: + case BTF_KIND_FLOAT: h = btf_hash_common(t); break; case BTF_KIND_INT: @@ -3722,6 +3763,7 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id) break; case BTF_KIND_FWD: + case BTF_KIND_FLOAT: h = btf_hash_common(t); for_each_dedup_cand(d, hash_entry, h) { cand_id = (__u32)(long)hash_entry->value; @@ -3983,6 +4025,7 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id, return btf_compat_enum(cand_type, canon_type); case BTF_KIND_FWD: + case BTF_KIND_FLOAT: return btf_equal_common(cand_type, canon_type); case BTF_KIND_CONST: @@ -4479,6 +4522,7 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id) switch (btf_kind(t)) { case BTF_KIND_INT: case BTF_KIND_ENUM: + case BTF_KIND_FLOAT: break; case BTF_KIND_FWD: diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h index 1237bcd1dd17..c3b11bcebeda 100644 --- a/tools/lib/bpf/btf.h +++ b/tools/lib/bpf/btf.h @@ -132,6 +132,9 @@ LIBBPF_API int btf__add_datasec(struct btf *btf, const char *name, __u32 byte_sz LIBBPF_API int btf__add_datasec_var_info(struct btf *btf, int var_type_id, __u32 offset, __u32 byte_sz); +/* float construction APIs */ +LIBBPF_API int btf__add_float(struct btf *btf, const char *name, size_t byte_sz); + struct btf_dedup_opts { unsigned int dedup_table_size; bool dont_resolve_fwds; @@ -294,6 +297,11 @@ static inline bool btf_is_datasec(const struct btf_type *t) return btf_kind(t) == BTF_KIND_DATASEC; } +static inline bool btf_is_float(const struct btf_type *t) +{ + return btf_kind(t) == BTF_KIND_FLOAT; +} + static inline __u8 btf_int_encoding(const struct btf_type *t) { return BTF_INT_ENCODING(*(__u32 *)(t + 1)); diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c index 2f9d685bd522..5e957fcceee6 100644 --- a/tools/lib/bpf/btf_dump.c +++ b/tools/lib/bpf/btf_dump.c @@ -279,6 +279,7 @@ static int btf_dump_mark_referenced(struct btf_dump *d) case BTF_KIND_INT: case BTF_KIND_ENUM: case BTF_KIND_FWD: + case BTF_KIND_FLOAT: break; case BTF_KIND_VOLATILE: @@ -453,6 +454,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr) switch (btf_kind(t)) { case BTF_KIND_INT: + case BTF_KIND_FLOAT: tstate->order_state = ORDERED; return 0; @@ -1133,6 +1135,7 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id, case BTF_KIND_STRUCT: case BTF_KIND_UNION: case BTF_KIND_TYPEDEF: + case BTF_KIND_FLOAT: goto done; default: pr_warn("unexpected type in decl chain, kind:%u, id:[%u]\n", @@ -1247,6 +1250,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d, switch (kind) { case BTF_KIND_INT: + case BTF_KIND_FLOAT: btf_dump_emit_mods(d, decls); name = btf_name_of(d, t->name_off); btf_dump_printf(d, "%s", name); diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index d43cc3f29dae..3b170066d613 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -178,6 +178,8 @@ enum kern_feature_id { FEAT_PROG_BIND_MAP, /* Kernel support for module BTFs */ FEAT_MODULE_BTF, + /* BTF_KIND_FLOAT support */ + FEAT_BTF_FLOAT, __FEAT_CNT, }; @@ -1935,6 +1937,7 @@ static const char *btf_kind_str(const struct btf_type *t) case BTF_KIND_FUNC_PROTO: return "func_proto"; case BTF_KIND_VAR: return "var"; case BTF_KIND_DATASEC: return "datasec"; + case BTF_KIND_FLOAT: return "float"; default: return "unknown"; } } @@ -2384,18 +2387,22 @@ static bool btf_needs_sanitization(struct bpf_object *obj) { bool has_func_global = kernel_supports(FEAT_BTF_GLOBAL_FUNC); bool has_datasec = kernel_supports(FEAT_BTF_DATASEC); + bool has_float = kernel_supports(FEAT_BTF_FLOAT); bool has_func = kernel_supports(FEAT_BTF_FUNC); - return !has_func || !has_datasec || !has_func_global; + return !has_func || !has_datasec || !has_func_global || !has_float; } static void bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf) { bool has_func_global = kernel_supports(FEAT_BTF_GLOBAL_FUNC); bool has_datasec = kernel_supports(FEAT_BTF_DATASEC); + bool has_float = kernel_supports(FEAT_BTF_FLOAT); bool has_func = kernel_supports(FEAT_BTF_FUNC); struct btf_type *t; int i, j, vlen; + int t_u32 = 0; + int t_u8 = 0; for (i = 1; i <= btf__get_nr_types(btf); i++) { t = (struct btf_type *)btf__type_by_id(btf, i); @@ -2445,6 +2452,23 @@ static void bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf) } else if (!has_func_global && btf_is_func(t)) { /* replace BTF_FUNC_GLOBAL with BTF_FUNC_STATIC */ t->info = BTF_INFO_ENC(BTF_KIND_FUNC, 0, 0); + } else if (!has_float && btf_is_float(t)) { + /* replace FLOAT with TYPEDEF(u8[]) */ + int t_array; + __u32 size; + + size = t->size; + if (!t_u8) + t_u8 = btf__add_int(btf, "u8", 1, 0); + if (!t_u32) + t_u32 = btf__add_int(btf, "u32", 4, 0); + t_array = btf__add_array(btf, t_u32, t_u8, size); + + /* adding new types may have invalidated t */ + t = (struct btf_type *)btf__type_by_id(btf, i); + + t->info = BTF_INFO_ENC(BTF_KIND_TYPEDEF, 0, 0); + t->type = t_array; } } } @@ -3882,6 +3906,18 @@ static int probe_kern_btf_datasec(void) strs, sizeof(strs))); } +static int probe_kern_btf_float(void) +{ + static const char strs[] = "\0float"; + __u32 types[] = { + /* float */ + BTF_TYPE_FLOAT_ENC(1, 4), + }; + + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), + strs, sizeof(strs))); +} + static int probe_kern_array_mmap(void) { struct bpf_create_map_attr attr = { @@ -4061,6 +4097,9 @@ static struct kern_feature_desc { [FEAT_MODULE_BTF] = { "module BTF support", probe_module_btf, }, + [FEAT_BTF_FLOAT] = { + "BTF_KIND_FLOAT support", probe_kern_btf_float, + }, }; static bool kernel_supports(enum kern_feature_id feat_id) @@ -4940,6 +4979,8 @@ static int bpf_core_fields_are_compat(const struct btf *local_btf, local_id = btf_array(local_type)->type; targ_id = btf_array(targ_type)->type; goto recur; + case BTF_KIND_FLOAT: + return local_type->size == targ_type->size; default: pr_warn("unexpected kind %d relocated, local [%d], target [%d]\n", btf_kind(local_type), local_id, targ_id); @@ -5122,6 +5163,8 @@ static int bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id skip_mods_and_typedefs(targ_btf, targ_type->type, &targ_id); goto recur; } + case BTF_KIND_FLOAT: + return local_type->size == targ_type->size; default: pr_warn("unexpected kind %s relocated, local [%d], target [%d]\n", btf_kind_str(local_type), local_id, targ_id); diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 1c0fd2dd233a..ec898f464ab9 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -350,3 +350,8 @@ LIBBPF_0.3.0 { xsk_setup_xdp_prog; xsk_socket__update_xskmap; } LIBBPF_0.2.0; + +LIBBPF_0.4.0 { + global: + btf__add_float; +} LIBBPF_0.3.0; diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h index 969d0ac592ba..343f6eb05637 100644 --- a/tools/lib/bpf/libbpf_internal.h +++ b/tools/lib/bpf/libbpf_internal.h @@ -31,6 +31,8 @@ #define BTF_MEMBER_ENC(name, type, bits_offset) (name), (type), (bits_offset) #define BTF_PARAM_ENC(name, type) (name), (type) #define BTF_VAR_SECINFO_ENC(type, offset, size) (type), (offset), (size) +#define BTF_TYPE_FLOAT_ENC(name, sz) \ + BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_FLOAT, 0, 0), sz) #ifndef likely #define likely(x) __builtin_expect(!!(x), 1)
The logic follows that of BTF_KIND_INT most of the time. Sanitization replaces BTF_KIND_FLOATs with BTF_KIND_TYPEDEFs pointing to equally-sized BTF_KIND_ARRAYs on older kernels. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> --- tools/lib/bpf/btf.c | 44 ++++++++++++++++++++++++++++++++ tools/lib/bpf/btf.h | 8 ++++++ tools/lib/bpf/btf_dump.c | 4 +++ tools/lib/bpf/libbpf.c | 45 ++++++++++++++++++++++++++++++++- tools/lib/bpf/libbpf.map | 5 ++++ tools/lib/bpf/libbpf_internal.h | 2 ++ 6 files changed, 107 insertions(+), 1 deletion(-)