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