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 *abi_file = "/sys/kernel/tracing/user_events_data"; 21const char *enable_file = "/sys/kernel/tracing/events/user_events/__test_event/enable"; 22 23static 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 40static 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 56static 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 67static 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 93static 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; 116cleanup: 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) \ 128do { \ 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) \ 135do { \ 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 145FIXTURE(user) { 146 int check; 147 bool umount; 148}; 149 150FIXTURE_SETUP(user) { 151 USER_EVENT_FIXTURE_SETUP(return, self->umount); 152} 153 154FIXTURE_TEARDOWN(user) { 155 USER_EVENT_FIXTURE_TEARDOWN(self->umount); 156 157 wait_for_delete(); 158} 159 160TEST_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 184TEST_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 192TEST_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 201TEST_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 239int main(int argc, char **argv) 240{ 241 return test_harness_run(argc, argv); 242} 243