brintos

brintos / linux-shallow public Read only

0
0
Text · 5.0 KiB · 6c17898 Raw
215 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <stdlib.h>3#include <string.h>4#include <unistd.h>5#include <errno.h>6#include <sys/ioctl.h>7#include <linux/compiler.h>8#include <linux/hw_breakpoint.h>9#include <linux/kernel.h>10#include "tests.h"11#include "debug.h"12#include "event.h"13#include "cloexec.h"14#include "../perf-sys.h"15 16#define WP_TEST_ASSERT_VAL(fd, text, val)       \17do {                                            \18	long long count;                        \19	wp_read(fd, &count, sizeof(long long)); \20	TEST_ASSERT_VAL(text, count == val);    \21} while (0)22 23#ifdef __i386__24/* Only breakpoint length less-than 8 has hardware support on i386. */25volatile u32 data1;26#else27volatile u64 data1;28#endif29volatile u8 data2[3];30 31#ifndef __s390x__32static int wp_read(int fd, long long *count, int size)33{34	int ret = read(fd, count, size);35 36	if (ret != size) {37		pr_debug("failed to read: %d\n", ret);38		return -1;39	}40	return 0;41}42 43static void get__perf_event_attr(struct perf_event_attr *attr, int wp_type,44				 void *wp_addr, unsigned long wp_len)45{46	memset(attr, 0, sizeof(struct perf_event_attr));47	attr->type           = PERF_TYPE_BREAKPOINT;48	attr->size           = sizeof(struct perf_event_attr);49	attr->config         = 0;50	attr->bp_type        = wp_type;51	attr->bp_addr        = (unsigned long)wp_addr;52	attr->bp_len         = wp_len;53	attr->sample_period  = 1;54	attr->sample_type    = PERF_SAMPLE_IP;55	attr->exclude_kernel = 1;56	attr->exclude_hv     = 1;57}58 59static int __event(int wp_type, void *wp_addr, unsigned long wp_len)60{61	int fd;62	struct perf_event_attr attr;63 64	get__perf_event_attr(&attr, wp_type, wp_addr, wp_len);65	fd = sys_perf_event_open(&attr, 0, -1, -1,66				 perf_event_open_cloexec_flag());67	if (fd < 0) {68		fd = -errno;69		pr_debug("failed opening event %x\n", attr.bp_type);70	}71 72	return fd;73}74#endif75 76static int test__wp_ro(struct test_suite *test __maybe_unused,77		       int subtest __maybe_unused)78{79#if defined(__s390x__) || defined(__x86_64__) || defined(__i386__)80	return TEST_SKIP;81#else82	int fd;83	unsigned long tmp, tmp1 = rand();84 85	fd = __event(HW_BREAKPOINT_R, (void *)&data1, sizeof(data1));86	if (fd < 0)87		return fd == -ENODEV ? TEST_SKIP : -1;88 89	tmp = data1;90	WP_TEST_ASSERT_VAL(fd, "RO watchpoint", 1);91 92	data1 = tmp1 + tmp;93	WP_TEST_ASSERT_VAL(fd, "RO watchpoint", 1);94 95	close(fd);96	return 0;97#endif98}99 100static int test__wp_wo(struct test_suite *test __maybe_unused,101		       int subtest __maybe_unused)102{103#if defined(__s390x__)104	return TEST_SKIP;105#else106	int fd;107	unsigned long tmp, tmp1 = rand();108 109	fd = __event(HW_BREAKPOINT_W, (void *)&data1, sizeof(data1));110	if (fd < 0)111		return fd == -ENODEV ? TEST_SKIP : -1;112 113	tmp = data1;114	WP_TEST_ASSERT_VAL(fd, "WO watchpoint", 0);115 116	data1 = tmp1 + tmp;117	WP_TEST_ASSERT_VAL(fd, "WO watchpoint", 1);118 119	close(fd);120	return 0;121#endif122}123 124static int test__wp_rw(struct test_suite *test __maybe_unused,125		       int subtest __maybe_unused)126{127#if defined(__s390x__)128	return TEST_SKIP;129#else130	int fd;131	unsigned long tmp, tmp1 = rand();132 133	fd = __event(HW_BREAKPOINT_R | HW_BREAKPOINT_W, (void *)&data1,134		     sizeof(data1));135	if (fd < 0)136		return fd == -ENODEV ? TEST_SKIP : -1;137 138	tmp = data1;139	WP_TEST_ASSERT_VAL(fd, "RW watchpoint", 1);140 141	data1 = tmp1 + tmp;142	WP_TEST_ASSERT_VAL(fd, "RW watchpoint", 2);143 144	close(fd);145	return 0;146#endif147}148 149static int test__wp_modify(struct test_suite *test __maybe_unused, int subtest __maybe_unused)150{151#if defined(__s390x__)152	return TEST_SKIP;153#else154	int fd, ret;155	unsigned long tmp = rand();156	struct perf_event_attr new_attr;157 158	fd = __event(HW_BREAKPOINT_W, (void *)&data1, sizeof(data1));159	if (fd < 0)160		return fd == -ENODEV ? TEST_SKIP : -1;161 162	data1 = tmp;163	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 1);164 165	/* Modify watchpoint with disabled = 1 */166	get__perf_event_attr(&new_attr, HW_BREAKPOINT_W, (void *)&data2[0],167			     sizeof(u8) * 2);168	new_attr.disabled = 1;169	ret = ioctl(fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr);170	if (ret < 0) {171		if (errno == ENOTTY) {172			test->test_cases[subtest].skip_reason = "missing kernel support";173			ret = TEST_SKIP;174		}175 176		pr_debug("ioctl(PERF_EVENT_IOC_MODIFY_ATTRIBUTES) failed\n");177		close(fd);178		return ret;179	}180 181	data2[1] = tmp; /* Not Counted */182	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 1);183 184	/* Enable the event */185	ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);186	if (ret < 0) {187		pr_debug("Failed to enable event\n");188		close(fd);189		return ret;190	}191 192	data2[1] = tmp; /* Counted */193	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 2);194 195	data2[2] = tmp; /* Not Counted */196	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 2);197 198	close(fd);199	return 0;200#endif201}202 203static struct test_case wp_tests[] = {204	TEST_CASE_REASON("Read Only Watchpoint", wp_ro, "missing hardware support"),205	TEST_CASE_REASON("Write Only Watchpoint", wp_wo, "missing hardware support"),206	TEST_CASE_REASON("Read / Write Watchpoint", wp_rw, "missing hardware support"),207	TEST_CASE_REASON("Modify Watchpoint", wp_modify, "missing hardware support"),208	{ .name = NULL, }209};210 211struct test_suite suite__wp = {212	.desc = "Watchpoint",213	.test_cases = wp_tests,214};215