root/tools/perf/tests/wp.c

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

DEFINITIONS

This source file includes following definitions.
  1. wp_read
  2. get__perf_event_attr
  3. __event
  4. wp_ro_test
  5. wp_wo_test
  6. wp_rw_test
  7. wp_modify_test
  8. wp_ro_supported
  9. wp_ro_skip_msg
  10. test__wp_subtest_get_nr
  11. test__wp_subtest_get_desc
  12. test__wp
  13. test__wp_is_supported

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <stdlib.h>
   3 #include <string.h>
   4 #include <unistd.h>
   5 #include <sys/ioctl.h>
   6 #include <linux/hw_breakpoint.h>
   7 #include <linux/kernel.h>
   8 #include "tests.h"
   9 #include "debug.h"
  10 #include "event.h"
  11 #include "cloexec.h"
  12 #include "../perf-sys.h"
  13 
  14 #define WP_TEST_ASSERT_VAL(fd, text, val)       \
  15 do {                                            \
  16         long long count;                        \
  17         wp_read(fd, &count, sizeof(long long)); \
  18         TEST_ASSERT_VAL(text, count == val);    \
  19 } while (0)
  20 
  21 volatile u64 data1;
  22 volatile u8 data2[3];
  23 
  24 static int wp_read(int fd, long long *count, int size)
  25 {
  26         int ret = read(fd, count, size);
  27 
  28         if (ret != size) {
  29                 pr_debug("failed to read: %d\n", ret);
  30                 return -1;
  31         }
  32         return 0;
  33 }
  34 
  35 static void get__perf_event_attr(struct perf_event_attr *attr, int wp_type,
  36                                  void *wp_addr, unsigned long wp_len)
  37 {
  38         memset(attr, 0, sizeof(struct perf_event_attr));
  39         attr->type           = PERF_TYPE_BREAKPOINT;
  40         attr->size           = sizeof(struct perf_event_attr);
  41         attr->config         = 0;
  42         attr->bp_type        = wp_type;
  43         attr->bp_addr        = (unsigned long)wp_addr;
  44         attr->bp_len         = wp_len;
  45         attr->sample_period  = 1;
  46         attr->sample_type    = PERF_SAMPLE_IP;
  47         attr->exclude_kernel = 1;
  48         attr->exclude_hv     = 1;
  49 }
  50 
  51 static int __event(int wp_type, void *wp_addr, unsigned long wp_len)
  52 {
  53         int fd;
  54         struct perf_event_attr attr;
  55 
  56         get__perf_event_attr(&attr, wp_type, wp_addr, wp_len);
  57         fd = sys_perf_event_open(&attr, 0, -1, -1,
  58                                  perf_event_open_cloexec_flag());
  59         if (fd < 0)
  60                 pr_debug("failed opening event %x\n", attr.bp_type);
  61 
  62         return fd;
  63 }
  64 
  65 static int wp_ro_test(void)
  66 {
  67         int fd;
  68         unsigned long tmp, tmp1 = rand();
  69 
  70         fd = __event(HW_BREAKPOINT_R, (void *)&data1, sizeof(data1));
  71         if (fd < 0)
  72                 return -1;
  73 
  74         tmp = data1;
  75         WP_TEST_ASSERT_VAL(fd, "RO watchpoint", 1);
  76 
  77         data1 = tmp1 + tmp;
  78         WP_TEST_ASSERT_VAL(fd, "RO watchpoint", 1);
  79 
  80         close(fd);
  81         return 0;
  82 }
  83 
  84 static int wp_wo_test(void)
  85 {
  86         int fd;
  87         unsigned long tmp, tmp1 = rand();
  88 
  89         fd = __event(HW_BREAKPOINT_W, (void *)&data1, sizeof(data1));
  90         if (fd < 0)
  91                 return -1;
  92 
  93         tmp = data1;
  94         WP_TEST_ASSERT_VAL(fd, "WO watchpoint", 0);
  95 
  96         data1 = tmp1 + tmp;
  97         WP_TEST_ASSERT_VAL(fd, "WO watchpoint", 1);
  98 
  99         close(fd);
 100         return 0;
 101 }
 102 
 103 static int wp_rw_test(void)
 104 {
 105         int fd;
 106         unsigned long tmp, tmp1 = rand();
 107 
 108         fd = __event(HW_BREAKPOINT_R | HW_BREAKPOINT_W, (void *)&data1,
 109                      sizeof(data1));
 110         if (fd < 0)
 111                 return -1;
 112 
 113         tmp = data1;
 114         WP_TEST_ASSERT_VAL(fd, "RW watchpoint", 1);
 115 
 116         data1 = tmp1 + tmp;
 117         WP_TEST_ASSERT_VAL(fd, "RW watchpoint", 2);
 118 
 119         close(fd);
 120         return 0;
 121 }
 122 
 123 static int wp_modify_test(void)
 124 {
 125         int fd, ret;
 126         unsigned long tmp = rand();
 127         struct perf_event_attr new_attr;
 128 
 129         fd = __event(HW_BREAKPOINT_W, (void *)&data1, sizeof(data1));
 130         if (fd < 0)
 131                 return -1;
 132 
 133         data1 = tmp;
 134         WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 1);
 135 
 136         /* Modify watchpoint with disabled = 1 */
 137         get__perf_event_attr(&new_attr, HW_BREAKPOINT_W, (void *)&data2[0],
 138                              sizeof(u8) * 2);
 139         new_attr.disabled = 1;
 140         ret = ioctl(fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr);
 141         if (ret < 0) {
 142                 pr_debug("ioctl(PERF_EVENT_IOC_MODIFY_ATTRIBUTES) failed\n");
 143                 close(fd);
 144                 return ret;
 145         }
 146 
 147         data2[1] = tmp; /* Not Counted */
 148         WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 1);
 149 
 150         /* Enable the event */
 151         ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
 152         if (ret < 0) {
 153                 pr_debug("Failed to enable event\n");
 154                 close(fd);
 155                 return ret;
 156         }
 157 
 158         data2[1] = tmp; /* Counted */
 159         WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 2);
 160 
 161         data2[2] = tmp; /* Not Counted */
 162         WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 2);
 163 
 164         close(fd);
 165         return 0;
 166 }
 167 
 168 static bool wp_ro_supported(void)
 169 {
 170 #if defined (__x86_64__) || defined (__i386__)
 171         return false;
 172 #else
 173         return true;
 174 #endif
 175 }
 176 
 177 static void wp_ro_skip_msg(void)
 178 {
 179 #if defined (__x86_64__) || defined (__i386__)
 180         pr_debug("Hardware does not support read only watchpoints.\n");
 181 #endif
 182 }
 183 
 184 static struct {
 185         const char *desc;
 186         int (*target_func)(void);
 187         bool (*is_supported)(void);
 188         void (*skip_msg)(void);
 189 } wp_testcase_table[] = {
 190         {
 191                 .desc = "Read Only Watchpoint",
 192                 .target_func = &wp_ro_test,
 193                 .is_supported = &wp_ro_supported,
 194                 .skip_msg = &wp_ro_skip_msg,
 195         },
 196         {
 197                 .desc = "Write Only Watchpoint",
 198                 .target_func = &wp_wo_test,
 199         },
 200         {
 201                 .desc = "Read / Write Watchpoint",
 202                 .target_func = &wp_rw_test,
 203         },
 204         {
 205                 .desc = "Modify Watchpoint",
 206                 .target_func = &wp_modify_test,
 207         },
 208 };
 209 
 210 int test__wp_subtest_get_nr(void)
 211 {
 212         return (int)ARRAY_SIZE(wp_testcase_table);
 213 }
 214 
 215 const char *test__wp_subtest_get_desc(int i)
 216 {
 217         if (i < 0 || i >= (int)ARRAY_SIZE(wp_testcase_table))
 218                 return NULL;
 219         return wp_testcase_table[i].desc;
 220 }
 221 
 222 int test__wp(struct test *test __maybe_unused, int i)
 223 {
 224         if (i < 0 || i >= (int)ARRAY_SIZE(wp_testcase_table))
 225                 return TEST_FAIL;
 226 
 227         if (wp_testcase_table[i].is_supported &&
 228             !wp_testcase_table[i].is_supported()) {
 229                 wp_testcase_table[i].skip_msg();
 230                 return TEST_SKIP;
 231         }
 232 
 233         return !wp_testcase_table[i].target_func() ? TEST_OK : TEST_FAIL;
 234 }
 235 
 236 /* The s390 so far does not have support for
 237  * instruction breakpoint using the perf_event_open() system call.
 238  */
 239 bool test__wp_is_supported(void)
 240 {
 241 #if defined(__s390x__)
 242         return false;
 243 #else
 244         return true;
 245 #endif
 246 }

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