linux/tools/perf/tests/bp_signal.c
<<
>>
Prefs
   1/*
   2 * Inspired by breakpoint overflow test done by
   3 * Vince Weaver <vincent.weaver@maine.edu> for perf_event_tests
   4 * (git://github.com/deater/perf_event_tests)
   5 */
   6
   7/*
   8 * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
   9 * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
  10 */
  11#define __SANE_USERSPACE_TYPES__
  12
  13#include <stdlib.h>
  14#include <stdio.h>
  15#include <unistd.h>
  16#include <string.h>
  17#include <sys/ioctl.h>
  18#include <time.h>
  19#include <fcntl.h>
  20#include <signal.h>
  21#include <sys/mman.h>
  22#include <linux/compiler.h>
  23#include <linux/hw_breakpoint.h>
  24
  25#include "tests.h"
  26#include "debug.h"
  27#include "perf.h"
  28#include "cloexec.h"
  29
  30static int fd1;
  31static int fd2;
  32static int overflows;
  33
  34__attribute__ ((noinline))
  35static int test_function(void)
  36{
  37        return time(NULL);
  38}
  39
  40static void sig_handler(int signum __maybe_unused,
  41                        siginfo_t *oh __maybe_unused,
  42                        void *uc __maybe_unused)
  43{
  44        overflows++;
  45
  46        if (overflows > 10) {
  47                /*
  48                 * This should be executed only once during
  49                 * this test, if we are here for the 10th
  50                 * time, consider this the recursive issue.
  51                 *
  52                 * We can get out of here by disable events,
  53                 * so no new SIGIO is delivered.
  54                 */
  55                ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
  56                ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
  57        }
  58}
  59
  60static int bp_event(void *fn, int setup_signal)
  61{
  62        struct perf_event_attr pe;
  63        int fd;
  64
  65        memset(&pe, 0, sizeof(struct perf_event_attr));
  66        pe.type = PERF_TYPE_BREAKPOINT;
  67        pe.size = sizeof(struct perf_event_attr);
  68
  69        pe.config = 0;
  70        pe.bp_type = HW_BREAKPOINT_X;
  71        pe.bp_addr = (unsigned long) fn;
  72        pe.bp_len = sizeof(long);
  73
  74        pe.sample_period = 1;
  75        pe.sample_type = PERF_SAMPLE_IP;
  76        pe.wakeup_events = 1;
  77
  78        pe.disabled = 1;
  79        pe.exclude_kernel = 1;
  80        pe.exclude_hv = 1;
  81
  82        fd = sys_perf_event_open(&pe, 0, -1, -1,
  83                                 perf_event_open_cloexec_flag());
  84        if (fd < 0) {
  85                pr_debug("failed opening event %llx\n", pe.config);
  86                return TEST_FAIL;
  87        }
  88
  89        if (setup_signal) {
  90                fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
  91                fcntl(fd, F_SETSIG, SIGIO);
  92                fcntl(fd, F_SETOWN, getpid());
  93        }
  94
  95        ioctl(fd, PERF_EVENT_IOC_RESET, 0);
  96
  97        return fd;
  98}
  99
 100static long long bp_count(int fd)
 101{
 102        long long count;
 103        int ret;
 104
 105        ret = read(fd, &count, sizeof(long long));
 106        if (ret != sizeof(long long)) {
 107                pr_debug("failed to read: %d\n", ret);
 108                return TEST_FAIL;
 109        }
 110
 111        return count;
 112}
 113
 114int test__bp_signal(void)
 115{
 116        struct sigaction sa;
 117        long long count1, count2;
 118
 119        /* setup SIGIO signal handler */
 120        memset(&sa, 0, sizeof(struct sigaction));
 121        sa.sa_sigaction = (void *) sig_handler;
 122        sa.sa_flags = SA_SIGINFO;
 123
 124        if (sigaction(SIGIO, &sa, NULL) < 0) {
 125                pr_debug("failed setting up signal handler\n");
 126                return TEST_FAIL;
 127        }
 128
 129        /*
 130         * We create following events:
 131         *
 132         * fd1 - breakpoint event on test_function with SIGIO
 133         *       signal configured. We should get signal
 134         *       notification each time the breakpoint is hit
 135         *
 136         * fd2 - breakpoint event on sig_handler without SIGIO
 137         *       configured.
 138         *
 139         * Following processing should happen:
 140         *   - execute test_function
 141         *   - fd1 event breakpoint hit -> count1 == 1
 142         *   - SIGIO is delivered       -> overflows == 1
 143         *   - fd2 event breakpoint hit -> count2 == 1
 144         *
 145         * The test case check following error conditions:
 146         * - we get stuck in signal handler because of debug
 147         *   exception being triggered receursively due to
 148         *   the wrong RF EFLAG management
 149         *
 150         * - we never trigger the sig_handler breakpoint due
 151         *   to the rong RF EFLAG management
 152         *
 153         */
 154
 155        fd1 = bp_event(test_function, 1);
 156        fd2 = bp_event(sig_handler, 0);
 157
 158        ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
 159        ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
 160
 161        /*
 162         * Kick off the test by trigering 'fd1'
 163         * breakpoint.
 164         */
 165        test_function();
 166
 167        ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
 168        ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
 169
 170        count1 = bp_count(fd1);
 171        count2 = bp_count(fd2);
 172
 173        close(fd1);
 174        close(fd2);
 175
 176        pr_debug("count1 %lld, count2 %lld, overflow %d\n",
 177                 count1, count2, overflows);
 178
 179        if (count1 != 1) {
 180                if (count1 == 11)
 181                        pr_debug("failed: RF EFLAG recursion issue detected\n");
 182                else
 183                        pr_debug("failed: wrong count for bp1%lld\n", count1);
 184        }
 185
 186        if (overflows != 1)
 187                pr_debug("failed: wrong overflow hit\n");
 188
 189        if (count2 != 1)
 190                pr_debug("failed: wrong count for bp2\n");
 191
 192        return count1 == 1 && overflows == 1 && count2 == 1 ?
 193                TEST_OK : TEST_FAIL;
 194}
 195