linux/tools/perf/tests/bp_signal.c
<<
>>
Prefs
   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
  32static int fd1;
  33static int fd2;
  34static int fd3;
  35static int overflows;
  36static int overflows_2;
  37
  38volatile 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__)
  46extern void __test_function(volatile long *ptr);
  47asm (
  48        ".globl __test_function\n"
  49        "__test_function:\n"
  50        "incq (%rdi)\n"
  51        "ret\n");
  52#else
  53static void __test_function(volatile long *ptr)
  54{
  55        *ptr = 0x1234;
  56}
  57#endif
  58
  59static noinline int test_function(void)
  60{
  61        __test_function(&the_var);
  62        the_var++;
  63        return time(NULL);
  64}
  65
  66static 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
  78static 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
  99static 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
 137static int bp_event(void *addr, int sig)
 138{
 139        return __event(true, addr, sig);
 140}
 141
 142static int wp_event(void *addr, int sig)
 143{
 144        return __event(false, addr, sig);
 145}
 146
 147static 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
 161int 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, expected 1\n", count1);
 267        }
 268
 269        if (overflows != 3)
 270                pr_debug("failed: wrong overflow (%d) hit, expected 3\n", overflows);
 271
 272        if (overflows_2 != 3)
 273                pr_debug("failed: wrong overflow_2 (%d) hit, expected 3\n", overflows_2);
 274
 275        if (count2 != 3)
 276                pr_debug("failed: wrong count for bp2 (%lld), expected 3\n", count2);
 277
 278        if (count3 != 2)
 279                pr_debug("failed: wrong count for bp3 (%lld), expected 2\n", count3);
 280
 281        return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ?
 282                TEST_OK : TEST_FAIL;
 283}
 284
 285bool 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 stuck 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}
 311