xref: /openbmc/linux/tools/perf/tests/sigtrap.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
15504f679SMarco Elver // SPDX-License-Identifier: GPL-2.0
25504f679SMarco Elver /*
35504f679SMarco Elver  * Basic test for sigtrap support.
45504f679SMarco Elver  *
55504f679SMarco Elver  * Copyright (C) 2021, Google LLC.
65504f679SMarco Elver  */
75504f679SMarco Elver 
8e9c08f72SArnaldo Carvalho de Melo #include <errno.h>
95504f679SMarco Elver #include <stdint.h>
105504f679SMarco Elver #include <stdlib.h>
115504f679SMarco Elver #include <linux/hw_breakpoint.h>
12e9c08f72SArnaldo Carvalho de Melo #include <linux/string.h>
135504f679SMarco Elver #include <pthread.h>
145504f679SMarco Elver #include <signal.h>
155504f679SMarco Elver #include <sys/ioctl.h>
165504f679SMarco Elver #include <sys/syscall.h>
175504f679SMarco Elver #include <unistd.h>
185504f679SMarco Elver 
195504f679SMarco Elver #include "cloexec.h"
205504f679SMarco Elver #include "debug.h"
215504f679SMarco Elver #include "event.h"
225504f679SMarco Elver #include "tests.h"
235504f679SMarco Elver #include "../perf-sys.h"
245504f679SMarco Elver 
255504f679SMarco Elver #define NUM_THREADS 5
265504f679SMarco Elver 
275504f679SMarco Elver static struct {
285504f679SMarco Elver 	int tids_want_signal;		/* Which threads still want a signal. */
295504f679SMarco Elver 	int signal_count;		/* Sanity check number of signals received. */
305504f679SMarco Elver 	volatile int iterate_on;	/* Variable to set breakpoint on. */
315504f679SMarco Elver 	siginfo_t first_siginfo;	/* First observed siginfo_t. */
325504f679SMarco Elver } ctx;
335504f679SMarco Elver 
345504f679SMarco Elver #define TEST_SIG_DATA (~(unsigned long)(&ctx.iterate_on))
355504f679SMarco Elver 
make_event_attr(void)365504f679SMarco Elver static struct perf_event_attr make_event_attr(void)
375504f679SMarco Elver {
385504f679SMarco Elver 	struct perf_event_attr attr = {
395504f679SMarco Elver 		.type		= PERF_TYPE_BREAKPOINT,
405504f679SMarco Elver 		.size		= sizeof(attr),
415504f679SMarco Elver 		.sample_period	= 1,
425504f679SMarco Elver 		.disabled	= 1,
435504f679SMarco Elver 		.bp_addr	= (unsigned long)&ctx.iterate_on,
445504f679SMarco Elver 		.bp_type	= HW_BREAKPOINT_RW,
455504f679SMarco Elver 		.bp_len		= HW_BREAKPOINT_LEN_1,
465504f679SMarco Elver 		.inherit	= 1, /* Children inherit events ... */
475504f679SMarco Elver 		.inherit_thread = 1, /* ... but only cloned with CLONE_THREAD. */
485504f679SMarco Elver 		.remove_on_exec = 1, /* Required by sigtrap. */
495504f679SMarco Elver 		.sigtrap	= 1, /* Request synchronous SIGTRAP on event. */
505504f679SMarco Elver 		.sig_data	= TEST_SIG_DATA,
515504f679SMarco Elver 		.exclude_kernel = 1, /* To allow */
525504f679SMarco Elver 		.exclude_hv     = 1, /* running as !root */
535504f679SMarco Elver 	};
545504f679SMarco Elver 	return attr;
555504f679SMarco Elver }
565504f679SMarco Elver 
57*187c7723SNamhyung Kim #ifdef HAVE_BPF_SKEL
58*187c7723SNamhyung Kim #include <bpf/btf.h>
59*187c7723SNamhyung Kim 
attr_has_sigtrap(void)60*187c7723SNamhyung Kim static bool attr_has_sigtrap(void)
61*187c7723SNamhyung Kim {
62*187c7723SNamhyung Kim 	bool ret = false;
63*187c7723SNamhyung Kim 	struct btf *btf;
64*187c7723SNamhyung Kim 	const struct btf_type *t;
65*187c7723SNamhyung Kim 	const struct btf_member *m;
66*187c7723SNamhyung Kim 	const char *name;
67*187c7723SNamhyung Kim 	int i, id;
68*187c7723SNamhyung Kim 
69*187c7723SNamhyung Kim 	btf = btf__load_vmlinux_btf();
70*187c7723SNamhyung Kim 	if (btf == NULL) {
71*187c7723SNamhyung Kim 		/* should be an old kernel */
72*187c7723SNamhyung Kim 		return false;
73*187c7723SNamhyung Kim 	}
74*187c7723SNamhyung Kim 
75*187c7723SNamhyung Kim 	id = btf__find_by_name_kind(btf, "perf_event_attr", BTF_KIND_STRUCT);
76*187c7723SNamhyung Kim 	if (id < 0)
77*187c7723SNamhyung Kim 		goto out;
78*187c7723SNamhyung Kim 
79*187c7723SNamhyung Kim 	t = btf__type_by_id(btf, id);
80*187c7723SNamhyung Kim 	for (i = 0, m = btf_members(t); i < btf_vlen(t); i++, m++) {
81*187c7723SNamhyung Kim 		name = btf__name_by_offset(btf, m->name_off);
82*187c7723SNamhyung Kim 		if (!strcmp(name, "sigtrap")) {
83*187c7723SNamhyung Kim 			ret = true;
84*187c7723SNamhyung Kim 			break;
85*187c7723SNamhyung Kim 		}
86*187c7723SNamhyung Kim 	}
87*187c7723SNamhyung Kim out:
88*187c7723SNamhyung Kim 	btf__free(btf);
89*187c7723SNamhyung Kim 	return ret;
90*187c7723SNamhyung Kim }
91*187c7723SNamhyung Kim #else  /* !HAVE_BPF_SKEL */
attr_has_sigtrap(void)92*187c7723SNamhyung Kim static bool attr_has_sigtrap(void)
93*187c7723SNamhyung Kim {
94*187c7723SNamhyung Kim 	struct perf_event_attr attr = {
95*187c7723SNamhyung Kim 		.type		= PERF_TYPE_SOFTWARE,
96*187c7723SNamhyung Kim 		.config		= PERF_COUNT_SW_DUMMY,
97*187c7723SNamhyung Kim 		.size		= sizeof(attr),
98*187c7723SNamhyung Kim 		.remove_on_exec = 1, /* Required by sigtrap. */
99*187c7723SNamhyung Kim 		.sigtrap	= 1, /* Request synchronous SIGTRAP on event. */
100*187c7723SNamhyung Kim 	};
101*187c7723SNamhyung Kim 	int fd;
102*187c7723SNamhyung Kim 	bool ret = false;
103*187c7723SNamhyung Kim 
104*187c7723SNamhyung Kim 	fd = sys_perf_event_open(&attr, 0, -1, -1, perf_event_open_cloexec_flag());
105*187c7723SNamhyung Kim 	if (fd >= 0) {
106*187c7723SNamhyung Kim 		ret = true;
107*187c7723SNamhyung Kim 		close(fd);
108*187c7723SNamhyung Kim 	}
109*187c7723SNamhyung Kim 
110*187c7723SNamhyung Kim 	return ret;
111*187c7723SNamhyung Kim }
112*187c7723SNamhyung Kim #endif  /* HAVE_BPF_SKEL */
113*187c7723SNamhyung Kim 
1145504f679SMarco Elver static void
sigtrap_handler(int signum __maybe_unused,siginfo_t * info,void * ucontext __maybe_unused)1155504f679SMarco Elver sigtrap_handler(int signum __maybe_unused, siginfo_t *info, void *ucontext __maybe_unused)
1165504f679SMarco Elver {
1175504f679SMarco Elver 	if (!__atomic_fetch_add(&ctx.signal_count, 1, __ATOMIC_RELAXED))
1185504f679SMarco Elver 		ctx.first_siginfo = *info;
1195504f679SMarco Elver 	__atomic_fetch_sub(&ctx.tids_want_signal, syscall(SYS_gettid), __ATOMIC_RELAXED);
1205504f679SMarco Elver }
1215504f679SMarco Elver 
test_thread(void * arg)1225504f679SMarco Elver static void *test_thread(void *arg)
1235504f679SMarco Elver {
1245504f679SMarco Elver 	pthread_barrier_t *barrier = (pthread_barrier_t *)arg;
1255504f679SMarco Elver 	pid_t tid = syscall(SYS_gettid);
1265504f679SMarco Elver 	int i;
1275504f679SMarco Elver 
1285504f679SMarco Elver 	pthread_barrier_wait(barrier);
1295504f679SMarco Elver 
1305504f679SMarco Elver 	__atomic_fetch_add(&ctx.tids_want_signal, tid, __ATOMIC_RELAXED);
1315504f679SMarco Elver 	for (i = 0; i < ctx.iterate_on - 1; i++)
1325504f679SMarco Elver 		__atomic_fetch_add(&ctx.tids_want_signal, tid, __ATOMIC_RELAXED);
1335504f679SMarco Elver 
1345504f679SMarco Elver 	return NULL;
1355504f679SMarco Elver }
1365504f679SMarco Elver 
run_test_threads(pthread_t * threads,pthread_barrier_t * barrier)1375504f679SMarco Elver static int run_test_threads(pthread_t *threads, pthread_barrier_t *barrier)
1385504f679SMarco Elver {
1395504f679SMarco Elver 	int i;
1405504f679SMarco Elver 
1415504f679SMarco Elver 	pthread_barrier_wait(barrier);
1425504f679SMarco Elver 	for (i = 0; i < NUM_THREADS; i++)
1435504f679SMarco Elver 		TEST_ASSERT_EQUAL("pthread_join() failed", pthread_join(threads[i], NULL), 0);
1445504f679SMarco Elver 
1455504f679SMarco Elver 	return TEST_OK;
1465504f679SMarco Elver }
1475504f679SMarco Elver 
run_stress_test(int fd,pthread_t * threads,pthread_barrier_t * barrier)1485504f679SMarco Elver static int run_stress_test(int fd, pthread_t *threads, pthread_barrier_t *barrier)
1495504f679SMarco Elver {
1505504f679SMarco Elver 	int ret;
1515504f679SMarco Elver 
1525504f679SMarco Elver 	ctx.iterate_on = 3000;
1535504f679SMarco Elver 
1545504f679SMarco Elver 	TEST_ASSERT_EQUAL("misfired signal?", ctx.signal_count, 0);
1555504f679SMarco Elver 	TEST_ASSERT_EQUAL("enable failed", ioctl(fd, PERF_EVENT_IOC_ENABLE, 0), 0);
1565504f679SMarco Elver 	ret = run_test_threads(threads, barrier);
1575504f679SMarco Elver 	TEST_ASSERT_EQUAL("disable failed", ioctl(fd, PERF_EVENT_IOC_DISABLE, 0), 0);
1585504f679SMarco Elver 
1595504f679SMarco Elver 	TEST_ASSERT_EQUAL("unexpected sigtraps", ctx.signal_count, NUM_THREADS * ctx.iterate_on);
1605504f679SMarco Elver 	TEST_ASSERT_EQUAL("missing signals or incorrectly delivered", ctx.tids_want_signal, 0);
1615504f679SMarco Elver 	TEST_ASSERT_VAL("unexpected si_addr", ctx.first_siginfo.si_addr == &ctx.iterate_on);
1625504f679SMarco Elver #if 0 /* FIXME: enable when libc's signal.h has si_perf_{type,data} */
1635504f679SMarco Elver 	TEST_ASSERT_EQUAL("unexpected si_perf_type", ctx.first_siginfo.si_perf_type,
1645504f679SMarco Elver 			  PERF_TYPE_BREAKPOINT);
1655504f679SMarco Elver 	TEST_ASSERT_EQUAL("unexpected si_perf_data", ctx.first_siginfo.si_perf_data,
1665504f679SMarco Elver 			  TEST_SIG_DATA);
1675504f679SMarco Elver #endif
1685504f679SMarco Elver 
1695504f679SMarco Elver 	return ret;
1705504f679SMarco Elver }
1715504f679SMarco Elver 
test__sigtrap(struct test_suite * test __maybe_unused,int subtest __maybe_unused)1725504f679SMarco Elver static int test__sigtrap(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
1735504f679SMarco Elver {
1745504f679SMarco Elver 	struct perf_event_attr attr = make_event_attr();
1755504f679SMarco Elver 	struct sigaction action = {};
1765504f679SMarco Elver 	struct sigaction oldact;
1775504f679SMarco Elver 	pthread_t threads[NUM_THREADS];
1785504f679SMarco Elver 	pthread_barrier_t barrier;
179e9c08f72SArnaldo Carvalho de Melo 	char sbuf[STRERR_BUFSIZE];
1805504f679SMarco Elver 	int i, fd, ret = TEST_FAIL;
1815504f679SMarco Elver 
182f268088fSJohn Garry 	if (!BP_SIGNAL_IS_SUPPORTED) {
183a840974eSThomas Richter 		pr_debug("Test not supported on this architecture");
184a840974eSThomas Richter 		return TEST_SKIP;
185a840974eSThomas Richter 	}
186a840974eSThomas Richter 
1875504f679SMarco Elver 	pthread_barrier_init(&barrier, NULL, NUM_THREADS + 1);
1885504f679SMarco Elver 
1895504f679SMarco Elver 	action.sa_flags = SA_SIGINFO | SA_NODEFER;
1905504f679SMarco Elver 	action.sa_sigaction = sigtrap_handler;
1915504f679SMarco Elver 	sigemptyset(&action.sa_mask);
1925504f679SMarco Elver 	if (sigaction(SIGTRAP, &action, &oldact)) {
193e9c08f72SArnaldo Carvalho de Melo 		pr_debug("FAILED sigaction(): %s\n", str_error_r(errno, sbuf, sizeof(sbuf)));
1945504f679SMarco Elver 		goto out;
1955504f679SMarco Elver 	}
1965504f679SMarco Elver 
1975504f679SMarco Elver 	fd = sys_perf_event_open(&attr, 0, -1, -1, perf_event_open_cloexec_flag());
1985504f679SMarco Elver 	if (fd < 0) {
199*187c7723SNamhyung Kim 		if (attr_has_sigtrap()) {
200*187c7723SNamhyung Kim 			pr_debug("FAILED sys_perf_event_open(): %s\n",
201*187c7723SNamhyung Kim 				 str_error_r(errno, sbuf, sizeof(sbuf)));
202*187c7723SNamhyung Kim 		} else {
203*187c7723SNamhyung Kim 			pr_debug("perf_event_attr doesn't have sigtrap\n");
204*187c7723SNamhyung Kim 			ret = TEST_SKIP;
205*187c7723SNamhyung Kim 		}
2065504f679SMarco Elver 		goto out_restore_sigaction;
2075504f679SMarco Elver 	}
2085504f679SMarco Elver 
2095504f679SMarco Elver 	for (i = 0; i < NUM_THREADS; i++) {
2105504f679SMarco Elver 		if (pthread_create(&threads[i], NULL, test_thread, &barrier)) {
211e9c08f72SArnaldo Carvalho de Melo 			pr_debug("FAILED pthread_create(): %s\n", str_error_r(errno, sbuf, sizeof(sbuf)));
2125504f679SMarco Elver 			goto out_close_perf_event;
2135504f679SMarco Elver 		}
2145504f679SMarco Elver 	}
2155504f679SMarco Elver 
2165504f679SMarco Elver 	ret = run_stress_test(fd, threads, &barrier);
2175504f679SMarco Elver 
2185504f679SMarco Elver out_close_perf_event:
2195504f679SMarco Elver 	close(fd);
2205504f679SMarco Elver out_restore_sigaction:
2215504f679SMarco Elver 	sigaction(SIGTRAP, &oldact, NULL);
2225504f679SMarco Elver out:
2235504f679SMarco Elver 	pthread_barrier_destroy(&barrier);
2245504f679SMarco Elver 	return ret;
2255504f679SMarco Elver }
2265504f679SMarco Elver 
2275504f679SMarco Elver DEFINE_SUITE("Sigtrap", sigtrap);
228