|
38 | 38 | #define TEST_TAG_JITED_PFX_UNPRIV "comment:test_jited_unpriv=" |
39 | 39 | #define TEST_TAG_CAPS_UNPRIV "comment:test_caps_unpriv=" |
40 | 40 | #define TEST_TAG_LOAD_MODE_PFX "comment:load_mode=" |
| 41 | +#define TEST_TAG_EXPECT_STDERR_PFX "comment:test_expect_stderr=" |
| 42 | +#define TEST_TAG_EXPECT_STDERR_PFX_UNPRIV "comment:test_expect_stderr_unpriv=" |
| 43 | +#define TEST_TAG_EXPECT_STDOUT_PFX "comment:test_expect_stdout=" |
| 44 | +#define TEST_TAG_EXPECT_STDOUT_PFX_UNPRIV "comment:test_expect_stdout_unpriv=" |
41 | 45 |
|
42 | 46 | /* Warning: duplicated in bpf_misc.h */ |
43 | 47 | #define POINTER_VALUE 0xbadcafe |
@@ -79,6 +83,8 @@ struct test_subspec { |
79 | 83 | struct expected_msgs expect_msgs; |
80 | 84 | struct expected_msgs expect_xlated; |
81 | 85 | struct expected_msgs jited; |
| 86 | + struct expected_msgs stderr; |
| 87 | + struct expected_msgs stdout; |
82 | 88 | int retval; |
83 | 89 | bool execute; |
84 | 90 | __u64 caps; |
@@ -139,6 +145,10 @@ static void free_test_spec(struct test_spec *spec) |
139 | 145 | free_msgs(&spec->unpriv.expect_xlated); |
140 | 146 | free_msgs(&spec->priv.jited); |
141 | 147 | free_msgs(&spec->unpriv.jited); |
| 148 | + free_msgs(&spec->unpriv.stderr); |
| 149 | + free_msgs(&spec->priv.stderr); |
| 150 | + free_msgs(&spec->unpriv.stdout); |
| 151 | + free_msgs(&spec->priv.stdout); |
142 | 152 |
|
143 | 153 | free(spec->priv.name); |
144 | 154 | free(spec->unpriv.name); |
@@ -407,6 +417,10 @@ static int parse_test_spec(struct test_loader *tester, |
407 | 417 | bool xlated_on_next_line = true; |
408 | 418 | bool unpriv_jit_on_next_line; |
409 | 419 | bool jit_on_next_line; |
| 420 | + bool stderr_on_next_line = true; |
| 421 | + bool unpriv_stderr_on_next_line = true; |
| 422 | + bool stdout_on_next_line = true; |
| 423 | + bool unpriv_stdout_on_next_line = true; |
410 | 424 | bool collect_jit = false; |
411 | 425 | int func_id, i, err = 0; |
412 | 426 | u32 arch_mask = 0; |
@@ -598,6 +612,26 @@ static int parse_test_spec(struct test_loader *tester, |
598 | 612 | err = -EINVAL; |
599 | 613 | goto cleanup; |
600 | 614 | } |
| 615 | + } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_STDERR_PFX))) { |
| 616 | + err = push_disasm_msg(msg, &stderr_on_next_line, |
| 617 | + &spec->priv.stderr); |
| 618 | + if (err) |
| 619 | + goto cleanup; |
| 620 | + } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_STDERR_PFX_UNPRIV))) { |
| 621 | + err = push_disasm_msg(msg, &unpriv_stderr_on_next_line, |
| 622 | + &spec->unpriv.stderr); |
| 623 | + if (err) |
| 624 | + goto cleanup; |
| 625 | + } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_STDOUT_PFX))) { |
| 626 | + err = push_disasm_msg(msg, &stdout_on_next_line, |
| 627 | + &spec->priv.stdout); |
| 628 | + if (err) |
| 629 | + goto cleanup; |
| 630 | + } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_STDOUT_PFX_UNPRIV))) { |
| 631 | + err = push_disasm_msg(msg, &unpriv_stdout_on_next_line, |
| 632 | + &spec->unpriv.stdout); |
| 633 | + if (err) |
| 634 | + goto cleanup; |
601 | 635 | } |
602 | 636 | } |
603 | 637 |
|
@@ -651,6 +685,10 @@ static int parse_test_spec(struct test_loader *tester, |
651 | 685 | clone_msgs(&spec->priv.expect_xlated, &spec->unpriv.expect_xlated); |
652 | 686 | if (spec->unpriv.jited.cnt == 0) |
653 | 687 | clone_msgs(&spec->priv.jited, &spec->unpriv.jited); |
| 688 | + if (spec->unpriv.stderr.cnt == 0) |
| 689 | + clone_msgs(&spec->priv.stderr, &spec->unpriv.stderr); |
| 690 | + if (spec->unpriv.stdout.cnt == 0) |
| 691 | + clone_msgs(&spec->priv.stdout, &spec->unpriv.stdout); |
654 | 692 | } |
655 | 693 |
|
656 | 694 | spec->valid = true; |
@@ -712,6 +750,20 @@ static void emit_jited(const char *jited, bool force) |
712 | 750 | fprintf(stdout, "JITED:\n=============\n%s=============\n", jited); |
713 | 751 | } |
714 | 752 |
|
| 753 | +static void emit_stderr(const char *stderr, bool force) |
| 754 | +{ |
| 755 | + if (!force && env.verbosity == VERBOSE_NONE) |
| 756 | + return; |
| 757 | + fprintf(stdout, "STDERR:\n=============\n%s=============\n", stderr); |
| 758 | +} |
| 759 | + |
| 760 | +static void emit_stdout(const char *bpf_stdout, bool force) |
| 761 | +{ |
| 762 | + if (!force && env.verbosity == VERBOSE_NONE) |
| 763 | + return; |
| 764 | + fprintf(stdout, "STDOUT:\n=============\n%s=============\n", bpf_stdout); |
| 765 | +} |
| 766 | + |
715 | 767 | static void validate_msgs(char *log_buf, struct expected_msgs *msgs, |
716 | 768 | void (*emit_fn)(const char *buf, bool force)) |
717 | 769 | { |
@@ -934,6 +986,19 @@ static int get_xlated_program_text(int prog_fd, char *text, size_t text_sz) |
934 | 986 | return err; |
935 | 987 | } |
936 | 988 |
|
| 989 | +/* Read the bpf stream corresponding to the stream_id */ |
| 990 | +static int get_stream(int stream_id, int prog_fd, char *text, size_t text_sz) |
| 991 | +{ |
| 992 | + LIBBPF_OPTS(bpf_prog_stream_read_opts, ropts); |
| 993 | + int ret; |
| 994 | + |
| 995 | + ret = bpf_prog_stream_read(prog_fd, stream_id, text, text_sz, &ropts); |
| 996 | + ASSERT_GT(ret, 0, "stream read"); |
| 997 | + text[ret] = '\0'; |
| 998 | + |
| 999 | + return ret; |
| 1000 | +} |
| 1001 | + |
937 | 1002 | /* this function is forced noinline and has short generic name to look better |
938 | 1003 | * in test_progs output (in case of a failure) |
939 | 1004 | */ |
@@ -1108,6 +1173,31 @@ void run_subtest(struct test_loader *tester, |
1108 | 1173 | PRINT_FAIL("Unexpected retval: %d != %d\n", retval, subspec->retval); |
1109 | 1174 | goto tobj_cleanup; |
1110 | 1175 | } |
| 1176 | + |
| 1177 | + if (subspec->stderr.cnt) { |
| 1178 | + err = get_stream(2, bpf_program__fd(tprog), |
| 1179 | + tester->log_buf, tester->log_buf_sz); |
| 1180 | + if (err <= 0) { |
| 1181 | + PRINT_FAIL("Unexpected retval from get_stream(): %d, errno = %d\n", |
| 1182 | + err, errno); |
| 1183 | + goto tobj_cleanup; |
| 1184 | + } |
| 1185 | + emit_stderr(tester->log_buf, false /*force*/); |
| 1186 | + validate_msgs(tester->log_buf, &subspec->stderr, emit_stderr); |
| 1187 | + } |
| 1188 | + |
| 1189 | + if (subspec->stdout.cnt) { |
| 1190 | + err = get_stream(1, bpf_program__fd(tprog), |
| 1191 | + tester->log_buf, tester->log_buf_sz); |
| 1192 | + if (err <= 0) { |
| 1193 | + PRINT_FAIL("Unexpected retval from get_stream(): %d, errno = %d\n", |
| 1194 | + err, errno); |
| 1195 | + goto tobj_cleanup; |
| 1196 | + } |
| 1197 | + emit_stdout(tester->log_buf, false /*force*/); |
| 1198 | + validate_msgs(tester->log_buf, &subspec->stdout, emit_stdout); |
| 1199 | + } |
| 1200 | + |
1111 | 1201 | /* redo bpf_map__attach_struct_ops for each test */ |
1112 | 1202 | while (links_cnt > 0) |
1113 | 1203 | bpf_link__destroy(links[--links_cnt]); |
|
0 commit comments