0001
0002
0003
0004
0005
0006
0007
0008 #include <errno.h>
0009 #include <stdint.h>
0010 #include <stdlib.h>
0011 #include <linux/hw_breakpoint.h>
0012 #include <linux/string.h>
0013 #include <pthread.h>
0014 #include <signal.h>
0015 #include <sys/ioctl.h>
0016 #include <sys/syscall.h>
0017 #include <unistd.h>
0018
0019 #include "cloexec.h"
0020 #include "debug.h"
0021 #include "event.h"
0022 #include "tests.h"
0023 #include "../perf-sys.h"
0024
0025 #define NUM_THREADS 5
0026
0027 static struct {
0028 int tids_want_signal;
0029 int signal_count;
0030 volatile int iterate_on;
0031 siginfo_t first_siginfo;
0032 } ctx;
0033
0034 #define TEST_SIG_DATA (~(unsigned long)(&ctx.iterate_on))
0035
0036 static struct perf_event_attr make_event_attr(void)
0037 {
0038 struct perf_event_attr attr = {
0039 .type = PERF_TYPE_BREAKPOINT,
0040 .size = sizeof(attr),
0041 .sample_period = 1,
0042 .disabled = 1,
0043 .bp_addr = (unsigned long)&ctx.iterate_on,
0044 .bp_type = HW_BREAKPOINT_RW,
0045 .bp_len = HW_BREAKPOINT_LEN_1,
0046 .inherit = 1,
0047 .inherit_thread = 1,
0048 .remove_on_exec = 1,
0049 .sigtrap = 1,
0050 .sig_data = TEST_SIG_DATA,
0051 .exclude_kernel = 1,
0052 .exclude_hv = 1,
0053 };
0054 return attr;
0055 }
0056
0057 static void
0058 sigtrap_handler(int signum __maybe_unused, siginfo_t *info, void *ucontext __maybe_unused)
0059 {
0060 if (!__atomic_fetch_add(&ctx.signal_count, 1, __ATOMIC_RELAXED))
0061 ctx.first_siginfo = *info;
0062 __atomic_fetch_sub(&ctx.tids_want_signal, syscall(SYS_gettid), __ATOMIC_RELAXED);
0063 }
0064
0065 static void *test_thread(void *arg)
0066 {
0067 pthread_barrier_t *barrier = (pthread_barrier_t *)arg;
0068 pid_t tid = syscall(SYS_gettid);
0069 int i;
0070
0071 pthread_barrier_wait(barrier);
0072
0073 __atomic_fetch_add(&ctx.tids_want_signal, tid, __ATOMIC_RELAXED);
0074 for (i = 0; i < ctx.iterate_on - 1; i++)
0075 __atomic_fetch_add(&ctx.tids_want_signal, tid, __ATOMIC_RELAXED);
0076
0077 return NULL;
0078 }
0079
0080 static int run_test_threads(pthread_t *threads, pthread_barrier_t *barrier)
0081 {
0082 int i;
0083
0084 pthread_barrier_wait(barrier);
0085 for (i = 0; i < NUM_THREADS; i++)
0086 TEST_ASSERT_EQUAL("pthread_join() failed", pthread_join(threads[i], NULL), 0);
0087
0088 return TEST_OK;
0089 }
0090
0091 static int run_stress_test(int fd, pthread_t *threads, pthread_barrier_t *barrier)
0092 {
0093 int ret;
0094
0095 ctx.iterate_on = 3000;
0096
0097 TEST_ASSERT_EQUAL("misfired signal?", ctx.signal_count, 0);
0098 TEST_ASSERT_EQUAL("enable failed", ioctl(fd, PERF_EVENT_IOC_ENABLE, 0), 0);
0099 ret = run_test_threads(threads, barrier);
0100 TEST_ASSERT_EQUAL("disable failed", ioctl(fd, PERF_EVENT_IOC_DISABLE, 0), 0);
0101
0102 TEST_ASSERT_EQUAL("unexpected sigtraps", ctx.signal_count, NUM_THREADS * ctx.iterate_on);
0103 TEST_ASSERT_EQUAL("missing signals or incorrectly delivered", ctx.tids_want_signal, 0);
0104 TEST_ASSERT_VAL("unexpected si_addr", ctx.first_siginfo.si_addr == &ctx.iterate_on);
0105 #if 0
0106 TEST_ASSERT_EQUAL("unexpected si_perf_type", ctx.first_siginfo.si_perf_type,
0107 PERF_TYPE_BREAKPOINT);
0108 TEST_ASSERT_EQUAL("unexpected si_perf_data", ctx.first_siginfo.si_perf_data,
0109 TEST_SIG_DATA);
0110 #endif
0111
0112 return ret;
0113 }
0114
0115 static int test__sigtrap(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
0116 {
0117 struct perf_event_attr attr = make_event_attr();
0118 struct sigaction action = {};
0119 struct sigaction oldact;
0120 pthread_t threads[NUM_THREADS];
0121 pthread_barrier_t barrier;
0122 char sbuf[STRERR_BUFSIZE];
0123 int i, fd, ret = TEST_FAIL;
0124
0125 if (!BP_SIGNAL_IS_SUPPORTED) {
0126 pr_debug("Test not supported on this architecture");
0127 return TEST_SKIP;
0128 }
0129
0130 pthread_barrier_init(&barrier, NULL, NUM_THREADS + 1);
0131
0132 action.sa_flags = SA_SIGINFO | SA_NODEFER;
0133 action.sa_sigaction = sigtrap_handler;
0134 sigemptyset(&action.sa_mask);
0135 if (sigaction(SIGTRAP, &action, &oldact)) {
0136 pr_debug("FAILED sigaction(): %s\n", str_error_r(errno, sbuf, sizeof(sbuf)));
0137 goto out;
0138 }
0139
0140 fd = sys_perf_event_open(&attr, 0, -1, -1, perf_event_open_cloexec_flag());
0141 if (fd < 0) {
0142 pr_debug("FAILED sys_perf_event_open(): %s\n", str_error_r(errno, sbuf, sizeof(sbuf)));
0143 goto out_restore_sigaction;
0144 }
0145
0146 for (i = 0; i < NUM_THREADS; i++) {
0147 if (pthread_create(&threads[i], NULL, test_thread, &barrier)) {
0148 pr_debug("FAILED pthread_create(): %s\n", str_error_r(errno, sbuf, sizeof(sbuf)));
0149 goto out_close_perf_event;
0150 }
0151 }
0152
0153 ret = run_stress_test(fd, threads, &barrier);
0154
0155 out_close_perf_event:
0156 close(fd);
0157 out_restore_sigaction:
0158 sigaction(SIGTRAP, &oldact, NULL);
0159 out:
0160 pthread_barrier_destroy(&barrier);
0161 return ret;
0162 }
0163
0164 DEFINE_SUITE("Sigtrap", sigtrap);