File Index
Files and directories
Sign in
FILE

dyn_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/user_events/dyn_test.c C
  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
 20const char *dyn_file = "/sys/kernel/tracing/dynamic_events";
 21const char *abi_file = "/sys/kernel/tracing/user_events_data";
 22const char *enable_file = "/sys/kernel/tracing/events/user_events/__test_event/enable";
 23
 24static 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
 39static 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
 56static 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
 72static 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
 83static 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
107static 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	wait_for_delete();
131
132	return ret;
133}
134
135static int parse(int *check, const char *value)
136{
137	int abi_ret = parse_abi(check, value);
138	int dyn_ret = parse_dyn(value);
139
140	/* Ensure both ABI and DYN parse the same way */
141	if (dyn_ret != abi_ret)
142		return -1;
143
144	return dyn_ret;
145}
146
147static int check_match(int *check, const char *first, const char *second, bool *match)
148{
149	int fd = open(abi_file, O_RDWR);
150	int ret = -1;
151
152	if (fd == -1)
153		return -1;
154
155	if (reg_event(fd, check, 31, first) == -1)
156		goto cleanup;
157
158	if (reg_event(fd, check, 30, second) == -1) {
159		if (errno == EADDRINUSE) {
160			/* Name is in use, with different fields */
161			*match = false;
162			ret = 0;
163		}
164
165		goto cleanup;
166	}
167
168	*match = true;
169	ret = 0;
170cleanup:
171	unreg_event(fd, check, 31);
172	unreg_event(fd, check, 30);
173
174	close(fd);
175
176	wait_for_delete();
177
178	return ret;
179}
180
181#define TEST_MATCH(x, y) \
182do { \
183	bool match; \
184	ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
185	ASSERT_EQ(true, match); \
186} while (0)
187
188#define TEST_NMATCH(x, y) \
189do { \
190	bool match; \
191	ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
192	ASSERT_EQ(false, match); \
193} while (0)
194
195#define TEST_PARSE(x) ASSERT_NE(-1, parse(&self->check, x))
196
197#define TEST_NPARSE(x) ASSERT_EQ(-1, parse(&self->check, x))
198
199FIXTURE(user) {
200	int check;
201	bool umount;
202};
203
204FIXTURE_SETUP(user) {
205	USER_EVENT_FIXTURE_SETUP(return, self->umount);
206}
207
208FIXTURE_TEARDOWN(user) {
209	USER_EVENT_FIXTURE_TEARDOWN(self->umount);
210
211	wait_for_delete();
212}
213
214TEST_F(user, basic_types) {
215	/* All should work */
216	TEST_PARSE("u:__test_event u64 a");
217	TEST_PARSE("u:__test_event u32 a");
218	TEST_PARSE("u:__test_event u16 a");
219	TEST_PARSE("u:__test_event u8 a");
220	TEST_PARSE("u:__test_event char a");
221	TEST_PARSE("u:__test_event unsigned char a");
222	TEST_PARSE("u:__test_event int a");
223	TEST_PARSE("u:__test_event unsigned int a");
224	TEST_PARSE("u:__test_event short a");
225	TEST_PARSE("u:__test_event unsigned short a");
226	TEST_PARSE("u:__test_event char[20] a");
227	TEST_PARSE("u:__test_event unsigned char[20] a");
228	TEST_PARSE("u:__test_event char[0x14] a");
229	TEST_PARSE("u:__test_event unsigned char[0x14] a");
230	/* Bad size format should fail */
231	TEST_NPARSE("u:__test_event char[aa] a");
232	/* Large size should fail */
233	TEST_NPARSE("u:__test_event char[9999] a");
234	/* Long size string should fail */
235	TEST_NPARSE("u:__test_event char[0x0000000000001] a");
236}
237
238TEST_F(user, loc_types) {
239	/* All should work */
240	TEST_PARSE("u:__test_event __data_loc char[] a");
241	TEST_PARSE("u:__test_event __data_loc unsigned char[] a");
242	TEST_PARSE("u:__test_event __rel_loc char[] a");
243	TEST_PARSE("u:__test_event __rel_loc unsigned char[] a");
244}
245
246TEST_F(user, size_types) {
247	/* Should work */
248	TEST_PARSE("u:__test_event struct custom a 20");
249	/* Size not specified on struct should fail */
250	TEST_NPARSE("u:__test_event struct custom a");
251	/* Size specified on non-struct should fail */
252	TEST_NPARSE("u:__test_event char a 20");
253}
254
255TEST_F(user, matching) {
256	/* Single name matches */
257	TEST_MATCH("__test_event u32 a",
258		   "__test_event u32 a");
259
260	/* Multiple names match */
261	TEST_MATCH("__test_event u32 a; u32 b",
262		   "__test_event u32 a; u32 b");
263
264	/* Multiple names match with dangling ; */
265	TEST_MATCH("__test_event u32 a; u32 b",
266		   "__test_event u32 a; u32 b;");
267
268	/* Single name doesn't match */
269	TEST_NMATCH("__test_event u32 a",
270		    "__test_event u32 b");
271
272	/* Multiple names don't match */
273	TEST_NMATCH("__test_event u32 a; u32 b",
274		    "__test_event u32 b; u32 a");
275
276	/* Types don't match */
277	TEST_NMATCH("__test_event u64 a; u64 b",
278		    "__test_event u32 a; u32 b");
279
280	/* Struct name and size matches */
281	TEST_MATCH("__test_event struct my_struct a 20",
282		   "__test_event struct my_struct a 20");
283
284	/* Struct name don't match */
285	TEST_NMATCH("__test_event struct my_struct a 20",
286		    "__test_event struct my_struct b 20");
287
288	/* Struct size don't match */
289	TEST_NMATCH("__test_event struct my_struct a 20",
290		    "__test_event struct my_struct a 21");
291}
292
293int main(int argc, char **argv)
294{
295	return test_harness_run(argc, argv);
296}
~/ Read-only file preview.