@@ -55,6 +55,20 @@ static bool str_has_suffix(const char *str, const char *suffix)
5555 return true;
5656}
5757
58+ static const struct btf_type *
59+ resolve_func_ptr (const struct btf * btf , __u32 id , __u32 * res_id )
60+ {
61+ const struct btf_type * t ;
62+
63+ t = skip_mods_and_typedefs (btf , id , NULL );
64+ if (!btf_is_ptr (t ))
65+ return NULL ;
66+
67+ t = skip_mods_and_typedefs (btf , t -> type , res_id );
68+
69+ return btf_is_func_proto (t ) ? t : NULL ;
70+ }
71+
5872static void get_obj_name (char * name , const char * file )
5973{
6074 char file_copy [PATH_MAX ];
@@ -909,6 +923,207 @@ codegen_progs_skeleton(struct bpf_object *obj, size_t prog_cnt, bool populate_li
909923 }
910924}
911925
926+ static int walk_st_ops_shadow_vars (struct btf * btf , const char * ident ,
927+ const struct btf_type * map_type , __u32 map_type_id )
928+ {
929+ LIBBPF_OPTS (btf_dump_emit_type_decl_opts , opts , .indent_level = 3 );
930+ const struct btf_type * member_type ;
931+ __u32 offset , next_offset = 0 ;
932+ const struct btf_member * m ;
933+ struct btf_dump * d = NULL ;
934+ const char * member_name ;
935+ __u32 member_type_id ;
936+ int i , err = 0 , n ;
937+ int size ;
938+
939+ d = btf_dump__new (btf , codegen_btf_dump_printf , NULL , NULL );
940+ if (!d )
941+ return - errno ;
942+
943+ n = btf_vlen (map_type );
944+ for (i = 0 , m = btf_members (map_type ); i < n ; i ++ , m ++ ) {
945+ member_type = skip_mods_and_typedefs (btf , m -> type , & member_type_id );
946+ member_name = btf__name_by_offset (btf , m -> name_off );
947+
948+ offset = m -> offset / 8 ;
949+ if (next_offset < offset )
950+ printf ("\t\t\tchar __padding_%d[%d];\n" , i , offset - next_offset );
951+
952+ switch (btf_kind (member_type )) {
953+ case BTF_KIND_INT :
954+ case BTF_KIND_FLOAT :
955+ case BTF_KIND_ENUM :
956+ case BTF_KIND_ENUM64 :
957+ /* scalar type */
958+ printf ("\t\t\t" );
959+ opts .field_name = member_name ;
960+ err = btf_dump__emit_type_decl (d , member_type_id , & opts );
961+ if (err ) {
962+ p_err ("Failed to emit type declaration for %s: %d" , member_name , err );
963+ goto out ;
964+ }
965+ printf (";\n" );
966+
967+ size = btf__resolve_size (btf , member_type_id );
968+ if (size < 0 ) {
969+ p_err ("Failed to resolve size of %s: %d\n" , member_name , size );
970+ err = size ;
971+ goto out ;
972+ }
973+
974+ next_offset = offset + size ;
975+ break ;
976+
977+ case BTF_KIND_PTR :
978+ if (resolve_func_ptr (btf , m -> type , NULL )) {
979+ /* Function pointer */
980+ printf ("\t\t\tstruct bpf_program *%s;\n" , member_name );
981+
982+ next_offset = offset + sizeof (void * );
983+ break ;
984+ }
985+ /* All pointer types are unsupported except for
986+ * function pointers.
987+ */
988+ fallthrough ;
989+
990+ default :
991+ /* Unsupported types
992+ *
993+ * Types other than scalar types and function
994+ * pointers are currently not supported in order to
995+ * prevent conflicts in the generated code caused
996+ * by multiple definitions. For instance, if the
997+ * struct type FOO is used in a struct_ops map,
998+ * bpftool has to generate definitions for FOO,
999+ * which may result in conflicts if FOO is defined
1000+ * in different skeleton files.
1001+ */
1002+ size = btf__resolve_size (btf , member_type_id );
1003+ if (size < 0 ) {
1004+ p_err ("Failed to resolve size of %s: %d\n" , member_name , size );
1005+ err = size ;
1006+ goto out ;
1007+ }
1008+ printf ("\t\t\tchar __unsupported_%d[%d];\n" , i , size );
1009+
1010+ next_offset = offset + size ;
1011+ break ;
1012+ }
1013+ }
1014+
1015+ /* Cannot fail since it must be a struct type */
1016+ size = btf__resolve_size (btf , map_type_id );
1017+ if (next_offset < (__u32 )size )
1018+ printf ("\t\t\tchar __padding_end[%d];\n" , size - next_offset );
1019+
1020+ out :
1021+ btf_dump__free (d );
1022+
1023+ return err ;
1024+ }
1025+
1026+ /* Generate the pointer of the shadow type for a struct_ops map.
1027+ *
1028+ * This function adds a pointer of the shadow type for a struct_ops map.
1029+ * The members of a struct_ops map can be exported through a pointer to a
1030+ * shadow type. The user can access these members through the pointer.
1031+ *
1032+ * A shadow type includes not all members, only members of some types.
1033+ * They are scalar types and function pointers. The function pointers are
1034+ * translated to the pointer of the struct bpf_program. The scalar types
1035+ * are translated to the original type without any modifiers.
1036+ *
1037+ * Unsupported types will be translated to a char array to occupy the same
1038+ * space as the original field, being renamed as __unsupported_*. The user
1039+ * should treat these fields as opaque data.
1040+ */
1041+ static int gen_st_ops_shadow_type (const char * obj_name , struct btf * btf , const char * ident ,
1042+ const struct bpf_map * map )
1043+ {
1044+ const struct btf_type * map_type ;
1045+ const char * type_name ;
1046+ __u32 map_type_id ;
1047+ int err ;
1048+
1049+ map_type_id = bpf_map__btf_value_type_id (map );
1050+ if (map_type_id == 0 )
1051+ return - EINVAL ;
1052+ map_type = btf__type_by_id (btf , map_type_id );
1053+ if (!map_type )
1054+ return - EINVAL ;
1055+
1056+ type_name = btf__name_by_offset (btf , map_type -> name_off );
1057+
1058+ printf ("\t\tstruct %s__%s__%s {\n" , obj_name , ident , type_name );
1059+
1060+ err = walk_st_ops_shadow_vars (btf , ident , map_type , map_type_id );
1061+ if (err )
1062+ return err ;
1063+
1064+ printf ("\t\t} *%s;\n" , ident );
1065+
1066+ return 0 ;
1067+ }
1068+
1069+ static int gen_st_ops_shadow (const char * obj_name , struct btf * btf , struct bpf_object * obj )
1070+ {
1071+ int err , st_ops_cnt = 0 ;
1072+ struct bpf_map * map ;
1073+ char ident [256 ];
1074+
1075+ if (!btf )
1076+ return 0 ;
1077+
1078+ /* Generate the pointers to shadow types of
1079+ * struct_ops maps.
1080+ */
1081+ bpf_object__for_each_map (map , obj ) {
1082+ if (bpf_map__type (map ) != BPF_MAP_TYPE_STRUCT_OPS )
1083+ continue ;
1084+ if (!get_map_ident (map , ident , sizeof (ident )))
1085+ continue ;
1086+
1087+ if (st_ops_cnt == 0 ) /* first struct_ops map */
1088+ printf ("\tstruct {\n" );
1089+ st_ops_cnt ++ ;
1090+
1091+ err = gen_st_ops_shadow_type (obj_name , btf , ident , map );
1092+ if (err )
1093+ return err ;
1094+ }
1095+
1096+ if (st_ops_cnt )
1097+ printf ("\t} struct_ops;\n" );
1098+
1099+ return 0 ;
1100+ }
1101+
1102+ /* Generate the code to initialize the pointers of shadow types. */
1103+ static void gen_st_ops_shadow_init (struct btf * btf , struct bpf_object * obj )
1104+ {
1105+ struct bpf_map * map ;
1106+ char ident [256 ];
1107+
1108+ if (!btf )
1109+ return ;
1110+
1111+ /* Initialize the pointers to_ops shadow types of
1112+ * struct_ops maps.
1113+ */
1114+ bpf_object__for_each_map (map , obj ) {
1115+ if (bpf_map__type (map ) != BPF_MAP_TYPE_STRUCT_OPS )
1116+ continue ;
1117+ if (!get_map_ident (map , ident , sizeof (ident )))
1118+ continue ;
1119+ codegen ("\
1120+ \n\
1121+ obj->struct_ops.%1$s = bpf_map__initial_value(obj->maps.%1$s, NULL);\n\
1122+ \n\
1123+ " , ident );
1124+ }
1125+ }
1126+
9121127static int do_skeleton (int argc , char * * argv )
9131128{
9141129 char header_guard [MAX_OBJ_NAME_LEN + sizeof ("__SKEL_H__" )];
@@ -1052,6 +1267,11 @@ static int do_skeleton(int argc, char **argv)
10521267 printf ("\t} maps;\n" );
10531268 }
10541269
1270+ btf = bpf_object__btf (obj );
1271+ err = gen_st_ops_shadow (obj_name , btf , obj );
1272+ if (err )
1273+ goto out ;
1274+
10551275 if (prog_cnt ) {
10561276 printf ("\tstruct {\n" );
10571277 bpf_object__for_each_program (prog , obj ) {
@@ -1075,7 +1295,6 @@ static int do_skeleton(int argc, char **argv)
10751295 printf ("\t} links;\n" );
10761296 }
10771297
1078- btf = bpf_object__btf (obj );
10791298 if (btf ) {
10801299 err = codegen_datasecs (obj , obj_name );
10811300 if (err )
@@ -1133,6 +1352,12 @@ static int do_skeleton(int argc, char **argv)
11331352 if (err) \n\
11341353 goto err_out; \n\
11351354 \n\
1355+ " , obj_name );
1356+
1357+ gen_st_ops_shadow_init (btf , obj );
1358+
1359+ codegen ("\
1360+ \n\
11361361 return obj; \n\
11371362 err_out: \n\
11381363 %1$s__destroy(obj); \n\
@@ -1442,6 +1667,10 @@ static int do_subskeleton(int argc, char **argv)
14421667 printf ("\t} maps;\n" );
14431668 }
14441669
1670+ err = gen_st_ops_shadow (obj_name , btf , obj );
1671+ if (err )
1672+ goto out ;
1673+
14451674 if (prog_cnt ) {
14461675 printf ("\tstruct {\n" );
14471676 bpf_object__for_each_program (prog , obj ) {
@@ -1553,6 +1782,12 @@ static int do_subskeleton(int argc, char **argv)
15531782 if (err) \n\
15541783 goto err; \n\
15551784 \n\
1785+ " );
1786+
1787+ gen_st_ops_shadow_init (btf , obj );
1788+
1789+ codegen ("\
1790+ \n\
15561791 return obj; \n\
15571792 err: \n\
15581793 %1$s__destroy(obj); \n\
0 commit comments