aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrii Nakryiko <andriin@fb.com>2019-06-17 15:26:56 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2019-06-17 18:10:41 -0400
commitabd29c9314595b1ee5ec6c61d7c49a497ffb30a3 (patch)
tree735c42d872ab0846fd58efe03a9fc38989b1ef1c
parent063183bf0486c7e61a2b454896bba2f7908b4ab0 (diff)
libbpf: allow specifying map definitions using BTF
This patch adds support for a new way to define BPF maps. It relies on BTF to describe mandatory and optional attributes of a map, as well as captures type information of key and value naturally. This eliminates the need for BPF_ANNOTATE_KV_PAIR hack and ensures key/value sizes are always in sync with the key/value type. Relying on BTF, this approach allows for both forward and backward compatibility w.r.t. extending supported map definition features. By default, any unrecognized attributes are treated as an error, but it's possible relax this using MAPS_RELAX_COMPAT flag. New attributes, added in the future will need to be optional. The outline of the new map definition (short, BTF-defined maps) is as follows: 1. All the maps should be defined in .maps ELF section. It's possible to have both "legacy" map definitions in `maps` sections and BTF-defined maps in .maps sections. Everything will still work transparently. 2. The map declaration and initialization is done through a global/static variable of a struct type with few mandatory and extra optional fields: - type field is mandatory and specified type of BPF map; - key/value fields are mandatory and capture key/value type/size information; - max_entries attribute is optional; if max_entries is not specified or initialized, it has to be provided in runtime through libbpf API before loading bpf_object; - map_flags is optional and if not defined, will be assumed to be 0. 3. Key/value fields should be **a pointer** to a type describing key/value. The pointee type is assumed (and will be recorded as such and used for size determination) to be a type describing key/value of the map. This is done to save excessive amounts of space allocated in corresponding ELF sections for key/value of big size. 4. As some maps disallow having BTF type ID associated with key/value, it's possible to specify key/value size explicitly without associating BTF type ID with it. Use key_size and value_size fields to do that (see example below). Here's an example of simple ARRAY map defintion: struct my_value { int x, y, z; }; struct { int type; int max_entries; int *key; struct my_value *value; } btf_map SEC(".maps") = { .type = BPF_MAP_TYPE_ARRAY, .max_entries = 16, }; This will define BPF ARRAY map 'btf_map' with 16 elements. The key will be of type int and thus key size will be 4 bytes. The value is struct my_value of size 12 bytes. This map can be used from C code exactly the same as with existing maps defined through struct bpf_map_def. Here's an example of STACKMAP definition (which currently disallows BTF type IDs for key/value): struct { __u32 type; __u32 max_entries; __u32 map_flags; __u32 key_size; __u32 value_size; } stackmap SEC(".maps") = { .type = BPF_MAP_TYPE_STACK_TRACE, .max_entries = 128, .map_flags = BPF_F_STACK_BUILD_ID, .key_size = sizeof(__u32), .value_size = PERF_MAX_STACK_DEPTH * sizeof(struct bpf_stack_build_id), }; This approach is naturally extended to support map-in-map, by making a value field to be another struct that describes inner map. This feature is not implemented yet. It's also possible to incrementally add features like pinning with full backwards and forward compatibility. Support for static initialization of BPF_MAP_TYPE_PROG_ARRAY using pointers to BPF programs is also on the roadmap. Signed-off-by: Andrii Nakryiko <andriin@fb.com> Acked-by: Song Liu <songliubraving@fb.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
-rw-r--r--tools/lib/bpf/btf.h1
-rw-r--r--tools/lib/bpf/libbpf.c353
2 files changed, 345 insertions, 9 deletions
diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h
index ba4ffa831aa4..88a52ae56fc6 100644
--- a/tools/lib/bpf/btf.h
+++ b/tools/lib/bpf/btf.h
@@ -17,6 +17,7 @@ extern "C" {
17 17
18#define BTF_ELF_SEC ".BTF" 18#define BTF_ELF_SEC ".BTF"
19#define BTF_EXT_ELF_SEC ".BTF.ext" 19#define BTF_EXT_ELF_SEC ".BTF.ext"
20#define MAPS_ELF_SEC ".maps"
20 21
21struct btf; 22struct btf;
22struct btf_ext; 23struct btf_ext;
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index da942ab2f06a..585e3a2f1eb4 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -262,6 +262,7 @@ struct bpf_object {
262 } *reloc; 262 } *reloc;
263 int nr_reloc; 263 int nr_reloc;
264 int maps_shndx; 264 int maps_shndx;
265 int btf_maps_shndx;
265 int text_shndx; 266 int text_shndx;
266 int data_shndx; 267 int data_shndx;
267 int rodata_shndx; 268 int rodata_shndx;
@@ -514,6 +515,7 @@ static struct bpf_object *bpf_object__new(const char *path,
514 obj->efile.obj_buf = obj_buf; 515 obj->efile.obj_buf = obj_buf;
515 obj->efile.obj_buf_sz = obj_buf_sz; 516 obj->efile.obj_buf_sz = obj_buf_sz;
516 obj->efile.maps_shndx = -1; 517 obj->efile.maps_shndx = -1;
518 obj->efile.btf_maps_shndx = -1;
517 obj->efile.data_shndx = -1; 519 obj->efile.data_shndx = -1;
518 obj->efile.rodata_shndx = -1; 520 obj->efile.rodata_shndx = -1;
519 obj->efile.bss_shndx = -1; 521 obj->efile.bss_shndx = -1;
@@ -1007,6 +1009,312 @@ static int bpf_object__init_user_maps(struct bpf_object *obj, bool strict)
1007 return 0; 1009 return 0;
1008} 1010}
1009 1011
1012static const struct btf_type *skip_mods_and_typedefs(const struct btf *btf,
1013 __u32 id)
1014{
1015 const struct btf_type *t = btf__type_by_id(btf, id);
1016
1017 while (true) {
1018 switch (BTF_INFO_KIND(t->info)) {
1019 case BTF_KIND_VOLATILE:
1020 case BTF_KIND_CONST:
1021 case BTF_KIND_RESTRICT:
1022 case BTF_KIND_TYPEDEF:
1023 t = btf__type_by_id(btf, t->type);
1024 break;
1025 default:
1026 return t;
1027 }
1028 }
1029}
1030
1031static bool get_map_field_int(const char *map_name,
1032 const struct btf *btf,
1033 const struct btf_type *def,
1034 const struct btf_member *m,
1035 const void *data, __u32 *res) {
1036 const struct btf_type *t = skip_mods_and_typedefs(btf, m->type);
1037 const char *name = btf__name_by_offset(btf, m->name_off);
1038 __u32 int_info = *(const __u32 *)(const void *)(t + 1);
1039
1040 if (BTF_INFO_KIND(t->info) != BTF_KIND_INT) {
1041 pr_warning("map '%s': attr '%s': expected INT, got %u.\n",
1042 map_name, name, BTF_INFO_KIND(t->info));
1043 return false;
1044 }
1045 if (t->size != 4 || BTF_INT_BITS(int_info) != 32 ||
1046 BTF_INT_OFFSET(int_info)) {
1047 pr_warning("map '%s': attr '%s': expected 32-bit non-bitfield integer, "
1048 "got %u-byte (%d-bit) one with bit offset %d.\n",
1049 map_name, name, t->size, BTF_INT_BITS(int_info),
1050 BTF_INT_OFFSET(int_info));
1051 return false;
1052 }
1053 if (BTF_INFO_KFLAG(def->info) && BTF_MEMBER_BITFIELD_SIZE(m->offset)) {
1054 pr_warning("map '%s': attr '%s': bitfield is not supported.\n",
1055 map_name, name);
1056 return false;
1057 }
1058 if (m->offset % 32) {
1059 pr_warning("map '%s': attr '%s': unaligned fields are not supported.\n",
1060 map_name, name);
1061 return false;
1062 }
1063
1064 *res = *(const __u32 *)(data + m->offset / 8);
1065 return true;
1066}
1067
1068static int bpf_object__init_user_btf_map(struct bpf_object *obj,
1069 const struct btf_type *sec,
1070 int var_idx, int sec_idx,
1071 const Elf_Data *data, bool strict)
1072{
1073 const struct btf_type *var, *def, *t;
1074 const struct btf_var_secinfo *vi;
1075 const struct btf_var *var_extra;
1076 const struct btf_member *m;
1077 const void *def_data;
1078 const char *map_name;
1079 struct bpf_map *map;
1080 int vlen, i;
1081
1082 vi = (const struct btf_var_secinfo *)(const void *)(sec + 1) + var_idx;
1083 var = btf__type_by_id(obj->btf, vi->type);
1084 var_extra = (const void *)(var + 1);
1085 map_name = btf__name_by_offset(obj->btf, var->name_off);
1086 vlen = BTF_INFO_VLEN(var->info);
1087
1088 if (map_name == NULL || map_name[0] == '\0') {
1089 pr_warning("map #%d: empty name.\n", var_idx);
1090 return -EINVAL;
1091 }
1092 if ((__u64)vi->offset + vi->size > data->d_size) {
1093 pr_warning("map '%s' BTF data is corrupted.\n", map_name);
1094 return -EINVAL;
1095 }
1096 if (BTF_INFO_KIND(var->info) != BTF_KIND_VAR) {
1097 pr_warning("map '%s': unexpected var kind %u.\n",
1098 map_name, BTF_INFO_KIND(var->info));
1099 return -EINVAL;
1100 }
1101 if (var_extra->linkage != BTF_VAR_GLOBAL_ALLOCATED &&
1102 var_extra->linkage != BTF_VAR_STATIC) {
1103 pr_warning("map '%s': unsupported var linkage %u.\n",
1104 map_name, var_extra->linkage);
1105 return -EOPNOTSUPP;
1106 }
1107
1108 def = skip_mods_and_typedefs(obj->btf, var->type);
1109 if (BTF_INFO_KIND(def->info) != BTF_KIND_STRUCT) {
1110 pr_warning("map '%s': unexpected def kind %u.\n",
1111 map_name, BTF_INFO_KIND(var->info));
1112 return -EINVAL;
1113 }
1114 if (def->size > vi->size) {
1115 pr_warning("map '%s': invalid def size.\n", map_name);
1116 return -EINVAL;
1117 }
1118
1119 map = bpf_object__add_map(obj);
1120 if (IS_ERR(map))
1121 return PTR_ERR(map);
1122 map->name = strdup(map_name);
1123 if (!map->name) {
1124 pr_warning("map '%s': failed to alloc map name.\n", map_name);
1125 return -ENOMEM;
1126 }
1127 map->libbpf_type = LIBBPF_MAP_UNSPEC;
1128 map->def.type = BPF_MAP_TYPE_UNSPEC;
1129 map->sec_idx = sec_idx;
1130 map->sec_offset = vi->offset;
1131 pr_debug("map '%s': at sec_idx %d, offset %zu.\n",
1132 map_name, map->sec_idx, map->sec_offset);
1133
1134 def_data = data->d_buf + vi->offset;
1135 vlen = BTF_INFO_VLEN(def->info);
1136 m = (const void *)(def + 1);
1137 for (i = 0; i < vlen; i++, m++) {
1138 const char *name = btf__name_by_offset(obj->btf, m->name_off);
1139
1140 if (!name) {
1141 pr_warning("map '%s': invalid field #%d.\n",
1142 map_name, i);
1143 return -EINVAL;
1144 }
1145 if (strcmp(name, "type") == 0) {
1146 if (!get_map_field_int(map_name, obj->btf, def, m,
1147 def_data, &map->def.type))
1148 return -EINVAL;
1149 pr_debug("map '%s': found type = %u.\n",
1150 map_name, map->def.type);
1151 } else if (strcmp(name, "max_entries") == 0) {
1152 if (!get_map_field_int(map_name, obj->btf, def, m,
1153 def_data, &map->def.max_entries))
1154 return -EINVAL;
1155 pr_debug("map '%s': found max_entries = %u.\n",
1156 map_name, map->def.max_entries);
1157 } else if (strcmp(name, "map_flags") == 0) {
1158 if (!get_map_field_int(map_name, obj->btf, def, m,
1159 def_data, &map->def.map_flags))
1160 return -EINVAL;
1161 pr_debug("map '%s': found map_flags = %u.\n",
1162 map_name, map->def.map_flags);
1163 } else if (strcmp(name, "key_size") == 0) {
1164 __u32 sz;
1165
1166 if (!get_map_field_int(map_name, obj->btf, def, m,
1167 def_data, &sz))
1168 return -EINVAL;
1169 pr_debug("map '%s': found key_size = %u.\n",
1170 map_name, sz);
1171 if (map->def.key_size && map->def.key_size != sz) {
1172 pr_warning("map '%s': conflictling key size %u != %u.\n",
1173 map_name, map->def.key_size, sz);
1174 return -EINVAL;
1175 }
1176 map->def.key_size = sz;
1177 } else if (strcmp(name, "key") == 0) {
1178 __s64 sz;
1179
1180 t = btf__type_by_id(obj->btf, m->type);
1181 if (!t) {
1182 pr_warning("map '%s': key type [%d] not found.\n",
1183 map_name, m->type);
1184 return -EINVAL;
1185 }
1186 if (BTF_INFO_KIND(t->info) != BTF_KIND_PTR) {
1187 pr_warning("map '%s': key spec is not PTR: %u.\n",
1188 map_name, BTF_INFO_KIND(t->info));
1189 return -EINVAL;
1190 }
1191 sz = btf__resolve_size(obj->btf, t->type);
1192 if (sz < 0) {
1193 pr_warning("map '%s': can't determine key size for type [%u]: %lld.\n",
1194 map_name, t->type, sz);
1195 return sz;
1196 }
1197 pr_debug("map '%s': found key [%u], sz = %lld.\n",
1198 map_name, t->type, sz);
1199 if (map->def.key_size && map->def.key_size != sz) {
1200 pr_warning("map '%s': conflictling key size %u != %lld.\n",
1201 map_name, map->def.key_size, sz);
1202 return -EINVAL;
1203 }
1204 map->def.key_size = sz;
1205 map->btf_key_type_id = t->type;
1206 } else if (strcmp(name, "value_size") == 0) {
1207 __u32 sz;
1208
1209 if (!get_map_field_int(map_name, obj->btf, def, m,
1210 def_data, &sz))
1211 return -EINVAL;
1212 pr_debug("map '%s': found value_size = %u.\n",
1213 map_name, sz);
1214 if (map->def.value_size && map->def.value_size != sz) {
1215 pr_warning("map '%s': conflictling value size %u != %u.\n",
1216 map_name, map->def.value_size, sz);
1217 return -EINVAL;
1218 }
1219 map->def.value_size = sz;
1220 } else if (strcmp(name, "value") == 0) {
1221 __s64 sz;
1222
1223 t = btf__type_by_id(obj->btf, m->type);
1224 if (!t) {
1225 pr_warning("map '%s': value type [%d] not found.\n",
1226 map_name, m->type);
1227 return -EINVAL;
1228 }
1229 if (BTF_INFO_KIND(t->info) != BTF_KIND_PTR) {
1230 pr_warning("map '%s': value spec is not PTR: %u.\n",
1231 map_name, BTF_INFO_KIND(t->info));
1232 return -EINVAL;
1233 }
1234 sz = btf__resolve_size(obj->btf, t->type);
1235 if (sz < 0) {
1236 pr_warning("map '%s': can't determine value size for type [%u]: %lld.\n",
1237 map_name, t->type, sz);
1238 return sz;
1239 }
1240 pr_debug("map '%s': found value [%u], sz = %lld.\n",
1241 map_name, t->type, sz);
1242 if (map->def.value_size && map->def.value_size != sz) {
1243 pr_warning("map '%s': conflictling value size %u != %lld.\n",
1244 map_name, map->def.value_size, sz);
1245 return -EINVAL;
1246 }
1247 map->def.value_size = sz;
1248 map->btf_value_type_id = t->type;
1249 } else {
1250 if (strict) {
1251 pr_warning("map '%s': unknown field '%s'.\n",
1252 map_name, name);
1253 return -ENOTSUP;
1254 }
1255 pr_debug("map '%s': ignoring unknown field '%s'.\n",
1256 map_name, name);
1257 }
1258 }
1259
1260 if (map->def.type == BPF_MAP_TYPE_UNSPEC) {
1261 pr_warning("map '%s': map type isn't specified.\n", map_name);
1262 return -EINVAL;
1263 }
1264
1265 return 0;
1266}
1267
1268static int bpf_object__init_user_btf_maps(struct bpf_object *obj, bool strict)
1269{
1270 const struct btf_type *sec = NULL;
1271 int nr_types, i, vlen, err;
1272 const struct btf_type *t;
1273 const char *name;
1274 Elf_Data *data;
1275 Elf_Scn *scn;
1276
1277 if (obj->efile.btf_maps_shndx < 0)
1278 return 0;
1279
1280 scn = elf_getscn(obj->efile.elf, obj->efile.btf_maps_shndx);
1281 if (scn)
1282 data = elf_getdata(scn, NULL);
1283 if (!scn || !data) {
1284 pr_warning("failed to get Elf_Data from map section %d (%s)\n",
1285 obj->efile.maps_shndx, MAPS_ELF_SEC);
1286 return -EINVAL;
1287 }
1288
1289 nr_types = btf__get_nr_types(obj->btf);
1290 for (i = 1; i <= nr_types; i++) {
1291 t = btf__type_by_id(obj->btf, i);
1292 if (BTF_INFO_KIND(t->info) != BTF_KIND_DATASEC)
1293 continue;
1294 name = btf__name_by_offset(obj->btf, t->name_off);
1295 if (strcmp(name, MAPS_ELF_SEC) == 0) {
1296 sec = t;
1297 break;
1298 }
1299 }
1300
1301 if (!sec) {
1302 pr_warning("DATASEC '%s' not found.\n", MAPS_ELF_SEC);
1303 return -ENOENT;
1304 }
1305
1306 vlen = BTF_INFO_VLEN(sec->info);
1307 for (i = 0; i < vlen; i++) {
1308 err = bpf_object__init_user_btf_map(obj, sec, i,
1309 obj->efile.btf_maps_shndx,
1310 data, strict);
1311 if (err)
1312 return err;
1313 }
1314
1315 return 0;
1316}
1317
1010static int bpf_object__init_maps(struct bpf_object *obj, int flags) 1318static int bpf_object__init_maps(struct bpf_object *obj, int flags)
1011{ 1319{
1012 bool strict = !(flags & MAPS_RELAX_COMPAT); 1320 bool strict = !(flags & MAPS_RELAX_COMPAT);
@@ -1016,6 +1324,10 @@ static int bpf_object__init_maps(struct bpf_object *obj, int flags)
1016 if (err) 1324 if (err)
1017 return err; 1325 return err;
1018 1326
1327 err = bpf_object__init_user_btf_maps(obj, strict);
1328 if (err)
1329 return err;
1330
1019 err = bpf_object__init_global_data_maps(obj); 1331 err = bpf_object__init_global_data_maps(obj);
1020 if (err) 1332 if (err)
1021 return err; 1333 return err;
@@ -1113,10 +1425,16 @@ static void bpf_object__sanitize_btf_ext(struct bpf_object *obj)
1113 } 1425 }
1114} 1426}
1115 1427
1428static bool bpf_object__is_btf_mandatory(const struct bpf_object *obj)
1429{
1430 return obj->efile.btf_maps_shndx >= 0;
1431}
1432
1116static int bpf_object__init_btf(struct bpf_object *obj, 1433static int bpf_object__init_btf(struct bpf_object *obj,
1117 Elf_Data *btf_data, 1434 Elf_Data *btf_data,
1118 Elf_Data *btf_ext_data) 1435 Elf_Data *btf_ext_data)
1119{ 1436{
1437 bool btf_required = bpf_object__is_btf_mandatory(obj);
1120 int err = 0; 1438 int err = 0;
1121 1439
1122 if (btf_data) { 1440 if (btf_data) {
@@ -1150,10 +1468,18 @@ static int bpf_object__init_btf(struct bpf_object *obj,
1150 } 1468 }
1151out: 1469out:
1152 if (err || IS_ERR(obj->btf)) { 1470 if (err || IS_ERR(obj->btf)) {
1471 if (btf_required)
1472 err = err ? : PTR_ERR(obj->btf);
1473 else
1474 err = 0;
1153 if (!IS_ERR_OR_NULL(obj->btf)) 1475 if (!IS_ERR_OR_NULL(obj->btf))
1154 btf__free(obj->btf); 1476 btf__free(obj->btf);
1155 obj->btf = NULL; 1477 obj->btf = NULL;
1156 } 1478 }
1479 if (btf_required && !obj->btf) {
1480 pr_warning("BTF is required, but is missing or corrupted.\n");
1481 return err == 0 ? -ENOENT : err;
1482 }
1157 return 0; 1483 return 0;
1158} 1484}
1159 1485
@@ -1173,6 +1499,8 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj)
1173 BTF_ELF_SEC, err); 1499 BTF_ELF_SEC, err);
1174 btf__free(obj->btf); 1500 btf__free(obj->btf);
1175 obj->btf = NULL; 1501 obj->btf = NULL;
1502 if (bpf_object__is_btf_mandatory(obj))
1503 return err;
1176 } 1504 }
1177 return 0; 1505 return 0;
1178} 1506}
@@ -1236,6 +1564,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags)
1236 return err; 1564 return err;
1237 } else if (strcmp(name, "maps") == 0) { 1565 } else if (strcmp(name, "maps") == 0) {
1238 obj->efile.maps_shndx = idx; 1566 obj->efile.maps_shndx = idx;
1567 } else if (strcmp(name, MAPS_ELF_SEC) == 0) {
1568 obj->efile.btf_maps_shndx = idx;
1239 } else if (strcmp(name, BTF_ELF_SEC) == 0) { 1569 } else if (strcmp(name, BTF_ELF_SEC) == 0) {
1240 btf_data = data; 1570 btf_data = data;
1241 } else if (strcmp(name, BTF_EXT_ELF_SEC) == 0) { 1571 } else if (strcmp(name, BTF_EXT_ELF_SEC) == 0) {
@@ -1355,7 +1685,8 @@ static bool bpf_object__shndx_is_data(const struct bpf_object *obj,
1355static bool bpf_object__shndx_is_maps(const struct bpf_object *obj, 1685static bool bpf_object__shndx_is_maps(const struct bpf_object *obj,
1356 int shndx) 1686 int shndx)
1357{ 1687{
1358 return shndx == obj->efile.maps_shndx; 1688 return shndx == obj->efile.maps_shndx ||
1689 shndx == obj->efile.btf_maps_shndx;
1359} 1690}
1360 1691
1361static bool bpf_object__relo_in_known_section(const struct bpf_object *obj, 1692static bool bpf_object__relo_in_known_section(const struct bpf_object *obj,
@@ -1399,14 +1730,14 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr,
1399 prog->nr_reloc = nrels; 1730 prog->nr_reloc = nrels;
1400 1731
1401 for (i = 0; i < nrels; i++) { 1732 for (i = 0; i < nrels; i++) {
1402 GElf_Sym sym;
1403 GElf_Rel rel;
1404 unsigned int insn_idx;
1405 unsigned int shdr_idx;
1406 struct bpf_insn *insns = prog->insns; 1733 struct bpf_insn *insns = prog->insns;
1407 enum libbpf_map_type type; 1734 enum libbpf_map_type type;
1735 unsigned int insn_idx;
1736 unsigned int shdr_idx;
1408 const char *name; 1737 const char *name;
1409 size_t map_idx; 1738 size_t map_idx;
1739 GElf_Sym sym;
1740 GElf_Rel rel;
1410 1741
1411 if (!gelf_getrel(data, i, &rel)) { 1742 if (!gelf_getrel(data, i, &rel)) {
1412 pr_warning("relocation: failed to get %d reloc\n", i); 1743 pr_warning("relocation: failed to get %d reloc\n", i);
@@ -1500,14 +1831,18 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr,
1500 return 0; 1831 return 0;
1501} 1832}
1502 1833
1503static int bpf_map_find_btf_info(struct bpf_map *map, const struct btf *btf) 1834static int bpf_map_find_btf_info(struct bpf_object *obj, struct bpf_map *map)
1504{ 1835{
1505 struct bpf_map_def *def = &map->def; 1836 struct bpf_map_def *def = &map->def;
1506 __u32 key_type_id = 0, value_type_id = 0; 1837 __u32 key_type_id = 0, value_type_id = 0;
1507 int ret; 1838 int ret;
1508 1839
1840 /* if it's BTF-defined map, we don't need to search for type IDs */
1841 if (map->sec_idx == obj->efile.btf_maps_shndx)
1842 return 0;
1843
1509 if (!bpf_map__is_internal(map)) { 1844 if (!bpf_map__is_internal(map)) {
1510 ret = btf__get_map_kv_tids(btf, map->name, def->key_size, 1845 ret = btf__get_map_kv_tids(obj->btf, map->name, def->key_size,
1511 def->value_size, &key_type_id, 1846 def->value_size, &key_type_id,
1512 &value_type_id); 1847 &value_type_id);
1513 } else { 1848 } else {
@@ -1515,7 +1850,7 @@ static int bpf_map_find_btf_info(struct bpf_map *map, const struct btf *btf)
1515 * LLVM annotates global data differently in BTF, that is, 1850 * LLVM annotates global data differently in BTF, that is,
1516 * only as '.data', '.bss' or '.rodata'. 1851 * only as '.data', '.bss' or '.rodata'.
1517 */ 1852 */
1518 ret = btf__find_by_name(btf, 1853 ret = btf__find_by_name(obj->btf,
1519 libbpf_type_to_btf_name[map->libbpf_type]); 1854 libbpf_type_to_btf_name[map->libbpf_type]);
1520 } 1855 }
1521 if (ret < 0) 1856 if (ret < 0)
@@ -1805,7 +2140,7 @@ bpf_object__create_maps(struct bpf_object *obj)
1805 map->inner_map_fd >= 0) 2140 map->inner_map_fd >= 0)
1806 create_attr.inner_map_fd = map->inner_map_fd; 2141 create_attr.inner_map_fd = map->inner_map_fd;
1807 2142
1808 if (obj->btf && !bpf_map_find_btf_info(map, obj->btf)) { 2143 if (obj->btf && !bpf_map_find_btf_info(obj, map)) {
1809 create_attr.btf_fd = btf__fd(obj->btf); 2144 create_attr.btf_fd = btf__fd(obj->btf);
1810 create_attr.btf_key_type_id = map->btf_key_type_id; 2145 create_attr.btf_key_type_id = map->btf_key_type_id;
1811 create_attr.btf_value_type_id = map->btf_value_type_id; 2146 create_attr.btf_value_type_id = map->btf_value_type_id;