1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */ 3 #include <test_progs.h> 4 #include <sys/mman.h> 5 #include <regex.h> 6 7 #include "stream.skel.h" 8 #include "stream_fail.skel.h" 9 10 void test_stream_failure(void) 11 { 12 RUN_TESTS(stream_fail); 13 } 14 15 void test_stream_success(void) 16 { 17 RUN_TESTS(stream); 18 return; 19 } 20 21 struct { 22 int prog_off; 23 const char *errstr; 24 } stream_error_arr[] = { 25 { 26 offsetof(struct stream, progs.stream_cond_break), 27 "ERROR: Timeout detected for may_goto instruction\n" 28 "CPU: [0-9]+ UID: 0 PID: [0-9]+ Comm: .*\n" 29 "Call trace:\n" 30 "([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n" 31 "|[ \t]+[^\n]+\n)*", 32 }, 33 { 34 offsetof(struct stream, progs.stream_deadlock), 35 "ERROR: AA or ABBA deadlock detected for bpf_res_spin_lock\n" 36 "Attempted lock = (0x[0-9a-fA-F]+)\n" 37 "Total held locks = 1\n" 38 "Held lock\\[ 0\\] = \\1\n" // Lock address must match 39 "CPU: [0-9]+ UID: 0 PID: [0-9]+ Comm: .*\n" 40 "Call trace:\n" 41 "([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n" 42 "|[ \t]+[^\n]+\n)*", 43 }, 44 }; 45 46 static int match_regex(const char *pattern, const char *string) 47 { 48 int err, rc; 49 regex_t re; 50 51 err = regcomp(&re, pattern, REG_EXTENDED | REG_NEWLINE); 52 if (err) 53 return -1; 54 rc = regexec(&re, string, 0, NULL, 0); 55 regfree(&re); 56 return rc == 0 ? 1 : 0; 57 } 58 59 void test_stream_errors(void) 60 { 61 LIBBPF_OPTS(bpf_test_run_opts, opts); 62 LIBBPF_OPTS(bpf_prog_stream_read_opts, ropts); 63 struct stream *skel; 64 int ret, prog_fd; 65 char buf[1024]; 66 67 skel = stream__open_and_load(); 68 if (!ASSERT_OK_PTR(skel, "stream__open_and_load")) 69 return; 70 71 for (int i = 0; i < ARRAY_SIZE(stream_error_arr); i++) { 72 struct bpf_program **prog; 73 74 prog = (struct bpf_program **)(((char *)skel) + stream_error_arr[i].prog_off); 75 prog_fd = bpf_program__fd(*prog); 76 ret = bpf_prog_test_run_opts(prog_fd, &opts); 77 ASSERT_OK(ret, "ret"); 78 ASSERT_OK(opts.retval, "retval"); 79 80 #if !defined(__x86_64__) 81 ASSERT_TRUE(1, "Timed may_goto unsupported, skip."); 82 if (i == 0) { 83 ret = bpf_prog_stream_read(prog_fd, 2, buf, sizeof(buf), &ropts); 84 ASSERT_EQ(ret, 0, "stream read"); 85 continue; 86 } 87 #endif 88 89 ret = bpf_prog_stream_read(prog_fd, BPF_STREAM_STDERR, buf, sizeof(buf), &ropts); 90 ASSERT_GT(ret, 0, "stream read"); 91 ASSERT_LE(ret, 1023, "len for buf"); 92 buf[ret] = '\0'; 93 94 ret = match_regex(stream_error_arr[i].errstr, buf); 95 if (!ASSERT_TRUE(ret == 1, "regex match")) 96 fprintf(stderr, "Output from stream:\n%s\n", buf); 97 } 98 99 stream__destroy(skel); 100 } 101 102 void test_stream_syscall(void) 103 { 104 LIBBPF_OPTS(bpf_test_run_opts, opts); 105 LIBBPF_OPTS(bpf_prog_stream_read_opts, ropts); 106 struct stream *skel; 107 int ret, prog_fd; 108 char buf[64]; 109 110 skel = stream__open_and_load(); 111 if (!ASSERT_OK_PTR(skel, "stream__open_and_load")) 112 return; 113 114 prog_fd = bpf_program__fd(skel->progs.stream_syscall); 115 ret = bpf_prog_test_run_opts(prog_fd, &opts); 116 ASSERT_OK(ret, "ret"); 117 ASSERT_OK(opts.retval, "retval"); 118 119 ASSERT_LT(bpf_prog_stream_read(0, BPF_STREAM_STDOUT, buf, sizeof(buf), &ropts), 0, "error"); 120 ret = -errno; 121 ASSERT_EQ(ret, -EINVAL, "bad prog_fd"); 122 123 ASSERT_LT(bpf_prog_stream_read(prog_fd, 0, buf, sizeof(buf), &ropts), 0, "error"); 124 ret = -errno; 125 ASSERT_EQ(ret, -ENOENT, "bad stream id"); 126 127 ASSERT_LT(bpf_prog_stream_read(prog_fd, BPF_STREAM_STDOUT, NULL, sizeof(buf), NULL), 0, "error"); 128 ret = -errno; 129 ASSERT_EQ(ret, -EFAULT, "bad stream buf"); 130 131 ret = bpf_prog_stream_read(prog_fd, BPF_STREAM_STDOUT, buf, 2, NULL); 132 ASSERT_EQ(ret, 2, "bytes"); 133 ret = bpf_prog_stream_read(prog_fd, BPF_STREAM_STDOUT, buf, 2, NULL); 134 ASSERT_EQ(ret, 1, "bytes"); 135 ret = bpf_prog_stream_read(prog_fd, BPF_STREAM_STDOUT, buf, 1, &ropts); 136 ASSERT_EQ(ret, 0, "no bytes stdout"); 137 ret = bpf_prog_stream_read(prog_fd, BPF_STREAM_STDERR, buf, 1, &ropts); 138 ASSERT_EQ(ret, 0, "no bytes stderr"); 139 140 stream__destroy(skel); 141 } 142