Re: [PATCH dwarves v10 0/5] pahole: Encode true signatures in kernel BTF
Alan Maguire <[email protected]> Thu, 25 Jun 2026 14:22:56 +0100
| Newsgroups | org.kernel.vger.dwarves,org.kernel.vger.bpf |
|---|---|
| Message-ID | <[email protected]> |
On 25/06/2026 11:59, Jiri Olsa wrote:
> On Wed, Jun 24, 2026 at 07:01:48PM -0700, Yonghong Song wrote:
>> Current vmlinux BTF encoding is based on the source level signatures.
>> But the compiler may do some optimization and changed the signature.
>> If the user tried with source level signature, their initial implementation
>> may have wrong results and then the user need to check what is the
>> problem and work around it, e.g. through kprobe since kprobe does not
>> need vmlinux BTF.
>>
>> Majority of changed signatures are due to dead argument elimination.
>> The following is a more complex one. The original source signature:
>> typedef struct {
>> union {
>> void *kernel;
>> void __user *user;
>> };
>> bool is_kernel : 1;
>> } sockptr_t;
>> typedef sockptr_t bpfptr_t;
>> static int map_create(union bpf_attr *attr, bpfptr_t uattr) { ... }
>> After compiler optimization, the signature becomes:
>> static int map_create(union bpf_attr *attr, bool uattr__is_kernel) { ... }
>> In the above, uattr__is_kernel corresponds to 'is_kernel' field in sockptr_t.
>> This makes it easier for developers to understand what changed.
>>
>> The new signature needs to properly follow ABI specification based on
>> locations. Otherwise, that signature should be discarded. For example,
>>
>> 0x0242f1f7: DW_TAG_subprogram
>> DW_AT_name ("memblock_find_in_range")
>> DW_AT_calling_convention (DW_CC_nocall)
>> DW_AT_type (0x0242decc "phys_addr_t")
>> ...
>> 0x0242f22e: DW_TAG_formal_parameter
>> DW_AT_location (indexed (0x14a) loclist = 0x005595bc:
>> [0xffffffff87a000f9, 0xffffffff87a00178): DW_OP_reg5 RDI
>> [0xffffffff87a00178, 0xffffffff87a001be): DW_OP_reg14 R14
>> [0xffffffff87a001be, 0xffffffff87a001c7): DW_OP_entry_value(DW_OP_reg5 RDI), DW_OP_stack_value
>> [0xffffffff87a001c7, 0xffffffff87a00214): DW_OP_reg14 R14)
>> DW_AT_name ("start")
>> DW_AT_type (0x0242decc "phys_addr_t")
>> ...
>> 0x0242f239: DW_TAG_formal_parameter
>> DW_AT_location (indexed (0x14b) loclist = 0x005595e6:
>> [0xffffffff87a000f9, 0xffffffff87a00175): DW_OP_reg4 RSI
>> [0xffffffff87a00175, 0xffffffff87a001b8): DW_OP_reg3 RBX
>> [0xffffffff87a001b8, 0xffffffff87a001c7): DW_OP_entry_value(DW_OP_reg4 RSI), DW_OP_stack_value
>> [0xffffffff87a001c7, 0xffffffff87a00214): DW_OP_reg3 RBX)
>> DW_AT_name ("end")
>> DW_AT_type (0x0242decc "phys_addr_t")
>> ...
>> 0x0242f245: DW_TAG_formal_parameter
>> DW_AT_location (indexed (0x14c) loclist = 0x00559610:
>> [0xffffffff87a001e3, 0xffffffff87a001ef): DW_OP_breg4 RSI+0)
>> DW_AT_name ("size")
>> DW_AT_type (0x0242decc "phys_addr_t")
>> ...
>> 0x0242f250: DW_TAG_formal_parameter
>> DW_AT_const_value (4096)
>> DW_AT_name ("align")
>> DW_AT_type (0x0242decc "phys_addr_t")
>> ...
>>
>> The third argument should correspond to RDX for x86_64. But the location suggests that
>> the parameter value is stored in the address with 'RSI + 0'. It is not clear whether
>> the parameter value is stored in RDX or not. So we have to discard this funciton in
>> vmlinux BTF to avoid incorrect true signatures.
>>
>> For llvm, any function having
>> DW_AT_calling_convention (DW_CC_nocall)
>> in dwarf DW_TAG_subprogram will indicate that this function has signature changed.
>> But for non DW_CC_nocall functions, it is possible that true signature still not
>> available due to locations. So every functions will be checked.
>>
>> I did experiment with latest bpf-next. For x86_64, there are 69103 kernel functions
>> and 875 kernel functions having signature changed. A series of patches are intended
>> to ensure true signatures are properly represented. Eventually, only 20 functions
>> cannot have true signatures due to locations.
>>
>> For arm64, there are 863 kernel functions having signature changed, and
>> 108 functions cannot have true signatures due to locations. I checked those
>> functions and look like llvm arm64 backend more relaxed to compute parameter
>> values.
>>
>> For full testing, I enabled true signature support in kernel scripts/Makefile.btf like below:
>> -pahole-flags-$(call test-ge, $(pahole-ver), 131) += --btf_features=attributes
>> +pahole-flags-$(call test-ge, $(pahole-ver), 131) += --btf_features=attributes --btf_features=+true_signature
>>
>> See individual patches for details.
>
> hi,
> I tried this version and had to choose another function, because "arp_process"
> suddenly started to show args registers in proper order ;-)
>
> now I checked "stop_cpus" function which is added to btf after this change,
> I attached the dwarf dump below
>
> "stop_cpus" has DW_CC_nocall set, so it has signature_changed=true and I see the
> function ends up in the btf_encoder with optimized_parms=1
>
> but we do not skip such functions now, it seems like we should?
>
> I tried the attached change below and it removes all the extra functions
> that were added in the btf with this change
>
> btw I can't see any other use for optimized_parms flag, it seems to be
> just set and never used.. so I wonder I'm missing something
>
Thanks for looking at this!
Yonghong can correct me if I have this wrong, but I think optimized parameters
are okay, but only if true signature is enabled, so omitting functions with
optimized parameters should probably only happen if !true_signature. so for
the change below, the modification to btf_encoder__add_saved_funcs() is right
but I don't think the modification to btf_encoder__add_true_signature() is needed.
> jirka
>
>
> dwarfdump:
>
> 0x016f4b1b: DW_TAG_subprogram
> DW_AT_low_pc (0xffffffff813e0fc0)
> DW_AT_high_pc (0xffffffff813e1133)
> DW_AT_frame_base (DW_OP_reg7 RSP)
> DW_AT_GNU_all_call_sites (true)
> DW_AT_name ("stop_cpus")
> DW_AT_decl_file ("/home/jolsa/kernel/linux-qemu-2/kernel/stop_machine.c")
> DW_AT_decl_line (464)
> DW_AT_prototyped (true)
> DW_AT_calling_convention (DW_CC_nocall)
> DW_AT_type (0x016e94c5 "int")
>
> 0x016f4b36: DW_TAG_formal_parameter
> DW_AT_location (0x0065ad9e:
> [0xffffffff813e0fc5, 0xffffffff813e0fed): DW_OP_reg5 RDI
> [0xffffffff813e0fed, 0xffffffff813e111e): DW_OP_reg14 R14
> [0xffffffff813e111e, 0xffffffff813e1127): DW_OP_GNU_entry_value(DW_OP_reg5 RDI), DW_OP_stack_value
> [0xffffffff813e1127, 0xffffffff813e1133): DW_OP_reg14 R14)
> DW_AT_name ("cpumask")
> DW_AT_decl_file ("/home/jolsa/kernel/linux-qemu-2/kernel/stop_machine.c")
> DW_AT_decl_line (464)
> DW_AT_type (0x016f3242 "const cpumask *")
>
> 0x016f4b46: DW_TAG_formal_parameter
> DW_AT_name ("fn")
> DW_AT_decl_file ("/home/jolsa/kernel/linux-qemu-2/kernel/stop_machine.c")
> DW_AT_decl_line (464)
> DW_AT_type (0x016f2ca5 "cpu_stop_fn_t")
>
> 0x016f4b52: DW_TAG_formal_parameter
> DW_AT_location (0x0065ae0d:
> [0xffffffff813e0fc5, 0xffffffff813e0ff2): DW_OP_reg4 RSI
> [0xffffffff813e0ff2, 0xffffffff813e10e4): DW_OP_reg3 RBX
> [0xffffffff813e10e4, 0xffffffff813e1127): DW_OP_GNU_entry_value(DW_OP_reg4 RSI), DW_OP_stack_value
> [0xffffffff813e1127, 0xffffffff813e112e): DW_OP_reg3 RBX
> [0xffffffff813e112e, 0xffffffff813e1133): DW_OP_GNU_entry_value(DW_OP_reg4 RSI), DW_OP_stack_value)
> DW_AT_name ("arg")
> DW_AT_decl_file ("/home/jolsa/kernel/linux-qemu-2/kernel/stop_machine.c")
> DW_AT_decl_line (464)
> DW_AT_type (0x016e858f "void *")
>
>
>
>
> ---
> diff --git a/btf_encoder.c b/btf_encoder.c
> index 38455a4c6b6b..cbc5063a6280 100644
> --- a/btf_encoder.c
> +++ b/btf_encoder.c
> @@ -1564,7 +1564,8 @@ static int btf_encoder__add_true_signature(struct btf_encoder *encoder,
> */
> if (true_state->unexpected_reg ||
> true_state->uncertain_parm_loc ||
> - true_state->ambiguous_addr)
> + true_state->ambiguous_addr ||
> + true_state->optimized_parms)
> continue;
> err = btf_encoder__add_func(encoder, true_state);
> if (err < 0)
> @@ -1656,6 +1657,8 @@ static int btf_encoder__add_saved_funcs(struct btf_encoder *encoder, bool skip_e
> skip_reason = "reordered parameters\n";
> if (state->elf->ambiguous_addr)
> skip_reason = "ambiguous address\n";
> + if (state->optimized_parms)
> + skip_reason = "optimized parms\n";
>
> if (skip_reason) {
> btf_encoder__log_func_skip(encoder, saved_fns[i].elf,