~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/perf/tests/bp_signal.c

Version: ~ [ linux-6.0 ] ~ [ linux-5.19.12 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.71 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.146 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.215 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.260 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.295 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.330 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.302 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Inspired by breakpoint overflow test done by
  4  * Vince Weaver <vincent.weaver@maine.edu> for perf_event_tests
  5  * (git://github.com/deater/perf_event_tests)
  6  */
  7 
  8 /*
  9  * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
 10  * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
 11  */
 12 #define __SANE_USERSPACE_TYPES__
 13 
 14 #include <stdlib.h>
 15 #include <stdio.h>
 16 #include <unistd.h>
 17 #include <string.h>
 18 #include <sys/ioctl.h>
 19 #include <time.h>
 20 #include <fcntl.h>
 21 #include <signal.h>
 22 #include <sys/mman.h>
 23 #include <linux/compiler.h>
 24 #include <linux/hw_breakpoint.h>
 25 
 26 #include "tests.h"
 27 #include "debug.h"
 28 #include "perf.h"
 29 #include "cloexec.h"
 30 
 31 static int fd1;
 32 static int fd2;
 33 static int fd3;
 34 static int overflows;
 35 static int overflows_2;
 36 
 37 volatile long the_var;
 38 
 39 
 40 /*
 41  * Use ASM to ensure watchpoint and breakpoint can be triggered
 42  * at one instruction.
 43  */
 44 #if defined (__x86_64__)
 45 extern void __test_function(volatile long *ptr);
 46 asm (
 47         ".globl __test_function\n"
 48         "__test_function:\n"
 49         "incq (%rdi)\n"
 50         "ret\n");
 51 #elif defined (__aarch64__)
 52 extern void __test_function(volatile long *ptr);
 53 asm (
 54         ".globl __test_function\n"
 55         "__test_function:\n"
 56         "str x30, [x0]\n"
 57         "ret\n");
 58 
 59 #else
 60 static void __test_function(volatile long *ptr)
 61 {
 62         *ptr = 0x1234;
 63 }
 64 #endif
 65 
 66 static noinline int test_function(void)
 67 {
 68         __test_function(&the_var);
 69         the_var++;
 70         return time(NULL);
 71 }
 72 
 73 static void sig_handler_2(int signum __maybe_unused,
 74                           siginfo_t *oh __maybe_unused,
 75                           void *uc __maybe_unused)
 76 {
 77         overflows_2++;
 78         if (overflows_2 > 10) {
 79                 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
 80                 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
 81                 ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
 82         }
 83 }
 84 
 85 static void sig_handler(int signum __maybe_unused,
 86                         siginfo_t *oh __maybe_unused,
 87                         void *uc __maybe_unused)
 88 {
 89         overflows++;
 90 
 91         if (overflows > 10) {
 92                 /*
 93                  * This should be executed only once during
 94                  * this test, if we are here for the 10th
 95                  * time, consider this the recursive issue.
 96                  *
 97                  * We can get out of here by disable events,
 98                  * so no new SIGIO is delivered.
 99                  */
100                 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
101                 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
102                 ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
103         }
104 }
105 
106 static int __event(bool is_x, void *addr, int sig)
107 {
108         struct perf_event_attr pe;
109         int fd;
110 
111         memset(&pe, 0, sizeof(struct perf_event_attr));
112         pe.type = PERF_TYPE_BREAKPOINT;
113         pe.size = sizeof(struct perf_event_attr);
114 
115         pe.config = 0;
116         pe.bp_type = is_x ? HW_BREAKPOINT_X : HW_BREAKPOINT_W;
117         pe.bp_addr = (unsigned long) addr;
118         pe.bp_len = sizeof(long);
119 
120         pe.sample_period = 1;
121         pe.sample_type = PERF_SAMPLE_IP;
122         pe.wakeup_events = 1;
123 
124         pe.disabled = 1;
125         pe.exclude_kernel = 1;
126         pe.exclude_hv = 1;
127 
128         fd = sys_perf_event_open(&pe, 0, -1, -1,
129                                  perf_event_open_cloexec_flag());
130         if (fd < 0) {
131                 pr_debug("failed opening event %llx\n", pe.config);
132                 return TEST_FAIL;
133         }
134 
135         fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
136         fcntl(fd, F_SETSIG, sig);
137         fcntl(fd, F_SETOWN, getpid());
138 
139         ioctl(fd, PERF_EVENT_IOC_RESET, 0);
140 
141         return fd;
142 }
143 
144 static int bp_event(void *addr, int sig)
145 {
146         return __event(true, addr, sig);
147 }
148 
149 static int wp_event(void *addr, int sig)
150 {
151         return __event(false, addr, sig);
152 }
153 
154 static long long bp_count(int fd)
155 {
156         long long count;
157         int ret;
158 
159         ret = read(fd, &count, sizeof(long long));
160         if (ret != sizeof(long long)) {
161                 pr_debug("failed to read: %d\n", ret);
162                 return TEST_FAIL;
163         }
164 
165         return count;
166 }
167 
168 int test__bp_signal(struct test *test __maybe_unused, int subtest __maybe_unused)
169 {
170         struct sigaction sa;
171         long long count1, count2, count3;
172 
173         /* setup SIGIO signal handler */
174         memset(&sa, 0, sizeof(struct sigaction));
175         sa.sa_sigaction = (void *) sig_handler;
176         sa.sa_flags = SA_SIGINFO;
177 
178         if (sigaction(SIGIO, &sa, NULL) < 0) {
179                 pr_debug("failed setting up signal handler\n");
180                 return TEST_FAIL;
181         }
182 
183         sa.sa_sigaction = (void *) sig_handler_2;
184         if (sigaction(SIGUSR1, &sa, NULL) < 0) {
185                 pr_debug("failed setting up signal handler 2\n");
186                 return TEST_FAIL;
187         }
188 
189         /*
190          * We create following events:
191          *
192          * fd1 - breakpoint event on __test_function with SIGIO
193          *       signal configured. We should get signal
194          *       notification each time the breakpoint is hit
195          *
196          * fd2 - breakpoint event on sig_handler with SIGUSR1
197          *       configured. We should get SIGUSR1 each time when
198          *       breakpoint is hit
199          *
200          * fd3 - watchpoint event on __test_function with SIGIO
201          *       configured.
202          *
203          * Following processing should happen:
204          *   Exec:               Action:                       Result:
205          *   incq (%rdi)       - fd1 event breakpoint hit   -> count1 == 1
206          *                     - SIGIO is delivered
207          *   sig_handler       - fd2 event breakpoint hit   -> count2 == 1
208          *                     - SIGUSR1 is delivered
209          *   sig_handler_2                                  -> overflows_2 == 1  (nested signal)
210          *   sys_rt_sigreturn  - return from sig_handler_2
211          *   overflows++                                    -> overflows = 1
212          *   sys_rt_sigreturn  - return from sig_handler
213          *   incq (%rdi)       - fd3 event watchpoint hit   -> count3 == 1       (wp and bp in one insn)
214          *                     - SIGIO is delivered
215          *   sig_handler       - fd2 event breakpoint hit   -> count2 == 2
216          *                     - SIGUSR1 is delivered
217          *   sig_handler_2                                  -> overflows_2 == 2  (nested signal)
218          *   sys_rt_sigreturn  - return from sig_handler_2
219          *   overflows++                                    -> overflows = 2
220          *   sys_rt_sigreturn  - return from sig_handler
221          *   the_var++         - fd3 event watchpoint hit   -> count3 == 2       (standalone watchpoint)
222          *                     - SIGIO is delivered
223          *   sig_handler       - fd2 event breakpoint hit   -> count2 == 3
224          *                     - SIGUSR1 is delivered
225          *   sig_handler_2                                  -> overflows_2 == 3  (nested signal)
226          *   sys_rt_sigreturn  - return from sig_handler_2
227          *   overflows++                                    -> overflows == 3
228          *   sys_rt_sigreturn  - return from sig_handler
229          *
230          * The test case check following error conditions:
231          * - we get stuck in signal handler because of debug
232          *   exception being triggered receursively due to
233          *   the wrong RF EFLAG management
234          *
235          * - we never trigger the sig_handler breakpoint due
236          *   to the rong RF EFLAG management
237          *
238          */
239 
240         fd1 = bp_event(__test_function, SIGIO);
241         fd2 = bp_event(sig_handler, SIGUSR1);
242         fd3 = wp_event((void *)&the_var, SIGIO);
243 
244         ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
245         ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
246         ioctl(fd3, PERF_EVENT_IOC_ENABLE, 0);
247 
248         /*
249          * Kick off the test by trigering 'fd1'
250          * breakpoint.
251          */
252         test_function();
253 
254         ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
255         ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
256         ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
257 
258         count1 = bp_count(fd1);
259         count2 = bp_count(fd2);
260         count3 = bp_count(fd3);
261 
262         close(fd1);
263         close(fd2);
264         close(fd3);
265 
266         pr_debug("count1 %lld, count2 %lld, count3 %lld, overflow %d, overflows_2 %d\n",
267                  count1, count2, count3, overflows, overflows_2);
268 
269         if (count1 != 1) {
270                 if (count1 == 11)
271                         pr_debug("failed: RF EFLAG recursion issue detected\n");
272                 else
273                         pr_debug("failed: wrong count for bp1%lld\n", count1);
274         }
275 
276         if (overflows != 3)
277                 pr_debug("failed: wrong overflow hit\n");
278 
279         if (overflows_2 != 3)
280                 pr_debug("failed: wrong overflow_2 hit\n");
281 
282         if (count2 != 3)
283                 pr_debug("failed: wrong count for bp2\n");
284 
285         if (count3 != 2)
286                 pr_debug("failed: wrong count for bp3\n");
287 
288         return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ?
289                 TEST_OK : TEST_FAIL;
290 }
291 
292 bool test__bp_signal_is_supported(void)
293 {
294         /*
295          * PowerPC and S390 do not support creation of instruction
296          * breakpoints using the perf_event interface.
297          *
298          * ARM requires explicit rounding down of the instruction
299          * pointer in Thumb mode, and then requires the single-step
300          * to be handled explicitly in the overflow handler to avoid
301          * stepping into the SIGIO handler and getting stuck on the
302          * breakpointed instruction.
303          *
304          * Just disable the test for these architectures until these
305          * issues are resolved.
306          */
307 #if defined(__powerpc__) || defined(__s390x__) || defined(__arm__)
308         return false;
309 #else
310         return true;
311 #endif
312 }
313 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp