* [PATCH dwarves v1] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems @ 2025-04-10 8:33 Tony Ambardar 2025-04-10 12:20 ` Alan Maguire 0 siblings, 1 reply; 15+ messages in thread From: Tony Ambardar @ 2025-04-10 8:33 UTC (permalink / raw) To: dwarves, bpf Cc: Tony Ambardar, Alan Maguire, Arnaldo Carvalho de Melo, Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann While doing JIT development on armhf BTF kernels, I hit a strange issue where some functions were missing in BTF data. This required considerable debugging but can be reproduced simply: $ bpftool --version bpftool v7.6.0 using libbpf v1.6 features: llvm, skeletons $ pahole --version v1.29 $ pahole -J -j --btf_features=decl_tag,consistent_func,decl_tag_kfuncs .tmp_vmlinux_armhf btf_encoder__tag_kfunc: failed to find kfunc 'scx_bpf_select_cpu_dfl' in BTF btf_encoder__tag_kfuncs: failed to tag kfunc 'scx_bpf_select_cpu_dfl' $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf <nothing> $ pfunct -Fdwarf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); $ pahole -J -j --btf_features=decl_tag,decl_tag_kfuncs .tmp_vmlinux_armhf $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf bpf_kfunc s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); The key things to note are the pahole 'consistent_func' feature and the u64 'wake_flags' parameter vs. arm 32-bit registers. These point to existing code handling arguments larger than register-size, but only structs. Generalize the code for any type of argument exceeding register size (i.e. cu->addr_size). This should work for integral or aggregate types, and also avoids a bug in the current code where a register-sized struct could be mistaken for larger. Fixes: a53c58158b76 ("dwarf_loader: Mark functions that do not use expected registers for params") Signed-off-by: Tony Ambardar <tony.ambardar@gmail.com> --- dwarf_loader.c | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/dwarf_loader.c b/dwarf_loader.c index e1ba7bc..22abfdb 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -2914,23 +2914,9 @@ out: return 0; } -static bool param__is_struct(struct cu *cu, struct tag *tag) +static bool param__is_wide(struct cu *cu, struct tag *tag) { - struct tag *type = cu__type(cu, tag->type); - - if (!type) - return false; - - switch (type->tag) { - case DW_TAG_structure_type: - return true; - case DW_TAG_const_type: - case DW_TAG_typedef: - /* handle "typedef struct", const parameter */ - return param__is_struct(cu, type); - default: - return false; - } + return tag__size(tag, cu) > cu->addr_size; } static int cu__resolve_func_ret_types_optimized(struct cu *cu) @@ -2942,9 +2928,9 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) struct tag *tag = pt->entries[i]; struct parameter *pos; struct function *fn = tag__function(tag); - bool has_unexpected_reg = false, has_struct_param = false; + bool has_unexpected_reg = false, has_wide_param = false; - /* mark function as optimized if parameter is, or + /* Mark function as optimized if parameter is, or * if parameter does not have a location; at this * point location presence has been marked in * abstract origins for cases where a parameter @@ -2953,10 +2939,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) * * Also mark functions which, due to optimization, * use an unexpected register for a parameter. - * Exception is functions which have a struct - * as a parameter, as multiple registers may - * be used to represent it, throwing off register - * to parameter mapping. + * Exception is functions which have a wide + * parameter, as multiple registers may be used + * to represent it, throwing off register to + * parameter mapping. Examples could include + * structs or 64-bit types on a 32-bit arch. */ ftype__for_each_parameter(&fn->proto, pos) { if (pos->optimized || !pos->has_loc) @@ -2967,11 +2954,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) } if (has_unexpected_reg) { ftype__for_each_parameter(&fn->proto, pos) { - has_struct_param = param__is_struct(cu, &pos->tag); - if (has_struct_param) + has_wide_param = param__is_wide(cu, &pos->tag); + if (has_wide_param) break; } - if (!has_struct_param) + if (!has_wide_param) fn->proto.unexpected_reg = 1; } -- 2.34.1 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH dwarves v1] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems 2025-04-10 8:33 [PATCH dwarves v1] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems Tony Ambardar @ 2025-04-10 12:20 ` Alan Maguire 2025-04-16 10:33 ` Tony Ambardar 0 siblings, 1 reply; 15+ messages in thread From: Alan Maguire @ 2025-04-10 12:20 UTC (permalink / raw) To: Tony Ambardar, dwarves, bpf Cc: Arnaldo Carvalho de Melo, Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann, Yonghong Song On 10/04/2025 09:33, Tony Ambardar wrote: > While doing JIT development on armhf BTF kernels, I hit a strange issue > where some functions were missing in BTF data. This required considerable > debugging but can be reproduced simply: > > $ bpftool --version > bpftool v7.6.0 > using libbpf v1.6 > features: llvm, skeletons > > $ pahole --version > v1.29 > > $ pahole -J -j --btf_features=decl_tag,consistent_func,decl_tag_kfuncs .tmp_vmlinux_armhf > btf_encoder__tag_kfunc: failed to find kfunc 'scx_bpf_select_cpu_dfl' in BTF > btf_encoder__tag_kfuncs: failed to tag kfunc 'scx_bpf_select_cpu_dfl' > > $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf > <nothing> > > $ pfunct -Fdwarf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf > s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); > > $ pahole -J -j --btf_features=decl_tag,decl_tag_kfuncs .tmp_vmlinux_armhf > > $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf > bpf_kfunc s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); > > The key things to note are the pahole 'consistent_func' feature and the u64 > 'wake_flags' parameter vs. arm 32-bit registers. These point to existing > code handling arguments larger than register-size, but only structs. > > Generalize the code for any type of argument exceeding register size (i.e. > cu->addr_size). This should work for integral or aggregate types, and also > avoids a bug in the current code where a register-sized struct could be > mistaken for larger. > > Fixes: a53c58158b76 ("dwarf_loader: Mark functions that do not use expected registers for params") > Signed-off-by: Tony Ambardar <tony.ambardar@gmail.com> Thanks for investigating this! I've tested this versus baseline on x86_64 and aarch64. I'm seeing some small divergence in functions encoded; for example on aarch64 we don't get a representation for static int __io_run_local_work(struct io_ring_ctx *ctx, io_tw_token_t tw, int min_events, int max_events); The reason for that is the second argument is a typedef io_tw_token_t, which is in turn a typedef for: struct io_tw_state { }; i.e. an empty struct. The reason is with your patch we've moved from type-centric to size-centric criteria used to allow functions into BTF that have unexpected register usage; because the above function uses unexpected registers _and_ does not exceed the address size, the function is marked as having an inconsistent reg mapping. In this case, that seems reasonable since it is true; there is no register needed to represent the second argument. The deeper rationale here in allowing functions that have structs that may be represented by multiple registers is that we can handle this outcome; the BPF_PROG2() macro was added to handle such cases and seems to handle multi-register representation but _not_ representations where a register is not needed at all. I'm basing that on the ___bpf_union_arg() macro in bpf_tracing.h so please correct me if I'm wrong (we could potentially add a sizeof(t) == 0 clause here perhaps). So in other words, though we see small divergences in representation I _think_ they are consistent with our expectations. I'd really like to see wider testing of this patch before it lands however so we can shake out other problematic cases if any. If folks could try this and compare BTF representations to baseline that would be great! In particular comparing raw BTF is necessary since vmlinux.h representations don't include functions (aside from kfuncs). Now that we have always-reproducible BTF a simple diff of "bpftool btf dump file vmlinux" can be used to make such comparisons. However perhaps we could also think about enhancing the bpf_tracing.h macro to handle zero-sized parameters like empty structs such that later parameters are mapped to registers correctly (presuming that's possible)? Yonghong, what do you think? Thanks! Alan > --- > dwarf_loader.c | 37 ++++++++++++------------------------- > 1 file changed, 12 insertions(+), 25 deletions(-) > > diff --git a/dwarf_loader.c b/dwarf_loader.c > index e1ba7bc..22abfdb 100644 > --- a/dwarf_loader.c > +++ b/dwarf_loader.c > @@ -2914,23 +2914,9 @@ out: > return 0; > } > > -static bool param__is_struct(struct cu *cu, struct tag *tag) > +static bool param__is_wide(struct cu *cu, struct tag *tag) > { > - struct tag *type = cu__type(cu, tag->type); > - > - if (!type) > - return false; > - > - switch (type->tag) { > - case DW_TAG_structure_type: > - return true; > - case DW_TAG_const_type: > - case DW_TAG_typedef: > - /* handle "typedef struct", const parameter */ > - return param__is_struct(cu, type); > - default: > - return false; > - } > + return tag__size(tag, cu) > cu->addr_size; > } > > static int cu__resolve_func_ret_types_optimized(struct cu *cu) > @@ -2942,9 +2928,9 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) > struct tag *tag = pt->entries[i]; > struct parameter *pos; > struct function *fn = tag__function(tag); > - bool has_unexpected_reg = false, has_struct_param = false; > + bool has_unexpected_reg = false, has_wide_param = false; > > - /* mark function as optimized if parameter is, or > + /* Mark function as optimized if parameter is, or > * if parameter does not have a location; at this > * point location presence has been marked in > * abstract origins for cases where a parameter > @@ -2953,10 +2939,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) > * > * Also mark functions which, due to optimization, > * use an unexpected register for a parameter. > - * Exception is functions which have a struct > - * as a parameter, as multiple registers may > - * be used to represent it, throwing off register > - * to parameter mapping. > + * Exception is functions which have a wide > + * parameter, as multiple registers may be used > + * to represent it, throwing off register to > + * parameter mapping. Examples could include > + * structs or 64-bit types on a 32-bit arch. > */ > ftype__for_each_parameter(&fn->proto, pos) { > if (pos->optimized || !pos->has_loc) > @@ -2967,11 +2954,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) > } > if (has_unexpected_reg) { > ftype__for_each_parameter(&fn->proto, pos) { > - has_struct_param = param__is_struct(cu, &pos->tag); > - if (has_struct_param) > + has_wide_param = param__is_wide(cu, &pos->tag); > + if (has_wide_param) > break; > } > - if (!has_struct_param) > + if (!has_wide_param) > fn->proto.unexpected_reg = 1; > } > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH dwarves v1] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems 2025-04-10 12:20 ` Alan Maguire @ 2025-04-16 10:33 ` Tony Ambardar 2025-05-02 7:03 ` [PATCH dwarves v2] " Tony Ambardar 0 siblings, 1 reply; 15+ messages in thread From: Tony Ambardar @ 2025-04-16 10:33 UTC (permalink / raw) To: Alan Maguire Cc: dwarves, bpf, Arnaldo Carvalho de Melo, Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann, Yonghong Song On Thu, Apr 10, 2025 at 01:20:45PM +0100, Alan Maguire wrote: > On 10/04/2025 09:33, Tony Ambardar wrote: > > While doing JIT development on armhf BTF kernels, I hit a strange issue > > where some functions were missing in BTF data. This required considerable > > debugging but can be reproduced simply: > > > > $ bpftool --version > > bpftool v7.6.0 > > using libbpf v1.6 > > features: llvm, skeletons > > > > $ pahole --version > > v1.29 > > > > $ pahole -J -j --btf_features=decl_tag,consistent_func,decl_tag_kfuncs .tmp_vmlinux_armhf > > btf_encoder__tag_kfunc: failed to find kfunc 'scx_bpf_select_cpu_dfl' in BTF > > btf_encoder__tag_kfuncs: failed to tag kfunc 'scx_bpf_select_cpu_dfl' > > > > $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf > > <nothing> > > > > $ pfunct -Fdwarf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf > > s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); > > > > $ pahole -J -j --btf_features=decl_tag,decl_tag_kfuncs .tmp_vmlinux_armhf > > > > $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf > > bpf_kfunc s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); > > > > The key things to note are the pahole 'consistent_func' feature and the u64 > > 'wake_flags' parameter vs. arm 32-bit registers. These point to existing > > code handling arguments larger than register-size, but only structs. > > > > Generalize the code for any type of argument exceeding register size (i.e. > > cu->addr_size). This should work for integral or aggregate types, and also > > avoids a bug in the current code where a register-sized struct could be > > mistaken for larger. > > > > Fixes: a53c58158b76 ("dwarf_loader: Mark functions that do not use expected registers for params") > > Signed-off-by: Tony Ambardar <tony.ambardar@gmail.com> > > Thanks for investigating this! I've tested this versus baseline on > x86_64 and aarch64. I'm seeing some small divergence in functions > encoded; for example on aarch64 we don't get a representation for > > static int __io_run_local_work(struct io_ring_ctx *ctx, io_tw_token_t > tw, int min_events, int max_events); > > The reason for that is the second argument is a typedef io_tw_token_t, > which is in turn a typedef for: > > struct io_tw_state { > }; > > i.e. an empty struct. > > The reason is with your patch we've moved from type-centric to > size-centric criteria used to allow functions into BTF that have > unexpected register usage; because the above function uses unexpected > registers _and_ does not exceed the address size, the function is marked > as having an inconsistent reg mapping. In this case, that seems > reasonable since it is true; there is no register needed to represent > the second argument. > > The deeper rationale here in allowing functions that have structs that > may be represented by multiple registers is that we can handle this > outcome; the BPF_PROG2() macro was added to handle such cases and seems > to handle multi-register representation but _not_ representations where > a register is not needed at all. I'm basing that on the > ___bpf_union_arg() macro in bpf_tracing.h so please correct me if I'm > wrong (we could potentially add a sizeof(t) == 0 clause here perhaps). > > So in other words, though we see small divergences in representation I > _think_ they are consistent with our expectations. > > I'd really like to see wider testing of this patch before it lands > however so we can shake out other problematic cases if any. If folks > could try this and compare BTF representations to baseline that would be > great! In particular comparing raw BTF is necessary since vmlinux.h > representations don't include functions (aside from kfuncs). Now that we > have always-reproducible BTF a simple diff of "bpftool btf dump file > vmlinux" can be used to make such comparisons. > > However perhaps we could also think about enhancing the bpf_tracing.h > macro to handle zero-sized parameters like empty structs such that later > parameters are mapped to registers correctly (presuming that's > possible)? Yonghong, what do you think? Hi Alan, Thanks so much for the additional context. I pressed pause to consider this while waiting for further testing news or feedback, but haven't seen anything since. Have you heard anything OOB? I also understood dwarves could have CI working now, so wondering how those tests with the patch might have gone. In fact, it would be great to have a regular arm32 CI running if that's possible. Could you share how the CI changes are being managed? I've recently been trying to update the arm32 JIT and test_progs in tandem, with the goal of having a working 32-bit target for kernel-patches/bpf CI, but some baby-steps with dwarves or libbpf could be very helpful. As far as type-based vs size-based criteria, I'm not wedded to either, and did look at the type-based route as currently exists. I needed to add cases for DW_TAG_base_type (for ints), DW_TAG_volatile_type (recursive), DW_TAG_union_type (same issues as structs), and then we still need size tests anyway. Sticking with size-based (and a zero-test as you suggested) seemed the simplest and preserved the functions you noticed missing. Cheers, Tony > > Thanks! > > Alan > > > --- > > dwarf_loader.c | 37 ++++++++++++------------------------- > > 1 file changed, 12 insertions(+), 25 deletions(-) > > > > diff --git a/dwarf_loader.c b/dwarf_loader.c > > index e1ba7bc..22abfdb 100644 > > --- a/dwarf_loader.c > > +++ b/dwarf_loader.c > > @@ -2914,23 +2914,9 @@ out: > > return 0; > > } > > > > -static bool param__is_struct(struct cu *cu, struct tag *tag) > > +static bool param__is_wide(struct cu *cu, struct tag *tag) > > { > > - struct tag *type = cu__type(cu, tag->type); > > - > > - if (!type) > > - return false; > > - > > - switch (type->tag) { > > - case DW_TAG_structure_type: > > - return true; > > - case DW_TAG_const_type: > > - case DW_TAG_typedef: > > - /* handle "typedef struct", const parameter */ > > - return param__is_struct(cu, type); > > - default: > > - return false; > > - } > > + return tag__size(tag, cu) > cu->addr_size; > > } > > > > static int cu__resolve_func_ret_types_optimized(struct cu *cu) > > @@ -2942,9 +2928,9 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) > > struct tag *tag = pt->entries[i]; > > struct parameter *pos; > > struct function *fn = tag__function(tag); > > - bool has_unexpected_reg = false, has_struct_param = false; > > + bool has_unexpected_reg = false, has_wide_param = false; > > > > - /* mark function as optimized if parameter is, or > > + /* Mark function as optimized if parameter is, or > > * if parameter does not have a location; at this > > * point location presence has been marked in > > * abstract origins for cases where a parameter > > @@ -2953,10 +2939,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) > > * > > * Also mark functions which, due to optimization, > > * use an unexpected register for a parameter. > > - * Exception is functions which have a struct > > - * as a parameter, as multiple registers may > > - * be used to represent it, throwing off register > > - * to parameter mapping. > > + * Exception is functions which have a wide > > + * parameter, as multiple registers may be used > > + * to represent it, throwing off register to > > + * parameter mapping. Examples could include > > + * structs or 64-bit types on a 32-bit arch. > > */ > > ftype__for_each_parameter(&fn->proto, pos) { > > if (pos->optimized || !pos->has_loc) > > @@ -2967,11 +2954,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) > > } > > if (has_unexpected_reg) { > > ftype__for_each_parameter(&fn->proto, pos) { > > - has_struct_param = param__is_struct(cu, &pos->tag); > > - if (has_struct_param) > > + has_wide_param = param__is_wide(cu, &pos->tag); > > + if (has_wide_param) > > break; > > } > > - if (!has_struct_param) > > + if (!has_wide_param) > > fn->proto.unexpected_reg = 1; > > } > > > ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH dwarves v2] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems 2025-04-16 10:33 ` Tony Ambardar @ 2025-05-02 7:03 ` Tony Ambardar 2025-05-08 9:38 ` Alexis Lothoré ` (2 more replies) 0 siblings, 3 replies; 15+ messages in thread From: Tony Ambardar @ 2025-05-02 7:03 UTC (permalink / raw) To: dwarves, bpf Cc: Tony Ambardar, Alan Maguire, Arnaldo Carvalho de Melo, Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann I encountered an issue building BTF kernels for 32-bit armhf, where many functions are missing in BTF data: LD vmlinux BTFIDS vmlinux WARN: resolve_btfids: unresolved symbol vfs_truncate WARN: resolve_btfids: unresolved symbol vfs_fallocate WARN: resolve_btfids: unresolved symbol scx_bpf_select_cpu_dfl WARN: resolve_btfids: unresolved symbol scx_bpf_pick_idle_cpu_node WARN: resolve_btfids: unresolved symbol scx_bpf_pick_idle_cpu WARN: resolve_btfids: unresolved symbol scx_bpf_pick_any_cpu_node WARN: resolve_btfids: unresolved symbol scx_bpf_pick_any_cpu WARN: resolve_btfids: unresolved symbol scx_bpf_kick_cpu WARN: resolve_btfids: unresolved symbol scx_bpf_exit_bstr WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_nr_queued WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move_vtime WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move_to_local WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_insert_vtime WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_insert WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_vtime_from_dsq WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_vtime WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq_set_vtime WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq_set_slice WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch WARN: resolve_btfids: unresolved symbol scx_bpf_destroy_dsq WARN: resolve_btfids: unresolved symbol scx_bpf_create_dsq WARN: resolve_btfids: unresolved symbol scx_bpf_consume WARN: resolve_btfids: unresolved symbol bpf_throw WARN: resolve_btfids: unresolved symbol bpf_sock_ops_enable_tx_tstamp WARN: resolve_btfids: unresolved symbol bpf_percpu_obj_new_impl WARN: resolve_btfids: unresolved symbol bpf_obj_new_impl WARN: resolve_btfids: unresolved symbol bpf_lookup_user_key WARN: resolve_btfids: unresolved symbol bpf_lookup_system_key WARN: resolve_btfids: unresolved symbol bpf_iter_task_vma_new WARN: resolve_btfids: unresolved symbol bpf_iter_scx_dsq_new WARN: resolve_btfids: unresolved symbol bpf_get_kmem_cache WARN: resolve_btfids: unresolved symbol bpf_dynptr_from_xdp WARN: resolve_btfids: unresolved symbol bpf_dynptr_from_skb WARN: resolve_btfids: unresolved symbol bpf_cgroup_from_id NM System.map After further debugging this can be reproduced more simply: $ pahole -J -j --btf_features=decl_tag,consistent_func,decl_tag_kfuncs .tmp_vmlinux_armhf btf_encoder__tag_kfunc: failed to find kfunc 'scx_bpf_select_cpu_dfl' in BTF btf_encoder__tag_kfuncs: failed to tag kfunc 'scx_bpf_select_cpu_dfl' $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf <nothing> $ pfunct -Fdwarf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); $ pahole -J -j --btf_features=decl_tag,decl_tag_kfuncs .tmp_vmlinux_armhf $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf bpf_kfunc s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); The key things to note are the pahole 'consistent_func' feature and the u64 'wake_flags' parameter vs. arm 32-bit registers. These point to existing code handling arguments larger than register-size, but only structs. Generalize the code for any type of argument misfit to register size (i.e. zero or > cu->addr_size). This should work for integral or aggregate types, and also avoids a bug in the current code where a register-sized struct could be mistaken for larger. Fixes: a53c58158b76 ("dwarf_loader: Mark functions that do not use expected registers for params") Signed-off-by: Tony Ambardar <tony.ambardar@gmail.com> --- v1 -> v2: - Update to preserve existing behaviour where zero-sized struct params still permit the function to be encoded, as noted by Alan. --- dwarf_loader.c | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/dwarf_loader.c b/dwarf_loader.c index e1ba7bc..abf1717 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -2914,23 +2914,11 @@ out: return 0; } -static bool param__is_struct(struct cu *cu, struct tag *tag) +static bool param__misfits_reg(struct cu *cu, struct tag *tag) { - struct tag *type = cu__type(cu, tag->type); + size_t sz = tag__size(tag, cu); - if (!type) - return false; - - switch (type->tag) { - case DW_TAG_structure_type: - return true; - case DW_TAG_const_type: - case DW_TAG_typedef: - /* handle "typedef struct", const parameter */ - return param__is_struct(cu, type); - default: - return false; - } + return sz == 0 || sz > cu->addr_size; } static int cu__resolve_func_ret_types_optimized(struct cu *cu) @@ -2942,9 +2930,9 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) struct tag *tag = pt->entries[i]; struct parameter *pos; struct function *fn = tag__function(tag); - bool has_unexpected_reg = false, has_struct_param = false; + bool has_unexpected_reg = false, has_misfit_param = false; - /* mark function as optimized if parameter is, or + /* Mark function as optimized if parameter is, or * if parameter does not have a location; at this * point location presence has been marked in * abstract origins for cases where a parameter @@ -2953,10 +2941,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) * * Also mark functions which, due to optimization, * use an unexpected register for a parameter. - * Exception is functions which have a struct - * as a parameter, as multiple registers may - * be used to represent it, throwing off register - * to parameter mapping. + * Exception is functions with a wide/zero-sized + * parameter, as single register won't be used + * to represent it, throwing off register to + * parameter mapping. Examples include large + * structs or 64-bit types on a 32-bit arch. */ ftype__for_each_parameter(&fn->proto, pos) { if (pos->optimized || !pos->has_loc) @@ -2967,11 +2956,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) } if (has_unexpected_reg) { ftype__for_each_parameter(&fn->proto, pos) { - has_struct_param = param__is_struct(cu, &pos->tag); - if (has_struct_param) + has_misfit_param = param__misfits_reg(cu, &pos->tag); + if (has_misfit_param) break; } - if (!has_struct_param) + if (!has_misfit_param) fn->proto.unexpected_reg = 1; } -- 2.34.1 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH dwarves v2] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems 2025-05-02 7:03 ` [PATCH dwarves v2] " Tony Ambardar @ 2025-05-08 9:38 ` Alexis Lothoré 2025-05-09 5:21 ` Tony Ambardar 2025-05-08 13:24 ` Alan Maguire 2025-05-22 6:37 ` [PATCH dwarves v3] " Tony Ambardar 2 siblings, 1 reply; 15+ messages in thread From: Alexis Lothoré @ 2025-05-08 9:38 UTC (permalink / raw) To: Tony Ambardar, dwarves, bpf Cc: Alan Maguire, Arnaldo Carvalho de Melo, Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann Hello, On Fri May 2, 2025 at 9:03 AM CEST, Tony Ambardar wrote: > I encountered an issue building BTF kernels for 32-bit armhf, where many > functions are missing in BTF data: [...] > Fixes: a53c58158b76 ("dwarf_loader: Mark functions that do not use expected registers for params") > Signed-off-by: Tony Ambardar <tony.ambardar@gmail.com> I encountered some issues with pahole 1.30 when trying to generate BTF data for functions having some __int128 values ([1]), and have been redirected here by Tony. I gave a try to the patch below and confirm that it fixes my issue: BTF data is now properly generated for my target function, so: Tested-by: Alexis Lothoré <alexis.lothore@bootlin.com> While at it, to follow-up on Alan's request for more testing, I did the following: - build kernel and bpf selftests with pahole 1.30, extract BTF raw data with bpftool - repeat with pahole 1.30 + Tony's patch - I build my kernel for arm64, it is based on bpf-next_base and I use a defconfig very close to the one used in BPF CI (so based on tools/testing/selftests/bpf/config*) I observe the following when comparing the resulting BTF data with/without Tony's patch: - There is no difference on vmlinux BTF data - For bpf_testmod.ko, there is a slight shift in the first BTF ID (first ID is 46 with pristine pahole, 47 with patched pahole), which in turns makes a lot of noise in the diff, but the actual diff seems to be about two new BTF entries related to my custom function now being properly detected (BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO) Alexis [1] https://lore.kernel.org/bpf/D9Q73OTLEOU4.LNAO9K4POETM@bootlin.com/ -- Alexis Lothoré, Bootlin Embedded Linux and Kernel engineering https://bootlin.com ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH dwarves v2] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems 2025-05-08 9:38 ` Alexis Lothoré @ 2025-05-09 5:21 ` Tony Ambardar 2025-05-09 8:33 ` Alexis Lothoré 0 siblings, 1 reply; 15+ messages in thread From: Tony Ambardar @ 2025-05-09 5:21 UTC (permalink / raw) To: Alexis Lothoré Cc: dwarves, bpf, Alan Maguire, Arnaldo Carvalho de Melo, Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann Hi Alexis, On Thu, May 08, 2025 at 11:38:06AM +0200, Alexis Lothoré wrote: > Hello, > > On Fri May 2, 2025 at 9:03 AM CEST, Tony Ambardar wrote: > > I encountered an issue building BTF kernels for 32-bit armhf, where many > > functions are missing in BTF data: > > [...] > > > Fixes: a53c58158b76 ("dwarf_loader: Mark functions that do not use expected registers for params") > > Signed-off-by: Tony Ambardar <tony.ambardar@gmail.com> > > I encountered some issues with pahole 1.30 when trying to generate BTF data > for functions having some __int128 values ([1]), and have been redirected > here by Tony. I gave a try to the patch below and confirm that it fixes my > issue: BTF data is now properly generated for my target function, so: > > Tested-by: Alexis Lothoré <alexis.lothore@bootlin.com> > Glad that resolved your issue, and thank you for the extra testing data point. > While at it, to follow-up on Alan's request for more testing, I did the > following: > - build kernel and bpf selftests with pahole 1.30, extract BTF raw data > with bpftool > - repeat with pahole 1.30 + Tony's patch > - I build my kernel for arm64, it is based on bpf-next_base and I use a > defconfig very close to the one used in BPF CI (so based on > tools/testing/selftests/bpf/config*) > Nice! I notice bootlin has worked on several BPF testing contributions, and was wondering if your build is some new standard buildroot/yocto config tailored for BPF testing, and what archs it might support? Reason for asking is I have a large stack of WIP patches for enabling use of test_progs across 64/32-bit archs and cross-compilation, and I'm keen to see other examples of configs, root images, etc. (especially for 32-bit) At the moment I'm targeting 32-bit armhf support to make progress.. > I observe the following when comparing the resulting BTF data with/without > Tony's patch: > - There is no difference on vmlinux BTF data > - For bpf_testmod.ko, there is a slight shift in the first BTF ID (first ID > is 46 with pristine pahole, 47 with patched pahole), which in turns makes > a lot of noise in the diff, but the actual diff seems to be about two new > BTF entries related to my custom function now being properly detected > (BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO) > Right, I noticed the same skew and it does make checking equivalence more complicated. > Alexis > > [1] https://lore.kernel.org/bpf/D9Q73OTLEOU4.LNAO9K4POETM@bootlin.com/ > > -- > Alexis Lothoré, Bootlin > Embedded Linux and Kernel engineering > https://bootlin.com > Thanks again, Tony ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH dwarves v2] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems 2025-05-09 5:21 ` Tony Ambardar @ 2025-05-09 8:33 ` Alexis Lothoré 2025-05-12 8:41 ` Tony Ambardar 0 siblings, 1 reply; 15+ messages in thread From: Alexis Lothoré @ 2025-05-09 8:33 UTC (permalink / raw) To: Tony Ambardar Cc: dwarves, bpf, Alan Maguire, Arnaldo Carvalho de Melo, Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann On Fri May 9, 2025 at 7:21 AM CEST, Tony Ambardar wrote: > Hi Alexis, > > On Thu, May 08, 2025 at 11:38:06AM +0200, Alexis Lothoré wrote: >> Hello, [...] > Nice! I notice bootlin has worked on several BPF testing contributions, > and was wondering if your build is some new standard buildroot/yocto > config tailored for BPF testing, and what archs it might support? Reason > for asking is I have a large stack of WIP patches for enabling use of > test_progs across 64/32-bit archs and cross-compilation, and I'm keen to > see other examples of configs, root images, etc. (especially for 32-bit) > At the moment I'm targeting 32-bit armhf support to make progress.. No, that's really a custom, minimal setup that I am using, based on buildroot. My workflow is roughly the following: - use buildroot to download an arm64 toolchain and build a minimal rootfs. No specific defconfig used, it is a configuration from scratch, with additional tools for development and debugging - configure a kernel for arm64 testing: $ cat tools/testing/selftest/bpf/{config,config.vm,config.aarch64} > .config - use the toolchain downloaded by buildroot to build the kernel - build the selftests with the same toolchain (so I am cross-building those directly from my host, I am not really using vmtest) - run all of those in qemu, and run the selftests directly with test_progs in there Alexis -- Alexis Lothoré, Bootlin Embedded Linux and Kernel engineering https://bootlin.com ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH dwarves v2] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems 2025-05-09 8:33 ` Alexis Lothoré @ 2025-05-12 8:41 ` Tony Ambardar 0 siblings, 0 replies; 15+ messages in thread From: Tony Ambardar @ 2025-05-12 8:41 UTC (permalink / raw) To: Alexis Lothoré Cc: dwarves, bpf, Alan Maguire, Arnaldo Carvalho de Melo, Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann On Fri, May 09, 2025 at 10:33:50AM +0200, Alexis Lothoré wrote: > On Fri May 9, 2025 at 7:21 AM CEST, Tony Ambardar wrote: > > Hi Alexis, > > > > On Thu, May 08, 2025 at 11:38:06AM +0200, Alexis Lothoré wrote: > >> Hello, > > [...] > > > Nice! I notice bootlin has worked on several BPF testing contributions, > > and was wondering if your build is some new standard buildroot/yocto > > config tailored for BPF testing, and what archs it might support? Reason > > for asking is I have a large stack of WIP patches for enabling use of > > test_progs across 64/32-bit archs and cross-compilation, and I'm keen to > > see other examples of configs, root images, etc. (especially for 32-bit) > > At the moment I'm targeting 32-bit armhf support to make progress.. > > No, that's really a custom, minimal setup that I am using, based on > buildroot. My workflow is roughly the following: > - use buildroot to download an arm64 toolchain and build a minimal rootfs. > No specific defconfig used, it is a configuration from scratch, with > additional tools for development and debugging > - configure a kernel for arm64 testing: > $ cat tools/testing/selftest/bpf/{config,config.vm,config.aarch64} > > .config > - use the toolchain downloaded by buildroot to build the kernel > - build the selftests with the same toolchain (so I am cross-building those > directly from my host, I am not really using vmtest) > - run all of those in qemu, and run the selftests directly with test_progs > in there Understood, and thanks for the details. I basically do the same, with only a couple of differences intended to ease adding armhf as a bpf-ci target eventually: - use the Ubuntu arm cross-toolchain to build on x86_64 - use mkrootfs tools from bpf-ci to make a Debian Bookworm rootfs Take care, Tony > > Alexis > > -- > Alexis Lothoré, Bootlin > Embedded Linux and Kernel engineering > https://bootlin.com > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH dwarves v2] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems 2025-05-02 7:03 ` [PATCH dwarves v2] " Tony Ambardar 2025-05-08 9:38 ` Alexis Lothoré @ 2025-05-08 13:24 ` Alan Maguire 2025-05-09 5:22 ` Tony Ambardar 2025-05-22 6:37 ` [PATCH dwarves v3] " Tony Ambardar 2 siblings, 1 reply; 15+ messages in thread From: Alan Maguire @ 2025-05-08 13:24 UTC (permalink / raw) To: Tony Ambardar, dwarves, bpf Cc: Arnaldo Carvalho de Melo, Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann On 02/05/2025 08:03, Tony Ambardar wrote: > I encountered an issue building BTF kernels for 32-bit armhf, where many > functions are missing in BTF data: > > LD vmlinux > BTFIDS vmlinux > WARN: resolve_btfids: unresolved symbol vfs_truncate > WARN: resolve_btfids: unresolved symbol vfs_fallocate > WARN: resolve_btfids: unresolved symbol scx_bpf_select_cpu_dfl > WARN: resolve_btfids: unresolved symbol scx_bpf_pick_idle_cpu_node > WARN: resolve_btfids: unresolved symbol scx_bpf_pick_idle_cpu > WARN: resolve_btfids: unresolved symbol scx_bpf_pick_any_cpu_node > WARN: resolve_btfids: unresolved symbol scx_bpf_pick_any_cpu > WARN: resolve_btfids: unresolved symbol scx_bpf_kick_cpu > WARN: resolve_btfids: unresolved symbol scx_bpf_exit_bstr > WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_nr_queued > WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move_vtime > WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move_to_local > WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move > WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_insert_vtime > WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_insert > WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_vtime_from_dsq > WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_vtime > WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq_set_vtime > WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq_set_slice > WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq > WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch > WARN: resolve_btfids: unresolved symbol scx_bpf_destroy_dsq > WARN: resolve_btfids: unresolved symbol scx_bpf_create_dsq > WARN: resolve_btfids: unresolved symbol scx_bpf_consume > WARN: resolve_btfids: unresolved symbol bpf_throw > WARN: resolve_btfids: unresolved symbol bpf_sock_ops_enable_tx_tstamp > WARN: resolve_btfids: unresolved symbol bpf_percpu_obj_new_impl > WARN: resolve_btfids: unresolved symbol bpf_obj_new_impl > WARN: resolve_btfids: unresolved symbol bpf_lookup_user_key > WARN: resolve_btfids: unresolved symbol bpf_lookup_system_key > WARN: resolve_btfids: unresolved symbol bpf_iter_task_vma_new > WARN: resolve_btfids: unresolved symbol bpf_iter_scx_dsq_new > WARN: resolve_btfids: unresolved symbol bpf_get_kmem_cache > WARN: resolve_btfids: unresolved symbol bpf_dynptr_from_xdp > WARN: resolve_btfids: unresolved symbol bpf_dynptr_from_skb > WARN: resolve_btfids: unresolved symbol bpf_cgroup_from_id > NM System.map > > After further debugging this can be reproduced more simply: > > $ pahole -J -j --btf_features=decl_tag,consistent_func,decl_tag_kfuncs .tmp_vmlinux_armhf > btf_encoder__tag_kfunc: failed to find kfunc 'scx_bpf_select_cpu_dfl' in BTF > btf_encoder__tag_kfuncs: failed to tag kfunc 'scx_bpf_select_cpu_dfl' > > $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf > <nothing> > > $ pfunct -Fdwarf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf > s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); > > $ pahole -J -j --btf_features=decl_tag,decl_tag_kfuncs .tmp_vmlinux_armhf > > $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf > bpf_kfunc s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); > > The key things to note are the pahole 'consistent_func' feature and the u64 > 'wake_flags' parameter vs. arm 32-bit registers. These point to existing > code handling arguments larger than register-size, but only structs. > > Generalize the code for any type of argument misfit to register size (i.e. > zero or > cu->addr_size). This should work for integral or aggregate types, > and also avoids a bug in the current code where a register-sized struct > could be mistaken for larger. > > Fixes: a53c58158b76 ("dwarf_loader: Mark functions that do not use expected registers for params") > Signed-off-by: Tony Ambardar <tony.ambardar@gmail.com> I've tried this on x86_64 and the issue of missing functions has disappeared; I get the exact same number of functions encoded. From a pahole perspective Tested-by: Alan Maguire <alan.maguire@oracle.com> However as mentioned previously I think we need to think a bit about how libbpf for example might accommodate such representations, as the implict assumption for fentry in BPF_PROG() is that the function call register conventions apply. BPF_PROG2() handles the struct case, but not the 0-sized struct case, and in fact there are checks in btf.c that also need to be fixed to enable verification once we have 0-sized struct argument support. So in investigating this I've put together a short RFC series [1] that seems to do the job in 1. fixing up the BPF_PROG2() handling of 0-sized structs. 2. fixing the verification failures with 0-sized parameters, carving out an exception for 0-sized structs. 3. testing the 0-sized struct case to ensure we get the correct data by adding a function with a 0-sized struct parameter to bpf_testmod and adding a tracing_struct test to verify the subsequent arguments are correct. In terms of cadence, I would propose that if the BPF folks are happy with the approach, we land this patch in pahole, then after that try to land the BPF changes. Does that work from your side? Thanks! [1] https://lore.kernel.org/bpf/20250508132237.1817317-1-alan.maguire@oracle.com/ Alan > --- > v1 -> v2: > - Update to preserve existing behaviour where zero-sized struct params > still permit the function to be encoded, as noted by Alan. > > --- > dwarf_loader.c | 37 +++++++++++++------------------------ > 1 file changed, 13 insertions(+), 24 deletions(-) > > diff --git a/dwarf_loader.c b/dwarf_loader.c > index e1ba7bc..abf1717 100644 > --- a/dwarf_loader.c > +++ b/dwarf_loader.c > @@ -2914,23 +2914,11 @@ out: > return 0; > } > > -static bool param__is_struct(struct cu *cu, struct tag *tag) > +static bool param__misfits_reg(struct cu *cu, struct tag *tag) > { > - struct tag *type = cu__type(cu, tag->type); > + size_t sz = tag__size(tag, cu); > > - if (!type) > - return false; > - > - switch (type->tag) { > - case DW_TAG_structure_type: > - return true; > - case DW_TAG_const_type: > - case DW_TAG_typedef: > - /* handle "typedef struct", const parameter */ > - return param__is_struct(cu, type); > - default: > - return false; > - } > + return sz == 0 || sz > cu->addr_size; > } > > static int cu__resolve_func_ret_types_optimized(struct cu *cu) > @@ -2942,9 +2930,9 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) > struct tag *tag = pt->entries[i]; > struct parameter *pos; > struct function *fn = tag__function(tag); > - bool has_unexpected_reg = false, has_struct_param = false; > + bool has_unexpected_reg = false, has_misfit_param = false; > > - /* mark function as optimized if parameter is, or > + /* Mark function as optimized if parameter is, or > * if parameter does not have a location; at this > * point location presence has been marked in > * abstract origins for cases where a parameter > @@ -2953,10 +2941,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) > * > * Also mark functions which, due to optimization, > * use an unexpected register for a parameter. > - * Exception is functions which have a struct > - * as a parameter, as multiple registers may > - * be used to represent it, throwing off register > - * to parameter mapping. > + * Exception is functions with a wide/zero-sized > + * parameter, as single register won't be used > + * to represent it, throwing off register to > + * parameter mapping. Examples include large > + * structs or 64-bit types on a 32-bit arch. > */ > ftype__for_each_parameter(&fn->proto, pos) { > if (pos->optimized || !pos->has_loc) > @@ -2967,11 +2956,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) > } > if (has_unexpected_reg) { > ftype__for_each_parameter(&fn->proto, pos) { > - has_struct_param = param__is_struct(cu, &pos->tag); > - if (has_struct_param) > + has_misfit_param = param__misfits_reg(cu, &pos->tag); > + if (has_misfit_param) > break; > } > - if (!has_struct_param) > + if (!has_misfit_param) > fn->proto.unexpected_reg = 1; > } > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH dwarves v2] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems 2025-05-08 13:24 ` Alan Maguire @ 2025-05-09 5:22 ` Tony Ambardar 0 siblings, 0 replies; 15+ messages in thread From: Tony Ambardar @ 2025-05-09 5:22 UTC (permalink / raw) To: Alan Maguire Cc: dwarves, bpf, Arnaldo Carvalho de Melo, Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann On Thu, May 08, 2025 at 02:24:57PM +0100, Alan Maguire wrote: > On 02/05/2025 08:03, Tony Ambardar wrote: > > I encountered an issue building BTF kernels for 32-bit armhf, where many > > functions are missing in BTF data: > > > > LD vmlinux > > BTFIDS vmlinux > > WARN: resolve_btfids: unresolved symbol vfs_truncate [...] > > > > Fixes: a53c58158b76 ("dwarf_loader: Mark functions that do not use expected registers for params") > > Signed-off-by: Tony Ambardar <tony.ambardar@gmail.com> > Hello Alan, > I've tried this on x86_64 and the issue of missing functions has > disappeared; I get the exact same number of functions encoded. From a > pahole perspective > > Tested-by: Alan Maguire <alan.maguire@oracle.com> > Thanks for reviewing the latest update and putting it through its paces. I was noticing many small changes in my own testing so this is welcome confirmation. > However as mentioned previously I think we need to think a bit about how > libbpf for example might accommodate such representations, as the > implict assumption for fentry in BPF_PROG() is that the function call > register conventions apply. BPF_PROG2() handles the struct case, but not > the 0-sized struct case, and in fact there are checks in btf.c that also > need to be fixed to enable verification once we have 0-sized struct > argument support. > > So in investigating this I've put together a short RFC series [1] that > seems to do the job in > > 1. fixing up the BPF_PROG2() handling of 0-sized structs. > 2. fixing the verification failures with 0-sized parameters, carving out > an exception for 0-sized structs. > 3. testing the 0-sized struct case to ensure we get the correct data by > adding a function with a 0-sized struct parameter to bpf_testmod and > adding a tracing_struct test to verify the subsequent arguments are correct. > OK, I'll try looking at this for 32-bit armhf since I'm in the middle of that, and comment in the RFC thread. > In terms of cadence, I would propose that if the BPF folks are happy > with the approach, we land this patch in pahole, then after that try to > land the BPF changes. Does that work from your side? Thanks! > > [1] > https://lore.kernel.org/bpf/20250508132237.1817317-1-alan.maguire@oracle.com/ > > Alan > Thanks, Tony [...] ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH dwarves v3] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems 2025-05-02 7:03 ` [PATCH dwarves v2] " Tony Ambardar 2025-05-08 9:38 ` Alexis Lothoré 2025-05-08 13:24 ` Alan Maguire @ 2025-05-22 6:37 ` Tony Ambardar 2025-06-24 16:14 ` Alan Maguire 2 siblings, 1 reply; 15+ messages in thread From: Tony Ambardar @ 2025-05-22 6:37 UTC (permalink / raw) To: dwarves, bpf Cc: Tony Ambardar, Alan Maguire, Arnaldo Carvalho de Melo, Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann, Alexis Lothoré I encountered an issue building BTF kernels for 32-bit armhf, where many functions are missing in BTF data: LD vmlinux BTFIDS vmlinux WARN: resolve_btfids: unresolved symbol vfs_truncate WARN: resolve_btfids: unresolved symbol vfs_fallocate WARN: resolve_btfids: unresolved symbol scx_bpf_select_cpu_dfl WARN: resolve_btfids: unresolved symbol scx_bpf_pick_idle_cpu_node WARN: resolve_btfids: unresolved symbol scx_bpf_pick_idle_cpu WARN: resolve_btfids: unresolved symbol scx_bpf_pick_any_cpu_node WARN: resolve_btfids: unresolved symbol scx_bpf_pick_any_cpu WARN: resolve_btfids: unresolved symbol scx_bpf_kick_cpu WARN: resolve_btfids: unresolved symbol scx_bpf_exit_bstr WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_nr_queued WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move_vtime WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move_to_local WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_insert_vtime WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_insert WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_vtime_from_dsq WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_vtime WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq_set_vtime WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq_set_slice WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch WARN: resolve_btfids: unresolved symbol scx_bpf_destroy_dsq WARN: resolve_btfids: unresolved symbol scx_bpf_create_dsq WARN: resolve_btfids: unresolved symbol scx_bpf_consume WARN: resolve_btfids: unresolved symbol bpf_throw WARN: resolve_btfids: unresolved symbol bpf_sock_ops_enable_tx_tstamp WARN: resolve_btfids: unresolved symbol bpf_percpu_obj_new_impl WARN: resolve_btfids: unresolved symbol bpf_obj_new_impl WARN: resolve_btfids: unresolved symbol bpf_lookup_user_key WARN: resolve_btfids: unresolved symbol bpf_lookup_system_key WARN: resolve_btfids: unresolved symbol bpf_iter_task_vma_new WARN: resolve_btfids: unresolved symbol bpf_iter_scx_dsq_new WARN: resolve_btfids: unresolved symbol bpf_get_kmem_cache WARN: resolve_btfids: unresolved symbol bpf_dynptr_from_xdp WARN: resolve_btfids: unresolved symbol bpf_dynptr_from_skb WARN: resolve_btfids: unresolved symbol bpf_cgroup_from_id NM System.map After further debugging this can be reproduced more simply: $ pahole -J -j --btf_features=decl_tag,consistent_func,decl_tag_kfuncs .tmp_vmlinux_armhf btf_encoder__tag_kfunc: failed to find kfunc 'scx_bpf_select_cpu_dfl' in BTF btf_encoder__tag_kfuncs: failed to tag kfunc 'scx_bpf_select_cpu_dfl' $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf <nothing> $ pfunct -Fdwarf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); $ pahole -J -j --btf_features=decl_tag,decl_tag_kfuncs .tmp_vmlinux_armhf $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf bpf_kfunc s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); The key things to note are the pahole 'consistent_func' feature and the u64 'wake_flags' parameter vs. arm 32-bit registers. These point to existing code handling arguments larger than register-size, allowing them to be BTF encoded but only if structs. Generalize the code for any argument type larger than register size (i.e. size > cu->addr_size). This should work for integral or aggregate types, and also avoids a bug in the current code where a register-sized struct could be mistaken for larger. Note that zero-sized arguments will still be marked as inconsistent and not encoded. Fixes: a53c58158b76 ("dwarf_loader: Mark functions that do not use expected registers for params") Tested-by: Alexis Lothoré <alexis.lothore@bootlin.com> Tested-by: Alan Maguire <alan.maguire@oracle.com> Signed-off-by: Tony Ambardar <tony.ambardar@gmail.com> --- v2 -> v3: - Added Tested-by: from Alexis and Alan. - Revert support for encoding 0-sized structs (as v1) after discussion: https://lore.kernel.org/dwarves/9a41b21f-c0ae-4298-bf95-09d0cdc3f3ab@oracle.com/ - Inline param__is_wide() and clarify some naming/wording. v1 -> v2: - Update to preserve existing behaviour where zero-sized struct params still permit the function to be encoded, as noted by Alan. --- dwarf_loader.c | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/dwarf_loader.c b/dwarf_loader.c index e1ba7bc..134a76b 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -2914,23 +2914,9 @@ out: return 0; } -static bool param__is_struct(struct cu *cu, struct tag *tag) +static inline bool param__is_wide(struct cu *cu, struct tag *tag) { - struct tag *type = cu__type(cu, tag->type); - - if (!type) - return false; - - switch (type->tag) { - case DW_TAG_structure_type: - return true; - case DW_TAG_const_type: - case DW_TAG_typedef: - /* handle "typedef struct", const parameter */ - return param__is_struct(cu, type); - default: - return false; - } + return tag__size(tag, cu) > cu->addr_size; } static int cu__resolve_func_ret_types_optimized(struct cu *cu) @@ -2942,9 +2928,9 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) struct tag *tag = pt->entries[i]; struct parameter *pos; struct function *fn = tag__function(tag); - bool has_unexpected_reg = false, has_struct_param = false; + bool has_unexpected_reg = false, has_wide_param = false; - /* mark function as optimized if parameter is, or + /* Mark function as optimized if parameter is, or * if parameter does not have a location; at this * point location presence has been marked in * abstract origins for cases where a parameter @@ -2953,10 +2939,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) * * Also mark functions which, due to optimization, * use an unexpected register for a parameter. - * Exception is functions which have a struct - * as a parameter, as multiple registers may - * be used to represent it, throwing off register - * to parameter mapping. + * Exception is functions with a wide parameter, + * as single register won't be used to represent + * it, throwing off register to parameter mapping. + * Examples include large structs or 64-bit types + * on a 32-bit arch. */ ftype__for_each_parameter(&fn->proto, pos) { if (pos->optimized || !pos->has_loc) @@ -2967,11 +2954,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) } if (has_unexpected_reg) { ftype__for_each_parameter(&fn->proto, pos) { - has_struct_param = param__is_struct(cu, &pos->tag); - if (has_struct_param) + has_wide_param = param__is_wide(cu, &pos->tag); + if (has_wide_param) break; } - if (!has_struct_param) + if (!has_wide_param) fn->proto.unexpected_reg = 1; } -- 2.34.1 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH dwarves v3] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems 2025-05-22 6:37 ` [PATCH dwarves v3] " Tony Ambardar @ 2025-06-24 16:14 ` Alan Maguire 2025-06-30 10:01 ` Alan Maguire 0 siblings, 1 reply; 15+ messages in thread From: Alan Maguire @ 2025-06-24 16:14 UTC (permalink / raw) To: Tony Ambardar, dwarves, bpf Cc: Arnaldo Carvalho de Melo, Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann, Alexis Lothoré On 22/05/2025 07:37, Tony Ambardar wrote: > I encountered an issue building BTF kernels for 32-bit armhf, where many > functions are missing in BTF data: > > LD vmlinux > BTFIDS vmlinux > WARN: resolve_btfids: unresolved symbol vfs_truncate > WARN: resolve_btfids: unresolved symbol vfs_fallocate > WARN: resolve_btfids: unresolved symbol scx_bpf_select_cpu_dfl > WARN: resolve_btfids: unresolved symbol scx_bpf_pick_idle_cpu_node > WARN: resolve_btfids: unresolved symbol scx_bpf_pick_idle_cpu > WARN: resolve_btfids: unresolved symbol scx_bpf_pick_any_cpu_node > WARN: resolve_btfids: unresolved symbol scx_bpf_pick_any_cpu > WARN: resolve_btfids: unresolved symbol scx_bpf_kick_cpu > WARN: resolve_btfids: unresolved symbol scx_bpf_exit_bstr > WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_nr_queued > WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move_vtime > WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move_to_local > WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move > WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_insert_vtime > WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_insert > WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_vtime_from_dsq > WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_vtime > WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq_set_vtime > WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq_set_slice > WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq > WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch > WARN: resolve_btfids: unresolved symbol scx_bpf_destroy_dsq > WARN: resolve_btfids: unresolved symbol scx_bpf_create_dsq > WARN: resolve_btfids: unresolved symbol scx_bpf_consume > WARN: resolve_btfids: unresolved symbol bpf_throw > WARN: resolve_btfids: unresolved symbol bpf_sock_ops_enable_tx_tstamp > WARN: resolve_btfids: unresolved symbol bpf_percpu_obj_new_impl > WARN: resolve_btfids: unresolved symbol bpf_obj_new_impl > WARN: resolve_btfids: unresolved symbol bpf_lookup_user_key > WARN: resolve_btfids: unresolved symbol bpf_lookup_system_key > WARN: resolve_btfids: unresolved symbol bpf_iter_task_vma_new > WARN: resolve_btfids: unresolved symbol bpf_iter_scx_dsq_new > WARN: resolve_btfids: unresolved symbol bpf_get_kmem_cache > WARN: resolve_btfids: unresolved symbol bpf_dynptr_from_xdp > WARN: resolve_btfids: unresolved symbol bpf_dynptr_from_skb > WARN: resolve_btfids: unresolved symbol bpf_cgroup_from_id > NM System.map > > After further debugging this can be reproduced more simply: > > $ pahole -J -j --btf_features=decl_tag,consistent_func,decl_tag_kfuncs .tmp_vmlinux_armhf > btf_encoder__tag_kfunc: failed to find kfunc 'scx_bpf_select_cpu_dfl' in BTF > btf_encoder__tag_kfuncs: failed to tag kfunc 'scx_bpf_select_cpu_dfl' > > $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf > <nothing> > > $ pfunct -Fdwarf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf > s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); > > $ pahole -J -j --btf_features=decl_tag,decl_tag_kfuncs .tmp_vmlinux_armhf > > $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf > bpf_kfunc s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); > > The key things to note are the pahole 'consistent_func' feature and the u64 > 'wake_flags' parameter vs. arm 32-bit registers. These point to existing > code handling arguments larger than register-size, allowing them to be > BTF encoded but only if structs. > > Generalize the code for any argument type larger than register size (i.e. > size > cu->addr_size). This should work for integral or aggregate types, > and also avoids a bug in the current code where a register-sized struct > could be mistaken for larger. Note that zero-sized arguments will still > be marked as inconsistent and not encoded. > > Fixes: a53c58158b76 ("dwarf_loader: Mark functions that do not use expected registers for params") > Tested-by: Alexis Lothoré <alexis.lothore@bootlin.com> > Tested-by: Alan Maguire <alan.maguire@oracle.com> > Signed-off-by: Tony Ambardar <tony.ambardar@gmail.com> hi Tony, I'm planning on landing this shortly unless anyone objects; and on that topic if anyone has the cycles to test with this patch that would be great! I ran it through the work-in-progress BTF comparison in github CI and all looks good; see the "Compare functions generated" step in [1]. Thanks! Alan [1] https://github.com/alan-maguire/dwarves/actions/runs/15854137212 > --- > v2 -> v3: > - Added Tested-by: from Alexis and Alan. > - Revert support for encoding 0-sized structs (as v1) after discussion: > https://lore.kernel.org/dwarves/9a41b21f-c0ae-4298-bf95-09d0cdc3f3ab@oracle.com/ > - Inline param__is_wide() and clarify some naming/wording. > > v1 -> v2: > - Update to preserve existing behaviour where zero-sized struct params > still permit the function to be encoded, as noted by Alan. > > --- > dwarf_loader.c | 37 ++++++++++++------------------------- > 1 file changed, 12 insertions(+), 25 deletions(-) > > diff --git a/dwarf_loader.c b/dwarf_loader.c > index e1ba7bc..134a76b 100644 > --- a/dwarf_loader.c > +++ b/dwarf_loader.c > @@ -2914,23 +2914,9 @@ out: > return 0; > } > > -static bool param__is_struct(struct cu *cu, struct tag *tag) > +static inline bool param__is_wide(struct cu *cu, struct tag *tag) > { > - struct tag *type = cu__type(cu, tag->type); > - > - if (!type) > - return false; > - > - switch (type->tag) { > - case DW_TAG_structure_type: > - return true; > - case DW_TAG_const_type: > - case DW_TAG_typedef: > - /* handle "typedef struct", const parameter */ > - return param__is_struct(cu, type); > - default: > - return false; > - } > + return tag__size(tag, cu) > cu->addr_size; > } > > static int cu__resolve_func_ret_types_optimized(struct cu *cu) > @@ -2942,9 +2928,9 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) > struct tag *tag = pt->entries[i]; > struct parameter *pos; > struct function *fn = tag__function(tag); > - bool has_unexpected_reg = false, has_struct_param = false; > + bool has_unexpected_reg = false, has_wide_param = false; > > - /* mark function as optimized if parameter is, or > + /* Mark function as optimized if parameter is, or > * if parameter does not have a location; at this > * point location presence has been marked in > * abstract origins for cases where a parameter > @@ -2953,10 +2939,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) > * > * Also mark functions which, due to optimization, > * use an unexpected register for a parameter. > - * Exception is functions which have a struct > - * as a parameter, as multiple registers may > - * be used to represent it, throwing off register > - * to parameter mapping. > + * Exception is functions with a wide parameter, > + * as single register won't be used to represent > + * it, throwing off register to parameter mapping. > + * Examples include large structs or 64-bit types > + * on a 32-bit arch. > */ > ftype__for_each_parameter(&fn->proto, pos) { > if (pos->optimized || !pos->has_loc) > @@ -2967,11 +2954,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) > } > if (has_unexpected_reg) { > ftype__for_each_parameter(&fn->proto, pos) { > - has_struct_param = param__is_struct(cu, &pos->tag); > - if (has_struct_param) > + has_wide_param = param__is_wide(cu, &pos->tag); > + if (has_wide_param) > break; > } > - if (!has_struct_param) > + if (!has_wide_param) > fn->proto.unexpected_reg = 1; > } > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH dwarves v3] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems 2025-06-24 16:14 ` Alan Maguire @ 2025-06-30 10:01 ` Alan Maguire 2025-06-30 13:51 ` Jiri Olsa 0 siblings, 1 reply; 15+ messages in thread From: Alan Maguire @ 2025-06-30 10:01 UTC (permalink / raw) To: Tony Ambardar, dwarves, bpf Cc: Arnaldo Carvalho de Melo, Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann, Alexis Lothoré On 24/06/2025 17:14, Alan Maguire wrote: > On 22/05/2025 07:37, Tony Ambardar wrote: >> I encountered an issue building BTF kernels for 32-bit armhf, where many >> functions are missing in BTF data: >> >> LD vmlinux >> BTFIDS vmlinux >> WARN: resolve_btfids: unresolved symbol vfs_truncate >> WARN: resolve_btfids: unresolved symbol vfs_fallocate >> WARN: resolve_btfids: unresolved symbol scx_bpf_select_cpu_dfl >> WARN: resolve_btfids: unresolved symbol scx_bpf_pick_idle_cpu_node >> WARN: resolve_btfids: unresolved symbol scx_bpf_pick_idle_cpu >> WARN: resolve_btfids: unresolved symbol scx_bpf_pick_any_cpu_node >> WARN: resolve_btfids: unresolved symbol scx_bpf_pick_any_cpu >> WARN: resolve_btfids: unresolved symbol scx_bpf_kick_cpu >> WARN: resolve_btfids: unresolved symbol scx_bpf_exit_bstr >> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_nr_queued >> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move_vtime >> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move_to_local >> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move >> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_insert_vtime >> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_insert >> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_vtime_from_dsq >> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_vtime >> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq_set_vtime >> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq_set_slice >> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq >> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch >> WARN: resolve_btfids: unresolved symbol scx_bpf_destroy_dsq >> WARN: resolve_btfids: unresolved symbol scx_bpf_create_dsq >> WARN: resolve_btfids: unresolved symbol scx_bpf_consume >> WARN: resolve_btfids: unresolved symbol bpf_throw >> WARN: resolve_btfids: unresolved symbol bpf_sock_ops_enable_tx_tstamp >> WARN: resolve_btfids: unresolved symbol bpf_percpu_obj_new_impl >> WARN: resolve_btfids: unresolved symbol bpf_obj_new_impl >> WARN: resolve_btfids: unresolved symbol bpf_lookup_user_key >> WARN: resolve_btfids: unresolved symbol bpf_lookup_system_key >> WARN: resolve_btfids: unresolved symbol bpf_iter_task_vma_new >> WARN: resolve_btfids: unresolved symbol bpf_iter_scx_dsq_new >> WARN: resolve_btfids: unresolved symbol bpf_get_kmem_cache >> WARN: resolve_btfids: unresolved symbol bpf_dynptr_from_xdp >> WARN: resolve_btfids: unresolved symbol bpf_dynptr_from_skb >> WARN: resolve_btfids: unresolved symbol bpf_cgroup_from_id >> NM System.map >> >> After further debugging this can be reproduced more simply: >> >> $ pahole -J -j --btf_features=decl_tag,consistent_func,decl_tag_kfuncs .tmp_vmlinux_armhf >> btf_encoder__tag_kfunc: failed to find kfunc 'scx_bpf_select_cpu_dfl' in BTF >> btf_encoder__tag_kfuncs: failed to tag kfunc 'scx_bpf_select_cpu_dfl' >> >> $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf >> <nothing> >> >> $ pfunct -Fdwarf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf >> s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); >> >> $ pahole -J -j --btf_features=decl_tag,decl_tag_kfuncs .tmp_vmlinux_armhf >> >> $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf >> bpf_kfunc s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); >> >> The key things to note are the pahole 'consistent_func' feature and the u64 >> 'wake_flags' parameter vs. arm 32-bit registers. These point to existing >> code handling arguments larger than register-size, allowing them to be >> BTF encoded but only if structs. >> >> Generalize the code for any argument type larger than register size (i.e. >> size > cu->addr_size). This should work for integral or aggregate types, >> and also avoids a bug in the current code where a register-sized struct >> could be mistaken for larger. Note that zero-sized arguments will still >> be marked as inconsistent and not encoded. >> >> Fixes: a53c58158b76 ("dwarf_loader: Mark functions that do not use expected registers for params") >> Tested-by: Alexis Lothoré <alexis.lothore@bootlin.com> >> Tested-by: Alan Maguire <alan.maguire@oracle.com> >> Signed-off-by: Tony Ambardar <tony.ambardar@gmail.com> > > hi Tony, > > I'm planning on landing this shortly unless anyone objects; and on that > topic if anyone has the cycles to test with this patch that would be > great! I ran it through the work-in-progress BTF comparison in github CI > and all looks good; see the "Compare functions generated" step in [1]. > > Thanks! > In fact I spoke too soon; there was a bug in the function comparison. After that was fixed, I reran with this patch; see [1]. It shows that - as expected - functions with 0-sized params are left out, specifically < int __io_run_local_work(struct io_ring_ctx * ctx, io_tw_token_t tw, int min_events, int max_events); < int __io_run_local_work_loop(struct llist_node * * node, io_tw_token_t tw, int events); We expect this since io_tw_token_t is 0-sized. However on x86_64 it did show one _extra_ function that I didn't expect: > int __vxlan_fdb_delete(struct vxlan_dev * vxlan, const unsigned char * addr, union vxlan_addr ip, __be16 port, __be32 src_vni, __be32 vni, u32 ifindex, bool swdev_notify); It's not clear to me why that function was added with this change - I would have expected it either with or without the change. Any idea why that might be? [1] https://github.com/alan-maguire/dwarves/actions/runs/15872520906/job/44752273776 > Alan > > [1] https://github.com/alan-maguire/dwarves/actions/runs/15854137212 > >> --- >> v2 -> v3: >> - Added Tested-by: from Alexis and Alan. >> - Revert support for encoding 0-sized structs (as v1) after discussion: >> https://lore.kernel.org/dwarves/9a41b21f-c0ae-4298-bf95-09d0cdc3f3ab@oracle.com/ >> - Inline param__is_wide() and clarify some naming/wording. >> >> v1 -> v2: >> - Update to preserve existing behaviour where zero-sized struct params >> still permit the function to be encoded, as noted by Alan. >> >> --- >> dwarf_loader.c | 37 ++++++++++++------------------------- >> 1 file changed, 12 insertions(+), 25 deletions(-) >> >> diff --git a/dwarf_loader.c b/dwarf_loader.c >> index e1ba7bc..134a76b 100644 >> --- a/dwarf_loader.c >> +++ b/dwarf_loader.c >> @@ -2914,23 +2914,9 @@ out: >> return 0; >> } >> >> -static bool param__is_struct(struct cu *cu, struct tag *tag) >> +static inline bool param__is_wide(struct cu *cu, struct tag *tag) >> { >> - struct tag *type = cu__type(cu, tag->type); >> - >> - if (!type) >> - return false; >> - >> - switch (type->tag) { >> - case DW_TAG_structure_type: >> - return true; >> - case DW_TAG_const_type: >> - case DW_TAG_typedef: >> - /* handle "typedef struct", const parameter */ >> - return param__is_struct(cu, type); >> - default: >> - return false; >> - } >> + return tag__size(tag, cu) > cu->addr_size; >> } >> >> static int cu__resolve_func_ret_types_optimized(struct cu *cu) >> @@ -2942,9 +2928,9 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) >> struct tag *tag = pt->entries[i]; >> struct parameter *pos; >> struct function *fn = tag__function(tag); >> - bool has_unexpected_reg = false, has_struct_param = false; >> + bool has_unexpected_reg = false, has_wide_param = false; >> >> - /* mark function as optimized if parameter is, or >> + /* Mark function as optimized if parameter is, or >> * if parameter does not have a location; at this >> * point location presence has been marked in >> * abstract origins for cases where a parameter >> @@ -2953,10 +2939,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) >> * >> * Also mark functions which, due to optimization, >> * use an unexpected register for a parameter. >> - * Exception is functions which have a struct >> - * as a parameter, as multiple registers may >> - * be used to represent it, throwing off register >> - * to parameter mapping. >> + * Exception is functions with a wide parameter, >> + * as single register won't be used to represent >> + * it, throwing off register to parameter mapping. >> + * Examples include large structs or 64-bit types >> + * on a 32-bit arch. >> */ >> ftype__for_each_parameter(&fn->proto, pos) { >> if (pos->optimized || !pos->has_loc) >> @@ -2967,11 +2954,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) >> } >> if (has_unexpected_reg) { >> ftype__for_each_parameter(&fn->proto, pos) { >> - has_struct_param = param__is_struct(cu, &pos->tag); >> - if (has_struct_param) >> + has_wide_param = param__is_wide(cu, &pos->tag); >> + if (has_wide_param) >> break; >> } >> - if (!has_struct_param) >> + if (!has_wide_param) >> fn->proto.unexpected_reg = 1; >> } >> > > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH dwarves v3] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems 2025-06-30 10:01 ` Alan Maguire @ 2025-06-30 13:51 ` Jiri Olsa 2025-06-30 17:32 ` Alan Maguire 0 siblings, 1 reply; 15+ messages in thread From: Jiri Olsa @ 2025-06-30 13:51 UTC (permalink / raw) To: Alan Maguire Cc: Tony Ambardar, dwarves, bpf, Arnaldo Carvalho de Melo, Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann, Alexis Lothoré On Mon, Jun 30, 2025 at 11:01:19AM +0100, Alan Maguire wrote: > On 24/06/2025 17:14, Alan Maguire wrote: > > On 22/05/2025 07:37, Tony Ambardar wrote: > >> I encountered an issue building BTF kernels for 32-bit armhf, where many > >> functions are missing in BTF data: > >> > >> LD vmlinux > >> BTFIDS vmlinux > >> WARN: resolve_btfids: unresolved symbol vfs_truncate > >> WARN: resolve_btfids: unresolved symbol vfs_fallocate > >> WARN: resolve_btfids: unresolved symbol scx_bpf_select_cpu_dfl > >> WARN: resolve_btfids: unresolved symbol scx_bpf_pick_idle_cpu_node > >> WARN: resolve_btfids: unresolved symbol scx_bpf_pick_idle_cpu > >> WARN: resolve_btfids: unresolved symbol scx_bpf_pick_any_cpu_node > >> WARN: resolve_btfids: unresolved symbol scx_bpf_pick_any_cpu > >> WARN: resolve_btfids: unresolved symbol scx_bpf_kick_cpu > >> WARN: resolve_btfids: unresolved symbol scx_bpf_exit_bstr > >> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_nr_queued > >> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move_vtime > >> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move_to_local > >> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move > >> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_insert_vtime > >> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_insert > >> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_vtime_from_dsq > >> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_vtime > >> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq_set_vtime > >> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq_set_slice > >> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq > >> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch > >> WARN: resolve_btfids: unresolved symbol scx_bpf_destroy_dsq > >> WARN: resolve_btfids: unresolved symbol scx_bpf_create_dsq > >> WARN: resolve_btfids: unresolved symbol scx_bpf_consume > >> WARN: resolve_btfids: unresolved symbol bpf_throw > >> WARN: resolve_btfids: unresolved symbol bpf_sock_ops_enable_tx_tstamp > >> WARN: resolve_btfids: unresolved symbol bpf_percpu_obj_new_impl > >> WARN: resolve_btfids: unresolved symbol bpf_obj_new_impl > >> WARN: resolve_btfids: unresolved symbol bpf_lookup_user_key > >> WARN: resolve_btfids: unresolved symbol bpf_lookup_system_key > >> WARN: resolve_btfids: unresolved symbol bpf_iter_task_vma_new > >> WARN: resolve_btfids: unresolved symbol bpf_iter_scx_dsq_new > >> WARN: resolve_btfids: unresolved symbol bpf_get_kmem_cache > >> WARN: resolve_btfids: unresolved symbol bpf_dynptr_from_xdp > >> WARN: resolve_btfids: unresolved symbol bpf_dynptr_from_skb > >> WARN: resolve_btfids: unresolved symbol bpf_cgroup_from_id > >> NM System.map > >> > >> After further debugging this can be reproduced more simply: > >> > >> $ pahole -J -j --btf_features=decl_tag,consistent_func,decl_tag_kfuncs .tmp_vmlinux_armhf > >> btf_encoder__tag_kfunc: failed to find kfunc 'scx_bpf_select_cpu_dfl' in BTF > >> btf_encoder__tag_kfuncs: failed to tag kfunc 'scx_bpf_select_cpu_dfl' > >> > >> $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf > >> <nothing> > >> > >> $ pfunct -Fdwarf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf > >> s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); > >> > >> $ pahole -J -j --btf_features=decl_tag,decl_tag_kfuncs .tmp_vmlinux_armhf > >> > >> $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf > >> bpf_kfunc s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); > >> > >> The key things to note are the pahole 'consistent_func' feature and the u64 > >> 'wake_flags' parameter vs. arm 32-bit registers. These point to existing > >> code handling arguments larger than register-size, allowing them to be > >> BTF encoded but only if structs. > >> > >> Generalize the code for any argument type larger than register size (i.e. > >> size > cu->addr_size). This should work for integral or aggregate types, > >> and also avoids a bug in the current code where a register-sized struct > >> could be mistaken for larger. Note that zero-sized arguments will still > >> be marked as inconsistent and not encoded. > >> > >> Fixes: a53c58158b76 ("dwarf_loader: Mark functions that do not use expected registers for params") > >> Tested-by: Alexis Lothoré <alexis.lothore@bootlin.com> > >> Tested-by: Alan Maguire <alan.maguire@oracle.com> > >> Signed-off-by: Tony Ambardar <tony.ambardar@gmail.com> > > > > hi Tony, > > > > I'm planning on landing this shortly unless anyone objects; and on that > > topic if anyone has the cycles to test with this patch that would be > > great! I ran it through the work-in-progress BTF comparison in github CI > > and all looks good; see the "Compare functions generated" step in [1]. > > > > Thanks! > > > > In fact I spoke too soon; there was a bug in the function comparison. > After that was fixed, I reran with this patch; see [1]. > > It shows that - as expected - functions with 0-sized params are left > out, specifically > > < int __io_run_local_work(struct io_ring_ctx * ctx, io_tw_token_t tw, > int min_events, int max_events); > < int __io_run_local_work_loop(struct llist_node * * node, io_tw_token_t > tw, int events); > > We expect this since io_tw_token_t is 0-sized. However on x86_64 it did > show one _extra_ function that I didn't expect: > > > int __vxlan_fdb_delete(struct vxlan_dev * vxlan, const unsigned char > * addr, union vxlan_addr ip, __be16 port, __be32 src_vni, __be32 vni, > u32 ifindex, bool swdev_notify); > > It's not clear to me why that function was added with this change - I > would have expected it either with or without the change. Any idea why > that might be? hi, I can see that as well, IIUC the 'ip' argument is: union vxlan_addr { struct sockaddr_in sin; struct sockaddr_in6 sin6; struct sockaddr sa; }; so we have struct as 4th argument, which sets the has_wide_param condition and won't set the fn->proto.unexpected_reg for the function, because of: if (!has_wide_param) fn->proto.unexpected_reg = 1; I'm not sure it's correct.. if the ip struct is big enough that it's passed on stack, why are the rest of the arguments marked with unexpected_reg (in parameter__new) I think I'm missing something jirka > > [1] > https://github.com/alan-maguire/dwarves/actions/runs/15872520906/job/44752273776 > > > Alan > > > > [1] https://github.com/alan-maguire/dwarves/actions/runs/15854137212 > > > >> --- > >> v2 -> v3: > >> - Added Tested-by: from Alexis and Alan. > >> - Revert support for encoding 0-sized structs (as v1) after discussion: > >> https://lore.kernel.org/dwarves/9a41b21f-c0ae-4298-bf95-09d0cdc3f3ab@oracle.com/ > >> - Inline param__is_wide() and clarify some naming/wording. > >> > >> v1 -> v2: > >> - Update to preserve existing behaviour where zero-sized struct params > >> still permit the function to be encoded, as noted by Alan. > >> > >> --- > >> dwarf_loader.c | 37 ++++++++++++------------------------- > >> 1 file changed, 12 insertions(+), 25 deletions(-) > >> > >> diff --git a/dwarf_loader.c b/dwarf_loader.c > >> index e1ba7bc..134a76b 100644 > >> --- a/dwarf_loader.c > >> +++ b/dwarf_loader.c > >> @@ -2914,23 +2914,9 @@ out: > >> return 0; > >> } > >> > >> -static bool param__is_struct(struct cu *cu, struct tag *tag) > >> +static inline bool param__is_wide(struct cu *cu, struct tag *tag) > >> { > >> - struct tag *type = cu__type(cu, tag->type); > >> - > >> - if (!type) > >> - return false; > >> - > >> - switch (type->tag) { > >> - case DW_TAG_structure_type: > >> - return true; > >> - case DW_TAG_const_type: > >> - case DW_TAG_typedef: > >> - /* handle "typedef struct", const parameter */ > >> - return param__is_struct(cu, type); > >> - default: > >> - return false; > >> - } > >> + return tag__size(tag, cu) > cu->addr_size; > >> } > >> > >> static int cu__resolve_func_ret_types_optimized(struct cu *cu) > >> @@ -2942,9 +2928,9 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) > >> struct tag *tag = pt->entries[i]; > >> struct parameter *pos; > >> struct function *fn = tag__function(tag); > >> - bool has_unexpected_reg = false, has_struct_param = false; > >> + bool has_unexpected_reg = false, has_wide_param = false; > >> > >> - /* mark function as optimized if parameter is, or > >> + /* Mark function as optimized if parameter is, or > >> * if parameter does not have a location; at this > >> * point location presence has been marked in > >> * abstract origins for cases where a parameter > >> @@ -2953,10 +2939,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) > >> * > >> * Also mark functions which, due to optimization, > >> * use an unexpected register for a parameter. > >> - * Exception is functions which have a struct > >> - * as a parameter, as multiple registers may > >> - * be used to represent it, throwing off register > >> - * to parameter mapping. > >> + * Exception is functions with a wide parameter, > >> + * as single register won't be used to represent > >> + * it, throwing off register to parameter mapping. > >> + * Examples include large structs or 64-bit types > >> + * on a 32-bit arch. > >> */ > >> ftype__for_each_parameter(&fn->proto, pos) { > >> if (pos->optimized || !pos->has_loc) > >> @@ -2967,11 +2954,11 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) > >> } > >> if (has_unexpected_reg) { > >> ftype__for_each_parameter(&fn->proto, pos) { > >> - has_struct_param = param__is_struct(cu, &pos->tag); > >> - if (has_struct_param) > >> + has_wide_param = param__is_wide(cu, &pos->tag); > >> + if (has_wide_param) > >> break; > >> } > >> - if (!has_struct_param) > >> + if (!has_wide_param) > >> fn->proto.unexpected_reg = 1; > >> } > >> > > > > > > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH dwarves v3] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems 2025-06-30 13:51 ` Jiri Olsa @ 2025-06-30 17:32 ` Alan Maguire 0 siblings, 0 replies; 15+ messages in thread From: Alan Maguire @ 2025-06-30 17:32 UTC (permalink / raw) To: Jiri Olsa Cc: Tony Ambardar, dwarves, bpf, Arnaldo Carvalho de Melo, Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann, Alexis Lothoré On 30/06/2025 14:51, Jiri Olsa wrote: > On Mon, Jun 30, 2025 at 11:01:19AM +0100, Alan Maguire wrote: >> On 24/06/2025 17:14, Alan Maguire wrote: >>> On 22/05/2025 07:37, Tony Ambardar wrote: >>>> I encountered an issue building BTF kernels for 32-bit armhf, where many >>>> functions are missing in BTF data: >>>> >>>> LD vmlinux >>>> BTFIDS vmlinux >>>> WARN: resolve_btfids: unresolved symbol vfs_truncate >>>> WARN: resolve_btfids: unresolved symbol vfs_fallocate >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_select_cpu_dfl >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_pick_idle_cpu_node >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_pick_idle_cpu >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_pick_any_cpu_node >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_pick_any_cpu >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_kick_cpu >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_exit_bstr >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_nr_queued >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move_vtime >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move_to_local >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_move >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_insert_vtime >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_dsq_insert >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_vtime_from_dsq >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_vtime >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq_set_vtime >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq_set_slice >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch_from_dsq >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_dispatch >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_destroy_dsq >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_create_dsq >>>> WARN: resolve_btfids: unresolved symbol scx_bpf_consume >>>> WARN: resolve_btfids: unresolved symbol bpf_throw >>>> WARN: resolve_btfids: unresolved symbol bpf_sock_ops_enable_tx_tstamp >>>> WARN: resolve_btfids: unresolved symbol bpf_percpu_obj_new_impl >>>> WARN: resolve_btfids: unresolved symbol bpf_obj_new_impl >>>> WARN: resolve_btfids: unresolved symbol bpf_lookup_user_key >>>> WARN: resolve_btfids: unresolved symbol bpf_lookup_system_key >>>> WARN: resolve_btfids: unresolved symbol bpf_iter_task_vma_new >>>> WARN: resolve_btfids: unresolved symbol bpf_iter_scx_dsq_new >>>> WARN: resolve_btfids: unresolved symbol bpf_get_kmem_cache >>>> WARN: resolve_btfids: unresolved symbol bpf_dynptr_from_xdp >>>> WARN: resolve_btfids: unresolved symbol bpf_dynptr_from_skb >>>> WARN: resolve_btfids: unresolved symbol bpf_cgroup_from_id >>>> NM System.map >>>> >>>> After further debugging this can be reproduced more simply: >>>> >>>> $ pahole -J -j --btf_features=decl_tag,consistent_func,decl_tag_kfuncs .tmp_vmlinux_armhf >>>> btf_encoder__tag_kfunc: failed to find kfunc 'scx_bpf_select_cpu_dfl' in BTF >>>> btf_encoder__tag_kfuncs: failed to tag kfunc 'scx_bpf_select_cpu_dfl' >>>> >>>> $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf >>>> <nothing> >>>> >>>> $ pfunct -Fdwarf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf >>>> s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); >>>> >>>> $ pahole -J -j --btf_features=decl_tag,decl_tag_kfuncs .tmp_vmlinux_armhf >>>> >>>> $ pfunct -Fbtf -E -f scx_bpf_select_cpu_dfl .tmp_vmlinux_armhf >>>> bpf_kfunc s32 scx_bpf_select_cpu_dfl(struct task_struct * p, s32 prev_cpu, u64 wake_flags, bool * is_idle); >>>> >>>> The key things to note are the pahole 'consistent_func' feature and the u64 >>>> 'wake_flags' parameter vs. arm 32-bit registers. These point to existing >>>> code handling arguments larger than register-size, allowing them to be >>>> BTF encoded but only if structs. >>>> >>>> Generalize the code for any argument type larger than register size (i.e. >>>> size > cu->addr_size). This should work for integral or aggregate types, >>>> and also avoids a bug in the current code where a register-sized struct >>>> could be mistaken for larger. Note that zero-sized arguments will still >>>> be marked as inconsistent and not encoded. >>>> >>>> Fixes: a53c58158b76 ("dwarf_loader: Mark functions that do not use expected registers for params") >>>> Tested-by: Alexis Lothoré <alexis.lothore@bootlin.com> >>>> Tested-by: Alan Maguire <alan.maguire@oracle.com> >>>> Signed-off-by: Tony Ambardar <tony.ambardar@gmail.com> >>> >>> hi Tony, >>> >>> I'm planning on landing this shortly unless anyone objects; and on that >>> topic if anyone has the cycles to test with this patch that would be >>> great! I ran it through the work-in-progress BTF comparison in github CI >>> and all looks good; see the "Compare functions generated" step in [1]. >>> >>> Thanks! >>> >> >> In fact I spoke too soon; there was a bug in the function comparison. >> After that was fixed, I reran with this patch; see [1]. >> >> It shows that - as expected - functions with 0-sized params are left >> out, specifically >> >> < int __io_run_local_work(struct io_ring_ctx * ctx, io_tw_token_t tw, >> int min_events, int max_events); >> < int __io_run_local_work_loop(struct llist_node * * node, io_tw_token_t >> tw, int events); >> >> We expect this since io_tw_token_t is 0-sized. However on x86_64 it did >> show one _extra_ function that I didn't expect: >> >>> int __vxlan_fdb_delete(struct vxlan_dev * vxlan, const unsigned char >> * addr, union vxlan_addr ip, __be16 port, __be32 src_vni, __be32 vni, >> u32 ifindex, bool swdev_notify); >> >> It's not clear to me why that function was added with this change - I >> would have expected it either with or without the change. Any idea why >> that might be? > > hi, > I can see that as well, IIUC the 'ip' argument is: > > union vxlan_addr { > struct sockaddr_in sin; > struct sockaddr_in6 sin6; > struct sockaddr sa; > }; > > so we have struct as 4th argument, which sets the has_wide_param condition > and won't set the fn->proto.unexpected_reg for the function, because of: > > if (!has_wide_param) > fn->proto.unexpected_reg = 1; > > I'm not sure it's correct.. if the ip struct is big enough that it's passed > on stack, why are the rest of the arguments marked with unexpected_reg > (in parameter__new) I think I'm missing something > Ah you've nailed it, that's the reason! Before we only checked for struct/typedef or const struct/typedef. However in this case it is a union, so moving to a size-based rather than an (incomplete) type-based tests means we previously excluded this function but don't now. Alan ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2025-06-30 17:33 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-04-10 8:33 [PATCH dwarves v1] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems Tony Ambardar 2025-04-10 12:20 ` Alan Maguire 2025-04-16 10:33 ` Tony Ambardar 2025-05-02 7:03 ` [PATCH dwarves v2] " Tony Ambardar 2025-05-08 9:38 ` Alexis Lothoré 2025-05-09 5:21 ` Tony Ambardar 2025-05-09 8:33 ` Alexis Lothoré 2025-05-12 8:41 ` Tony Ambardar 2025-05-08 13:24 ` Alan Maguire 2025-05-09 5:22 ` Tony Ambardar 2025-05-22 6:37 ` [PATCH dwarves v3] " Tony Ambardar 2025-06-24 16:14 ` Alan Maguire 2025-06-30 10:01 ` Alan Maguire 2025-06-30 13:51 ` Jiri Olsa 2025-06-30 17:32 ` Alan Maguire
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).