root/tools/perf/tests/bp_signal.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __test_function
  2. test_function
  3. sig_handler_2
  4. sig_handler
  5. __event
  6. bp_event
  7. wp_event
  8. bp_count
  9. test__bp_signal
  10. test__bp_signal_is_supported

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

/* [<][>][^][v][top][bottom][index][help] */