Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libbpf: Support kfunc detection in light skeleton.

Teach gen_loader to find {btf_id, btf_obj_fd} of kernel variables and kfuncs
and populate corresponding ld_imm64 and bpf_call insns.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20230321203854.3035-4-alexei.starovoitov@gmail.com

authored by

Alexei Starovoitov and committed by
Andrii Nakryiko
708cdc57 1057d299

+27 -22
+3 -1
tools/lib/bpf/bpf_gen_internal.h
··· 11 11 int insn_idx; 12 12 bool is_weak; 13 13 bool is_typeless; 14 + bool is_ld64; 14 15 }; 15 16 16 17 struct ksym_desc { ··· 25 24 bool typeless; 26 25 }; 27 26 int insn; 27 + bool is_ld64; 28 28 }; 29 29 30 30 struct bpf_gen { ··· 67 65 void bpf_gen__map_freeze(struct bpf_gen *gen, int map_idx); 68 66 void bpf_gen__record_attach_target(struct bpf_gen *gen, const char *name, enum bpf_attach_type type); 69 67 void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak, 70 - bool is_typeless, int kind, int insn_idx); 68 + bool is_typeless, bool is_ld64, int kind, int insn_idx); 71 69 void bpf_gen__record_relo_core(struct bpf_gen *gen, const struct bpf_core_relo *core_relo); 72 70 void bpf_gen__populate_outer_map(struct bpf_gen *gen, int outer_map_idx, int key, int inner_map_idx); 73 71
+19 -19
tools/lib/bpf/gen_loader.c
··· 560 560 } 561 561 562 562 void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak, 563 - bool is_typeless, int kind, int insn_idx) 563 + bool is_typeless, bool is_ld64, int kind, int insn_idx) 564 564 { 565 565 struct ksym_relo_desc *relo; 566 566 ··· 574 574 relo->name = name; 575 575 relo->is_weak = is_weak; 576 576 relo->is_typeless = is_typeless; 577 + relo->is_ld64 = is_ld64; 577 578 relo->kind = kind; 578 579 relo->insn_idx = insn_idx; 579 580 gen->relo_cnt++; ··· 587 586 int i; 588 587 589 588 for (i = 0; i < gen->nr_ksyms; i++) { 590 - if (!strcmp(gen->ksyms[i].name, relo->name)) { 591 - gen->ksyms[i].ref++; 592 - return &gen->ksyms[i]; 589 + kdesc = &gen->ksyms[i]; 590 + if (kdesc->kind == relo->kind && kdesc->is_ld64 == relo->is_ld64 && 591 + !strcmp(kdesc->name, relo->name)) { 592 + kdesc->ref++; 593 + return kdesc; 593 594 } 594 595 } 595 596 kdesc = libbpf_reallocarray(gen->ksyms, gen->nr_ksyms + 1, sizeof(*kdesc)); ··· 606 603 kdesc->ref = 1; 607 604 kdesc->off = 0; 608 605 kdesc->insn = 0; 606 + kdesc->is_ld64 = relo->is_ld64; 609 607 return kdesc; 610 608 } 611 609 ··· 868 864 { 869 865 int insn; 870 866 871 - pr_debug("gen: emit_relo (%d): %s at %d\n", relo->kind, relo->name, relo->insn_idx); 867 + pr_debug("gen: emit_relo (%d): %s at %d %s\n", 868 + relo->kind, relo->name, relo->insn_idx, relo->is_ld64 ? "ld64" : "call"); 872 869 insn = insns + sizeof(struct bpf_insn) * relo->insn_idx; 873 870 emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_8, BPF_PSEUDO_MAP_IDX_VALUE, 0, 0, 0, insn)); 874 - switch (relo->kind) { 875 - case BTF_KIND_VAR: 871 + if (relo->is_ld64) { 876 872 if (relo->is_typeless) 877 873 emit_relo_ksym_typeless(gen, relo, insn); 878 874 else 879 875 emit_relo_ksym_btf(gen, relo, insn); 880 - break; 881 - case BTF_KIND_FUNC: 876 + } else { 882 877 emit_relo_kfunc_btf(gen, relo, insn); 883 - break; 884 - default: 885 - pr_warn("Unknown relocation kind '%d'\n", relo->kind); 886 - gen->error = -EDOM; 887 - return; 888 878 } 889 879 } 890 880 ··· 901 903 902 904 static void cleanup_relos(struct bpf_gen *gen, int insns) 903 905 { 906 + struct ksym_desc *kdesc; 904 907 int i, insn; 905 908 906 909 for (i = 0; i < gen->nr_ksyms; i++) { 910 + kdesc = &gen->ksyms[i]; 907 911 /* only close fds for typed ksyms and kfuncs */ 908 - if (gen->ksyms[i].kind == BTF_KIND_VAR && !gen->ksyms[i].typeless) { 912 + if (kdesc->is_ld64 && !kdesc->typeless) { 909 913 /* close fd recorded in insn[insn_idx + 1].imm */ 910 - insn = gen->ksyms[i].insn; 914 + insn = kdesc->insn; 911 915 insn += sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm); 912 916 emit_sys_close_blob(gen, insn); 913 - } else if (gen->ksyms[i].kind == BTF_KIND_FUNC) { 914 - emit_sys_close_blob(gen, blob_fd_array_off(gen, gen->ksyms[i].off)); 915 - if (gen->ksyms[i].off < MAX_FD_ARRAY_SZ) 917 + } else if (!kdesc->is_ld64) { 918 + emit_sys_close_blob(gen, blob_fd_array_off(gen, kdesc->off)); 919 + if (kdesc->off < MAX_FD_ARRAY_SZ) 916 920 gen->nr_fd_array--; 917 921 } 918 922 }
+5 -2
tools/lib/bpf/libbpf.c
··· 7070 7070 for (i = 0; i < prog->nr_reloc; i++) { 7071 7071 struct reloc_desc *relo = &prog->reloc_desc[i]; 7072 7072 struct extern_desc *ext = &obj->externs[relo->sym_off]; 7073 + int kind; 7073 7074 7074 7075 switch (relo->type) { 7075 7076 case RELO_EXTERN_LD64: 7076 7077 if (ext->type != EXT_KSYM) 7077 7078 continue; 7079 + kind = btf_is_var(btf__type_by_id(obj->btf, ext->btf_id)) ? 7080 + BTF_KIND_VAR : BTF_KIND_FUNC; 7078 7081 bpf_gen__record_extern(obj->gen_loader, ext->name, 7079 7082 ext->is_weak, !ext->ksym.type_id, 7080 - BTF_KIND_VAR, relo->insn_idx); 7083 + true, kind, relo->insn_idx); 7081 7084 break; 7082 7085 case RELO_EXTERN_CALL: 7083 7086 bpf_gen__record_extern(obj->gen_loader, ext->name, 7084 - ext->is_weak, false, BTF_KIND_FUNC, 7087 + ext->is_weak, false, false, BTF_KIND_FUNC, 7085 7088 relo->insn_idx); 7086 7089 break; 7087 7090 case RELO_CORE: {