linux-zen-desktop/tools/testing/selftests/user_events/dyn_test.c

238 lines
5.2 KiB
C
Raw Normal View History

2023-08-30 16:31:07 +01:00
// SPDX-License-Identifier: GPL-2.0
/*
* User Events Dyn Events Test Program
*
* Copyright (c) 2021 Beau Belgrave <beaub@linux.microsoft.com>
*/
#include <errno.h>
#include <linux/user_events.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <unistd.h>
#include "../kselftest_harness.h"
2023-10-24 11:59:35 +01:00
const char *abi_file = "/sys/kernel/tracing/user_events_data";
const char *enable_file = "/sys/kernel/tracing/events/user_events/__test_event/enable";
2023-08-30 16:31:07 +01:00
2023-10-24 11:59:35 +01:00
static bool wait_for_delete(void)
2023-08-30 16:31:07 +01:00
{
2023-10-24 11:59:35 +01:00
int i;
for (i = 0; i < 1000; ++i) {
int fd = open(enable_file, O_RDONLY);
if (fd == -1)
return true;
close(fd);
usleep(1000);
}
return false;
}
static int reg_event(int fd, int *check, int bit, const char *value)
{
struct user_reg reg = {0};
reg.size = sizeof(reg);
reg.name_args = (__u64)value;
reg.enable_bit = bit;
reg.enable_addr = (__u64)check;
reg.enable_size = sizeof(*check);
if (ioctl(fd, DIAG_IOCSREG, &reg) == -1)
return -1;
return 0;
}
static int unreg_event(int fd, int *check, int bit)
{
struct user_unreg unreg = {0};
unreg.size = sizeof(unreg);
unreg.disable_bit = bit;
unreg.disable_addr = (__u64)check;
return ioctl(fd, DIAG_IOCSUNREG, &unreg);
}
static int parse(int *check, const char *value)
{
int fd = open(abi_file, O_RDWR);
int ret;
if (fd == -1)
return -1;
/* Until we have persist flags via dynamic events, use the base name */
if (value[0] != 'u' || value[1] != ':') {
close(fd);
return -1;
}
ret = reg_event(fd, check, 31, value + 2);
if (ret != -1) {
if (unreg_event(fd, check, 31) == -1)
printf("WARN: Couldn't unreg event\n");
}
close(fd);
return ret;
}
static int check_match(int *check, const char *first, const char *second, bool *match)
{
int fd = open(abi_file, O_RDWR);
int ret = -1;
if (fd == -1)
return -1;
if (reg_event(fd, check, 31, first) == -1)
goto cleanup;
if (reg_event(fd, check, 30, second) == -1) {
if (errno == EADDRINUSE) {
/* Name is in use, with different fields */
*match = false;
ret = 0;
}
goto cleanup;
}
*match = true;
ret = 0;
cleanup:
unreg_event(fd, check, 31);
unreg_event(fd, check, 30);
2023-08-30 16:31:07 +01:00
close(fd);
2023-10-24 11:59:35 +01:00
wait_for_delete();
2023-08-30 16:31:07 +01:00
return ret;
}
2023-10-24 11:59:35 +01:00
#define TEST_MATCH(x, y) \
2023-08-30 16:31:07 +01:00
do { \
2023-10-24 11:59:35 +01:00
bool match; \
ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
ASSERT_EQ(true, match); \
2023-08-30 16:31:07 +01:00
} while (0)
2023-10-24 11:59:35 +01:00
#define TEST_NMATCH(x, y) \
2023-08-30 16:31:07 +01:00
do { \
2023-10-24 11:59:35 +01:00
bool match; \
ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
ASSERT_EQ(false, match); \
2023-08-30 16:31:07 +01:00
} while (0)
2023-10-24 11:59:35 +01:00
#define TEST_PARSE(x) ASSERT_NE(-1, parse(&self->check, x))
#define TEST_NPARSE(x) ASSERT_EQ(-1, parse(&self->check, x))
2023-08-30 16:31:07 +01:00
FIXTURE(user) {
2023-10-24 11:59:35 +01:00
int check;
2023-08-30 16:31:07 +01:00
};
FIXTURE_SETUP(user) {
}
FIXTURE_TEARDOWN(user) {
2023-10-24 11:59:35 +01:00
wait_for_delete();
2023-08-30 16:31:07 +01:00
}
TEST_F(user, basic_types) {
/* All should work */
TEST_PARSE("u:__test_event u64 a");
TEST_PARSE("u:__test_event u32 a");
TEST_PARSE("u:__test_event u16 a");
TEST_PARSE("u:__test_event u8 a");
TEST_PARSE("u:__test_event char a");
TEST_PARSE("u:__test_event unsigned char a");
TEST_PARSE("u:__test_event int a");
TEST_PARSE("u:__test_event unsigned int a");
TEST_PARSE("u:__test_event short a");
TEST_PARSE("u:__test_event unsigned short a");
TEST_PARSE("u:__test_event char[20] a");
TEST_PARSE("u:__test_event unsigned char[20] a");
TEST_PARSE("u:__test_event char[0x14] a");
TEST_PARSE("u:__test_event unsigned char[0x14] a");
/* Bad size format should fail */
TEST_NPARSE("u:__test_event char[aa] a");
/* Large size should fail */
TEST_NPARSE("u:__test_event char[9999] a");
/* Long size string should fail */
TEST_NPARSE("u:__test_event char[0x0000000000001] a");
}
TEST_F(user, loc_types) {
/* All should work */
TEST_PARSE("u:__test_event __data_loc char[] a");
TEST_PARSE("u:__test_event __data_loc unsigned char[] a");
TEST_PARSE("u:__test_event __rel_loc char[] a");
TEST_PARSE("u:__test_event __rel_loc unsigned char[] a");
}
TEST_F(user, size_types) {
/* Should work */
TEST_PARSE("u:__test_event struct custom a 20");
/* Size not specified on struct should fail */
TEST_NPARSE("u:__test_event struct custom a");
/* Size specified on non-struct should fail */
TEST_NPARSE("u:__test_event char a 20");
}
TEST_F(user, matching) {
2023-10-24 11:59:35 +01:00
/* Single name matches */
TEST_MATCH("__test_event u32 a",
"__test_event u32 a");
/* Multiple names match */
TEST_MATCH("__test_event u32 a; u32 b",
"__test_event u32 a; u32 b");
/* Multiple names match with dangling ; */
TEST_MATCH("__test_event u32 a; u32 b",
"__test_event u32 a; u32 b;");
/* Single name doesn't match */
TEST_NMATCH("__test_event u32 a",
"__test_event u32 b");
/* Multiple names don't match */
TEST_NMATCH("__test_event u32 a; u32 b",
"__test_event u32 b; u32 a");
/* Types don't match */
TEST_NMATCH("__test_event u64 a; u64 b",
"__test_event u32 a; u32 b");
/* Struct name and size matches */
TEST_MATCH("__test_event struct my_struct a 20",
"__test_event struct my_struct a 20");
/* Struct name don't match */
TEST_NMATCH("__test_event struct my_struct a 20",
"__test_event struct my_struct b 20");
/* Struct size don't match */
TEST_NMATCH("__test_event struct my_struct a 20",
"__test_event struct my_struct a 21");
2023-08-30 16:31:07 +01:00
}
int main(int argc, char **argv)
{
return test_harness_run(argc, argv);
}