162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * User Events FTrace 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 <sys/uio.h> 1662306a36Sopenharmony_ci#include <unistd.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "../kselftest_harness.h" 1962306a36Sopenharmony_ci#include "user_events_selftests.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciconst char *data_file = "/sys/kernel/tracing/user_events_data"; 2262306a36Sopenharmony_ciconst char *status_file = "/sys/kernel/tracing/user_events_status"; 2362306a36Sopenharmony_ciconst char *enable_file = "/sys/kernel/tracing/events/user_events/__test_event/enable"; 2462306a36Sopenharmony_ciconst char *trace_file = "/sys/kernel/tracing/trace"; 2562306a36Sopenharmony_ciconst char *fmt_file = "/sys/kernel/tracing/events/user_events/__test_event/format"; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int trace_bytes(void) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci int fd = open(trace_file, O_RDONLY); 3062306a36Sopenharmony_ci char buf[256]; 3162306a36Sopenharmony_ci int bytes = 0, got; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci if (fd == -1) 3462306a36Sopenharmony_ci return -1; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci while (true) { 3762306a36Sopenharmony_ci got = read(fd, buf, sizeof(buf)); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (got == -1) 4062306a36Sopenharmony_ci return -1; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (got == 0) 4362306a36Sopenharmony_ci break; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci bytes += got; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci close(fd); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci return bytes; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int skip_until_empty_line(FILE *fp) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci int c, last = 0; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci while (true) { 5862306a36Sopenharmony_ci c = getc(fp); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (c == EOF) 6162306a36Sopenharmony_ci break; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (last == '\n' && c == '\n') 6462306a36Sopenharmony_ci return 0; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci last = c; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return -1; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int get_print_fmt(char *buffer, int len) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci FILE *fp = fopen(fmt_file, "r"); 7562306a36Sopenharmony_ci char *newline; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (!fp) 7862306a36Sopenharmony_ci return -1; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* Read until empty line (Skip Common) */ 8162306a36Sopenharmony_ci if (skip_until_empty_line(fp) < 0) 8262306a36Sopenharmony_ci goto err; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* Read until empty line (Skip Properties) */ 8562306a36Sopenharmony_ci if (skip_until_empty_line(fp) < 0) 8662306a36Sopenharmony_ci goto err; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* Read in print_fmt: */ 8962306a36Sopenharmony_ci if (fgets(buffer, len, fp) == NULL) 9062306a36Sopenharmony_ci goto err; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci newline = strchr(buffer, '\n'); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (newline) 9562306a36Sopenharmony_ci *newline = '\0'; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci fclose(fp); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_cierr: 10162306a36Sopenharmony_ci fclose(fp); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return -1; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic bool wait_for_delete(void) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci int i; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci for (i = 0; i < 1000; ++i) { 11162306a36Sopenharmony_ci int fd = open(enable_file, O_RDONLY); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (fd == -1) 11462306a36Sopenharmony_ci return true; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci close(fd); 11762306a36Sopenharmony_ci usleep(1000); 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci return false; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int clear(int *check) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct user_unreg unreg = {0}; 12662306a36Sopenharmony_ci int fd; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci unreg.size = sizeof(unreg); 12962306a36Sopenharmony_ci unreg.disable_bit = 31; 13062306a36Sopenharmony_ci unreg.disable_addr = (__u64)check; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci fd = open(data_file, O_RDWR); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (fd == -1) 13562306a36Sopenharmony_ci return -1; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (ioctl(fd, DIAG_IOCSUNREG, &unreg) == -1) 13862306a36Sopenharmony_ci if (errno != ENOENT) 13962306a36Sopenharmony_ci goto fail; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (ioctl(fd, DIAG_IOCSDEL, "__test_event") == -1) { 14262306a36Sopenharmony_ci if (errno == EBUSY) { 14362306a36Sopenharmony_ci if (!wait_for_delete()) 14462306a36Sopenharmony_ci goto fail; 14562306a36Sopenharmony_ci } else if (errno != ENOENT) 14662306a36Sopenharmony_ci goto fail; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci close(fd); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_cifail: 15362306a36Sopenharmony_ci close(fd); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return -1; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int check_print_fmt(const char *event, const char *expected, int *check) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct user_reg reg = {0}; 16162306a36Sopenharmony_ci char print_fmt[256]; 16262306a36Sopenharmony_ci int ret; 16362306a36Sopenharmony_ci int fd; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Ensure cleared */ 16662306a36Sopenharmony_ci ret = clear(check); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (ret != 0) 16962306a36Sopenharmony_ci return ret; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci fd = open(data_file, O_RDWR); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (fd == -1) 17462306a36Sopenharmony_ci return fd; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci reg.size = sizeof(reg); 17762306a36Sopenharmony_ci reg.name_args = (__u64)event; 17862306a36Sopenharmony_ci reg.enable_bit = 31; 17962306a36Sopenharmony_ci reg.enable_addr = (__u64)check; 18062306a36Sopenharmony_ci reg.enable_size = sizeof(*check); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* Register should work */ 18362306a36Sopenharmony_ci ret = ioctl(fd, DIAG_IOCSREG, ®); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (ret != 0) { 18662306a36Sopenharmony_ci close(fd); 18762306a36Sopenharmony_ci printf("Reg failed in fmt\n"); 18862306a36Sopenharmony_ci return ret; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* Ensure correct print_fmt */ 19262306a36Sopenharmony_ci ret = get_print_fmt(print_fmt, sizeof(print_fmt)); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci close(fd); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (ret != 0) 19762306a36Sopenharmony_ci return ret; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci return strcmp(print_fmt, expected); 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ciFIXTURE(user) { 20362306a36Sopenharmony_ci int status_fd; 20462306a36Sopenharmony_ci int data_fd; 20562306a36Sopenharmony_ci int enable_fd; 20662306a36Sopenharmony_ci int check; 20762306a36Sopenharmony_ci bool umount; 20862306a36Sopenharmony_ci}; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ciFIXTURE_SETUP(user) { 21162306a36Sopenharmony_ci USER_EVENT_FIXTURE_SETUP(return, self->umount); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci self->status_fd = open(status_file, O_RDONLY); 21462306a36Sopenharmony_ci ASSERT_NE(-1, self->status_fd); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci self->data_fd = open(data_file, O_RDWR); 21762306a36Sopenharmony_ci ASSERT_NE(-1, self->data_fd); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci self->enable_fd = -1; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ciFIXTURE_TEARDOWN(user) { 22362306a36Sopenharmony_ci USER_EVENT_FIXTURE_TEARDOWN(self->umount); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci close(self->status_fd); 22662306a36Sopenharmony_ci close(self->data_fd); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (self->enable_fd != -1) { 22962306a36Sopenharmony_ci write(self->enable_fd, "0", sizeof("0")); 23062306a36Sopenharmony_ci close(self->enable_fd); 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (clear(&self->check) != 0) 23462306a36Sopenharmony_ci printf("WARNING: Clear didn't work!\n"); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ciTEST_F(user, register_events) { 23862306a36Sopenharmony_ci struct user_reg reg = {0}; 23962306a36Sopenharmony_ci struct user_unreg unreg = {0}; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci reg.size = sizeof(reg); 24262306a36Sopenharmony_ci reg.name_args = (__u64)"__test_event u32 field1; u32 field2"; 24362306a36Sopenharmony_ci reg.enable_bit = 31; 24462306a36Sopenharmony_ci reg.enable_addr = (__u64)&self->check; 24562306a36Sopenharmony_ci reg.enable_size = sizeof(self->check); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci unreg.size = sizeof(unreg); 24862306a36Sopenharmony_ci unreg.disable_bit = 31; 24962306a36Sopenharmony_ci unreg.disable_addr = (__u64)&self->check; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Register should work */ 25262306a36Sopenharmony_ci ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®)); 25362306a36Sopenharmony_ci ASSERT_EQ(0, reg.write_index); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* Multiple registers to the same addr + bit should fail */ 25662306a36Sopenharmony_ci ASSERT_EQ(-1, ioctl(self->data_fd, DIAG_IOCSREG, ®)); 25762306a36Sopenharmony_ci ASSERT_EQ(EADDRINUSE, errno); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* Multiple registers to same name should result in same index */ 26062306a36Sopenharmony_ci reg.enable_bit = 30; 26162306a36Sopenharmony_ci ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®)); 26262306a36Sopenharmony_ci ASSERT_EQ(0, reg.write_index); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* Multiple registers to same name but different args should fail */ 26562306a36Sopenharmony_ci reg.enable_bit = 29; 26662306a36Sopenharmony_ci reg.name_args = (__u64)"__test_event u32 field1;"; 26762306a36Sopenharmony_ci ASSERT_EQ(-1, ioctl(self->data_fd, DIAG_IOCSREG, ®)); 26862306a36Sopenharmony_ci ASSERT_EQ(EADDRINUSE, errno); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* Ensure disabled */ 27162306a36Sopenharmony_ci self->enable_fd = open(enable_file, O_RDWR); 27262306a36Sopenharmony_ci ASSERT_NE(-1, self->enable_fd); 27362306a36Sopenharmony_ci ASSERT_NE(-1, write(self->enable_fd, "0", sizeof("0"))) 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* Enable event and ensure bits updated in status */ 27662306a36Sopenharmony_ci ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1"))) 27762306a36Sopenharmony_ci ASSERT_EQ(1 << reg.enable_bit, self->check); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* Disable event and ensure bits updated in status */ 28062306a36Sopenharmony_ci ASSERT_NE(-1, write(self->enable_fd, "0", sizeof("0"))) 28162306a36Sopenharmony_ci ASSERT_EQ(0, self->check); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* File still open should return -EBUSY for delete */ 28462306a36Sopenharmony_ci ASSERT_EQ(-1, ioctl(self->data_fd, DIAG_IOCSDEL, "__test_event")); 28562306a36Sopenharmony_ci ASSERT_EQ(EBUSY, errno); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* Unregister */ 28862306a36Sopenharmony_ci ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg)); 28962306a36Sopenharmony_ci unreg.disable_bit = 30; 29062306a36Sopenharmony_ci ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg)); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* Delete should have been auto-done after close and unregister */ 29362306a36Sopenharmony_ci close(self->data_fd); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci ASSERT_EQ(true, wait_for_delete()); 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ciTEST_F(user, write_events) { 29962306a36Sopenharmony_ci struct user_reg reg = {0}; 30062306a36Sopenharmony_ci struct iovec io[3]; 30162306a36Sopenharmony_ci __u32 field1, field2; 30262306a36Sopenharmony_ci int before = 0, after = 0; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci reg.size = sizeof(reg); 30562306a36Sopenharmony_ci reg.name_args = (__u64)"__test_event u32 field1; u32 field2"; 30662306a36Sopenharmony_ci reg.enable_bit = 31; 30762306a36Sopenharmony_ci reg.enable_addr = (__u64)&self->check; 30862306a36Sopenharmony_ci reg.enable_size = sizeof(self->check); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci field1 = 1; 31162306a36Sopenharmony_ci field2 = 2; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci io[0].iov_base = ®.write_index; 31462306a36Sopenharmony_ci io[0].iov_len = sizeof(reg.write_index); 31562306a36Sopenharmony_ci io[1].iov_base = &field1; 31662306a36Sopenharmony_ci io[1].iov_len = sizeof(field1); 31762306a36Sopenharmony_ci io[2].iov_base = &field2; 31862306a36Sopenharmony_ci io[2].iov_len = sizeof(field2); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* Register should work */ 32162306a36Sopenharmony_ci ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®)); 32262306a36Sopenharmony_ci ASSERT_EQ(0, reg.write_index); 32362306a36Sopenharmony_ci ASSERT_EQ(0, self->check); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* Write should fail on invalid slot with ENOENT */ 32662306a36Sopenharmony_ci io[0].iov_base = &field2; 32762306a36Sopenharmony_ci io[0].iov_len = sizeof(field2); 32862306a36Sopenharmony_ci ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3)); 32962306a36Sopenharmony_ci ASSERT_EQ(ENOENT, errno); 33062306a36Sopenharmony_ci io[0].iov_base = ®.write_index; 33162306a36Sopenharmony_ci io[0].iov_len = sizeof(reg.write_index); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* Write should return -EBADF when event is not enabled */ 33462306a36Sopenharmony_ci ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3)); 33562306a36Sopenharmony_ci ASSERT_EQ(EBADF, errno); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* Enable event */ 33862306a36Sopenharmony_ci self->enable_fd = open(enable_file, O_RDWR); 33962306a36Sopenharmony_ci ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1"))) 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* Event should now be enabled */ 34262306a36Sopenharmony_ci ASSERT_NE(1 << reg.enable_bit, self->check); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* Write should make it out to ftrace buffers */ 34562306a36Sopenharmony_ci before = trace_bytes(); 34662306a36Sopenharmony_ci ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 3)); 34762306a36Sopenharmony_ci after = trace_bytes(); 34862306a36Sopenharmony_ci ASSERT_GT(after, before); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* Negative index should fail with EINVAL */ 35162306a36Sopenharmony_ci reg.write_index = -1; 35262306a36Sopenharmony_ci ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3)); 35362306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ciTEST_F(user, write_empty_events) { 35762306a36Sopenharmony_ci struct user_reg reg = {0}; 35862306a36Sopenharmony_ci struct iovec io[1]; 35962306a36Sopenharmony_ci int before = 0, after = 0; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci reg.size = sizeof(reg); 36262306a36Sopenharmony_ci reg.name_args = (__u64)"__test_event"; 36362306a36Sopenharmony_ci reg.enable_bit = 31; 36462306a36Sopenharmony_ci reg.enable_addr = (__u64)&self->check; 36562306a36Sopenharmony_ci reg.enable_size = sizeof(self->check); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci io[0].iov_base = ®.write_index; 36862306a36Sopenharmony_ci io[0].iov_len = sizeof(reg.write_index); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* Register should work */ 37162306a36Sopenharmony_ci ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®)); 37262306a36Sopenharmony_ci ASSERT_EQ(0, reg.write_index); 37362306a36Sopenharmony_ci ASSERT_EQ(0, self->check); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* Enable event */ 37662306a36Sopenharmony_ci self->enable_fd = open(enable_file, O_RDWR); 37762306a36Sopenharmony_ci ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1"))) 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* Event should now be enabled */ 38062306a36Sopenharmony_ci ASSERT_EQ(1 << reg.enable_bit, self->check); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* Write should make it out to ftrace buffers */ 38362306a36Sopenharmony_ci before = trace_bytes(); 38462306a36Sopenharmony_ci ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 1)); 38562306a36Sopenharmony_ci after = trace_bytes(); 38662306a36Sopenharmony_ci ASSERT_GT(after, before); 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ciTEST_F(user, write_fault) { 39062306a36Sopenharmony_ci struct user_reg reg = {0}; 39162306a36Sopenharmony_ci struct iovec io[2]; 39262306a36Sopenharmony_ci int l = sizeof(__u64); 39362306a36Sopenharmony_ci void *anon; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci reg.size = sizeof(reg); 39662306a36Sopenharmony_ci reg.name_args = (__u64)"__test_event u64 anon"; 39762306a36Sopenharmony_ci reg.enable_bit = 31; 39862306a36Sopenharmony_ci reg.enable_addr = (__u64)&self->check; 39962306a36Sopenharmony_ci reg.enable_size = sizeof(self->check); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci anon = mmap(NULL, l, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 40262306a36Sopenharmony_ci ASSERT_NE(MAP_FAILED, anon); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci io[0].iov_base = ®.write_index; 40562306a36Sopenharmony_ci io[0].iov_len = sizeof(reg.write_index); 40662306a36Sopenharmony_ci io[1].iov_base = anon; 40762306a36Sopenharmony_ci io[1].iov_len = l; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* Register should work */ 41062306a36Sopenharmony_ci ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®)); 41162306a36Sopenharmony_ci ASSERT_EQ(0, reg.write_index); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* Enable event */ 41462306a36Sopenharmony_ci self->enable_fd = open(enable_file, O_RDWR); 41562306a36Sopenharmony_ci ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1"))) 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci /* Write should work normally */ 41862306a36Sopenharmony_ci ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 2)); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* Faulted data should zero fill and work */ 42162306a36Sopenharmony_ci ASSERT_EQ(0, madvise(anon, l, MADV_DONTNEED)); 42262306a36Sopenharmony_ci ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 2)); 42362306a36Sopenharmony_ci ASSERT_EQ(0, munmap(anon, l)); 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ciTEST_F(user, write_validator) { 42762306a36Sopenharmony_ci struct user_reg reg = {0}; 42862306a36Sopenharmony_ci struct iovec io[3]; 42962306a36Sopenharmony_ci int loc, bytes; 43062306a36Sopenharmony_ci char data[8]; 43162306a36Sopenharmony_ci int before = 0, after = 0; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci reg.size = sizeof(reg); 43462306a36Sopenharmony_ci reg.name_args = (__u64)"__test_event __rel_loc char[] data"; 43562306a36Sopenharmony_ci reg.enable_bit = 31; 43662306a36Sopenharmony_ci reg.enable_addr = (__u64)&self->check; 43762306a36Sopenharmony_ci reg.enable_size = sizeof(self->check); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* Register should work */ 44062306a36Sopenharmony_ci ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®)); 44162306a36Sopenharmony_ci ASSERT_EQ(0, reg.write_index); 44262306a36Sopenharmony_ci ASSERT_EQ(0, self->check); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci io[0].iov_base = ®.write_index; 44562306a36Sopenharmony_ci io[0].iov_len = sizeof(reg.write_index); 44662306a36Sopenharmony_ci io[1].iov_base = &loc; 44762306a36Sopenharmony_ci io[1].iov_len = sizeof(loc); 44862306a36Sopenharmony_ci io[2].iov_base = data; 44962306a36Sopenharmony_ci bytes = snprintf(data, sizeof(data), "Test") + 1; 45062306a36Sopenharmony_ci io[2].iov_len = bytes; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* Undersized write should fail */ 45362306a36Sopenharmony_ci ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 1)); 45462306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* Enable event */ 45762306a36Sopenharmony_ci self->enable_fd = open(enable_file, O_RDWR); 45862306a36Sopenharmony_ci ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1"))) 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* Event should now be enabled */ 46162306a36Sopenharmony_ci ASSERT_EQ(1 << reg.enable_bit, self->check); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* Full in-bounds write should work */ 46462306a36Sopenharmony_ci before = trace_bytes(); 46562306a36Sopenharmony_ci loc = DYN_LOC(0, bytes); 46662306a36Sopenharmony_ci ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 3)); 46762306a36Sopenharmony_ci after = trace_bytes(); 46862306a36Sopenharmony_ci ASSERT_GT(after, before); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* Out of bounds write should fault (offset way out) */ 47162306a36Sopenharmony_ci loc = DYN_LOC(1024, bytes); 47262306a36Sopenharmony_ci ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3)); 47362306a36Sopenharmony_ci ASSERT_EQ(EFAULT, errno); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* Out of bounds write should fault (offset 1 byte out) */ 47662306a36Sopenharmony_ci loc = DYN_LOC(1, bytes); 47762306a36Sopenharmony_ci ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3)); 47862306a36Sopenharmony_ci ASSERT_EQ(EFAULT, errno); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* Out of bounds write should fault (size way out) */ 48162306a36Sopenharmony_ci loc = DYN_LOC(0, bytes + 1024); 48262306a36Sopenharmony_ci ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3)); 48362306a36Sopenharmony_ci ASSERT_EQ(EFAULT, errno); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* Out of bounds write should fault (size 1 byte out) */ 48662306a36Sopenharmony_ci loc = DYN_LOC(0, bytes + 1); 48762306a36Sopenharmony_ci ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3)); 48862306a36Sopenharmony_ci ASSERT_EQ(EFAULT, errno); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* Non-Null should fault */ 49162306a36Sopenharmony_ci memset(data, 'A', sizeof(data)); 49262306a36Sopenharmony_ci loc = DYN_LOC(0, bytes); 49362306a36Sopenharmony_ci ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3)); 49462306a36Sopenharmony_ci ASSERT_EQ(EFAULT, errno); 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ciTEST_F(user, print_fmt) { 49862306a36Sopenharmony_ci int ret; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci ret = check_print_fmt("__test_event __rel_loc char[] data", 50162306a36Sopenharmony_ci "print fmt: \"data=%s\", __get_rel_str(data)", 50262306a36Sopenharmony_ci &self->check); 50362306a36Sopenharmony_ci ASSERT_EQ(0, ret); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci ret = check_print_fmt("__test_event __data_loc char[] data", 50662306a36Sopenharmony_ci "print fmt: \"data=%s\", __get_str(data)", 50762306a36Sopenharmony_ci &self->check); 50862306a36Sopenharmony_ci ASSERT_EQ(0, ret); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci ret = check_print_fmt("__test_event s64 data", 51162306a36Sopenharmony_ci "print fmt: \"data=%lld\", REC->data", 51262306a36Sopenharmony_ci &self->check); 51362306a36Sopenharmony_ci ASSERT_EQ(0, ret); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci ret = check_print_fmt("__test_event u64 data", 51662306a36Sopenharmony_ci "print fmt: \"data=%llu\", REC->data", 51762306a36Sopenharmony_ci &self->check); 51862306a36Sopenharmony_ci ASSERT_EQ(0, ret); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci ret = check_print_fmt("__test_event s32 data", 52162306a36Sopenharmony_ci "print fmt: \"data=%d\", REC->data", 52262306a36Sopenharmony_ci &self->check); 52362306a36Sopenharmony_ci ASSERT_EQ(0, ret); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci ret = check_print_fmt("__test_event u32 data", 52662306a36Sopenharmony_ci "print fmt: \"data=%u\", REC->data", 52762306a36Sopenharmony_ci &self->check); 52862306a36Sopenharmony_ci ASSERT_EQ(0, ret); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci ret = check_print_fmt("__test_event int data", 53162306a36Sopenharmony_ci "print fmt: \"data=%d\", REC->data", 53262306a36Sopenharmony_ci &self->check); 53362306a36Sopenharmony_ci ASSERT_EQ(0, ret); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci ret = check_print_fmt("__test_event unsigned int data", 53662306a36Sopenharmony_ci "print fmt: \"data=%u\", REC->data", 53762306a36Sopenharmony_ci &self->check); 53862306a36Sopenharmony_ci ASSERT_EQ(0, ret); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci ret = check_print_fmt("__test_event s16 data", 54162306a36Sopenharmony_ci "print fmt: \"data=%d\", REC->data", 54262306a36Sopenharmony_ci &self->check); 54362306a36Sopenharmony_ci ASSERT_EQ(0, ret); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci ret = check_print_fmt("__test_event u16 data", 54662306a36Sopenharmony_ci "print fmt: \"data=%u\", REC->data", 54762306a36Sopenharmony_ci &self->check); 54862306a36Sopenharmony_ci ASSERT_EQ(0, ret); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci ret = check_print_fmt("__test_event short data", 55162306a36Sopenharmony_ci "print fmt: \"data=%d\", REC->data", 55262306a36Sopenharmony_ci &self->check); 55362306a36Sopenharmony_ci ASSERT_EQ(0, ret); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci ret = check_print_fmt("__test_event unsigned short data", 55662306a36Sopenharmony_ci "print fmt: \"data=%u\", REC->data", 55762306a36Sopenharmony_ci &self->check); 55862306a36Sopenharmony_ci ASSERT_EQ(0, ret); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci ret = check_print_fmt("__test_event s8 data", 56162306a36Sopenharmony_ci "print fmt: \"data=%d\", REC->data", 56262306a36Sopenharmony_ci &self->check); 56362306a36Sopenharmony_ci ASSERT_EQ(0, ret); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci ret = check_print_fmt("__test_event u8 data", 56662306a36Sopenharmony_ci "print fmt: \"data=%u\", REC->data", 56762306a36Sopenharmony_ci &self->check); 56862306a36Sopenharmony_ci ASSERT_EQ(0, ret); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci ret = check_print_fmt("__test_event char data", 57162306a36Sopenharmony_ci "print fmt: \"data=%d\", REC->data", 57262306a36Sopenharmony_ci &self->check); 57362306a36Sopenharmony_ci ASSERT_EQ(0, ret); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci ret = check_print_fmt("__test_event unsigned char data", 57662306a36Sopenharmony_ci "print fmt: \"data=%u\", REC->data", 57762306a36Sopenharmony_ci &self->check); 57862306a36Sopenharmony_ci ASSERT_EQ(0, ret); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci ret = check_print_fmt("__test_event char[4] data", 58162306a36Sopenharmony_ci "print fmt: \"data=%s\", REC->data", 58262306a36Sopenharmony_ci &self->check); 58362306a36Sopenharmony_ci ASSERT_EQ(0, ret); 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ciint main(int argc, char **argv) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci return test_harness_run(argc, argv); 58962306a36Sopenharmony_ci} 590