Re: [PATCH dwarves v3] dwarf_loader: Fix skipped encoding of function BTF on 32-bit systems

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

 



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@xxxxxxxxxxx>
>>>> Tested-by: Alan Maguire <alan.maguire@xxxxxxxxxx>
>>>> Signed-off-by: Tony Ambardar <tony.ambardar@xxxxxxxxx>
>>>
>>> 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




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


  Powered by Linux