Message ID | 20230616171728.530116-6-alan.maguire@oracle.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | BPF |
Headers | show |
Series | bpf: support BTF kind layout info, CRCs | expand |
On 6/16/23 10:17 AM, Alan Maguire wrote: > Support encoding of BTF kind layout data and crcs via > btf__new_empty_opts(). > > Current supported opts are base_btf, add_kind_layout and > add_crc. > > Signed-off-by: Alan Maguire <alan.maguire@oracle.com> > --- > tools/lib/bpf/btf.c | 99 ++++++++++++++++++++++++++++++++++++++-- > tools/lib/bpf/btf.h | 11 +++++ > tools/lib/bpf/libbpf.map | 1 + > 3 files changed, 108 insertions(+), 3 deletions(-) > > diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c > index 457997c2a43c..060a93809f64 100644 > --- a/tools/lib/bpf/btf.c > +++ b/tools/lib/bpf/btf.c > @@ -16,6 +16,7 @@ > #include <linux/err.h> > #include <linux/btf.h> > #include <gelf.h> > +#include <zlib.h> > #include "btf.h" > #include "bpf.h" > #include "libbpf.h" > @@ -882,8 +883,58 @@ void btf__free(struct btf *btf) > free(btf); > } > > -static struct btf *btf_new_empty(struct btf *base_btf) > +static void btf_add_kind_layout(struct btf *btf, __u8 kind, > + __u16 flags, __u8 info_sz, __u8 elem_sz) > { > + struct btf_kind_layout *k = &btf->kind_layout[kind]; > + > + k->flags = flags; > + k->info_sz = info_sz; > + k->elem_sz = elem_sz; > + btf->hdr->kind_layout_len += sizeof(*k); > +} > + > +static int btf_ensure_modifiable(struct btf *btf); > + > +static int btf_add_kind_layouts(struct btf *btf, struct btf_new_opts *opts) > +{ > + if (btf_ensure_modifiable(btf)) > + return libbpf_err(-ENOMEM); > + > + btf->kind_layout = calloc(NR_BTF_KINDS, sizeof(struct btf_kind_layout)); > + > + if (!btf->kind_layout) > + return -ENOMEM; > + > + /* all supported kinds should describe their layout here. */ > + btf_add_kind_layout(btf, BTF_KIND_UNKN, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_INT, 0, sizeof(__u32), 0); > + btf_add_kind_layout(btf, BTF_KIND_PTR, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_ARRAY, 0, sizeof(struct btf_array), 0); > + btf_add_kind_layout(btf, BTF_KIND_STRUCT, 0, 0, sizeof(struct btf_member)); > + btf_add_kind_layout(btf, BTF_KIND_UNION, 0, 0, sizeof(struct btf_member)); > + btf_add_kind_layout(btf, BTF_KIND_ENUM, 0, 0, sizeof(struct btf_enum)); > + btf_add_kind_layout(btf, BTF_KIND_FWD, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_TYPEDEF, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_VOLATILE, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_CONST, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_RESTRICT, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_FUNC, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_FUNC_PROTO, 0, 0, sizeof(struct btf_param)); > + btf_add_kind_layout(btf, BTF_KIND_VAR, 0, sizeof(struct btf_var), 0); > + btf_add_kind_layout(btf, BTF_KIND_DATASEC, 0, 0, sizeof(struct btf_var_secinfo)); > + btf_add_kind_layout(btf, BTF_KIND_FLOAT, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_DECL_TAG, BTF_KIND_LAYOUT_OPTIONAL, > + sizeof(struct btf_decl_tag), 0); > + btf_add_kind_layout(btf, BTF_KIND_TYPE_TAG, BTF_KIND_LAYOUT_OPTIONAL, 0, 0); BTF_KIND_TYPE_TAG cannot be optional. For example, ptr -> type_tag -> const -> int if type_tag becomes optional, the whole type chain cannot be parsed properly. Also, in Patch 3, we have +static int btf_type_size(const struct btf *btf, const struct btf_type *t) { const int base_size = sizeof(struct btf_type); __u16 vlen = btf_vlen(t); @@ -363,8 +391,7 @@ static int btf_type_size(const struct btf_type *t) case BTF_KIND_DECL_TAG: return base_size + sizeof(struct btf_decl_tag); default: - pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t)); - return -EINVAL; + return btf_type_size_unknown(btf, t); } } Clearly even if we mark decl_tag as optional, it still handled properly in the above. So decl_tag does not need BTF_KIND_LAYOUT_OPTIONAL, right? I guess what we really want to test is in the selftest: - Add a couple of new kinds for testing purpose, e.g., BTF_KIND_OPTIONAL, BTF_KIND_NOT_OPTIONAL, generate two btf's which uses BTF_KIND_OPTIONAL and BTF_KIND_NOT_OPTIONAL respectively. - test these two btf's with this patch set to see whether it works as expected or not. Does this make sense? > + btf_add_kind_layout(btf, BTF_KIND_ENUM64, 0, 0, sizeof(struct btf_enum64)); > + > + return 0; > +} > + [...]
On 20/06/2023 00:24, Yonghong Song wrote: > > > On 6/16/23 10:17 AM, Alan Maguire wrote: >> Support encoding of BTF kind layout data and crcs via >> btf__new_empty_opts(). >> >> Current supported opts are base_btf, add_kind_layout and >> add_crc. >> >> Signed-off-by: Alan Maguire <alan.maguire@oracle.com> >> --- >> tools/lib/bpf/btf.c | 99 ++++++++++++++++++++++++++++++++++++++-- >> tools/lib/bpf/btf.h | 11 +++++ >> tools/lib/bpf/libbpf.map | 1 + >> 3 files changed, 108 insertions(+), 3 deletions(-) >> >> diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c >> index 457997c2a43c..060a93809f64 100644 >> --- a/tools/lib/bpf/btf.c >> +++ b/tools/lib/bpf/btf.c >> @@ -16,6 +16,7 @@ >> #include <linux/err.h> >> #include <linux/btf.h> >> #include <gelf.h> >> +#include <zlib.h> >> #include "btf.h" >> #include "bpf.h" >> #include "libbpf.h" >> @@ -882,8 +883,58 @@ void btf__free(struct btf *btf) >> free(btf); >> } >> -static struct btf *btf_new_empty(struct btf *base_btf) >> +static void btf_add_kind_layout(struct btf *btf, __u8 kind, >> + __u16 flags, __u8 info_sz, __u8 elem_sz) >> { >> + struct btf_kind_layout *k = &btf->kind_layout[kind]; >> + >> + k->flags = flags; >> + k->info_sz = info_sz; >> + k->elem_sz = elem_sz; >> + btf->hdr->kind_layout_len += sizeof(*k); >> +} >> + >> +static int btf_ensure_modifiable(struct btf *btf); >> + >> +static int btf_add_kind_layouts(struct btf *btf, struct btf_new_opts >> *opts) >> +{ >> + if (btf_ensure_modifiable(btf)) >> + return libbpf_err(-ENOMEM); >> + >> + btf->kind_layout = calloc(NR_BTF_KINDS, sizeof(struct >> btf_kind_layout)); >> + >> + if (!btf->kind_layout) >> + return -ENOMEM; >> + >> + /* all supported kinds should describe their layout here. */ >> + btf_add_kind_layout(btf, BTF_KIND_UNKN, 0, 0, 0); >> + btf_add_kind_layout(btf, BTF_KIND_INT, 0, sizeof(__u32), 0); >> + btf_add_kind_layout(btf, BTF_KIND_PTR, 0, 0, 0); >> + btf_add_kind_layout(btf, BTF_KIND_ARRAY, 0, sizeof(struct >> btf_array), 0); >> + btf_add_kind_layout(btf, BTF_KIND_STRUCT, 0, 0, sizeof(struct >> btf_member)); >> + btf_add_kind_layout(btf, BTF_KIND_UNION, 0, 0, sizeof(struct >> btf_member)); >> + btf_add_kind_layout(btf, BTF_KIND_ENUM, 0, 0, sizeof(struct >> btf_enum)); >> + btf_add_kind_layout(btf, BTF_KIND_FWD, 0, 0, 0); >> + btf_add_kind_layout(btf, BTF_KIND_TYPEDEF, 0, 0, 0); >> + btf_add_kind_layout(btf, BTF_KIND_VOLATILE, 0, 0, 0); >> + btf_add_kind_layout(btf, BTF_KIND_CONST, 0, 0, 0); >> + btf_add_kind_layout(btf, BTF_KIND_RESTRICT, 0, 0, 0); >> + btf_add_kind_layout(btf, BTF_KIND_FUNC, 0, 0, 0); >> + btf_add_kind_layout(btf, BTF_KIND_FUNC_PROTO, 0, 0, sizeof(struct >> btf_param)); >> + btf_add_kind_layout(btf, BTF_KIND_VAR, 0, sizeof(struct btf_var), >> 0); >> + btf_add_kind_layout(btf, BTF_KIND_DATASEC, 0, 0, sizeof(struct >> btf_var_secinfo)); >> + btf_add_kind_layout(btf, BTF_KIND_FLOAT, 0, 0, 0); >> + btf_add_kind_layout(btf, BTF_KIND_DECL_TAG, >> BTF_KIND_LAYOUT_OPTIONAL, >> + sizeof(struct btf_decl_tag), 0); >> + btf_add_kind_layout(btf, BTF_KIND_TYPE_TAG, >> BTF_KIND_LAYOUT_OPTIONAL, 0, 0); > > BTF_KIND_TYPE_TAG cannot be optional. For example, > ptr -> type_tag -> const -> int > > if type_tag becomes optional, the whole type chain cannot be parsed > properly. > Ah, I missed that, thanks! You're absolutely right. There are two separate concerns I think: 1. if an unknown kind (unknown to libbpf/kernel but present in the kind layout) is ever pointed at by another kind, regardless of optional status, the BTF must be rejected on the grounds that we don't really have a way to understand what the BTF means. That catches the case above. 2. however if an unknown kind exists in BTF and _is_ optional _and_ is not pointed at by any known kinds, that is fine. In other words it's logically possible for us to want to either accept or reject BTF when we encounter unknown kinds that fall outside of the existing type graph relations; the optional flag tells us which to do. I think for meta checking, the right way to handle 1 is to reject BTF in the kind-specific meta checking for any known kinds that can refer to other kinds; if the kind referred to is > KIND_MAX, we reject the BTF. > Also, in Patch 3, we have > > +static int btf_type_size(const struct btf *btf, const struct btf_type *t) > { > const int base_size = sizeof(struct btf_type); > __u16 vlen = btf_vlen(t); > @@ -363,8 +391,7 @@ static int btf_type_size(const struct btf_type *t) > case BTF_KIND_DECL_TAG: > return base_size + sizeof(struct btf_decl_tag); > default: > - pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t)); > - return -EINVAL; > + return btf_type_size_unknown(btf, t); > } > } > > Clearly even if we mark decl_tag as optional, it still handled properly > in the above. So decl_tag does not need BTF_KIND_LAYOUT_OPTIONAL, right? > But in btf_type_size_unknown() we have: if (!(k->flags & BTF_KIND_LAYOUT_OPTIONAL)) { /* a required kind, and we do not know about it.. */ pr_debug("unknown but required kind: %u\n", kind); return -EINVAL; } The problem however I think is that we need to spot reference types that refer to unknown kinds regardless of optional status as described above. > I guess what we really want to test is in the selftest: > - Add a couple of new kinds for testing purpose, e.g., > BTF_KIND_OPTIONAL, BTF_KIND_NOT_OPTIONAL, > generate two btf's which uses BTF_KIND_OPTIONAL > and BTF_KIND_NOT_OPTIONAL respectively. > - test these two btf's with this patch set to see whether it > works as expected or not. > > Does this make sense? > There's a test that does this currently for libbpf only (since we need a struct btf to load into the kernel), but nothing to cover the case where a reference type points at a kind we don't know about. I'll update the tests to use reference types too. Thanks! Alan >> + btf_add_kind_layout(btf, BTF_KIND_ENUM64, 0, 0, sizeof(struct >> btf_enum64)); >> + >> + return 0; >> +} >> + > [...]
On 6/20/23 2:09 AM, Alan Maguire wrote: > On 20/06/2023 00:24, Yonghong Song wrote: >> >> >> On 6/16/23 10:17 AM, Alan Maguire wrote: >>> Support encoding of BTF kind layout data and crcs via >>> btf__new_empty_opts(). >>> >>> Current supported opts are base_btf, add_kind_layout and >>> add_crc. >>> >>> Signed-off-by: Alan Maguire <alan.maguire@oracle.com> >>> --- >>> tools/lib/bpf/btf.c | 99 ++++++++++++++++++++++++++++++++++++++-- >>> tools/lib/bpf/btf.h | 11 +++++ >>> tools/lib/bpf/libbpf.map | 1 + >>> 3 files changed, 108 insertions(+), 3 deletions(-) >>> >>> diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c >>> index 457997c2a43c..060a93809f64 100644 >>> --- a/tools/lib/bpf/btf.c >>> +++ b/tools/lib/bpf/btf.c >>> @@ -16,6 +16,7 @@ >>> #include <linux/err.h> >>> #include <linux/btf.h> >>> #include <gelf.h> >>> +#include <zlib.h> >>> #include "btf.h" >>> #include "bpf.h" >>> #include "libbpf.h" >>> @@ -882,8 +883,58 @@ void btf__free(struct btf *btf) >>> free(btf); >>> } >>> -static struct btf *btf_new_empty(struct btf *base_btf) >>> +static void btf_add_kind_layout(struct btf *btf, __u8 kind, >>> + __u16 flags, __u8 info_sz, __u8 elem_sz) >>> { >>> + struct btf_kind_layout *k = &btf->kind_layout[kind]; >>> + >>> + k->flags = flags; >>> + k->info_sz = info_sz; >>> + k->elem_sz = elem_sz; >>> + btf->hdr->kind_layout_len += sizeof(*k); >>> +} >>> + >>> +static int btf_ensure_modifiable(struct btf *btf); >>> + >>> +static int btf_add_kind_layouts(struct btf *btf, struct btf_new_opts >>> *opts) >>> +{ >>> + if (btf_ensure_modifiable(btf)) >>> + return libbpf_err(-ENOMEM); >>> + >>> + btf->kind_layout = calloc(NR_BTF_KINDS, sizeof(struct >>> btf_kind_layout)); >>> + >>> + if (!btf->kind_layout) >>> + return -ENOMEM; >>> + >>> + /* all supported kinds should describe their layout here. */ >>> + btf_add_kind_layout(btf, BTF_KIND_UNKN, 0, 0, 0); >>> + btf_add_kind_layout(btf, BTF_KIND_INT, 0, sizeof(__u32), 0); >>> + btf_add_kind_layout(btf, BTF_KIND_PTR, 0, 0, 0); >>> + btf_add_kind_layout(btf, BTF_KIND_ARRAY, 0, sizeof(struct >>> btf_array), 0); >>> + btf_add_kind_layout(btf, BTF_KIND_STRUCT, 0, 0, sizeof(struct >>> btf_member)); >>> + btf_add_kind_layout(btf, BTF_KIND_UNION, 0, 0, sizeof(struct >>> btf_member)); >>> + btf_add_kind_layout(btf, BTF_KIND_ENUM, 0, 0, sizeof(struct >>> btf_enum)); >>> + btf_add_kind_layout(btf, BTF_KIND_FWD, 0, 0, 0); >>> + btf_add_kind_layout(btf, BTF_KIND_TYPEDEF, 0, 0, 0); >>> + btf_add_kind_layout(btf, BTF_KIND_VOLATILE, 0, 0, 0); >>> + btf_add_kind_layout(btf, BTF_KIND_CONST, 0, 0, 0); >>> + btf_add_kind_layout(btf, BTF_KIND_RESTRICT, 0, 0, 0); >>> + btf_add_kind_layout(btf, BTF_KIND_FUNC, 0, 0, 0); >>> + btf_add_kind_layout(btf, BTF_KIND_FUNC_PROTO, 0, 0, sizeof(struct >>> btf_param)); >>> + btf_add_kind_layout(btf, BTF_KIND_VAR, 0, sizeof(struct btf_var), >>> 0); >>> + btf_add_kind_layout(btf, BTF_KIND_DATASEC, 0, 0, sizeof(struct >>> btf_var_secinfo)); >>> + btf_add_kind_layout(btf, BTF_KIND_FLOAT, 0, 0, 0); >>> + btf_add_kind_layout(btf, BTF_KIND_DECL_TAG, >>> BTF_KIND_LAYOUT_OPTIONAL, >>> + sizeof(struct btf_decl_tag), 0); >>> + btf_add_kind_layout(btf, BTF_KIND_TYPE_TAG, >>> BTF_KIND_LAYOUT_OPTIONAL, 0, 0); >> >> BTF_KIND_TYPE_TAG cannot be optional. For example, >> ptr -> type_tag -> const -> int >> >> if type_tag becomes optional, the whole type chain cannot be parsed >> properly. >> > > Ah, I missed that, thanks! You're absolutely right. > > There are two separate concerns I think: > > 1. if an unknown kind (unknown to libbpf/kernel but present in the kind > layout) is ever pointed at by another kind, regardless of optional > status, the BTF must be rejected on the grounds that we don't really > have a way to understand what the BTF means. That catches the case > above. > 2. however if an unknown kind exists in BTF and _is_ optional _and_ > is not pointed at by any known kinds, that is fine. > > In other words it's logically possible for us to want to either > accept or reject BTF when we encounter unknown kinds that fall outside > of the existing type graph relations; the optional flag tells us which > to do. > > I think for meta checking, the right way to handle 1 is to > reject BTF in the kind-specific meta checking for any known > kinds that can refer to other kinds; if the kind referred to > is > KIND_MAX, we reject the BTF. I agree with your above analysis. > >> Also, in Patch 3, we have >> >> +static int btf_type_size(const struct btf *btf, const struct btf_type *t) >> { >> const int base_size = sizeof(struct btf_type); >> __u16 vlen = btf_vlen(t); >> @@ -363,8 +391,7 @@ static int btf_type_size(const struct btf_type *t) >> case BTF_KIND_DECL_TAG: >> return base_size + sizeof(struct btf_decl_tag); >> default: >> - pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t)); >> - return -EINVAL; >> + return btf_type_size_unknown(btf, t); >> } >> } >> >> Clearly even if we mark decl_tag as optional, it still handled properly >> in the above. So decl_tag does not need BTF_KIND_LAYOUT_OPTIONAL, right? >> > But in btf_type_size_unknown() we have: > > if (!(k->flags & BTF_KIND_LAYOUT_OPTIONAL)) { > /* a required kind, and we do not know about it.. */ > pr_debug("unknown but required kind: %u\n", kind); > return -EINVAL; > } > > The problem however I think is that we need to spot reference > types that refer to unknown kinds regardless of optional status > as described above. What I mean is there is no need to tag decl_tag with BTF_KIND_LAYOUT_OPTIONAL since for any btf with kind_layout, decl_tag is already there. But BTF_KIND_LAYOUT_OPTIONAL is still necessary for future kinds. > >> I guess what we really want to test is in the selftest: >> - Add a couple of new kinds for testing purpose, e.g., >> BTF_KIND_OPTIONAL, BTF_KIND_NOT_OPTIONAL, >> generate two btf's which uses BTF_KIND_OPTIONAL >> and BTF_KIND_NOT_OPTIONAL respectively. >> - test these two btf's with this patch set to see whether it >> works as expected or not. >> >> Does this make sense? >> > > There's a test that does this currently for libbpf only (since we > need a struct btf to load into the kernel), but nothing to cover the > case where a reference type points at a kind we don't know about. > I'll update the tests to use reference types too. Sounds good. thanks for adding additional tests. > > Thanks! > > Alan > >>> + btf_add_kind_layout(btf, BTF_KIND_ENUM64, 0, 0, sizeof(struct >>> btf_enum64)); >>> + >>> + return 0; >>> +} >>> + >> [...]
On Fri, Jun 16, 2023 at 10:18 AM Alan Maguire <alan.maguire@oracle.com> wrote: > > Support encoding of BTF kind layout data and crcs via > btf__new_empty_opts(). > > Current supported opts are base_btf, add_kind_layout and > add_crc. > > Signed-off-by: Alan Maguire <alan.maguire@oracle.com> > --- > tools/lib/bpf/btf.c | 99 ++++++++++++++++++++++++++++++++++++++-- > tools/lib/bpf/btf.h | 11 +++++ > tools/lib/bpf/libbpf.map | 1 + > 3 files changed, 108 insertions(+), 3 deletions(-) > > diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c > index 457997c2a43c..060a93809f64 100644 > --- a/tools/lib/bpf/btf.c > +++ b/tools/lib/bpf/btf.c > @@ -16,6 +16,7 @@ > #include <linux/err.h> > #include <linux/btf.h> > #include <gelf.h> > +#include <zlib.h> > #include "btf.h" > #include "bpf.h" > #include "libbpf.h" > @@ -882,8 +883,58 @@ void btf__free(struct btf *btf) > free(btf); > } > > -static struct btf *btf_new_empty(struct btf *base_btf) > +static void btf_add_kind_layout(struct btf *btf, __u8 kind, > + __u16 flags, __u8 info_sz, __u8 elem_sz) > { > + struct btf_kind_layout *k = &btf->kind_layout[kind]; > + > + k->flags = flags; > + k->info_sz = info_sz; > + k->elem_sz = elem_sz; > + btf->hdr->kind_layout_len += sizeof(*k); > +} > + > +static int btf_ensure_modifiable(struct btf *btf); > + > +static int btf_add_kind_layouts(struct btf *btf, struct btf_new_opts *opts) > +{ > + if (btf_ensure_modifiable(btf)) > + return libbpf_err(-ENOMEM); > + > + btf->kind_layout = calloc(NR_BTF_KINDS, sizeof(struct btf_kind_layout)); > + > + if (!btf->kind_layout) > + return -ENOMEM; > + > + /* all supported kinds should describe their layout here. */ why not have a static table for each known kind and then just memcpy it? Seems both more elegant and more maintainable? static struct btf_kind_layout layout[] = { [BTF_KIND_UNKN] = {0, 0, 0}, [BTF_KIND_UNKN] = {0, sizeof(__u32), 0}, ... [BTF_KIND_STRUCT] = {0, 0, sizeof(struct btf_member)}, }; ? > + btf_add_kind_layout(btf, BTF_KIND_UNKN, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_INT, 0, sizeof(__u32), 0); > + btf_add_kind_layout(btf, BTF_KIND_PTR, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_ARRAY, 0, sizeof(struct btf_array), 0); > + btf_add_kind_layout(btf, BTF_KIND_STRUCT, 0, 0, sizeof(struct btf_member)); > + btf_add_kind_layout(btf, BTF_KIND_UNION, 0, 0, sizeof(struct btf_member)); > + btf_add_kind_layout(btf, BTF_KIND_ENUM, 0, 0, sizeof(struct btf_enum)); > + btf_add_kind_layout(btf, BTF_KIND_FWD, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_TYPEDEF, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_VOLATILE, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_CONST, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_RESTRICT, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_FUNC, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_FUNC_PROTO, 0, 0, sizeof(struct btf_param)); > + btf_add_kind_layout(btf, BTF_KIND_VAR, 0, sizeof(struct btf_var), 0); > + btf_add_kind_layout(btf, BTF_KIND_DATASEC, 0, 0, sizeof(struct btf_var_secinfo)); > + btf_add_kind_layout(btf, BTF_KIND_FLOAT, 0, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_DECL_TAG, BTF_KIND_LAYOUT_OPTIONAL, > + sizeof(struct btf_decl_tag), 0); > + btf_add_kind_layout(btf, BTF_KIND_TYPE_TAG, BTF_KIND_LAYOUT_OPTIONAL, 0, 0); > + btf_add_kind_layout(btf, BTF_KIND_ENUM64, 0, 0, sizeof(struct btf_enum64)); > + > + return 0; > +} > + > +static struct btf *btf_new_empty(struct btf_new_opts *opts) > +{ > + struct btf *base_btf = OPTS_GET(opts, base_btf, NULL); > struct btf *btf; > > btf = calloc(1, sizeof(*btf)); > @@ -920,17 +971,53 @@ static struct btf *btf_new_empty(struct btf *base_btf) > btf->strs_data = btf->raw_data + btf->hdr->hdr_len; > btf->hdr->str_len = base_btf ? 0 : 1; /* empty string at offset 0 */ > > + if (opts->add_kind_layout) { > + int err = btf_add_kind_layouts(btf, opts); > + as I mentioned, I'd always add it internally, but allow to control whether it has to be emitted into raw_data > + if (err) { > + free(btf->raw_data); > + free(btf); > + return ERR_PTR(err); > + } > + } > + if (opts->add_crc) { > + if (btf->base_btf) { > + struct btf_header *base_hdr = btf->base_btf->hdr; > + > + if (base_hdr->hdr_len >= sizeof(struct btf_header) && > + base_hdr->flags & BTF_FLAG_CRC_SET) { > + btf->hdr->base_crc = base_hdr->crc; > + btf->hdr->flags |= BTF_FLAG_BASE_CRC_SET; > + } > + } > + btf->hdr->flags |= BTF_FLAG_CRC_SET; > + } > + > return btf; > } > > struct btf *btf__new_empty(void) > { > - return libbpf_ptr(btf_new_empty(NULL)); > + LIBBPF_OPTS(btf_new_opts, opts); > + > + return libbpf_ptr(btf_new_empty(&opts)); why? just pass NULL, it's fine, no need to create empty opts > } > > struct btf *btf__new_empty_split(struct btf *base_btf) > { > - return libbpf_ptr(btf_new_empty(base_btf)); > + LIBBPF_OPTS(btf_new_opts, opts); > + > + opts.base_btf = base_btf; nit: it's cleaner to initialize opts on declaration in this case LIBBPF_OPTS(btf_new_opts, opts, .base_btf = base_btf); > + > + return libbpf_ptr(btf_new_empty(&opts)); > +} > + > +struct btf *btf__new_empty_opts(struct btf_new_opts *opts) > +{ > + if (!OPTS_VALID(opts, btf_new_opts)) > + return libbpf_err_ptr(-EINVAL); > + > + return libbpf_ptr(btf_new_empty(opts)); > } > > static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf) > @@ -1377,6 +1464,12 @@ static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endi > btf_bswap_kind_layout_sec(p, hdr->kind_layout_len); > p += hdr->kind_layout_len; > } > + if (hdr->flags & BTF_FLAG_CRC_SET) { > + struct btf_header *h = data; > + > + h->crc = crc32(0L, (const Bytef *)&data, sizeof(data)); is crc32() part of zlib's public API? > + } > + > *size = data_sz; > return data; > err_out: > diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h > index 8e6880d91c84..d25bd5c19eec 100644 > --- a/tools/lib/bpf/btf.h > +++ b/tools/lib/bpf/btf.h > @@ -107,6 +107,17 @@ LIBBPF_API struct btf *btf__new_empty(void); > */ > LIBBPF_API struct btf *btf__new_empty_split(struct btf *base_btf); > > +struct btf_new_opts { > + size_t sz; > + struct btf *base_btf; /* optional base BTF */ > + bool add_kind_layout; /* add BTF kind layout information */ I'd say let's make it opt-out option and by default do emit kind layout? so rather "skip_kind_layout" > + bool add_crc; /* add CRC information */ same for crc? "skip_crc"? btw, does add_crc imply both crc and base_crc (if base_btf != NULL)? just thinking out loud if we need to control that independently... > + size_t:0; > +}; > +#define btf_new_opts__last_field add_crc > + > +LIBBPF_API struct btf *btf__new_empty_opts(struct btf_new_opts *opts); > + > LIBBPF_API struct btf *btf__parse(const char *path, struct btf_ext **btf_ext); > LIBBPF_API struct btf *btf__parse_split(const char *path, struct btf *base_btf); > LIBBPF_API struct btf *btf__parse_elf(const char *path, struct btf_ext **btf_ext); > diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map > index 7521a2fb7626..edd8be4b21d0 100644 > --- a/tools/lib/bpf/libbpf.map > +++ b/tools/lib/bpf/libbpf.map > @@ -395,4 +395,5 @@ LIBBPF_1.2.0 { > LIBBPF_1.3.0 { > global: > bpf_obj_pin_opts; > + btf__new_empty_opts; > } LIBBPF_1.2.0; > -- > 2.39.3 >
diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index 457997c2a43c..060a93809f64 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -16,6 +16,7 @@ #include <linux/err.h> #include <linux/btf.h> #include <gelf.h> +#include <zlib.h> #include "btf.h" #include "bpf.h" #include "libbpf.h" @@ -882,8 +883,58 @@ void btf__free(struct btf *btf) free(btf); } -static struct btf *btf_new_empty(struct btf *base_btf) +static void btf_add_kind_layout(struct btf *btf, __u8 kind, + __u16 flags, __u8 info_sz, __u8 elem_sz) { + struct btf_kind_layout *k = &btf->kind_layout[kind]; + + k->flags = flags; + k->info_sz = info_sz; + k->elem_sz = elem_sz; + btf->hdr->kind_layout_len += sizeof(*k); +} + +static int btf_ensure_modifiable(struct btf *btf); + +static int btf_add_kind_layouts(struct btf *btf, struct btf_new_opts *opts) +{ + if (btf_ensure_modifiable(btf)) + return libbpf_err(-ENOMEM); + + btf->kind_layout = calloc(NR_BTF_KINDS, sizeof(struct btf_kind_layout)); + + if (!btf->kind_layout) + return -ENOMEM; + + /* all supported kinds should describe their layout here. */ + btf_add_kind_layout(btf, BTF_KIND_UNKN, 0, 0, 0); + btf_add_kind_layout(btf, BTF_KIND_INT, 0, sizeof(__u32), 0); + btf_add_kind_layout(btf, BTF_KIND_PTR, 0, 0, 0); + btf_add_kind_layout(btf, BTF_KIND_ARRAY, 0, sizeof(struct btf_array), 0); + btf_add_kind_layout(btf, BTF_KIND_STRUCT, 0, 0, sizeof(struct btf_member)); + btf_add_kind_layout(btf, BTF_KIND_UNION, 0, 0, sizeof(struct btf_member)); + btf_add_kind_layout(btf, BTF_KIND_ENUM, 0, 0, sizeof(struct btf_enum)); + btf_add_kind_layout(btf, BTF_KIND_FWD, 0, 0, 0); + btf_add_kind_layout(btf, BTF_KIND_TYPEDEF, 0, 0, 0); + btf_add_kind_layout(btf, BTF_KIND_VOLATILE, 0, 0, 0); + btf_add_kind_layout(btf, BTF_KIND_CONST, 0, 0, 0); + btf_add_kind_layout(btf, BTF_KIND_RESTRICT, 0, 0, 0); + btf_add_kind_layout(btf, BTF_KIND_FUNC, 0, 0, 0); + btf_add_kind_layout(btf, BTF_KIND_FUNC_PROTO, 0, 0, sizeof(struct btf_param)); + btf_add_kind_layout(btf, BTF_KIND_VAR, 0, sizeof(struct btf_var), 0); + btf_add_kind_layout(btf, BTF_KIND_DATASEC, 0, 0, sizeof(struct btf_var_secinfo)); + btf_add_kind_layout(btf, BTF_KIND_FLOAT, 0, 0, 0); + btf_add_kind_layout(btf, BTF_KIND_DECL_TAG, BTF_KIND_LAYOUT_OPTIONAL, + sizeof(struct btf_decl_tag), 0); + btf_add_kind_layout(btf, BTF_KIND_TYPE_TAG, BTF_KIND_LAYOUT_OPTIONAL, 0, 0); + btf_add_kind_layout(btf, BTF_KIND_ENUM64, 0, 0, sizeof(struct btf_enum64)); + + return 0; +} + +static struct btf *btf_new_empty(struct btf_new_opts *opts) +{ + struct btf *base_btf = OPTS_GET(opts, base_btf, NULL); struct btf *btf; btf = calloc(1, sizeof(*btf)); @@ -920,17 +971,53 @@ static struct btf *btf_new_empty(struct btf *base_btf) btf->strs_data = btf->raw_data + btf->hdr->hdr_len; btf->hdr->str_len = base_btf ? 0 : 1; /* empty string at offset 0 */ + if (opts->add_kind_layout) { + int err = btf_add_kind_layouts(btf, opts); + + if (err) { + free(btf->raw_data); + free(btf); + return ERR_PTR(err); + } + } + if (opts->add_crc) { + if (btf->base_btf) { + struct btf_header *base_hdr = btf->base_btf->hdr; + + if (base_hdr->hdr_len >= sizeof(struct btf_header) && + base_hdr->flags & BTF_FLAG_CRC_SET) { + btf->hdr->base_crc = base_hdr->crc; + btf->hdr->flags |= BTF_FLAG_BASE_CRC_SET; + } + } + btf->hdr->flags |= BTF_FLAG_CRC_SET; + } + return btf; } struct btf *btf__new_empty(void) { - return libbpf_ptr(btf_new_empty(NULL)); + LIBBPF_OPTS(btf_new_opts, opts); + + return libbpf_ptr(btf_new_empty(&opts)); } struct btf *btf__new_empty_split(struct btf *base_btf) { - return libbpf_ptr(btf_new_empty(base_btf)); + LIBBPF_OPTS(btf_new_opts, opts); + + opts.base_btf = base_btf; + + return libbpf_ptr(btf_new_empty(&opts)); +} + +struct btf *btf__new_empty_opts(struct btf_new_opts *opts) +{ + if (!OPTS_VALID(opts, btf_new_opts)) + return libbpf_err_ptr(-EINVAL); + + return libbpf_ptr(btf_new_empty(opts)); } static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf) @@ -1377,6 +1464,12 @@ static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endi btf_bswap_kind_layout_sec(p, hdr->kind_layout_len); p += hdr->kind_layout_len; } + if (hdr->flags & BTF_FLAG_CRC_SET) { + struct btf_header *h = data; + + h->crc = crc32(0L, (const Bytef *)&data, sizeof(data)); + } + *size = data_sz; return data; err_out: diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h index 8e6880d91c84..d25bd5c19eec 100644 --- a/tools/lib/bpf/btf.h +++ b/tools/lib/bpf/btf.h @@ -107,6 +107,17 @@ LIBBPF_API struct btf *btf__new_empty(void); */ LIBBPF_API struct btf *btf__new_empty_split(struct btf *base_btf); +struct btf_new_opts { + size_t sz; + struct btf *base_btf; /* optional base BTF */ + bool add_kind_layout; /* add BTF kind layout information */ + bool add_crc; /* add CRC information */ + size_t:0; +}; +#define btf_new_opts__last_field add_crc + +LIBBPF_API struct btf *btf__new_empty_opts(struct btf_new_opts *opts); + LIBBPF_API struct btf *btf__parse(const char *path, struct btf_ext **btf_ext); LIBBPF_API struct btf *btf__parse_split(const char *path, struct btf *base_btf); LIBBPF_API struct btf *btf__parse_elf(const char *path, struct btf_ext **btf_ext); diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 7521a2fb7626..edd8be4b21d0 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -395,4 +395,5 @@ LIBBPF_1.2.0 { LIBBPF_1.3.0 { global: bpf_obj_pin_opts; + btf__new_empty_opts; } LIBBPF_1.2.0;
Support encoding of BTF kind layout data and crcs via btf__new_empty_opts(). Current supported opts are base_btf, add_kind_layout and add_crc. Signed-off-by: Alan Maguire <alan.maguire@oracle.com> --- tools/lib/bpf/btf.c | 99 ++++++++++++++++++++++++++++++++++++++-- tools/lib/bpf/btf.h | 11 +++++ tools/lib/bpf/libbpf.map | 1 + 3 files changed, 108 insertions(+), 3 deletions(-)