@@ -390,6 +390,12 @@ struct extern_desc {
390390 } kcfg ;
391391 struct {
392392 unsigned long long addr ;
393+
394+ /* target btf_id of the corresponding kernel var. */
395+ int vmlinux_btf_id ;
396+
397+ /* local btf_id of the ksym extern's type. */
398+ __u32 type_id ;
393399 } ksym ;
394400 };
395401};
@@ -2522,12 +2528,23 @@ static int bpf_object__load_vmlinux_btf(struct bpf_object *obj)
25222528{
25232529 bool need_vmlinux_btf = false;
25242530 struct bpf_program * prog ;
2525- int err ;
2531+ int i , err ;
25262532
25272533 /* CO-RE relocations need kernel BTF */
25282534 if (obj -> btf_ext && obj -> btf_ext -> core_relo_info .len )
25292535 need_vmlinux_btf = true;
25302536
2537+ /* Support for typed ksyms needs kernel BTF */
2538+ for (i = 0 ; i < obj -> nr_extern ; i ++ ) {
2539+ const struct extern_desc * ext ;
2540+
2541+ ext = & obj -> externs [i ];
2542+ if (ext -> type == EXT_KSYM && ext -> ksym .type_id ) {
2543+ need_vmlinux_btf = true;
2544+ break ;
2545+ }
2546+ }
2547+
25312548 bpf_object__for_each_program (prog , obj ) {
25322549 if (!prog -> load )
25332550 continue ;
@@ -3156,16 +3173,10 @@ static int bpf_object__collect_externs(struct bpf_object *obj)
31563173 return - ENOTSUP ;
31573174 }
31583175 } else if (strcmp (sec_name , KSYMS_SEC ) == 0 ) {
3159- const struct btf_type * vt ;
3160-
31613176 ksym_sec = sec ;
31623177 ext -> type = EXT_KSYM ;
3163-
3164- vt = skip_mods_and_typedefs (obj -> btf , t -> type , NULL );
3165- if (!btf_is_void (vt )) {
3166- pr_warn ("extern (ksym) '%s' is not typeless (void)\n" , ext_name );
3167- return - ENOTSUP ;
3168- }
3178+ skip_mods_and_typedefs (obj -> btf , t -> type ,
3179+ & ext -> ksym .type_id );
31693180 } else {
31703181 pr_warn ("unrecognized extern section '%s'\n" , sec_name );
31713182 return - ENOTSUP ;
@@ -5800,8 +5811,13 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog)
58005811 insn [0 ].imm = obj -> maps [obj -> kconfig_map_idx ].fd ;
58015812 insn [1 ].imm = ext -> kcfg .data_off ;
58025813 } else /* EXT_KSYM */ {
5803- insn [0 ].imm = (__u32 )ext -> ksym .addr ;
5804- insn [1 ].imm = ext -> ksym .addr >> 32 ;
5814+ if (ext -> ksym .type_id ) { /* typed ksyms */
5815+ insn [0 ].src_reg = BPF_PSEUDO_BTF_ID ;
5816+ insn [0 ].imm = ext -> ksym .vmlinux_btf_id ;
5817+ } else { /* typeless ksyms */
5818+ insn [0 ].imm = (__u32 )ext -> ksym .addr ;
5819+ insn [1 ].imm = ext -> ksym .addr >> 32 ;
5820+ }
58055821 }
58065822 relo -> processed = true;
58075823 break ;
@@ -6933,10 +6949,72 @@ static int bpf_object__read_kallsyms_file(struct bpf_object *obj)
69336949 return err ;
69346950}
69356951
6952+ static int bpf_object__resolve_ksyms_btf_id (struct bpf_object * obj )
6953+ {
6954+ struct extern_desc * ext ;
6955+ int i , id ;
6956+
6957+ for (i = 0 ; i < obj -> nr_extern ; i ++ ) {
6958+ const struct btf_type * targ_var , * targ_type ;
6959+ __u32 targ_type_id , local_type_id ;
6960+ const char * targ_var_name ;
6961+ int ret ;
6962+
6963+ ext = & obj -> externs [i ];
6964+ if (ext -> type != EXT_KSYM || !ext -> ksym .type_id )
6965+ continue ;
6966+
6967+ id = btf__find_by_name_kind (obj -> btf_vmlinux , ext -> name ,
6968+ BTF_KIND_VAR );
6969+ if (id <= 0 ) {
6970+ pr_warn ("extern (ksym) '%s': failed to find BTF ID in vmlinux BTF.\n" ,
6971+ ext -> name );
6972+ return - ESRCH ;
6973+ }
6974+
6975+ /* find local type_id */
6976+ local_type_id = ext -> ksym .type_id ;
6977+
6978+ /* find target type_id */
6979+ targ_var = btf__type_by_id (obj -> btf_vmlinux , id );
6980+ targ_var_name = btf__name_by_offset (obj -> btf_vmlinux ,
6981+ targ_var -> name_off );
6982+ targ_type = skip_mods_and_typedefs (obj -> btf_vmlinux ,
6983+ targ_var -> type ,
6984+ & targ_type_id );
6985+
6986+ ret = bpf_core_types_are_compat (obj -> btf , local_type_id ,
6987+ obj -> btf_vmlinux , targ_type_id );
6988+ if (ret <= 0 ) {
6989+ const struct btf_type * local_type ;
6990+ const char * targ_name , * local_name ;
6991+
6992+ local_type = btf__type_by_id (obj -> btf , local_type_id );
6993+ local_name = btf__name_by_offset (obj -> btf ,
6994+ local_type -> name_off );
6995+ targ_name = btf__name_by_offset (obj -> btf_vmlinux ,
6996+ targ_type -> name_off );
6997+
6998+ pr_warn ("extern (ksym) '%s': incompatible types, expected [%d] %s %s, but kernel has [%d] %s %s\n" ,
6999+ ext -> name , local_type_id ,
7000+ btf_kind_str (local_type ), local_name , targ_type_id ,
7001+ btf_kind_str (targ_type ), targ_name );
7002+ return - EINVAL ;
7003+ }
7004+
7005+ ext -> is_set = true;
7006+ ext -> ksym .vmlinux_btf_id = id ;
7007+ pr_debug ("extern (ksym) '%s': resolved to [%d] %s %s\n" ,
7008+ ext -> name , id , btf_kind_str (targ_var ), targ_var_name );
7009+ }
7010+ return 0 ;
7011+ }
7012+
69367013static int bpf_object__resolve_externs (struct bpf_object * obj ,
69377014 const char * extra_kconfig )
69387015{
69397016 bool need_config = false, need_kallsyms = false;
7017+ bool need_vmlinux_btf = false;
69407018 struct extern_desc * ext ;
69417019 void * kcfg_data = NULL ;
69427020 int err , i ;
@@ -6967,7 +7045,10 @@ static int bpf_object__resolve_externs(struct bpf_object *obj,
69677045 strncmp (ext -> name , "CONFIG_" , 7 ) == 0 ) {
69687046 need_config = true;
69697047 } else if (ext -> type == EXT_KSYM ) {
6970- need_kallsyms = true;
7048+ if (ext -> ksym .type_id )
7049+ need_vmlinux_btf = true;
7050+ else
7051+ need_kallsyms = true;
69717052 } else {
69727053 pr_warn ("unrecognized extern '%s'\n" , ext -> name );
69737054 return - EINVAL ;
@@ -6996,6 +7077,11 @@ static int bpf_object__resolve_externs(struct bpf_object *obj,
69967077 if (err )
69977078 return - EINVAL ;
69987079 }
7080+ if (need_vmlinux_btf ) {
7081+ err = bpf_object__resolve_ksyms_btf_id (obj );
7082+ if (err )
7083+ return - EINVAL ;
7084+ }
69997085 for (i = 0 ; i < obj -> nr_extern ; i ++ ) {
70007086 ext = & obj -> externs [i ];
70017087
@@ -7028,10 +7114,10 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr)
70287114 }
70297115
70307116 err = bpf_object__probe_loading (obj );
7117+ err = err ? : bpf_object__load_vmlinux_btf (obj );
70317118 err = err ? : bpf_object__resolve_externs (obj , obj -> kconfig );
70327119 err = err ? : bpf_object__sanitize_and_load_btf (obj );
70337120 err = err ? : bpf_object__sanitize_maps (obj );
7034- err = err ? : bpf_object__load_vmlinux_btf (obj );
70357121 err = err ? : bpf_object__init_kern_struct_ops_maps (obj );
70367122 err = err ? : bpf_object__create_maps (obj );
70377123 err = err ? : bpf_object__relocate (obj , attr -> target_btf_path );
0 commit comments