1 // SPDX-License-Identifier: GPL-2.0 2 #include <test_progs.h> 3 #include <bpf/btf.h> 4 5 static int duration = 0; 6 7 void btf_dump_printf(void *ctx, const char *fmt, va_list args) 8 { 9 vfprintf(ctx, fmt, args); 10 } 11 12 static struct btf_dump_test_case { 13 const char *name; 14 const char *file; 15 bool known_ptr_sz; 16 struct btf_dump_opts opts; 17 } btf_dump_test_cases[] = { 18 {"btf_dump: syntax", "btf_dump_test_case_syntax", true, {}}, 19 {"btf_dump: ordering", "btf_dump_test_case_ordering", false, {}}, 20 {"btf_dump: padding", "btf_dump_test_case_padding", true, {}}, 21 {"btf_dump: packing", "btf_dump_test_case_packing", true, {}}, 22 {"btf_dump: bitfields", "btf_dump_test_case_bitfields", true, {}}, 23 {"btf_dump: multidim", "btf_dump_test_case_multidim", false, {}}, 24 {"btf_dump: namespacing", "btf_dump_test_case_namespacing", false, {}}, 25 }; 26 27 static int btf_dump_all_types(const struct btf *btf, 28 const struct btf_dump_opts *opts) 29 { 30 size_t type_cnt = btf__get_nr_types(btf); 31 struct btf_dump *d; 32 int err = 0, id; 33 34 d = btf_dump__new(btf, NULL, opts, btf_dump_printf); 35 err = libbpf_get_error(d); 36 if (err) 37 return err; 38 39 for (id = 1; id <= type_cnt; id++) { 40 err = btf_dump__dump_type(d, id); 41 if (err) 42 goto done; 43 } 44 45 done: 46 btf_dump__free(d); 47 return err; 48 } 49 50 static int test_btf_dump_case(int n, struct btf_dump_test_case *t) 51 { 52 char test_file[256], out_file[256], diff_cmd[1024]; 53 struct btf *btf = NULL; 54 int err = 0, fd = -1; 55 FILE *f = NULL; 56 57 snprintf(test_file, sizeof(test_file), "%s.o", t->file); 58 59 btf = btf__parse_elf(test_file, NULL); 60 if (!ASSERT_OK_PTR(btf, "btf_parse_elf")) { 61 err = -PTR_ERR(btf); 62 btf = NULL; 63 goto done; 64 } 65 66 /* tests with t->known_ptr_sz have no "long" or "unsigned long" type, 67 * so it's impossible to determine correct pointer size; but if they 68 * do, it should be 8 regardless of host architecture, becaues BPF 69 * target is always 64-bit 70 */ 71 if (!t->known_ptr_sz) { 72 btf__set_pointer_size(btf, 8); 73 } else { 74 CHECK(btf__pointer_size(btf) != 8, "ptr_sz", "exp %d, got %zu\n", 75 8, btf__pointer_size(btf)); 76 } 77 78 snprintf(out_file, sizeof(out_file), "/tmp/%s.output.XXXXXX", t->file); 79 fd = mkstemp(out_file); 80 if (!ASSERT_GE(fd, 0, "create_tmp")) { 81 err = fd; 82 goto done; 83 } 84 f = fdopen(fd, "w"); 85 if (CHECK(f == NULL, "open_tmp", "failed to open file: %s(%d)\n", 86 strerror(errno), errno)) { 87 close(fd); 88 goto done; 89 } 90 91 t->opts.ctx = f; 92 err = btf_dump_all_types(btf, &t->opts); 93 fclose(f); 94 close(fd); 95 if (CHECK(err, "btf_dump", "failure during C dumping: %d\n", err)) { 96 goto done; 97 } 98 99 snprintf(test_file, sizeof(test_file), "progs/%s.c", t->file); 100 if (access(test_file, R_OK) == -1) 101 /* 102 * When the test is run with O=, kselftest copies TEST_FILES 103 * without preserving the directory structure. 104 */ 105 snprintf(test_file, sizeof(test_file), "%s.c", t->file); 106 /* 107 * Diff test output and expected test output, contained between 108 * START-EXPECTED-OUTPUT and END-EXPECTED-OUTPUT lines in test case. 109 * For expected output lines, everything before '*' is stripped out. 110 * Also lines containing comment start and comment end markers are 111 * ignored. 112 */ 113 snprintf(diff_cmd, sizeof(diff_cmd), 114 "awk '/START-EXPECTED-OUTPUT/{out=1;next} " 115 "/END-EXPECTED-OUTPUT/{out=0} " 116 "/\\/\\*|\\*\\//{next} " /* ignore comment start/end lines */ 117 "out {sub(/^[ \\t]*\\*/, \"\"); print}' '%s' | diff -u - '%s'", 118 test_file, out_file); 119 err = system(diff_cmd); 120 if (CHECK(err, "diff", 121 "differing test output, output=%s, err=%d, diff cmd:\n%s\n", 122 out_file, err, diff_cmd)) 123 goto done; 124 125 remove(out_file); 126 127 done: 128 btf__free(btf); 129 return err; 130 } 131 132 static char *dump_buf; 133 static size_t dump_buf_sz; 134 static FILE *dump_buf_file; 135 136 void test_btf_dump_incremental(void) 137 { 138 struct btf *btf = NULL; 139 struct btf_dump *d = NULL; 140 struct btf_dump_opts opts; 141 int id, err, i; 142 143 dump_buf_file = open_memstream(&dump_buf, &dump_buf_sz); 144 if (!ASSERT_OK_PTR(dump_buf_file, "dump_memstream")) 145 return; 146 btf = btf__new_empty(); 147 if (!ASSERT_OK_PTR(btf, "new_empty")) 148 goto err_out; 149 opts.ctx = dump_buf_file; 150 d = btf_dump__new(btf, NULL, &opts, btf_dump_printf); 151 if (!ASSERT_OK(libbpf_get_error(d), "btf_dump__new")) 152 goto err_out; 153 154 /* First, generate BTF corresponding to the following C code: 155 * 156 * enum { VAL = 1 }; 157 * 158 * struct s { int x; }; 159 * 160 */ 161 id = btf__add_enum(btf, NULL, 4); 162 ASSERT_EQ(id, 1, "enum_id"); 163 err = btf__add_enum_value(btf, "VAL", 1); 164 ASSERT_OK(err, "enum_val_ok"); 165 166 id = btf__add_int(btf, "int", 4, BTF_INT_SIGNED); 167 ASSERT_EQ(id, 2, "int_id"); 168 169 id = btf__add_struct(btf, "s", 4); 170 ASSERT_EQ(id, 3, "struct_id"); 171 err = btf__add_field(btf, "x", 2, 0, 0); 172 ASSERT_OK(err, "field_ok"); 173 174 for (i = 1; i <= btf__get_nr_types(btf); i++) { 175 err = btf_dump__dump_type(d, i); 176 ASSERT_OK(err, "dump_type_ok"); 177 } 178 179 fflush(dump_buf_file); 180 dump_buf[dump_buf_sz] = 0; /* some libc implementations don't do this */ 181 ASSERT_STREQ(dump_buf, 182 "enum {\n" 183 " VAL = 1,\n" 184 "};\n" 185 "\n" 186 "struct s {\n" 187 " int x;\n" 188 "};\n\n", "c_dump1"); 189 190 /* Now, after dumping original BTF, append another struct that embeds 191 * anonymous enum. It also has a name conflict with the first struct: 192 * 193 * struct s___2 { 194 * enum { VAL___2 = 1 } x; 195 * struct s s; 196 * }; 197 * 198 * This will test that btf_dump'er maintains internal state properly. 199 * Note that VAL___2 enum value. It's because we've already emitted 200 * that enum as a global anonymous enum, so btf_dump will ensure that 201 * enum values don't conflict; 202 * 203 */ 204 fseek(dump_buf_file, 0, SEEK_SET); 205 206 id = btf__add_struct(btf, "s", 4); 207 ASSERT_EQ(id, 4, "struct_id"); 208 err = btf__add_field(btf, "x", 1, 0, 0); 209 ASSERT_OK(err, "field_ok"); 210 err = btf__add_field(btf, "s", 3, 32, 0); 211 ASSERT_OK(err, "field_ok"); 212 213 for (i = 1; i <= btf__get_nr_types(btf); i++) { 214 err = btf_dump__dump_type(d, i); 215 ASSERT_OK(err, "dump_type_ok"); 216 } 217 218 fflush(dump_buf_file); 219 dump_buf[dump_buf_sz] = 0; /* some libc implementations don't do this */ 220 ASSERT_STREQ(dump_buf, 221 "struct s___2 {\n" 222 " enum {\n" 223 " VAL___2 = 1,\n" 224 " } x;\n" 225 " struct s s;\n" 226 "};\n\n" , "c_dump1"); 227 228 err_out: 229 fclose(dump_buf_file); 230 free(dump_buf); 231 btf_dump__free(d); 232 btf__free(btf); 233 } 234 235 #define STRSIZE 4096 236 237 static void btf_dump_snprintf(void *ctx, const char *fmt, va_list args) 238 { 239 char *s = ctx, new[STRSIZE]; 240 241 vsnprintf(new, STRSIZE, fmt, args); 242 if (strlen(s) < STRSIZE) 243 strncat(s, new, STRSIZE - strlen(s) - 1); 244 } 245 246 static int btf_dump_data(struct btf *btf, struct btf_dump *d, 247 char *name, char *prefix, __u64 flags, void *ptr, 248 size_t ptr_sz, char *str, const char *expected_val) 249 { 250 DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts); 251 size_t type_sz; 252 __s32 type_id; 253 int ret = 0; 254 255 if (flags & BTF_F_COMPACT) 256 opts.compact = true; 257 if (flags & BTF_F_NONAME) 258 opts.skip_names = true; 259 if (flags & BTF_F_ZERO) 260 opts.emit_zeroes = true; 261 if (prefix) { 262 ASSERT_STRNEQ(name, prefix, strlen(prefix), 263 "verify prefix match"); 264 name += strlen(prefix) + 1; 265 } 266 type_id = btf__find_by_name(btf, name); 267 if (!ASSERT_GE(type_id, 0, "find type id")) 268 return -ENOENT; 269 type_sz = btf__resolve_size(btf, type_id); 270 str[0] = '\0'; 271 ret = btf_dump__dump_type_data(d, type_id, ptr, ptr_sz, &opts); 272 if (type_sz <= ptr_sz) { 273 if (!ASSERT_EQ(ret, type_sz, "failed/unexpected type_sz")) 274 return -EINVAL; 275 } else { 276 if (!ASSERT_EQ(ret, -E2BIG, "failed to return -E2BIG")) 277 return -EINVAL; 278 } 279 if (!ASSERT_STREQ(str, expected_val, "ensure expected/actual match")) 280 return -EFAULT; 281 return 0; 282 } 283 284 #define TEST_BTF_DUMP_DATA(_b, _d, _prefix, _str, _type, _flags, \ 285 _expected, ...) \ 286 do { \ 287 char __ptrtype[64] = #_type; \ 288 char *_ptrtype = (char *)__ptrtype; \ 289 _type _ptrdata = __VA_ARGS__; \ 290 void *_ptr = &_ptrdata; \ 291 \ 292 (void) btf_dump_data(_b, _d, _ptrtype, _prefix, _flags, \ 293 _ptr, sizeof(_type), _str, \ 294 _expected); \ 295 } while (0) 296 297 /* Use where expected data string matches its stringified declaration */ 298 #define TEST_BTF_DUMP_DATA_C(_b, _d, _prefix, _str, _type, _flags, \ 299 ...) \ 300 TEST_BTF_DUMP_DATA(_b, _d, _prefix, _str, _type, _flags, \ 301 "(" #_type ")" #__VA_ARGS__, __VA_ARGS__) 302 303 /* overflow test; pass typesize < expected type size, ensure E2BIG returned */ 304 #define TEST_BTF_DUMP_DATA_OVER(_b, _d, _prefix, _str, _type, _type_sz, \ 305 _expected, ...) \ 306 do { \ 307 char __ptrtype[64] = #_type; \ 308 char *_ptrtype = (char *)__ptrtype; \ 309 _type _ptrdata = __VA_ARGS__; \ 310 void *_ptr = &_ptrdata; \ 311 \ 312 (void) btf_dump_data(_b, _d, _ptrtype, _prefix, 0, \ 313 _ptr, _type_sz, _str, _expected); \ 314 } while (0) 315 316 #define TEST_BTF_DUMP_VAR(_b, _d, _prefix, _str, _var, _type, _flags, \ 317 _expected, ...) \ 318 do { \ 319 _type _ptrdata = __VA_ARGS__; \ 320 void *_ptr = &_ptrdata; \ 321 \ 322 (void) btf_dump_data(_b, _d, _var, _prefix, _flags, \ 323 _ptr, sizeof(_type), _str, \ 324 _expected); \ 325 } while (0) 326 327 static void test_btf_dump_int_data(struct btf *btf, struct btf_dump *d, 328 char *str) 329 { 330 #ifdef __SIZEOF_INT128__ 331 __int128 i = 0xffffffffffffffff; 332 333 /* this dance is required because we cannot directly initialize 334 * a 128-bit value to anything larger than a 64-bit value. 335 */ 336 i = (i << 64) | (i - 1); 337 #endif 338 /* simple int */ 339 TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, int, BTF_F_COMPACT, 1234); 340 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_NONAME, 341 "1234", 1234); 342 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, 0, "(int)1234", 1234); 343 344 /* zero value should be printed at toplevel */ 345 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT, "(int)0", 0); 346 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_NONAME, 347 "0", 0); 348 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_ZERO, 349 "(int)0", 0); 350 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, 351 BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO, 352 "0", 0); 353 TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, int, BTF_F_COMPACT, -4567); 354 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_NONAME, 355 "-4567", -4567); 356 TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, 0, "(int)-4567", -4567); 357 358 TEST_BTF_DUMP_DATA_OVER(btf, d, NULL, str, int, sizeof(int)-1, "", 1); 359 360 #ifdef __SIZEOF_INT128__ 361 TEST_BTF_DUMP_DATA(btf, d, NULL, str, __int128, BTF_F_COMPACT, 362 "(__int128)0xffffffffffffffff", 363 0xffffffffffffffff); 364 ASSERT_OK(btf_dump_data(btf, d, "__int128", NULL, 0, &i, 16, str, 365 "(__int128)0xfffffffffffffffffffffffffffffffe"), 366 "dump __int128"); 367 #endif 368 } 369 370 static void test_btf_dump_float_data(struct btf *btf, struct btf_dump *d, 371 char *str) 372 { 373 float t1 = 1.234567; 374 float t2 = -1.234567; 375 float t3 = 0.0; 376 double t4 = 5.678912; 377 double t5 = -5.678912; 378 double t6 = 0.0; 379 long double t7 = 9.876543; 380 long double t8 = -9.876543; 381 long double t9 = 0.0; 382 383 /* since the kernel does not likely have any float types in its BTF, we 384 * will need to add some of various sizes. 385 */ 386 387 ASSERT_GT(btf__add_float(btf, "test_float", 4), 0, "add float"); 388 ASSERT_OK(btf_dump_data(btf, d, "test_float", NULL, 0, &t1, 4, str, 389 "(test_float)1.234567"), "dump float"); 390 ASSERT_OK(btf_dump_data(btf, d, "test_float", NULL, 0, &t2, 4, str, 391 "(test_float)-1.234567"), "dump float"); 392 ASSERT_OK(btf_dump_data(btf, d, "test_float", NULL, 0, &t3, 4, str, 393 "(test_float)0.000000"), "dump float"); 394 395 ASSERT_GT(btf__add_float(btf, "test_double", 8), 0, "add_double"); 396 ASSERT_OK(btf_dump_data(btf, d, "test_double", NULL, 0, &t4, 8, str, 397 "(test_double)5.678912"), "dump double"); 398 ASSERT_OK(btf_dump_data(btf, d, "test_double", NULL, 0, &t5, 8, str, 399 "(test_double)-5.678912"), "dump double"); 400 ASSERT_OK(btf_dump_data(btf, d, "test_double", NULL, 0, &t6, 8, str, 401 "(test_double)0.000000"), "dump double"); 402 403 ASSERT_GT(btf__add_float(btf, "test_long_double", 16), 0, "add long double"); 404 ASSERT_OK(btf_dump_data(btf, d, "test_long_double", NULL, 0, &t7, 16, 405 str, "(test_long_double)9.876543"), 406 "dump long_double"); 407 ASSERT_OK(btf_dump_data(btf, d, "test_long_double", NULL, 0, &t8, 16, 408 str, "(test_long_double)-9.876543"), 409 "dump long_double"); 410 ASSERT_OK(btf_dump_data(btf, d, "test_long_double", NULL, 0, &t9, 16, 411 str, "(test_long_double)0.000000"), 412 "dump long_double"); 413 } 414 415 static void test_btf_dump_char_data(struct btf *btf, struct btf_dump *d, 416 char *str) 417 { 418 /* simple char */ 419 TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, char, BTF_F_COMPACT, 100); 420 TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_NONAME, 421 "100", 100); 422 TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, 0, "(char)100", 100); 423 /* zero value should be printed at toplevel */ 424 TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT, 425 "(char)0", 0); 426 TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_NONAME, 427 "0", 0); 428 TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_ZERO, 429 "(char)0", 0); 430 TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO, 431 "0", 0); 432 TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, 0, "(char)0", 0); 433 434 TEST_BTF_DUMP_DATA_OVER(btf, d, NULL, str, char, sizeof(char)-1, "", 100); 435 } 436 437 static void test_btf_dump_typedef_data(struct btf *btf, struct btf_dump *d, 438 char *str) 439 { 440 /* simple typedef */ 441 TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, uint64_t, BTF_F_COMPACT, 100); 442 TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT | BTF_F_NONAME, 443 "1", 1); 444 TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, 0, "(u64)1", 1); 445 /* zero value should be printed at toplevel */ 446 TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT, "(u64)0", 0); 447 TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT | BTF_F_NONAME, 448 "0", 0); 449 TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT | BTF_F_ZERO, 450 "(u64)0", 0); 451 TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, 452 BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO, 453 "0", 0); 454 TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, 0, "(u64)0", 0); 455 456 /* typedef struct */ 457 TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, atomic_t, BTF_F_COMPACT, 458 {.counter = (int)1,}); 459 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT | BTF_F_NONAME, 460 "{1,}", { .counter = 1 }); 461 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, 0, 462 "(atomic_t){\n" 463 " .counter = (int)1,\n" 464 "}", 465 {.counter = 1,}); 466 /* typedef with 0 value should be printed at toplevel */ 467 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT, "(atomic_t){}", 468 {.counter = 0,}); 469 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT | BTF_F_NONAME, 470 "{}", {.counter = 0,}); 471 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, 0, 472 "(atomic_t){\n" 473 "}", 474 {.counter = 0,}); 475 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT | BTF_F_ZERO, 476 "(atomic_t){.counter = (int)0,}", 477 {.counter = 0,}); 478 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, 479 BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO, 480 "{0,}", {.counter = 0,}); 481 TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_ZERO, 482 "(atomic_t){\n" 483 " .counter = (int)0,\n" 484 "}", 485 { .counter = 0,}); 486 487 /* overflow should show type but not value since it overflows */ 488 TEST_BTF_DUMP_DATA_OVER(btf, d, NULL, str, atomic_t, sizeof(atomic_t)-1, 489 "(atomic_t){\n", { .counter = 1}); 490 } 491 492 static void test_btf_dump_enum_data(struct btf *btf, struct btf_dump *d, 493 char *str) 494 { 495 /* enum where enum value does (and does not) exist */ 496 TEST_BTF_DUMP_DATA_C(btf, d, "enum", str, enum bpf_cmd, BTF_F_COMPACT, 497 BPF_MAP_CREATE); 498 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, BTF_F_COMPACT, 499 "(enum bpf_cmd)BPF_MAP_CREATE", 0); 500 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, 501 BTF_F_COMPACT | BTF_F_NONAME, 502 "BPF_MAP_CREATE", 503 BPF_MAP_CREATE); 504 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, 0, 505 "(enum bpf_cmd)BPF_MAP_CREATE", 506 BPF_MAP_CREATE); 507 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, 508 BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO, 509 "BPF_MAP_CREATE", 0); 510 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, 511 BTF_F_COMPACT | BTF_F_ZERO, 512 "(enum bpf_cmd)BPF_MAP_CREATE", 513 BPF_MAP_CREATE); 514 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, 515 BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO, 516 "BPF_MAP_CREATE", BPF_MAP_CREATE); 517 TEST_BTF_DUMP_DATA_C(btf, d, "enum", str, enum bpf_cmd, BTF_F_COMPACT, 2000); 518 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, 519 BTF_F_COMPACT | BTF_F_NONAME, 520 "2000", 2000); 521 TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, 0, 522 "(enum bpf_cmd)2000", 2000); 523 524 TEST_BTF_DUMP_DATA_OVER(btf, d, "enum", str, enum bpf_cmd, 525 sizeof(enum bpf_cmd) - 1, "", BPF_MAP_CREATE); 526 } 527 528 static void test_btf_dump_struct_data(struct btf *btf, struct btf_dump *d, 529 char *str) 530 { 531 DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts); 532 char zero_data[512] = { }; 533 char type_data[512]; 534 void *fops = type_data; 535 void *skb = type_data; 536 size_t type_sz; 537 __s32 type_id; 538 char *cmpstr; 539 int ret; 540 541 memset(type_data, 255, sizeof(type_data)); 542 543 /* simple struct */ 544 TEST_BTF_DUMP_DATA_C(btf, d, "struct", str, struct btf_enum, BTF_F_COMPACT, 545 {.name_off = (__u32)3,.val = (__s32)-1,}); 546 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, 547 BTF_F_COMPACT | BTF_F_NONAME, 548 "{3,-1,}", 549 { .name_off = 3, .val = -1,}); 550 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, 0, 551 "(struct btf_enum){\n" 552 " .name_off = (__u32)3,\n" 553 " .val = (__s32)-1,\n" 554 "}", 555 { .name_off = 3, .val = -1,}); 556 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, 557 BTF_F_COMPACT | BTF_F_NONAME, 558 "{-1,}", 559 { .name_off = 0, .val = -1,}); 560 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, 561 BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO, 562 "{0,-1,}", 563 { .name_off = 0, .val = -1,}); 564 /* empty struct should be printed */ 565 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, BTF_F_COMPACT, 566 "(struct btf_enum){}", 567 { .name_off = 0, .val = 0,}); 568 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, 569 BTF_F_COMPACT | BTF_F_NONAME, 570 "{}", 571 { .name_off = 0, .val = 0,}); 572 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, 0, 573 "(struct btf_enum){\n" 574 "}", 575 { .name_off = 0, .val = 0,}); 576 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, 577 BTF_F_COMPACT | BTF_F_ZERO, 578 "(struct btf_enum){.name_off = (__u32)0,.val = (__s32)0,}", 579 { .name_off = 0, .val = 0,}); 580 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, 581 BTF_F_ZERO, 582 "(struct btf_enum){\n" 583 " .name_off = (__u32)0,\n" 584 " .val = (__s32)0,\n" 585 "}", 586 { .name_off = 0, .val = 0,}); 587 588 /* struct with pointers */ 589 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, BTF_F_COMPACT, 590 "(struct list_head){.next = (struct list_head *)0x1,}", 591 { .next = (struct list_head *)1 }); 592 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, 0, 593 "(struct list_head){\n" 594 " .next = (struct list_head *)0x1,\n" 595 "}", 596 { .next = (struct list_head *)1 }); 597 /* NULL pointer should not be displayed */ 598 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, BTF_F_COMPACT, 599 "(struct list_head){}", 600 { .next = (struct list_head *)0 }); 601 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, 0, 602 "(struct list_head){\n" 603 "}", 604 { .next = (struct list_head *)0 }); 605 606 /* struct with function pointers */ 607 type_id = btf__find_by_name(btf, "file_operations"); 608 if (ASSERT_GT(type_id, 0, "find type id")) { 609 type_sz = btf__resolve_size(btf, type_id); 610 str[0] = '\0'; 611 612 ret = btf_dump__dump_type_data(d, type_id, fops, type_sz, &opts); 613 ASSERT_EQ(ret, type_sz, 614 "unexpected return value dumping file_operations"); 615 cmpstr = 616 "(struct file_operations){\n" 617 " .owner = (struct module *)0xffffffffffffffff,\n" 618 " .llseek = (loff_t (*)(struct file *, loff_t, int))0xffffffffffffffff,"; 619 620 ASSERT_STRNEQ(str, cmpstr, strlen(cmpstr), "file_operations"); 621 } 622 623 /* struct with char array */ 624 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, BTF_F_COMPACT, 625 "(struct bpf_prog_info){.name = (char[16])['f','o','o',],}", 626 { .name = "foo",}); 627 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, 628 BTF_F_COMPACT | BTF_F_NONAME, 629 "{['f','o','o',],}", 630 {.name = "foo",}); 631 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, 0, 632 "(struct bpf_prog_info){\n" 633 " .name = (char[16])[\n" 634 " 'f',\n" 635 " 'o',\n" 636 " 'o',\n" 637 " ],\n" 638 "}", 639 {.name = "foo",}); 640 /* leading null char means do not display string */ 641 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, BTF_F_COMPACT, 642 "(struct bpf_prog_info){}", 643 {.name = {'\0', 'f', 'o', 'o'}}); 644 /* handle non-printable characters */ 645 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, BTF_F_COMPACT, 646 "(struct bpf_prog_info){.name = (char[16])[1,2,3,],}", 647 { .name = {1, 2, 3, 0}}); 648 649 /* struct with non-char array */ 650 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, BTF_F_COMPACT, 651 "(struct __sk_buff){.cb = (__u32[5])[1,2,3,4,5,],}", 652 { .cb = {1, 2, 3, 4, 5,},}); 653 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, 654 BTF_F_COMPACT | BTF_F_NONAME, 655 "{[1,2,3,4,5,],}", 656 { .cb = { 1, 2, 3, 4, 5},}); 657 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, 0, 658 "(struct __sk_buff){\n" 659 " .cb = (__u32[5])[\n" 660 " 1,\n" 661 " 2,\n" 662 " 3,\n" 663 " 4,\n" 664 " 5,\n" 665 " ],\n" 666 "}", 667 { .cb = { 1, 2, 3, 4, 5},}); 668 /* For non-char, arrays, show non-zero values only */ 669 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, BTF_F_COMPACT, 670 "(struct __sk_buff){.cb = (__u32[5])[0,0,1,0,0,],}", 671 { .cb = { 0, 0, 1, 0, 0},}); 672 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, 0, 673 "(struct __sk_buff){\n" 674 " .cb = (__u32[5])[\n" 675 " 0,\n" 676 " 0,\n" 677 " 1,\n" 678 " 0,\n" 679 " 0,\n" 680 " ],\n" 681 "}", 682 { .cb = { 0, 0, 1, 0, 0},}); 683 684 /* struct with bitfields */ 685 TEST_BTF_DUMP_DATA_C(btf, d, "struct", str, struct bpf_insn, BTF_F_COMPACT, 686 {.code = (__u8)1,.dst_reg = (__u8)0x2,.src_reg = (__u8)0x3,.off = (__s16)4,.imm = (__s32)5,}); 687 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_insn, 688 BTF_F_COMPACT | BTF_F_NONAME, 689 "{1,0x2,0x3,4,5,}", 690 { .code = 1, .dst_reg = 0x2, .src_reg = 0x3, .off = 4, 691 .imm = 5,}); 692 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_insn, 0, 693 "(struct bpf_insn){\n" 694 " .code = (__u8)1,\n" 695 " .dst_reg = (__u8)0x2,\n" 696 " .src_reg = (__u8)0x3,\n" 697 " .off = (__s16)4,\n" 698 " .imm = (__s32)5,\n" 699 "}", 700 {.code = 1, .dst_reg = 2, .src_reg = 3, .off = 4, .imm = 5}); 701 702 /* zeroed bitfields should not be displayed */ 703 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_insn, BTF_F_COMPACT, 704 "(struct bpf_insn){.dst_reg = (__u8)0x1,}", 705 { .code = 0, .dst_reg = 1}); 706 707 /* struct with enum bitfield */ 708 type_id = btf__find_by_name(btf, "fs_context"); 709 if (ASSERT_GT(type_id, 0, "find fs_context")) { 710 type_sz = btf__resolve_size(btf, type_id); 711 str[0] = '\0'; 712 713 opts.emit_zeroes = true; 714 ret = btf_dump__dump_type_data(d, type_id, zero_data, type_sz, &opts); 715 ASSERT_EQ(ret, type_sz, 716 "unexpected return value dumping fs_context"); 717 718 ASSERT_NEQ(strstr(str, "FS_CONTEXT_FOR_MOUNT"), NULL, 719 "bitfield value not present"); 720 } 721 722 /* struct with nested anon union */ 723 TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_sock_ops, BTF_F_COMPACT, 724 "(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,],},}", 725 { .op = 1, .args = { 1, 2, 3, 4}}); 726 727 /* union with nested struct */ 728 TEST_BTF_DUMP_DATA(btf, d, "union", str, union bpf_iter_link_info, BTF_F_COMPACT, 729 "(union bpf_iter_link_info){.map = (struct){.map_fd = (__u32)1,},}", 730 { .map = { .map_fd = 1 }}); 731 732 /* struct skb with nested structs/unions; because type output is so 733 * complex, we don't do a string comparison, just verify we return 734 * the type size as the amount of data displayed. 735 */ 736 type_id = btf__find_by_name(btf, "sk_buff"); 737 if (ASSERT_GT(type_id, 0, "find struct sk_buff")) { 738 type_sz = btf__resolve_size(btf, type_id); 739 str[0] = '\0'; 740 741 ret = btf_dump__dump_type_data(d, type_id, skb, type_sz, &opts); 742 ASSERT_EQ(ret, type_sz, 743 "unexpected return value dumping sk_buff"); 744 } 745 746 /* overflow bpf_sock_ops struct with final element nonzero/zero. 747 * Regardless of the value of the final field, we don't have all the 748 * data we need to display it, so we should trigger an overflow. 749 * In other words oveflow checking should trump "is field zero?" 750 * checks because if we've overflowed, it shouldn't matter what the 751 * field is - we can't trust its value so shouldn't display it. 752 */ 753 TEST_BTF_DUMP_DATA_OVER(btf, d, "struct", str, struct bpf_sock_ops, 754 sizeof(struct bpf_sock_ops) - 1, 755 "(struct bpf_sock_ops){\n\t.op = (__u32)1,\n", 756 { .op = 1, .skb_tcp_flags = 2}); 757 TEST_BTF_DUMP_DATA_OVER(btf, d, "struct", str, struct bpf_sock_ops, 758 sizeof(struct bpf_sock_ops) - 1, 759 "(struct bpf_sock_ops){\n\t.op = (__u32)1,\n", 760 { .op = 1, .skb_tcp_flags = 0}); 761 } 762 763 static void test_btf_dump_var_data(struct btf *btf, struct btf_dump *d, 764 char *str) 765 { 766 TEST_BTF_DUMP_VAR(btf, d, NULL, str, "cpu_number", int, BTF_F_COMPACT, 767 "int cpu_number = (int)100", 100); 768 TEST_BTF_DUMP_VAR(btf, d, NULL, str, "cpu_profile_flip", int, BTF_F_COMPACT, 769 "static int cpu_profile_flip = (int)2", 2); 770 } 771 772 static void test_btf_datasec(struct btf *btf, struct btf_dump *d, char *str, 773 const char *name, const char *expected_val, 774 void *data, size_t data_sz) 775 { 776 DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts); 777 int ret = 0, cmp; 778 size_t secsize; 779 __s32 type_id; 780 781 opts.compact = true; 782 783 type_id = btf__find_by_name(btf, name); 784 if (!ASSERT_GT(type_id, 0, "find type id")) 785 return; 786 787 secsize = btf__resolve_size(btf, type_id); 788 ASSERT_EQ(secsize, 0, "verify section size"); 789 790 str[0] = '\0'; 791 ret = btf_dump__dump_type_data(d, type_id, data, data_sz, &opts); 792 ASSERT_EQ(ret, 0, "unexpected return value"); 793 794 cmp = strcmp(str, expected_val); 795 ASSERT_EQ(cmp, 0, "ensure expected/actual match"); 796 } 797 798 static void test_btf_dump_datasec_data(char *str) 799 { 800 struct btf *btf = btf__parse("xdping_kern.o", NULL); 801 struct btf_dump_opts opts = { .ctx = str }; 802 char license[4] = "GPL"; 803 struct btf_dump *d; 804 805 if (!ASSERT_OK_PTR(btf, "xdping_kern.o BTF not found")) 806 return; 807 808 d = btf_dump__new(btf, NULL, &opts, btf_dump_snprintf); 809 if (!ASSERT_OK_PTR(d, "could not create BTF dump")) 810 return; 811 812 test_btf_datasec(btf, d, str, "license", 813 "SEC(\"license\") char[4] _license = (char[4])['G','P','L',];", 814 license, sizeof(license)); 815 } 816 817 void test_btf_dump() { 818 char str[STRSIZE]; 819 struct btf_dump_opts opts = { .ctx = str }; 820 struct btf_dump *d; 821 struct btf *btf; 822 int i; 823 824 for (i = 0; i < ARRAY_SIZE(btf_dump_test_cases); i++) { 825 struct btf_dump_test_case *t = &btf_dump_test_cases[i]; 826 827 if (!test__start_subtest(t->name)) 828 continue; 829 830 test_btf_dump_case(i, &btf_dump_test_cases[i]); 831 } 832 if (test__start_subtest("btf_dump: incremental")) 833 test_btf_dump_incremental(); 834 835 btf = libbpf_find_kernel_btf(); 836 if (!ASSERT_OK_PTR(btf, "no kernel BTF found")) 837 return; 838 839 d = btf_dump__new(btf, NULL, &opts, btf_dump_snprintf); 840 if (!ASSERT_OK_PTR(d, "could not create BTF dump")) 841 return; 842 843 /* Verify type display for various types. */ 844 if (test__start_subtest("btf_dump: int_data")) 845 test_btf_dump_int_data(btf, d, str); 846 if (test__start_subtest("btf_dump: float_data")) 847 test_btf_dump_float_data(btf, d, str); 848 if (test__start_subtest("btf_dump: char_data")) 849 test_btf_dump_char_data(btf, d, str); 850 if (test__start_subtest("btf_dump: typedef_data")) 851 test_btf_dump_typedef_data(btf, d, str); 852 if (test__start_subtest("btf_dump: enum_data")) 853 test_btf_dump_enum_data(btf, d, str); 854 if (test__start_subtest("btf_dump: struct_data")) 855 test_btf_dump_struct_data(btf, d, str); 856 if (test__start_subtest("btf_dump: var_data")) 857 test_btf_dump_var_data(btf, d, str); 858 btf_dump__free(d); 859 btf__free(btf); 860 861 if (test__start_subtest("btf_dump: datasec_data")) 862 test_btf_dump_datasec_data(str); 863 } 864