162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * User Events Dyn Events Test Program 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2021 Beau Belgrave <beaub@linux.microsoft.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <errno.h> 962306a36Sopenharmony_ci#include <linux/user_events.h> 1062306a36Sopenharmony_ci#include <stdio.h> 1162306a36Sopenharmony_ci#include <stdlib.h> 1262306a36Sopenharmony_ci#include <fcntl.h> 1362306a36Sopenharmony_ci#include <sys/ioctl.h> 1462306a36Sopenharmony_ci#include <sys/stat.h> 1562306a36Sopenharmony_ci#include <unistd.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "../kselftest_harness.h" 1862306a36Sopenharmony_ci#include "user_events_selftests.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ciconst char *abi_file = "/sys/kernel/tracing/user_events_data"; 2162306a36Sopenharmony_ciconst char *enable_file = "/sys/kernel/tracing/events/user_events/__test_event/enable"; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic bool wait_for_delete(void) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci int i; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci for (i = 0; i < 1000; ++i) { 2862306a36Sopenharmony_ci int fd = open(enable_file, O_RDONLY); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci if (fd == -1) 3162306a36Sopenharmony_ci return true; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci close(fd); 3462306a36Sopenharmony_ci usleep(1000); 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci return false; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic int reg_event(int fd, int *check, int bit, const char *value) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct user_reg reg = {0}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci reg.size = sizeof(reg); 4562306a36Sopenharmony_ci reg.name_args = (__u64)value; 4662306a36Sopenharmony_ci reg.enable_bit = bit; 4762306a36Sopenharmony_ci reg.enable_addr = (__u64)check; 4862306a36Sopenharmony_ci reg.enable_size = sizeof(*check); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (ioctl(fd, DIAG_IOCSREG, ®) == -1) 5162306a36Sopenharmony_ci return -1; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return 0; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int unreg_event(int fd, int *check, int bit) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct user_unreg unreg = {0}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci unreg.size = sizeof(unreg); 6162306a36Sopenharmony_ci unreg.disable_bit = bit; 6262306a36Sopenharmony_ci unreg.disable_addr = (__u64)check; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci return ioctl(fd, DIAG_IOCSUNREG, &unreg); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int parse(int *check, const char *value) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci int fd = open(abi_file, O_RDWR); 7062306a36Sopenharmony_ci int ret; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (fd == -1) 7362306a36Sopenharmony_ci return -1; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* Until we have persist flags via dynamic events, use the base name */ 7662306a36Sopenharmony_ci if (value[0] != 'u' || value[1] != ':') { 7762306a36Sopenharmony_ci close(fd); 7862306a36Sopenharmony_ci return -1; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci ret = reg_event(fd, check, 31, value + 2); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (ret != -1) { 8462306a36Sopenharmony_ci if (unreg_event(fd, check, 31) == -1) 8562306a36Sopenharmony_ci printf("WARN: Couldn't unreg event\n"); 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci close(fd); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return ret; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int check_match(int *check, const char *first, const char *second, bool *match) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci int fd = open(abi_file, O_RDWR); 9662306a36Sopenharmony_ci int ret = -1; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (fd == -1) 9962306a36Sopenharmony_ci return -1; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (reg_event(fd, check, 31, first) == -1) 10262306a36Sopenharmony_ci goto cleanup; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (reg_event(fd, check, 30, second) == -1) { 10562306a36Sopenharmony_ci if (errno == EADDRINUSE) { 10662306a36Sopenharmony_ci /* Name is in use, with different fields */ 10762306a36Sopenharmony_ci *match = false; 10862306a36Sopenharmony_ci ret = 0; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci goto cleanup; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci *match = true; 11562306a36Sopenharmony_ci ret = 0; 11662306a36Sopenharmony_cicleanup: 11762306a36Sopenharmony_ci unreg_event(fd, check, 31); 11862306a36Sopenharmony_ci unreg_event(fd, check, 30); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci close(fd); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci wait_for_delete(); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return ret; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#define TEST_MATCH(x, y) \ 12862306a36Sopenharmony_cido { \ 12962306a36Sopenharmony_ci bool match; \ 13062306a36Sopenharmony_ci ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \ 13162306a36Sopenharmony_ci ASSERT_EQ(true, match); \ 13262306a36Sopenharmony_ci} while (0) 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci#define TEST_NMATCH(x, y) \ 13562306a36Sopenharmony_cido { \ 13662306a36Sopenharmony_ci bool match; \ 13762306a36Sopenharmony_ci ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \ 13862306a36Sopenharmony_ci ASSERT_EQ(false, match); \ 13962306a36Sopenharmony_ci} while (0) 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci#define TEST_PARSE(x) ASSERT_NE(-1, parse(&self->check, x)) 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci#define TEST_NPARSE(x) ASSERT_EQ(-1, parse(&self->check, x)) 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ciFIXTURE(user) { 14662306a36Sopenharmony_ci int check; 14762306a36Sopenharmony_ci bool umount; 14862306a36Sopenharmony_ci}; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ciFIXTURE_SETUP(user) { 15162306a36Sopenharmony_ci USER_EVENT_FIXTURE_SETUP(return, self->umount); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ciFIXTURE_TEARDOWN(user) { 15562306a36Sopenharmony_ci USER_EVENT_FIXTURE_TEARDOWN(self->umount); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci wait_for_delete(); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ciTEST_F(user, basic_types) { 16162306a36Sopenharmony_ci /* All should work */ 16262306a36Sopenharmony_ci TEST_PARSE("u:__test_event u64 a"); 16362306a36Sopenharmony_ci TEST_PARSE("u:__test_event u32 a"); 16462306a36Sopenharmony_ci TEST_PARSE("u:__test_event u16 a"); 16562306a36Sopenharmony_ci TEST_PARSE("u:__test_event u8 a"); 16662306a36Sopenharmony_ci TEST_PARSE("u:__test_event char a"); 16762306a36Sopenharmony_ci TEST_PARSE("u:__test_event unsigned char a"); 16862306a36Sopenharmony_ci TEST_PARSE("u:__test_event int a"); 16962306a36Sopenharmony_ci TEST_PARSE("u:__test_event unsigned int a"); 17062306a36Sopenharmony_ci TEST_PARSE("u:__test_event short a"); 17162306a36Sopenharmony_ci TEST_PARSE("u:__test_event unsigned short a"); 17262306a36Sopenharmony_ci TEST_PARSE("u:__test_event char[20] a"); 17362306a36Sopenharmony_ci TEST_PARSE("u:__test_event unsigned char[20] a"); 17462306a36Sopenharmony_ci TEST_PARSE("u:__test_event char[0x14] a"); 17562306a36Sopenharmony_ci TEST_PARSE("u:__test_event unsigned char[0x14] a"); 17662306a36Sopenharmony_ci /* Bad size format should fail */ 17762306a36Sopenharmony_ci TEST_NPARSE("u:__test_event char[aa] a"); 17862306a36Sopenharmony_ci /* Large size should fail */ 17962306a36Sopenharmony_ci TEST_NPARSE("u:__test_event char[9999] a"); 18062306a36Sopenharmony_ci /* Long size string should fail */ 18162306a36Sopenharmony_ci TEST_NPARSE("u:__test_event char[0x0000000000001] a"); 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ciTEST_F(user, loc_types) { 18562306a36Sopenharmony_ci /* All should work */ 18662306a36Sopenharmony_ci TEST_PARSE("u:__test_event __data_loc char[] a"); 18762306a36Sopenharmony_ci TEST_PARSE("u:__test_event __data_loc unsigned char[] a"); 18862306a36Sopenharmony_ci TEST_PARSE("u:__test_event __rel_loc char[] a"); 18962306a36Sopenharmony_ci TEST_PARSE("u:__test_event __rel_loc unsigned char[] a"); 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ciTEST_F(user, size_types) { 19362306a36Sopenharmony_ci /* Should work */ 19462306a36Sopenharmony_ci TEST_PARSE("u:__test_event struct custom a 20"); 19562306a36Sopenharmony_ci /* Size not specified on struct should fail */ 19662306a36Sopenharmony_ci TEST_NPARSE("u:__test_event struct custom a"); 19762306a36Sopenharmony_ci /* Size specified on non-struct should fail */ 19862306a36Sopenharmony_ci TEST_NPARSE("u:__test_event char a 20"); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ciTEST_F(user, matching) { 20262306a36Sopenharmony_ci /* Single name matches */ 20362306a36Sopenharmony_ci TEST_MATCH("__test_event u32 a", 20462306a36Sopenharmony_ci "__test_event u32 a"); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* Multiple names match */ 20762306a36Sopenharmony_ci TEST_MATCH("__test_event u32 a; u32 b", 20862306a36Sopenharmony_ci "__test_event u32 a; u32 b"); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* Multiple names match with dangling ; */ 21162306a36Sopenharmony_ci TEST_MATCH("__test_event u32 a; u32 b", 21262306a36Sopenharmony_ci "__test_event u32 a; u32 b;"); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* Single name doesn't match */ 21562306a36Sopenharmony_ci TEST_NMATCH("__test_event u32 a", 21662306a36Sopenharmony_ci "__test_event u32 b"); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* Multiple names don't match */ 21962306a36Sopenharmony_ci TEST_NMATCH("__test_event u32 a; u32 b", 22062306a36Sopenharmony_ci "__test_event u32 b; u32 a"); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* Types don't match */ 22362306a36Sopenharmony_ci TEST_NMATCH("__test_event u64 a; u64 b", 22462306a36Sopenharmony_ci "__test_event u32 a; u32 b"); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* Struct name and size matches */ 22762306a36Sopenharmony_ci TEST_MATCH("__test_event struct my_struct a 20", 22862306a36Sopenharmony_ci "__test_event struct my_struct a 20"); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* Struct name don't match */ 23162306a36Sopenharmony_ci TEST_NMATCH("__test_event struct my_struct a 20", 23262306a36Sopenharmony_ci "__test_event struct my_struct b 20"); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* Struct size don't match */ 23562306a36Sopenharmony_ci TEST_NMATCH("__test_event struct my_struct a 20", 23662306a36Sopenharmony_ci "__test_event struct my_struct a 21"); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ciint main(int argc, char **argv) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci return test_harness_run(argc, argv); 24262306a36Sopenharmony_ci} 243