selftests: bpf: add tests for dead code removal
authorJakub Kicinski <jakub.kicinski@netronome.com>
Wed, 23 Jan 2019 06:45:22 +0000 (22:45 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Thu, 24 Jan 2019 01:35:32 +0000 (17:35 -0800)
Add tests for newly added dead code elimination.  Both verifier
and BTF tests are added.  BTF test infrastructure has to be
extended to be able to account for line info which is eliminated
during dead code removal.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/testing/selftests/bpf/test_btf.c
tools/testing/selftests/bpf/test_verifier.c

index bfd92182533b1eaa3618c3184aa92e50e8ab2258..179f1d8ec5bfef6e2334669438a4b1193772d187 100644 (file)
@@ -4293,6 +4293,10 @@ static struct prog_info_raw_test {
        __u32 line_info_rec_size;
        __u32 nr_jited_ksyms;
        bool expected_prog_load_failure;
+       __u32 dead_code_cnt;
+       __u32 dead_code_mask;
+       __u32 dead_func_cnt;
+       __u32 dead_func_mask;
 } info_raw_tests[] = {
 {
        .descr = "func_type (main func + one sub)",
@@ -4719,6 +4723,369 @@ static struct prog_info_raw_test {
        .expected_prog_load_failure = true,
 },
 
+{
+       .descr = "line_info (dead start)",
+       .raw_types = {
+               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),   /* [1] */
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0int\0/* dead jmp */\0int a=1;\0int b=2;\0return a + b;\0return a + b;"),
+       .insns = {
+               BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+               BPF_MOV64_IMM(BPF_REG_0, 1),
+               BPF_MOV64_IMM(BPF_REG_1, 2),
+               BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+               BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+       .func_info_cnt = 0,
+       .line_info = {
+               BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(1, 0, NAME_TBD, 2, 9),
+               BPF_LINE_INFO_ENC(2, 0, NAME_TBD, 3, 8),
+               BPF_LINE_INFO_ENC(3, 0, NAME_TBD, 4, 7),
+               BPF_LINE_INFO_ENC(4, 0, NAME_TBD, 5, 6),
+               BTF_END_RAW,
+       },
+       .line_info_rec_size = sizeof(struct bpf_line_info),
+       .nr_jited_ksyms = 1,
+       .dead_code_cnt = 1,
+       .dead_code_mask = 0x01,
+},
+
+{
+       .descr = "line_info (dead end)",
+       .raw_types = {
+               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),   /* [1] */
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0int\0int a=1;\0int b=2;\0return a + b;\0/* dead jmp */\0return a + b;\0/* dead exit */"),
+       .insns = {
+               BPF_MOV64_IMM(BPF_REG_0, 1),
+               BPF_MOV64_IMM(BPF_REG_1, 2),
+               BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+               BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 10, 1),
+               BPF_EXIT_INSN(),
+               BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+       .func_info_cnt = 0,
+       .line_info = {
+               BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 12),
+               BPF_LINE_INFO_ENC(1, 0, NAME_TBD, 2, 11),
+               BPF_LINE_INFO_ENC(2, 0, NAME_TBD, 3, 10),
+               BPF_LINE_INFO_ENC(3, 0, NAME_TBD, 4, 9),
+               BPF_LINE_INFO_ENC(4, 0, NAME_TBD, 5, 8),
+               BPF_LINE_INFO_ENC(5, 0, NAME_TBD, 6, 7),
+               BTF_END_RAW,
+       },
+       .line_info_rec_size = sizeof(struct bpf_line_info),
+       .nr_jited_ksyms = 1,
+       .dead_code_cnt = 2,
+       .dead_code_mask = 0x28,
+},
+
+{
+       .descr = "line_info (dead code + subprog + func_info)",
+       .raw_types = {
+               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),   /* [1] */
+               BTF_FUNC_PROTO_ENC(1, 1),                       /* [2] */
+                       BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
+               BTF_FUNC_ENC(NAME_TBD, 2),                      /* [3] */
+               BTF_FUNC_ENC(NAME_TBD, 2),                      /* [4] */
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0int\0x\0sub\0main\0int a=1+1;\0/* dead jmp */"
+                   "\0/* dead */\0/* dead */\0/* dead */\0/* dead */"
+                   "\0/* dead */\0/* dead */\0/* dead */\0/* dead */"
+                   "\0return func(a);\0b+=1;\0return b;"),
+       .insns = {
+               BPF_MOV64_IMM(BPF_REG_2, 1),
+               BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 1),
+               BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+               BPF_JMP_IMM(BPF_JGE, BPF_REG_2, 0, 8),
+               BPF_MOV64_IMM(BPF_REG_2, 1),
+               BPF_MOV64_IMM(BPF_REG_2, 1),
+               BPF_MOV64_IMM(BPF_REG_2, 1),
+               BPF_MOV64_IMM(BPF_REG_2, 1),
+               BPF_MOV64_IMM(BPF_REG_2, 1),
+               BPF_MOV64_IMM(BPF_REG_2, 1),
+               BPF_MOV64_IMM(BPF_REG_2, 1),
+               BPF_MOV64_IMM(BPF_REG_2, 1),
+               BPF_CALL_REL(1),
+               BPF_EXIT_INSN(),
+               BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
+               BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1),
+               BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+       .func_info_cnt = 2,
+       .func_info_rec_size = 8,
+       .func_info = { {0, 4}, {14, 3} },
+       .line_info = {
+               BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(3, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(4, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(5, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(6, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(7, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(8, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(9, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(10, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(11, 0, NAME_TBD, 2, 9),
+               BPF_LINE_INFO_ENC(12, 0, NAME_TBD, 2, 9),
+               BPF_LINE_INFO_ENC(14, 0, NAME_TBD, 3, 8),
+               BPF_LINE_INFO_ENC(16, 0, NAME_TBD, 4, 7),
+               BTF_END_RAW,
+       },
+       .line_info_rec_size = sizeof(struct bpf_line_info),
+       .nr_jited_ksyms = 2,
+       .dead_code_cnt = 9,
+       .dead_code_mask = 0x3fe,
+},
+
+{
+       .descr = "line_info (dead subprog)",
+       .raw_types = {
+               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),   /* [1] */
+               BTF_FUNC_PROTO_ENC(1, 1),                       /* [2] */
+                       BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
+               BTF_FUNC_ENC(NAME_TBD, 2),                      /* [3] */
+               BTF_FUNC_ENC(NAME_TBD, 2),                      /* [4] */
+               BTF_FUNC_ENC(NAME_TBD, 2),                      /* [5] */
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0int\0x\0dead\0main\0func\0int a=1+1;\0/* live call */"
+                   "\0return 0;\0return 0;\0/* dead */\0/* dead */"
+                   "\0/* dead */\0return bla + 1;\0return bla + 1;"
+                   "\0return bla + 1;\0return func(a);\0b+=1;\0return b;"),
+       .insns = {
+               BPF_MOV64_IMM(BPF_REG_2, 1),
+               BPF_JMP_IMM(BPF_JGE, BPF_REG_2, 0, 1),
+               BPF_CALL_REL(3),
+               BPF_CALL_REL(5),
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_CALL_REL(1),
+               BPF_EXIT_INSN(),
+               BPF_MOV64_REG(BPF_REG_0, 2),
+               BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1),
+               BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+       .func_info_cnt = 3,
+       .func_info_rec_size = 8,
+               .func_info = { {0, 4}, {6, 3}, {9, 5} },
+       .line_info = {
+               BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(3, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(4, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(5, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(6, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(7, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(8, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(9, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(10, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(11, 0, NAME_TBD, 2, 9),
+               BTF_END_RAW,
+       },
+       .line_info_rec_size = sizeof(struct bpf_line_info),
+       .nr_jited_ksyms = 2,
+       .dead_code_cnt = 3,
+       .dead_code_mask = 0x70,
+       .dead_func_cnt = 1,
+       .dead_func_mask = 0x2,
+},
+
+{
+       .descr = "line_info (dead last subprog)",
+       .raw_types = {
+               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),   /* [1] */
+               BTF_FUNC_PROTO_ENC(1, 1),                       /* [2] */
+                       BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
+               BTF_FUNC_ENC(NAME_TBD, 2),                      /* [3] */
+               BTF_FUNC_ENC(NAME_TBD, 2),                      /* [5] */
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0int\0x\0dead\0main\0int a=1+1;\0/* live call */"
+                   "\0return 0;\0/* dead */\0/* dead */"),
+       .insns = {
+               BPF_MOV64_IMM(BPF_REG_2, 1),
+               BPF_JMP_IMM(BPF_JGE, BPF_REG_2, 0, 1),
+               BPF_CALL_REL(2),
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+       .func_info_cnt = 2,
+       .func_info_rec_size = 8,
+               .func_info = { {0, 4}, {5, 3} },
+       .line_info = {
+               BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(3, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(4, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(5, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(6, 0, NAME_TBD, 1, 10),
+               BTF_END_RAW,
+       },
+       .line_info_rec_size = sizeof(struct bpf_line_info),
+       .nr_jited_ksyms = 1,
+       .dead_code_cnt = 2,
+       .dead_code_mask = 0x18,
+       .dead_func_cnt = 1,
+       .dead_func_mask = 0x2,
+},
+
+{
+       .descr = "line_info (dead subprog + dead start)",
+       .raw_types = {
+               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),   /* [1] */
+               BTF_FUNC_PROTO_ENC(1, 1),                       /* [2] */
+                       BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
+               BTF_FUNC_ENC(NAME_TBD, 2),                      /* [3] */
+               BTF_FUNC_ENC(NAME_TBD, 2),                      /* [4] */
+               BTF_FUNC_ENC(NAME_TBD, 2),                      /* [5] */
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0int\0x\0dead\0main\0func\0int a=1+1;\0/* dead */"
+                   "\0return 0;\0return 0;\0return 0;"
+                   "\0/* dead */\0/* dead */\0/* dead */\0/* dead */"
+                   "\0return b + 1;\0return b + 1;\0return b + 1;"),
+       .insns = {
+               BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+               BPF_MOV64_IMM(BPF_REG_2, 1),
+               BPF_JMP_IMM(BPF_JGE, BPF_REG_2, 0, 1),
+               BPF_CALL_REL(3),
+               BPF_CALL_REL(5),
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_CALL_REL(1),
+               BPF_EXIT_INSN(),
+               BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+               BPF_MOV64_REG(BPF_REG_0, 2),
+               BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1),
+               BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+       .func_info_cnt = 3,
+       .func_info_rec_size = 8,
+               .func_info = { {0, 4}, {7, 3}, {10, 5} },
+       .line_info = {
+               BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(3, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(4, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(5, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(6, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(7, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(8, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(9, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(10, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(11, 0, NAME_TBD, 2, 9),
+               BPF_LINE_INFO_ENC(12, 0, NAME_TBD, 2, 9),
+               BPF_LINE_INFO_ENC(13, 0, NAME_TBD, 2, 9),
+               BTF_END_RAW,
+       },
+       .line_info_rec_size = sizeof(struct bpf_line_info),
+       .nr_jited_ksyms = 2,
+       .dead_code_cnt = 5,
+       .dead_code_mask = 0x1e2,
+       .dead_func_cnt = 1,
+       .dead_func_mask = 0x2,
+},
+
+{
+       .descr = "line_info (dead subprog + dead start w/ move)",
+       .raw_types = {
+               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),   /* [1] */
+               BTF_FUNC_PROTO_ENC(1, 1),                       /* [2] */
+                       BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
+               BTF_FUNC_ENC(NAME_TBD, 2),                      /* [3] */
+               BTF_FUNC_ENC(NAME_TBD, 2),                      /* [4] */
+               BTF_FUNC_ENC(NAME_TBD, 2),                      /* [5] */
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0int\0x\0dead\0main\0func\0int a=1+1;\0/* live call */"
+                   "\0return 0;\0return 0;\0/* dead */\0/* dead */"
+                   "\0/* dead */\0return bla + 1;\0return bla + 1;"
+                   "\0return bla + 1;\0return func(a);\0b+=1;\0return b;"),
+       .insns = {
+               BPF_MOV64_IMM(BPF_REG_2, 1),
+               BPF_JMP_IMM(BPF_JGE, BPF_REG_2, 0, 1),
+               BPF_CALL_REL(3),
+               BPF_CALL_REL(5),
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_CALL_REL(1),
+               BPF_EXIT_INSN(),
+               BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+               BPF_MOV64_REG(BPF_REG_0, 2),
+               BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1),
+               BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+       .func_info_cnt = 3,
+       .func_info_rec_size = 8,
+               .func_info = { {0, 4}, {6, 3}, {9, 5} },
+       .line_info = {
+               BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(3, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(4, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(5, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(6, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(7, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(8, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(9, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(11, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(12, 0, NAME_TBD, 2, 9),
+               BTF_END_RAW,
+       },
+       .line_info_rec_size = sizeof(struct bpf_line_info),
+       .nr_jited_ksyms = 2,
+       .dead_code_cnt = 3,
+       .dead_code_mask = 0x70,
+       .dead_func_cnt = 1,
+       .dead_func_mask = 0x2,
+},
+
+{
+       .descr = "line_info (dead end + subprog start w/ no linfo)",
+       .raw_types = {
+               BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),   /* [1] */
+               BTF_FUNC_PROTO_ENC(1, 1),                       /* [2] */
+                       BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
+               BTF_FUNC_ENC(NAME_TBD, 2),                      /* [3] */
+               BTF_FUNC_ENC(NAME_TBD, 2),                      /* [4] */
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0int\0x\0main\0func\0/* main linfo */\0/* func linfo */"),
+       .insns = {
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 1, 3),
+               BPF_CALL_REL(3),
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+               BPF_EXIT_INSN(),
+               BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+               BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+       .func_info_cnt = 2,
+       .func_info_rec_size = 8,
+       .func_info = { {0, 3}, {6, 4}, },
+       .line_info = {
+               BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10),
+               BPF_LINE_INFO_ENC(6, 0, NAME_TBD, 1, 10),
+               BTF_END_RAW,
+       },
+       .line_info_rec_size = sizeof(struct bpf_line_info),
+       .nr_jited_ksyms = 2,
+},
+
 };
 
 static size_t probe_prog_length(const struct bpf_insn *fp)
@@ -4778,6 +5145,7 @@ static int test_get_finfo(const struct prog_info_raw_test *test,
        struct bpf_func_info *finfo;
        __u32 info_len, rec_size, i;
        void *func_info = NULL;
+       __u32 nr_func_info;
        int err;
 
        /* get necessary lens */
@@ -4787,7 +5155,8 @@ static int test_get_finfo(const struct prog_info_raw_test *test,
                fprintf(stderr, "%s\n", btf_log_buf);
                return -1;
        }
-       if (CHECK(info.nr_func_info != test->func_info_cnt,
+       nr_func_info = test->func_info_cnt - test->dead_func_cnt;
+       if (CHECK(info.nr_func_info != nr_func_info,
                  "incorrect info.nr_func_info (1st) %d",
                  info.nr_func_info)) {
                return -1;
@@ -4808,7 +5177,7 @@ static int test_get_finfo(const struct prog_info_raw_test *test,
 
        /* reset info to only retrieve func_info related data */
        memset(&info, 0, sizeof(info));
-       info.nr_func_info = test->func_info_cnt;
+       info.nr_func_info = nr_func_info;
        info.func_info_rec_size = rec_size;
        info.func_info = ptr_to_u64(func_info);
        err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
@@ -4817,7 +5186,7 @@ static int test_get_finfo(const struct prog_info_raw_test *test,
                err = -1;
                goto done;
        }
-       if (CHECK(info.nr_func_info != test->func_info_cnt,
+       if (CHECK(info.nr_func_info != nr_func_info,
                  "incorrect info.nr_func_info (2nd) %d",
                  info.nr_func_info)) {
                err = -1;
@@ -4831,7 +5200,9 @@ static int test_get_finfo(const struct prog_info_raw_test *test,
        }
 
        finfo = func_info;
-       for (i = 0; i < test->func_info_cnt; i++) {
+       for (i = 0; i < nr_func_info; i++) {
+               if (test->dead_func_mask & (1 << i))
+                       continue;
                if (CHECK(finfo->type_id != test->func_info[i][1],
                          "incorrect func_type %u expected %u",
                          finfo->type_id, test->func_info[i][1])) {
@@ -4860,6 +5231,7 @@ static int test_get_linfo(const struct prog_info_raw_test *test,
        struct bpf_prog_info info = {};
        __u32 *jited_func_lens = NULL;
        __u64 cur_func_ksyms;
+       __u32 dead_insns;
        int err;
 
        jited_cnt = cnt;
@@ -4868,7 +5240,7 @@ static int test_get_linfo(const struct prog_info_raw_test *test,
        if (test->nr_jited_ksyms)
                nr_jited_ksyms = test->nr_jited_ksyms;
        else
-               nr_jited_ksyms = test->func_info_cnt;
+               nr_jited_ksyms = test->func_info_cnt - test->dead_func_cnt;
        nr_jited_func_lens = nr_jited_ksyms;
 
        info_len = sizeof(struct bpf_prog_info);
@@ -4970,12 +5342,20 @@ static int test_get_linfo(const struct prog_info_raw_test *test,
                goto done;
        }
 
+       dead_insns = 0;
+       while (test->dead_code_mask & (1 << dead_insns))
+               dead_insns++;
+
        CHECK(linfo[0].insn_off, "linfo[0].insn_off:%u",
              linfo[0].insn_off);
        for (i = 1; i < cnt; i++) {
                const struct bpf_line_info *expected_linfo;
 
-               expected_linfo = patched_linfo + (i * test->line_info_rec_size);
+               while (test->dead_code_mask & (1 << (i + dead_insns)))
+                       dead_insns++;
+
+               expected_linfo = patched_linfo +
+                       ((i + dead_insns) * test->line_info_rec_size);
                if (CHECK(linfo[i].insn_off <= linfo[i - 1].insn_off,
                          "linfo[%u].insn_off:%u <= linfo[%u].insn_off:%u",
                          i, linfo[i].insn_off,
@@ -5133,7 +5513,9 @@ static int do_test_info_raw(unsigned int test_num)
        if (err)
                goto done;
 
-       err = test_get_linfo(test, patched_linfo, attr.line_info_cnt, prog_fd);
+       err = test_get_linfo(test, patched_linfo,
+                            attr.line_info_cnt - test->dead_code_cnt,
+                            prog_fd);
        if (err)
                goto done;
 
index 2fd90d4568926d13542783c870507d43a6d6bb64..4f67afeec8d90b6df496f805633d28fc34b3cfe6 100644 (file)
@@ -15599,6 +15599,166 @@ static struct bpf_test tests[] = {
                .result_unpriv = ACCEPT,
                .result = ACCEPT,
        },
+       {
+               "dead code: start",
+               .insns = {
+                       BPF_JMP_IMM(BPF_JA, 0, 0, 2),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, 2),
+                       BPF_MOV64_IMM(BPF_REG_0, 7),
+                       BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 10, -4),
+                       BPF_EXIT_INSN(),
+               },
+               .result = ACCEPT,
+               .retval = 7,
+       },
+       {
+               "dead code: mid 1",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_0, 7),
+                       BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1),
+                       BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 10, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .result = ACCEPT,
+               .retval = 7,
+       },
+       {
+               "dead code: mid 2",
+               .insns = {
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_get_prandom_u32),
+                       BPF_JMP_IMM(BPF_JSET, BPF_REG_0, 1, 4),
+                       BPF_JMP_IMM(BPF_JSET, BPF_REG_0, 1, 1),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, 2),
+                       BPF_MOV64_IMM(BPF_REG_0, 7),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .result = ACCEPT,
+               .retval = 1,
+       },
+       {
+               "dead code: end 1",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_0, 7),
+                       BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 10, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_EXIT_INSN(),
+               },
+               .result = ACCEPT,
+               .retval = 7,
+       },
+       {
+               "dead code: end 2",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_0, 7),
+                       BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 10, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_0, 12),
+                       BPF_EXIT_INSN(),
+               },
+               .result = ACCEPT,
+               .retval = 7,
+       },
+       {
+               "dead code: end 3",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_0, 7),
+                       BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 8, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 10, 1),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+                       BPF_MOV64_IMM(BPF_REG_0, 12),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, -5),
+               },
+               .result = ACCEPT,
+               .retval = 7,
+       },
+       {
+               "dead code: tail of main + func",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_0, 7),
+                       BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 8, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_0, 12),
+                       BPF_EXIT_INSN(),
+               },
+               .errstr_unpriv = "function calls to other bpf functions are allowed for root only",
+               .result_unpriv = REJECT,
+               .result = ACCEPT,
+               .retval = 7,
+       },
+       {
+               "dead code: tail of main + two functions",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_0, 7),
+                       BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 8, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_0, 12),
+                       BPF_EXIT_INSN(),
+               },
+               .errstr_unpriv = "function calls to other bpf functions are allowed for root only",
+               .result_unpriv = REJECT,
+               .result = ACCEPT,
+               .retval = 7,
+       },
+       {
+               "dead code: function in the middle and mid of another func",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_1, 7),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_0, 12),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_0, 7),
+                       BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 7, 1),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, -5),
+                       BPF_EXIT_INSN(),
+               },
+               .errstr_unpriv = "function calls to other bpf functions are allowed for root only",
+               .result_unpriv = REJECT,
+               .result = ACCEPT,
+               .retval = 7,
+       },
+       {
+               "dead code: middle of main before call",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_1, 2),
+                       BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 2, 1),
+                       BPF_MOV64_IMM(BPF_REG_1, 5),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
+                       BPF_EXIT_INSN(),
+               },
+               .errstr_unpriv = "function calls to other bpf functions are allowed for root only",
+               .result_unpriv = REJECT,
+               .result = ACCEPT,
+               .retval = 2,
+       },
+       {
+               "dead code: start of a function",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_1, 2),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
+                       BPF_EXIT_INSN(),
+               },
+               .errstr_unpriv = "function calls to other bpf functions are allowed for root only",
+               .result_unpriv = REJECT,
+               .result = ACCEPT,
+               .retval = 2,
+       },
 };
 
 static int probe_filter_length(const struct bpf_insn *fp)