Commit 284d2587 authored by Andrii Nakryiko's avatar Andrii Nakryiko Committed by Alexei Starovoitov

libbpf: Support kernel module ksym externs

Add support for searching for ksym externs not just in vmlinux BTF, but across
all module BTFs, similarly to how it's done for CO-RE relocations. Kernels
that expose module BTFs through sysfs are assumed to support new ldimm64
instruction extension with BTF FD provided in insn[1].imm field, so no extra
feature detection is performed.
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarYonghong Song <yhs@fb.com>
Acked-by: default avatarHao Luo <haoluo@google.com>
Link: https://lore.kernel.org/bpf/20210112075520.4103414-7-andrii@kernel.org
parent 541c3bad
...@@ -395,7 +395,8 @@ struct extern_desc { ...@@ -395,7 +395,8 @@ struct extern_desc {
unsigned long long addr; unsigned long long addr;
/* target btf_id of the corresponding kernel var. */ /* target btf_id of the corresponding kernel var. */
int vmlinux_btf_id; int kernel_btf_obj_fd;
int kernel_btf_id;
/* local btf_id of the ksym extern's type. */ /* local btf_id of the ksym extern's type. */
__u32 type_id; __u32 type_id;
...@@ -6162,7 +6163,8 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog) ...@@ -6162,7 +6163,8 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog)
} else /* EXT_KSYM */ { } else /* EXT_KSYM */ {
if (ext->ksym.type_id) { /* typed ksyms */ if (ext->ksym.type_id) { /* typed ksyms */
insn[0].src_reg = BPF_PSEUDO_BTF_ID; insn[0].src_reg = BPF_PSEUDO_BTF_ID;
insn[0].imm = ext->ksym.vmlinux_btf_id; insn[0].imm = ext->ksym.kernel_btf_id;
insn[1].imm = ext->ksym.kernel_btf_obj_fd;
} else { /* typeless ksyms */ } else { /* typeless ksyms */
insn[0].imm = (__u32)ext->ksym.addr; insn[0].imm = (__u32)ext->ksym.addr;
insn[1].imm = ext->ksym.addr >> 32; insn[1].imm = ext->ksym.addr >> 32;
...@@ -7319,7 +7321,8 @@ static int bpf_object__read_kallsyms_file(struct bpf_object *obj) ...@@ -7319,7 +7321,8 @@ static int bpf_object__read_kallsyms_file(struct bpf_object *obj)
static int bpf_object__resolve_ksyms_btf_id(struct bpf_object *obj) static int bpf_object__resolve_ksyms_btf_id(struct bpf_object *obj)
{ {
struct extern_desc *ext; struct extern_desc *ext;
int i, id; struct btf *btf;
int i, j, id, btf_fd, err;
for (i = 0; i < obj->nr_extern; i++) { for (i = 0; i < obj->nr_extern; i++) {
const struct btf_type *targ_var, *targ_type; const struct btf_type *targ_var, *targ_type;
...@@ -7331,10 +7334,25 @@ static int bpf_object__resolve_ksyms_btf_id(struct bpf_object *obj) ...@@ -7331,10 +7334,25 @@ static int bpf_object__resolve_ksyms_btf_id(struct bpf_object *obj)
if (ext->type != EXT_KSYM || !ext->ksym.type_id) if (ext->type != EXT_KSYM || !ext->ksym.type_id)
continue; continue;
id = btf__find_by_name_kind(obj->btf_vmlinux, ext->name, btf = obj->btf_vmlinux;
BTF_KIND_VAR); btf_fd = 0;
id = btf__find_by_name_kind(btf, ext->name, BTF_KIND_VAR);
if (id == -ENOENT) {
err = load_module_btfs(obj);
if (err)
return err;
for (j = 0; j < obj->btf_module_cnt; j++) {
btf = obj->btf_modules[j].btf;
/* we assume module BTF FD is always >0 */
btf_fd = obj->btf_modules[j].fd;
id = btf__find_by_name_kind(btf, ext->name, BTF_KIND_VAR);
if (id != -ENOENT)
break;
}
}
if (id <= 0) { if (id <= 0) {
pr_warn("extern (ksym) '%s': failed to find BTF ID in vmlinux BTF.\n", pr_warn("extern (ksym) '%s': failed to find BTF ID in kernel BTF(s).\n",
ext->name); ext->name);
return -ESRCH; return -ESRCH;
} }
...@@ -7343,24 +7361,19 @@ static int bpf_object__resolve_ksyms_btf_id(struct bpf_object *obj) ...@@ -7343,24 +7361,19 @@ static int bpf_object__resolve_ksyms_btf_id(struct bpf_object *obj)
local_type_id = ext->ksym.type_id; local_type_id = ext->ksym.type_id;
/* find target type_id */ /* find target type_id */
targ_var = btf__type_by_id(obj->btf_vmlinux, id); targ_var = btf__type_by_id(btf, id);
targ_var_name = btf__name_by_offset(obj->btf_vmlinux, targ_var_name = btf__name_by_offset(btf, targ_var->name_off);
targ_var->name_off); targ_type = skip_mods_and_typedefs(btf, targ_var->type, &targ_type_id);
targ_type = skip_mods_and_typedefs(obj->btf_vmlinux,
targ_var->type,
&targ_type_id);
ret = bpf_core_types_are_compat(obj->btf, local_type_id, ret = bpf_core_types_are_compat(obj->btf, local_type_id,
obj->btf_vmlinux, targ_type_id); btf, targ_type_id);
if (ret <= 0) { if (ret <= 0) {
const struct btf_type *local_type; const struct btf_type *local_type;
const char *targ_name, *local_name; const char *targ_name, *local_name;
local_type = btf__type_by_id(obj->btf, local_type_id); local_type = btf__type_by_id(obj->btf, local_type_id);
local_name = btf__name_by_offset(obj->btf, local_name = btf__name_by_offset(obj->btf, local_type->name_off);
local_type->name_off); targ_name = btf__name_by_offset(btf, targ_type->name_off);
targ_name = btf__name_by_offset(obj->btf_vmlinux,
targ_type->name_off);
pr_warn("extern (ksym) '%s': incompatible types, expected [%d] %s %s, but kernel has [%d] %s %s\n", pr_warn("extern (ksym) '%s': incompatible types, expected [%d] %s %s, but kernel has [%d] %s %s\n",
ext->name, local_type_id, ext->name, local_type_id,
...@@ -7370,7 +7383,8 @@ static int bpf_object__resolve_ksyms_btf_id(struct bpf_object *obj) ...@@ -7370,7 +7383,8 @@ static int bpf_object__resolve_ksyms_btf_id(struct bpf_object *obj)
} }
ext->is_set = true; ext->is_set = true;
ext->ksym.vmlinux_btf_id = id; ext->ksym.kernel_btf_obj_fd = btf_fd;
ext->ksym.kernel_btf_id = id;
pr_debug("extern (ksym) '%s': resolved to [%d] %s %s\n", pr_debug("extern (ksym) '%s': resolved to [%d] %s %s\n",
ext->name, id, btf_kind_str(targ_var), targ_var_name); ext->name, id, btf_kind_str(targ_var), targ_var_name);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment