[PATCHv6 bpf-next 7/9] bpf: Add trampoline ip hash table

Jiri Olsa posted 9 patches 1 month, 1 week ago
[PATCHv6 bpf-next 7/9] bpf: Add trampoline ip hash table
Posted by Jiri Olsa 1 month, 1 week ago
Following changes need to lookup trampoline based on its ip address,
adding hash table for that.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 include/linux/bpf.h     |  7 +++++--
 kernel/bpf/trampoline.c | 30 +++++++++++++++++++-----------
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 4e7d72dfbcd4..c85677aae865 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1325,14 +1325,17 @@ struct bpf_tramp_image {
 };
 
 struct bpf_trampoline {
-	/* hlist for trampoline_table */
-	struct hlist_node hlist;
+	/* hlist for trampoline_key_table */
+	struct hlist_node hlist_key;
+	/* hlist for trampoline_ip_table */
+	struct hlist_node hlist_ip;
 	struct ftrace_ops *fops;
 	/* serializes access to fields of this trampoline */
 	struct mutex mutex;
 	refcount_t refcnt;
 	u32 flags;
 	u64 key;
+	unsigned long ip;
 	struct {
 		struct btf_func_model model;
 		void *addr;
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 789ff4e1f40b..bdac9d673776 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -24,9 +24,10 @@ const struct bpf_prog_ops bpf_extension_prog_ops = {
 #define TRAMPOLINE_HASH_BITS 10
 #define TRAMPOLINE_TABLE_SIZE (1 << TRAMPOLINE_HASH_BITS)
 
-static struct hlist_head trampoline_table[TRAMPOLINE_TABLE_SIZE];
+static struct hlist_head trampoline_key_table[TRAMPOLINE_TABLE_SIZE];
+static struct hlist_head trampoline_ip_table[TRAMPOLINE_TABLE_SIZE];
 
-/* serializes access to trampoline_table */
+/* serializes access to trampoline tables */
 static DEFINE_MUTEX(trampoline_mutex);
 
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
@@ -135,15 +136,15 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
 			   PAGE_SIZE, true, ksym->name);
 }
 
-static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
+static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
 {
 	struct bpf_trampoline *tr;
 	struct hlist_head *head;
 	int i;
 
 	mutex_lock(&trampoline_mutex);
-	head = &trampoline_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
-	hlist_for_each_entry(tr, head, hlist) {
+	head = &trampoline_key_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
+	hlist_for_each_entry(tr, head, hlist_key) {
 		if (tr->key == key) {
 			refcount_inc(&tr->refcnt);
 			goto out;
@@ -164,8 +165,12 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
 #endif
 
 	tr->key = key;
-	INIT_HLIST_NODE(&tr->hlist);
-	hlist_add_head(&tr->hlist, head);
+	tr->ip = ftrace_location(ip);
+	INIT_HLIST_NODE(&tr->hlist_key);
+	INIT_HLIST_NODE(&tr->hlist_ip);
+	hlist_add_head(&tr->hlist_key, head);
+	head = &trampoline_ip_table[hash_64(tr->ip, TRAMPOLINE_HASH_BITS)];
+	hlist_add_head(&tr->hlist_ip, head);
 	refcount_set(&tr->refcnt, 1);
 	mutex_init(&tr->mutex);
 	for (i = 0; i < BPF_TRAMP_MAX; i++)
@@ -846,7 +851,7 @@ void bpf_trampoline_unlink_cgroup_shim(struct bpf_prog *prog)
 					 prog->aux->attach_btf_id);
 
 	bpf_lsm_find_cgroup_shim(prog, &bpf_func);
-	tr = bpf_trampoline_lookup(key);
+	tr = bpf_trampoline_lookup(key, 0);
 	if (WARN_ON_ONCE(!tr))
 		return;
 
@@ -866,7 +871,7 @@ struct bpf_trampoline *bpf_trampoline_get(u64 key,
 {
 	struct bpf_trampoline *tr;
 
-	tr = bpf_trampoline_lookup(key);
+	tr = bpf_trampoline_lookup(key, tgt_info->tgt_addr);
 	if (!tr)
 		return NULL;
 
@@ -902,7 +907,8 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
 	 * fexit progs. The fentry-only trampoline will be freed via
 	 * multiple rcu callbacks.
 	 */
-	hlist_del(&tr->hlist);
+	hlist_del(&tr->hlist_key);
+	hlist_del(&tr->hlist_ip);
 	if (tr->fops) {
 		ftrace_free_filter(tr->fops);
 		kfree(tr->fops);
@@ -1175,7 +1181,9 @@ static int __init init_trampolines(void)
 	int i;
 
 	for (i = 0; i < TRAMPOLINE_TABLE_SIZE; i++)
-		INIT_HLIST_HEAD(&trampoline_table[i]);
+		INIT_HLIST_HEAD(&trampoline_key_table[i]);
+	for (i = 0; i < TRAMPOLINE_TABLE_SIZE; i++)
+		INIT_HLIST_HEAD(&trampoline_ip_table[i]);
 	return 0;
 }
 late_initcall(init_trampolines);
-- 
2.52.0
Re: [PATCHv6 bpf-next 7/9] bpf: Add trampoline ip hash table
Posted by Andrii Nakryiko 4 weeks, 1 day ago
On Tue, Dec 30, 2025 at 6:51 AM Jiri Olsa <jolsa@kernel.org> wrote:
>
> Following changes need to lookup trampoline based on its ip address,
> adding hash table for that.
>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
>  include/linux/bpf.h     |  7 +++++--
>  kernel/bpf/trampoline.c | 30 +++++++++++++++++++-----------
>  2 files changed, 24 insertions(+), 13 deletions(-)
>
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 4e7d72dfbcd4..c85677aae865 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -1325,14 +1325,17 @@ struct bpf_tramp_image {
>  };
>
>  struct bpf_trampoline {
> -       /* hlist for trampoline_table */
> -       struct hlist_node hlist;
> +       /* hlist for trampoline_key_table */
> +       struct hlist_node hlist_key;
> +       /* hlist for trampoline_ip_table */
> +       struct hlist_node hlist_ip;
>         struct ftrace_ops *fops;
>         /* serializes access to fields of this trampoline */
>         struct mutex mutex;
>         refcount_t refcnt;
>         u32 flags;
>         u64 key;
> +       unsigned long ip;
>         struct {
>                 struct btf_func_model model;
>                 void *addr;
> diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
> index 789ff4e1f40b..bdac9d673776 100644
> --- a/kernel/bpf/trampoline.c
> +++ b/kernel/bpf/trampoline.c
> @@ -24,9 +24,10 @@ const struct bpf_prog_ops bpf_extension_prog_ops = {
>  #define TRAMPOLINE_HASH_BITS 10
>  #define TRAMPOLINE_TABLE_SIZE (1 << TRAMPOLINE_HASH_BITS)
>
> -static struct hlist_head trampoline_table[TRAMPOLINE_TABLE_SIZE];
> +static struct hlist_head trampoline_key_table[TRAMPOLINE_TABLE_SIZE];
> +static struct hlist_head trampoline_ip_table[TRAMPOLINE_TABLE_SIZE];
>
> -/* serializes access to trampoline_table */
> +/* serializes access to trampoline tables */
>  static DEFINE_MUTEX(trampoline_mutex);
>
>  #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
> @@ -135,15 +136,15 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
>                            PAGE_SIZE, true, ksym->name);
>  }
>
> -static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
> +static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
>  {
>         struct bpf_trampoline *tr;
>         struct hlist_head *head;
>         int i;
>
>         mutex_lock(&trampoline_mutex);
> -       head = &trampoline_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
> -       hlist_for_each_entry(tr, head, hlist) {
> +       head = &trampoline_key_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
> +       hlist_for_each_entry(tr, head, hlist_key) {
>                 if (tr->key == key) {
>                         refcount_inc(&tr->refcnt);
>                         goto out;
> @@ -164,8 +165,12 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
>  #endif
>
>         tr->key = key;
> -       INIT_HLIST_NODE(&tr->hlist);
> -       hlist_add_head(&tr->hlist, head);
> +       tr->ip = ftrace_location(ip);
> +       INIT_HLIST_NODE(&tr->hlist_key);
> +       INIT_HLIST_NODE(&tr->hlist_ip);
> +       hlist_add_head(&tr->hlist_key, head);
> +       head = &trampoline_ip_table[hash_64(tr->ip, TRAMPOLINE_HASH_BITS)];

For key lookups we check that there is no existing trampoline for the
given key. Can it happen that we have two trampolines at the same IP
but using two different keys?



> +       hlist_add_head(&tr->hlist_ip, head);
>         refcount_set(&tr->refcnt, 1);
>         mutex_init(&tr->mutex);
>         for (i = 0; i < BPF_TRAMP_MAX; i++)
> @@ -846,7 +851,7 @@ void bpf_trampoline_unlink_cgroup_shim(struct bpf_prog *prog)
>                                          prog->aux->attach_btf_id);
>
>         bpf_lsm_find_cgroup_shim(prog, &bpf_func);
> -       tr = bpf_trampoline_lookup(key);
> +       tr = bpf_trampoline_lookup(key, 0);
>         if (WARN_ON_ONCE(!tr))
>                 return;
>
> @@ -866,7 +871,7 @@ struct bpf_trampoline *bpf_trampoline_get(u64 key,
>  {
>         struct bpf_trampoline *tr;
>
> -       tr = bpf_trampoline_lookup(key);
> +       tr = bpf_trampoline_lookup(key, tgt_info->tgt_addr);
>         if (!tr)
>                 return NULL;
>
> @@ -902,7 +907,8 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
>          * fexit progs. The fentry-only trampoline will be freed via
>          * multiple rcu callbacks.
>          */
> -       hlist_del(&tr->hlist);
> +       hlist_del(&tr->hlist_key);
> +       hlist_del(&tr->hlist_ip);
>         if (tr->fops) {
>                 ftrace_free_filter(tr->fops);
>                 kfree(tr->fops);
> @@ -1175,7 +1181,9 @@ static int __init init_trampolines(void)
>         int i;
>
>         for (i = 0; i < TRAMPOLINE_TABLE_SIZE; i++)
> -               INIT_HLIST_HEAD(&trampoline_table[i]);
> +               INIT_HLIST_HEAD(&trampoline_key_table[i]);
> +       for (i = 0; i < TRAMPOLINE_TABLE_SIZE; i++)
> +               INIT_HLIST_HEAD(&trampoline_ip_table[i]);
>         return 0;
>  }
>  late_initcall(init_trampolines);
> --
> 2.52.0
>
Re: [PATCHv6 bpf-next 7/9] bpf: Add trampoline ip hash table
Posted by Jiri Olsa 3 weeks, 5 days ago
On Fri, Jan 09, 2026 at 04:36:41PM -0800, Andrii Nakryiko wrote:
> On Tue, Dec 30, 2025 at 6:51 AM Jiri Olsa <jolsa@kernel.org> wrote:
> >
> > Following changes need to lookup trampoline based on its ip address,
> > adding hash table for that.
> >
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > ---
> >  include/linux/bpf.h     |  7 +++++--
> >  kernel/bpf/trampoline.c | 30 +++++++++++++++++++-----------
> >  2 files changed, 24 insertions(+), 13 deletions(-)
> >
> > diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> > index 4e7d72dfbcd4..c85677aae865 100644
> > --- a/include/linux/bpf.h
> > +++ b/include/linux/bpf.h
> > @@ -1325,14 +1325,17 @@ struct bpf_tramp_image {
> >  };
> >
> >  struct bpf_trampoline {
> > -       /* hlist for trampoline_table */
> > -       struct hlist_node hlist;
> > +       /* hlist for trampoline_key_table */
> > +       struct hlist_node hlist_key;
> > +       /* hlist for trampoline_ip_table */
> > +       struct hlist_node hlist_ip;
> >         struct ftrace_ops *fops;
> >         /* serializes access to fields of this trampoline */
> >         struct mutex mutex;
> >         refcount_t refcnt;
> >         u32 flags;
> >         u64 key;
> > +       unsigned long ip;
> >         struct {
> >                 struct btf_func_model model;
> >                 void *addr;
> > diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
> > index 789ff4e1f40b..bdac9d673776 100644
> > --- a/kernel/bpf/trampoline.c
> > +++ b/kernel/bpf/trampoline.c
> > @@ -24,9 +24,10 @@ const struct bpf_prog_ops bpf_extension_prog_ops = {
> >  #define TRAMPOLINE_HASH_BITS 10
> >  #define TRAMPOLINE_TABLE_SIZE (1 << TRAMPOLINE_HASH_BITS)
> >
> > -static struct hlist_head trampoline_table[TRAMPOLINE_TABLE_SIZE];
> > +static struct hlist_head trampoline_key_table[TRAMPOLINE_TABLE_SIZE];
> > +static struct hlist_head trampoline_ip_table[TRAMPOLINE_TABLE_SIZE];
> >
> > -/* serializes access to trampoline_table */
> > +/* serializes access to trampoline tables */
> >  static DEFINE_MUTEX(trampoline_mutex);
> >
> >  #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
> > @@ -135,15 +136,15 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
> >                            PAGE_SIZE, true, ksym->name);
> >  }
> >
> > -static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
> > +static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
> >  {
> >         struct bpf_trampoline *tr;
> >         struct hlist_head *head;
> >         int i;
> >
> >         mutex_lock(&trampoline_mutex);
> > -       head = &trampoline_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
> > -       hlist_for_each_entry(tr, head, hlist) {
> > +       head = &trampoline_key_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
> > +       hlist_for_each_entry(tr, head, hlist_key) {
> >                 if (tr->key == key) {
> >                         refcount_inc(&tr->refcnt);
> >                         goto out;
> > @@ -164,8 +165,12 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
> >  #endif
> >
> >         tr->key = key;
> > -       INIT_HLIST_NODE(&tr->hlist);
> > -       hlist_add_head(&tr->hlist, head);
> > +       tr->ip = ftrace_location(ip);
> > +       INIT_HLIST_NODE(&tr->hlist_key);
> > +       INIT_HLIST_NODE(&tr->hlist_ip);
> > +       hlist_add_head(&tr->hlist_key, head);
> > +       head = &trampoline_ip_table[hash_64(tr->ip, TRAMPOLINE_HASH_BITS)];
> 
> For key lookups we check that there is no existing trampoline for the
> given key. Can it happen that we have two trampolines at the same IP
> but using two different keys?

so multiple keys (different static functions with same name) resolving to
the same ip happened in past and we should now be able to catch those in
pahole, right? CC-ing Alan ;-)

however, that should fail the attachment on ftrace/direct layer

say we have already registered and attached trampoline key1-ip1,
follow-up attachment of trampoline with key2-ip1 will fail on:

  bpf_trampoline_update
    register_fentry
      direct_ops_add
        update_ftrace_direct_add
	  ...
	  /* Make sure requested entries are not already registered. */
	  fails, because ip1 is already in direct_functions
	  ...

jirka
 
> 
> 
> 
> > +       hlist_add_head(&tr->hlist_ip, head);
> >         refcount_set(&tr->refcnt, 1);
> >         mutex_init(&tr->mutex);
> >         for (i = 0; i < BPF_TRAMP_MAX; i++)
> > @@ -846,7 +851,7 @@ void bpf_trampoline_unlink_cgroup_shim(struct bpf_prog *prog)
> >                                          prog->aux->attach_btf_id);
> >
> >         bpf_lsm_find_cgroup_shim(prog, &bpf_func);
> > -       tr = bpf_trampoline_lookup(key);
> > +       tr = bpf_trampoline_lookup(key, 0);
> >         if (WARN_ON_ONCE(!tr))
> >                 return;
> >
> > @@ -866,7 +871,7 @@ struct bpf_trampoline *bpf_trampoline_get(u64 key,
> >  {
> >         struct bpf_trampoline *tr;
> >
> > -       tr = bpf_trampoline_lookup(key);
> > +       tr = bpf_trampoline_lookup(key, tgt_info->tgt_addr);
> >         if (!tr)
> >                 return NULL;
> >
> > @@ -902,7 +907,8 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
> >          * fexit progs. The fentry-only trampoline will be freed via
> >          * multiple rcu callbacks.
> >          */
> > -       hlist_del(&tr->hlist);
> > +       hlist_del(&tr->hlist_key);
> > +       hlist_del(&tr->hlist_ip);
> >         if (tr->fops) {
> >                 ftrace_free_filter(tr->fops);
> >                 kfree(tr->fops);
> > @@ -1175,7 +1181,9 @@ static int __init init_trampolines(void)
> >         int i;
> >
> >         for (i = 0; i < TRAMPOLINE_TABLE_SIZE; i++)
> > -               INIT_HLIST_HEAD(&trampoline_table[i]);
> > +               INIT_HLIST_HEAD(&trampoline_key_table[i]);
> > +       for (i = 0; i < TRAMPOLINE_TABLE_SIZE; i++)
> > +               INIT_HLIST_HEAD(&trampoline_ip_table[i]);
> >         return 0;
> >  }
> >  late_initcall(init_trampolines);
> > --
> > 2.52.0
> >
Re: [PATCHv6 bpf-next 7/9] bpf: Add trampoline ip hash table
Posted by Alan Maguire 3 weeks, 4 days ago
On 12/01/2026 21:27, Jiri Olsa wrote:
> On Fri, Jan 09, 2026 at 04:36:41PM -0800, Andrii Nakryiko wrote:
>> On Tue, Dec 30, 2025 at 6:51 AM Jiri Olsa <jolsa@kernel.org> wrote:
>>>
>>> Following changes need to lookup trampoline based on its ip address,
>>> adding hash table for that.
>>>
>>> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
>>> ---
>>>  include/linux/bpf.h     |  7 +++++--
>>>  kernel/bpf/trampoline.c | 30 +++++++++++++++++++-----------
>>>  2 files changed, 24 insertions(+), 13 deletions(-)
>>>
>>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>>> index 4e7d72dfbcd4..c85677aae865 100644
>>> --- a/include/linux/bpf.h
>>> +++ b/include/linux/bpf.h
>>> @@ -1325,14 +1325,17 @@ struct bpf_tramp_image {
>>>  };
>>>
>>>  struct bpf_trampoline {
>>> -       /* hlist for trampoline_table */
>>> -       struct hlist_node hlist;
>>> +       /* hlist for trampoline_key_table */
>>> +       struct hlist_node hlist_key;
>>> +       /* hlist for trampoline_ip_table */
>>> +       struct hlist_node hlist_ip;
>>>         struct ftrace_ops *fops;
>>>         /* serializes access to fields of this trampoline */
>>>         struct mutex mutex;
>>>         refcount_t refcnt;
>>>         u32 flags;
>>>         u64 key;
>>> +       unsigned long ip;
>>>         struct {
>>>                 struct btf_func_model model;
>>>                 void *addr;
>>> diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
>>> index 789ff4e1f40b..bdac9d673776 100644
>>> --- a/kernel/bpf/trampoline.c
>>> +++ b/kernel/bpf/trampoline.c
>>> @@ -24,9 +24,10 @@ const struct bpf_prog_ops bpf_extension_prog_ops = {
>>>  #define TRAMPOLINE_HASH_BITS 10
>>>  #define TRAMPOLINE_TABLE_SIZE (1 << TRAMPOLINE_HASH_BITS)
>>>
>>> -static struct hlist_head trampoline_table[TRAMPOLINE_TABLE_SIZE];
>>> +static struct hlist_head trampoline_key_table[TRAMPOLINE_TABLE_SIZE];
>>> +static struct hlist_head trampoline_ip_table[TRAMPOLINE_TABLE_SIZE];
>>>
>>> -/* serializes access to trampoline_table */
>>> +/* serializes access to trampoline tables */
>>>  static DEFINE_MUTEX(trampoline_mutex);
>>>
>>>  #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
>>> @@ -135,15 +136,15 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
>>>                            PAGE_SIZE, true, ksym->name);
>>>  }
>>>
>>> -static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
>>> +static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
>>>  {
>>>         struct bpf_trampoline *tr;
>>>         struct hlist_head *head;
>>>         int i;
>>>
>>>         mutex_lock(&trampoline_mutex);
>>> -       head = &trampoline_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
>>> -       hlist_for_each_entry(tr, head, hlist) {
>>> +       head = &trampoline_key_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
>>> +       hlist_for_each_entry(tr, head, hlist_key) {
>>>                 if (tr->key == key) {
>>>                         refcount_inc(&tr->refcnt);
>>>                         goto out;
>>> @@ -164,8 +165,12 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
>>>  #endif
>>>
>>>         tr->key = key;
>>> -       INIT_HLIST_NODE(&tr->hlist);
>>> -       hlist_add_head(&tr->hlist, head);
>>> +       tr->ip = ftrace_location(ip);
>>> +       INIT_HLIST_NODE(&tr->hlist_key);
>>> +       INIT_HLIST_NODE(&tr->hlist_ip);
>>> +       hlist_add_head(&tr->hlist_key, head);
>>> +       head = &trampoline_ip_table[hash_64(tr->ip, TRAMPOLINE_HASH_BITS)];
>>
>> For key lookups we check that there is no existing trampoline for the
>> given key. Can it happen that we have two trampolines at the same IP
>> but using two different keys?
> 
> so multiple keys (different static functions with same name) resolving to
> the same ip happened in past and we should now be able to catch those in
> pahole, right? CC-ing Alan ;-)
>

We could catch this I think, but today we don't. We have support to avoid 
encoding BTF where a function name has multiple instances (ambiguous address).
Here you're concerned with mapping from ip to function name, where multiple 
names share the same ip, right?

A quick scan of System.map suggests there's a ~150 of these,
excluding __pfx_ entries:

$ awk 'NR > 1 && ($2 == "T" || $2 == "t") && $1 == prev_field { print;} { prev_field = $1}' System.map|egrep -v __pfx|wc -l
155

Alan
Re: [PATCHv6 bpf-next 7/9] bpf: Add trampoline ip hash table
Posted by Jiri Olsa 3 weeks, 4 days ago
On Tue, Jan 13, 2026 at 11:02:33AM +0000, Alan Maguire wrote:
> On 12/01/2026 21:27, Jiri Olsa wrote:
> > On Fri, Jan 09, 2026 at 04:36:41PM -0800, Andrii Nakryiko wrote:
> >> On Tue, Dec 30, 2025 at 6:51 AM Jiri Olsa <jolsa@kernel.org> wrote:
> >>>
> >>> Following changes need to lookup trampoline based on its ip address,
> >>> adding hash table for that.
> >>>
> >>> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> >>> ---
> >>>  include/linux/bpf.h     |  7 +++++--
> >>>  kernel/bpf/trampoline.c | 30 +++++++++++++++++++-----------
> >>>  2 files changed, 24 insertions(+), 13 deletions(-)
> >>>
> >>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> >>> index 4e7d72dfbcd4..c85677aae865 100644
> >>> --- a/include/linux/bpf.h
> >>> +++ b/include/linux/bpf.h
> >>> @@ -1325,14 +1325,17 @@ struct bpf_tramp_image {
> >>>  };
> >>>
> >>>  struct bpf_trampoline {
> >>> -       /* hlist for trampoline_table */
> >>> -       struct hlist_node hlist;
> >>> +       /* hlist for trampoline_key_table */
> >>> +       struct hlist_node hlist_key;
> >>> +       /* hlist for trampoline_ip_table */
> >>> +       struct hlist_node hlist_ip;
> >>>         struct ftrace_ops *fops;
> >>>         /* serializes access to fields of this trampoline */
> >>>         struct mutex mutex;
> >>>         refcount_t refcnt;
> >>>         u32 flags;
> >>>         u64 key;
> >>> +       unsigned long ip;
> >>>         struct {
> >>>                 struct btf_func_model model;
> >>>                 void *addr;
> >>> diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
> >>> index 789ff4e1f40b..bdac9d673776 100644
> >>> --- a/kernel/bpf/trampoline.c
> >>> +++ b/kernel/bpf/trampoline.c
> >>> @@ -24,9 +24,10 @@ const struct bpf_prog_ops bpf_extension_prog_ops = {
> >>>  #define TRAMPOLINE_HASH_BITS 10
> >>>  #define TRAMPOLINE_TABLE_SIZE (1 << TRAMPOLINE_HASH_BITS)
> >>>
> >>> -static struct hlist_head trampoline_table[TRAMPOLINE_TABLE_SIZE];
> >>> +static struct hlist_head trampoline_key_table[TRAMPOLINE_TABLE_SIZE];
> >>> +static struct hlist_head trampoline_ip_table[TRAMPOLINE_TABLE_SIZE];
> >>>
> >>> -/* serializes access to trampoline_table */
> >>> +/* serializes access to trampoline tables */
> >>>  static DEFINE_MUTEX(trampoline_mutex);
> >>>
> >>>  #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
> >>> @@ -135,15 +136,15 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
> >>>                            PAGE_SIZE, true, ksym->name);
> >>>  }
> >>>
> >>> -static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
> >>> +static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
> >>>  {
> >>>         struct bpf_trampoline *tr;
> >>>         struct hlist_head *head;
> >>>         int i;
> >>>
> >>>         mutex_lock(&trampoline_mutex);
> >>> -       head = &trampoline_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
> >>> -       hlist_for_each_entry(tr, head, hlist) {
> >>> +       head = &trampoline_key_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
> >>> +       hlist_for_each_entry(tr, head, hlist_key) {
> >>>                 if (tr->key == key) {
> >>>                         refcount_inc(&tr->refcnt);
> >>>                         goto out;
> >>> @@ -164,8 +165,12 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
> >>>  #endif
> >>>
> >>>         tr->key = key;
> >>> -       INIT_HLIST_NODE(&tr->hlist);
> >>> -       hlist_add_head(&tr->hlist, head);
> >>> +       tr->ip = ftrace_location(ip);
> >>> +       INIT_HLIST_NODE(&tr->hlist_key);
> >>> +       INIT_HLIST_NODE(&tr->hlist_ip);
> >>> +       hlist_add_head(&tr->hlist_key, head);
> >>> +       head = &trampoline_ip_table[hash_64(tr->ip, TRAMPOLINE_HASH_BITS)];
> >>
> >> For key lookups we check that there is no existing trampoline for the
> >> given key. Can it happen that we have two trampolines at the same IP
> >> but using two different keys?
> > 
> > so multiple keys (different static functions with same name) resolving to
> > the same ip happened in past and we should now be able to catch those in
> > pahole, right? CC-ing Alan ;-)
> >
> 
> We could catch this I think, but today we don't. We have support to avoid 
> encoding BTF where a function name has multiple instances (ambiguous address).
> Here you're concerned with mapping from ip to function name, where multiple 
> names share the same ip, right?

so trampolines work only on top of BTF func record, so the 'key' represents
BTF_KIND_FUNC record.. and as such it can resolve to just single ip, because
pahole filters out functions with ambiguous instances IIUC

> 
> A quick scan of System.map suggests there's a ~150 of these,
> excluding __pfx_ entries:
> 
> $ awk 'NR > 1 && ($2 == "T" || $2 == "t") && $1 == prev_field { print;} { prev_field = $1}' System.map|egrep -v __pfx|wc -l
> 155

right, but these are just regular kernel symbols with aliases and other
shared stuff

jirka