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 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 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 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, ®) == -1) 67 return -1; 68 69 return 0; 70 } 71 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 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 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 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 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 197 FIXTURE(user) { 198 int check; 199 bool umount; 200 }; 201 202 FIXTURE_SETUP(user) { 203 USER_EVENT_FIXTURE_SETUP(return, self->umount); 204 } 205 206 FIXTURE_TEARDOWN(user) { 207 USER_EVENT_FIXTURE_TEARDOWN(self->umount); 208 209 wait_for_delete(); 210 } 211 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 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 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 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 291 int main(int argc, char **argv) 292 { 293 return test_harness_run(argc, argv); 294 } 295
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.