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