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 19 const char *abi_file = "/sys/kernel/tracing/user_events_data"; 20 const char *enable_file = "/sys/kernel/tracing/events/user_events/__test_event/enable"; 21 22 static 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 39 static 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 55 static 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 66 static 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 92 static 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; 115 cleanup: 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) \ 127 do { \ 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) \ 134 do { \ 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 144 FIXTURE(user) { 145 int check; 146 }; 147 148 FIXTURE_SETUP(user) { 149 } 150 151 FIXTURE_TEARDOWN(user) { 152 wait_for_delete(); 153 } 154 155 TEST_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 179 TEST_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 187 TEST_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 196 TEST_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 222 int main(int argc, char **argv) 223 { 224 return test_harness_run(argc, argv); 225 } 226