Em Mon, Oct 28, 2019 at 10:30:15PM -0700, Andrii Nakryiko escreveu: > Add encoding of DWARF's DW_TAG_subprogram_type into BTF's BTF_KIND_FUNC > (plus corresponding BTF_KIND_FUNC_PROTO). Only exported functions are > converted for now. This allows to capture all the exported kernel functions, > same subset that's exposed through /proc/kallsyms. Applied, added these committer notes: commit 3c5f2a224aa1934c87525d81ff894c9cad1451a9 Author: Andrii Nakryiko <andriin@xxxxxx> Date: Mon Oct 28 22:30:15 2019 -0700 btf_encoder: Preserve and encode exported functions as BTF_KIND_FUNC Add encoding of DWARF's DW_TAG_subprogram_type into BTF's BTF_KIND_FUNC (plus corresponding BTF_KIND_FUNC_PROTO). Only exported functions are converted for now. This allows to capture all the exported kernel functions, same subset that's exposed through /proc/kallsyms. Committer testing: Before: $ readelf -SW vmlinux | grep BTF [78] .BTF PROGBITS 0000000000000000 26a27da9 1e5543 00 0 0 1 $ After: $ pahole -J vmlinux $ readelf -SW vmlinux | grep BTF [78] .BTF PROGBITS 0000000000000000 26a27da9 2d5f47 00 0 0 1 $ >>> 0x2d5f47 - 0x1e5543 985604 The kernel has a lot of functions! :-) $ pahole -VJ vmlinux > /tmp/pahole-btf-encoding-verbose-output.txt $ grep -w FUNC /tmp/pahole-btf-encoding-verbose-output.txt | wc -l 22871 [acme@quaco pahole]$ grep -w FUNC /tmp/pahole-btf-encoding-verbose-output.txt | tail [4511543] FUNC copy_from_user_nmi type_id=4511542 [4512934] FUNC memcpy_page_flushcache type_id=4512933 [4512936] FUNC __memcpy_flushcache type_id=4512935 [4512938] FUNC __copy_user_flushcache type_id=4512937 [4512940] FUNC arch_wb_cache_pmem type_id=4512939 [4512942] FUNC mcsafe_handle_tail type_id=4512941 [4512944] FUNC copy_user_handle_tail type_id=4512943 [4512946] FUNC clear_user type_id=4512945 [4512948] FUNC __clear_user type_id=4512947 [4512950] FUNC memcpy type_id=4512949 $ grep -w FUNC_PROTO /tmp/pahole-btf-encoding-verbose-output.txt | tail [4512902] FUNC_PROTO (anon) return=4511725 args=(4512097 (anon), 4511544 (anon)) [4512933] FUNC_PROTO (anon) return=0 args=(4511598 to, 4511725 page, 4511610 offset, 4511610 len) [4512935] FUNC_PROTO (anon) return=0 args=(4511638 _dst, 4511759 _src, 4511610 size) [4512937] FUNC_PROTO (anon) return=4511585 args=(4511638 dst, 4511759 src, 4511552 size) [4512939] FUNC_PROTO (anon) return=0 args=(4511638 addr, 4511610 size) [4512941] FUNC_PROTO (anon) return=4511544 args=(4511598 to, 4511598 from, 4511552 len) [4512943] FUNC_PROTO (anon) return=4511544 args=(4511598 to, 4511598 from, 4511552 len) [4512945] FUNC_PROTO (anon) return=4511544 args=(4511638 to, 4511544 n) [4512947] FUNC_PROTO (anon) return=4511544 args=(4511638 addr, 4511544 size) [4512949] FUNC_PROTO (anon) return=4511638 args=(4511638 p, 4511759 q, 4511591 size) $ grep -w FUNC_PROTO /tmp/pahole-btf-encoding-verbose-output.txt |grep 4511542 [4511542] FUNC_PROTO (anon) return=4510159 args=(4510254 to, 4510374 from, 4510159 n) $ With a little change to pdwtags to see DW_TAG_subroutine_type, which is what BTF's KIND_FUNC_PROTO maps to, we see some of those last prototypes: [acme@quaco pahole]$ pdwtags -F btf vmlinux | grep '()(' | tail void ()(struct insn * insn); /* size: 45404744 */ int ()(struct insn * insn); /* size: 4 */ void ()(struct insn * insn, const void * kaddr, int buf_len, int x86_64); /* size: 45405032 */ long unsigned int ()(const char * purpose); /* size: 8 */ void ()(char * to, struct page * page, size_t offset, size_t len); /* size: 45405864 */ void ()(void * _dst, const void * _src, size_t size); /* size: 45406200 */ long int ()(void * dst, const void * src, unsigned int size); /* size: 8 */ long unsigned int ()(char * to, char * from, unsigned int len); /* size: 8 */ long unsigned int ()(void * to, long unsigned int n); /* size: 8 */ long unsigned int ()(void * addr, long unsigned int size); /* size: 8 */ [acme@quaco pahole]$ I.e.: [4512941] FUNC_PROTO (anon) return=4511544 args=(4511598 to, 4511598 from, 4511552 len) gets decoded by pdwtags as: long unsigned int ()(char * to, char * from, unsigned int len); /* size: 8 */ $ grep '\[\(4511544\|4511598\|4511550\|4511552\)\]' /tmp/pahole-btf-encoding-verbose-output.txt [4511544] INT long unsigned int size=8 bit_offset=0 nr_bits=64 encoding=(none) [4511550] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [4511552] INT unsigned int size=4 bit_offset=0 nr_bits=32 encoding=(none) [4511598] PTR (anon) type_id=4511550 $ Signed-off-by: Andrii Nakryiko <andriin@xxxxxx> Tested-by: Alexei Starovoitov <ast@xxxxxxxxxx> Tested-by: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx> Acked-by: Alexei Starovoitov <ast@xxxxxxxxxx> Cc: Alexei Starovoitov <ast@xxxxxx> Cc: Andrii Nakryiko <andrii.nakryiko@xxxxxxxxx> Cc: Yonghong Song <yhs@xxxxxx> Cc: dwarves@xxxxxxxxxxxxxxx Cc: kernel-team@xxxxxx Signed-off-by: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx> diff --git a/btf_encoder.c b/btf_encoder.c index f85b978a3981..df16ba0ae98e 100644 --- a/btf_encoder.c +++ b/btf_encoder.c @@ -173,6 +173,7 @@ int cu__encode_btf(struct cu *cu, int verbose) bool add_index_type = false; uint32_t type_id_off; uint32_t core_id; + struct function *fn; struct tag *pos; int err = 0; @@ -225,6 +226,21 @@ int cu__encode_btf(struct cu *cu, int verbose) btf_elf__add_base_type(btfe, &bt); } + cu__for_each_function(cu, core_id, fn) { + int btf_fnproto_id, btf_fn_id; + + if (fn->declaration || !fn->external) + continue; + + btf_fnproto_id = btf_elf__add_func_proto(btfe, &fn->proto, type_id_off); + btf_fn_id = btf_elf__add_ref_type(btfe, BTF_KIND_FUNC, btf_fnproto_id, fn->name, false); + if (btf_fnproto_id < 0 || btf_fn_id < 0) { + err = -1; + printf("error: failed to encode function '%s'\n", function__name(fn, cu)); + goto out; + } + } + out: if (err) btf_elf__delete(btfe); diff --git a/dwarf_loader.c b/dwarf_loader.c index 4c6783b9af7e..09edcfb91bf0 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -920,6 +920,7 @@ static struct function *function__new(Dwarf_Die *die, struct cu *cu) func->name = strings__add(strings, attr_string(die, DW_AT_name)); func->linkage_name = strings__add(strings, attr_string(die, DW_AT_MIPS_linkage_name)); func->inlined = attr_numeric(die, DW_AT_inline); + func->declaration = dwarf_hasattr(die, DW_AT_declaration); func->external = dwarf_hasattr(die, DW_AT_external); func->abstract_origin = dwarf_hasattr(die, DW_AT_abstract_origin); dwarf_tag__set_spec(func->proto.tag.priv, diff --git a/dwarves.h b/dwarves.h index b162e751cc99..b53bdfc2bca9 100644 --- a/dwarves.h +++ b/dwarves.h @@ -784,6 +784,7 @@ struct function { uint8_t external:1; uint8_t accessibility:2; /* DW_ACCESS_{public,protected,private} */ uint8_t virtuality:2; /* DW_VIRTUALITY_{none,virtual,pure_virtual} */ + uint8_t declaration:1; int32_t vtable_entry; struct list_head vtable_node; /* fields used by tools */