0001
0002 #include <test_progs.h>
0003 #include <bpf/btf.h>
0004
0005 static int duration = 0;
0006
0007 void btf_dump_printf(void *ctx, const char *fmt, va_list args)
0008 {
0009 vfprintf(ctx, fmt, args);
0010 }
0011
0012 static struct btf_dump_test_case {
0013 const char *name;
0014 const char *file;
0015 bool known_ptr_sz;
0016 } btf_dump_test_cases[] = {
0017 {"btf_dump: syntax", "btf_dump_test_case_syntax", true},
0018 {"btf_dump: ordering", "btf_dump_test_case_ordering", false},
0019 {"btf_dump: padding", "btf_dump_test_case_padding", true},
0020 {"btf_dump: packing", "btf_dump_test_case_packing", true},
0021 {"btf_dump: bitfields", "btf_dump_test_case_bitfields", true},
0022 {"btf_dump: multidim", "btf_dump_test_case_multidim", false},
0023 {"btf_dump: namespacing", "btf_dump_test_case_namespacing", false},
0024 };
0025
0026 static int btf_dump_all_types(const struct btf *btf, void *ctx)
0027 {
0028 size_t type_cnt = btf__type_cnt(btf);
0029 struct btf_dump *d;
0030 int err = 0, id;
0031
0032 d = btf_dump__new(btf, btf_dump_printf, ctx, NULL);
0033 err = libbpf_get_error(d);
0034 if (err)
0035 return err;
0036
0037 for (id = 1; id < type_cnt; id++) {
0038 err = btf_dump__dump_type(d, id);
0039 if (err)
0040 goto done;
0041 }
0042
0043 done:
0044 btf_dump__free(d);
0045 return err;
0046 }
0047
0048 static int test_btf_dump_case(int n, struct btf_dump_test_case *t)
0049 {
0050 char test_file[256], out_file[256], diff_cmd[1024];
0051 struct btf *btf = NULL;
0052 int err = 0, fd = -1;
0053 FILE *f = NULL;
0054
0055 snprintf(test_file, sizeof(test_file), "%s.o", t->file);
0056
0057 btf = btf__parse_elf(test_file, NULL);
0058 if (!ASSERT_OK_PTR(btf, "btf_parse_elf")) {
0059 err = -PTR_ERR(btf);
0060 btf = NULL;
0061 goto done;
0062 }
0063
0064
0065
0066
0067
0068
0069 if (!t->known_ptr_sz) {
0070 btf__set_pointer_size(btf, 8);
0071 } else {
0072 CHECK(btf__pointer_size(btf) != 8, "ptr_sz", "exp %d, got %zu\n",
0073 8, btf__pointer_size(btf));
0074 }
0075
0076 snprintf(out_file, sizeof(out_file), "/tmp/%s.output.XXXXXX", t->file);
0077 fd = mkstemp(out_file);
0078 if (!ASSERT_GE(fd, 0, "create_tmp")) {
0079 err = fd;
0080 goto done;
0081 }
0082 f = fdopen(fd, "w");
0083 if (CHECK(f == NULL, "open_tmp", "failed to open file: %s(%d)\n",
0084 strerror(errno), errno)) {
0085 close(fd);
0086 goto done;
0087 }
0088
0089 err = btf_dump_all_types(btf, f);
0090 fclose(f);
0091 close(fd);
0092 if (CHECK(err, "btf_dump", "failure during C dumping: %d\n", err)) {
0093 goto done;
0094 }
0095
0096 snprintf(test_file, sizeof(test_file), "progs/%s.c", t->file);
0097 if (access(test_file, R_OK) == -1)
0098
0099
0100
0101
0102 snprintf(test_file, sizeof(test_file), "%s.c", t->file);
0103
0104
0105
0106
0107
0108
0109
0110 snprintf(diff_cmd, sizeof(diff_cmd),
0111 "awk '/START-EXPECTED-OUTPUT/{out=1;next} "
0112 "/END-EXPECTED-OUTPUT/{out=0} "
0113 "/\\/\\*|\\*\\//{next} "
0114 "out {sub(/^[ \\t]*\\*/, \"\"); print}' '%s' | diff -u - '%s'",
0115 test_file, out_file);
0116 err = system(diff_cmd);
0117 if (CHECK(err, "diff",
0118 "differing test output, output=%s, err=%d, diff cmd:\n%s\n",
0119 out_file, err, diff_cmd))
0120 goto done;
0121
0122 remove(out_file);
0123
0124 done:
0125 btf__free(btf);
0126 return err;
0127 }
0128
0129 static char *dump_buf;
0130 static size_t dump_buf_sz;
0131 static FILE *dump_buf_file;
0132
0133 static void test_btf_dump_incremental(void)
0134 {
0135 struct btf *btf = NULL;
0136 struct btf_dump *d = NULL;
0137 int id, err, i;
0138
0139 dump_buf_file = open_memstream(&dump_buf, &dump_buf_sz);
0140 if (!ASSERT_OK_PTR(dump_buf_file, "dump_memstream"))
0141 return;
0142 btf = btf__new_empty();
0143 if (!ASSERT_OK_PTR(btf, "new_empty"))
0144 goto err_out;
0145 d = btf_dump__new(btf, btf_dump_printf, dump_buf_file, NULL);
0146 if (!ASSERT_OK(libbpf_get_error(d), "btf_dump__new"))
0147 goto err_out;
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162 id = btf__add_enum(btf, "x", 4);
0163 ASSERT_EQ(id, 1, "enum_declaration_id");
0164 id = btf__add_enum(btf, "x", 4);
0165 ASSERT_EQ(id, 2, "named_enum_id");
0166 err = btf__add_enum_value(btf, "X", 1);
0167 ASSERT_OK(err, "named_enum_val_ok");
0168
0169 id = btf__add_enum(btf, NULL, 4);
0170 ASSERT_EQ(id, 3, "anon_enum_id");
0171 err = btf__add_enum_value(btf, "Y", 1);
0172 ASSERT_OK(err, "anon_enum_val_ok");
0173
0174 id = btf__add_int(btf, "int", 4, BTF_INT_SIGNED);
0175 ASSERT_EQ(id, 4, "int_id");
0176
0177 id = btf__add_fwd(btf, "s", BTF_FWD_STRUCT);
0178 ASSERT_EQ(id, 5, "fwd_id");
0179
0180 id = btf__add_struct(btf, "s", 4);
0181 ASSERT_EQ(id, 6, "struct_id");
0182 err = btf__add_field(btf, "x", 4, 0, 0);
0183 ASSERT_OK(err, "field_ok");
0184
0185 for (i = 1; i < btf__type_cnt(btf); i++) {
0186 err = btf_dump__dump_type(d, i);
0187 ASSERT_OK(err, "dump_type_ok");
0188 }
0189
0190 fflush(dump_buf_file);
0191 dump_buf[dump_buf_sz] = 0;
0192
0193 ASSERT_STREQ(dump_buf,
0194 "enum x;\n"
0195 "\n"
0196 "enum x {\n"
0197 " X = 1,\n"
0198 "};\n"
0199 "\n"
0200 "enum {\n"
0201 " Y = 1,\n"
0202 "};\n"
0203 "\n"
0204 "struct s;\n"
0205 "\n"
0206 "struct s {\n"
0207 " int x;\n"
0208 "};\n\n", "c_dump1");
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224 fseek(dump_buf_file, 0, SEEK_SET);
0225
0226 id = btf__add_struct(btf, "s", 4);
0227 ASSERT_EQ(id, 7, "struct_id");
0228 err = btf__add_field(btf, "x", 2, 0, 0);
0229 ASSERT_OK(err, "field_ok");
0230 err = btf__add_field(btf, "y", 3, 32, 0);
0231 ASSERT_OK(err, "field_ok");
0232 err = btf__add_field(btf, "s", 6, 64, 0);
0233 ASSERT_OK(err, "field_ok");
0234
0235 for (i = 1; i < btf__type_cnt(btf); i++) {
0236 err = btf_dump__dump_type(d, i);
0237 ASSERT_OK(err, "dump_type_ok");
0238 }
0239
0240 fflush(dump_buf_file);
0241 dump_buf[dump_buf_sz] = 0;
0242 ASSERT_STREQ(dump_buf,
0243 "struct s___2 {\n"
0244 " enum x x;\n"
0245 " enum {\n"
0246 " Y___2 = 1,\n"
0247 " } y;\n"
0248 " struct s s;\n"
0249 "};\n\n" , "c_dump1");
0250
0251 err_out:
0252 fclose(dump_buf_file);
0253 free(dump_buf);
0254 btf_dump__free(d);
0255 btf__free(btf);
0256 }
0257
0258 #define STRSIZE 4096
0259
0260 static void btf_dump_snprintf(void *ctx, const char *fmt, va_list args)
0261 {
0262 char *s = ctx, new[STRSIZE];
0263
0264 vsnprintf(new, STRSIZE, fmt, args);
0265 if (strlen(s) < STRSIZE)
0266 strncat(s, new, STRSIZE - strlen(s) - 1);
0267 }
0268
0269 static int btf_dump_data(struct btf *btf, struct btf_dump *d,
0270 char *name, char *prefix, __u64 flags, void *ptr,
0271 size_t ptr_sz, char *str, const char *expected_val)
0272 {
0273 DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts);
0274 size_t type_sz;
0275 __s32 type_id;
0276 int ret = 0;
0277
0278 if (flags & BTF_F_COMPACT)
0279 opts.compact = true;
0280 if (flags & BTF_F_NONAME)
0281 opts.skip_names = true;
0282 if (flags & BTF_F_ZERO)
0283 opts.emit_zeroes = true;
0284 if (prefix) {
0285 ASSERT_STRNEQ(name, prefix, strlen(prefix),
0286 "verify prefix match");
0287 name += strlen(prefix) + 1;
0288 }
0289 type_id = btf__find_by_name(btf, name);
0290 if (!ASSERT_GE(type_id, 0, "find type id"))
0291 return -ENOENT;
0292 type_sz = btf__resolve_size(btf, type_id);
0293 str[0] = '\0';
0294 ret = btf_dump__dump_type_data(d, type_id, ptr, ptr_sz, &opts);
0295 if (type_sz <= ptr_sz) {
0296 if (!ASSERT_EQ(ret, type_sz, "failed/unexpected type_sz"))
0297 return -EINVAL;
0298 } else {
0299 if (!ASSERT_EQ(ret, -E2BIG, "failed to return -E2BIG"))
0300 return -EINVAL;
0301 }
0302 if (!ASSERT_STREQ(str, expected_val, "ensure expected/actual match"))
0303 return -EFAULT;
0304 return 0;
0305 }
0306
0307 #define TEST_BTF_DUMP_DATA(_b, _d, _prefix, _str, _type, _flags, \
0308 _expected, ...) \
0309 do { \
0310 char __ptrtype[64] = #_type; \
0311 char *_ptrtype = (char *)__ptrtype; \
0312 _type _ptrdata = __VA_ARGS__; \
0313 void *_ptr = &_ptrdata; \
0314 \
0315 (void) btf_dump_data(_b, _d, _ptrtype, _prefix, _flags, \
0316 _ptr, sizeof(_type), _str, \
0317 _expected); \
0318 } while (0)
0319
0320
0321 #define TEST_BTF_DUMP_DATA_C(_b, _d, _prefix, _str, _type, _flags, \
0322 ...) \
0323 TEST_BTF_DUMP_DATA(_b, _d, _prefix, _str, _type, _flags, \
0324 "(" #_type ")" #__VA_ARGS__, __VA_ARGS__)
0325
0326
0327 #define TEST_BTF_DUMP_DATA_OVER(_b, _d, _prefix, _str, _type, _type_sz, \
0328 _expected, ...) \
0329 do { \
0330 char __ptrtype[64] = #_type; \
0331 char *_ptrtype = (char *)__ptrtype; \
0332 _type _ptrdata = __VA_ARGS__; \
0333 void *_ptr = &_ptrdata; \
0334 \
0335 (void) btf_dump_data(_b, _d, _ptrtype, _prefix, 0, \
0336 _ptr, _type_sz, _str, _expected); \
0337 } while (0)
0338
0339 #define TEST_BTF_DUMP_VAR(_b, _d, _prefix, _str, _var, _type, _flags, \
0340 _expected, ...) \
0341 do { \
0342 _type _ptrdata = __VA_ARGS__; \
0343 void *_ptr = &_ptrdata; \
0344 \
0345 (void) btf_dump_data(_b, _d, _var, _prefix, _flags, \
0346 _ptr, sizeof(_type), _str, \
0347 _expected); \
0348 } while (0)
0349
0350 static void test_btf_dump_int_data(struct btf *btf, struct btf_dump *d,
0351 char *str)
0352 {
0353 #ifdef __SIZEOF_INT128__
0354 unsigned __int128 i = 0xffffffffffffffff;
0355
0356
0357
0358
0359 i = (i << 64) | (i - 1);
0360 #endif
0361
0362 TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, int, BTF_F_COMPACT, 1234);
0363 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_NONAME,
0364 "1234", 1234);
0365 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, 0, "(int)1234", 1234);
0366
0367
0368 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT, "(int)0", 0);
0369 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_NONAME,
0370 "0", 0);
0371 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_ZERO,
0372 "(int)0", 0);
0373 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int,
0374 BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
0375 "0", 0);
0376 TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, int, BTF_F_COMPACT, -4567);
0377 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_NONAME,
0378 "-4567", -4567);
0379 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, 0, "(int)-4567", -4567);
0380
0381 TEST_BTF_DUMP_DATA_OVER(btf, d, NULL, str, int, sizeof(int)-1, "", 1);
0382
0383 #ifdef __SIZEOF_INT128__
0384
0385
0386
0387
0388 if (btf__find_by_name(btf, "unsigned __int128") > 0) {
0389 TEST_BTF_DUMP_DATA(btf, d, NULL, str, unsigned __int128, BTF_F_COMPACT,
0390 "(unsigned __int128)0xffffffffffffffff",
0391 0xffffffffffffffff);
0392 ASSERT_OK(btf_dump_data(btf, d, "unsigned __int128", NULL, 0, &i, 16, str,
0393 "(unsigned __int128)0xfffffffffffffffffffffffffffffffe"),
0394 "dump unsigned __int128");
0395 } else if (btf__find_by_name(btf, "__int128 unsigned") > 0) {
0396 TEST_BTF_DUMP_DATA(btf, d, NULL, str, __int128 unsigned, BTF_F_COMPACT,
0397 "(__int128 unsigned)0xffffffffffffffff",
0398 0xffffffffffffffff);
0399 ASSERT_OK(btf_dump_data(btf, d, "__int128 unsigned", NULL, 0, &i, 16, str,
0400 "(__int128 unsigned)0xfffffffffffffffffffffffffffffffe"),
0401 "dump unsigned __int128");
0402 } else {
0403 ASSERT_TRUE(false, "unsigned_int128_not_found");
0404 }
0405 #endif
0406 }
0407
0408 static void test_btf_dump_float_data(struct btf *btf, struct btf_dump *d,
0409 char *str)
0410 {
0411 float t1 = 1.234567;
0412 float t2 = -1.234567;
0413 float t3 = 0.0;
0414 double t4 = 5.678912;
0415 double t5 = -5.678912;
0416 double t6 = 0.0;
0417 long double t7 = 9.876543;
0418 long double t8 = -9.876543;
0419 long double t9 = 0.0;
0420
0421
0422
0423
0424
0425 ASSERT_GT(btf__add_float(btf, "test_float", 4), 0, "add float");
0426 ASSERT_OK(btf_dump_data(btf, d, "test_float", NULL, 0, &t1, 4, str,
0427 "(test_float)1.234567"), "dump float");
0428 ASSERT_OK(btf_dump_data(btf, d, "test_float", NULL, 0, &t2, 4, str,
0429 "(test_float)-1.234567"), "dump float");
0430 ASSERT_OK(btf_dump_data(btf, d, "test_float", NULL, 0, &t3, 4, str,
0431 "(test_float)0.000000"), "dump float");
0432
0433 ASSERT_GT(btf__add_float(btf, "test_double", 8), 0, "add_double");
0434 ASSERT_OK(btf_dump_data(btf, d, "test_double", NULL, 0, &t4, 8, str,
0435 "(test_double)5.678912"), "dump double");
0436 ASSERT_OK(btf_dump_data(btf, d, "test_double", NULL, 0, &t5, 8, str,
0437 "(test_double)-5.678912"), "dump double");
0438 ASSERT_OK(btf_dump_data(btf, d, "test_double", NULL, 0, &t6, 8, str,
0439 "(test_double)0.000000"), "dump double");
0440
0441 ASSERT_GT(btf__add_float(btf, "test_long_double", 16), 0, "add long double");
0442 ASSERT_OK(btf_dump_data(btf, d, "test_long_double", NULL, 0, &t7, 16,
0443 str, "(test_long_double)9.876543"),
0444 "dump long_double");
0445 ASSERT_OK(btf_dump_data(btf, d, "test_long_double", NULL, 0, &t8, 16,
0446 str, "(test_long_double)-9.876543"),
0447 "dump long_double");
0448 ASSERT_OK(btf_dump_data(btf, d, "test_long_double", NULL, 0, &t9, 16,
0449 str, "(test_long_double)0.000000"),
0450 "dump long_double");
0451 }
0452
0453 static void test_btf_dump_char_data(struct btf *btf, struct btf_dump *d,
0454 char *str)
0455 {
0456
0457 TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, char, BTF_F_COMPACT, 100);
0458 TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_NONAME,
0459 "100", 100);
0460 TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, 0, "(char)100", 100);
0461
0462 TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT,
0463 "(char)0", 0);
0464 TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_NONAME,
0465 "0", 0);
0466 TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_ZERO,
0467 "(char)0", 0);
0468 TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
0469 "0", 0);
0470 TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, 0, "(char)0", 0);
0471
0472 TEST_BTF_DUMP_DATA_OVER(btf, d, NULL, str, char, sizeof(char)-1, "", 100);
0473 }
0474
0475 static void test_btf_dump_typedef_data(struct btf *btf, struct btf_dump *d,
0476 char *str)
0477 {
0478
0479 TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, uint64_t, BTF_F_COMPACT, 100);
0480 TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT | BTF_F_NONAME,
0481 "1", 1);
0482 TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, 0, "(u64)1", 1);
0483
0484 TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT, "(u64)0", 0);
0485 TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT | BTF_F_NONAME,
0486 "0", 0);
0487 TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT | BTF_F_ZERO,
0488 "(u64)0", 0);
0489 TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64,
0490 BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
0491 "0", 0);
0492 TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, 0, "(u64)0", 0);
0493
0494
0495 TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, atomic_t, BTF_F_COMPACT,
0496 {.counter = (int)1,});
0497 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT | BTF_F_NONAME,
0498 "{1,}", { .counter = 1 });
0499 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, 0,
0500 "(atomic_t){\n"
0501 " .counter = (int)1,\n"
0502 "}",
0503 {.counter = 1,});
0504
0505 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT, "(atomic_t){}",
0506 {.counter = 0,});
0507 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT | BTF_F_NONAME,
0508 "{}", {.counter = 0,});
0509 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, 0,
0510 "(atomic_t){\n"
0511 "}",
0512 {.counter = 0,});
0513 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT | BTF_F_ZERO,
0514 "(atomic_t){.counter = (int)0,}",
0515 {.counter = 0,});
0516 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t,
0517 BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
0518 "{0,}", {.counter = 0,});
0519 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_ZERO,
0520 "(atomic_t){\n"
0521 " .counter = (int)0,\n"
0522 "}",
0523 { .counter = 0,});
0524
0525
0526 TEST_BTF_DUMP_DATA_OVER(btf, d, NULL, str, atomic_t, sizeof(atomic_t)-1,
0527 "(atomic_t){\n", { .counter = 1});
0528 }
0529
0530 static void test_btf_dump_enum_data(struct btf *btf, struct btf_dump *d,
0531 char *str)
0532 {
0533
0534 TEST_BTF_DUMP_DATA_C(btf, d, "enum", str, enum bpf_cmd, BTF_F_COMPACT,
0535 BPF_MAP_CREATE);
0536 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, BTF_F_COMPACT,
0537 "(enum bpf_cmd)BPF_MAP_CREATE", 0);
0538 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd,
0539 BTF_F_COMPACT | BTF_F_NONAME,
0540 "BPF_MAP_CREATE",
0541 BPF_MAP_CREATE);
0542 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, 0,
0543 "(enum bpf_cmd)BPF_MAP_CREATE",
0544 BPF_MAP_CREATE);
0545 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd,
0546 BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
0547 "BPF_MAP_CREATE", 0);
0548 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd,
0549 BTF_F_COMPACT | BTF_F_ZERO,
0550 "(enum bpf_cmd)BPF_MAP_CREATE",
0551 BPF_MAP_CREATE);
0552 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd,
0553 BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
0554 "BPF_MAP_CREATE", BPF_MAP_CREATE);
0555 TEST_BTF_DUMP_DATA_C(btf, d, "enum", str, enum bpf_cmd, BTF_F_COMPACT, 2000);
0556 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd,
0557 BTF_F_COMPACT | BTF_F_NONAME,
0558 "2000", 2000);
0559 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, 0,
0560 "(enum bpf_cmd)2000", 2000);
0561
0562 TEST_BTF_DUMP_DATA_OVER(btf, d, "enum", str, enum bpf_cmd,
0563 sizeof(enum bpf_cmd) - 1, "", BPF_MAP_CREATE);
0564 }
0565
0566 static void test_btf_dump_struct_data(struct btf *btf, struct btf_dump *d,
0567 char *str)
0568 {
0569 DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts);
0570 char zero_data[512] = { };
0571 char type_data[512];
0572 void *fops = type_data;
0573 void *skb = type_data;
0574 size_t type_sz;
0575 __s32 type_id;
0576 char *cmpstr;
0577 int ret;
0578
0579 memset(type_data, 255, sizeof(type_data));
0580
0581
0582 TEST_BTF_DUMP_DATA_C(btf, d, "struct", str, struct btf_enum, BTF_F_COMPACT,
0583 {.name_off = (__u32)3,.val = (__s32)-1,});
0584 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
0585 BTF_F_COMPACT | BTF_F_NONAME,
0586 "{3,-1,}",
0587 { .name_off = 3, .val = -1,});
0588 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, 0,
0589 "(struct btf_enum){\n"
0590 " .name_off = (__u32)3,\n"
0591 " .val = (__s32)-1,\n"
0592 "}",
0593 { .name_off = 3, .val = -1,});
0594 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
0595 BTF_F_COMPACT | BTF_F_NONAME,
0596 "{-1,}",
0597 { .name_off = 0, .val = -1,});
0598 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
0599 BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
0600 "{0,-1,}",
0601 { .name_off = 0, .val = -1,});
0602
0603 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, BTF_F_COMPACT,
0604 "(struct btf_enum){}",
0605 { .name_off = 0, .val = 0,});
0606 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
0607 BTF_F_COMPACT | BTF_F_NONAME,
0608 "{}",
0609 { .name_off = 0, .val = 0,});
0610 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, 0,
0611 "(struct btf_enum){\n"
0612 "}",
0613 { .name_off = 0, .val = 0,});
0614 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
0615 BTF_F_COMPACT | BTF_F_ZERO,
0616 "(struct btf_enum){.name_off = (__u32)0,.val = (__s32)0,}",
0617 { .name_off = 0, .val = 0,});
0618 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
0619 BTF_F_ZERO,
0620 "(struct btf_enum){\n"
0621 " .name_off = (__u32)0,\n"
0622 " .val = (__s32)0,\n"
0623 "}",
0624 { .name_off = 0, .val = 0,});
0625
0626
0627 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, BTF_F_COMPACT,
0628 "(struct list_head){.next = (struct list_head *)0x1,}",
0629 { .next = (struct list_head *)1 });
0630 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, 0,
0631 "(struct list_head){\n"
0632 " .next = (struct list_head *)0x1,\n"
0633 "}",
0634 { .next = (struct list_head *)1 });
0635
0636 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, BTF_F_COMPACT,
0637 "(struct list_head){}",
0638 { .next = (struct list_head *)0 });
0639 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, 0,
0640 "(struct list_head){\n"
0641 "}",
0642 { .next = (struct list_head *)0 });
0643
0644
0645 type_id = btf__find_by_name(btf, "file_operations");
0646 if (ASSERT_GT(type_id, 0, "find type id")) {
0647 type_sz = btf__resolve_size(btf, type_id);
0648 str[0] = '\0';
0649
0650 ret = btf_dump__dump_type_data(d, type_id, fops, type_sz, &opts);
0651 ASSERT_EQ(ret, type_sz,
0652 "unexpected return value dumping file_operations");
0653 cmpstr =
0654 "(struct file_operations){\n"
0655 " .owner = (struct module *)0xffffffffffffffff,\n"
0656 " .llseek = (loff_t (*)(struct file *, loff_t, int))0xffffffffffffffff,";
0657
0658 ASSERT_STRNEQ(str, cmpstr, strlen(cmpstr), "file_operations");
0659 }
0660
0661
0662 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, BTF_F_COMPACT,
0663 "(struct bpf_prog_info){.name = (char[16])['f','o','o',],}",
0664 { .name = "foo",});
0665 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info,
0666 BTF_F_COMPACT | BTF_F_NONAME,
0667 "{['f','o','o',],}",
0668 {.name = "foo",});
0669 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, 0,
0670 "(struct bpf_prog_info){\n"
0671 " .name = (char[16])[\n"
0672 " 'f',\n"
0673 " 'o',\n"
0674 " 'o',\n"
0675 " ],\n"
0676 "}",
0677 {.name = "foo",});
0678
0679 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, BTF_F_COMPACT,
0680 "(struct bpf_prog_info){}",
0681 {.name = {'\0', 'f', 'o', 'o'}});
0682
0683 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, BTF_F_COMPACT,
0684 "(struct bpf_prog_info){.name = (char[16])[1,2,3,],}",
0685 { .name = {1, 2, 3, 0}});
0686
0687
0688 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, BTF_F_COMPACT,
0689 "(struct __sk_buff){.cb = (__u32[5])[1,2,3,4,5,],}",
0690 { .cb = {1, 2, 3, 4, 5,},});
0691 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff,
0692 BTF_F_COMPACT | BTF_F_NONAME,
0693 "{[1,2,3,4,5,],}",
0694 { .cb = { 1, 2, 3, 4, 5},});
0695 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, 0,
0696 "(struct __sk_buff){\n"
0697 " .cb = (__u32[5])[\n"
0698 " 1,\n"
0699 " 2,\n"
0700 " 3,\n"
0701 " 4,\n"
0702 " 5,\n"
0703 " ],\n"
0704 "}",
0705 { .cb = { 1, 2, 3, 4, 5},});
0706
0707 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, BTF_F_COMPACT,
0708 "(struct __sk_buff){.cb = (__u32[5])[0,0,1,0,0,],}",
0709 { .cb = { 0, 0, 1, 0, 0},});
0710 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, 0,
0711 "(struct __sk_buff){\n"
0712 " .cb = (__u32[5])[\n"
0713 " 0,\n"
0714 " 0,\n"
0715 " 1,\n"
0716 " 0,\n"
0717 " 0,\n"
0718 " ],\n"
0719 "}",
0720 { .cb = { 0, 0, 1, 0, 0},});
0721
0722
0723 TEST_BTF_DUMP_DATA_C(btf, d, "struct", str, struct bpf_insn, BTF_F_COMPACT,
0724 {.code = (__u8)1,.dst_reg = (__u8)0x2,.src_reg = (__u8)0x3,.off = (__s16)4,.imm = (__s32)5,});
0725 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_insn,
0726 BTF_F_COMPACT | BTF_F_NONAME,
0727 "{1,0x2,0x3,4,5,}",
0728 { .code = 1, .dst_reg = 0x2, .src_reg = 0x3, .off = 4,
0729 .imm = 5,});
0730 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_insn, 0,
0731 "(struct bpf_insn){\n"
0732 " .code = (__u8)1,\n"
0733 " .dst_reg = (__u8)0x2,\n"
0734 " .src_reg = (__u8)0x3,\n"
0735 " .off = (__s16)4,\n"
0736 " .imm = (__s32)5,\n"
0737 "}",
0738 {.code = 1, .dst_reg = 2, .src_reg = 3, .off = 4, .imm = 5});
0739
0740
0741 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_insn, BTF_F_COMPACT,
0742 "(struct bpf_insn){.dst_reg = (__u8)0x1,}",
0743 { .code = 0, .dst_reg = 1});
0744
0745
0746 type_id = btf__find_by_name(btf, "fs_context");
0747 if (ASSERT_GT(type_id, 0, "find fs_context")) {
0748 type_sz = btf__resolve_size(btf, type_id);
0749 str[0] = '\0';
0750
0751 opts.emit_zeroes = true;
0752 ret = btf_dump__dump_type_data(d, type_id, zero_data, type_sz, &opts);
0753 ASSERT_EQ(ret, type_sz,
0754 "unexpected return value dumping fs_context");
0755
0756 ASSERT_NEQ(strstr(str, "FS_CONTEXT_FOR_MOUNT"), NULL,
0757 "bitfield value not present");
0758 }
0759
0760
0761 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_sock_ops, BTF_F_COMPACT,
0762 "(struct bpf_sock_ops){.op = (__u32)1,(union){.args = (__u32[4])[1,2,3,4,],.reply = (__u32)1,.replylong = (__u32[4])[1,2,3,4,],},}",
0763 { .op = 1, .args = { 1, 2, 3, 4}});
0764
0765
0766 TEST_BTF_DUMP_DATA(btf, d, "union", str, union bpf_iter_link_info, BTF_F_COMPACT,
0767 "(union bpf_iter_link_info){.map = (struct){.map_fd = (__u32)1,},}",
0768 { .map = { .map_fd = 1 }});
0769
0770
0771
0772
0773
0774 type_id = btf__find_by_name(btf, "sk_buff");
0775 if (ASSERT_GT(type_id, 0, "find struct sk_buff")) {
0776 type_sz = btf__resolve_size(btf, type_id);
0777 str[0] = '\0';
0778
0779 ret = btf_dump__dump_type_data(d, type_id, skb, type_sz, &opts);
0780 ASSERT_EQ(ret, type_sz,
0781 "unexpected return value dumping sk_buff");
0782 }
0783
0784
0785
0786
0787
0788
0789
0790
0791 TEST_BTF_DUMP_DATA_OVER(btf, d, "struct", str, struct bpf_sock_ops,
0792 sizeof(struct bpf_sock_ops) - 1,
0793 "(struct bpf_sock_ops){\n\t.op = (__u32)1,\n",
0794 { .op = 1, .skb_tcp_flags = 2});
0795 TEST_BTF_DUMP_DATA_OVER(btf, d, "struct", str, struct bpf_sock_ops,
0796 sizeof(struct bpf_sock_ops) - 1,
0797 "(struct bpf_sock_ops){\n\t.op = (__u32)1,\n",
0798 { .op = 1, .skb_tcp_flags = 0});
0799 }
0800
0801 static void test_btf_dump_var_data(struct btf *btf, struct btf_dump *d,
0802 char *str)
0803 {
0804 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
0805 TEST_BTF_DUMP_VAR(btf, d, NULL, str, "cpu_number", int, BTF_F_COMPACT,
0806 "int cpu_number = (int)100", 100);
0807 #endif
0808 TEST_BTF_DUMP_VAR(btf, d, NULL, str, "cpu_profile_flip", int, BTF_F_COMPACT,
0809 "static int cpu_profile_flip = (int)2", 2);
0810 }
0811
0812 static void test_btf_datasec(struct btf *btf, struct btf_dump *d, char *str,
0813 const char *name, const char *expected_val,
0814 void *data, size_t data_sz)
0815 {
0816 DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts);
0817 int ret = 0, cmp;
0818 size_t secsize;
0819 __s32 type_id;
0820
0821 opts.compact = true;
0822
0823 type_id = btf__find_by_name(btf, name);
0824 if (!ASSERT_GT(type_id, 0, "find type id"))
0825 return;
0826
0827 secsize = btf__resolve_size(btf, type_id);
0828 ASSERT_EQ(secsize, 0, "verify section size");
0829
0830 str[0] = '\0';
0831 ret = btf_dump__dump_type_data(d, type_id, data, data_sz, &opts);
0832 ASSERT_EQ(ret, 0, "unexpected return value");
0833
0834 cmp = strcmp(str, expected_val);
0835 ASSERT_EQ(cmp, 0, "ensure expected/actual match");
0836 }
0837
0838 static void test_btf_dump_datasec_data(char *str)
0839 {
0840 struct btf *btf;
0841 char license[4] = "GPL";
0842 struct btf_dump *d;
0843
0844 btf = btf__parse("xdping_kern.o", NULL);
0845 if (!ASSERT_OK_PTR(btf, "xdping_kern.o BTF not found"))
0846 return;
0847
0848 d = btf_dump__new(btf, btf_dump_snprintf, str, NULL);
0849 if (!ASSERT_OK_PTR(d, "could not create BTF dump"))
0850 goto out;
0851
0852 test_btf_datasec(btf, d, str, "license",
0853 "SEC(\"license\") char[4] _license = (char[4])['G','P','L',];",
0854 license, sizeof(license));
0855 out:
0856 btf_dump__free(d);
0857 btf__free(btf);
0858 }
0859
0860 void test_btf_dump() {
0861 char str[STRSIZE];
0862 struct btf_dump *d;
0863 struct btf *btf;
0864 int i;
0865
0866 for (i = 0; i < ARRAY_SIZE(btf_dump_test_cases); i++) {
0867 struct btf_dump_test_case *t = &btf_dump_test_cases[i];
0868
0869 if (!test__start_subtest(t->name))
0870 continue;
0871
0872 test_btf_dump_case(i, &btf_dump_test_cases[i]);
0873 }
0874 if (test__start_subtest("btf_dump: incremental"))
0875 test_btf_dump_incremental();
0876
0877 btf = libbpf_find_kernel_btf();
0878 if (!ASSERT_OK_PTR(btf, "no kernel BTF found"))
0879 return;
0880
0881 d = btf_dump__new(btf, btf_dump_snprintf, str, NULL);
0882 if (!ASSERT_OK_PTR(d, "could not create BTF dump"))
0883 return;
0884
0885
0886 if (test__start_subtest("btf_dump: int_data"))
0887 test_btf_dump_int_data(btf, d, str);
0888 if (test__start_subtest("btf_dump: float_data"))
0889 test_btf_dump_float_data(btf, d, str);
0890 if (test__start_subtest("btf_dump: char_data"))
0891 test_btf_dump_char_data(btf, d, str);
0892 if (test__start_subtest("btf_dump: typedef_data"))
0893 test_btf_dump_typedef_data(btf, d, str);
0894 if (test__start_subtest("btf_dump: enum_data"))
0895 test_btf_dump_enum_data(btf, d, str);
0896 if (test__start_subtest("btf_dump: struct_data"))
0897 test_btf_dump_struct_data(btf, d, str);
0898 if (test__start_subtest("btf_dump: var_data"))
0899 test_btf_dump_var_data(btf, d, str);
0900 btf_dump__free(d);
0901 btf__free(btf);
0902
0903 if (test__start_subtest("btf_dump: datasec_data"))
0904 test_btf_dump_datasec_data(str);
0905 }