Re: [PATCH dwarves v6 0/5] pahole: Encode true signatures in kernel BTF
Alan Maguire <[email protected]> Mon, 22 Jun 2026 09:14:22 +0100
| Newsgroups | org.kernel.vger.dwarves,org.kernel.vger.bpf |
|---|---|
| Message-ID | <[email protected]> |
On 21/06/2026 17:47, Yonghong Song wrote:
>
>
> On 6/20/26 1:46 AM, Alan Maguire wrote:
>> On 18/06/2026 02:13, 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.
>>> 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 Yonghong, changes look good but we do hit a CI issue; specifically
>> in run_selftests in [1] for gcc+aarch64:
>>
>> 3: clang_parm_aggregate.sh
>> Validation of BTF encoding of true_signatures.
>> On arm64, BTF and DWARF signatures should be the same but they are not: BTF: long foo(struct t a__f1, struct t b, int i); ; DWARF long foo(struct t a, struct t b, int i);
>> Test ./clang_parm_aggregate.sh failed
>> Test data is in /tmp/clang_parm_aggregate.sh.NH5a6D
>>
>> I think the problem is that as well as creating aggregate parameter names we
>> need to decide whether they should actually be used; in this case it looks like
>> we hit a function using aggregates, but without DW_CC_nocall. Perhaps the
>> reason is that the calling conventions are preserved while we only get a piece
>> of the "struct t a" argument? Something like [2] seems to resolve the problem,
>> please take a look and feel free to roll the fix into one of the patches if it makes
>> sense. You might find it convenient to use the merges of your series at [3]; they
>> merge your work with Vineet's tag changes now that they have landed (just patch 1
>> required merging IIRC).
>
> On my arm64 machine, I run ./clang_parm_aggregate.sh and can reproduce your failure.
> In v5, it does work with llvm23. Probalby due to compiler and/or pahole change in v6,
> the test failed. The following can fix the issue (I tested with llvm22 and development
> llvm23):
>
> diff --git a/tests/clang_parm_aggregate.sh b/tests/clang_parm_aggregate.sh
> index 9502f8b..339cd19 100755
> --- a/tests/clang_parm_aggregate.sh
> +++ b/tests/clang_parm_aggregate.sh
> @@ -58,7 +58,7 @@ verbose_log "BTF: $btf_optimized DWARF: $dwarf"
>
> arch=$(uname -m)
>
> -if [[ "$arch" == "x86_64" ]]; then
> +if [[ "$arch" == "x86_64" || "$arch" == "aarch64" ]]; then
> # On x86_64, clang emits DW_CC_nocall for optimized functions,
> # so pahole should detect the optimization and produce a
> # different BTF signature.
> @@ -66,14 +66,6 @@ if [[ "$arch" == "x86_64" ]]; then
> error_log "BTF and DWARF signatures should be different and they are not: BTF: $btf_optimized ; DWARF $dwarf"
> test_fail
> fi
> -elif [[ "$arch" == "aarch64" ]]; then
> - # On arm64, clang does not emit DW_CC_nocall, so pahole cannot
> - # detect the optimization. BTF and DWARF signatures are expected
> - # to be the same.
> - if [[ "$btf_cmp" != "$dwarf" ]]; then
> - error_log "On arm64, BTF and DWARF signatures should be the same but they are not: BTF: $btf_optimized ; DWARF $dwarf"
> - test_fail
> - fi
> else
> # On other architectures, skip if we cannot determine the
> # expected behavior.
>
> Currently, my test mostly on llvm23. I will test with llvm22 as well and push another
> revision after your CI with llvm22 land.
>
Great, those CI changes have landed now in pahole so you should be good to go.
I think the problem I was seeing was we got some of the effect of your changes
(renaming of parameters due to partial parameter) in the absence of DW_CC_nocall.
This raises a question for me; if the function register usage does not change -
matches calling conventions (meaning no DW_CC_nocall I think) - but we do get a
partial parameter from DWARF, should the parameter name still change to
reflect we only have a piece of the parameter?