]> granicus.if.org Git - strace/commitdiff
tests: refactor bpf test
authorEugene Syromyatnikov <evgsyr@gmail.com>
Wed, 21 Mar 2018 18:10:15 +0000 (19:10 +0100)
committerDmitry V. Levin <ldv@altlinux.org>
Wed, 4 Apr 2018 16:33:19 +0000 (16:33 +0000)
The aim of this change is to introduce an ability to perform multiple
checks for a specific bpf command.  In order to achieve so, all the
related data is stored in check descriptor, and test_bpf iterates over
it.  There are also some provisions made in regard to future changes
(specifically, the way bpf_attr_data union is defined).

* tests/bpf.c (print_bpf_attr): New function, a wrapper around
struct bpf_check.printer.
(test_bpf_): Rename to...
(test_bpf): ...this.  Replace arguments with struct bpf_check pointer.
Iterate over possible attribute variants. Account for changes in
attribute initialisation routine: provide a pointer to locally defined
union bpf_attr_data and perform memcpy afterwards. Initialise memory
from data each time before a bpf call.
(TEST_BPF, DEF_*, init_*, print_*): Remove.
(init_BPF_PROG_LOAD_attr, print_BPF_PROG_LOAD_attr,
init_BPF_OBJ_PIN_attr): New functions.
(license, pathname): New variables.
(BPF_MAP_CREATE_checks, BPF_MAP_LOOKUP_ELEM_checks,
BPF_MAP_UPDATE_ELEM_checks, BPF_MAP_DELETE_ELEM_checks,
BPF_MAP_GET_NEXT_KEY_checks, BPF_PROG_LOAD_checks, BPF_OBJ_PIN_checks,
BPF_PROG_ATTACH_checks, BPF_PROG_DETACH_checks,
BPF_PROG_TEST_RUN_checks, BPF_PROG_GET_NEXT_ID_checks,
BPF_PROG_GET_FD_BY_ID_checks, BPF_MAP_GET_FD_BY_ID_checks,
BPF_OBJ_GET_INFO_BY_FD_checks): New arrays.
(BPF_OBJ_GET_checks, BPF_MAP_GET_NEXT_ID_checks): New macros.
(CHK): New macro, a shorthand for initialising array of struct bpf_check.
(main): New static constant checks, iterate over checks and run test_bpf
with each element.

Co-Authored-by: Dmitry V. Levin <ldv@altlinux.org>
tests/bpf.c

index aa94e5894ffcf30730d2689e247ab6a07a0ba43e..21d1c49b820533dd606029c9cb2bbe002ed39c07 100644 (file)
@@ -78,6 +78,22 @@ union bpf_attr_data {
        char char_data[256];
 };
 
+struct bpf_attr_check {
+       union bpf_attr_data data;
+       size_t size;
+       const char *str;
+       void (*init_fn)(struct bpf_attr_check *check);
+       void (*print_fn)(const struct bpf_attr_check *check,
+                        unsigned long addr);
+};
+
+struct bpf_check {
+       kernel_ulong_t cmd;
+       const char *cmd_str;
+       const struct bpf_attr_check *checks;
+       size_t count;
+};
+
 static const kernel_ulong_t long_bits = (kernel_ulong_t) 0xfacefeed00000000ULL;
 static const char *errstr;
 static unsigned int sizeof_attr = sizeof(union bpf_attr_data);
@@ -103,77 +119,78 @@ sys_bpf(kernel_ulong_t cmd, kernel_ulong_t attr, kernel_ulong_t size)
 #endif
 
 static void
-test_bpf_(kernel_ulong_t cmd, const char *cmd_str,
-         unsigned int (*init_first)(const unsigned long eop),
-         void (*print_first)(const unsigned long eop),
-         unsigned int (*init_attr)(const unsigned long eop),
-         void (*print_attr)(const unsigned long eop))
+print_bpf_attr(const struct bpf_attr_check *check, unsigned long addr)
+{
+       if (check->print_fn)
+               check->print_fn(check, addr);
+       else
+               printf("%s", check->str);
+}
+
+static void
+test_bpf(const struct bpf_check *cmd_check)
 {
+       const struct bpf_attr_check *check = 0;
+       const union bpf_attr_data *data = 0;
+       unsigned int offset = 0;
+
        /* zero addr */
-       sys_bpf(cmd, 0, long_bits | sizeof(union bpf_attr_data));
+       sys_bpf(cmd_check->cmd, 0, long_bits | sizeof(union bpf_attr_data));
        printf("bpf(%s, NULL, %u) = %s\n",
-              cmd_str, sizeof_attr, errstr);
+              cmd_check->cmd_str, sizeof_attr, errstr);
 
        /* zero size */
        unsigned long addr = end_of_page - sizeof_attr;
-       sys_bpf(cmd, addr, long_bits);
+       sys_bpf(cmd_check->cmd, addr, long_bits);
        printf("bpf(%s, %#lx, 0) = %s\n",
-              cmd_str, addr, errstr);
-
-       /* the first field only */
-       unsigned int offset = init_first(end_of_page);
-       addr = end_of_page - offset;
-       sys_bpf(cmd, addr, offset);
-       printf("bpf(%s, {", cmd_str);
-       print_first(addr);
-       printf("}, %u) = %s\n", offset, errstr);
-
-       /* efault after the first field */
-       sys_bpf(cmd, addr, offset + 1);
-       printf("bpf(%s, %#lx, %u) = %s\n",
-              cmd_str, addr, offset + 1, errstr);
-
-       /* the relevant part of bpf_attr_data */
-       offset = init_attr(end_of_page);
-       addr = end_of_page - offset;
-       sys_bpf(cmd, addr, offset);
-       printf("bpf(%s, {", cmd_str);
-       print_attr(addr);
-       printf("}, %u) = %s\n", offset, errstr);
-
-       /* short read of the relevant part of bpf_attr_data */
-       sys_bpf(cmd, addr + 1, offset);
-       printf("bpf(%s, %#lx, %u) = %s\n",
-              cmd_str, addr + 1, offset, errstr);
+              cmd_check->cmd_str, addr, errstr);
+
+       for (size_t i = 0; i < cmd_check->count; i++) {
+               check = &cmd_check->checks[i];
+               if (check->init_fn)
+                       check->init_fn((struct bpf_attr_check *) check);
+               data = &check->data;
+               offset = check->size;
+
+               addr = end_of_page - offset;
+               memcpy((void *) addr, data, offset);
+
+               /* starting piece of bpf_attr_data */
+               sys_bpf(cmd_check->cmd, addr, offset);
+               printf("bpf(%s, {", cmd_check->cmd_str);
+               print_bpf_attr(check, addr);
+               printf("}, %u) = %s\n", offset, errstr);
+
+               /* short read of the starting piece */
+               sys_bpf(cmd_check->cmd, addr + 1, offset);
+               printf("bpf(%s, %#lx, %u) = %s\n",
+                      cmd_check->cmd_str, addr + 1, offset, errstr);
+       }
 
        if (offset < sizeof_attr) {
                /* short read of the whole bpf_attr_data */
-               memmove((void *) end_of_page - sizeof_attr + 1,
-                       (void *) addr, offset);
+               memcpy((void *) end_of_page - sizeof_attr + 1, data, offset);
                addr = end_of_page - sizeof_attr + 1;
-               memset((void *) addr + offset, 0,
-                      sizeof_attr - offset - 1);
-               sys_bpf(cmd, addr, sizeof_attr);
+               memset((void *) addr + offset, 0, sizeof_attr - offset - 1);
+               sys_bpf(cmd_check->cmd, addr, sizeof_attr);
                printf("bpf(%s, %#lx, %u) = %s\n",
-                      cmd_str, addr, sizeof_attr, errstr);
+                      cmd_check->cmd_str, addr, sizeof_attr, errstr);
 
                /* the whole bpf_attr_data */
-               memmove((void *) end_of_page - sizeof_attr,
-                       (void *) addr, offset);
+               memcpy((void *) end_of_page - sizeof_attr, data, offset);
                addr = end_of_page - sizeof_attr;
-               memset((void *) addr + offset, 0,
-                      sizeof_attr - offset);
-               sys_bpf(cmd, addr, sizeof_attr);
-               printf("bpf(%s, {", cmd_str);
-               print_attr(addr);
+               memset((void *) addr + offset, 0, sizeof_attr - offset);
+               sys_bpf(cmd_check->cmd, addr, sizeof_attr);
+               printf("bpf(%s, {", cmd_check->cmd_str);
+               print_bpf_attr(check, addr);
                printf("}, %u) = %s\n", sizeof_attr, errstr);
 
                /* non-zero bytes after the relevant part */
                fill_memory_ex((void *) addr + offset,
                               sizeof_attr - offset, '0', 10);
-               sys_bpf(cmd, addr, sizeof_attr);
-               printf("bpf(%s, {", cmd_str);
-               print_attr(addr);
+               sys_bpf(cmd_check->cmd, addr, sizeof_attr);
+               printf("bpf(%s, {", cmd_check->cmd_str);
+               print_bpf_attr(check, addr);
                printf(", ");
                print_extra_data((char *) addr, offset,
                                 sizeof_attr - offset);
@@ -181,532 +198,379 @@ test_bpf_(kernel_ulong_t cmd, const char *cmd_str,
        }
 
        /* short read of the whole page */
-       memmove((void *) end_of_page - page_size + 1,
-               (void *) addr, offset);
+       memcpy((void *) end_of_page - page_size + 1, data, offset);
        addr = end_of_page - page_size + 1;
-       memset((void *) addr + offset, 0,
-              page_size - offset - 1);
-       sys_bpf(cmd, addr, page_size);
+       memset((void *) addr + offset, 0, page_size - offset - 1);
+       sys_bpf(cmd_check->cmd, addr, page_size);
        printf("bpf(%s, %#lx, %u) = %s\n",
-              cmd_str, addr, page_size, errstr);
+              cmd_check->cmd_str, addr, page_size, errstr);
 
        /* the whole page */
-       memmove((void *) end_of_page - page_size,
-               (void *) addr, offset);
+       memcpy((void *) end_of_page - page_size, data, offset);
        addr = end_of_page - page_size;
        memset((void *) addr + offset, 0, page_size - offset);
-       sys_bpf(cmd, addr, page_size);
-       printf("bpf(%s, {", cmd_str);
-       print_attr(addr);
+       sys_bpf(cmd_check->cmd, addr, page_size);
+       printf("bpf(%s, {", cmd_check->cmd_str);
+       print_bpf_attr(check, addr);
        printf("}, %u) = %s\n", page_size, errstr);
 
        /* non-zero bytes after the whole bpf_attr_data */
        fill_memory_ex((void *) addr + offset,
                       page_size - offset, '0', 10);
-       sys_bpf(cmd, addr, page_size);
-       printf("bpf(%s, {", cmd_str);
-       print_attr(addr);
+       sys_bpf(cmd_check->cmd, addr, page_size);
+       printf("bpf(%s, {", cmd_check->cmd_str);
+       print_bpf_attr(check, addr);
        printf(", ");
        print_extra_data((char *) addr, offset,
                         page_size - offset);
        printf("}, %u) = %s\n", page_size, errstr);
 
        /* more than a page */
-       sys_bpf(cmd, addr, page_size + 1);
+       sys_bpf(cmd_check->cmd, addr, page_size + 1);
        printf("bpf(%s, %#lx, %u) = %s\n",
-              cmd_str, addr, page_size + 1, errstr);
-}
-
-#define TEST_BPF(cmd_)                                                 \
-       test_bpf_((cmd_), #cmd_,                                        \
-                 init_ ## cmd_ ## _first, print_ ## cmd_ ## _first,    \
-                 init_ ## cmd_ ## _attr, print_ ## cmd_ ## _attr)      \
-       /* End of TEST_BPF definition. */
-
-#define DEF_BPF_INIT_FIRST(cmd_, field_, value_)                       \
-       static unsigned int                                             \
-       init_ ## cmd_ ## _first(const unsigned long eop)                \
-       {                                                               \
-               static const struct cmd_ ## _struct attr = {            \
-                       .field_ = value_                                \
-               };                                                      \
-               static const unsigned int offset = sizeof(attr.field_); \
-               const unsigned long addr = eop - offset;                \
-                                                                       \
-               memcpy((void *) addr, &attr.field_, offset);            \
-               return offset;                                          \
-       }                                                               \
-       /* End of DEF_INIT_FIRST definition. */
-
-DEF_BPF_INIT_FIRST(BPF_MAP_CREATE, map_type, 2)
-
-static void
-print_BPF_MAP_CREATE_first(const unsigned long addr)
-{
-       printf("map_type=BPF_MAP_TYPE_ARRAY, key_size=0, value_size=0"
-              ", max_entries=0, map_flags=0, inner_map_fd=0");
-}
-
-static unsigned int
-init_BPF_MAP_CREATE_attr(const unsigned long eop)
-{
-       static const struct BPF_MAP_CREATE_struct attr = {
-               .map_type = 1,
-               .key_size = 4,
-               .value_size = 8,
-               .max_entries = 256,
-               .map_flags = 7,
-               .inner_map_fd = -1,
-               .numa_node = 42
-       };
-       static const unsigned int offset =
-               offsetofend(struct BPF_MAP_CREATE_struct, numa_node);
-       const unsigned long addr = eop - offset;
-
-       memcpy((void *) addr, &attr, offset);
-       return offset;
-}
-
-static void
-print_BPF_MAP_CREATE_attr(const unsigned long addr)
-{
-       printf("map_type=BPF_MAP_TYPE_HASH, key_size=4"
-              ", value_size=8, max_entries=256"
-              ", map_flags=BPF_F_NO_PREALLOC|BPF_F_NO_COMMON_LRU"
-              "|BPF_F_NUMA_NODE, inner_map_fd=-1, numa_node=42");
-}
-
-DEF_BPF_INIT_FIRST(BPF_MAP_LOOKUP_ELEM, map_fd, -1)
-
-static void
-print_BPF_MAP_LOOKUP_ELEM_first(const unsigned long addr)
-{
-       printf("map_fd=-1, key=0, value=0");
-}
-
-static unsigned int
-init_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long eop)
-{
-       static const struct BPF_MAP_LOOKUP_ELEM_struct attr = {
-               .map_fd = -1,
-               .key = 0xdeadbeef,
-               .value = 0xbadc0ded
-       };
-       static const unsigned int offset =
-               offsetofend(struct BPF_MAP_LOOKUP_ELEM_struct, value);
-       const unsigned long addr = eop - offset;
-
-       memcpy((void *) addr, &attr, offset);
-       return offset;
-}
-
-static void
-print_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long addr)
-{
-       printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded");
-}
-
-#define init_BPF_MAP_UPDATE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first
-
-static void
-print_BPF_MAP_UPDATE_ELEM_first(const unsigned long addr)
-{
-       printf("map_fd=-1, key=0, value=0, flags=BPF_ANY");
-}
-
-static unsigned int
-init_BPF_MAP_UPDATE_ELEM_attr(const unsigned long eop)
-{
-       static const struct BPF_MAP_UPDATE_ELEM_struct attr = {
-               .map_fd = -1,
-               .key = 0xdeadbeef,
-               .value = 0xbadc0ded,
-               .flags = 2
-       };
-       static const unsigned int offset =
-               offsetofend(struct BPF_MAP_UPDATE_ELEM_struct, flags);
-       const unsigned long addr = eop - offset;
-
-       memcpy((void *) addr, &attr, offset);
-       return offset;
-}
-
-static void
-print_BPF_MAP_UPDATE_ELEM_attr(const unsigned long addr)
-{
-       printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded, flags=BPF_EXIST");
-}
-
-#define init_BPF_MAP_DELETE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first
-
-static void
-print_BPF_MAP_DELETE_ELEM_first(const unsigned long addr)
-{
-       printf("map_fd=-1, key=0");
-}
-
-static unsigned int
-init_BPF_MAP_DELETE_ELEM_attr(const unsigned long eop)
-{
-       static const struct BPF_MAP_DELETE_ELEM_struct attr = {
-               .map_fd = -1,
-               .key = 0xdeadbeef
-       };
-       static const unsigned int offset =
-               offsetofend(struct BPF_MAP_DELETE_ELEM_struct, key);
-       const unsigned long addr = eop - offset;
-
-       memcpy((void *) addr, &attr, offset);
-       return offset;
-}
-
-static void
-print_BPF_MAP_DELETE_ELEM_attr(const unsigned long addr)
-{
-       printf("map_fd=-1, key=0xdeadbeef");
-}
-
-#define init_BPF_MAP_GET_NEXT_KEY_first init_BPF_MAP_LOOKUP_ELEM_first
-
-static void
-print_BPF_MAP_GET_NEXT_KEY_first(const unsigned long addr)
-{
-       printf("map_fd=-1, key=0, next_key=0");
-}
-
-static unsigned int
-init_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long eop)
-{
-       static const struct BPF_MAP_GET_NEXT_KEY_struct attr = {
-               .map_fd = -1,
-               .key = 0xdeadbeef,
-               .next_key = 0xbadc0ded
-       };
-       static const unsigned int offset =
-               offsetofend(struct BPF_MAP_GET_NEXT_KEY_struct, next_key);
-       const unsigned long addr = eop - offset;
-
-       memcpy((void *) addr, &attr, offset);
-       return offset;
-}
+              cmd_check->cmd_str, addr, page_size + 1, errstr);
+}
+
+static const struct bpf_attr_check BPF_MAP_CREATE_checks[] = {
+       {
+               .data = { .BPF_MAP_CREATE_data = { .map_type = 2 } },
+               .size = offsetofend(struct BPF_MAP_CREATE_struct, map_type),
+               .str = "map_type=BPF_MAP_TYPE_ARRAY, key_size=0, value_size=0"
+                      ", max_entries=0, map_flags=0, inner_map_fd=0"
+       },
+       {
+               .data = { .BPF_MAP_CREATE_data = {
+                       .map_type = 1,
+                       .key_size = 4,
+                       .value_size = 8,
+                       .max_entries = 256,
+                       .map_flags = 7,
+                       .inner_map_fd = -1,
+                       .numa_node = 42
+               } },
+               .size = offsetofend(struct BPF_MAP_CREATE_struct, numa_node),
+               .str = "map_type=BPF_MAP_TYPE_HASH, key_size=4"
+                      ", value_size=8, max_entries=256"
+                      ", map_flags=BPF_F_NO_PREALLOC|BPF_F_NO_COMMON_LRU"
+                      "|BPF_F_NUMA_NODE, inner_map_fd=-1, numa_node=42"
+       }
+};
 
-static void
-print_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long addr)
-{
-       printf("map_fd=-1, key=0xdeadbeef, next_key=0xbadc0ded");
-}
+static const struct bpf_attr_check BPF_MAP_LOOKUP_ELEM_checks[] = {
+       {
+               .data = { .BPF_MAP_LOOKUP_ELEM_data = { .map_fd = -1 } },
+               .size = offsetofend(struct BPF_MAP_LOOKUP_ELEM_struct, map_fd),
+               .str = "map_fd=-1, key=0, value=0"
+       },
+       {
+               .data = { .BPF_MAP_LOOKUP_ELEM_data = {
+                       .map_fd = -1,
+                       .key = 0xdeadbeef,
+                       .value = 0xbadc0ded
+               } },
+               .size = offsetofend(struct BPF_MAP_LOOKUP_ELEM_struct, value),
+               .str = "map_fd=-1, key=0xdeadbeef, value=0xbadc0ded"
+       }
+};
 
-DEF_BPF_INIT_FIRST(BPF_PROG_LOAD, prog_type, 1)
+static const struct bpf_attr_check BPF_MAP_UPDATE_ELEM_checks[] = {
+       {
+               .data = { .BPF_MAP_UPDATE_ELEM_data = { .map_fd = -1 } },
+               .size = offsetofend(struct BPF_MAP_UPDATE_ELEM_struct, map_fd),
+               .str = "map_fd=-1, key=0, value=0, flags=BPF_ANY"
+       },
+       {
+               .data = { .BPF_MAP_UPDATE_ELEM_data = {
+                       .map_fd = -1,
+                       .key = 0xdeadbeef,
+                       .value = 0xbadc0ded,
+                       .flags = 2
+               } },
+               .size = offsetofend(struct BPF_MAP_UPDATE_ELEM_struct, flags),
+               .str = "map_fd=-1, key=0xdeadbeef, value=0xbadc0ded"
+                      ", flags=BPF_EXIST"
+       }
+};
 
-static void
-print_BPF_PROG_LOAD_first(const unsigned long addr)
-{
+static const struct bpf_attr_check BPF_MAP_DELETE_ELEM_checks[] = {
+       {
+               .data = { .BPF_MAP_DELETE_ELEM_data = { .map_fd = -1 } },
+               .size = offsetofend(struct BPF_MAP_DELETE_ELEM_struct, map_fd),
+               .str = "map_fd=-1, key=0"
+       },
+       {
+               .data = { .BPF_MAP_DELETE_ELEM_data = {
+                       .map_fd = -1,
+                       .key = 0xdeadbeef
+               } },
+               .size = offsetofend(struct BPF_MAP_DELETE_ELEM_struct, key),
+               .str = "map_fd=-1, key=0xdeadbeef"
+       }
+};
 
-       printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=0, insns=0"
-              ", license=NULL");
-}
+static const struct bpf_attr_check BPF_MAP_GET_NEXT_KEY_checks[] = {
+       {
+               .data = { .BPF_MAP_GET_NEXT_KEY_data = { .map_fd = -1 } },
+               .size = offsetofend(struct BPF_MAP_GET_NEXT_KEY_struct, map_fd),
+               .str = "map_fd=-1, key=0, next_key=0"
+       },
+       {
+               .data = { .BPF_MAP_GET_NEXT_KEY_data = {
+                       .map_fd = -1,
+                       .key = 0xdeadbeef,
+                       .next_key = 0xbadc0ded
+               } },
+               .size = offsetofend(struct BPF_MAP_GET_NEXT_KEY_struct, next_key),
+               .str = "map_fd=-1, key=0xdeadbeef, next_key=0xbadc0ded"
+       }
+};
 
 static const struct bpf_insn insns[] = {
        { .code = 0x95 }
 };
+static const char license[] = "GPL";
 static char log_buf[4096];
+static const char pathname[] = "/sys/fs/bpf/foo/bar";
 
-static unsigned int
-init_BPF_PROG_LOAD_attr(const unsigned long eop)
+static void
+init_BPF_PROG_LOAD_attr(struct bpf_attr_check *check)
 {
-       const struct BPF_PROG_LOAD_struct attr = {
-               .prog_type = 1,
-               .insn_cnt = ARRAY_SIZE(insns),
-               .insns = (uintptr_t) insns,
-               .license = (uintptr_t) "GPL",
-               .log_level = 42,
-               .log_size = sizeof(log_buf),
-               .log_buf = (uintptr_t) log_buf,
-               .kern_version = 0xcafef00d,
-               .prog_flags = 1
-       };
-       static const unsigned int offset =
-               offsetofend(struct BPF_PROG_LOAD_struct, prog_flags);
-       const unsigned long addr = eop - offset;
-
-       memcpy((void *) addr, &attr, offset);
-       return offset;
+       struct BPF_PROG_LOAD_struct *attr = &check->data.BPF_PROG_LOAD_data;
+       attr->insns = (uintptr_t) insns;
+       attr->license = (uintptr_t) license;
+       attr->log_buf = (uintptr_t) log_buf;
 }
 
 static void
-print_BPF_PROG_LOAD_attr(const unsigned long addr)
+print_BPF_PROG_LOAD_attr(const struct bpf_attr_check *check, unsigned long addr)
 {
        printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=%u, insns=%p"
-              ", license=\"GPL\", log_level=42, log_size=4096, log_buf=%p"
+              ", license=\"%s\", log_level=42, log_size=4096, log_buf=%p"
               ", kern_version=KERNEL_VERSION(51966, 240, 13)"
               ", prog_flags=BPF_F_STRICT_ALIGNMENT",
               (unsigned int) ARRAY_SIZE(insns), insns,
-              log_buf);
-}
-
-DEF_BPF_INIT_FIRST(BPF_OBJ_PIN, pathname, 0)
-
-static void
-print_BPF_OBJ_PIN_first(const unsigned long addr)
-{
-
-       printf("pathname=NULL, bpf_fd=0");
-}
-
-static unsigned int
-init_BPF_OBJ_PIN_attr(const unsigned long eop)
-{
-       const struct BPF_OBJ_PIN_struct attr = {
-               .pathname = (uintptr_t) "/sys/fs/bpf/foo/bar",
-               .bpf_fd = -1
-       };
-       static const unsigned int offset =
-               offsetofend(struct BPF_OBJ_PIN_struct, bpf_fd);
-       const unsigned long addr = eop - offset;
-
-       memcpy((void *) addr, &attr, offset);
-       return offset;
-}
-
-static void
-print_BPF_OBJ_PIN_attr(const unsigned long addr)
-{
-       printf("pathname=\"/sys/fs/bpf/foo/bar\", bpf_fd=-1");
-}
-
-#define init_BPF_OBJ_GET_first init_BPF_OBJ_PIN_first
-#define print_BPF_OBJ_GET_first print_BPF_OBJ_PIN_first
-#define init_BPF_OBJ_GET_attr init_BPF_OBJ_PIN_attr
-#define print_BPF_OBJ_GET_attr print_BPF_OBJ_PIN_attr
-
-DEF_BPF_INIT_FIRST(BPF_PROG_ATTACH, target_fd, -1)
-
-static void
-print_BPF_PROG_ATTACH_first(const unsigned long addr)
-{
-       printf("target_fd=-1, attach_bpf_fd=0"
-              ", attach_type=BPF_CGROUP_INET_INGRESS, attach_flags=0");
-}
-
-static unsigned int
-init_BPF_PROG_ATTACH_attr(const unsigned long eop)
-{
-       static const struct BPF_PROG_ATTACH_struct attr = {
-               .target_fd = -1,
-               .attach_bpf_fd = -2,
-               .attach_type = 2,
-               .attach_flags = 1
-       };
-       static const unsigned int offset =
-               offsetofend(struct BPF_PROG_ATTACH_struct, attach_flags);
-       const unsigned long addr = eop - offset;
-
-       memcpy((void *) addr, &attr, offset);
-       return offset;
-}
-
-static void
-print_BPF_PROG_ATTACH_attr(const unsigned long addr)
-{
-       printf("target_fd=-1, attach_bpf_fd=-2"
-              ", attach_type=BPF_CGROUP_INET_SOCK_CREATE"
-              ", attach_flags=BPF_F_ALLOW_OVERRIDE");
-}
-
-#define init_BPF_PROG_DETACH_first init_BPF_PROG_ATTACH_first
-
-static unsigned int
-init_BPF_PROG_DETACH_attr(const unsigned long eop)
-{
-       static const struct BPF_PROG_DETACH_struct attr = {
-               .target_fd = -1,
-               .attach_type = 2
-       };
-       static const unsigned int offset =
-               offsetofend(struct BPF_PROG_DETACH_struct, attach_type);
-       const unsigned long addr = eop - offset;
-
-       memcpy((void *) addr, &attr, offset);
-       return offset;
-}
-
-
-static void
-print_BPF_PROG_DETACH_first(const unsigned long addr)
-{
-       printf("target_fd=-1, attach_type=BPF_CGROUP_INET_INGRESS");
-}
-
-static void
-print_BPF_PROG_DETACH_attr(const unsigned long addr)
-{
-       printf("target_fd=-1, attach_type=BPF_CGROUP_INET_SOCK_CREATE");
-}
-
-DEF_BPF_INIT_FIRST(BPF_PROG_TEST_RUN, prog_fd, -1)
-
-static void
-print_BPF_PROG_TEST_RUN_first(const unsigned long addr)
-{
-       printf("test={prog_fd=-1, retval=0, data_size_in=0, data_size_out=0"
-              ", data_in=0, data_out=0, repeat=0, duration=0}");
-}
-
-static const struct BPF_PROG_TEST_RUN_struct sample_BPF_PROG_TEST_RUN_attr = {
-       .prog_fd = -1,
-       .retval = 0xfac1fed2,
-       .data_size_in = 0xfac3fed4,
-       .data_size_out = 0xfac5fed6,
-       .data_in = (uint64_t) 0xfacef11dbadc2ded,
-       .data_out = (uint64_t) 0xfacef33dbadc4ded,
-       .repeat = 0xfac7fed8,
-       .duration = 0xfac9feda
+              license, log_buf);
+}
+
+static struct bpf_attr_check BPF_PROG_LOAD_checks[] = {
+       {
+               .data = { .BPF_PROG_LOAD_data = { .prog_type = 1 } },
+               .size = offsetofend(struct BPF_PROG_LOAD_struct, prog_type),
+               .str = "prog_type=BPF_PROG_TYPE_SOCKET_FILTER"
+                      ", insn_cnt=0, insns=0, license=NULL"
+       },
+       {
+               .data = { .BPF_PROG_LOAD_data = {
+                       .prog_type = 1,
+                       .insn_cnt = ARRAY_SIZE(insns),
+                       .log_level = 42,
+                       .log_size = sizeof(log_buf),
+                       .kern_version = 0xcafef00d,
+                       .prog_flags = 1
+               } },
+               .size = offsetofend(struct BPF_PROG_LOAD_struct, prog_flags),
+               .init_fn = init_BPF_PROG_LOAD_attr,
+               .print_fn = print_BPF_PROG_LOAD_attr
+       }
 };
-static unsigned int
-init_BPF_PROG_TEST_RUN_attr(const unsigned long eop)
-{
-       static const unsigned int offset =
-               offsetofend(struct BPF_PROG_TEST_RUN_struct, duration);
-       const unsigned long addr = eop - offset;
-
-       memcpy((void *) addr, &sample_BPF_PROG_TEST_RUN_attr, offset);
-       return offset;
-}
-
-static void
-print_BPF_PROG_TEST_RUN_attr(const unsigned long addr)
-{
-       PRINT_FIELD_D("test={", sample_BPF_PROG_TEST_RUN_attr, prog_fd);
-       PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr, retval);
-       PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr, data_size_in);
-       PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr, data_size_out);
-       PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr, data_in);
-       PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr, data_out);
-       PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr, repeat);
-       PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr, duration);
-       printf("}");
-}
-
-DEF_BPF_INIT_FIRST(BPF_PROG_GET_NEXT_ID, start_id, 0xdeadbeef)
 
 static void
-print_BPF_PROG_GET_NEXT_ID_first(const unsigned long addr)
-{
-       printf("start_id=%u, next_id=0", 0xdeadbeef);
-}
-
-static unsigned int
-init_BPF_PROG_GET_NEXT_ID_attr(const unsigned long eop)
-{
-       static const struct BPF_PROG_GET_NEXT_ID_struct attr = {
-               .start_id = 0xbadc0ded,
-               .next_id = 0xcafef00d
-       };
-       static const unsigned int offset =
-               offsetofend(struct BPF_PROG_GET_NEXT_ID_struct, next_id);
-       const unsigned long addr = eop - offset;
-
-       memcpy((void *) addr, &attr, offset);
-       return offset;
-}
-
-static void
-print_BPF_PROG_GET_NEXT_ID_attr(const unsigned long addr)
-{
-       printf("start_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d);
-}
-
-#define init_BPF_MAP_GET_NEXT_ID_first init_BPF_PROG_GET_NEXT_ID_first
-#define print_BPF_MAP_GET_NEXT_ID_first print_BPF_PROG_GET_NEXT_ID_first
-#define init_BPF_MAP_GET_NEXT_ID_attr init_BPF_PROG_GET_NEXT_ID_attr
-#define print_BPF_MAP_GET_NEXT_ID_attr print_BPF_PROG_GET_NEXT_ID_attr
-
-#define init_BPF_PROG_GET_FD_BY_ID_first init_BPF_PROG_GET_NEXT_ID_first
-#define init_BPF_PROG_GET_FD_BY_ID_attr init_BPF_PROG_GET_NEXT_ID_attr
-
-static void
-print_BPF_PROG_GET_FD_BY_ID_first(const unsigned long addr)
-{
-       printf("prog_id=%u, next_id=0", 0xdeadbeef);
-}
+init_BPF_OBJ_PIN_attr(struct bpf_attr_check *check)
+{
+       struct BPF_OBJ_PIN_struct *attr = &check->data.BPF_OBJ_PIN_data;
+       attr->pathname = (uintptr_t) pathname;
+}
+
+static struct bpf_attr_check BPF_OBJ_PIN_checks[] = {
+       {
+               .data = { .BPF_OBJ_PIN_data = { .pathname = 0 } },
+               .size = offsetofend(struct BPF_OBJ_PIN_struct, pathname),
+               .str = "pathname=NULL, bpf_fd=0"
+       },
+       {
+               .data = { .BPF_OBJ_PIN_data = { .bpf_fd = -1 } },
+               .size = offsetofend(struct BPF_OBJ_PIN_struct, bpf_fd),
+               .init_fn = init_BPF_OBJ_PIN_attr,
+               .str = "pathname=\"/sys/fs/bpf/foo/bar\", bpf_fd=-1"
+       }
+};
 
-static void
-print_BPF_PROG_GET_FD_BY_ID_attr(const unsigned long addr)
-{
-       printf("prog_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d);
-}
+#define BPF_OBJ_GET_checks BPF_OBJ_PIN_checks
+
+static const struct bpf_attr_check BPF_PROG_ATTACH_checks[] = {
+       {
+               .data = { .BPF_PROG_ATTACH_data = { .target_fd = -1 } },
+               .size = offsetofend(struct BPF_PROG_ATTACH_struct, target_fd),
+               .str = "target_fd=-1, attach_bpf_fd=0"
+                      ", attach_type=BPF_CGROUP_INET_INGRESS, attach_flags=0"
+       },
+       {
+               .data = { .BPF_PROG_ATTACH_data = {
+                       .target_fd = -1,
+                       .attach_bpf_fd = -2,
+                       .attach_type = 2,
+                       .attach_flags = 1
+               } },
+               .size = offsetofend(struct BPF_PROG_ATTACH_struct, attach_flags),
+               .str = "target_fd=-1, attach_bpf_fd=-2"
+                      ", attach_type=BPF_CGROUP_INET_SOCK_CREATE"
+                      ", attach_flags=BPF_F_ALLOW_OVERRIDE"
+       }
+};
 
-#define init_BPF_MAP_GET_FD_BY_ID_first init_BPF_PROG_GET_NEXT_ID_first
-#define init_BPF_MAP_GET_FD_BY_ID_attr init_BPF_PROG_GET_NEXT_ID_attr
 
-static void
-print_BPF_MAP_GET_FD_BY_ID_first(const unsigned long addr)
-{
-       printf("map_id=%u, next_id=0", 0xdeadbeef);
-}
+static const struct bpf_attr_check BPF_PROG_DETACH_checks[] = {
+       {
+               .data = { .BPF_PROG_DETACH_data = { .target_fd = -1 } },
+               .size = offsetofend(struct BPF_PROG_DETACH_struct, target_fd),
+               .str = "target_fd=-1, attach_type=BPF_CGROUP_INET_INGRESS"
+       },
+       {
+               .data = { .BPF_PROG_DETACH_data = {
+                       .target_fd = -1,
+                       .attach_type = 2
+               } },
+               .size = offsetofend(struct BPF_PROG_DETACH_struct, attach_type),
+               .str = "target_fd=-1, attach_type=BPF_CGROUP_INET_SOCK_CREATE"
+       }
+};
 
-static void
-print_BPF_MAP_GET_FD_BY_ID_attr(const unsigned long addr)
-{
-       printf("map_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d);
-}
+static const struct bpf_attr_check BPF_PROG_TEST_RUN_checks[] = {
+       {
+               .data = { .BPF_PROG_TEST_RUN_data = { .prog_fd = -1 } },
+               .size = offsetofend(struct BPF_PROG_TEST_RUN_struct, prog_fd),
+               .str = "test={prog_fd=-1, retval=0, data_size_in=0"
+                      ", data_size_out=0, data_in=0, data_out=0"
+                      ", repeat=0, duration=0}"
+       },
+       {
+               .data = { .BPF_PROG_TEST_RUN_data = {
+                       .prog_fd = -1,
+                       .retval = 0xfac1fed2,
+                       .data_size_in = 0xfac3fed4,
+                       .data_size_out = 0xfac5fed6,
+                       .data_in = (uint64_t) 0xfacef11dbadc2dedULL,
+                       .data_out = (uint64_t) 0xfacef33dbadc4dedULL,
+                       .repeat = 0xfac7fed8,
+                       .duration = 0xfac9feda
+               } },
+               .size = offsetofend(struct BPF_PROG_TEST_RUN_struct, duration),
+               .str = "test={prog_fd=-1, retval=4207017682"
+                      ", data_size_in=4207148756, data_size_out=4207279830"
+                      ", data_in=0xfacef11dbadc2ded"
+                      ", data_out=0xfacef33dbadc4ded"
+                      ", repeat=4207410904, duration=4207541978}"
+       }
+};
 
-DEF_BPF_INIT_FIRST(BPF_OBJ_GET_INFO_BY_FD, bpf_fd, -1)
+static const struct bpf_attr_check BPF_PROG_GET_NEXT_ID_checks[] = {
+       {
+               .data = { .BPF_PROG_GET_NEXT_ID_data = {
+                       .start_id = 0xdeadbeef
+               } },
+               .size = offsetofend(struct BPF_PROG_GET_NEXT_ID_struct, start_id),
+               .str = "start_id=3735928559, next_id=0"
+       },
+       {
+               .data = { .BPF_PROG_GET_NEXT_ID_data = {
+                       .start_id = 0xbadc0ded,
+                       .next_id = 0xcafef00d
+               } },
+               .size = offsetofend(struct BPF_PROG_GET_NEXT_ID_struct, next_id),
+               .str = "start_id=3134983661, next_id=3405705229"
+       }
+};
 
-static void
-print_BPF_OBJ_GET_INFO_BY_FD_first(const unsigned long addr)
-{
-       printf("info={bpf_fd=-1, info_len=0, info=0}");
-}
+#define BPF_MAP_GET_NEXT_ID_checks BPF_PROG_GET_NEXT_ID_checks
+
+static const struct bpf_attr_check BPF_PROG_GET_FD_BY_ID_checks[] = {
+       {
+               .data = { .BPF_PROG_GET_FD_BY_ID_data = {
+                       .prog_id = 0xdeadbeef
+               } },
+               .size = offsetofend(struct BPF_PROG_GET_FD_BY_ID_struct, prog_id),
+               .str = "prog_id=3735928559, next_id=0"
+       },
+       {
+               .data = { .BPF_PROG_GET_FD_BY_ID_data = {
+                       .prog_id = 0xbadc0ded,
+                       .next_id = 0xcafef00d
+               } },
+               .size = offsetofend(struct BPF_PROG_GET_FD_BY_ID_struct, next_id),
+               .str = "prog_id=3134983661, next_id=3405705229"
+       }
+};
 
-static const struct BPF_OBJ_GET_INFO_BY_FD_struct
-       sample_BPF_OBJ_GET_INFO_BY_FD_attr = {
-               .bpf_fd = -1,
-               .info_len = 0xdeadbeef,
-               .info = (uint64_t) 0xfacefeedbadc0ded
-       };
-static unsigned int
-init_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long eop)
-{
-       static const unsigned int offset =
-               offsetofend(struct BPF_OBJ_GET_INFO_BY_FD_struct, info);
-       const unsigned long addr = eop - offset;
+static const struct bpf_attr_check BPF_MAP_GET_FD_BY_ID_checks[] = {
+       {
+               .data = { .BPF_MAP_GET_FD_BY_ID_data = {
+                       .map_id = 0xdeadbeef
+               } },
+               .size = offsetofend(struct BPF_MAP_GET_FD_BY_ID_struct, map_id),
+               .str = "map_id=3735928559, next_id=0"
+       },
+       {
+               .data = { .BPF_MAP_GET_FD_BY_ID_data = {
+                       .map_id = 0xbadc0ded,
+                       .next_id = 0xcafef00d
+               } },
+               .size = offsetofend(struct BPF_MAP_GET_FD_BY_ID_struct, next_id),
+               .str = "map_id=3134983661, next_id=3405705229"
+       }
+};
 
-       memcpy((void *) addr, &sample_BPF_OBJ_GET_INFO_BY_FD_attr, offset);
-       return offset;
-}
+static const struct bpf_attr_check BPF_OBJ_GET_INFO_BY_FD_checks[] = {
+       {
+               .data = { .BPF_OBJ_GET_INFO_BY_FD_data = { .bpf_fd = -1 } },
+               .size = offsetofend(struct BPF_OBJ_GET_INFO_BY_FD_struct, bpf_fd),
+               .str = "info={bpf_fd=-1, info_len=0, info=0}"
+       },
+       {
+               .data = { .BPF_OBJ_GET_INFO_BY_FD_data = {
+                       .bpf_fd = -1,
+                       .info_len = 0xdeadbeef,
+                       .info = (uint64_t) 0xfacefeedbadc0dedULL
+               } },
+               .size = offsetofend(struct BPF_OBJ_GET_INFO_BY_FD_struct, info),
+               .str = "info={bpf_fd=-1, info_len=3735928559"
+                      ", info=0xfacefeedbadc0ded}"
+       }
+};
 
-static void
-print_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long addr)
-{
-       PRINT_FIELD_D("info={", sample_BPF_OBJ_GET_INFO_BY_FD_attr, bpf_fd);
-       PRINT_FIELD_U(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr, info_len);
-       PRINT_FIELD_X(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr, info);
-       printf("}");
-}
+#define CHK(cmd_) \
+       { \
+               cmd_, #cmd_, \
+               cmd_##_checks, ARRAY_SIZE(cmd_##_checks), \
+       } \
+       /* End of CHK definition */
 
 int
 main(void)
 {
+       static const struct bpf_check checks[] = {
+               CHK(BPF_MAP_CREATE),
+               CHK(BPF_MAP_LOOKUP_ELEM),
+               CHK(BPF_MAP_UPDATE_ELEM),
+               CHK(BPF_MAP_DELETE_ELEM),
+               CHK(BPF_MAP_GET_NEXT_KEY),
+               CHK(BPF_PROG_LOAD),
+               CHK(BPF_OBJ_PIN),
+               CHK(BPF_OBJ_GET),
+               CHK(BPF_PROG_ATTACH),
+               CHK(BPF_PROG_DETACH),
+               CHK(BPF_PROG_TEST_RUN),
+               CHK(BPF_PROG_GET_NEXT_ID),
+               CHK(BPF_MAP_GET_NEXT_ID),
+               CHK(BPF_PROG_GET_FD_BY_ID),
+               CHK(BPF_MAP_GET_FD_BY_ID),
+               CHK(BPF_OBJ_GET_INFO_BY_FD),
+       };
+
        page_size = get_page_size();
        end_of_page = (unsigned long) tail_alloc(1) + 1;
 
-       TEST_BPF(BPF_MAP_CREATE);
-       TEST_BPF(BPF_MAP_LOOKUP_ELEM);
-       TEST_BPF(BPF_MAP_UPDATE_ELEM);
-       TEST_BPF(BPF_MAP_DELETE_ELEM);
-       TEST_BPF(BPF_MAP_GET_NEXT_KEY);
-       TEST_BPF(BPF_PROG_LOAD);
-       TEST_BPF(BPF_OBJ_PIN);
-       TEST_BPF(BPF_OBJ_GET);
-       TEST_BPF(BPF_PROG_ATTACH);
-       TEST_BPF(BPF_PROG_DETACH);
-       TEST_BPF(BPF_PROG_TEST_RUN);
-       TEST_BPF(BPF_PROG_GET_NEXT_ID);
-       TEST_BPF(BPF_MAP_GET_NEXT_ID);
-       TEST_BPF(BPF_PROG_GET_FD_BY_ID);
-       TEST_BPF(BPF_MAP_GET_FD_BY_ID);
-       TEST_BPF(BPF_OBJ_GET_INFO_BY_FD);
+       for (size_t i = 0; i < ARRAY_SIZE(checks); i++)
+               test_bpf(checks + i);
 
        sys_bpf(0xfacefeed, 0, (kernel_ulong_t) 0xfacefeedbadc0dedULL);
        printf("bpf(0xfacefeed /* BPF_??? */, NULL, %u) = %s\n",