Re: [PATCH v2 bpf-next 04/13] libbpf: add btf__parse_opts() API for flexible BTF parsing

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

 



On 30/04/2024 00:40, Andrii Nakryiko wrote:
> On Wed, Apr 24, 2024 at 8:48 AM Alan Maguire <alan.maguire@xxxxxxxxxx> wrote:
>>
>> Options cover existing parsing scenarios (ELF, raw, retrieving
>> .BTF.ext) and also allow specification of the ELF section name
>> containing BTF.  This will allow consumers to retrieve BTF from
>> .BTF.base sections (BTF_BASE_ELF_SEC) also.
>>
>> Signed-off-by: Alan Maguire <alan.maguire@xxxxxxxxxx>
>> ---
>>  tools/lib/bpf/btf.c      | 50 ++++++++++++++++++++++++++++------------
>>  tools/lib/bpf/btf.h      | 32 +++++++++++++++++++++++++
>>  tools/lib/bpf/libbpf.map |  1 +
>>  3 files changed, 68 insertions(+), 15 deletions(-)
>>
>> diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
>> index 419cc4fa2e86..9036c1dc45d0 100644
>> --- a/tools/lib/bpf/btf.c
>> +++ b/tools/lib/bpf/btf.c
>> @@ -1084,7 +1084,7 @@ struct btf *btf__new_split(const void *data, __u32 size, struct btf *base_btf)
>>         return libbpf_ptr(btf_new(data, size, base_btf));
>>  }
>>
>> -static struct btf *btf_parse_elf(const char *path, struct btf *base_btf,
>> +static struct btf *btf_parse_elf(const char *path, const char *btf_sec, struct btf *base_btf,
>>                                  struct btf_ext **btf_ext)
>>  {
>>         Elf_Data *btf_data = NULL, *btf_ext_data = NULL;
>> @@ -1146,7 +1146,7 @@ static struct btf *btf_parse_elf(const char *path, struct btf *base_btf,
>>                                 idx, path);
>>                         goto done;
>>                 }
>> -               if (strcmp(name, BTF_ELF_SEC) == 0) {
>> +               if (strcmp(name, btf_sec) == 0) {
>>                         btf_data = elf_getdata(scn, 0);
>>                         if (!btf_data) {
>>                                 pr_warn("failed to get section(%d, %s) data from %s\n",
>> @@ -1166,7 +1166,7 @@ static struct btf *btf_parse_elf(const char *path, struct btf *base_btf,
>>         }
>>
>>         if (!btf_data) {
>> -               pr_warn("failed to find '%s' ELF section in %s\n", BTF_ELF_SEC, path);
>> +               pr_warn("failed to find '%s' ELF section in %s\n", btf_sec, path);
>>                 err = -ENODATA;
>>                 goto done;
>>         }
>> @@ -1212,12 +1212,12 @@ static struct btf *btf_parse_elf(const char *path, struct btf *base_btf,
>>
>>  struct btf *btf__parse_elf(const char *path, struct btf_ext **btf_ext)
>>  {
>> -       return libbpf_ptr(btf_parse_elf(path, NULL, btf_ext));
>> +       return libbpf_ptr(btf_parse_elf(path, BTF_ELF_SEC, NULL, btf_ext));
>>  }
>>
>>  struct btf *btf__parse_elf_split(const char *path, struct btf *base_btf)
>>  {
>> -       return libbpf_ptr(btf_parse_elf(path, base_btf, NULL));
>> +       return libbpf_ptr(btf_parse_elf(path, BTF_ELF_SEC, base_btf, NULL));
>>  }
>>
>>  static struct btf *btf_parse_raw(const char *path, struct btf *base_btf)
>> @@ -1293,7 +1293,8 @@ struct btf *btf__parse_raw_split(const char *path, struct btf *base_btf)
>>         return libbpf_ptr(btf_parse_raw(path, base_btf));
>>  }
>>
>> -static struct btf *btf_parse(const char *path, struct btf *base_btf, struct btf_ext **btf_ext)
>> +static struct btf *btf_parse(const char *path, const char *btf_elf_sec, struct btf *base_btf,
>> +                            struct btf_ext **btf_ext)
>>  {
>>         struct btf *btf;
>>         int err;
>> @@ -1301,23 +1302,42 @@ static struct btf *btf_parse(const char *path, struct btf *base_btf, struct btf_
>>         if (btf_ext)
>>                 *btf_ext = NULL;
>>
>> -       btf = btf_parse_raw(path, base_btf);
>> -       err = libbpf_get_error(btf);
>> -       if (!err)
>> -               return btf;
>> -       if (err != -EPROTO)
>> -               return ERR_PTR(err);
>> -       return btf_parse_elf(path, base_btf, btf_ext);
>> +       if (!btf_elf_sec) {
>> +               btf = btf_parse_raw(path, base_btf);
>> +               err = libbpf_get_error(btf);
>> +               if (!err)
>> +                       return btf;
>> +               if (err != -EPROTO)
>> +                       return ERR_PTR(err);
>> +       }
>> +       if (!btf_elf_sec)
>> +               btf_elf_sec = BTF_ELF_SEC;
>> +
>> +       return btf_parse_elf(path, btf_elf_sec, base_btf, btf_ext);
> 
> nit: btf_elf_sec ?: BTF_ELF_SEC
>

sure, will fix.

> 
>> +}
>> +
>> +struct btf *btf__parse_opts(const char *path, struct btf_parse_opts *opts)
>> +{
>> +       struct btf *base_btf;
>> +       const char *btf_sec;
>> +       struct btf_ext **btf_ext;
>> +
>> +       if (!OPTS_VALID(opts, btf_parse_opts))
>> +               return libbpf_err_ptr(-EINVAL);
>> +       base_btf = OPTS_GET(opts, base_btf, NULL);
>> +       btf_sec = OPTS_GET(opts, btf_sec, NULL);
>> +       btf_ext = OPTS_GET(opts, btf_ext, NULL);
>> +       return libbpf_ptr(btf_parse(path, btf_sec, base_btf, btf_ext));
>>  }
>>
>>  struct btf *btf__parse(const char *path, struct btf_ext **btf_ext)
>>  {
>> -       return libbpf_ptr(btf_parse(path, NULL, btf_ext));
>> +       return libbpf_ptr(btf_parse(path, NULL, NULL, btf_ext));
>>  }
>>
>>  struct btf *btf__parse_split(const char *path, struct btf *base_btf)
>>  {
>> -       return libbpf_ptr(btf_parse(path, base_btf, NULL));
>> +       return libbpf_ptr(btf_parse(path, NULL, base_btf, NULL));
>>  }
>>
>>  static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endian);
>> diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h
>> index 025ed28b7fe8..94dfdfdef617 100644
>> --- a/tools/lib/bpf/btf.h
>> +++ b/tools/lib/bpf/btf.h
>> @@ -18,6 +18,7 @@ extern "C" {
>>
>>  #define BTF_ELF_SEC ".BTF"
>>  #define BTF_EXT_ELF_SEC ".BTF.ext"
>> +#define BTF_BASE_ELF_SEC ".BTF.base"
> 
> Does libbpf code itself use this? If not, let's get rid of it.
> 

We could, but I wonder would there be value to keeping it around as
multiple consumers need to agree on this name (pahole, resolve_btfids,
bpftool)?

>>  #define MAPS_ELF_SEC ".maps"
>>
>>  struct btf;
>> @@ -134,6 +135,37 @@ LIBBPF_API struct btf *btf__parse_elf_split(const char *path, struct btf *base_b
>>  LIBBPF_API struct btf *btf__parse_raw(const char *path);
>>  LIBBPF_API struct btf *btf__parse_raw_split(const char *path, struct btf *base_btf);
>>
>> +struct btf_parse_opts {
>> +       size_t sz;
>> +       /* use base BTF to parse split BTF */
>> +       struct btf *base_btf;
>> +       /* retrieve optional .BTF.ext info */
>> +       struct btf_ext **btf_ext;
>> +       /* BTF section name */
> 
> let's mention that if not set, libbpf will default to trying to parse
> data as raw BTF, and then will fallback to .BTF in ELF. If it is set
> to non-NULL, we'll assume ELF and use that section to fetch BTF data.
>

sure, will do.

>> +       const char *btf_sec;
>> +       size_t:0;
> 
> nit: size_t :0; (consistency)
> 
>> +};
>> +
>> +#define btf_parse_opts__last_field btf_sec
>> +
>> +/* @brief **btf__parse_opts()** parses BTF information from either a
>> + * raw BTF file (*btf_sec* is NULL) or from the specified BTF section,
>> + * also retrieving  .BTF.ext info if *btf_ext* is non-NULL.  If
>> + * *base_btf* is specified, use it to parse split BTF from the
>> + * specified location.
>> + *
>> + * @return new BTF object instance which has to be eventually freed with
>> + * **btf__free()**
>> + *
>> + * On error, error-code-encoded-as-pointer is returned, not a NULL. To extract
> 
> this is false, we don't encode error as pointer anymore. starting from
> v1.0 it's always NULL + errno.
> 

ah good catch, I must have cut-and-pasted this..

Thanks again for all the review help!

Alan

>> + * error code from such a pointer `libbpf_get_error()` should be used. If
>> + * `libbpf_set_strict_mode(LIBBPF_STRICT_CLEAN_PTRS)` is enabled, NULL is
>> + * returned on error instead. In both cases thread-local `errno` variable is
>> + * always set to error code as well.
>> + */
>> +
>> +LIBBPF_API struct btf *btf__parse_opts(const char *path, struct btf_parse_opts *opts);
>> +
>>  LIBBPF_API struct btf *btf__load_vmlinux_btf(void);
>>  LIBBPF_API struct btf *btf__load_module_btf(const char *module_name, struct btf *vmlinux_btf);
>>
>> diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
>> index c4d9bd7d3220..a9151e31dfa9 100644
>> --- a/tools/lib/bpf/libbpf.map
>> +++ b/tools/lib/bpf/libbpf.map
>> @@ -421,6 +421,7 @@ LIBBPF_1.5.0 {
>>         global:
>>                 bpf_program__attach_sockmap;
>>                 btf__distill_base;
>> +               btf__parse_opts;
>>                 ring__consume_n;
>>                 ring_buffer__consume_n;
>>  } LIBBPF_1.4.0;
>> --
>> 2.31.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