xref: /linux/tools/testing/selftests/user_events/dyn_test.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
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 #include "user_events_selftests.h"
19 
20 const char *dyn_file = "/sys/kernel/tracing/dynamic_events";
21 const char *abi_file = "/sys/kernel/tracing/user_events_data";
22 const char *enable_file = "/sys/kernel/tracing/events/user_events/__test_event/enable";
23 
event_delete(void)24 static int event_delete(void)
25 {
26 	int fd = open(abi_file, O_RDWR);
27 	int ret;
28 
29 	if (fd < 0)
30 		return -1;
31 
32 	ret = ioctl(fd, DIAG_IOCSDEL, "__test_event");
33 
34 	close(fd);
35 
36 	return ret;
37 }
38 
wait_for_delete(void)39 static bool wait_for_delete(void)
40 {
41 	int i;
42 
43 	for (i = 0; i < 1000; ++i) {
44 		int fd = open(enable_file, O_RDONLY);
45 
46 		if (fd == -1)
47 			return true;
48 
49 		close(fd);
50 		usleep(1000);
51 	}
52 
53 	return false;
54 }
55 
reg_event(int fd,int * check,int bit,const char * value)56 static int reg_event(int fd, int *check, int bit, const char *value)
57 {
58 	struct user_reg reg = {0};
59 
60 	reg.size = sizeof(reg);
61 	reg.name_args = (__u64)value;
62 	reg.enable_bit = bit;
63 	reg.enable_addr = (__u64)check;
64 	reg.enable_size = sizeof(*check);
65 
66 	if (ioctl(fd, DIAG_IOCSREG, &reg) == -1)
67 		return -1;
68 
69 	return 0;
70 }
71 
unreg_event(int fd,int * check,int bit)72 static int unreg_event(int fd, int *check, int bit)
73 {
74 	struct user_unreg unreg = {0};
75 
76 	unreg.size = sizeof(unreg);
77 	unreg.disable_bit = bit;
78 	unreg.disable_addr = (__u64)check;
79 
80 	return ioctl(fd, DIAG_IOCSUNREG, &unreg);
81 }
82 
parse_dyn(const char * value)83 static int parse_dyn(const char *value)
84 {
85 	int fd = open(dyn_file, O_RDWR | O_APPEND);
86 	int len = strlen(value);
87 	int ret;
88 
89 	if (fd == -1)
90 		return -1;
91 
92 	ret = write(fd, value, len);
93 
94 	if (ret == len)
95 		ret = 0;
96 	else
97 		ret = -1;
98 
99 	close(fd);
100 
101 	if (ret == 0)
102 		event_delete();
103 
104 	return ret;
105 }
106 
parse_abi(int * check,const char * value)107 static int parse_abi(int *check, const char *value)
108 {
109 	int fd = open(abi_file, O_RDWR);
110 	int ret;
111 
112 	if (fd == -1)
113 		return -1;
114 
115 	/* Until we have persist flags via dynamic events, use the base name */
116 	if (value[0] != 'u' || value[1] != ':') {
117 		close(fd);
118 		return -1;
119 	}
120 
121 	ret = reg_event(fd, check, 31, value + 2);
122 
123 	if (ret != -1) {
124 		if (unreg_event(fd, check, 31) == -1)
125 			printf("WARN: Couldn't unreg event\n");
126 	}
127 
128 	close(fd);
129 
130 	return ret;
131 }
132 
parse(int * check,const char * value)133 static int parse(int *check, const char *value)
134 {
135 	int abi_ret = parse_abi(check, value);
136 	int dyn_ret = parse_dyn(value);
137 
138 	/* Ensure both ABI and DYN parse the same way */
139 	if (dyn_ret != abi_ret)
140 		return -1;
141 
142 	return dyn_ret;
143 }
144 
check_match(int * check,const char * first,const char * second,bool * match)145 static int check_match(int *check, const char *first, const char *second, bool *match)
146 {
147 	int fd = open(abi_file, O_RDWR);
148 	int ret = -1;
149 
150 	if (fd == -1)
151 		return -1;
152 
153 	if (reg_event(fd, check, 31, first) == -1)
154 		goto cleanup;
155 
156 	if (reg_event(fd, check, 30, second) == -1) {
157 		if (errno == EADDRINUSE) {
158 			/* Name is in use, with different fields */
159 			*match = false;
160 			ret = 0;
161 		}
162 
163 		goto cleanup;
164 	}
165 
166 	*match = true;
167 	ret = 0;
168 cleanup:
169 	unreg_event(fd, check, 31);
170 	unreg_event(fd, check, 30);
171 
172 	close(fd);
173 
174 	wait_for_delete();
175 
176 	return ret;
177 }
178 
179 #define TEST_MATCH(x, y) \
180 do { \
181 	bool match; \
182 	ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
183 	ASSERT_EQ(true, match); \
184 } while (0)
185 
186 #define TEST_NMATCH(x, y) \
187 do { \
188 	bool match; \
189 	ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
190 	ASSERT_EQ(false, match); \
191 } while (0)
192 
193 #define TEST_PARSE(x) ASSERT_NE(-1, parse(&self->check, x))
194 
195 #define TEST_NPARSE(x) ASSERT_EQ(-1, parse(&self->check, x))
196 
FIXTURE(user)197 FIXTURE(user) {
198 	int check;
199 	bool umount;
200 };
201 
FIXTURE_SETUP(user)202 FIXTURE_SETUP(user) {
203 	USER_EVENT_FIXTURE_SETUP(return, self->umount);
204 }
205 
FIXTURE_TEARDOWN(user)206 FIXTURE_TEARDOWN(user) {
207 	USER_EVENT_FIXTURE_TEARDOWN(self->umount);
208 
209 	wait_for_delete();
210 }
211 
TEST_F(user,basic_types)212 TEST_F(user, basic_types) {
213 	/* All should work */
214 	TEST_PARSE("u:__test_event u64 a");
215 	TEST_PARSE("u:__test_event u32 a");
216 	TEST_PARSE("u:__test_event u16 a");
217 	TEST_PARSE("u:__test_event u8 a");
218 	TEST_PARSE("u:__test_event char a");
219 	TEST_PARSE("u:__test_event unsigned char a");
220 	TEST_PARSE("u:__test_event int a");
221 	TEST_PARSE("u:__test_event unsigned int a");
222 	TEST_PARSE("u:__test_event short a");
223 	TEST_PARSE("u:__test_event unsigned short a");
224 	TEST_PARSE("u:__test_event char[20] a");
225 	TEST_PARSE("u:__test_event unsigned char[20] a");
226 	TEST_PARSE("u:__test_event char[0x14] a");
227 	TEST_PARSE("u:__test_event unsigned char[0x14] a");
228 	/* Bad size format should fail */
229 	TEST_NPARSE("u:__test_event char[aa] a");
230 	/* Large size should fail */
231 	TEST_NPARSE("u:__test_event char[9999] a");
232 	/* Long size string should fail */
233 	TEST_NPARSE("u:__test_event char[0x0000000000001] a");
234 }
235 
TEST_F(user,loc_types)236 TEST_F(user, loc_types) {
237 	/* All should work */
238 	TEST_PARSE("u:__test_event __data_loc char[] a");
239 	TEST_PARSE("u:__test_event __data_loc unsigned char[] a");
240 	TEST_PARSE("u:__test_event __rel_loc char[] a");
241 	TEST_PARSE("u:__test_event __rel_loc unsigned char[] a");
242 }
243 
TEST_F(user,size_types)244 TEST_F(user, size_types) {
245 	/* Should work */
246 	TEST_PARSE("u:__test_event struct custom a 20");
247 	/* Size not specified on struct should fail */
248 	TEST_NPARSE("u:__test_event struct custom a");
249 	/* Size specified on non-struct should fail */
250 	TEST_NPARSE("u:__test_event char a 20");
251 }
252 
TEST_F(user,matching)253 TEST_F(user, matching) {
254 	/* Single name matches */
255 	TEST_MATCH("__test_event u32 a",
256 		   "__test_event u32 a");
257 
258 	/* Multiple names match */
259 	TEST_MATCH("__test_event u32 a; u32 b",
260 		   "__test_event u32 a; u32 b");
261 
262 	/* Multiple names match with dangling ; */
263 	TEST_MATCH("__test_event u32 a; u32 b",
264 		   "__test_event u32 a; u32 b;");
265 
266 	/* Single name doesn't match */
267 	TEST_NMATCH("__test_event u32 a",
268 		    "__test_event u32 b");
269 
270 	/* Multiple names don't match */
271 	TEST_NMATCH("__test_event u32 a; u32 b",
272 		    "__test_event u32 b; u32 a");
273 
274 	/* Types don't match */
275 	TEST_NMATCH("__test_event u64 a; u64 b",
276 		    "__test_event u32 a; u32 b");
277 
278 	/* Struct name and size matches */
279 	TEST_MATCH("__test_event struct my_struct a 20",
280 		   "__test_event struct my_struct a 20");
281 
282 	/* Struct name don't match */
283 	TEST_NMATCH("__test_event struct my_struct a 20",
284 		    "__test_event struct my_struct b 20");
285 
286 	/* Struct size don't match */
287 	TEST_NMATCH("__test_event struct my_struct a 20",
288 		    "__test_event struct my_struct a 21");
289 }
290 
main(int argc,char ** argv)291 int main(int argc, char **argv)
292 {
293 	return test_harness_run(argc, argv);
294 }
295