Move almost 200 tests from test_btf into test_progs framework to be exercised
regularly. Pretty-printing tests were left alone and renamed into
test_btf_pprint because they are very slow and were not even executed by
default with test_btf.

All the test_btf tests that were moved are modeled as proper sub-tests in
test_progs framework for ease of debugging and reporting.

No functional or behavioral changes were intended, I tried to preserve
original behavior as close to the original as possible. `test_progs -v` will
activate "always_log" flag to emit BTF validation log.

Signed-off-by: Andrii Nakryiko <andr...@fb.com>
---

v1->v2:
 - pretty-print BTF tests were renamed test_btf -> test_btf_pprint, which
   allowed GIT to detect that majority of  test_btf code was moved into
   prog_tests/btf.c; so diff is much-much smaller;

 tools/testing/selftests/bpf/.gitignore        |    2 +-
 .../bpf/{test_btf.c => prog_tests/btf.c}      | 1069 +----------------
 tools/testing/selftests/bpf/test_btf_pprint.c |  969 +++++++++++++++
 3 files changed, 1033 insertions(+), 1007 deletions(-)
 rename tools/testing/selftests/bpf/{test_btf.c => prog_tests/btf.c} (85%)
 create mode 100644 tools/testing/selftests/bpf/test_btf_pprint.c

diff --git a/tools/testing/selftests/bpf/.gitignore 
b/tools/testing/selftests/bpf/.gitignore
index 9a0946ddb705..160c413ee960 100644
--- a/tools/testing/selftests/bpf/.gitignore
+++ b/tools/testing/selftests/bpf/.gitignore
@@ -15,7 +15,7 @@ test_sock
 test_sock_addr
 test_sock_fields
 urandom_read
-test_btf
+test_btf_pprint
 test_sockmap
 test_lirc_mode2_user
 get_cgroup_id_user
diff --git a/tools/testing/selftests/bpf/test_btf.c 
b/tools/testing/selftests/bpf/prog_tests/btf.c
similarity index 85%
rename from tools/testing/selftests/bpf/test_btf.c
rename to tools/testing/selftests/bpf/prog_tests/btf.c
index c75fc6447186..94719b692a1b 100644
--- a/tools/testing/selftests/bpf/test_btf.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf.c
@@ -24,40 +24,17 @@
 
 #include "bpf_rlimit.h"
 #include "bpf_util.h"
-#include "test_btf.h"
+#include "../test_btf.h"
+#include "test_progs.h"
 
 #define MAX_INSNS      512
 #define MAX_SUBPROGS   16
 
-static uint32_t pass_cnt;
-static uint32_t error_cnt;
-static uint32_t skip_cnt;
+static int duration = 0;
+static bool always_log;
 
-#define CHECK(condition, format...) ({                                 \
-       int __ret = !!(condition);                                      \
-       if (__ret) {                                                    \
-               fprintf(stderr, "%s:%d:FAIL ", __func__, __LINE__);     \
-               fprintf(stderr, format);                                \
-       }                                                               \
-       __ret;                                                          \
-})
-
-static int count_result(int err)
-{
-       if (err)
-               error_cnt++;
-       else
-               pass_cnt++;
-
-       fprintf(stderr, "\n");
-       return err;
-}
-
-static int __base_pr(enum libbpf_print_level level __attribute__((unused)),
-                    const char *format, va_list args)
-{
-       return vfprintf(stderr, format, args);
-}
+#undef CHECK
+#define CHECK(condition, format...) _CHECK(condition, "check", duration, 
format)
 
 #define BTF_END_RAW 0xdeadbeef
 #define NAME_TBD 0xdeadb33f
@@ -69,21 +46,6 @@ static int __base_pr(enum libbpf_print_level level 
__attribute__((unused)),
 #define MAX_NR_RAW_U32 1024
 #define BTF_LOG_BUF_SIZE 65535
 
-static struct args {
-       unsigned int raw_test_num;
-       unsigned int file_test_num;
-       unsigned int get_info_test_num;
-       unsigned int info_raw_test_num;
-       unsigned int dedup_test_num;
-       bool raw_test;
-       bool file_test;
-       bool get_info_test;
-       bool pprint_test;
-       bool always_log;
-       bool info_raw_test;
-       bool dedup_test;
-} args;
-
 static char btf_log_buf[BTF_LOG_BUF_SIZE];
 
 static struct btf_header hdr_tmpl = {
@@ -3664,7 +3626,7 @@ static void *btf_raw_create(const struct btf_header *hdr,
        return raw_btf;
 }
 
-static int do_test_raw(unsigned int test_num)
+static void do_test_raw(unsigned int test_num)
 {
        struct btf_raw_test *test = &raw_tests[test_num - 1];
        struct bpf_create_map_attr create_attr = {};
@@ -3674,15 +3636,16 @@ static int do_test_raw(unsigned int test_num)
        void *raw_btf;
        int err;
 
-       fprintf(stderr, "BTF raw test[%u] (%s): ", test_num, test->descr);
+       if (!test__start_subtest(test->descr))
+               return;
+
        raw_btf = btf_raw_create(&hdr_tmpl,
                                 test->raw_types,
                                 test->str_sec,
                                 test->str_sec_size,
                                 &raw_btf_size, NULL);
-
        if (!raw_btf)
-               return -1;
+               return;
 
        hdr = raw_btf;
 
@@ -3694,7 +3657,7 @@ static int do_test_raw(unsigned int test_num)
        *btf_log_buf = '\0';
        btf_fd = bpf_load_btf(raw_btf, raw_btf_size,
                              btf_log_buf, BTF_LOG_BUF_SIZE,
-                             args.always_log);
+                             always_log);
        free(raw_btf);
 
        err = ((btf_fd == -1) != test->btf_load_err);
@@ -3725,32 +3688,12 @@ static int do_test_raw(unsigned int test_num)
              map_fd, test->map_create_err);
 
 done:
-       if (!err)
-               fprintf(stderr, "OK");
-
-       if (*btf_log_buf && (err || args.always_log))
+       if (*btf_log_buf && (err || always_log))
                fprintf(stderr, "\n%s", btf_log_buf);
-
        if (btf_fd != -1)
                close(btf_fd);
        if (map_fd != -1)
                close(map_fd);
-
-       return err;
-}
-
-static int test_raw(void)
-{
-       unsigned int i;
-       int err = 0;
-
-       if (args.raw_test_num)
-               return count_result(do_test_raw(args.raw_test_num));
-
-       for (i = 1; i <= ARRAY_SIZE(raw_tests); i++)
-               err |= count_result(do_test_raw(i));
-
-       return err;
 }
 
 struct btf_get_info_test {
@@ -3814,11 +3757,6 @@ const struct btf_get_info_test get_info_tests[] = {
 },
 };
 
-static inline __u64 ptr_to_u64(const void *ptr)
-{
-       return (__u64)(unsigned long)ptr;
-}
-
 static int test_big_btf_info(unsigned int test_num)
 {
        const struct btf_get_info_test *test = &get_info_tests[test_num - 1];
@@ -3851,7 +3789,7 @@ static int test_big_btf_info(unsigned int test_num)
 
        btf_fd = bpf_load_btf(raw_btf, raw_btf_size,
                              btf_log_buf, BTF_LOG_BUF_SIZE,
-                             args.always_log);
+                             always_log);
        if (CHECK(btf_fd == -1, "errno:%d", errno)) {
                err = -1;
                goto done;
@@ -3892,7 +3830,7 @@ static int test_big_btf_info(unsigned int test_num)
        fprintf(stderr, "OK");
 
 done:
-       if (*btf_log_buf && (err || args.always_log))
+       if (*btf_log_buf && (err || always_log))
                fprintf(stderr, "\n%s", btf_log_buf);
 
        free(raw_btf);
@@ -3939,7 +3877,7 @@ static int test_btf_id(unsigned int test_num)
 
        btf_fd[0] = bpf_load_btf(raw_btf, raw_btf_size,
                                 btf_log_buf, BTF_LOG_BUF_SIZE,
-                                args.always_log);
+                                always_log);
        if (CHECK(btf_fd[0] == -1, "errno:%d", errno)) {
                err = -1;
                goto done;
@@ -4024,7 +3962,7 @@ static int test_btf_id(unsigned int test_num)
        fprintf(stderr, "OK");
 
 done:
-       if (*btf_log_buf && (err || args.always_log))
+       if (*btf_log_buf && (err || always_log))
                fprintf(stderr, "\n%s", btf_log_buf);
 
        free(raw_btf);
@@ -4039,7 +3977,7 @@ static int test_btf_id(unsigned int test_num)
        return err;
 }
 
-static int do_test_get_info(unsigned int test_num)
+static void do_test_get_info(unsigned int test_num)
 {
        const struct btf_get_info_test *test = &get_info_tests[test_num - 1];
        unsigned int raw_btf_size, user_btf_size, expected_nbytes;
@@ -4048,11 +3986,14 @@ static int do_test_get_info(unsigned int test_num)
        int btf_fd = -1, err, ret;
        uint32_t info_len;
 
-       fprintf(stderr, "BTF GET_INFO test[%u] (%s): ",
-               test_num, test->descr);
+       if (!test__start_subtest(test->descr))
+               return;
 
-       if (test->special_test)
-               return test->special_test(test_num);
+       if (test->special_test) {
+               err = test->special_test(test_num);
+               if (CHECK(err, "failed: %d\n", err))
+                       return;
+       }
 
        raw_btf = btf_raw_create(&hdr_tmpl,
                                 test->raw_types,
@@ -4061,7 +4002,7 @@ static int do_test_get_info(unsigned int test_num)
                                 &raw_btf_size, NULL);
 
        if (!raw_btf)
-               return -1;
+               return;
 
        *btf_log_buf = '\0';
 
@@ -4073,7 +4014,7 @@ static int do_test_get_info(unsigned int test_num)
 
        btf_fd = bpf_load_btf(raw_btf, raw_btf_size,
                              btf_log_buf, BTF_LOG_BUF_SIZE,
-                             args.always_log);
+                             always_log);
        if (CHECK(btf_fd == -1, "errno:%d", errno)) {
                err = -1;
                goto done;
@@ -4114,7 +4055,7 @@ static int do_test_get_info(unsigned int test_num)
        fprintf(stderr, "OK");
 
 done:
-       if (*btf_log_buf && (err || args.always_log))
+       if (*btf_log_buf && (err || always_log))
                fprintf(stderr, "\n%s", btf_log_buf);
 
        free(raw_btf);
@@ -4122,22 +4063,6 @@ static int do_test_get_info(unsigned int test_num)
 
        if (btf_fd != -1)
                close(btf_fd);
-
-       return err;
-}
-
-static int test_get_info(void)
-{
-       unsigned int i;
-       int err = 0;
-
-       if (args.get_info_test_num)
-               return count_result(do_test_get_info(args.get_info_test_num));
-
-       for (i = 1; i <= ARRAY_SIZE(get_info_tests); i++)
-               err |= count_result(do_test_get_info(i));
-
-       return err;
 }
 
 struct btf_file_test {
@@ -4151,7 +4076,7 @@ static struct btf_file_test file_tests[] = {
        { .file = "test_btf_nokv.o", .btf_kv_notfound = true, },
 };
 
-static int do_test_file(unsigned int test_num)
+static void do_test_file(unsigned int test_num)
 {
        const struct btf_file_test *test = &file_tests[test_num - 1];
        const char *expected_fnames[] = {"_dummy_tracepoint",
@@ -4169,17 +4094,17 @@ static int do_test_file(unsigned int test_num)
        struct bpf_map *map;
        int i, err, prog_fd;
 
-       fprintf(stderr, "BTF libbpf test[%u] (%s): ", test_num,
-               test->file);
+       if (!test__start_subtest(test->file))
+               return;
 
        btf = btf__parse_elf(test->file, &btf_ext);
        if (IS_ERR(btf)) {
                if (PTR_ERR(btf) == -ENOENT) {
-                       fprintf(stderr, "SKIP. No ELF %s found", BTF_ELF_SEC);
-                       skip_cnt++;
-                       return 0;
+                       printf("%s:SKIP: No ELF %s found", __func__, 
BTF_ELF_SEC);
+                       test__skip();
+                       return;
                }
-               return PTR_ERR(btf);
+               return;
        }
        btf__free(btf);
 
@@ -4188,7 +4113,7 @@ static int do_test_file(unsigned int test_num)
 
        obj = bpf_object__open(test->file);
        if (CHECK(IS_ERR(obj), "obj: %ld", PTR_ERR(obj)))
-               return PTR_ERR(obj);
+               return;
 
        prog = bpf_program__next(NULL, obj);
        if (CHECK(!prog, "Cannot find bpf_prog")) {
@@ -4305,715 +4230,11 @@ static int do_test_file(unsigned int test_num)
        }
 
 skip:
-       fprintf(stderr, "OK");
+       return;
 
 done:
        free(func_info);
        bpf_object__close(obj);
-       return err;
-}
-
-static int test_file(void)
-{
-       unsigned int i;
-       int err = 0;
-
-       if (args.file_test_num)
-               return count_result(do_test_file(args.file_test_num));
-
-       for (i = 1; i <= ARRAY_SIZE(file_tests); i++)
-               err |= count_result(do_test_file(i));
-
-       return err;
-}
-
-const char *pprint_enum_str[] = {
-       "ENUM_ZERO",
-       "ENUM_ONE",
-       "ENUM_TWO",
-       "ENUM_THREE",
-};
-
-struct pprint_mapv {
-       uint32_t ui32;
-       uint16_t ui16;
-       /* 2 bytes hole */
-       int32_t si32;
-       uint32_t unused_bits2a:2,
-               bits28:28,
-               unused_bits2b:2;
-       union {
-               uint64_t ui64;
-               uint8_t ui8a[8];
-       };
-       enum {
-               ENUM_ZERO,
-               ENUM_ONE,
-               ENUM_TWO,
-               ENUM_THREE,
-       } aenum;
-       uint32_t ui32b;
-       uint32_t bits2c:2;
-       uint8_t si8_4[2][2];
-};
-
-#ifdef __SIZEOF_INT128__
-struct pprint_mapv_int128 {
-       __int128 si128a;
-       __int128 si128b;
-       unsigned __int128 bits3:3;
-       unsigned __int128 bits80:80;
-       unsigned __int128 ui128;
-};
-#endif
-
-static struct btf_raw_test pprint_test_template[] = {
-{
-       .raw_types = {
-               /* unsighed char */                     /* [1] */
-               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
-               /* unsigned short */                    /* [2] */
-               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 16, 2),
-               /* unsigned int */                      /* [3] */
-               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4),
-               /* int */                               /* [4] */
-               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
-               /* unsigned long long */                /* [5] */
-               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 64, 8),
-               /* 2 bits */                            /* [6] */
-               BTF_TYPE_INT_ENC(0, 0, 0, 2, 2),
-               /* 28 bits */                           /* [7] */
-               BTF_TYPE_INT_ENC(0, 0, 0, 28, 4),
-               /* uint8_t[8] */                        /* [8] */
-               BTF_TYPE_ARRAY_ENC(9, 1, 8),
-               /* typedef unsigned char uint8_t */     /* [9] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 1),
-               /* typedef unsigned short uint16_t */   /* [10] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 2),
-               /* typedef unsigned int uint32_t */     /* [11] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 3),
-               /* typedef int int32_t */               /* [12] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 4),
-               /* typedef unsigned long long uint64_t *//* [13] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 5),
-               /* union (anon) */                      /* [14] */
-               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 0, 2), 8),
-               BTF_MEMBER_ENC(NAME_TBD, 13, 0),/* uint64_t ui64; */
-               BTF_MEMBER_ENC(NAME_TBD, 8, 0), /* uint8_t ui8a[8]; */
-               /* enum (anon) */                       /* [15] */
-               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 4), 4),
-               BTF_ENUM_ENC(NAME_TBD, 0),
-               BTF_ENUM_ENC(NAME_TBD, 1),
-               BTF_ENUM_ENC(NAME_TBD, 2),
-               BTF_ENUM_ENC(NAME_TBD, 3),
-               /* struct pprint_mapv */                /* [16] */
-               BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 11), 
40),
-               BTF_MEMBER_ENC(NAME_TBD, 11, 0),        /* uint32_t ui32 */
-               BTF_MEMBER_ENC(NAME_TBD, 10, 32),       /* uint16_t ui16 */
-               BTF_MEMBER_ENC(NAME_TBD, 12, 64),       /* int32_t si32 */
-               BTF_MEMBER_ENC(NAME_TBD, 6, 96),        /* unused_bits2a */
-               BTF_MEMBER_ENC(NAME_TBD, 7, 98),        /* bits28 */
-               BTF_MEMBER_ENC(NAME_TBD, 6, 126),       /* unused_bits2b */
-               BTF_MEMBER_ENC(0, 14, 128),             /* union (anon) */
-               BTF_MEMBER_ENC(NAME_TBD, 15, 192),      /* aenum */
-               BTF_MEMBER_ENC(NAME_TBD, 11, 224),      /* uint32_t ui32b */
-               BTF_MEMBER_ENC(NAME_TBD, 6, 256),       /* bits2c */
-               BTF_MEMBER_ENC(NAME_TBD, 17, 264),      /* si8_4 */
-               BTF_TYPE_ARRAY_ENC(18, 1, 2),           /* [17] */
-               BTF_TYPE_ARRAY_ENC(1, 1, 2),            /* [18] */
-               BTF_END_RAW,
-       },
-       BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned 
int\0int\0unsigned long 
long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0ui32b\0bits2c\0si8_4"),
-       .key_size = sizeof(unsigned int),
-       .value_size = sizeof(struct pprint_mapv),
-       .key_type_id = 3,       /* unsigned int */
-       .value_type_id = 16,    /* struct pprint_mapv */
-       .max_entries = 128 * 1024,
-},
-
-{
-       /* this type will have the same type as the
-        * first .raw_types definition, but struct type will
-        * be encoded with kind_flag set.
-        */
-       .raw_types = {
-               /* unsighed char */                     /* [1] */
-               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
-               /* unsigned short */                    /* [2] */
-               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 16, 2),
-               /* unsigned int */                      /* [3] */
-               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4),
-               /* int */                               /* [4] */
-               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
-               /* unsigned long long */                /* [5] */
-               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 64, 8),
-               BTF_TYPE_INT_ENC(0, 0, 0, 32, 4),       /* [6] */
-               BTF_TYPE_INT_ENC(0, 0, 0, 32, 4),       /* [7] */
-               /* uint8_t[8] */                        /* [8] */
-               BTF_TYPE_ARRAY_ENC(9, 1, 8),
-               /* typedef unsigned char uint8_t */     /* [9] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 1),
-               /* typedef unsigned short uint16_t */   /* [10] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 2),
-               /* typedef unsigned int uint32_t */     /* [11] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 3),
-               /* typedef int int32_t */               /* [12] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 4),
-               /* typedef unsigned long long uint64_t *//* [13] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 5),
-               /* union (anon) */                      /* [14] */
-               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 0, 2), 8),
-               BTF_MEMBER_ENC(NAME_TBD, 13, 0),/* uint64_t ui64; */
-               BTF_MEMBER_ENC(NAME_TBD, 8, 0), /* uint8_t ui8a[8]; */
-               /* enum (anon) */                       /* [15] */
-               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 4), 4),
-               BTF_ENUM_ENC(NAME_TBD, 0),
-               BTF_ENUM_ENC(NAME_TBD, 1),
-               BTF_ENUM_ENC(NAME_TBD, 2),
-               BTF_ENUM_ENC(NAME_TBD, 3),
-               /* struct pprint_mapv */                /* [16] */
-               BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 11), 
40),
-               BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 0)),  /* 
uint32_t ui32 */
-               BTF_MEMBER_ENC(NAME_TBD, 10, BTF_MEMBER_OFFSET(0, 32)), /* 
uint16_t ui16 */
-               BTF_MEMBER_ENC(NAME_TBD, 12, BTF_MEMBER_OFFSET(0, 64)), /* 
int32_t si32 */
-               BTF_MEMBER_ENC(NAME_TBD, 6, BTF_MEMBER_OFFSET(2, 96)),  /* 
unused_bits2a */
-               BTF_MEMBER_ENC(NAME_TBD, 7, BTF_MEMBER_OFFSET(28, 98)), /* 
bits28 */
-               BTF_MEMBER_ENC(NAME_TBD, 6, BTF_MEMBER_OFFSET(2, 126)), /* 
unused_bits2b */
-               BTF_MEMBER_ENC(0, 14, BTF_MEMBER_OFFSET(0, 128)),       /* 
union (anon) */
-               BTF_MEMBER_ENC(NAME_TBD, 15, BTF_MEMBER_OFFSET(0, 192)),        
/* aenum */
-               BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 224)),        
/* uint32_t ui32b */
-               BTF_MEMBER_ENC(NAME_TBD, 6, BTF_MEMBER_OFFSET(2, 256)), /* 
bits2c */
-               BTF_MEMBER_ENC(NAME_TBD, 17, 264),      /* si8_4 */
-               BTF_TYPE_ARRAY_ENC(18, 1, 2),           /* [17] */
-               BTF_TYPE_ARRAY_ENC(1, 1, 2),            /* [18] */
-               BTF_END_RAW,
-       },
-       BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned 
int\0int\0unsigned long 
long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0ui32b\0bits2c\0si8_4"),
-       .key_size = sizeof(unsigned int),
-       .value_size = sizeof(struct pprint_mapv),
-       .key_type_id = 3,       /* unsigned int */
-       .value_type_id = 16,    /* struct pprint_mapv */
-       .max_entries = 128 * 1024,
-},
-
-{
-       /* this type will have the same layout as the
-        * first .raw_types definition. The struct type will
-        * be encoded with kind_flag set, bitfield members
-        * are added typedef/const/volatile, and bitfield members
-        * will have both int and enum types.
-        */
-       .raw_types = {
-               /* unsighed char */                     /* [1] */
-               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
-               /* unsigned short */                    /* [2] */
-               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 16, 2),
-               /* unsigned int */                      /* [3] */
-               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4),
-               /* int */                               /* [4] */
-               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
-               /* unsigned long long */                /* [5] */
-               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 64, 8),
-               BTF_TYPE_INT_ENC(0, 0, 0, 32, 4),       /* [6] */
-               BTF_TYPE_INT_ENC(0, 0, 0, 32, 4),       /* [7] */
-               /* uint8_t[8] */                        /* [8] */
-               BTF_TYPE_ARRAY_ENC(9, 1, 8),
-               /* typedef unsigned char uint8_t */     /* [9] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 1),
-               /* typedef unsigned short uint16_t */   /* [10] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 2),
-               /* typedef unsigned int uint32_t */     /* [11] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 3),
-               /* typedef int int32_t */               /* [12] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 4),
-               /* typedef unsigned long long uint64_t *//* [13] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 5),
-               /* union (anon) */                      /* [14] */
-               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 0, 2), 8),
-               BTF_MEMBER_ENC(NAME_TBD, 13, 0),/* uint64_t ui64; */
-               BTF_MEMBER_ENC(NAME_TBD, 8, 0), /* uint8_t ui8a[8]; */
-               /* enum (anon) */                       /* [15] */
-               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 4), 4),
-               BTF_ENUM_ENC(NAME_TBD, 0),
-               BTF_ENUM_ENC(NAME_TBD, 1),
-               BTF_ENUM_ENC(NAME_TBD, 2),
-               BTF_ENUM_ENC(NAME_TBD, 3),
-               /* struct pprint_mapv */                /* [16] */
-               BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 11), 
40),
-               BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 0)),  /* 
uint32_t ui32 */
-               BTF_MEMBER_ENC(NAME_TBD, 10, BTF_MEMBER_OFFSET(0, 32)), /* 
uint16_t ui16 */
-               BTF_MEMBER_ENC(NAME_TBD, 12, BTF_MEMBER_OFFSET(0, 64)), /* 
int32_t si32 */
-               BTF_MEMBER_ENC(NAME_TBD, 17, BTF_MEMBER_OFFSET(2, 96)), /* 
unused_bits2a */
-               BTF_MEMBER_ENC(NAME_TBD, 7, BTF_MEMBER_OFFSET(28, 98)), /* 
bits28 */
-               BTF_MEMBER_ENC(NAME_TBD, 19, BTF_MEMBER_OFFSET(2, 126)),/* 
unused_bits2b */
-               BTF_MEMBER_ENC(0, 14, BTF_MEMBER_OFFSET(0, 128)),       /* 
union (anon) */
-               BTF_MEMBER_ENC(NAME_TBD, 15, BTF_MEMBER_OFFSET(0, 192)),        
/* aenum */
-               BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 224)),        
/* uint32_t ui32b */
-               BTF_MEMBER_ENC(NAME_TBD, 17, BTF_MEMBER_OFFSET(2, 256)),        
/* bits2c */
-               BTF_MEMBER_ENC(NAME_TBD, 20, BTF_MEMBER_OFFSET(0, 264)),        
/* si8_4 */
-               /* typedef unsigned int ___int */       /* [17] */
-               BTF_TYPEDEF_ENC(NAME_TBD, 18),
-               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_VOLATILE, 0, 0), 6),      
/* [18] */
-               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 15),        
/* [19] */
-               BTF_TYPE_ARRAY_ENC(21, 1, 2),                                   
/* [20] */
-               BTF_TYPE_ARRAY_ENC(1, 1, 2),                                    
/* [21] */
-               BTF_END_RAW,
-       },
-       BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned 
int\0int\0unsigned long 
long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0ui32b\0bits2c\0___int\0si8_4"),
-       .key_size = sizeof(unsigned int),
-       .value_size = sizeof(struct pprint_mapv),
-       .key_type_id = 3,       /* unsigned int */
-       .value_type_id = 16,    /* struct pprint_mapv */
-       .max_entries = 128 * 1024,
-},
-
-#ifdef __SIZEOF_INT128__
-{
-       /* test int128 */
-       .raw_types = {
-               /* unsigned int */                              /* [1] */
-               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4),
-               /* __int128 */                                  /* [2] */
-               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 128, 16),
-               /* unsigned __int128 */                         /* [3] */
-               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 128, 16),
-               /* struct pprint_mapv_int128 */                 /* [4] */
-               BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 5), 64),
-               BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(0, 0)),           
/* si128a */
-               BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(0, 128)),         
/* si128b */
-               BTF_MEMBER_ENC(NAME_TBD, 3, BTF_MEMBER_OFFSET(3, 256)),         
/* bits3 */
-               BTF_MEMBER_ENC(NAME_TBD, 3, BTF_MEMBER_OFFSET(80, 259)),        
/* bits80 */
-               BTF_MEMBER_ENC(NAME_TBD, 3, BTF_MEMBER_OFFSET(0, 384)),         
/* ui128 */
-               BTF_END_RAW,
-       },
-       BTF_STR_SEC("\0unsigned int\0__int128\0unsigned 
__int128\0pprint_mapv_int128\0si128a\0si128b\0bits3\0bits80\0ui128"),
-       .key_size = sizeof(unsigned int),
-       .value_size = sizeof(struct pprint_mapv_int128),
-       .key_type_id = 1,
-       .value_type_id = 4,
-       .max_entries = 128 * 1024,
-       .mapv_kind = PPRINT_MAPV_KIND_INT128,
-},
-#endif
-
-};
-
-static struct btf_pprint_test_meta {
-       const char *descr;
-       enum bpf_map_type map_type;
-       const char *map_name;
-       bool ordered_map;
-       bool lossless_map;
-       bool percpu_map;
-} pprint_tests_meta[] = {
-{
-       .descr = "BTF pretty print array",
-       .map_type = BPF_MAP_TYPE_ARRAY,
-       .map_name = "pprint_test_array",
-       .ordered_map = true,
-       .lossless_map = true,
-       .percpu_map = false,
-},
-
-{
-       .descr = "BTF pretty print hash",
-       .map_type = BPF_MAP_TYPE_HASH,
-       .map_name = "pprint_test_hash",
-       .ordered_map = false,
-       .lossless_map = true,
-       .percpu_map = false,
-},
-
-{
-       .descr = "BTF pretty print lru hash",
-       .map_type = BPF_MAP_TYPE_LRU_HASH,
-       .map_name = "pprint_test_lru_hash",
-       .ordered_map = false,
-       .lossless_map = false,
-       .percpu_map = false,
-},
-
-{
-       .descr = "BTF pretty print percpu array",
-       .map_type = BPF_MAP_TYPE_PERCPU_ARRAY,
-       .map_name = "pprint_test_percpu_array",
-       .ordered_map = true,
-       .lossless_map = true,
-       .percpu_map = true,
-},
-
-{
-       .descr = "BTF pretty print percpu hash",
-       .map_type = BPF_MAP_TYPE_PERCPU_HASH,
-       .map_name = "pprint_test_percpu_hash",
-       .ordered_map = false,
-       .lossless_map = true,
-       .percpu_map = true,
-},
-
-{
-       .descr = "BTF pretty print lru percpu hash",
-       .map_type = BPF_MAP_TYPE_LRU_PERCPU_HASH,
-       .map_name = "pprint_test_lru_percpu_hash",
-       .ordered_map = false,
-       .lossless_map = false,
-       .percpu_map = true,
-},
-
-};
-
-static size_t get_pprint_mapv_size(enum pprint_mapv_kind_t mapv_kind)
-{
-       if (mapv_kind == PPRINT_MAPV_KIND_BASIC)
-               return sizeof(struct pprint_mapv);
-
-#ifdef __SIZEOF_INT128__
-       if (mapv_kind == PPRINT_MAPV_KIND_INT128)
-               return sizeof(struct pprint_mapv_int128);
-#endif
-
-       assert(0);
-}
-
-static void set_pprint_mapv(enum pprint_mapv_kind_t mapv_kind,
-                           void *mapv, uint32_t i,
-                           int num_cpus, int rounded_value_size)
-{
-       int cpu;
-
-       if (mapv_kind == PPRINT_MAPV_KIND_BASIC) {
-               struct pprint_mapv *v = mapv;
-
-               for (cpu = 0; cpu < num_cpus; cpu++) {
-                       v->ui32 = i + cpu;
-                       v->si32 = -i;
-                       v->unused_bits2a = 3;
-                       v->bits28 = i;
-                       v->unused_bits2b = 3;
-                       v->ui64 = i;
-                       v->aenum = i & 0x03;
-                       v->ui32b = 4;
-                       v->bits2c = 1;
-                       v->si8_4[0][0] = (cpu + i) & 0xff;
-                       v->si8_4[0][1] = (cpu + i + 1) & 0xff;
-                       v->si8_4[1][0] = (cpu + i + 2) & 0xff;
-                       v->si8_4[1][1] = (cpu + i + 3) & 0xff;
-                       v = (void *)v + rounded_value_size;
-               }
-       }
-
-#ifdef __SIZEOF_INT128__
-       if (mapv_kind == PPRINT_MAPV_KIND_INT128) {
-               struct pprint_mapv_int128 *v = mapv;
-
-               for (cpu = 0; cpu < num_cpus; cpu++) {
-                       v->si128a = i;
-                       v->si128b = -i;
-                       v->bits3 = i & 0x07;
-                       v->bits80 = (((unsigned __int128)1) << 64) + i;
-                       v->ui128 = (((unsigned __int128)2) << 64) + i;
-                       v = (void *)v + rounded_value_size;
-               }
-       }
-#endif
-}
-
-ssize_t get_pprint_expected_line(enum pprint_mapv_kind_t mapv_kind,
-                                char *expected_line, ssize_t line_size,
-                                bool percpu_map, unsigned int next_key,
-                                int cpu, void *mapv)
-{
-       ssize_t nexpected_line = -1;
-
-       if (mapv_kind == PPRINT_MAPV_KIND_BASIC) {
-               struct pprint_mapv *v = mapv;
-
-               nexpected_line = snprintf(expected_line, line_size,
-                                         "%s%u: {%u,0,%d,0x%x,0x%x,0x%x,"
-                                         "{%llu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s,"
-                                         "%u,0x%x,[[%d,%d],[%d,%d]]}\n",
-                                         percpu_map ? "\tcpu" : "",
-                                         percpu_map ? cpu : next_key,
-                                         v->ui32, v->si32,
-                                         v->unused_bits2a,
-                                         v->bits28,
-                                         v->unused_bits2b,
-                                         (__u64)v->ui64,
-                                         v->ui8a[0], v->ui8a[1],
-                                         v->ui8a[2], v->ui8a[3],
-                                         v->ui8a[4], v->ui8a[5],
-                                         v->ui8a[6], v->ui8a[7],
-                                         pprint_enum_str[v->aenum],
-                                         v->ui32b,
-                                         v->bits2c,
-                                         v->si8_4[0][0], v->si8_4[0][1],
-                                         v->si8_4[1][0], v->si8_4[1][1]);
-       }
-
-#ifdef __SIZEOF_INT128__
-       if (mapv_kind == PPRINT_MAPV_KIND_INT128) {
-               struct pprint_mapv_int128 *v = mapv;
-
-               nexpected_line = snprintf(expected_line, line_size,
-                                         "%s%u: {0x%lx,0x%lx,0x%lx,"
-                                         "0x%lx%016lx,0x%lx%016lx}\n",
-                                         percpu_map ? "\tcpu" : "",
-                                         percpu_map ? cpu : next_key,
-                                         (uint64_t)v->si128a,
-                                         (uint64_t)v->si128b,
-                                         (uint64_t)v->bits3,
-                                         (uint64_t)(v->bits80 >> 64),
-                                         (uint64_t)v->bits80,
-                                         (uint64_t)(v->ui128 >> 64),
-                                         (uint64_t)v->ui128);
-       }
-#endif
-
-       return nexpected_line;
-}
-
-static int check_line(const char *expected_line, int nexpected_line,
-                     int expected_line_len, const char *line)
-{
-       if (CHECK(nexpected_line == expected_line_len,
-                 "expected_line is too long"))
-               return -1;
-
-       if (strcmp(expected_line, line)) {
-               fprintf(stderr, "unexpected pprint output\n");
-               fprintf(stderr, "expected: %s", expected_line);
-               fprintf(stderr, "    read: %s", line);
-               return -1;
-       }
-
-       return 0;
-}
-
-
-static int do_test_pprint(int test_num)
-{
-       const struct btf_raw_test *test = &pprint_test_template[test_num];
-       enum pprint_mapv_kind_t mapv_kind = test->mapv_kind;
-       struct bpf_create_map_attr create_attr = {};
-       bool ordered_map, lossless_map, percpu_map;
-       int err, ret, num_cpus, rounded_value_size;
-       unsigned int key, nr_read_elems;
-       int map_fd = -1, btf_fd = -1;
-       unsigned int raw_btf_size;
-       char expected_line[255];
-       FILE *pin_file = NULL;
-       char pin_path[255];
-       size_t line_len = 0;
-       char *line = NULL;
-       void *mapv = NULL;
-       uint8_t *raw_btf;
-       ssize_t nread;
-
-       fprintf(stderr, "%s(#%d)......", test->descr, test_num);
-       raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types,
-                                test->str_sec, test->str_sec_size,
-                                &raw_btf_size, NULL);
-
-       if (!raw_btf)
-               return -1;
-
-       *btf_log_buf = '\0';
-       btf_fd = bpf_load_btf(raw_btf, raw_btf_size,
-                             btf_log_buf, BTF_LOG_BUF_SIZE,
-                             args.always_log);
-       free(raw_btf);
-
-       if (CHECK(btf_fd == -1, "errno:%d", errno)) {
-               err = -1;
-               goto done;
-       }
-
-       create_attr.name = test->map_name;
-       create_attr.map_type = test->map_type;
-       create_attr.key_size = test->key_size;
-       create_attr.value_size = test->value_size;
-       create_attr.max_entries = test->max_entries;
-       create_attr.btf_fd = btf_fd;
-       create_attr.btf_key_type_id = test->key_type_id;
-       create_attr.btf_value_type_id = test->value_type_id;
-
-       map_fd = bpf_create_map_xattr(&create_attr);
-       if (CHECK(map_fd == -1, "errno:%d", errno)) {
-               err = -1;
-               goto done;
-       }
-
-       ret = snprintf(pin_path, sizeof(pin_path), "%s/%s",
-                      "/sys/fs/bpf", test->map_name);
-
-       if (CHECK(ret == sizeof(pin_path), "pin_path %s/%s is too long",
-                 "/sys/fs/bpf", test->map_name)) {
-               err = -1;
-               goto done;
-       }
-
-       err = bpf_obj_pin(map_fd, pin_path);
-       if (CHECK(err, "bpf_obj_pin(%s): errno:%d.", pin_path, errno))
-               goto done;
-
-       percpu_map = test->percpu_map;
-       num_cpus = percpu_map ? bpf_num_possible_cpus() : 1;
-       rounded_value_size = round_up(get_pprint_mapv_size(mapv_kind), 8);
-       mapv = calloc(num_cpus, rounded_value_size);
-       if (CHECK(!mapv, "mapv allocation failure")) {
-               err = -1;
-               goto done;
-       }
-
-       for (key = 0; key < test->max_entries; key++) {
-               set_pprint_mapv(mapv_kind, mapv, key, num_cpus, 
rounded_value_size);
-               bpf_map_update_elem(map_fd, &key, mapv, 0);
-       }
-
-       pin_file = fopen(pin_path, "r");
-       if (CHECK(!pin_file, "fopen(%s): errno:%d", pin_path, errno)) {
-               err = -1;
-               goto done;
-       }
-
-       /* Skip lines start with '#' */
-       while ((nread = getline(&line, &line_len, pin_file)) > 0 &&
-              *line == '#')
-               ;
-
-       if (CHECK(nread <= 0, "Unexpected EOF")) {
-               err = -1;
-               goto done;
-       }
-
-       nr_read_elems = 0;
-       ordered_map = test->ordered_map;
-       lossless_map = test->lossless_map;
-       do {
-               ssize_t nexpected_line;
-               unsigned int next_key;
-               void *cmapv;
-               int cpu;
-
-               next_key = ordered_map ? nr_read_elems : atoi(line);
-               set_pprint_mapv(mapv_kind, mapv, next_key, num_cpus, 
rounded_value_size);
-               cmapv = mapv;
-
-               for (cpu = 0; cpu < num_cpus; cpu++) {
-                       if (percpu_map) {
-                               /* for percpu map, the format looks like:
-                                * <key>: {
-                                *      cpu0: <value_on_cpu0>
-                                *      cpu1: <value_on_cpu1>
-                                *      ...
-                                *      cpun: <value_on_cpun>
-                                * }
-                                *
-                                * let us verify the line containing the key 
here.
-                                */
-                               if (cpu == 0) {
-                                       nexpected_line = snprintf(expected_line,
-                                                                 
sizeof(expected_line),
-                                                                 "%u: {\n",
-                                                                 next_key);
-
-                                       err = check_line(expected_line, 
nexpected_line,
-                                                        sizeof(expected_line), 
line);
-                                       if (err == -1)
-                                               goto done;
-                               }
-
-                               /* read value@cpu */
-                               nread = getline(&line, &line_len, pin_file);
-                               if (nread < 0)
-                                       break;
-                       }
-
-                       nexpected_line = get_pprint_expected_line(mapv_kind, 
expected_line,
-                                                                 
sizeof(expected_line),
-                                                                 percpu_map, 
next_key,
-                                                                 cpu, cmapv);
-                       err = check_line(expected_line, nexpected_line,
-                                        sizeof(expected_line), line);
-                       if (err == -1)
-                               goto done;
-
-                       cmapv = cmapv + rounded_value_size;
-               }
-
-               if (percpu_map) {
-                       /* skip the last bracket for the percpu map */
-                       nread = getline(&line, &line_len, pin_file);
-                       if (nread < 0)
-                               break;
-               }
-
-               nread = getline(&line, &line_len, pin_file);
-       } while (++nr_read_elems < test->max_entries && nread > 0);
-
-       if (lossless_map &&
-           CHECK(nr_read_elems < test->max_entries,
-                 "Unexpected EOF. nr_read_elems:%u test->max_entries:%u",
-                 nr_read_elems, test->max_entries)) {
-               err = -1;
-               goto done;
-       }
-
-       if (CHECK(nread > 0, "Unexpected extra pprint output: %s", line)) {
-               err = -1;
-               goto done;
-       }
-
-       err = 0;
-
-done:
-       if (mapv)
-               free(mapv);
-       if (!err)
-               fprintf(stderr, "OK");
-       if (*btf_log_buf && (err || args.always_log))
-               fprintf(stderr, "\n%s", btf_log_buf);
-       if (btf_fd != -1)
-               close(btf_fd);
-       if (map_fd != -1)
-               close(map_fd);
-       if (pin_file)
-               fclose(pin_file);
-       unlink(pin_path);
-       free(line);
-
-       return err;
-}
-
-static int test_pprint(void)
-{
-       unsigned int i;
-       int err = 0;
-
-       /* test various maps with the first test template */
-       for (i = 0; i < ARRAY_SIZE(pprint_tests_meta); i++) {
-               pprint_test_template[0].descr = pprint_tests_meta[i].descr;
-               pprint_test_template[0].map_type = 
pprint_tests_meta[i].map_type;
-               pprint_test_template[0].map_name = 
pprint_tests_meta[i].map_name;
-               pprint_test_template[0].ordered_map = 
pprint_tests_meta[i].ordered_map;
-               pprint_test_template[0].lossless_map = 
pprint_tests_meta[i].lossless_map;
-               pprint_test_template[0].percpu_map = 
pprint_tests_meta[i].percpu_map;
-
-               err |= count_result(do_test_pprint(0));
-       }
-
-       /* test rest test templates with the first map */
-       for (i = 1; i < ARRAY_SIZE(pprint_test_template); i++) {
-               pprint_test_template[i].descr = pprint_tests_meta[0].descr;
-               pprint_test_template[i].map_type = 
pprint_tests_meta[0].map_type;
-               pprint_test_template[i].map_name = 
pprint_tests_meta[0].map_name;
-               pprint_test_template[i].ordered_map = 
pprint_tests_meta[0].ordered_map;
-               pprint_test_template[i].lossless_map = 
pprint_tests_meta[0].lossless_map;
-               pprint_test_template[i].percpu_map = 
pprint_tests_meta[0].percpu_map;
-               err |= count_result(do_test_pprint(i));
-       }
-
-       return err;
 }
 
 #define BPF_LINE_INFO_ENC(insn_off, file_off, line_off, line_num, line_col) \
@@ -6178,7 +5399,7 @@ static int test_get_linfo(const struct prog_info_raw_test 
*test,
        return err;
 }
 
-static int do_test_info_raw(unsigned int test_num)
+static void do_test_info_raw(unsigned int test_num)
 {
        const struct prog_info_raw_test *test = &info_raw_tests[test_num - 1];
        unsigned int raw_btf_size, linfo_str_off, linfo_size;
@@ -6187,18 +5408,19 @@ static int do_test_info_raw(unsigned int test_num)
        const char *ret_next_str;
        union bpf_attr attr = {};
 
-       fprintf(stderr, "BTF prog info raw test[%u] (%s): ", test_num, 
test->descr);
+       if (!test__start_subtest(test->descr))
+               return;
+
        raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types,
                                 test->str_sec, test->str_sec_size,
                                 &raw_btf_size, &ret_next_str);
-
        if (!raw_btf)
-               return -1;
+               return;
 
        *btf_log_buf = '\0';
        btf_fd = bpf_load_btf(raw_btf, raw_btf_size,
                              btf_log_buf, BTF_LOG_BUF_SIZE,
-                             args.always_log);
+                             always_log);
        free(raw_btf);
 
        if (CHECK(btf_fd == -1, "invalid btf_fd errno:%d", errno)) {
@@ -6206,7 +5428,7 @@ static int do_test_info_raw(unsigned int test_num)
                goto done;
        }
 
-       if (*btf_log_buf && args.always_log)
+       if (*btf_log_buf && always_log)
                fprintf(stderr, "\n%s", btf_log_buf);
        *btf_log_buf = '\0';
 
@@ -6261,10 +5483,7 @@ static int do_test_info_raw(unsigned int test_num)
                goto done;
 
 done:
-       if (!err)
-               fprintf(stderr, "OK");
-
-       if (*btf_log_buf && (err || args.always_log))
+       if (*btf_log_buf && (err || always_log))
                fprintf(stderr, "\n%s", btf_log_buf);
 
        if (btf_fd != -1)
@@ -6274,22 +5493,6 @@ static int do_test_info_raw(unsigned int test_num)
 
        if (!IS_ERR(patched_linfo))
                free(patched_linfo);
-
-       return err;
-}
-
-static int test_info_raw(void)
-{
-       unsigned int i;
-       int err = 0;
-
-       if (args.info_raw_test_num)
-               return count_result(do_test_info_raw(args.info_raw_test_num));
-
-       for (i = 1; i <= ARRAY_SIZE(info_raw_tests); i++)
-               err |= count_result(do_test_info_raw(i));
-
-       return err;
 }
 
 struct btf_raw_data {
@@ -6754,7 +5957,7 @@ static void dump_btf_strings(const char *strs, __u32 len)
        }
 }
 
-static int do_test_dedup(unsigned int test_num)
+static void do_test_dedup(unsigned int test_num)
 {
        const struct btf_dedup_test *test = &dedup_tests[test_num - 1];
        __u32 test_nr_types, expect_nr_types, test_btf_size, expect_btf_size;
@@ -6769,13 +5972,15 @@ static int do_test_dedup(unsigned int test_num)
        void *raw_btf;
        int err = 0, i;
 
-       fprintf(stderr, "BTF dedup test[%u] (%s):", test_num, test->descr);
+       if (!test__start_subtest(test->descr))
+               return;
 
        raw_btf = btf_raw_create(&hdr_tmpl, test->input.raw_types,
                                 test->input.str_sec, test->input.str_sec_size,
                                 &raw_btf_size, &ret_test_next_str);
        if (!raw_btf)
-               return -1;
+               return;
+
        test_btf = btf__new((__u8 *)raw_btf, raw_btf_size);
        free(raw_btf);
        if (CHECK(IS_ERR(test_btf), "invalid test_btf errno:%ld",
@@ -6789,7 +5994,7 @@ static int do_test_dedup(unsigned int test_num)
                                 test->expect.str_sec_size,
                                 &raw_btf_size, &ret_expect_next_str);
        if (!raw_btf)
-               return -1;
+               return;
        expect_btf = btf__new((__u8 *)raw_btf, raw_btf_size);
        free(raw_btf);
        if (CHECK(IS_ERR(expect_btf), "invalid expect_btf errno:%ld",
@@ -6894,174 +6099,26 @@ static int do_test_dedup(unsigned int test_num)
        }
 
 done:
-       if (!err)
-               fprintf(stderr, "OK");
        if (!IS_ERR(test_btf))
                btf__free(test_btf);
        if (!IS_ERR(expect_btf))
                btf__free(expect_btf);
-
-       return err;
 }
 
-static int test_dedup(void)
+void test_btf(void)
 {
-       unsigned int i;
-       int err = 0;
+       int i;
 
-       if (args.dedup_test_num)
-               return count_result(do_test_dedup(args.dedup_test_num));
+       always_log = env.verbosity > VERBOSE_NONE;
 
+       for (i = 1; i <= ARRAY_SIZE(raw_tests); i++)
+               do_test_raw(i);
+       for (i = 1; i <= ARRAY_SIZE(get_info_tests); i++)
+               do_test_get_info(i);
+       for (i = 1; i <= ARRAY_SIZE(file_tests); i++)
+               do_test_file(i);
+       for (i = 1; i <= ARRAY_SIZE(info_raw_tests); i++)
+               do_test_info_raw(i);
        for (i = 1; i <= ARRAY_SIZE(dedup_tests); i++)
-               err |= count_result(do_test_dedup(i));
-
-       return err;
-}
-
-static void usage(const char *cmd)
-{
-       fprintf(stderr, "Usage: %s [-l] [[-r btf_raw_test_num (1 - %zu)] |\n"
-                       "\t[-g btf_get_info_test_num (1 - %zu)] |\n"
-                       "\t[-f btf_file_test_num (1 - %zu)] |\n"
-                       "\t[-k btf_prog_info_raw_test_num (1 - %zu)] |\n"
-                       "\t[-p (pretty print test)] |\n"
-                       "\t[-d btf_dedup_test_num (1 - %zu)]]\n",
-               cmd, ARRAY_SIZE(raw_tests), ARRAY_SIZE(get_info_tests),
-               ARRAY_SIZE(file_tests), ARRAY_SIZE(info_raw_tests),
-               ARRAY_SIZE(dedup_tests));
-}
-
-static int parse_args(int argc, char **argv)
-{
-       const char *optstr = "hlpk:f:r:g:d:";
-       int opt;
-
-       while ((opt = getopt(argc, argv, optstr)) != -1) {
-               switch (opt) {
-               case 'l':
-                       args.always_log = true;
-                       break;
-               case 'f':
-                       args.file_test_num = atoi(optarg);
-                       args.file_test = true;
-                       break;
-               case 'r':
-                       args.raw_test_num = atoi(optarg);
-                       args.raw_test = true;
-                       break;
-               case 'g':
-                       args.get_info_test_num = atoi(optarg);
-                       args.get_info_test = true;
-                       break;
-               case 'p':
-                       args.pprint_test = true;
-                       break;
-               case 'k':
-                       args.info_raw_test_num = atoi(optarg);
-                       args.info_raw_test = true;
-                       break;
-               case 'd':
-                       args.dedup_test_num = atoi(optarg);
-                       args.dedup_test = true;
-                       break;
-               case 'h':
-                       usage(argv[0]);
-                       exit(0);
-               default:
-                       usage(argv[0]);
-                       return -1;
-               }
-       }
-
-       if (args.raw_test_num &&
-           (args.raw_test_num < 1 ||
-            args.raw_test_num > ARRAY_SIZE(raw_tests))) {
-               fprintf(stderr, "BTF raw test number must be [1 - %zu]\n",
-                       ARRAY_SIZE(raw_tests));
-               return -1;
-       }
-
-       if (args.file_test_num &&
-           (args.file_test_num < 1 ||
-            args.file_test_num > ARRAY_SIZE(file_tests))) {
-               fprintf(stderr, "BTF file test number must be [1 - %zu]\n",
-                       ARRAY_SIZE(file_tests));
-               return -1;
-       }
-
-       if (args.get_info_test_num &&
-           (args.get_info_test_num < 1 ||
-            args.get_info_test_num > ARRAY_SIZE(get_info_tests))) {
-               fprintf(stderr, "BTF get info test number must be [1 - %zu]\n",
-                       ARRAY_SIZE(get_info_tests));
-               return -1;
-       }
-
-       if (args.info_raw_test_num &&
-           (args.info_raw_test_num < 1 ||
-            args.info_raw_test_num > ARRAY_SIZE(info_raw_tests))) {
-               fprintf(stderr, "BTF prog info raw test number must be [1 - 
%zu]\n",
-                       ARRAY_SIZE(info_raw_tests));
-               return -1;
-       }
-
-       if (args.dedup_test_num &&
-           (args.dedup_test_num < 1 ||
-            args.dedup_test_num > ARRAY_SIZE(dedup_tests))) {
-               fprintf(stderr, "BTF dedup test number must be [1 - %zu]\n",
-                       ARRAY_SIZE(dedup_tests));
-               return -1;
-       }
-
-       return 0;
-}
-
-static void print_summary(void)
-{
-       fprintf(stderr, "PASS:%u SKIP:%u FAIL:%u\n",
-               pass_cnt - skip_cnt, skip_cnt, error_cnt);
-}
-
-int main(int argc, char **argv)
-{
-       int err = 0;
-
-       err = parse_args(argc, argv);
-       if (err)
-               return err;
-
-       if (args.always_log)
-               libbpf_set_print(__base_pr);
-
-       if (args.raw_test)
-               err |= test_raw();
-
-       if (args.get_info_test)
-               err |= test_get_info();
-
-       if (args.file_test)
-               err |= test_file();
-
-       if (args.pprint_test)
-               err |= test_pprint();
-
-       if (args.info_raw_test)
-               err |= test_info_raw();
-
-       if (args.dedup_test)
-               err |= test_dedup();
-
-       if (args.raw_test || args.get_info_test || args.file_test ||
-           args.pprint_test || args.info_raw_test || args.dedup_test)
-               goto done;
-
-       err |= test_raw();
-       err |= test_get_info();
-       err |= test_file();
-       err |= test_info_raw();
-       err |= test_dedup();
-
-done:
-       print_summary();
-       return err;
+               do_test_dedup(i);
 }
diff --git a/tools/testing/selftests/bpf/test_btf_pprint.c 
b/tools/testing/selftests/bpf/test_btf_pprint.c
new file mode 100644
index 000000000000..2108c1ada14b
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_btf_pprint.c
@@ -0,0 +1,969 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Facebook */
+
+#include <linux/bpf.h>
+#include <linux/btf.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/filter.h>
+#include <linux/unistd.h>
+#include <bpf/bpf.h>
+#include <sys/resource.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <bpf/libbpf.h>
+#include <bpf/btf.h>
+
+#include "bpf_rlimit.h"
+#include "bpf_util.h"
+#include "test_btf.h"
+
+#define MAX_INSNS      512
+#define MAX_SUBPROGS   16
+
+static uint32_t pass_cnt;
+static uint32_t error_cnt;
+static uint32_t skip_cnt;
+
+#define CHECK(condition, format...) ({                                 \
+       int __ret = !!(condition);                                      \
+       if (__ret) {                                                    \
+               fprintf(stderr, "%s:%d:FAIL ", __func__, __LINE__);     \
+               fprintf(stderr, format);                                \
+       }                                                               \
+       __ret;                                                          \
+})
+
+static int count_result(int err)
+{
+       if (err)
+               error_cnt++;
+       else
+               pass_cnt++;
+
+       fprintf(stderr, "\n");
+       return err;
+}
+
+static int __base_pr(enum libbpf_print_level level __attribute__((unused)),
+                    const char *format, va_list args)
+{
+       return vfprintf(stderr, format, args);
+}
+
+#define BTF_END_RAW 0xdeadbeef
+#define NAME_TBD 0xdeadb33f
+
+#define NAME_NTH(N) (0xffff0000 | N)
+#define IS_NAME_NTH(X) ((X & 0xffff0000) == 0xffff0000)
+#define GET_NAME_NTH_IDX(X) (X & 0x0000ffff)
+
+#define MAX_NR_RAW_U32 1024
+#define BTF_LOG_BUF_SIZE 65535
+
+static struct args {
+       bool always_log;
+} args;
+
+static char btf_log_buf[BTF_LOG_BUF_SIZE];
+
+static struct btf_header hdr_tmpl = {
+       .magic = BTF_MAGIC,
+       .version = BTF_VERSION,
+       .hdr_len = sizeof(struct btf_header),
+};
+
+/* several different mapv kinds(types) supported by pprint */
+enum pprint_mapv_kind_t {
+       PPRINT_MAPV_KIND_BASIC = 0,
+       PPRINT_MAPV_KIND_INT128,
+};
+
+struct btf_raw_test {
+       const char *descr;
+       const char *str_sec;
+       const char *map_name;
+       const char *err_str;
+       __u32 raw_types[MAX_NR_RAW_U32];
+       __u32 str_sec_size;
+       enum bpf_map_type map_type;
+       __u32 key_size;
+       __u32 value_size;
+       __u32 key_type_id;
+       __u32 value_type_id;
+       __u32 max_entries;
+       bool btf_load_err;
+       bool map_create_err;
+       bool ordered_map;
+       bool lossless_map;
+       bool percpu_map;
+       int hdr_len_delta;
+       int type_off_delta;
+       int str_off_delta;
+       int str_len_delta;
+       enum pprint_mapv_kind_t mapv_kind;
+};
+
+#define BTF_STR_SEC(str) \
+       .str_sec = str, .str_sec_size = sizeof(str)
+
+static const char *get_next_str(const char *start, const char *end)
+{
+       return start < end - 1 ? start + 1 : NULL;
+}
+
+static int get_raw_sec_size(const __u32 *raw_types)
+{
+       int i;
+
+       for (i = MAX_NR_RAW_U32 - 1;
+            i >= 0 && raw_types[i] != BTF_END_RAW;
+            i--)
+               ;
+
+       return i < 0 ? i : i * sizeof(raw_types[0]);
+}
+
+static void *btf_raw_create(const struct btf_header *hdr,
+                           const __u32 *raw_types,
+                           const char *str,
+                           unsigned int str_sec_size,
+                           unsigned int *btf_size,
+                           const char **ret_next_str)
+{
+       const char *next_str = str, *end_str = str + str_sec_size;
+       const char **strs_idx = NULL, **tmp_strs_idx;
+       int strs_cap = 0, strs_cnt = 0, next_str_idx = 0;
+       unsigned int size_needed, offset;
+       struct btf_header *ret_hdr;
+       int i, type_sec_size, err = 0;
+       uint32_t *ret_types;
+       void *raw_btf = NULL;
+
+       type_sec_size = get_raw_sec_size(raw_types);
+       if (CHECK(type_sec_size < 0, "Cannot get nr_raw_types"))
+               return NULL;
+
+       size_needed = sizeof(*hdr) + type_sec_size + str_sec_size;
+       raw_btf = malloc(size_needed);
+       if (CHECK(!raw_btf, "Cannot allocate memory for raw_btf"))
+               return NULL;
+
+       /* Copy header */
+       memcpy(raw_btf, hdr, sizeof(*hdr));
+       offset = sizeof(*hdr);
+
+       /* Index strings */
+       while ((next_str = get_next_str(next_str, end_str))) {
+               if (strs_cnt == strs_cap) {
+                       strs_cap += max(16, strs_cap / 2);
+                       tmp_strs_idx = realloc(strs_idx,
+                                              sizeof(*strs_idx) * strs_cap);
+                       if (CHECK(!tmp_strs_idx,
+                                 "Cannot allocate memory for strs_idx")) {
+                               err = -1;
+                               goto done;
+                       }
+                       strs_idx = tmp_strs_idx;
+               }
+               strs_idx[strs_cnt++] = next_str;
+               next_str += strlen(next_str);
+       }
+
+       /* Copy type section */
+       ret_types = raw_btf + offset;
+       for (i = 0; i < type_sec_size / sizeof(raw_types[0]); i++) {
+               if (raw_types[i] == NAME_TBD) {
+                       if (CHECK(next_str_idx == strs_cnt,
+                                 "Error in getting next_str #%d",
+                                 next_str_idx)) {
+                               err = -1;
+                               goto done;
+                       }
+                       ret_types[i] = strs_idx[next_str_idx++] - str;
+               } else if (IS_NAME_NTH(raw_types[i])) {
+                       int idx = GET_NAME_NTH_IDX(raw_types[i]);
+
+                       if (CHECK(idx <= 0 || idx > strs_cnt,
+                                 "Error getting string #%d, strs_cnt:%d",
+                                 idx, strs_cnt)) {
+                               err = -1;
+                               goto done;
+                       }
+                       ret_types[i] = strs_idx[idx-1] - str;
+               } else {
+                       ret_types[i] = raw_types[i];
+               }
+       }
+       offset += type_sec_size;
+
+       /* Copy string section */
+       memcpy(raw_btf + offset, str, str_sec_size);
+
+       ret_hdr = (struct btf_header *)raw_btf;
+       ret_hdr->type_len = type_sec_size;
+       ret_hdr->str_off = type_sec_size;
+       ret_hdr->str_len = str_sec_size;
+
+       *btf_size = size_needed;
+       if (ret_next_str)
+               *ret_next_str =
+                       next_str_idx < strs_cnt ? strs_idx[next_str_idx] : NULL;
+
+done:
+       if (err) {
+               if (raw_btf)
+                       free(raw_btf);
+               if (strs_idx)
+                       free(strs_idx);
+               return NULL;
+       }
+       return raw_btf;
+}
+
+const char *pprint_enum_str[] = {
+       "ENUM_ZERO",
+       "ENUM_ONE",
+       "ENUM_TWO",
+       "ENUM_THREE",
+};
+
+struct pprint_mapv {
+       uint32_t ui32;
+       uint16_t ui16;
+       /* 2 bytes hole */
+       int32_t si32;
+       uint32_t unused_bits2a:2,
+               bits28:28,
+               unused_bits2b:2;
+       union {
+               uint64_t ui64;
+               uint8_t ui8a[8];
+       };
+       enum {
+               ENUM_ZERO,
+               ENUM_ONE,
+               ENUM_TWO,
+               ENUM_THREE,
+       } aenum;
+       uint32_t ui32b;
+       uint32_t bits2c:2;
+       uint8_t si8_4[2][2];
+};
+
+#ifdef __SIZEOF_INT128__
+struct pprint_mapv_int128 {
+       __int128 si128a;
+       __int128 si128b;
+       unsigned __int128 bits3:3;
+       unsigned __int128 bits80:80;
+       unsigned __int128 ui128;
+};
+#endif
+
+static struct btf_raw_test pprint_test_template[] = {
+{
+       .raw_types = {
+               /* unsighed char */                     /* [1] */
+               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
+               /* unsigned short */                    /* [2] */
+               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 16, 2),
+               /* unsigned int */                      /* [3] */
+               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4),
+               /* int */                               /* [4] */
+               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
+               /* unsigned long long */                /* [5] */
+               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 64, 8),
+               /* 2 bits */                            /* [6] */
+               BTF_TYPE_INT_ENC(0, 0, 0, 2, 2),
+               /* 28 bits */                           /* [7] */
+               BTF_TYPE_INT_ENC(0, 0, 0, 28, 4),
+               /* uint8_t[8] */                        /* [8] */
+               BTF_TYPE_ARRAY_ENC(9, 1, 8),
+               /* typedef unsigned char uint8_t */     /* [9] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 1),
+               /* typedef unsigned short uint16_t */   /* [10] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 2),
+               /* typedef unsigned int uint32_t */     /* [11] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 3),
+               /* typedef int int32_t */               /* [12] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 4),
+               /* typedef unsigned long long uint64_t *//* [13] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 5),
+               /* union (anon) */                      /* [14] */
+               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 0, 2), 8),
+               BTF_MEMBER_ENC(NAME_TBD, 13, 0),/* uint64_t ui64; */
+               BTF_MEMBER_ENC(NAME_TBD, 8, 0), /* uint8_t ui8a[8]; */
+               /* enum (anon) */                       /* [15] */
+               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 4), 4),
+               BTF_ENUM_ENC(NAME_TBD, 0),
+               BTF_ENUM_ENC(NAME_TBD, 1),
+               BTF_ENUM_ENC(NAME_TBD, 2),
+               BTF_ENUM_ENC(NAME_TBD, 3),
+               /* struct pprint_mapv */                /* [16] */
+               BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 11), 
40),
+               BTF_MEMBER_ENC(NAME_TBD, 11, 0),        /* uint32_t ui32 */
+               BTF_MEMBER_ENC(NAME_TBD, 10, 32),       /* uint16_t ui16 */
+               BTF_MEMBER_ENC(NAME_TBD, 12, 64),       /* int32_t si32 */
+               BTF_MEMBER_ENC(NAME_TBD, 6, 96),        /* unused_bits2a */
+               BTF_MEMBER_ENC(NAME_TBD, 7, 98),        /* bits28 */
+               BTF_MEMBER_ENC(NAME_TBD, 6, 126),       /* unused_bits2b */
+               BTF_MEMBER_ENC(0, 14, 128),             /* union (anon) */
+               BTF_MEMBER_ENC(NAME_TBD, 15, 192),      /* aenum */
+               BTF_MEMBER_ENC(NAME_TBD, 11, 224),      /* uint32_t ui32b */
+               BTF_MEMBER_ENC(NAME_TBD, 6, 256),       /* bits2c */
+               BTF_MEMBER_ENC(NAME_TBD, 17, 264),      /* si8_4 */
+               BTF_TYPE_ARRAY_ENC(18, 1, 2),           /* [17] */
+               BTF_TYPE_ARRAY_ENC(1, 1, 2),            /* [18] */
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned 
int\0int\0unsigned long 
long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0ui32b\0bits2c\0si8_4"),
+       .key_size = sizeof(unsigned int),
+       .value_size = sizeof(struct pprint_mapv),
+       .key_type_id = 3,       /* unsigned int */
+       .value_type_id = 16,    /* struct pprint_mapv */
+       .max_entries = 128 * 1024,
+},
+
+{
+       /* this type will have the same type as the
+        * first .raw_types definition, but struct type will
+        * be encoded with kind_flag set.
+        */
+       .raw_types = {
+               /* unsighed char */                     /* [1] */
+               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
+               /* unsigned short */                    /* [2] */
+               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 16, 2),
+               /* unsigned int */                      /* [3] */
+               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4),
+               /* int */                               /* [4] */
+               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
+               /* unsigned long long */                /* [5] */
+               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 64, 8),
+               BTF_TYPE_INT_ENC(0, 0, 0, 32, 4),       /* [6] */
+               BTF_TYPE_INT_ENC(0, 0, 0, 32, 4),       /* [7] */
+               /* uint8_t[8] */                        /* [8] */
+               BTF_TYPE_ARRAY_ENC(9, 1, 8),
+               /* typedef unsigned char uint8_t */     /* [9] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 1),
+               /* typedef unsigned short uint16_t */   /* [10] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 2),
+               /* typedef unsigned int uint32_t */     /* [11] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 3),
+               /* typedef int int32_t */               /* [12] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 4),
+               /* typedef unsigned long long uint64_t *//* [13] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 5),
+               /* union (anon) */                      /* [14] */
+               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 0, 2), 8),
+               BTF_MEMBER_ENC(NAME_TBD, 13, 0),/* uint64_t ui64; */
+               BTF_MEMBER_ENC(NAME_TBD, 8, 0), /* uint8_t ui8a[8]; */
+               /* enum (anon) */                       /* [15] */
+               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 4), 4),
+               BTF_ENUM_ENC(NAME_TBD, 0),
+               BTF_ENUM_ENC(NAME_TBD, 1),
+               BTF_ENUM_ENC(NAME_TBD, 2),
+               BTF_ENUM_ENC(NAME_TBD, 3),
+               /* struct pprint_mapv */                /* [16] */
+               BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 11), 
40),
+               BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 0)),  /* 
uint32_t ui32 */
+               BTF_MEMBER_ENC(NAME_TBD, 10, BTF_MEMBER_OFFSET(0, 32)), /* 
uint16_t ui16 */
+               BTF_MEMBER_ENC(NAME_TBD, 12, BTF_MEMBER_OFFSET(0, 64)), /* 
int32_t si32 */
+               BTF_MEMBER_ENC(NAME_TBD, 6, BTF_MEMBER_OFFSET(2, 96)),  /* 
unused_bits2a */
+               BTF_MEMBER_ENC(NAME_TBD, 7, BTF_MEMBER_OFFSET(28, 98)), /* 
bits28 */
+               BTF_MEMBER_ENC(NAME_TBD, 6, BTF_MEMBER_OFFSET(2, 126)), /* 
unused_bits2b */
+               BTF_MEMBER_ENC(0, 14, BTF_MEMBER_OFFSET(0, 128)),       /* 
union (anon) */
+               BTF_MEMBER_ENC(NAME_TBD, 15, BTF_MEMBER_OFFSET(0, 192)),        
/* aenum */
+               BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 224)),        
/* uint32_t ui32b */
+               BTF_MEMBER_ENC(NAME_TBD, 6, BTF_MEMBER_OFFSET(2, 256)), /* 
bits2c */
+               BTF_MEMBER_ENC(NAME_TBD, 17, 264),      /* si8_4 */
+               BTF_TYPE_ARRAY_ENC(18, 1, 2),           /* [17] */
+               BTF_TYPE_ARRAY_ENC(1, 1, 2),            /* [18] */
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned 
int\0int\0unsigned long 
long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0ui32b\0bits2c\0si8_4"),
+       .key_size = sizeof(unsigned int),
+       .value_size = sizeof(struct pprint_mapv),
+       .key_type_id = 3,       /* unsigned int */
+       .value_type_id = 16,    /* struct pprint_mapv */
+       .max_entries = 128 * 1024,
+},
+
+{
+       /* this type will have the same layout as the
+        * first .raw_types definition. The struct type will
+        * be encoded with kind_flag set, bitfield members
+        * are added typedef/const/volatile, and bitfield members
+        * will have both int and enum types.
+        */
+       .raw_types = {
+               /* unsighed char */                     /* [1] */
+               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
+               /* unsigned short */                    /* [2] */
+               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 16, 2),
+               /* unsigned int */                      /* [3] */
+               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4),
+               /* int */                               /* [4] */
+               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
+               /* unsigned long long */                /* [5] */
+               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 64, 8),
+               BTF_TYPE_INT_ENC(0, 0, 0, 32, 4),       /* [6] */
+               BTF_TYPE_INT_ENC(0, 0, 0, 32, 4),       /* [7] */
+               /* uint8_t[8] */                        /* [8] */
+               BTF_TYPE_ARRAY_ENC(9, 1, 8),
+               /* typedef unsigned char uint8_t */     /* [9] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 1),
+               /* typedef unsigned short uint16_t */   /* [10] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 2),
+               /* typedef unsigned int uint32_t */     /* [11] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 3),
+               /* typedef int int32_t */               /* [12] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 4),
+               /* typedef unsigned long long uint64_t *//* [13] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 5),
+               /* union (anon) */                      /* [14] */
+               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 0, 2), 8),
+               BTF_MEMBER_ENC(NAME_TBD, 13, 0),/* uint64_t ui64; */
+               BTF_MEMBER_ENC(NAME_TBD, 8, 0), /* uint8_t ui8a[8]; */
+               /* enum (anon) */                       /* [15] */
+               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 4), 4),
+               BTF_ENUM_ENC(NAME_TBD, 0),
+               BTF_ENUM_ENC(NAME_TBD, 1),
+               BTF_ENUM_ENC(NAME_TBD, 2),
+               BTF_ENUM_ENC(NAME_TBD, 3),
+               /* struct pprint_mapv */                /* [16] */
+               BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 11), 
40),
+               BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 0)),  /* 
uint32_t ui32 */
+               BTF_MEMBER_ENC(NAME_TBD, 10, BTF_MEMBER_OFFSET(0, 32)), /* 
uint16_t ui16 */
+               BTF_MEMBER_ENC(NAME_TBD, 12, BTF_MEMBER_OFFSET(0, 64)), /* 
int32_t si32 */
+               BTF_MEMBER_ENC(NAME_TBD, 17, BTF_MEMBER_OFFSET(2, 96)), /* 
unused_bits2a */
+               BTF_MEMBER_ENC(NAME_TBD, 7, BTF_MEMBER_OFFSET(28, 98)), /* 
bits28 */
+               BTF_MEMBER_ENC(NAME_TBD, 19, BTF_MEMBER_OFFSET(2, 126)),/* 
unused_bits2b */
+               BTF_MEMBER_ENC(0, 14, BTF_MEMBER_OFFSET(0, 128)),       /* 
union (anon) */
+               BTF_MEMBER_ENC(NAME_TBD, 15, BTF_MEMBER_OFFSET(0, 192)),        
/* aenum */
+               BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 224)),        
/* uint32_t ui32b */
+               BTF_MEMBER_ENC(NAME_TBD, 17, BTF_MEMBER_OFFSET(2, 256)),        
/* bits2c */
+               BTF_MEMBER_ENC(NAME_TBD, 20, BTF_MEMBER_OFFSET(0, 264)),        
/* si8_4 */
+               /* typedef unsigned int ___int */       /* [17] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 18),
+               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_VOLATILE, 0, 0), 6),      
/* [18] */
+               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 15),        
/* [19] */
+               BTF_TYPE_ARRAY_ENC(21, 1, 2),                                   
/* [20] */
+               BTF_TYPE_ARRAY_ENC(1, 1, 2),                                    
/* [21] */
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned 
int\0int\0unsigned long 
long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0ui32b\0bits2c\0___int\0si8_4"),
+       .key_size = sizeof(unsigned int),
+       .value_size = sizeof(struct pprint_mapv),
+       .key_type_id = 3,       /* unsigned int */
+       .value_type_id = 16,    /* struct pprint_mapv */
+       .max_entries = 128 * 1024,
+},
+
+#ifdef __SIZEOF_INT128__
+{
+       /* test int128 */
+       .raw_types = {
+               /* unsigned int */                              /* [1] */
+               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4),
+               /* __int128 */                                  /* [2] */
+               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 128, 16),
+               /* unsigned __int128 */                         /* [3] */
+               BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 128, 16),
+               /* struct pprint_mapv_int128 */                 /* [4] */
+               BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 5), 64),
+               BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(0, 0)),           
/* si128a */
+               BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(0, 128)),         
/* si128b */
+               BTF_MEMBER_ENC(NAME_TBD, 3, BTF_MEMBER_OFFSET(3, 256)),         
/* bits3 */
+               BTF_MEMBER_ENC(NAME_TBD, 3, BTF_MEMBER_OFFSET(80, 259)),        
/* bits80 */
+               BTF_MEMBER_ENC(NAME_TBD, 3, BTF_MEMBER_OFFSET(0, 384)),         
/* ui128 */
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0unsigned int\0__int128\0unsigned 
__int128\0pprint_mapv_int128\0si128a\0si128b\0bits3\0bits80\0ui128"),
+       .key_size = sizeof(unsigned int),
+       .value_size = sizeof(struct pprint_mapv_int128),
+       .key_type_id = 1,
+       .value_type_id = 4,
+       .max_entries = 128 * 1024,
+       .mapv_kind = PPRINT_MAPV_KIND_INT128,
+},
+#endif
+
+};
+
+static struct btf_pprint_test_meta {
+       const char *descr;
+       enum bpf_map_type map_type;
+       const char *map_name;
+       bool ordered_map;
+       bool lossless_map;
+       bool percpu_map;
+} pprint_tests_meta[] = {
+{
+       .descr = "BTF pretty print array",
+       .map_type = BPF_MAP_TYPE_ARRAY,
+       .map_name = "pprint_test_array",
+       .ordered_map = true,
+       .lossless_map = true,
+       .percpu_map = false,
+},
+
+{
+       .descr = "BTF pretty print hash",
+       .map_type = BPF_MAP_TYPE_HASH,
+       .map_name = "pprint_test_hash",
+       .ordered_map = false,
+       .lossless_map = true,
+       .percpu_map = false,
+},
+
+{
+       .descr = "BTF pretty print lru hash",
+       .map_type = BPF_MAP_TYPE_LRU_HASH,
+       .map_name = "pprint_test_lru_hash",
+       .ordered_map = false,
+       .lossless_map = false,
+       .percpu_map = false,
+},
+
+{
+       .descr = "BTF pretty print percpu array",
+       .map_type = BPF_MAP_TYPE_PERCPU_ARRAY,
+       .map_name = "pprint_test_percpu_array",
+       .ordered_map = true,
+       .lossless_map = true,
+       .percpu_map = true,
+},
+
+{
+       .descr = "BTF pretty print percpu hash",
+       .map_type = BPF_MAP_TYPE_PERCPU_HASH,
+       .map_name = "pprint_test_percpu_hash",
+       .ordered_map = false,
+       .lossless_map = true,
+       .percpu_map = true,
+},
+
+{
+       .descr = "BTF pretty print lru percpu hash",
+       .map_type = BPF_MAP_TYPE_LRU_PERCPU_HASH,
+       .map_name = "pprint_test_lru_percpu_hash",
+       .ordered_map = false,
+       .lossless_map = false,
+       .percpu_map = true,
+},
+
+};
+
+static size_t get_pprint_mapv_size(enum pprint_mapv_kind_t mapv_kind)
+{
+       if (mapv_kind == PPRINT_MAPV_KIND_BASIC)
+               return sizeof(struct pprint_mapv);
+
+#ifdef __SIZEOF_INT128__
+       if (mapv_kind == PPRINT_MAPV_KIND_INT128)
+               return sizeof(struct pprint_mapv_int128);
+#endif
+
+       assert(0);
+}
+
+static void set_pprint_mapv(enum pprint_mapv_kind_t mapv_kind,
+                           void *mapv, uint32_t i,
+                           int num_cpus, int rounded_value_size)
+{
+       int cpu;
+
+       if (mapv_kind == PPRINT_MAPV_KIND_BASIC) {
+               struct pprint_mapv *v = mapv;
+
+               for (cpu = 0; cpu < num_cpus; cpu++) {
+                       v->ui32 = i + cpu;
+                       v->si32 = -i;
+                       v->unused_bits2a = 3;
+                       v->bits28 = i;
+                       v->unused_bits2b = 3;
+                       v->ui64 = i;
+                       v->aenum = i & 0x03;
+                       v->ui32b = 4;
+                       v->bits2c = 1;
+                       v->si8_4[0][0] = (cpu + i) & 0xff;
+                       v->si8_4[0][1] = (cpu + i + 1) & 0xff;
+                       v->si8_4[1][0] = (cpu + i + 2) & 0xff;
+                       v->si8_4[1][1] = (cpu + i + 3) & 0xff;
+                       v = (void *)v + rounded_value_size;
+               }
+       }
+
+#ifdef __SIZEOF_INT128__
+       if (mapv_kind == PPRINT_MAPV_KIND_INT128) {
+               struct pprint_mapv_int128 *v = mapv;
+
+               for (cpu = 0; cpu < num_cpus; cpu++) {
+                       v->si128a = i;
+                       v->si128b = -i;
+                       v->bits3 = i & 0x07;
+                       v->bits80 = (((unsigned __int128)1) << 64) + i;
+                       v->ui128 = (((unsigned __int128)2) << 64) + i;
+                       v = (void *)v + rounded_value_size;
+               }
+       }
+#endif
+}
+
+ssize_t get_pprint_expected_line(enum pprint_mapv_kind_t mapv_kind,
+                                char *expected_line, ssize_t line_size,
+                                bool percpu_map, unsigned int next_key,
+                                int cpu, void *mapv)
+{
+       ssize_t nexpected_line = -1;
+
+       if (mapv_kind == PPRINT_MAPV_KIND_BASIC) {
+               struct pprint_mapv *v = mapv;
+
+               nexpected_line = snprintf(expected_line, line_size,
+                                         "%s%u: {%u,0,%d,0x%x,0x%x,0x%x,"
+                                         "{%llu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s,"
+                                         "%u,0x%x,[[%d,%d],[%d,%d]]}\n",
+                                         percpu_map ? "\tcpu" : "",
+                                         percpu_map ? cpu : next_key,
+                                         v->ui32, v->si32,
+                                         v->unused_bits2a,
+                                         v->bits28,
+                                         v->unused_bits2b,
+                                         (__u64)v->ui64,
+                                         v->ui8a[0], v->ui8a[1],
+                                         v->ui8a[2], v->ui8a[3],
+                                         v->ui8a[4], v->ui8a[5],
+                                         v->ui8a[6], v->ui8a[7],
+                                         pprint_enum_str[v->aenum],
+                                         v->ui32b,
+                                         v->bits2c,
+                                         v->si8_4[0][0], v->si8_4[0][1],
+                                         v->si8_4[1][0], v->si8_4[1][1]);
+       }
+
+#ifdef __SIZEOF_INT128__
+       if (mapv_kind == PPRINT_MAPV_KIND_INT128) {
+               struct pprint_mapv_int128 *v = mapv;
+
+               nexpected_line = snprintf(expected_line, line_size,
+                                         "%s%u: {0x%lx,0x%lx,0x%lx,"
+                                         "0x%lx%016lx,0x%lx%016lx}\n",
+                                         percpu_map ? "\tcpu" : "",
+                                         percpu_map ? cpu : next_key,
+                                         (uint64_t)v->si128a,
+                                         (uint64_t)v->si128b,
+                                         (uint64_t)v->bits3,
+                                         (uint64_t)(v->bits80 >> 64),
+                                         (uint64_t)v->bits80,
+                                         (uint64_t)(v->ui128 >> 64),
+                                         (uint64_t)v->ui128);
+       }
+#endif
+
+       return nexpected_line;
+}
+
+static int check_line(const char *expected_line, int nexpected_line,
+                     int expected_line_len, const char *line)
+{
+       if (CHECK(nexpected_line == expected_line_len,
+                 "expected_line is too long"))
+               return -1;
+
+       if (strcmp(expected_line, line)) {
+               fprintf(stderr, "unexpected pprint output\n");
+               fprintf(stderr, "expected: %s", expected_line);
+               fprintf(stderr, "    read: %s", line);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+static int do_test_pprint(int test_num)
+{
+       const struct btf_raw_test *test = &pprint_test_template[test_num];
+       enum pprint_mapv_kind_t mapv_kind = test->mapv_kind;
+       struct bpf_create_map_attr create_attr = {};
+       bool ordered_map, lossless_map, percpu_map;
+       int err, ret, num_cpus, rounded_value_size;
+       unsigned int key, nr_read_elems;
+       int map_fd = -1, btf_fd = -1;
+       unsigned int raw_btf_size;
+       char expected_line[255];
+       FILE *pin_file = NULL;
+       char pin_path[255];
+       size_t line_len = 0;
+       char *line = NULL;
+       void *mapv = NULL;
+       uint8_t *raw_btf;
+       ssize_t nread;
+
+       fprintf(stderr, "%s(#%d)......", test->descr, test_num);
+       raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types,
+                                test->str_sec, test->str_sec_size,
+                                &raw_btf_size, NULL);
+
+       if (!raw_btf)
+               return -1;
+
+       *btf_log_buf = '\0';
+       btf_fd = bpf_load_btf(raw_btf, raw_btf_size,
+                             btf_log_buf, BTF_LOG_BUF_SIZE,
+                             args.always_log);
+       free(raw_btf);
+
+       if (CHECK(btf_fd == -1, "errno:%d", errno)) {
+               err = -1;
+               goto done;
+       }
+
+       create_attr.name = test->map_name;
+       create_attr.map_type = test->map_type;
+       create_attr.key_size = test->key_size;
+       create_attr.value_size = test->value_size;
+       create_attr.max_entries = test->max_entries;
+       create_attr.btf_fd = btf_fd;
+       create_attr.btf_key_type_id = test->key_type_id;
+       create_attr.btf_value_type_id = test->value_type_id;
+
+       map_fd = bpf_create_map_xattr(&create_attr);
+       if (CHECK(map_fd == -1, "errno:%d", errno)) {
+               err = -1;
+               goto done;
+       }
+
+       ret = snprintf(pin_path, sizeof(pin_path), "%s/%s",
+                      "/sys/fs/bpf", test->map_name);
+
+       if (CHECK(ret == sizeof(pin_path), "pin_path %s/%s is too long",
+                 "/sys/fs/bpf", test->map_name)) {
+               err = -1;
+               goto done;
+       }
+
+       err = bpf_obj_pin(map_fd, pin_path);
+       if (CHECK(err, "bpf_obj_pin(%s): errno:%d.", pin_path, errno))
+               goto done;
+
+       percpu_map = test->percpu_map;
+       num_cpus = percpu_map ? bpf_num_possible_cpus() : 1;
+       rounded_value_size = round_up(get_pprint_mapv_size(mapv_kind), 8);
+       mapv = calloc(num_cpus, rounded_value_size);
+       if (CHECK(!mapv, "mapv allocation failure")) {
+               err = -1;
+               goto done;
+       }
+
+       for (key = 0; key < test->max_entries; key++) {
+               set_pprint_mapv(mapv_kind, mapv, key, num_cpus, 
rounded_value_size);
+               bpf_map_update_elem(map_fd, &key, mapv, 0);
+       }
+
+       pin_file = fopen(pin_path, "r");
+       if (CHECK(!pin_file, "fopen(%s): errno:%d", pin_path, errno)) {
+               err = -1;
+               goto done;
+       }
+
+       /* Skip lines start with '#' */
+       while ((nread = getline(&line, &line_len, pin_file)) > 0 &&
+              *line == '#')
+               ;
+
+       if (CHECK(nread <= 0, "Unexpected EOF")) {
+               err = -1;
+               goto done;
+       }
+
+       nr_read_elems = 0;
+       ordered_map = test->ordered_map;
+       lossless_map = test->lossless_map;
+       do {
+               ssize_t nexpected_line;
+               unsigned int next_key;
+               void *cmapv;
+               int cpu;
+
+               next_key = ordered_map ? nr_read_elems : atoi(line);
+               set_pprint_mapv(mapv_kind, mapv, next_key, num_cpus, 
rounded_value_size);
+               cmapv = mapv;
+
+               for (cpu = 0; cpu < num_cpus; cpu++) {
+                       if (percpu_map) {
+                               /* for percpu map, the format looks like:
+                                * <key>: {
+                                *      cpu0: <value_on_cpu0>
+                                *      cpu1: <value_on_cpu1>
+                                *      ...
+                                *      cpun: <value_on_cpun>
+                                * }
+                                *
+                                * let us verify the line containing the key 
here.
+                                */
+                               if (cpu == 0) {
+                                       nexpected_line = snprintf(expected_line,
+                                                                 
sizeof(expected_line),
+                                                                 "%u: {\n",
+                                                                 next_key);
+
+                                       err = check_line(expected_line, 
nexpected_line,
+                                                        sizeof(expected_line), 
line);
+                                       if (err == -1)
+                                               goto done;
+                               }
+
+                               /* read value@cpu */
+                               nread = getline(&line, &line_len, pin_file);
+                               if (nread < 0)
+                                       break;
+                       }
+
+                       nexpected_line = get_pprint_expected_line(mapv_kind, 
expected_line,
+                                                                 
sizeof(expected_line),
+                                                                 percpu_map, 
next_key,
+                                                                 cpu, cmapv);
+                       err = check_line(expected_line, nexpected_line,
+                                        sizeof(expected_line), line);
+                       if (err == -1)
+                               goto done;
+
+                       cmapv = cmapv + rounded_value_size;
+               }
+
+               if (percpu_map) {
+                       /* skip the last bracket for the percpu map */
+                       nread = getline(&line, &line_len, pin_file);
+                       if (nread < 0)
+                               break;
+               }
+
+               nread = getline(&line, &line_len, pin_file);
+       } while (++nr_read_elems < test->max_entries && nread > 0);
+
+       if (lossless_map &&
+           CHECK(nr_read_elems < test->max_entries,
+                 "Unexpected EOF. nr_read_elems:%u test->max_entries:%u",
+                 nr_read_elems, test->max_entries)) {
+               err = -1;
+               goto done;
+       }
+
+       if (CHECK(nread > 0, "Unexpected extra pprint output: %s", line)) {
+               err = -1;
+               goto done;
+       }
+
+       err = 0;
+
+done:
+       if (mapv)
+               free(mapv);
+       if (!err)
+               fprintf(stderr, "OK");
+       if (*btf_log_buf && (err || args.always_log))
+               fprintf(stderr, "\n%s", btf_log_buf);
+       if (btf_fd != -1)
+               close(btf_fd);
+       if (map_fd != -1)
+               close(map_fd);
+       if (pin_file)
+               fclose(pin_file);
+       unlink(pin_path);
+       free(line);
+
+       return err;
+}
+
+static int test_pprint(void)
+{
+       unsigned int i;
+       int err = 0;
+
+       /* test various maps with the first test template */
+       for (i = 0; i < ARRAY_SIZE(pprint_tests_meta); i++) {
+               pprint_test_template[0].descr = pprint_tests_meta[i].descr;
+               pprint_test_template[0].map_type = 
pprint_tests_meta[i].map_type;
+               pprint_test_template[0].map_name = 
pprint_tests_meta[i].map_name;
+               pprint_test_template[0].ordered_map = 
pprint_tests_meta[i].ordered_map;
+               pprint_test_template[0].lossless_map = 
pprint_tests_meta[i].lossless_map;
+               pprint_test_template[0].percpu_map = 
pprint_tests_meta[i].percpu_map;
+
+               err |= count_result(do_test_pprint(0));
+       }
+
+       /* test rest test templates with the first map */
+       for (i = 1; i < ARRAY_SIZE(pprint_test_template); i++) {
+               pprint_test_template[i].descr = pprint_tests_meta[0].descr;
+               pprint_test_template[i].map_type = 
pprint_tests_meta[0].map_type;
+               pprint_test_template[i].map_name = 
pprint_tests_meta[0].map_name;
+               pprint_test_template[i].ordered_map = 
pprint_tests_meta[0].ordered_map;
+               pprint_test_template[i].lossless_map = 
pprint_tests_meta[0].lossless_map;
+               pprint_test_template[i].percpu_map = 
pprint_tests_meta[0].percpu_map;
+               err |= count_result(do_test_pprint(i));
+       }
+
+       return err;
+}
+
+static void usage(const char *cmd)
+{
+       fprintf(stderr, "Usage: %s [-l]\n", cmd);
+}
+
+static int parse_args(int argc, char **argv)
+{
+       const char *optstr = "hlpk:f:r:g:d:";
+       int opt;
+
+       while ((opt = getopt(argc, argv, optstr)) != -1) {
+               switch (opt) {
+               case 'l':
+                       args.always_log = true;
+                       break;
+               case 'h':
+                       usage(argv[0]);
+                       exit(0);
+               default:
+                       usage(argv[0]);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static void print_summary(void)
+{
+       fprintf(stderr, "PASS:%u SKIP:%u FAIL:%u\n",
+               pass_cnt - skip_cnt, skip_cnt, error_cnt);
+}
+
+int main(int argc, char **argv)
+{
+       int err = 0;
+
+       err = parse_args(argc, argv);
+       if (err)
+               return err;
+
+       if (args.always_log)
+               libbpf_set_print(__base_pr);
+
+       test_pprint();
+
+       print_summary();
+       return err;
+}
-- 
2.24.1

Reply via email to