Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
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     /* tests with t->known_ptr_sz have no "long" or "unsigned long" type,
0065      * so it's impossible to determine correct pointer size; but if they
0066      * do, it should be 8 regardless of host architecture, becaues BPF
0067      * target is always 64-bit
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          * When the test is run with O=, kselftest copies TEST_FILES
0100          * without preserving the directory structure.
0101          */
0102         snprintf(test_file, sizeof(test_file), "%s.c", t->file);
0103     /*
0104      * Diff test output and expected test output, contained between
0105      * START-EXPECTED-OUTPUT and END-EXPECTED-OUTPUT lines in test case.
0106      * For expected output lines, everything before '*' is stripped out.
0107      * Also lines containing comment start and comment end markers are
0108      * ignored. 
0109      */
0110     snprintf(diff_cmd, sizeof(diff_cmd),
0111          "awk '/START-EXPECTED-OUTPUT/{out=1;next} "
0112          "/END-EXPECTED-OUTPUT/{out=0} "
0113          "/\\/\\*|\\*\\//{next} " /* ignore comment start/end lines */
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     /* First, generate BTF corresponding to the following C code:
0150      *
0151      * enum x;
0152      *
0153      * enum x { X = 1 };
0154      *
0155      * enum { Y = 1 };
0156      *
0157      * struct s;
0158      *
0159      * struct s { int x; };
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; /* some libc implementations don't do this */
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     /* Now, after dumping original BTF, append another struct that embeds
0211      * anonymous enum. It also has a name conflict with the first struct:
0212      *
0213      * struct s___2 {
0214      *     enum { VAL___2 = 1 } x;
0215      *     struct s s;
0216      * };
0217      *
0218      * This will test that btf_dump'er maintains internal state properly.
0219      * Note that VAL___2 enum value. It's because we've already emitted
0220      * that enum as a global anonymous enum, so btf_dump will ensure that
0221      * enum values don't conflict;
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; /* some libc implementations don't do this */
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 /* Use where expected data string matches its stringified declaration */
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 /* overflow test; pass typesize < expected type size, ensure E2BIG returned */
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     /* this dance is required because we cannot directly initialize
0357      * a 128-bit value to anything larger than a 64-bit value.
0358      */
0359     i = (i << 64) | (i - 1);
0360 #endif
0361     /* simple int */
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     /* zero value should be printed at toplevel */
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     /* gcc encode unsigned __int128 type with name "__int128 unsigned" in dwarf,
0385      * and clang encode it with name "unsigned __int128" in dwarf.
0386      * Do an availability test for either variant before doing actual test.
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     /* since the kernel does not likely have any float types in its BTF, we
0422      * will need to add some of various sizes.
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     /* simple char */
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     /* zero value should be printed at toplevel */
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     /* simple typedef */
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     /* zero value should be printed at toplevel */
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     /* typedef struct */
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     /* typedef with 0 value should be printed at toplevel */
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     /* overflow should show type but not value since it overflows */
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     /* enum where enum value does (and does not) exist */
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     /* simple struct */
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     /* empty struct should be printed */
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     /* struct with pointers */
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     /* NULL pointer should not be displayed */
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     /* struct with function pointers */
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     /* struct with char array */
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     /* leading null char means do not display string */
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     /* handle non-printable characters */
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     /* struct with non-char array */
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     /* For non-char, arrays, show non-zero values only */
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     /* struct with bitfields */
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     /* zeroed bitfields should not be displayed */
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     /* struct with enum bitfield */
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     /* struct with nested anon union */
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     /* union with nested struct */
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     /* struct skb with nested structs/unions; because type output is so
0771      * complex, we don't do a string comparison, just verify we return
0772      * the type size as the amount of data displayed.
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     /* overflow bpf_sock_ops struct with final element nonzero/zero.
0785      * Regardless of the value of the final field, we don't have all the
0786      * data we need to display it, so we should trigger an overflow.
0787      * In other words overflow checking should trump "is field zero?"
0788      * checks because if we've overflowed, it shouldn't matter what the
0789      * field is - we can't trust its value so shouldn't display it.
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     /* Verify type display for various types. */
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 }