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, &reg);
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, &reg));
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, &reg));
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, &reg));
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, &reg));
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 = &reg.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, &reg));
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 = &reg.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 = &reg.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, &reg));
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 = &reg.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, &reg));
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, &reg));
44162306a36Sopenharmony_ci	ASSERT_EQ(0, reg.write_index);
44262306a36Sopenharmony_ci	ASSERT_EQ(0, self->check);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	io[0].iov_base = &reg.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