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, ®) == -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 bool umount; 148 }; 149 150 FIXTURE_SETUP(user) { 151 USER_EVENT_FIXTURE_SETUP(return, self->umount); 152 } 153 154 FIXTURE_TEARDOWN(user) { 155 USER_EVENT_FIXTURE_TEARDOWN(self->umount); 156 157 wait_for_delete(); 158 } 159 160 TEST_F(user, basic_types) { 161 /* All should work */ 162 TEST_PARSE("u:__test_event u64 a"); 163 TEST_PARSE("u:__test_event u32 a"); 164 TEST_PARSE("u:__test_event u16 a"); 165 TEST_PARSE("u:__test_event u8 a"); 166 TEST_PARSE("u:__test_event char a"); 167 TEST_PARSE("u:__test_event unsigned char a"); 168 TEST_PARSE("u:__test_event int a"); 169 TEST_PARSE("u:__test_event unsigned int a"); 170 TEST_PARSE("u:__test_event short a"); 171 TEST_PARSE("u:__test_event unsigned short a"); 172 TEST_PARSE("u:__test_event char[20] a"); 173 TEST_PARSE("u:__test_event unsigned char[20] a"); 174 TEST_PARSE("u:__test_event char[0x14] a"); 175 TEST_PARSE("u:__test_event unsigned char[0x14] a"); 176 /* Bad size format should fail */ 177 TEST_NPARSE("u:__test_event char[aa] a"); 178 /* Large size should fail */ 179 TEST_NPARSE("u:__test_event char[9999] a"); 180 /* Long size string should fail */ 181 TEST_NPARSE("u:__test_event char[0x0000000000001] a"); 182 } 183 184 TEST_F(user, loc_types) { 185 /* All should work */ 186 TEST_PARSE("u:__test_event __data_loc char[] a"); 187 TEST_PARSE("u:__test_event __data_loc unsigned char[] a"); 188 TEST_PARSE("u:__test_event __rel_loc char[] a"); 189 TEST_PARSE("u:__test_event __rel_loc unsigned char[] a"); 190 } 191 192 TEST_F(user, size_types) { 193 /* Should work */ 194 TEST_PARSE("u:__test_event struct custom a 20"); 195 /* Size not specified on struct should fail */ 196 TEST_NPARSE("u:__test_event struct custom a"); 197 /* Size specified on non-struct should fail */ 198 TEST_NPARSE("u:__test_event char a 20"); 199 } 200 201 TEST_F(user, matching) { 202 /* Single name matches */ 203 TEST_MATCH("__test_event u32 a", 204 "__test_event u32 a"); 205 206 /* Multiple names match */ 207 TEST_MATCH("__test_event u32 a; u32 b", 208 "__test_event u32 a; u32 b"); 209 210 /* Multiple names match with dangling ; */ 211 TEST_MATCH("__test_event u32 a; u32 b", 212 "__test_event u32 a; u32 b;"); 213 214 /* Single name doesn't match */ 215 TEST_NMATCH("__test_event u32 a", 216 "__test_event u32 b"); 217 218 /* Multiple names don't match */ 219 TEST_NMATCH("__test_event u32 a; u32 b", 220 "__test_event u32 b; u32 a"); 221 222 /* Types don't match */ 223 TEST_NMATCH("__test_event u64 a; u64 b", 224 "__test_event u32 a; u32 b"); 225 226 /* Struct name and size matches */ 227 TEST_MATCH("__test_event struct my_struct a 20", 228 "__test_event struct my_struct a 20"); 229 230 /* Struct name don't match */ 231 TEST_NMATCH("__test_event struct my_struct a 20", 232 "__test_event struct my_struct b 20"); 233 234 /* Struct size don't match */ 235 TEST_NMATCH("__test_event struct my_struct a 20", 236 "__test_event struct my_struct a 21"); 237 } 238 239 int main(int argc, char **argv) 240 { 241 return test_harness_run(argc, argv); 242 } 243