On Thu, Dec 4, 2025 at 11:25 AM Frank Ch. Eigler <[email protected]> wrote:
>
> Hi -
>
> > Let us say there is a kernel function map_create().
> > The 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) { ... }
> >
> > Eventually after optimization, it becomes:
> > static int map_create(union bpf_attr *attr, bool is_kernel) { ... }
>
> Well, no, it doesn't. There's no equivalent C "signature" generated
> by the compiler for a random optimized clone of a function, which you
> could use to take ABI heuristic shortcuts to generate interoperable code.
The generated signature is based on the information in llvm.
It is a best effort. For example for map_create, in llvm we have
define internal fastcc i32 @map_create(ptr noundef %0, i8 range(i8 0,
2) %1) unnamed_addr #0 align 16 !dbg !14902 {
#dbg_value(ptr poison, !14907, !DIExpression(DW_OP_LLVM_fragment,
0, 64), !23117)
#dbg_value(i8 %1, !14907, !DIExpression(DW_OP_LLVM_fragment, 64, 8), !23117)
#dbg_value(ptr %0, !14906, !DIExpression(), !23117)
…
%3 = getelementptr i8, ptr %0, i64 16, !dbg !23120
In the above !14907 and !14906 are debuginfo entries. But look at
DIExpression and debuginfo,
we can reliably find what the signature should look like.
Of course, there are some complicated cases (esp. -O3) which makes to
get changed signature difficult.
>
>
> > The dwarf:
> > 0x0186acca: DW_TAG_formal_parameter
> > DW_AT_location (indexed (0x2b3) loclist =
> > 0x00256a31:
> > [0xffffffff814a7f15, 0xffffffff814a7f34):
> > DW_OP_piece 0x8, DW_OP_reg4 RSI, DW_OP_piece 0x1
> > [0xffffffff814a7f34, 0xffffffff814a7f64):
> > DW_OP_piece 0x8, DW_OP_reg6 RBP, DW_OP_piece 0x1
> > [0xffffffff814a7f6a, 0xffffffff814a83fb):
> > DW_OP_piece 0x8, DW_OP_reg6 RBP, DW_OP_piece 0x1)
> > DW_AT_name ("uattr")
> > DW_AT_decl_file
> > ("/home/yhs/work/bpf-next/kernel/bpf/syscall.c")
> > DW_AT_decl_line (1375)
> > DW_AT_type (0x0186a002 "bpfptr_t")
>
> Right, 8 bytes of holes for the parts of the structs that didn't need
> passing to this particular optimized copy.
>
Thanks for confirmation.
>
> > Not sure how to recover the true signature from the above?
>
> Perhaps this is the wrong way to think about it. There is no "true
> signature" per se that is necessarily expressible in C. Some
> parameters are passed somewhere in registers/memory. By decoding the
> location lists, you can enumerate source-level parameters, find what
> pieces may be found where.
>
> Code that to read/write these values has to be deeply aware of where
> to look, since compilers are not bound to any particular ABI for these
> static functions. That means the code would also be aware which parts
> have been optimized away, and could reject accesses to such pieces.
Unfortunately, our linux kernel tracing facility needs a signature and
a true signature makes tracing at least removing one headache
for users.
As you mentioned, I guess it is possible to parse locations to find
the true signature. But maybe compiler can do this in a better way,
first it can have true signature and second the true signature is
generated in arch-independent way so we do not need to handle
locations for different arch's. Does this make sense?
Another option is to do function cloning to preserve the true signature.
I have implemented this before and it will make visible changes
for lldb
https://github.com/llvm/llvm-project/pull/157349#issuecomment-3412590751
I will revisit this.
Thanks!
>
> (systemtap and debuggers have had to do all this for decades. :-)
>
>
> - FChE
>
--
Dwarf-discuss mailing list
[email protected]
https://lists.dwarfstd.org/mailman/listinfo/dwarf-discuss