Re: [RFC bpf-next 2/5] libbpf: provide libbpf API to encode BTF kind information

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Nov 29, 2022 at 5:51 AM Alan Maguire <alan.maguire@xxxxxxxxxx> wrote:
>
> On 29/11/2022 05:35, Andrii Nakryiko wrote:
> > On Wed, Nov 23, 2022 at 9:42 AM Alan Maguire <alan.maguire@xxxxxxxxxx> wrote:
> >>
> >> This can be used by BTF parsers to handle kinds they do not know about;
> >> this is useful when the encoding libbpf is more recent than the parsing
> >> BTF; the parser can then skip over the encoded types it does not know
> >> about.
> >>
> >> We use BTF to encode the BTF kinds that are known at the time of
> >> BTF encoding; the use of basic BTF kinds (structs, arrays, base types)
> >> to describe each kind and any associated metadata allows BTF parsing
> >> to handle new kinds that the parser (in libbpf or the kernel) does
> >> not know about.  These kinds will not be used, but since we know
> >> their format they can be skipped over and the rest of the BTF can
> >> be parsed.  This means we can encode BTF without worrying about the
> >> kinds a BTF parser knows about, and means we can avoid using
> >> --skip_new_kind solutions.  This is valuable, as if kernel BTF encodes
> >> everything it can, something as simple as a libbpf package update
> >> then unlocks that encoded information, whereas if we encode
> >> pessimistically and drop representations of new kinds, this is not
> >> possible.
> >>
> >> So, in short, by carrying a representation of all the kinds encoded,
> >> parsers can parse all of the encoded kinds, even if they cannot use
> >> them all.
> >>
> >> We use BTF itself to carry this representation because this approach
> >> does not require BTF parsing to understand a new BTF header format;
> >> BTF parsing simply sees some additional types it does not do anything
> >> with.  However, a BTF parser that knows about the encoding of kind
> >> information can use this information to guide parsing.
> >>
> >> The process works by explicitly adding btf structs for each kind.
> >> Each struct consists of a "struct __btf_type" followed by an array of
> >> metadata structs representing the following metadata (for those kinds
> >> that have it).  For kinds where a single metadata structure is used,
> >> the metadata array has one element.  For kinds where the number
> >> of metadata elements varies as per the info.vlen field, a zero-element
> >> array is encoded.
> >>
> >> For a given kind, we add a struct __BTF_KIND_<kind>.  For example,
> >>
> >> struct __BTF_KIND_INT {
> >>         struct __btf_type type;
> >> };
> >>
> >> For a type with one metadata element, the representation looks like
> >> this:
> >>
> >> struct __BTF_KIND_META_ARRAY {
> >>         __u32 type;
> >>         __u32 index_type;
> >>         __u32 nelems;
> >> };
> >>
> >> struct __BTF_KIND_ARRAY {
> >>         struct __btf_type type;
> >>         struct __BTF_KIND_META_ARRAY meta[1];
> >> };
> >>
> >> For a type with an info.vlen-determined number of following metadata
> >> objects, a zero-length array is used:
> >>
> >> struct __BTF_KIND_STRUCT {
> >>         struct __btf_type type;
> >>         struct __BTF_KIND_META_STRUCT meta[0];
> >> };
> >>
> >> In order to link kind numeric kind values to the appropriate struct,
> >> a typedef is added; for example:
> >>
> >> typedef struct __BTF_KIND_INT __BTF_KIND_1;
> >>
> >> When BTF parsing encounters a kind that is not known, the
> >> typedef __BTF_KIND_<kind number> is looked up, and we find which
> >> struct type id it points to.  So
> >>
> >>         1 -> typedef __BTF_KIND_1 -> struct __BTF_KIND_INT
> >>
> >> This approach is preferred, since it ensures the structs representing
> >> BTF kinds have names which match their associated kind rather than
> >> an opaque number.
> >>
> >> From there, BTF parsing can look up that struct and determine
> >>         - its basic size;
> >>         - if it has metadata; and if so
> >>         - how many array instances are present;
> >>                 - if 0, we know it is a vlen-determined number;
> >>                   i.e. vlen * meta_size
> >>                 - if > 0, simply use the overall struct size;
> >>
> >> Based upon that information, BTF parsing can proceed for such
> >> unknown kinds, since sufficient information was provided
> >> at encoding time to skip over them.
> >>
> >> Note that this assumes that the above kind-related data
> >> structures are represented in BTF _prior_ to any kinds that
> >> are new to the parser.  It also assumes the basic kinds
> >> required to represent kinds + metadata; base types, structs,
> >> arrays, etc.
> >>
> >> Signed-off-by: Alan Maguire <alan.maguire@xxxxxxxxxx>
> >> ---
> >>  tools/lib/bpf/btf.c      | 281 +++++++++++++++++++++++++++++++++++++++++++++++
> >>  tools/lib/bpf/btf.h      |  10 ++
> >>  tools/lib/bpf/libbpf.map |   1 +
> >>  3 files changed, 292 insertions(+)
> >>
> >> diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
> >> index 71e165b..e3cea44 100644
> >> --- a/tools/lib/bpf/btf.c
> >> +++ b/tools/lib/bpf/btf.c
> >> @@ -28,6 +28,16 @@
> >>
> >>  static struct btf_type btf_void;
> >>
> >> +/* info used to encode/decode an unrecognized kind */
> >> +struct btf_kind_desc {
> >> +       int kind;
> >> +       const char *struct_name;        /* __BTF_KIND_ARRAY */
> >> +       const char *typedef_name;       /* __BTF_KIND_2 */
> >> +       const char *meta_name;          /* __BTF_KIND_META_ARRAY */
> >> +       int nr_meta;
> >> +       int meta_size;
> >> +};
> >> +
> >>  struct btf {
> >>         /* raw BTF data in native endianness */
> >>         void *raw_data;
> >> @@ -5011,3 +5021,274 @@ int btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void
> >>
> >>         return 0;
> >>  }
> >> +
> >> +/* Here we use BTF to encode the BTF kinds that are known at the time of
> >> + * BTF encoding; the use of basic BTF kinds (structs, arrays, base types)
> >> + * to describe each kind and any associated metadata allows BTF parsing
> >> + * to handle new kinds that the parser (in libbpf or the kernel) does
> >> + * not know about.  These kinds will not be used, but since we know
> >> + * their format they can be skipped over and the rest of the BTF can
> >> + * be parsed.  This means we can encode BTF without worrying about the
> >> + * kinds a BTF parser knows about, and means we can avoid using
> >> + * --skip_new_kind solutions.  This is valuable, as if kernel BTF encodes
> >> + * everything it can, something as simple as a libbpf package update
> >> + * then unlocks that encodeded information, whereas if we encode
> >> + * pessimistically and drop representations of new kinds, this is not
> >> + * possible.
> >> + *
> >> + * So, in short, by carrying a representation of all the kinds encoded,
> >> + * parsers can parse all of the encoded kinds, even if they cannot use
> >> + * them all.
> >> + *
> >> + * We use BTF itself to carry this representation because this approach
> >> + * does not require BTF parsing to understand a new BTF header format;
> >> + * BTF parsing simply sees some additional types it does not do anything
> >> + * with.  A BTF parser that knows about the encoding of kind information
> >> + * however can use this information in parsing.
> >> + *
> >> + * The process works by explicitly adding btf structs for each kind.
> >> + * Each struct consists of a struct __btf_type followed by an array of
> >> + * metadata structs representing the following metadata (for those kinds
> >> + * that have it).  For kinds where a single metadata structure is used,
> >> + * the metadata array has one element.  For kinds where the number
> >> + * of metadata elements varies as per the info.vlen field, a zero-element
> >> + * array is encoded.
> >> + *
> >> + * For a given kind, we add a struct __BTF_KIND_<kind>.  For example,
> >> + *
> >> + * struct __BTF_KIND_INT {
> >> + *     struct __btf_type type;
> >> + * };
> >> + *
> >> + * For a type with one metadata element, the representation looks like
> >> + * this:
> >> + *
> >> + * struct __BTF_KIND_META_ARRAY {
> >> + *     __u32 type;
> >> + *     __u32 index_type;
> >> + *     __u32  nelems;
> >> + * };
> >> + *
> >> + * struct __BTF_KIND_ARRAY {
> >> + *     struct __btf_type type;
> >> + *     struct __BTF_KIND_META_ARRAY meta[1];
> >> + * };
> >> + *
> >> + *
> >> + * For a type with an info.vlen-determined number of following metadata
> >> + * objects, a zero-length array is used:
> >> + *
> >> + * struct __BTF_KIND_STRUCT {
> >> + *     struct __btf_type type;
> >> + *     struct __BTF_KIND_META_STRUCT meta[0];
> >> + * };
> >> + *
> >> + * In order to link kind numeric kind values to the appropriate struct,
> >> + * a typedef is added; for example:
> >> + *
> >> + * typedef struct __BTF_KIND_INT __BTF_KIND_1;
> >> + *
> >> + * When BTF parsing encounters a kind that is not known, the
> >> + * typedef __BTF_KIND_<kind number> is looked up, and we find which
> >> + * struct type id it points to.  So
> >> + *
> >> + *     1 -> typedef __BTF_KIND_1 -> struct __BTF_KIND_INT
> >> + *
> >> + * This approach is preferred, since it ensures the structs representing
> >> + * BTF kinds have names which match their associated kind rather than
> >> + * an opaque number.
> >> + *
> >> + * From there, BTF parsing can look up that struct and determine
> >> + *     - its basic size;
> >> + *     - if it has metadata; and if so
> >> + *     - how many array instances are present;
> >> + *             - if 0, we know it is a vlen-determined number;
> >> + *             - if > 0, simply use the overall struct size;
> >> + *
> >> + * Based upon that information, BTF parsing can proceed for such
> >> + * unknown kinds, since sufficient information was provided
> >> + * at encoding time.
> >> + *
> >> + * Note that this assumes that the above kind-related data
> >> + * structures are represented in BTF _prior_ to any kinds that
> >> + * are new to the parser.  It also assumes the basic kinds
> >> + * required to represent kinds + metadata; base types, structs,
> >> + * arrays, etc.
> >> + */
> >
> > Goodness gracious! :)
> >
> > Aesthetics of all this aside (which hurts me deeply, but let's ignore
> > that for a moment), this whole requirement that these
> > self-describing-but-also-convention-driven types which are supposed to
> > help with parsing types information are themselves in types
> > information is quite unusual. Yes, by saying "we assume they come
> > before a first type with unknown kind" we kind of work around this,
> > but even the fact that you can use btf__type_by_id() and
> > btf__find_by_name_kind() before BTF is fully parsed is kind of by
> > accident. All-in-all this screams "a kludge" at me, sorry.
> >
> > I really don't like this approach, even if *technically* it would
> > work. But even if so, it would add quite a bunch of size to BTF just
> > to self-describe it.
> >
> > Let's go again (and in more detail) over my alternative proposal I
> > briefly described in another email thread.
> >
> > So, what I'm proposing is similar in spirit and solves all the same
> > goals you have (and actually some more, I'll point this out below).
> > The only downside is that we'll need to, again, teach kernel to
> > understand this BTF format extension to allow kernel to use it (so we
> > still will need an opt-in flag for pahole, unfortunately, but
> > hopefully just this one time). That's pretty much the only downside.
> > But it's more compact, simpler and more straightforward, more elegant
> > (IMO), and it is easy for libbpf to sanitize it for old kernels.
> >
> > Ok, so it's pretty much completely described by these changes:
> >
> > --- a/include/uapi/linux/btf.h
> > +++ b/include/uapi/linux/btf.h
> > @@ -8,6 +8,21 @@
> >  #define BTF_MAGIC      0xeB9F
> >  #define BTF_VERSION    1
> >
> > +struct btf_kind_meta {
> > +       /* extra flags, initially define just one:
> > +        * 0x01 - required or optional (is it safe to skip if unknown)
> > +        */
> > +       __u16 flags;
> > +       __u8 info_sz;
> > +       __u8 elem_sz;
> > +};
> > +
> > +struct btf_metadata {
> > +       __u8 kind_meta_cnt;
> > +       __u32 :0;
> > +       struct btf_kind_meta[];
> > +};
> > +
> >  struct btf_header {
> >         __u16   magic;
> >         __u8    version;
> > @@ -19,6 +34,8 @@ struct btf_header {
> >         __u32   type_len;       /* length of type section       */
> >         __u32   str_off;        /* offset of string section     */
> >         __u32   str_len;        /* length of string section     */
> > +       __u32   meta_off;
> > +       __u32   meta_len;
> >  };
> >
>
> Ok, if we're going this route though, let's try to think through any
> other info we need to add so the format changes are a one-time thing.
> We should add flags too. One current use-case would be the
> "is this BTF standalone, or does it require base BTF?" [1]. Either using
> an existing value in the header flags field, or using the space for a flags
> field in  struct btf_metadata would probably make sense.

Yes, it's a good idea. But instead of a flag, I wonder if we should
add some sort of "build ID" concept here, so that we can check
validity of base BTF as expected by split BTF?

>
> Do we have any other outstanding issues with BTF that would be eased
> by some sort of up-front declaration? If we can at least tackle those
> things at once, the pain will be somewhat less when updating the toolchain.

Base vs split BTF + some check whether base BTF is valid is the only
thing that currently comes to mind.

>
> >
> > So, we add meta_off/meta_len fields to btf_header, which, if non-zero,
> > will point to a piece of metadata (4-byte aligned) that's described by
> > struct btf_metadata.
> >
> > In btf_metadata, the first byte records the number of known BTF kinds,
> > we have three more bytes for extra flags or counters for
> > extensibility, they should be zeroed out right now.
> >
>
> Right; see above for one flags use-case.
>
> > After these 4 bytes we have kind_meta_cnt struct btf_kind_meta
> > entries, each 4-byte long. It's a 1-indexed array, where each entry
> > corresponds to sequentially numbered BTF kinds. First two bytes are
> > reserved for flags and stuff like that. Among those, I think the most
> > useful right now would be the "optional flag". If set, it would mean
> > that generally speaking it's safe to skip types of that kind without
> > losing integrity of the data. So e.g., we could have used that for
> > DECL_TAGS, or perhaps even for FUNCs, if we had this metadata back
> > then, as these kinds are, generally speaking, not referenced from
> > other types (not 100% for FUNCs, as we can have FUNC externs, but
> > those came later). Anyways, for kernel needs we can say that optional
> > kinds don't cause failure to validate BTF.
> >
>
> This would definitely be useful; but are you saying here that
> a struct with a reference to an unknown kind should fail BTF
> validation (something like a struct with an enum64 member parsed by a
> libbpf prior to enum64 support)? Not sure there's any alternative
> for a case like that...

>From the kernel validation point -- yes, probably. From generic
tooling and libbpf-side -- perhaps not. I think kernel will always
have to be pretty strict due to security reasons.


>
> > *But for security reasons we should make the kernel zero-out
> > corresponding parts of type information, just to prevent injection of
> > well-known data by malicious user*.
> >
> > Next, to the meat of the proposal. info_sz is size in bytes of an
> > additional singular information (e.g., btf_array for ARRAY kind,
> > 4-byte info for INT kind, etc) that goes after common 12-byte struct
> > btf_type. It can be zero, of course. elem_sz is a size in bytes of
> > each nested element (field info for STRUCT, arg info for FUNC_ARG,
> > etc). Number of elements is defined by btf_vlen(t), which works for
> > any kind, regardless if it's known or not. If elem_sz is zero, KIND
> > can't have nested elements (and thus if vlen is non-zero, that's a
> > corruption).
> >
> > That's it. We don't allow mixing differently-sized nested elements
> > within a single kind, but we don't have that today and we don't have
> > any meaningful ways to express this. And I don't think we'd want to do
> > this anyways (there are way to work around that if absolutely
> > necessary, as well).
> >
> > From libbpf's point of view, this metadata section is easy to
> > sanitize, as kernel allows btf_headers of bigger size than is known to
> > it, provided they are zeroed out. So libbpf will just zero out
> > meta_off/meta_len fields, and contents of the metadata section.
> >
> > As for the size, it adds just 8 + 4 + 19 * 4 = 88 bytes to the overall
> > BTF size. It's nothing. I didn't count the total size for your
> > approach, but at the very least it would be 19 * 2 * sizeof(struct
> > btf_type) (=12) = 456, but that's super conservative.
> >
> > Note also that each btf_type can always have a name (described by
> > btf_type->name_off), so generic BTF tools can easily output what is
> > the name of the skipped entity, regardless of its actual kind. Tools
> > can also point out how many nested elements it is supposed to have.
> > Both are quite nice features, IMO.
> >
> > Anyways, that's what I had in mind. I think we should bite a bullet
> > and do it, so that future extensions can make use of this
> > self-describing metadata.
> >
> > Thoughts?
> >
>
> It'll work, a few specific questions we should probably resolve up front:
>
> - We can deduce the presence of the metadata info from the header length, so we
>   don't need a BTF version bump, right?

yep

>
> - from the encoding perspective, you mentioned having metadata opt-in;
>   so I presume we'd have a btf__add_metadata() API (it is zero by default so
>   accepted by the kernel I think) if --encode_metadata is set? Perhaps eventually
>   we could move to opt-out.

I'd say that btf__new() should by default produce metadata, unless
opted out through opts. But pahole should default for opt-out to not
regress on old kernels built with new pahole.

>
> - there are some cases where what is valid has evolved over time. For example,
>   kind flags have appeared for some kinds; should we have a flag for "supports kind
>   flag"? (set for struct/union/enum/fwd/eum64)?
>

"supports kind flag" seems way too specific, tbh. Seems wrong to have
such a flag.


> I can probably respin what I have, unless you want to take it on?

Let's discuss base vs split BTF identification first.

>
> [1] https://lore.kernel.org/bpf/CAEf4BzYXRT9pFmC1RqnNBmvQWGQkd0zs9rbH9z9Ug8FWOArb_Q@xxxxxxxxxxxxxx/
>
> >
> >> +
> >> +/* info used to encode a kind metadata field */
> >> +struct btf_meta_field {
> >> +       const char *type;
> >> +       const char *name;
> >> +       int size;
> >> +       int type_id;
> >> +};
> >> +
> >> +#define BTF_MAX_META_FIELDS             10
> >> +
> >> +#define BTF_META_FIELD(__type, __name)                                 \
> >> +       { .type = #__type, .name = #__name, .size = sizeof(__type) }
> >> +
> >> +#define BTF_KIND_STR(__kind)   #__kind
> >> +
> >> +struct btf_kind_encoding {
> >> +       struct btf_kind_desc kind;
> >> +       struct btf_meta_field meta[BTF_MAX_META_FIELDS];
> >> +};
> >> +
> >> +#define BTF_KIND(__name, __nr_meta, __meta_size, ...)                  \
> >> +       { .kind = {                                                     \
> >> +         .kind = BTF_KIND_##__name,                                    \
> >> +         .struct_name = BTF_KIND_PFX#__name,                           \
> >> +         .meta_name = BTF_KIND_META_PFX #__name,                       \
> >> +         .nr_meta = __nr_meta,                                         \
> >> +         .meta_size = __meta_size,                                     \
> >> +       }, .meta = { __VA_ARGS__ } }
> >> +
> >> +struct btf_kind_encoding kinds[] = {
> >> +       BTF_KIND(UNKN,          0,      0),
> >> +
> >> +       BTF_KIND(INT,           0,      0),
> >> +
> >> +       BTF_KIND(PTR,           0,      0),
> >> +
> >> +       BTF_KIND(ARRAY,         1,      sizeof(struct btf_array),
> >> +                                       BTF_META_FIELD(__u32, type),
> >> +                                       BTF_META_FIELD(__u32, index_type),
> >> +                                       BTF_META_FIELD(__u32, nelems)),
> >> +
> >> +       BTF_KIND(STRUCT,        0,      sizeof(struct btf_member),
> >> +                                       BTF_META_FIELD(__u32, name_off),
> >> +                                       BTF_META_FIELD(__u32, type),
> >> +                                       BTF_META_FIELD(__u32, offset)),
> >> +
> >> +       BTF_KIND(UNION,         0,      sizeof(struct btf_member),
> >> +                                       BTF_META_FIELD(__u32, name_off),
> >> +                                       BTF_META_FIELD(__u32, type),
> >> +                                       BTF_META_FIELD(__u32, offset)),
> >> +
> >> +       BTF_KIND(ENUM,          0,      sizeof(struct btf_enum),
> >> +                                       BTF_META_FIELD(__u32, name_off),
> >> +                                       BTF_META_FIELD(__s32, val)),
> >> +
> >> +       BTF_KIND(FWD,           0,      0),
> >> +
> >> +       BTF_KIND(TYPEDEF,       0,      0),
> >> +
> >> +       BTF_KIND(VOLATILE,      0,      0),
> >> +
> >> +       BTF_KIND(CONST,         0,      0),
> >> +
> >> +       BTF_KIND(RESTRICT,      0,      0),
> >> +
> >> +       BTF_KIND(FUNC,          0,      0),
> >> +
> >> +       BTF_KIND(FUNC_PROTO,    0,      sizeof(struct btf_param),
> >> +                                       BTF_META_FIELD(__u32, name_off),
> >> +                                       BTF_META_FIELD(__u32, type)),
> >> +
> >> +       BTF_KIND(VAR,           1,      sizeof(struct btf_var),
> >> +                                       BTF_META_FIELD(__u32, linkage)),
> >> +
> >> +       BTF_KIND(DATASEC,       0,      sizeof(struct btf_var_secinfo),
> >> +                                       BTF_META_FIELD(__u32, type),
> >> +                                       BTF_META_FIELD(__u32, offset),
> >> +                                       BTF_META_FIELD(__u32, size)),
> >> +
> >> +
> >> +       BTF_KIND(FLOAT,         0,      0),
> >> +
> >> +       BTF_KIND(DECL_TAG,      1,      sizeof(struct btf_decl_tag),
> >> +                                       BTF_META_FIELD(__s32, component_idx)),
> >> +
> >> +       BTF_KIND(TYPE_TAG,      0,      0),
> >> +
> >> +       BTF_KIND(ENUM64,        0,      sizeof(struct btf_enum64),
> >> +                                       BTF_META_FIELD(__u32, name_off),
> >> +                                       BTF_META_FIELD(__u32, val_lo32),
> >> +                                       BTF_META_FIELD(__u32, val_hi32)),
> >> +};
> >> +
> >> +/* Try to add representations of the kinds supported to BTF provided.  This will allow parsers
> >> + * to decode kinds they do not support and skip over them.
> >> + */
> >> +int btf__add_kinds(struct btf *btf)
> >> +{
> >> +       int btf_type_id, __u32_id, __s32_id, struct_type_id;
> >> +       char name[64];
> >> +       int i;
> >> +
> >> +       /* should have base types; if not bootstrap them. */
> >> +       __u32_id = btf__find_by_name(btf, "__u32");
> >> +       if (__u32_id < 0) {
> >> +               __s32 unsigned_int_id = btf__find_by_name(btf, "unsigned int");
> >> +
> >> +               if (unsigned_int_id < 0)
> >> +                       unsigned_int_id = btf__add_int(btf, "unsigned int", 4, 0);
> >> +               __u32_id = btf__add_typedef(btf, "__u32", unsigned_int_id);
> >> +       }
> >> +       __s32_id = btf__find_by_name(btf, "__s32");
> >> +       if (__s32_id < 0) {
> >> +               __s32 int_id = btf__find_by_name_kind(btf, "int", BTF_KIND_INT);
> >> +
> >> +               if (int_id < 0)
> >> +                       int_id = btf__add_int(btf, "int", 4, BTF_INT_SIGNED);
> >> +               __s32_id = btf__add_typedef(btf, "__s32", int_id);
> >> +       }
> >> +
> >> +       /* add "struct __btf_type" if not already present. */
> >> +       btf_type_id = btf__find_by_name(btf, "__btf_type");
> >> +       if (btf_type_id < 0) {
> >> +               __s32 union_id = btf__add_union(btf, NULL, sizeof(__u32));
> >> +
> >> +               btf__add_field(btf, "size", __u32_id, 0, 0);
> >> +               btf__add_field(btf, "type", __u32_id, 0, 0);
> >> +
> >> +               btf_type_id = btf__add_struct(btf, "__btf_type", sizeof(struct btf_type));
> >> +               btf__add_field(btf, "name_off", __u32_id, 0, 0);
> >> +               btf__add_field(btf, "info", __u32_id, sizeof(__u32) * 8, 0);
> >> +               btf__add_field(btf, NULL, union_id, sizeof(__u32) * 16, 0);
> >> +       }
> >> +
> >> +       for (i = 0; i < ARRAY_SIZE(kinds); i++) {
> >> +               struct btf_kind_encoding *kind = &kinds[i];
> >> +               int meta_id, array_id = 0;
> >> +
> >> +               if (btf__find_by_name(btf, kind->kind.struct_name) > 0)
> >> +                       continue;
> >> +
> >> +               if (kind->kind.meta_size != 0) {
> >> +                       struct btf_meta_field *field;
> >> +                       __u32 bit_offset = 0;
> >> +                       int j;
> >> +
> >> +                       meta_id = btf__add_struct(btf, kind->kind.meta_name, kind->kind.meta_size);
> >> +
> >> +                       for (j = 0; bit_offset < kind->kind.meta_size * 8; j++) {
> >> +                               field = &kind->meta[j];
> >> +
> >> +                               field->type_id = btf__find_by_name(btf, field->type);
> >> +                               if (field->type_id < 0) {
> >> +                                       pr_debug("cannot find type '%s' for kind '%s' field '%s'\n",
> >> +                                                kind->meta[j].type, kind->kind.struct_name,
> >> +                                                kind->meta[j].name);
> >> +                               } else {
> >> +                                       btf__add_field(btf, field->name, field->type_id, bit_offset, 0);
> >> +                               }
> >> +                               bit_offset += field->size * 8;
> >> +                       }
> >> +                       array_id = btf__add_array(btf, __u32_id, meta_id,
> >> +                                                 kind->kind.nr_meta);
> >> +
> >> +               }
> >> +               struct_type_id = btf__add_struct(btf, kind->kind.struct_name,
> >> +                                                sizeof(struct btf_type) +
> >> +                                                (kind->kind.nr_meta * kind->kind.meta_size));
> >> +               btf__add_field(btf, "type", btf_type_id, 0, 0);
> >> +               if (kind->kind.meta_size != 0)
> >> +                       btf__add_field(btf, "meta", array_id, sizeof(struct btf_type) * 8, 0);
> >> +               snprintf(name, sizeof(name), BTF_KIND_PFX "%u", i);
> >> +               btf__add_typedef(btf, name, struct_type_id);
> >> +       }
> >> +       return 0;
> >> +}
> >> diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h
> >> index 8e6880d..a054082 100644
> >> --- a/tools/lib/bpf/btf.h
> >> +++ b/tools/lib/bpf/btf.h
> >> @@ -219,6 +219,16 @@ LIBBPF_API int btf__add_datasec_var_info(struct btf *btf, int var_type_id,
> >>  LIBBPF_API int btf__add_decl_tag(struct btf *btf, const char *value, int ref_type_id,
> >>                             int component_idx);
> >>
> >> +/**
> >> + * @brief **btf__add_kinds()** adds BTF representations of the kind encoding for
> >> + * all of the kinds known to libbpf.  This ensures that when BTF is encoded, it
> >> + * will include enough information for parsers to decode (and skip over) kinds
> >> + * that the parser does not know about yet.  This ensures that an older BTF
> >> + * parser can read newer BTF, and avoids the need for the BTF encoder to limit
> >> + * which kinds it emits to make decoding easier.
> >> + */
> >> +LIBBPF_API int btf__add_kinds(struct btf *btf);
> >> +
> >>  struct btf_dedup_opts {
> >>         size_t sz;
> >>         /* optional .BTF.ext info to dedup along the main BTF info */
> >> diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> >> index 71bf569..6121ff1 100644
> >> --- a/tools/lib/bpf/libbpf.map
> >> +++ b/tools/lib/bpf/libbpf.map
> >> @@ -375,6 +375,7 @@ LIBBPF_1.1.0 {
> >>                 bpf_link_get_fd_by_id_opts;
> >>                 bpf_map_get_fd_by_id_opts;
> >>                 bpf_prog_get_fd_by_id_opts;
> >> +               btf__add_kinds;
> >>                 user_ring_buffer__discard;
> >>                 user_ring_buffer__free;
> >>                 user_ring_buffer__new;
> >> --
> >> 1.8.3.1
> >>



[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux