1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * User Events Dyn Events Test Program
4  *
5  * Copyright (c) 2021 Beau Belgrave <beaub@linux.microsoft.com>
6  */
7 
8 #include <errno.h>
9 #include <linux/user_events.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <fcntl.h>
13 #include <sys/ioctl.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16 
17 #include "../kselftest_harness.h"
18 
19 const char *abi_file = "/sys/kernel/tracing/user_events_data";
20 const char *enable_file = "/sys/kernel/tracing/events/user_events/__test_event/enable";
21 
22 static bool wait_for_delete(void)
23 {
24 	int i;
25 
26 	for (i = 0; i < 1000; ++i) {
27 		int fd = open(enable_file, O_RDONLY);
28 
29 		if (fd == -1)
30 			return true;
31 
32 		close(fd);
33 		usleep(1000);
34 	}
35 
36 	return false;
37 }
38 
39 static int reg_event(int fd, int *check, int bit, const char *value)
40 {
41 	struct user_reg reg = {0};
42 
43 	reg.size = sizeof(reg);
44 	reg.name_args = (__u64)value;
45 	reg.enable_bit = bit;
46 	reg.enable_addr = (__u64)check;
47 	reg.enable_size = sizeof(*check);
48 
49 	if (ioctl(fd, DIAG_IOCSREG, &reg) == -1)
50 		return -1;
51 
52 	return 0;
53 }
54 
55 static int unreg_event(int fd, int *check, int bit)
56 {
57 	struct user_unreg unreg = {0};
58 
59 	unreg.size = sizeof(unreg);
60 	unreg.disable_bit = bit;
61 	unreg.disable_addr = (__u64)check;
62 
63 	return ioctl(fd, DIAG_IOCSUNREG, &unreg);
64 }
65 
66 static int parse(int *check, const char *value)
67 {
68 	int fd = open(abi_file, O_RDWR);
69 	int ret;
70 
71 	if (fd == -1)
72 		return -1;
73 
74 	/* Until we have persist flags via dynamic events, use the base name */
75 	if (value[0] != 'u' || value[1] != ':') {
76 		close(fd);
77 		return -1;
78 	}
79 
80 	ret = reg_event(fd, check, 31, value + 2);
81 
82 	if (ret != -1) {
83 		if (unreg_event(fd, check, 31) == -1)
84 			printf("WARN: Couldn't unreg event\n");
85 	}
86 
87 	close(fd);
88 
89 	return ret;
90 }
91 
92 static int check_match(int *check, const char *first, const char *second, bool *match)
93 {
94 	int fd = open(abi_file, O_RDWR);
95 	int ret = -1;
96 
97 	if (fd == -1)
98 		return -1;
99 
100 	if (reg_event(fd, check, 31, first) == -1)
101 		goto cleanup;
102 
103 	if (reg_event(fd, check, 30, second) == -1) {
104 		if (errno == EADDRINUSE) {
105 			/* Name is in use, with different fields */
106 			*match = false;
107 			ret = 0;
108 		}
109 
110 		goto cleanup;
111 	}
112 
113 	*match = true;
114 	ret = 0;
115 cleanup:
116 	unreg_event(fd, check, 31);
117 	unreg_event(fd, check, 30);
118 
119 	close(fd);
120 
121 	wait_for_delete();
122 
123 	return ret;
124 }
125 
126 #define TEST_MATCH(x, y) \
127 do { \
128 	bool match; \
129 	ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
130 	ASSERT_EQ(true, match); \
131 } while (0)
132 
133 #define TEST_NMATCH(x, y) \
134 do { \
135 	bool match; \
136 	ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
137 	ASSERT_EQ(false, match); \
138 } while (0)
139 
140 #define TEST_PARSE(x) ASSERT_NE(-1, parse(&self->check, x))
141 
142 #define TEST_NPARSE(x) ASSERT_EQ(-1, parse(&self->check, x))
143 
144 FIXTURE(user) {
145 	int check;
146 };
147 
148 FIXTURE_SETUP(user) {
149 }
150 
151 FIXTURE_TEARDOWN(user) {
152 	wait_for_delete();
153 }
154 
155 TEST_F(user, basic_types) {
156 	/* All should work */
157 	TEST_PARSE("u:__test_event u64 a");
158 	TEST_PARSE("u:__test_event u32 a");
159 	TEST_PARSE("u:__test_event u16 a");
160 	TEST_PARSE("u:__test_event u8 a");
161 	TEST_PARSE("u:__test_event char a");
162 	TEST_PARSE("u:__test_event unsigned char a");
163 	TEST_PARSE("u:__test_event int a");
164 	TEST_PARSE("u:__test_event unsigned int a");
165 	TEST_PARSE("u:__test_event short a");
166 	TEST_PARSE("u:__test_event unsigned short a");
167 	TEST_PARSE("u:__test_event char[20] a");
168 	TEST_PARSE("u:__test_event unsigned char[20] a");
169 	TEST_PARSE("u:__test_event char[0x14] a");
170 	TEST_PARSE("u:__test_event unsigned char[0x14] a");
171 	/* Bad size format should fail */
172 	TEST_NPARSE("u:__test_event char[aa] a");
173 	/* Large size should fail */
174 	TEST_NPARSE("u:__test_event char[9999] a");
175 	/* Long size string should fail */
176 	TEST_NPARSE("u:__test_event char[0x0000000000001] a");
177 }
178 
179 TEST_F(user, loc_types) {
180 	/* All should work */
181 	TEST_PARSE("u:__test_event __data_loc char[] a");
182 	TEST_PARSE("u:__test_event __data_loc unsigned char[] a");
183 	TEST_PARSE("u:__test_event __rel_loc char[] a");
184 	TEST_PARSE("u:__test_event __rel_loc unsigned char[] a");
185 }
186 
187 TEST_F(user, size_types) {
188 	/* Should work */
189 	TEST_PARSE("u:__test_event struct custom a 20");
190 	/* Size not specified on struct should fail */
191 	TEST_NPARSE("u:__test_event struct custom a");
192 	/* Size specified on non-struct should fail */
193 	TEST_NPARSE("u:__test_event char a 20");
194 }
195 
196 TEST_F(user, matching) {
197 	/* Single name matches */
198 	TEST_MATCH("__test_event u32 a",
199 		   "__test_event u32 a");
200 
201 	/* Multiple names match */
202 	TEST_MATCH("__test_event u32 a; u32 b",
203 		   "__test_event u32 a; u32 b");
204 
205 	/* Multiple names match with dangling ; */
206 	TEST_MATCH("__test_event u32 a; u32 b",
207 		   "__test_event u32 a; u32 b;");
208 
209 	/* Single name doesn't match */
210 	TEST_NMATCH("__test_event u32 a",
211 		    "__test_event u32 b");
212 
213 	/* Multiple names don't match */
214 	TEST_NMATCH("__test_event u32 a; u32 b",
215 		    "__test_event u32 b; u32 a");
216 
217 	/* Types don't match */
218 	TEST_NMATCH("__test_event u64 a; u64 b",
219 		    "__test_event u32 a; u32 b");
220 
221 	/* Struct name and size matches */
222 	TEST_MATCH("__test_event struct my_struct a 20",
223 		   "__test_event struct my_struct a 20");
224 
225 	/* Struct name don't match */
226 	TEST_NMATCH("__test_event struct my_struct a 20",
227 		    "__test_event struct my_struct b 20");
228 
229 	/* Struct size don't match */
230 	TEST_NMATCH("__test_event struct my_struct a 20",
231 		    "__test_event struct my_struct a 21");
232 }
233 
234 int main(int argc, char **argv)
235 {
236 	return test_harness_run(argc, argv);
237 }
238