1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Test for perf events with SIGTRAP across all threads. 4 * 5 * Copyright (C) 2021, Google LLC. 6 */ 7 8 #define _GNU_SOURCE 9 10 /* We need the latest siginfo from the kernel repo. */ 11 #include <sys/types.h> 12 #include <asm/siginfo.h> 13 #define __have_siginfo_t 1 14 #define __have_sigval_t 1 15 #define __have_sigevent_t 1 16 #define __siginfo_t_defined 17 #define __sigval_t_defined 18 #define __sigevent_t_defined 19 #define _BITS_SIGINFO_CONSTS_H 1 20 #define _BITS_SIGEVENT_CONSTS_H 1 21 22 #include <stdbool.h> 23 #include <stddef.h> 24 #include <stdint.h> 25 #include <stdio.h> 26 #include <linux/hw_breakpoint.h> 27 #include <linux/perf_event.h> 28 #include <pthread.h> 29 #include <signal.h> 30 #include <sys/ioctl.h> 31 #include <sys/syscall.h> 32 #include <unistd.h> 33 34 #include "../kselftest_harness.h" 35 36 #define NUM_THREADS 5 37 38 /* Data shared between test body, threads, and signal handler. */ 39 static struct { 40 int tids_want_signal; /* Which threads still want a signal. */ 41 int signal_count; /* Sanity check number of signals received. */ 42 volatile int iterate_on; /* Variable to set breakpoint on. */ 43 siginfo_t first_siginfo; /* First observed siginfo_t. */ 44 } ctx; 45 46 /* Unique value to check si_perf_data is correctly set from perf_event_attr::sig_data. */ 47 #define TEST_SIG_DATA(addr) (~(unsigned long)(addr)) 48 49 static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr) 50 { 51 struct perf_event_attr attr = { 52 .type = PERF_TYPE_BREAKPOINT, 53 .size = sizeof(attr), 54 .sample_period = 1, 55 .disabled = !enabled, 56 .bp_addr = (unsigned long)addr, 57 .bp_type = HW_BREAKPOINT_RW, 58 .bp_len = HW_BREAKPOINT_LEN_1, 59 .inherit = 1, /* Children inherit events ... */ 60 .inherit_thread = 1, /* ... but only cloned with CLONE_THREAD. */ 61 .remove_on_exec = 1, /* Required by sigtrap. */ 62 .sigtrap = 1, /* Request synchronous SIGTRAP on event. */ 63 .sig_data = TEST_SIG_DATA(addr), 64 }; 65 return attr; 66 } 67 68 static void sigtrap_handler(int signum, siginfo_t *info, void *ucontext) 69 { 70 if (info->si_code != TRAP_PERF) { 71 fprintf(stderr, "%s: unexpected si_code %d\n", __func__, info->si_code); 72 return; 73 } 74 75 /* 76 * The data in siginfo_t we're interested in should all be the same 77 * across threads. 78 */ 79 if (!__atomic_fetch_add(&ctx.signal_count, 1, __ATOMIC_RELAXED)) 80 ctx.first_siginfo = *info; 81 __atomic_fetch_sub(&ctx.tids_want_signal, syscall(__NR_gettid), __ATOMIC_RELAXED); 82 } 83 84 static void *test_thread(void *arg) 85 { 86 pthread_barrier_t *barrier = (pthread_barrier_t *)arg; 87 pid_t tid = syscall(__NR_gettid); 88 int iter; 89 int i; 90 91 pthread_barrier_wait(barrier); 92 93 __atomic_fetch_add(&ctx.tids_want_signal, tid, __ATOMIC_RELAXED); 94 iter = ctx.iterate_on; /* read */ 95 for (i = 0; i < iter - 1; i++) { 96 __atomic_fetch_add(&ctx.tids_want_signal, tid, __ATOMIC_RELAXED); 97 ctx.iterate_on = iter; /* idempotent write */ 98 } 99 100 return NULL; 101 } 102 103 FIXTURE(sigtrap_threads) 104 { 105 struct sigaction oldact; 106 pthread_t threads[NUM_THREADS]; 107 pthread_barrier_t barrier; 108 int fd; 109 }; 110 111 FIXTURE_SETUP(sigtrap_threads) 112 { 113 struct perf_event_attr attr = make_event_attr(false, &ctx.iterate_on); 114 struct sigaction action = {}; 115 int i; 116 117 memset(&ctx, 0, sizeof(ctx)); 118 119 /* Initialize sigtrap handler. */ 120 action.sa_flags = SA_SIGINFO | SA_NODEFER; 121 action.sa_sigaction = sigtrap_handler; 122 sigemptyset(&action.sa_mask); 123 ASSERT_EQ(sigaction(SIGTRAP, &action, &self->oldact), 0); 124 125 /* Initialize perf event. */ 126 self->fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, PERF_FLAG_FD_CLOEXEC); 127 ASSERT_NE(self->fd, -1); 128 129 /* Spawn threads inheriting perf event. */ 130 pthread_barrier_init(&self->barrier, NULL, NUM_THREADS + 1); 131 for (i = 0; i < NUM_THREADS; i++) 132 ASSERT_EQ(pthread_create(&self->threads[i], NULL, test_thread, &self->barrier), 0); 133 } 134 135 FIXTURE_TEARDOWN(sigtrap_threads) 136 { 137 pthread_barrier_destroy(&self->barrier); 138 close(self->fd); 139 sigaction(SIGTRAP, &self->oldact, NULL); 140 } 141 142 static void run_test_threads(struct __test_metadata *_metadata, 143 FIXTURE_DATA(sigtrap_threads) *self) 144 { 145 int i; 146 147 pthread_barrier_wait(&self->barrier); 148 for (i = 0; i < NUM_THREADS; i++) 149 ASSERT_EQ(pthread_join(self->threads[i], NULL), 0); 150 } 151 152 TEST_F(sigtrap_threads, remain_disabled) 153 { 154 run_test_threads(_metadata, self); 155 EXPECT_EQ(ctx.signal_count, 0); 156 EXPECT_NE(ctx.tids_want_signal, 0); 157 } 158 159 TEST_F(sigtrap_threads, enable_event) 160 { 161 EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0); 162 run_test_threads(_metadata, self); 163 164 EXPECT_EQ(ctx.signal_count, NUM_THREADS); 165 EXPECT_EQ(ctx.tids_want_signal, 0); 166 EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on); 167 EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT); 168 EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on)); 169 170 /* Check enabled for parent. */ 171 ctx.iterate_on = 0; 172 EXPECT_EQ(ctx.signal_count, NUM_THREADS + 1); 173 } 174 175 /* Test that modification propagates to all inherited events. */ 176 TEST_F(sigtrap_threads, modify_and_enable_event) 177 { 178 struct perf_event_attr new_attr = make_event_attr(true, &ctx.iterate_on); 179 180 EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr), 0); 181 run_test_threads(_metadata, self); 182 183 EXPECT_EQ(ctx.signal_count, NUM_THREADS); 184 EXPECT_EQ(ctx.tids_want_signal, 0); 185 EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on); 186 EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT); 187 EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on)); 188 189 /* Check enabled for parent. */ 190 ctx.iterate_on = 0; 191 EXPECT_EQ(ctx.signal_count, NUM_THREADS + 1); 192 } 193 194 /* Stress test event + signal handling. */ 195 TEST_F(sigtrap_threads, signal_stress) 196 { 197 ctx.iterate_on = 3000; 198 199 EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0); 200 run_test_threads(_metadata, self); 201 EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_DISABLE, 0), 0); 202 203 EXPECT_EQ(ctx.signal_count, NUM_THREADS * ctx.iterate_on); 204 EXPECT_EQ(ctx.tids_want_signal, 0); 205 EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on); 206 EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT); 207 EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on)); 208 } 209 210 TEST_HARNESS_MAIN 211