0001
0002
0003
0004
0005
0006
0007
0008 #include <errno.h>
0009 #include <linux/user_events.h>
0010 #include <linux/perf_event.h>
0011 #include <stdio.h>
0012 #include <stdlib.h>
0013 #include <fcntl.h>
0014 #include <sys/ioctl.h>
0015 #include <sys/stat.h>
0016 #include <unistd.h>
0017 #include <asm/unistd.h>
0018
0019 #include "../kselftest_harness.h"
0020
0021 const char *data_file = "/sys/kernel/debug/tracing/user_events_data";
0022 const char *status_file = "/sys/kernel/debug/tracing/user_events_status";
0023 const char *id_file = "/sys/kernel/debug/tracing/events/user_events/__test_event/id";
0024 const char *fmt_file = "/sys/kernel/debug/tracing/events/user_events/__test_event/format";
0025
0026 struct event {
0027 __u32 index;
0028 __u32 field1;
0029 __u32 field2;
0030 };
0031
0032 static long perf_event_open(struct perf_event_attr *pe, pid_t pid,
0033 int cpu, int group_fd, unsigned long flags)
0034 {
0035 return syscall(__NR_perf_event_open, pe, pid, cpu, group_fd, flags);
0036 }
0037
0038 static int get_id(void)
0039 {
0040 FILE *fp = fopen(id_file, "r");
0041 int ret, id = 0;
0042
0043 if (!fp)
0044 return -1;
0045
0046 ret = fscanf(fp, "%d", &id);
0047 fclose(fp);
0048
0049 if (ret != 1)
0050 return -1;
0051
0052 return id;
0053 }
0054
0055 static int get_offset(void)
0056 {
0057 FILE *fp = fopen(fmt_file, "r");
0058 int ret, c, last = 0, offset = 0;
0059
0060 if (!fp)
0061 return -1;
0062
0063
0064 while (true) {
0065 c = getc(fp);
0066
0067 if (c == EOF)
0068 break;
0069
0070 if (last == '\n' && c == '\n')
0071 break;
0072
0073 last = c;
0074 }
0075
0076 ret = fscanf(fp, "\tfield:u32 field1;\toffset:%d;", &offset);
0077 fclose(fp);
0078
0079 if (ret != 1)
0080 return -1;
0081
0082 return offset;
0083 }
0084
0085 FIXTURE(user) {
0086 int status_fd;
0087 int data_fd;
0088 };
0089
0090 FIXTURE_SETUP(user) {
0091 self->status_fd = open(status_file, O_RDONLY);
0092 ASSERT_NE(-1, self->status_fd);
0093
0094 self->data_fd = open(data_file, O_RDWR);
0095 ASSERT_NE(-1, self->data_fd);
0096 }
0097
0098 FIXTURE_TEARDOWN(user) {
0099 close(self->status_fd);
0100 close(self->data_fd);
0101 }
0102
0103 TEST_F(user, perf_write) {
0104 struct perf_event_attr pe = {0};
0105 struct user_reg reg = {0};
0106 int page_size = sysconf(_SC_PAGESIZE);
0107 char *status_page;
0108 struct event event;
0109 struct perf_event_mmap_page *perf_page;
0110 int id, fd, offset;
0111 __u32 *val;
0112
0113 reg.size = sizeof(reg);
0114 reg.name_args = (__u64)"__test_event u32 field1; u32 field2";
0115
0116 status_page = mmap(NULL, page_size, PROT_READ, MAP_SHARED,
0117 self->status_fd, 0);
0118 ASSERT_NE(MAP_FAILED, status_page);
0119
0120
0121 ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®));
0122 ASSERT_EQ(0, reg.write_index);
0123 ASSERT_NE(0, reg.status_index);
0124 ASSERT_EQ(0, status_page[reg.status_index]);
0125
0126
0127 id = get_id();
0128 ASSERT_NE(-1, id);
0129 offset = get_offset();
0130 ASSERT_NE(-1, offset);
0131
0132 pe.type = PERF_TYPE_TRACEPOINT;
0133 pe.size = sizeof(pe);
0134 pe.config = id;
0135 pe.sample_type = PERF_SAMPLE_RAW;
0136 pe.sample_period = 1;
0137 pe.wakeup_events = 1;
0138
0139
0140 fd = perf_event_open(&pe, 0, -1, -1, 0);
0141 ASSERT_NE(-1, fd);
0142
0143 perf_page = mmap(NULL, page_size * 2, PROT_READ, MAP_SHARED, fd, 0);
0144 ASSERT_NE(MAP_FAILED, perf_page);
0145
0146
0147 ASSERT_EQ(EVENT_STATUS_PERF, status_page[reg.status_index]);
0148
0149 event.index = reg.write_index;
0150 event.field1 = 0xc001;
0151 event.field2 = 0xc01a;
0152
0153
0154 ASSERT_NE(-1, write(self->data_fd, &event, sizeof(event)));
0155 val = (void *)(((char *)perf_page) + perf_page->data_offset);
0156 ASSERT_EQ(PERF_RECORD_SAMPLE, *val);
0157
0158 val += 3;
0159 val = (void *)((char *)val) + offset;
0160
0161 ASSERT_EQ(event.field1, *val++);
0162 ASSERT_EQ(event.field2, *val++);
0163 }
0164
0165 int main(int argc, char **argv)
0166 {
0167 return test_harness_run(argc, argv);
0168 }