public inbox for bpf@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH dwarves v4 00/11] pahole: Encode true signatures in kernel BTF
@ 2026-03-26  1:31 Yonghong Song
  2026-03-26  1:31 ` [PATCH dwarves v4 01/11] dwarf_loader: Reduce parameter checking with clang DW_AT_calling_convention attr Yonghong Song
                   ` (11 more replies)
  0 siblings, 12 replies; 17+ messages in thread
From: Yonghong Song @ 2026-03-26  1:31 UTC (permalink / raw)
  To: Alan Maguire, Arnaldo Carvalho de Melo, dwarves
  Cc: Alexei Starovoitov, Andrii Nakryiko, bpf, kernel-team

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 18 functions
cannot have true signatures due to locations.

For arm64, there are 863 kernel functions having signature changed, and
70 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), 130) += --btf_features=attributes
  +pahole-flags-$(call test-ge, $(pahole-ver), 130) += --btf_features=attributes --btf_features=+true_signature

For the patch set, Patch 1 introduced usage of DW_AT_calling_convention, which
can precisely identify which function has signature changed. This can filter
majority of functions where their signature won't change. Patch 2 did a prescan
of parameter registers to accommodate some cases where the optimization could
happen but didn't. Patches 3 to 9 tried to find functions with true signature.
Patch 10 enables to btf encoder to properly generate BTF.
Patch 11 includes a few tests.

Changelog:
  v3 -> v4:
    - v3: https://lore.kernel.org/bpf/20260320190917.1970524-1-yonghong.song@linux.dev/
    - Add simple prescan of parameter registers in order to get true signatures
      for those functions where optimization could happen but compiler didn't do it.
    - Do not create a new name (e.g. "uattr__is_kernel") with malloc at parameter_reg()
      stage. Instead remember both "uattr" and "is_kernel" and later generate the
      name "uattr_is_kernel" in btf encoder.
    - Add comments to explain how to handle parameters which may take two registers.
    - Fix some test failures on aarch64.
  v2 -> v3:
    - v2: https://lore.kernel.org/bpf/20260309153215.1917033-1-yonghong.song@linux.dev/
    - Change tests by using newly added test_lib.sh.
    - Simplify to get bool variable producer_clang.
    - Try to avoid producer_clang appearance in dwarf_loader.c in order to avoid
      clear separation between clang and gcc.
  v1 -> v2:
    - v1: https://lore.kernel.org/bpf/20260305225455.1151066-1-yonghong.song@linux.dev/
    - Added producer_clang guarding in btf_encoder. Otherwise, gcc kernel build
      will crash pahole.
    - Fix an early return in parameter__reg() which didn't do pthread_mutex_unlock()
      which caused the deadlock for arm64.
    - Add a few more places to guard with producer_clang and conf->true_signature
      to maintain the previous behavior if not clang or conf->true_signature is false.

Yonghong Song (11):
  dwarf_loader: Reduce parameter checking with clang
    DW_AT_calling_convention attr
  dwarf_loader: Prescan all parameters with expected registers
  dwarf_loader: Handle signatures with dead arguments
  dwarf_loader: Refactor initial ret -1 to be macro PARM_DEFAULT_FAIL
  dwarf_laoder: Handle locations with DW_OP_fbreg
  dwarf_loader: Change exprlen checking condition in parameter__reg()
  dwarf_loader: Detect optimized parameters with locations having
    constant values
  dwarf_loader: Check whether two-reg parameter actually use two regs or
    not
  dwarf_loader: Handle expression lists
  btf_encoder: Handle optimized parameter properly
  tests: Add a few clang true signature tests

 btf_encoder.c                       |  32 +-
 dwarf_loader.c                      | 546 ++++++++++++++++++++++++++--
 dwarves.h                           |   3 +
 tests/clang_parm_aggregate.sh       |  85 +++++
 tests/clang_parm_optimized.sh       |  63 ++++
 tests/clang_parm_optimized_stack.sh |  63 ++++
 6 files changed, 763 insertions(+), 29 deletions(-)
 create mode 100755 tests/clang_parm_aggregate.sh
 create mode 100755 tests/clang_parm_optimized.sh
 create mode 100755 tests/clang_parm_optimized_stack.sh

-- 
2.52.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2026-03-30 10:13 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-26  1:31 [PATCH dwarves v4 00/11] pahole: Encode true signatures in kernel BTF Yonghong Song
2026-03-26  1:31 ` [PATCH dwarves v4 01/11] dwarf_loader: Reduce parameter checking with clang DW_AT_calling_convention attr Yonghong Song
2026-03-30  8:31   ` Alan Maguire
2026-03-26  1:31 ` [PATCH dwarves v4 02/11] dwarf_loader: Prescan all parameters with expected registers Yonghong Song
2026-03-26  1:31 ` [PATCH dwarves v4 03/11] dwarf_loader: Handle signatures with dead arguments Yonghong Song
2026-03-30 10:13   ` Alan Maguire
2026-03-26  1:32 ` [PATCH dwarves v4 04/11] dwarf_loader: Refactor initial ret -1 to be macro PARM_DEFAULT_FAIL Yonghong Song
2026-03-26  1:32 ` [PATCH dwarves v4 05/11] dwarf_laoder: Handle locations with DW_OP_fbreg Yonghong Song
2026-03-26  1:32 ` [PATCH dwarves v4 06/11] dwarf_loader: Change exprlen checking condition in parameter__reg() Yonghong Song
2026-03-26  1:32 ` [PATCH dwarves v4 07/11] dwarf_loader: Detect optimized parameters with locations having constant values Yonghong Song
2026-03-26  1:32 ` [PATCH dwarves v4 08/11] dwarf_loader: Check whether two-reg parameter actually use two regs or not Yonghong Song
2026-03-26  1:32 ` [PATCH dwarves v4 09/11] dwarf_loader: Handle expression lists Yonghong Song
2026-03-26  1:33 ` [PATCH dwarves v4 10/11] btf_encoder: Handle optimized parameter properly Yonghong Song
2026-03-26  1:33 ` [PATCH dwarves v4 11/11] tests: Add a few clang true signature tests Yonghong Song
2026-03-27 16:02 ` [PATCH dwarves v4 00/11] pahole: Encode true signatures in kernel BTF Alan Maguire
2026-03-27 19:38   ` Yonghong Song
2026-03-30  9:56     ` Alan Maguire

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox