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