In llvm pull request [1], the dwarf is changed to accommodate functions whose signatures are different from source level although they have the same name. Other non-source functions are also included in dwarf. The following is an example: The source: ==== $ cat test.c struct t { int a; }; char *tar(struct t *a, struct t *d); __attribute__((noinline)) static char * foo(struct t *a, struct t *d, int b) { return tar(a, d); } char *bar(struct t *a, struct t *d) { return foo(a, d, 1); } ==== Part of generated dwarf: ==== 0x0000005c: DW_TAG_subprogram DW_AT_low_pc (0x0000000000000010) DW_AT_high_pc (0x0000000000000015) DW_AT_frame_base (DW_OP_reg7 RSP) DW_AT_linkage_name ("foo") DW_AT_name ("foo") DW_AT_decl_file ("/home/yhs/tests/sig-change/deadarg/test.c") DW_AT_decl_line (3) DW_AT_type (0x000000bb "char *") DW_AT_artificial (true) DW_AT_external (true) 0x0000006c: DW_TAG_formal_parameter DW_AT_location (DW_OP_reg5 RDI) DW_AT_decl_file ("/home/yhs/tests/sig-change/deadarg/test.c") DW_AT_decl_line (3) DW_AT_type (0x000000c4 "t *") 0x00000075: DW_TAG_formal_parameter DW_AT_location (DW_OP_reg4 RSI) DW_AT_decl_file ("/home/yhs/tests/sig-change/deadarg/test.c") DW_AT_decl_line (3) DW_AT_type (0x000000c4 "t *") 0x0000007e: DW_TAG_inlined_subroutine DW_AT_abstract_origin (0x0000009a "foo") DW_AT_low_pc (0x0000000000000010) DW_AT_high_pc (0x0000000000000015) DW_AT_call_file ("/home/yhs/tests/sig-change/deadarg/test.c") DW_AT_call_line (0) 0x0000008a: DW_TAG_formal_parameter DW_AT_location (DW_OP_reg5 RDI) DW_AT_abstract_origin (0x000000a2 "a") 0x00000091: DW_TAG_formal_parameter DW_AT_location (DW_OP_reg4 RSI) DW_AT_abstract_origin (0x000000aa "d") 0x00000098: NULL 0x00000099: NULL 0x0000009a: DW_TAG_subprogram DW_AT_name ("foo") DW_AT_decl_file ("/home/yhs/tests/sig-change/deadarg/test.c") DW_AT_decl_line (3) DW_AT_prototyped (true) DW_AT_type (0x000000bb "char *") DW_AT_inline (DW_INL_inlined) 0x000000a2: DW_TAG_formal_parameter DW_AT_name ("a") DW_AT_decl_file ("/home/yhs/tests/sig-change/deadarg/test.c") DW_AT_decl_line (3) DW_AT_type (0x000000c4 "t *") 0x000000aa: DW_TAG_formal_parameter DW_AT_name ("d") DW_AT_decl_file ("/home/yhs/tests/sig-change/deadarg/test.c") DW_AT_decl_line (3) DW_AT_type (0x000000c4 "t *") 0x000000b2: DW_TAG_formal_parameter DW_AT_name ("b") DW_AT_decl_file ("/home/yhs/tests/sig-change/deadarg/test.c") DW_AT_decl_line (3) DW_AT_type (0x000000d8 "int") 0x000000ba: NULL ==== In the above, there are two subprograms with the same name 'foo'. Currently btf encoder will consider both functions as ELF functions. Since two subprograms have different signature, the funciton will be ignored. But actually, one of function 'foo' is marked as DW_INL_inlined which means we should not treat it as an elf funciton. The patch fixed this issue by filtering subprograms if the corresponding function__inlined() is true. This will fix the issue for [1]. But it should work fine without [1] too. [1] https://github.com/llvm/llvm-project/pull/157349 --- btf_encoder.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/btf_encoder.c b/btf_encoder.c index 0bc2334..18f0162 100644 --- a/btf_encoder.c +++ b/btf_encoder.c @@ -2652,6 +2652,8 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co */ if (fn->declaration) continue; + if (function__inlined(fn)) + continue; if (!ftype__has_arg_names(&fn->proto)) continue; if (funcs->cnt) { -- 2.47.3