diff mbox series

[dwarves,v1] pahole: generate "bpf_fastcall" decl tags for eligible kfuncs

Message ID 20240916091921.2929615-1-eddyz87@gmail.com (mailing list archive)
State Not Applicable
Headers show
Series [dwarves,v1] pahole: generate "bpf_fastcall" decl tags for eligible kfuncs | expand

Checks

Context Check Description
netdev/tree_selection success Not a local patch

Commit Message

Eduard Zingerman Sept. 16, 2024, 9:19 a.m. UTC
For kfuncs marked with KF_FASTCALL flag generate the following pair of
decl tags:

    $ bpftool btf dump file vmlinux
    ...
    [A] FUNC 'bpf_rdonly_cast' type_id=...
    ...
    [B] DECL_TAG 'bpf_kfunc' type_id=A component_idx=-1
    [C] DECL_TAG 'bpf_fastcall' type_id=A component_idx=-1

So that bpftool could find 'bpf_fastcall' decl tag and generate
appropriate C declarations for such kfuncs, e.g.:

    #ifndef __VMLINUX_H__
    #define __VMLINUX_H__
    ...
    #define __bpf_fastcall __attribute__((bpf_fastcall))
    ...
    __bpf_fastcall extern void *bpf_rdonly_cast(...) ...;

For additional information about 'bpf_fastcall' attribute,
see the following commit in the LLVM source tree:

64e464349bfc ("[BPF] introduce __attribute__((bpf_fastcall))")

And the following Linux kernel commit:

52839f31cece ("Merge branch 'no_caller_saved_registers-attribute-for-helper-calls'")

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
---
 btf_encoder.c | 59 +++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 43 insertions(+), 16 deletions(-)

Comments

Eduard Zingerman Sept. 16, 2024, 9:24 a.m. UTC | #1
On Mon, 2024-09-16 at 02:19 -0700, Eduard Zingerman wrote:
> For kfuncs marked with KF_FASTCALL flag generate the following pair of
> decl tags:
> 
>     $ bpftool btf dump file vmlinux
>     ...
>     [A] FUNC 'bpf_rdonly_cast' type_id=...
>     ...
>     [B] DECL_TAG 'bpf_kfunc' type_id=A component_idx=-1
>     [C] DECL_TAG 'bpf_fastcall' type_id=A component_idx=-1

Note, corresponding kernel changes are submitted here:
https://lore.kernel.org/bpf/20240916091712.2929279-1-eddyz87@gmail.com/

[...]
Alan Maguire Sept. 16, 2024, 10:16 a.m. UTC | #2
On 16/09/2024 10:19, Eduard Zingerman wrote:
> For kfuncs marked with KF_FASTCALL flag generate the following pair of
> decl tags:
> 
>     $ bpftool btf dump file vmlinux
>     ...
>     [A] FUNC 'bpf_rdonly_cast' type_id=...
>     ...
>     [B] DECL_TAG 'bpf_kfunc' type_id=A component_idx=-1
>     [C] DECL_TAG 'bpf_fastcall' type_id=A component_idx=-1
> 
> So that bpftool could find 'bpf_fastcall' decl tag and generate
> appropriate C declarations for such kfuncs, e.g.:
> 
>     #ifndef __VMLINUX_H__
>     #define __VMLINUX_H__
>     ...
>     #define __bpf_fastcall __attribute__((bpf_fastcall))
>     ...
>     __bpf_fastcall extern void *bpf_rdonly_cast(...) ...;
> 
> For additional information about 'bpf_fastcall' attribute,
> see the following commit in the LLVM source tree:
> 
> 64e464349bfc ("[BPF] introduce __attribute__((bpf_fastcall))")
> 
> And the following Linux kernel commit:
> 
> 52839f31cece ("Merge branch 'no_caller_saved_registers-attribute-for-helper-calls'")
> 
> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>

hi Eduard,

you've added support for multiple declaration tags as part of this, but
I wonder if we could go slightly further to simplify any additional
future KF_* flags -> decl tag needs?

Specifically if we had an array of <set8 flags, tag name> mappings such
that we can add support for new declaration tags by simply adding a new
flag and declaration tag string. When checking flags value in
btf_encoder__tag_kfunc(), we'd just walk the array entries, and for each
matching flag add the associated decl tag. Would that work?

> ---
>  btf_encoder.c | 59 +++++++++++++++++++++++++++++++++++++--------------
>  1 file changed, 43 insertions(+), 16 deletions(-)
> 
> diff --git a/btf_encoder.c b/btf_encoder.c
> index 8a2d92e..ae059e0 100644
> --- a/btf_encoder.c
> +++ b/btf_encoder.c
> @@ -39,15 +39,19 @@
>  #define BTF_ID_SET8_PFX		"__BTF_ID__set8__"
>  #define BTF_SET8_KFUNCS		(1 << 0)
>  #define BTF_KFUNC_TYPE_TAG	"bpf_kfunc"
> +#define BTF_FASTCALL_TAG	"bpf_fastcall"
> +#define KF_FASTCALL		(1 << 12)
> +

probably need an #ifndef KF_FASTCALL/#endif here once this makes it into
uapi.


> +struct btf_id_and_flag {
> +        uint32_t id;
> +        uint32_t flags;
> +};
>  
>  /* Adapted from include/linux/btf_ids.h */
>  struct btf_id_set8 {
>          uint32_t cnt;
>          uint32_t flags;
> -        struct {
> -                uint32_t id;
> -                uint32_t flags;
> -        } pairs[];
> +	struct btf_id_and_flag pairs[];
>  };
>  
>  /* state used to do later encoding of saved functions */
> @@ -1517,21 +1521,34 @@ out:
>  	return err;
>  }
>  
> -static int btf_encoder__tag_kfunc(struct btf_encoder *encoder, struct gobuffer *funcs, const char *kfunc)
> +static int add_kfunc_decl_tag(struct btf *btf, const char *tag, __u32 id, const char *kfunc)
> +{
> +	int err;
> +
> +	err = btf__add_decl_tag(btf, tag, id, -1);
> +	if (err < 0) {
> +		fprintf(stderr, "%s: failed to insert kfunc decl tag for '%s': %d\n",
> +			__func__, kfunc, err);
> +		return err;
> +	}
> +	return 0;
> +}
> +
> +static int btf_encoder__tag_kfunc(struct btf_encoder *encoder, struct gobuffer *funcs, const char *kfunc, __u32 flags)
>  {
>  	struct btf_func key = { .name = kfunc };
>  	struct btf *btf = encoder->btf;
>  	struct btf_func *target;
>  	const void *base;
>  	unsigned int cnt;
> -	int err = -1;
> +	int err;
>  
>  	base = gobuffer__entries(funcs);
>  	cnt = gobuffer__nr_entries(funcs);
>  	target = bsearch(&key, base, cnt, sizeof(key), btf_func_cmp);
>  	if (!target) {
>  		fprintf(stderr, "%s: failed to find kfunc '%s' in BTF\n", __func__, kfunc);
> -		goto out;
> +		return -1;
>  	}
>  
>  	/* Note we are unconditionally adding the btf_decl_tag even
> @@ -1539,16 +1556,16 @@ static int btf_encoder__tag_kfunc(struct btf_encoder *encoder, struct gobuffer *
>  	 * We are ok to do this b/c we will later btf__dedup() to remove
>  	 * any duplicates.
>  	 */
> -	err = btf__add_decl_tag(btf, BTF_KFUNC_TYPE_TAG, target->type_id, -1);
> -	if (err < 0) {
> -		fprintf(stderr, "%s: failed to insert kfunc decl tag for '%s': %d\n",
> -			__func__, kfunc, err);
> -		goto out;
> +	err = add_kfunc_decl_tag(btf, BTF_KFUNC_TYPE_TAG, target->type_id, kfunc);
> +	if (err < 0)
> +		return err;
> +	if (flags & KF_FASTCALL) {
> +		err = add_kfunc_decl_tag(btf, BTF_FASTCALL_TAG, target->type_id, kfunc);
> +		if (err < 0)
> +			return err;
>  	}
>  
> -	err = 0;
> -out:
> -	return err;
> +	return 0;
>  }
>  
>  static int btf_encoder__tag_kfuncs(struct btf_encoder *encoder)
> @@ -1675,8 +1692,10 @@ static int btf_encoder__tag_kfuncs(struct btf_encoder *encoder)
>  	/* Now inject BTF with kfunc decl tag for detected kfuncs */
>  	for (i = 0; i < nr_syms; i++) {
>  		const struct btf_kfunc_set_range *ranges;
> +		const struct btf_id_and_flag *pair;
>  		unsigned int ranges_cnt;
>  		char *func, *name;
> +		ptrdiff_t off;
>  		GElf_Sym sym;
>  		bool found;
>  		int err;
> @@ -1704,6 +1723,14 @@ static int btf_encoder__tag_kfuncs(struct btf_encoder *encoder)
>  
>  			if (ranges[j].start <= addr && addr < ranges[j].end) {
>  				found = true;
> +				off = addr - idlist_addr;
> +				if (off < 0 || off + sizeof(*pair) > idlist->d_size) {
> +					fprintf(stderr, "%s: kfunc '%s' offset outside section '%s'\n",
> +						__func__, func, BTF_IDS_SECTION);
> +					free(func);
> +					goto out;
> +				}
> +				pair = idlist->d_buf + off;
>  				break;
>  			}
>  		}
> @@ -1712,7 +1739,7 @@ static int btf_encoder__tag_kfuncs(struct btf_encoder *encoder)
>  			continue;
>  		}
>  
> -		err = btf_encoder__tag_kfunc(encoder, &btf_funcs, func);
> +		err = btf_encoder__tag_kfunc(encoder, &btf_funcs, func, pair->flags);
>  		if (err) {
>  			fprintf(stderr, "%s: failed to tag kfunc '%s'\n", __func__, func);
>  			free(func);
Eduard Zingerman Sept. 17, 2024, 4:40 a.m. UTC | #3
On Mon, 2024-09-16 at 11:16 +0100, Alan Maguire wrote:

[...]

> hi Eduard,
> 
> you've added support for multiple declaration tags as part of this, but
> I wonder if we could go slightly further to simplify any additional
> future KF_* flags -> decl tag needs?
> 
> Specifically if we had an array of <set8 flags, tag name> mappings such
> that we can add support for new declaration tags by simply adding a new
> flag and declaration tag string. When checking flags value in
> btf_encoder__tag_kfunc(), we'd just walk the array entries, and for each
> matching flag add the associated decl tag. Would that work?

Hi Alan,

That would be something like below.
It works, but looks a bit over-complicated for my taste, wdyt?

--- 8< ----------------------------------------
iff --git a/btf_encoder.c b/btf_encoder.c
index ae059e0..b6178c3 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -39,7 +39,6 @@
 #define BTF_ID_SET8_PFX                "__BTF_ID__set8__"
 #define BTF_SET8_KFUNCS                (1 << 0)
 #define BTF_KFUNC_TYPE_TAG     "bpf_kfunc"
-#define BTF_FASTCALL_TAG       "bpf_fastcall"
 #define KF_FASTCALL            (1 << 12)
 
 struct btf_id_and_flag {
@@ -1534,6 +1533,15 @@ static int add_kfunc_decl_tag(struct btf *btf, const char *tag, __u32 id, const
        return 0;
 }
 
+enum kf_bit_nums {
+       KF_BIT_NUM_FASTCALL = 12,
+       KF_BIT_NUM_FASTCALL_NR
+};
+
+static const char *kfunc_tags[KF_BIT_NUM_FASTCALL_NR] = {
+       [KF_BIT_NUM_FASTCALL] = "bpf_fastcall"
+};
+
 static int btf_encoder__tag_kfunc(struct btf_encoder *encoder, struct gobuffer *funcs, const char *kfunc, __u32 flags)
 {
        struct btf_func key = { .name = kfunc };
@@ -1559,8 +1567,11 @@ static int btf_encoder__tag_kfunc(struct btf_encoder *encoder, struct gobuffer *
        err = add_kfunc_decl_tag(btf, BTF_KFUNC_TYPE_TAG, target->type_id, kfunc);
        if (err < 0)
                return err;
-       if (flags & KF_FASTCALL) {
-               err = add_kfunc_decl_tag(btf, BTF_FASTCALL_TAG, target->type_id, kfunc);
+
+       for (uint32_t i = 0; i < KF_BIT_NUM_FASTCALL_NR; i++) {
+                if (!(flags & (1u << i)) || !kfunc_tags[i])
+                       continue;
+               err = add_kfunc_decl_tag(btf, kfunc_tags[i], target->type_id, kfunc);
                if (err < 0)
                        return err;
        }
---------------------------------------- >8 ---

> 
> > ---
> >  btf_encoder.c | 59 +++++++++++++++++++++++++++++++++++++--------------
> >  1 file changed, 43 insertions(+), 16 deletions(-)
> > 
> > diff --git a/btf_encoder.c b/btf_encoder.c
> > index 8a2d92e..ae059e0 100644
> > --- a/btf_encoder.c
> > +++ b/btf_encoder.c
> > @@ -39,15 +39,19 @@
> >  #define BTF_ID_SET8_PFX		"__BTF_ID__set8__"
> >  #define BTF_SET8_KFUNCS		(1 << 0)
> >  #define BTF_KFUNC_TYPE_TAG	"bpf_kfunc"
> > +#define BTF_FASTCALL_TAG	"bpf_fastcall"
> > +#define KF_FASTCALL		(1 << 12)
> > +
> 
> probably need an #ifndef KF_FASTCALL/#endif here once this makes it into
> uapi.

kfunc flags are defined in include/linux/btf.h so these should not be
visible in the uapi/linux/btf.h, unless I'm confused.

> 
> 
> > +struct btf_id_and_flag {
> > +        uint32_t id;
> > +        uint32_t flags;
> > +};

[...]
Alan Maguire Sept. 17, 2024, 8:21 a.m. UTC | #4
On 17/09/2024 05:40, Eduard Zingerman wrote:
> On Mon, 2024-09-16 at 11:16 +0100, Alan Maguire wrote:
> 
> [...]
> 
>> hi Eduard,
>>
>> you've added support for multiple declaration tags as part of this, but
>> I wonder if we could go slightly further to simplify any additional
>> future KF_* flags -> decl tag needs?
>>
>> Specifically if we had an array of <set8 flags, tag name> mappings such
>> that we can add support for new declaration tags by simply adding a new
>> flag and declaration tag string. When checking flags value in
>> btf_encoder__tag_kfunc(), we'd just walk the array entries, and for each
>> matching flag add the associated decl tag. Would that work?
> 
> Hi Alan,
> 
> That would be something like below.
> It works, but looks a bit over-complicated for my taste, wdyt?

yeah, I guess I was thinking the kfunc flag would be checked along with
KF_FASTCALL, but the code already knows it's a kfunc, so no need.  We
can add something like this if/when other flags are added.

Sorry for the noise!

Reviewed-by: Alan Maguire <alan.maguire@oracle.com>
> 
> --- 8< ----------------------------------------
> iff --git a/btf_encoder.c b/btf_encoder.c
> index ae059e0..b6178c3 100644
> --- a/btf_encoder.c
> +++ b/btf_encoder.c
> @@ -39,7 +39,6 @@
>  #define BTF_ID_SET8_PFX                "__BTF_ID__set8__"
>  #define BTF_SET8_KFUNCS                (1 << 0)
>  #define BTF_KFUNC_TYPE_TAG     "bpf_kfunc"
> -#define BTF_FASTCALL_TAG       "bpf_fastcall"
>  #define KF_FASTCALL            (1 << 12)
>  
>  struct btf_id_and_flag {
> @@ -1534,6 +1533,15 @@ static int add_kfunc_decl_tag(struct btf *btf, const char *tag, __u32 id, const
>         return 0;
>  }
>  
> +enum kf_bit_nums {
> +       KF_BIT_NUM_FASTCALL = 12,
> +       KF_BIT_NUM_FASTCALL_NR
> +};
> +
> +static const char *kfunc_tags[KF_BIT_NUM_FASTCALL_NR] = {
> +       [KF_BIT_NUM_FASTCALL] = "bpf_fastcall"
> +};
> +
>  static int btf_encoder__tag_kfunc(struct btf_encoder *encoder, struct gobuffer *funcs, const char *kfunc, __u32 flags)
>  {
>         struct btf_func key = { .name = kfunc };
> @@ -1559,8 +1567,11 @@ static int btf_encoder__tag_kfunc(struct btf_encoder *encoder, struct gobuffer *
>         err = add_kfunc_decl_tag(btf, BTF_KFUNC_TYPE_TAG, target->type_id, kfunc);
>         if (err < 0)
>                 return err;
> -       if (flags & KF_FASTCALL) {
> -               err = add_kfunc_decl_tag(btf, BTF_FASTCALL_TAG, target->type_id, kfunc);
> +
> +       for (uint32_t i = 0; i < KF_BIT_NUM_FASTCALL_NR; i++) {
> +                if (!(flags & (1u << i)) || !kfunc_tags[i])
> +                       continue;
> +               err = add_kfunc_decl_tag(btf, kfunc_tags[i], target->type_id, kfunc);
>                 if (err < 0)
>                         return err;
>         }
> ---------------------------------------- >8 ---
> 
>>
>>> ---
>>>  btf_encoder.c | 59 +++++++++++++++++++++++++++++++++++++--------------
>>>  1 file changed, 43 insertions(+), 16 deletions(-)
>>>
>>> diff --git a/btf_encoder.c b/btf_encoder.c
>>> index 8a2d92e..ae059e0 100644
>>> --- a/btf_encoder.c
>>> +++ b/btf_encoder.c
>>> @@ -39,15 +39,19 @@
>>>  #define BTF_ID_SET8_PFX		"__BTF_ID__set8__"
>>>  #define BTF_SET8_KFUNCS		(1 << 0)
>>>  #define BTF_KFUNC_TYPE_TAG	"bpf_kfunc"
>>> +#define BTF_FASTCALL_TAG	"bpf_fastcall"
>>> +#define KF_FASTCALL		(1 << 12)
>>> +
>>
>> probably need an #ifndef KF_FASTCALL/#endif here once this makes it into
>> uapi.
> 
> kfunc flags are defined in include/linux/btf.h so these should not be
> visible in the uapi/linux/btf.h, unless I'm confused.
>

ah, ok sorry I thought it was UAPI, never mind.

>>
>>
>>> +struct btf_id_and_flag {
>>> +        uint32_t id;
>>> +        uint32_t flags;
>>> +};
> 
> [...]
>
Andrii Nakryiko Sept. 27, 2024, 9:52 p.m. UTC | #5
On Mon, Sep 16, 2024 at 2:19 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> For kfuncs marked with KF_FASTCALL flag generate the following pair of
> decl tags:
>
>     $ bpftool btf dump file vmlinux
>     ...
>     [A] FUNC 'bpf_rdonly_cast' type_id=...
>     ...
>     [B] DECL_TAG 'bpf_kfunc' type_id=A component_idx=-1
>     [C] DECL_TAG 'bpf_fastcall' type_id=A component_idx=-1
>
> So that bpftool could find 'bpf_fastcall' decl tag and generate
> appropriate C declarations for such kfuncs, e.g.:
>
>     #ifndef __VMLINUX_H__
>     #define __VMLINUX_H__
>     ...
>     #define __bpf_fastcall __attribute__((bpf_fastcall))
>     ...
>     __bpf_fastcall extern void *bpf_rdonly_cast(...) ...;
>
> For additional information about 'bpf_fastcall' attribute,
> see the following commit in the LLVM source tree:
>
> 64e464349bfc ("[BPF] introduce __attribute__((bpf_fastcall))")
>
> And the following Linux kernel commit:
>
> 52839f31cece ("Merge branch 'no_caller_saved_registers-attribute-for-helper-calls'")
>
> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> ---
>  btf_encoder.c | 59 +++++++++++++++++++++++++++++++++++++--------------
>  1 file changed, 43 insertions(+), 16 deletions(-)
>

LGTM,

Acked-by: Andrii Nakryiko <andrii@kernel.org>

Arnaldo, can you please take a look and if everything seems sane apply
it to pahole master, so it's easier to use it locally? Thanks!

[...]
Arnaldo Carvalho de Melo Sept. 30, 2024, 2:44 p.m. UTC | #6
On Fri, Sep 27, 2024 at 02:52:24PM -0700, Andrii Nakryiko wrote:
> On Mon, Sep 16, 2024 at 2:19 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
> >
> > For kfuncs marked with KF_FASTCALL flag generate the following pair of
> > decl tags:
> >
> >     $ bpftool btf dump file vmlinux
> >     ...
> >     [A] FUNC 'bpf_rdonly_cast' type_id=...
> >     ...
> >     [B] DECL_TAG 'bpf_kfunc' type_id=A component_idx=-1
> >     [C] DECL_TAG 'bpf_fastcall' type_id=A component_idx=-1
> >
> > So that bpftool could find 'bpf_fastcall' decl tag and generate
> > appropriate C declarations for such kfuncs, e.g.:
> >
> >     #ifndef __VMLINUX_H__
> >     #define __VMLINUX_H__
> >     ...
> >     #define __bpf_fastcall __attribute__((bpf_fastcall))
> >     ...
> >     __bpf_fastcall extern void *bpf_rdonly_cast(...) ...;
> >
> > For additional information about 'bpf_fastcall' attribute,
> > see the following commit in the LLVM source tree:
> >
> > 64e464349bfc ("[BPF] introduce __attribute__((bpf_fastcall))")
> >
> > And the following Linux kernel commit:
> >
> > 52839f31cece ("Merge branch 'no_caller_saved_registers-attribute-for-helper-calls'")
> >
> > Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> > ---
> >  btf_encoder.c | 59 +++++++++++++++++++++++++++++++++++++--------------
> >  1 file changed, 43 insertions(+), 16 deletions(-)
> >
> 
> LGTM,
> 
> Acked-by: Andrii Nakryiko <andrii@kernel.org>
> 
> Arnaldo, can you please take a look and if everything seems sane apply
> it to pahole master, so it's easier to use it locally? Thanks!

Minor clash with Alan's

Fixes: 5205d02d8e84a775 ("btf_encoder: record BTF-centric function state instead of DWARF-centric")

Fixed up, testing.

- Arnaldo
Arnaldo Carvalho de Melo Dec. 9, 2024, 7:30 p.m. UTC | #7
On Mon, Sep 16, 2024 at 02:19:21AM -0700, Eduard Zingerman wrote:
> For kfuncs marked with KF_FASTCALL flag generate the following pair of
> decl tags:
> 
>     $ bpftool btf dump file vmlinux
>     ...
>     [A] FUNC 'bpf_rdonly_cast' type_id=...
>     ...
>     [B] DECL_TAG 'bpf_kfunc' type_id=A component_idx=-1
>     [C] DECL_TAG 'bpf_fastcall' type_id=A component_idx=-1

While testing slab cache BPF iterators I noticed:

⬢ [acme@toolbox perf-tools-next]$ pahole bpf_iter__kmem_cache
WARNING: still unsuported BTF_KIND_DECL_TAG(bpf_fastcall) for bpf_cast_to_kern_ctx already with attribute (bpf_kfunc), ignoring
WARNING: still unsuported BTF_KIND_DECL_TAG(bpf_fastcall) for bpf_rdonly_cast already with attribute (bpf_kfunc), ignoring
struct bpf_iter__kmem_cache {
	union {
		struct bpf_iter_meta * meta;             /*     0     8 */
	};                                               /*     0     8 */
	union {
		struct kmem_cache * s;                   /*     8     8 */
	};                                               /*     8     8 */

	/* size: 16, cachelines: 1, members: 2 */
	/* last cacheline: 16 bytes */
};

⬢ [acme@toolbox perf-tools-next]$

Next time adding a feature in the BTF encoder, please consider adding
the support for the BTF loader and the pretty printer, so that we can
capture that info and produce compileable output that has those tags.

I'll do it when I get some free time.

- Arnaldo
Eduard Zingerman Dec. 9, 2024, 8:05 p.m. UTC | #8
On Mon, 2024-12-09 at 16:30 -0300, Arnaldo Carvalho de Melo wrote:

[...]

> Next time adding a feature in the BTF encoder, please consider adding
> the support for the BTF loader and the pretty printer, so that we can
> capture that info and produce compileable output that has those tags.
> 
> I'll do it when I get some free time.

Hi Arnaldo,

I'll handle this, sorry for inconvenience.

Thanks,
Eduard
diff mbox series

Patch

diff --git a/btf_encoder.c b/btf_encoder.c
index 8a2d92e..ae059e0 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -39,15 +39,19 @@ 
 #define BTF_ID_SET8_PFX		"__BTF_ID__set8__"
 #define BTF_SET8_KFUNCS		(1 << 0)
 #define BTF_KFUNC_TYPE_TAG	"bpf_kfunc"
+#define BTF_FASTCALL_TAG	"bpf_fastcall"
+#define KF_FASTCALL		(1 << 12)
+
+struct btf_id_and_flag {
+        uint32_t id;
+        uint32_t flags;
+};
 
 /* Adapted from include/linux/btf_ids.h */
 struct btf_id_set8 {
         uint32_t cnt;
         uint32_t flags;
-        struct {
-                uint32_t id;
-                uint32_t flags;
-        } pairs[];
+	struct btf_id_and_flag pairs[];
 };
 
 /* state used to do later encoding of saved functions */
@@ -1517,21 +1521,34 @@  out:
 	return err;
 }
 
-static int btf_encoder__tag_kfunc(struct btf_encoder *encoder, struct gobuffer *funcs, const char *kfunc)
+static int add_kfunc_decl_tag(struct btf *btf, const char *tag, __u32 id, const char *kfunc)
+{
+	int err;
+
+	err = btf__add_decl_tag(btf, tag, id, -1);
+	if (err < 0) {
+		fprintf(stderr, "%s: failed to insert kfunc decl tag for '%s': %d\n",
+			__func__, kfunc, err);
+		return err;
+	}
+	return 0;
+}
+
+static int btf_encoder__tag_kfunc(struct btf_encoder *encoder, struct gobuffer *funcs, const char *kfunc, __u32 flags)
 {
 	struct btf_func key = { .name = kfunc };
 	struct btf *btf = encoder->btf;
 	struct btf_func *target;
 	const void *base;
 	unsigned int cnt;
-	int err = -1;
+	int err;
 
 	base = gobuffer__entries(funcs);
 	cnt = gobuffer__nr_entries(funcs);
 	target = bsearch(&key, base, cnt, sizeof(key), btf_func_cmp);
 	if (!target) {
 		fprintf(stderr, "%s: failed to find kfunc '%s' in BTF\n", __func__, kfunc);
-		goto out;
+		return -1;
 	}
 
 	/* Note we are unconditionally adding the btf_decl_tag even
@@ -1539,16 +1556,16 @@  static int btf_encoder__tag_kfunc(struct btf_encoder *encoder, struct gobuffer *
 	 * We are ok to do this b/c we will later btf__dedup() to remove
 	 * any duplicates.
 	 */
-	err = btf__add_decl_tag(btf, BTF_KFUNC_TYPE_TAG, target->type_id, -1);
-	if (err < 0) {
-		fprintf(stderr, "%s: failed to insert kfunc decl tag for '%s': %d\n",
-			__func__, kfunc, err);
-		goto out;
+	err = add_kfunc_decl_tag(btf, BTF_KFUNC_TYPE_TAG, target->type_id, kfunc);
+	if (err < 0)
+		return err;
+	if (flags & KF_FASTCALL) {
+		err = add_kfunc_decl_tag(btf, BTF_FASTCALL_TAG, target->type_id, kfunc);
+		if (err < 0)
+			return err;
 	}
 
-	err = 0;
-out:
-	return err;
+	return 0;
 }
 
 static int btf_encoder__tag_kfuncs(struct btf_encoder *encoder)
@@ -1675,8 +1692,10 @@  static int btf_encoder__tag_kfuncs(struct btf_encoder *encoder)
 	/* Now inject BTF with kfunc decl tag for detected kfuncs */
 	for (i = 0; i < nr_syms; i++) {
 		const struct btf_kfunc_set_range *ranges;
+		const struct btf_id_and_flag *pair;
 		unsigned int ranges_cnt;
 		char *func, *name;
+		ptrdiff_t off;
 		GElf_Sym sym;
 		bool found;
 		int err;
@@ -1704,6 +1723,14 @@  static int btf_encoder__tag_kfuncs(struct btf_encoder *encoder)
 
 			if (ranges[j].start <= addr && addr < ranges[j].end) {
 				found = true;
+				off = addr - idlist_addr;
+				if (off < 0 || off + sizeof(*pair) > idlist->d_size) {
+					fprintf(stderr, "%s: kfunc '%s' offset outside section '%s'\n",
+						__func__, func, BTF_IDS_SECTION);
+					free(func);
+					goto out;
+				}
+				pair = idlist->d_buf + off;
 				break;
 			}
 		}
@@ -1712,7 +1739,7 @@  static int btf_encoder__tag_kfuncs(struct btf_encoder *encoder)
 			continue;
 		}
 
-		err = btf_encoder__tag_kfunc(encoder, &btf_funcs, func);
+		err = btf_encoder__tag_kfunc(encoder, &btf_funcs, func, pair->flags);
 		if (err) {
 			fprintf(stderr, "%s: failed to tag kfunc '%s'\n", __func__, func);
 			free(func);