Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
19const char *abi_file = "/sys/kernel/tracing/user_events_data";
20const char *enable_file = "/sys/kernel/tracing/events/user_events/__test_event/enable";
21
22static 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
39static 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, ®) == -1)
50 return -1;
51
52 return 0;
53}
54
55static 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
66static 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
92static 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;
115cleanup:
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) \
127do { \
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) \
134do { \
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
144FIXTURE(user) {
145 int check;
146};
147
148FIXTURE_SETUP(user) {
149}
150
151FIXTURE_TEARDOWN(user) {
152 wait_for_delete();
153}
154
155TEST_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
179TEST_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
187TEST_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
196TEST_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
222int main(int argc, char **argv)
223{
224 return test_harness_run(argc, argv);
225}