| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * perf events self profiling example test case for hw breakpoints. |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 14 | 15 | * http://ozlabs.org/~anton/junkcode/perf_events_example1.c |
|---|
| 15 | 16 | * |
|---|
| 16 | 17 | * Copyright (C) 2018 Michael Neuling, IBM Corporation. |
|---|
| 17 | | - * |
|---|
| 18 | | - * This program is free software; you can redistribute it and/or |
|---|
| 19 | | - * modify it under the terms of the GNU General Public License |
|---|
| 20 | | - * as published by the Free Software Foundation; either version |
|---|
| 21 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 22 | 18 | */ |
|---|
| 23 | 19 | |
|---|
| 24 | 20 | #include <unistd.h> |
|---|
| .. | .. |
|---|
| 152 | 148 | return 0; |
|---|
| 153 | 149 | } |
|---|
| 154 | 150 | |
|---|
| 151 | +static int runtest_dar_outside(void) |
|---|
| 152 | +{ |
|---|
| 153 | + void *target; |
|---|
| 154 | + volatile __u16 temp16; |
|---|
| 155 | + volatile __u64 temp64; |
|---|
| 156 | + struct perf_event_attr attr; |
|---|
| 157 | + int break_fd; |
|---|
| 158 | + unsigned long long breaks; |
|---|
| 159 | + int fail = 0; |
|---|
| 160 | + size_t res; |
|---|
| 161 | + |
|---|
| 162 | + target = malloc(8); |
|---|
| 163 | + if (!target) { |
|---|
| 164 | + perror("malloc failed"); |
|---|
| 165 | + exit(EXIT_FAILURE); |
|---|
| 166 | + } |
|---|
| 167 | + |
|---|
| 168 | + /* setup counters */ |
|---|
| 169 | + memset(&attr, 0, sizeof(attr)); |
|---|
| 170 | + attr.disabled = 1; |
|---|
| 171 | + attr.type = PERF_TYPE_BREAKPOINT; |
|---|
| 172 | + attr.exclude_kernel = 1; |
|---|
| 173 | + attr.exclude_hv = 1; |
|---|
| 174 | + attr.exclude_guest = 1; |
|---|
| 175 | + attr.bp_type = HW_BREAKPOINT_RW; |
|---|
| 176 | + /* watch middle half of target array */ |
|---|
| 177 | + attr.bp_addr = (__u64)(target + 2); |
|---|
| 178 | + attr.bp_len = 4; |
|---|
| 179 | + break_fd = sys_perf_event_open(&attr, 0, -1, -1, 0); |
|---|
| 180 | + if (break_fd < 0) { |
|---|
| 181 | + free(target); |
|---|
| 182 | + perror("sys_perf_event_open"); |
|---|
| 183 | + exit(EXIT_FAILURE); |
|---|
| 184 | + } |
|---|
| 185 | + |
|---|
| 186 | + /* Shouldn't hit. */ |
|---|
| 187 | + ioctl(break_fd, PERF_EVENT_IOC_RESET); |
|---|
| 188 | + ioctl(break_fd, PERF_EVENT_IOC_ENABLE); |
|---|
| 189 | + temp16 = *((__u16 *)target); |
|---|
| 190 | + *((__u16 *)target) = temp16; |
|---|
| 191 | + ioctl(break_fd, PERF_EVENT_IOC_DISABLE); |
|---|
| 192 | + res = read(break_fd, &breaks, sizeof(unsigned long long)); |
|---|
| 193 | + assert(res == sizeof(unsigned long long)); |
|---|
| 194 | + if (breaks == 0) { |
|---|
| 195 | + printf("TESTED: No overlap\n"); |
|---|
| 196 | + } else { |
|---|
| 197 | + printf("FAILED: No overlap: %lld != 0\n", breaks); |
|---|
| 198 | + fail = 1; |
|---|
| 199 | + } |
|---|
| 200 | + |
|---|
| 201 | + /* Hit */ |
|---|
| 202 | + ioctl(break_fd, PERF_EVENT_IOC_RESET); |
|---|
| 203 | + ioctl(break_fd, PERF_EVENT_IOC_ENABLE); |
|---|
| 204 | + temp16 = *((__u16 *)(target + 1)); |
|---|
| 205 | + *((__u16 *)(target + 1)) = temp16; |
|---|
| 206 | + ioctl(break_fd, PERF_EVENT_IOC_DISABLE); |
|---|
| 207 | + res = read(break_fd, &breaks, sizeof(unsigned long long)); |
|---|
| 208 | + assert(res == sizeof(unsigned long long)); |
|---|
| 209 | + if (breaks == 2) { |
|---|
| 210 | + printf("TESTED: Partial overlap\n"); |
|---|
| 211 | + } else { |
|---|
| 212 | + printf("FAILED: Partial overlap: %lld != 2\n", breaks); |
|---|
| 213 | + fail = 1; |
|---|
| 214 | + } |
|---|
| 215 | + |
|---|
| 216 | + /* Hit */ |
|---|
| 217 | + ioctl(break_fd, PERF_EVENT_IOC_RESET); |
|---|
| 218 | + ioctl(break_fd, PERF_EVENT_IOC_ENABLE); |
|---|
| 219 | + temp16 = *((__u16 *)(target + 5)); |
|---|
| 220 | + *((__u16 *)(target + 5)) = temp16; |
|---|
| 221 | + ioctl(break_fd, PERF_EVENT_IOC_DISABLE); |
|---|
| 222 | + res = read(break_fd, &breaks, sizeof(unsigned long long)); |
|---|
| 223 | + assert(res == sizeof(unsigned long long)); |
|---|
| 224 | + if (breaks == 2) { |
|---|
| 225 | + printf("TESTED: Partial overlap\n"); |
|---|
| 226 | + } else { |
|---|
| 227 | + printf("FAILED: Partial overlap: %lld != 2\n", breaks); |
|---|
| 228 | + fail = 1; |
|---|
| 229 | + } |
|---|
| 230 | + |
|---|
| 231 | + /* Shouldn't Hit */ |
|---|
| 232 | + ioctl(break_fd, PERF_EVENT_IOC_RESET); |
|---|
| 233 | + ioctl(break_fd, PERF_EVENT_IOC_ENABLE); |
|---|
| 234 | + temp16 = *((__u16 *)(target + 6)); |
|---|
| 235 | + *((__u16 *)(target + 6)) = temp16; |
|---|
| 236 | + ioctl(break_fd, PERF_EVENT_IOC_DISABLE); |
|---|
| 237 | + res = read(break_fd, &breaks, sizeof(unsigned long long)); |
|---|
| 238 | + assert(res == sizeof(unsigned long long)); |
|---|
| 239 | + if (breaks == 0) { |
|---|
| 240 | + printf("TESTED: No overlap\n"); |
|---|
| 241 | + } else { |
|---|
| 242 | + printf("FAILED: No overlap: %lld != 0\n", breaks); |
|---|
| 243 | + fail = 1; |
|---|
| 244 | + } |
|---|
| 245 | + |
|---|
| 246 | + /* Hit */ |
|---|
| 247 | + ioctl(break_fd, PERF_EVENT_IOC_RESET); |
|---|
| 248 | + ioctl(break_fd, PERF_EVENT_IOC_ENABLE); |
|---|
| 249 | + temp64 = *((__u64 *)target); |
|---|
| 250 | + *((__u64 *)target) = temp64; |
|---|
| 251 | + ioctl(break_fd, PERF_EVENT_IOC_DISABLE); |
|---|
| 252 | + res = read(break_fd, &breaks, sizeof(unsigned long long)); |
|---|
| 253 | + assert(res == sizeof(unsigned long long)); |
|---|
| 254 | + if (breaks == 2) { |
|---|
| 255 | + printf("TESTED: Full overlap\n"); |
|---|
| 256 | + } else { |
|---|
| 257 | + printf("FAILED: Full overlap: %lld != 2\n", breaks); |
|---|
| 258 | + fail = 1; |
|---|
| 259 | + } |
|---|
| 260 | + |
|---|
| 261 | + free(target); |
|---|
| 262 | + close(break_fd); |
|---|
| 263 | + return fail; |
|---|
| 264 | +} |
|---|
| 265 | + |
|---|
| 155 | 266 | static int runtest(void) |
|---|
| 156 | 267 | { |
|---|
| 157 | 268 | int rwflag; |
|---|
| .. | .. |
|---|
| 176 | 287 | return ret; |
|---|
| 177 | 288 | } |
|---|
| 178 | 289 | } |
|---|
| 179 | | - return 0; |
|---|
| 290 | + |
|---|
| 291 | + ret = runtest_dar_outside(); |
|---|
| 292 | + return ret; |
|---|
| 180 | 293 | } |
|---|
| 181 | 294 | |
|---|
| 182 | 295 | |
|---|