1290f7d8cSRavi Bangoria // SPDX-License-Identifier: GPL-2.0+ 2290f7d8cSRavi Bangoria #include <stdio.h> 3290f7d8cSRavi Bangoria #include <string.h> 4290f7d8cSRavi Bangoria #include <signal.h> 5290f7d8cSRavi Bangoria #include <stdlib.h> 6290f7d8cSRavi Bangoria #include <unistd.h> 7290f7d8cSRavi Bangoria #include <errno.h> 8290f7d8cSRavi Bangoria #include <linux/hw_breakpoint.h> 9290f7d8cSRavi Bangoria #include <linux/perf_event.h> 10290f7d8cSRavi Bangoria #include <asm/unistd.h> 11290f7d8cSRavi Bangoria #include <sys/ptrace.h> 12290f7d8cSRavi Bangoria #include <sys/wait.h> 13290f7d8cSRavi Bangoria #include "ptrace.h" 14290f7d8cSRavi Bangoria 15290f7d8cSRavi Bangoria char data[16]; 16290f7d8cSRavi Bangoria 17290f7d8cSRavi Bangoria /* Overlapping address range */ 18290f7d8cSRavi Bangoria volatile __u64 *ptrace_data1 = (__u64 *)&data[0]; 19290f7d8cSRavi Bangoria volatile __u64 *perf_data1 = (__u64 *)&data[4]; 20290f7d8cSRavi Bangoria 21290f7d8cSRavi Bangoria /* Non-overlapping address range */ 22290f7d8cSRavi Bangoria volatile __u64 *ptrace_data2 = (__u64 *)&data[0]; 23290f7d8cSRavi Bangoria volatile __u64 *perf_data2 = (__u64 *)&data[8]; 24290f7d8cSRavi Bangoria 25290f7d8cSRavi Bangoria static unsigned long pid_max_addr(void) 26290f7d8cSRavi Bangoria { 27290f7d8cSRavi Bangoria FILE *fp; 28290f7d8cSRavi Bangoria char *line, *c; 29290f7d8cSRavi Bangoria char addr[100]; 30290f7d8cSRavi Bangoria size_t len = 0; 31290f7d8cSRavi Bangoria 32290f7d8cSRavi Bangoria fp = fopen("/proc/kallsyms", "r"); 33290f7d8cSRavi Bangoria if (!fp) { 34290f7d8cSRavi Bangoria printf("Failed to read /proc/kallsyms. Exiting..\n"); 35290f7d8cSRavi Bangoria exit(EXIT_FAILURE); 36290f7d8cSRavi Bangoria } 37290f7d8cSRavi Bangoria 38290f7d8cSRavi Bangoria while (getline(&line, &len, fp) != -1) { 39290f7d8cSRavi Bangoria if (!strstr(line, "pid_max") || strstr(line, "pid_max_max") || 40290f7d8cSRavi Bangoria strstr(line, "pid_max_min")) 41290f7d8cSRavi Bangoria continue; 42290f7d8cSRavi Bangoria 43290f7d8cSRavi Bangoria strncpy(addr, line, len < 100 ? len : 100); 44290f7d8cSRavi Bangoria c = strchr(addr, ' '); 45290f7d8cSRavi Bangoria *c = '\0'; 46290f7d8cSRavi Bangoria return strtoul(addr, &c, 16); 47290f7d8cSRavi Bangoria } 48290f7d8cSRavi Bangoria fclose(fp); 49290f7d8cSRavi Bangoria printf("Could not find pix_max. Exiting..\n"); 50290f7d8cSRavi Bangoria exit(EXIT_FAILURE); 51290f7d8cSRavi Bangoria return -1; 52290f7d8cSRavi Bangoria } 53290f7d8cSRavi Bangoria 54290f7d8cSRavi Bangoria static void perf_user_event_attr_set(struct perf_event_attr *attr, __u64 addr, __u64 len) 55290f7d8cSRavi Bangoria { 56290f7d8cSRavi Bangoria memset(attr, 0, sizeof(struct perf_event_attr)); 57290f7d8cSRavi Bangoria attr->type = PERF_TYPE_BREAKPOINT; 58290f7d8cSRavi Bangoria attr->size = sizeof(struct perf_event_attr); 59290f7d8cSRavi Bangoria attr->bp_type = HW_BREAKPOINT_R; 60290f7d8cSRavi Bangoria attr->bp_addr = addr; 61290f7d8cSRavi Bangoria attr->bp_len = len; 62290f7d8cSRavi Bangoria attr->exclude_kernel = 1; 63290f7d8cSRavi Bangoria attr->exclude_hv = 1; 64290f7d8cSRavi Bangoria } 65290f7d8cSRavi Bangoria 66290f7d8cSRavi Bangoria static void perf_kernel_event_attr_set(struct perf_event_attr *attr) 67290f7d8cSRavi Bangoria { 68290f7d8cSRavi Bangoria memset(attr, 0, sizeof(struct perf_event_attr)); 69290f7d8cSRavi Bangoria attr->type = PERF_TYPE_BREAKPOINT; 70290f7d8cSRavi Bangoria attr->size = sizeof(struct perf_event_attr); 71290f7d8cSRavi Bangoria attr->bp_type = HW_BREAKPOINT_R; 72290f7d8cSRavi Bangoria attr->bp_addr = pid_max_addr(); 73290f7d8cSRavi Bangoria attr->bp_len = sizeof(unsigned long); 74290f7d8cSRavi Bangoria attr->exclude_user = 1; 75290f7d8cSRavi Bangoria attr->exclude_hv = 1; 76290f7d8cSRavi Bangoria } 77290f7d8cSRavi Bangoria 78290f7d8cSRavi Bangoria static int perf_cpu_event_open(int cpu, __u64 addr, __u64 len) 79290f7d8cSRavi Bangoria { 80290f7d8cSRavi Bangoria struct perf_event_attr attr; 81290f7d8cSRavi Bangoria 82290f7d8cSRavi Bangoria perf_user_event_attr_set(&attr, addr, len); 83290f7d8cSRavi Bangoria return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0); 84290f7d8cSRavi Bangoria } 85290f7d8cSRavi Bangoria 86290f7d8cSRavi Bangoria static int perf_thread_event_open(pid_t child_pid, __u64 addr, __u64 len) 87290f7d8cSRavi Bangoria { 88290f7d8cSRavi Bangoria struct perf_event_attr attr; 89290f7d8cSRavi Bangoria 90290f7d8cSRavi Bangoria perf_user_event_attr_set(&attr, addr, len); 91290f7d8cSRavi Bangoria return syscall(__NR_perf_event_open, &attr, child_pid, -1, -1, 0); 92290f7d8cSRavi Bangoria } 93290f7d8cSRavi Bangoria 94290f7d8cSRavi Bangoria static int perf_thread_cpu_event_open(pid_t child_pid, int cpu, __u64 addr, __u64 len) 95290f7d8cSRavi Bangoria { 96290f7d8cSRavi Bangoria struct perf_event_attr attr; 97290f7d8cSRavi Bangoria 98290f7d8cSRavi Bangoria perf_user_event_attr_set(&attr, addr, len); 99290f7d8cSRavi Bangoria return syscall(__NR_perf_event_open, &attr, child_pid, cpu, -1, 0); 100290f7d8cSRavi Bangoria } 101290f7d8cSRavi Bangoria 102290f7d8cSRavi Bangoria static int perf_thread_kernel_event_open(pid_t child_pid) 103290f7d8cSRavi Bangoria { 104290f7d8cSRavi Bangoria struct perf_event_attr attr; 105290f7d8cSRavi Bangoria 106290f7d8cSRavi Bangoria perf_kernel_event_attr_set(&attr); 107290f7d8cSRavi Bangoria return syscall(__NR_perf_event_open, &attr, child_pid, -1, -1, 0); 108290f7d8cSRavi Bangoria } 109290f7d8cSRavi Bangoria 110290f7d8cSRavi Bangoria static int perf_cpu_kernel_event_open(int cpu) 111290f7d8cSRavi Bangoria { 112290f7d8cSRavi Bangoria struct perf_event_attr attr; 113290f7d8cSRavi Bangoria 114290f7d8cSRavi Bangoria perf_kernel_event_attr_set(&attr); 115290f7d8cSRavi Bangoria return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0); 116290f7d8cSRavi Bangoria } 117290f7d8cSRavi Bangoria 118290f7d8cSRavi Bangoria static int child(void) 119290f7d8cSRavi Bangoria { 120290f7d8cSRavi Bangoria int ret; 121290f7d8cSRavi Bangoria 122290f7d8cSRavi Bangoria ret = ptrace(PTRACE_TRACEME, 0, NULL, 0); 123290f7d8cSRavi Bangoria if (ret) { 124290f7d8cSRavi Bangoria printf("Error: PTRACE_TRACEME failed\n"); 125290f7d8cSRavi Bangoria return 0; 126290f7d8cSRavi Bangoria } 127290f7d8cSRavi Bangoria kill(getpid(), SIGUSR1); /* --> parent (SIGUSR1) */ 128290f7d8cSRavi Bangoria 129290f7d8cSRavi Bangoria return 0; 130290f7d8cSRavi Bangoria } 131290f7d8cSRavi Bangoria 132290f7d8cSRavi Bangoria static void ptrace_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type, 133290f7d8cSRavi Bangoria __u64 addr, int len) 134290f7d8cSRavi Bangoria { 135290f7d8cSRavi Bangoria info->version = 1; 136290f7d8cSRavi Bangoria info->trigger_type = type; 137290f7d8cSRavi Bangoria info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE; 138290f7d8cSRavi Bangoria info->addr = addr; 139290f7d8cSRavi Bangoria info->addr2 = addr + len; 140290f7d8cSRavi Bangoria info->condition_value = 0; 141290f7d8cSRavi Bangoria if (!len) 142290f7d8cSRavi Bangoria info->addr_mode = PPC_BREAKPOINT_MODE_EXACT; 143290f7d8cSRavi Bangoria else 144290f7d8cSRavi Bangoria info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE; 145290f7d8cSRavi Bangoria } 146290f7d8cSRavi Bangoria 147290f7d8cSRavi Bangoria static int ptrace_open(pid_t child_pid, __u64 wp_addr, int len) 148290f7d8cSRavi Bangoria { 149290f7d8cSRavi Bangoria struct ppc_hw_breakpoint info; 150290f7d8cSRavi Bangoria 151290f7d8cSRavi Bangoria ptrace_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len); 152290f7d8cSRavi Bangoria return ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, &info); 153290f7d8cSRavi Bangoria } 154290f7d8cSRavi Bangoria 155290f7d8cSRavi Bangoria static int test1(pid_t child_pid) 156290f7d8cSRavi Bangoria { 157290f7d8cSRavi Bangoria int perf_fd; 158290f7d8cSRavi Bangoria int ptrace_fd; 159290f7d8cSRavi Bangoria int ret = 0; 160290f7d8cSRavi Bangoria 161290f7d8cSRavi Bangoria /* Test: 162290f7d8cSRavi Bangoria * if (new per thread event by ptrace) 163290f7d8cSRavi Bangoria * if (existing cpu event by perf) 164290f7d8cSRavi Bangoria * if (addr range overlaps) 165290f7d8cSRavi Bangoria * fail; 166290f7d8cSRavi Bangoria */ 167290f7d8cSRavi Bangoria 168290f7d8cSRavi Bangoria perf_fd = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1)); 169290f7d8cSRavi Bangoria if (perf_fd < 0) 170290f7d8cSRavi Bangoria return -1; 171290f7d8cSRavi Bangoria 172290f7d8cSRavi Bangoria ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 173290f7d8cSRavi Bangoria if (ptrace_fd > 0 || errno != ENOSPC) 174290f7d8cSRavi Bangoria ret = -1; 175290f7d8cSRavi Bangoria 176290f7d8cSRavi Bangoria close(perf_fd); 177290f7d8cSRavi Bangoria return ret; 178290f7d8cSRavi Bangoria } 179290f7d8cSRavi Bangoria 180290f7d8cSRavi Bangoria static int test2(pid_t child_pid) 181290f7d8cSRavi Bangoria { 182290f7d8cSRavi Bangoria int perf_fd; 183290f7d8cSRavi Bangoria int ptrace_fd; 184290f7d8cSRavi Bangoria int ret = 0; 185290f7d8cSRavi Bangoria 186290f7d8cSRavi Bangoria /* Test: 187290f7d8cSRavi Bangoria * if (new per thread event by ptrace) 188290f7d8cSRavi Bangoria * if (existing cpu event by perf) 189290f7d8cSRavi Bangoria * if (addr range does not overlaps) 190290f7d8cSRavi Bangoria * allow; 191290f7d8cSRavi Bangoria */ 192290f7d8cSRavi Bangoria 193290f7d8cSRavi Bangoria perf_fd = perf_cpu_event_open(0, (__u64)perf_data2, sizeof(*perf_data2)); 194290f7d8cSRavi Bangoria if (perf_fd < 0) 195290f7d8cSRavi Bangoria return -1; 196290f7d8cSRavi Bangoria 197290f7d8cSRavi Bangoria ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2)); 198290f7d8cSRavi Bangoria if (ptrace_fd < 0) { 199290f7d8cSRavi Bangoria ret = -1; 200290f7d8cSRavi Bangoria goto perf_close; 201290f7d8cSRavi Bangoria } 202290f7d8cSRavi Bangoria ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 203290f7d8cSRavi Bangoria 204290f7d8cSRavi Bangoria perf_close: 205290f7d8cSRavi Bangoria close(perf_fd); 206290f7d8cSRavi Bangoria return ret; 207290f7d8cSRavi Bangoria } 208290f7d8cSRavi Bangoria 209290f7d8cSRavi Bangoria static int test3(pid_t child_pid) 210290f7d8cSRavi Bangoria { 211290f7d8cSRavi Bangoria int perf_fd; 212290f7d8cSRavi Bangoria int ptrace_fd; 213290f7d8cSRavi Bangoria int ret = 0; 214290f7d8cSRavi Bangoria 215290f7d8cSRavi Bangoria /* Test: 216290f7d8cSRavi Bangoria * if (new per thread event by ptrace) 217290f7d8cSRavi Bangoria * if (existing thread event by perf on the same thread) 218290f7d8cSRavi Bangoria * if (addr range overlaps) 219290f7d8cSRavi Bangoria * fail; 220290f7d8cSRavi Bangoria */ 221290f7d8cSRavi Bangoria perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data1, 222290f7d8cSRavi Bangoria sizeof(*perf_data1)); 223290f7d8cSRavi Bangoria if (perf_fd < 0) 224290f7d8cSRavi Bangoria return -1; 225290f7d8cSRavi Bangoria 226290f7d8cSRavi Bangoria ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 227290f7d8cSRavi Bangoria if (ptrace_fd > 0 || errno != ENOSPC) 228290f7d8cSRavi Bangoria ret = -1; 229290f7d8cSRavi Bangoria 230290f7d8cSRavi Bangoria close(perf_fd); 231290f7d8cSRavi Bangoria return ret; 232290f7d8cSRavi Bangoria } 233290f7d8cSRavi Bangoria 234290f7d8cSRavi Bangoria static int test4(pid_t child_pid) 235290f7d8cSRavi Bangoria { 236290f7d8cSRavi Bangoria int perf_fd; 237290f7d8cSRavi Bangoria int ptrace_fd; 238290f7d8cSRavi Bangoria int ret = 0; 239290f7d8cSRavi Bangoria 240290f7d8cSRavi Bangoria /* Test: 241290f7d8cSRavi Bangoria * if (new per thread event by ptrace) 242290f7d8cSRavi Bangoria * if (existing thread event by perf on the same thread) 243290f7d8cSRavi Bangoria * if (addr range does not overlaps) 244290f7d8cSRavi Bangoria * fail; 245290f7d8cSRavi Bangoria */ 246290f7d8cSRavi Bangoria perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data2, 247290f7d8cSRavi Bangoria sizeof(*perf_data2)); 248290f7d8cSRavi Bangoria if (perf_fd < 0) 249290f7d8cSRavi Bangoria return -1; 250290f7d8cSRavi Bangoria 251290f7d8cSRavi Bangoria ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2)); 252290f7d8cSRavi Bangoria if (ptrace_fd < 0) { 253290f7d8cSRavi Bangoria ret = -1; 254290f7d8cSRavi Bangoria goto perf_close; 255290f7d8cSRavi Bangoria } 256290f7d8cSRavi Bangoria ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 257290f7d8cSRavi Bangoria 258290f7d8cSRavi Bangoria perf_close: 259290f7d8cSRavi Bangoria close(perf_fd); 260290f7d8cSRavi Bangoria return ret; 261290f7d8cSRavi Bangoria } 262290f7d8cSRavi Bangoria 263290f7d8cSRavi Bangoria static int test5(pid_t child_pid) 264290f7d8cSRavi Bangoria { 265290f7d8cSRavi Bangoria int perf_fd; 266290f7d8cSRavi Bangoria int ptrace_fd; 267290f7d8cSRavi Bangoria int cpid; 268290f7d8cSRavi Bangoria int ret = 0; 269290f7d8cSRavi Bangoria 270290f7d8cSRavi Bangoria /* Test: 271290f7d8cSRavi Bangoria * if (new per thread event by ptrace) 272290f7d8cSRavi Bangoria * if (existing thread event by perf on the different thread) 273290f7d8cSRavi Bangoria * allow; 274290f7d8cSRavi Bangoria */ 275290f7d8cSRavi Bangoria cpid = fork(); 276290f7d8cSRavi Bangoria if (!cpid) { 277290f7d8cSRavi Bangoria /* Temporary Child */ 278290f7d8cSRavi Bangoria pause(); 279290f7d8cSRavi Bangoria exit(EXIT_SUCCESS); 280290f7d8cSRavi Bangoria } 281290f7d8cSRavi Bangoria 282290f7d8cSRavi Bangoria perf_fd = perf_thread_event_open(cpid, (__u64)perf_data1, sizeof(*perf_data1)); 283290f7d8cSRavi Bangoria if (perf_fd < 0) { 284290f7d8cSRavi Bangoria ret = -1; 285290f7d8cSRavi Bangoria goto kill_child; 286290f7d8cSRavi Bangoria } 287290f7d8cSRavi Bangoria 288290f7d8cSRavi Bangoria ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 289290f7d8cSRavi Bangoria if (ptrace_fd < 0) { 290290f7d8cSRavi Bangoria ret = -1; 291290f7d8cSRavi Bangoria goto perf_close; 292290f7d8cSRavi Bangoria } 293290f7d8cSRavi Bangoria 294290f7d8cSRavi Bangoria ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 295290f7d8cSRavi Bangoria perf_close: 296290f7d8cSRavi Bangoria close(perf_fd); 297290f7d8cSRavi Bangoria kill_child: 298290f7d8cSRavi Bangoria kill(cpid, SIGINT); 299290f7d8cSRavi Bangoria return ret; 300290f7d8cSRavi Bangoria } 301290f7d8cSRavi Bangoria 302290f7d8cSRavi Bangoria static int test6(pid_t child_pid) 303290f7d8cSRavi Bangoria { 304290f7d8cSRavi Bangoria int perf_fd; 305290f7d8cSRavi Bangoria int ptrace_fd; 306290f7d8cSRavi Bangoria int ret = 0; 307290f7d8cSRavi Bangoria 308290f7d8cSRavi Bangoria /* Test: 309290f7d8cSRavi Bangoria * if (new per thread kernel event by perf) 310290f7d8cSRavi Bangoria * if (existing thread event by ptrace on the same thread) 311290f7d8cSRavi Bangoria * allow; 312290f7d8cSRavi Bangoria * -- OR -- 313290f7d8cSRavi Bangoria * if (new per cpu kernel event by perf) 314290f7d8cSRavi Bangoria * if (existing thread event by ptrace) 315290f7d8cSRavi Bangoria * allow; 316290f7d8cSRavi Bangoria */ 317290f7d8cSRavi Bangoria ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 318290f7d8cSRavi Bangoria if (ptrace_fd < 0) 319290f7d8cSRavi Bangoria return -1; 320290f7d8cSRavi Bangoria 321290f7d8cSRavi Bangoria perf_fd = perf_thread_kernel_event_open(child_pid); 322290f7d8cSRavi Bangoria if (perf_fd < 0) { 323290f7d8cSRavi Bangoria ret = -1; 324290f7d8cSRavi Bangoria goto ptrace_close; 325290f7d8cSRavi Bangoria } 326290f7d8cSRavi Bangoria close(perf_fd); 327290f7d8cSRavi Bangoria 328290f7d8cSRavi Bangoria perf_fd = perf_cpu_kernel_event_open(0); 329290f7d8cSRavi Bangoria if (perf_fd < 0) { 330290f7d8cSRavi Bangoria ret = -1; 331290f7d8cSRavi Bangoria goto ptrace_close; 332290f7d8cSRavi Bangoria } 333290f7d8cSRavi Bangoria close(perf_fd); 334290f7d8cSRavi Bangoria 335290f7d8cSRavi Bangoria ptrace_close: 336290f7d8cSRavi Bangoria ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 337290f7d8cSRavi Bangoria return ret; 338290f7d8cSRavi Bangoria } 339290f7d8cSRavi Bangoria 340290f7d8cSRavi Bangoria static int test7(pid_t child_pid) 341290f7d8cSRavi Bangoria { 342290f7d8cSRavi Bangoria int perf_fd; 343290f7d8cSRavi Bangoria int ptrace_fd; 344290f7d8cSRavi Bangoria int ret = 0; 345290f7d8cSRavi Bangoria 346290f7d8cSRavi Bangoria /* Test: 347290f7d8cSRavi Bangoria * if (new per thread event by perf) 348290f7d8cSRavi Bangoria * if (existing thread event by ptrace on the same thread) 349290f7d8cSRavi Bangoria * if (addr range overlaps) 350290f7d8cSRavi Bangoria * fail; 351290f7d8cSRavi Bangoria */ 352290f7d8cSRavi Bangoria ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 353290f7d8cSRavi Bangoria if (ptrace_fd < 0) 354290f7d8cSRavi Bangoria return -1; 355290f7d8cSRavi Bangoria 356290f7d8cSRavi Bangoria perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data1, 357290f7d8cSRavi Bangoria sizeof(*perf_data1)); 358290f7d8cSRavi Bangoria if (perf_fd > 0 || errno != ENOSPC) 359290f7d8cSRavi Bangoria ret = -1; 360290f7d8cSRavi Bangoria 361290f7d8cSRavi Bangoria ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 362290f7d8cSRavi Bangoria return ret; 363290f7d8cSRavi Bangoria } 364290f7d8cSRavi Bangoria 365290f7d8cSRavi Bangoria static int test8(pid_t child_pid) 366290f7d8cSRavi Bangoria { 367290f7d8cSRavi Bangoria int perf_fd; 368290f7d8cSRavi Bangoria int ptrace_fd; 369290f7d8cSRavi Bangoria int ret = 0; 370290f7d8cSRavi Bangoria 371290f7d8cSRavi Bangoria /* Test: 372290f7d8cSRavi Bangoria * if (new per thread event by perf) 373290f7d8cSRavi Bangoria * if (existing thread event by ptrace on the same thread) 374290f7d8cSRavi Bangoria * if (addr range does not overlaps) 375290f7d8cSRavi Bangoria * allow; 376290f7d8cSRavi Bangoria */ 377290f7d8cSRavi Bangoria ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2)); 378290f7d8cSRavi Bangoria if (ptrace_fd < 0) 379290f7d8cSRavi Bangoria return -1; 380290f7d8cSRavi Bangoria 381290f7d8cSRavi Bangoria perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data2, 382290f7d8cSRavi Bangoria sizeof(*perf_data2)); 383290f7d8cSRavi Bangoria if (perf_fd < 0) { 384290f7d8cSRavi Bangoria ret = -1; 385290f7d8cSRavi Bangoria goto ptrace_close; 386290f7d8cSRavi Bangoria } 387290f7d8cSRavi Bangoria close(perf_fd); 388290f7d8cSRavi Bangoria 389290f7d8cSRavi Bangoria ptrace_close: 390290f7d8cSRavi Bangoria ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 391290f7d8cSRavi Bangoria return ret; 392290f7d8cSRavi Bangoria } 393290f7d8cSRavi Bangoria 394290f7d8cSRavi Bangoria static int test9(pid_t child_pid) 395290f7d8cSRavi Bangoria { 396290f7d8cSRavi Bangoria int perf_fd; 397290f7d8cSRavi Bangoria int ptrace_fd; 398290f7d8cSRavi Bangoria int cpid; 399290f7d8cSRavi Bangoria int ret = 0; 400290f7d8cSRavi Bangoria 401290f7d8cSRavi Bangoria /* Test: 402290f7d8cSRavi Bangoria * if (new per thread event by perf) 403290f7d8cSRavi Bangoria * if (existing thread event by ptrace on the other thread) 404290f7d8cSRavi Bangoria * allow; 405290f7d8cSRavi Bangoria */ 406290f7d8cSRavi Bangoria ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 407290f7d8cSRavi Bangoria if (ptrace_fd < 0) 408290f7d8cSRavi Bangoria return -1; 409290f7d8cSRavi Bangoria 410290f7d8cSRavi Bangoria cpid = fork(); 411290f7d8cSRavi Bangoria if (!cpid) { 412290f7d8cSRavi Bangoria /* Temporary Child */ 413290f7d8cSRavi Bangoria pause(); 414290f7d8cSRavi Bangoria exit(EXIT_SUCCESS); 415290f7d8cSRavi Bangoria } 416290f7d8cSRavi Bangoria 417290f7d8cSRavi Bangoria perf_fd = perf_thread_event_open(cpid, (__u64)perf_data1, sizeof(*perf_data1)); 418290f7d8cSRavi Bangoria if (perf_fd < 0) { 419290f7d8cSRavi Bangoria ret = -1; 420290f7d8cSRavi Bangoria goto kill_child; 421290f7d8cSRavi Bangoria } 422290f7d8cSRavi Bangoria close(perf_fd); 423290f7d8cSRavi Bangoria 424290f7d8cSRavi Bangoria kill_child: 425290f7d8cSRavi Bangoria kill(cpid, SIGINT); 426290f7d8cSRavi Bangoria ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 427290f7d8cSRavi Bangoria return ret; 428290f7d8cSRavi Bangoria } 429290f7d8cSRavi Bangoria 430290f7d8cSRavi Bangoria static int test10(pid_t child_pid) 431290f7d8cSRavi Bangoria { 432290f7d8cSRavi Bangoria int perf_fd; 433290f7d8cSRavi Bangoria int ptrace_fd; 434290f7d8cSRavi Bangoria int ret = 0; 435290f7d8cSRavi Bangoria 436290f7d8cSRavi Bangoria /* Test: 437290f7d8cSRavi Bangoria * if (new per cpu event by perf) 438290f7d8cSRavi Bangoria * if (existing thread event by ptrace on the same thread) 439290f7d8cSRavi Bangoria * if (addr range overlaps) 440290f7d8cSRavi Bangoria * fail; 441290f7d8cSRavi Bangoria */ 442290f7d8cSRavi Bangoria ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 443290f7d8cSRavi Bangoria if (ptrace_fd < 0) 444290f7d8cSRavi Bangoria return -1; 445290f7d8cSRavi Bangoria 446290f7d8cSRavi Bangoria perf_fd = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1)); 447290f7d8cSRavi Bangoria if (perf_fd > 0 || errno != ENOSPC) 448290f7d8cSRavi Bangoria ret = -1; 449290f7d8cSRavi Bangoria 450290f7d8cSRavi Bangoria ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 451290f7d8cSRavi Bangoria return ret; 452290f7d8cSRavi Bangoria } 453290f7d8cSRavi Bangoria 454290f7d8cSRavi Bangoria static int test11(pid_t child_pid) 455290f7d8cSRavi Bangoria { 456290f7d8cSRavi Bangoria int perf_fd; 457290f7d8cSRavi Bangoria int ptrace_fd; 458290f7d8cSRavi Bangoria int ret = 0; 459290f7d8cSRavi Bangoria 460290f7d8cSRavi Bangoria /* Test: 461290f7d8cSRavi Bangoria * if (new per cpu event by perf) 462290f7d8cSRavi Bangoria * if (existing thread event by ptrace on the same thread) 463290f7d8cSRavi Bangoria * if (addr range does not overlap) 464290f7d8cSRavi Bangoria * allow; 465290f7d8cSRavi Bangoria */ 466290f7d8cSRavi Bangoria ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2)); 467290f7d8cSRavi Bangoria if (ptrace_fd < 0) 468290f7d8cSRavi Bangoria return -1; 469290f7d8cSRavi Bangoria 470290f7d8cSRavi Bangoria perf_fd = perf_cpu_event_open(0, (__u64)perf_data2, sizeof(*perf_data2)); 471290f7d8cSRavi Bangoria if (perf_fd < 0) { 472290f7d8cSRavi Bangoria ret = -1; 473290f7d8cSRavi Bangoria goto ptrace_close; 474290f7d8cSRavi Bangoria } 475290f7d8cSRavi Bangoria close(perf_fd); 476290f7d8cSRavi Bangoria 477290f7d8cSRavi Bangoria ptrace_close: 478290f7d8cSRavi Bangoria ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 479290f7d8cSRavi Bangoria return ret; 480290f7d8cSRavi Bangoria } 481290f7d8cSRavi Bangoria 482290f7d8cSRavi Bangoria static int test12(pid_t child_pid) 483290f7d8cSRavi Bangoria { 484290f7d8cSRavi Bangoria int perf_fd; 485290f7d8cSRavi Bangoria int ptrace_fd; 486290f7d8cSRavi Bangoria int ret = 0; 487290f7d8cSRavi Bangoria 488290f7d8cSRavi Bangoria /* Test: 489290f7d8cSRavi Bangoria * if (new per thread and per cpu event by perf) 490290f7d8cSRavi Bangoria * if (existing thread event by ptrace on the same thread) 491290f7d8cSRavi Bangoria * if (addr range overlaps) 492290f7d8cSRavi Bangoria * fail; 493290f7d8cSRavi Bangoria */ 494290f7d8cSRavi Bangoria ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 495290f7d8cSRavi Bangoria if (ptrace_fd < 0) 496290f7d8cSRavi Bangoria return -1; 497290f7d8cSRavi Bangoria 498290f7d8cSRavi Bangoria perf_fd = perf_thread_cpu_event_open(child_pid, 0, (__u64)perf_data1, sizeof(*perf_data1)); 499290f7d8cSRavi Bangoria if (perf_fd > 0 || errno != ENOSPC) 500290f7d8cSRavi Bangoria ret = -1; 501290f7d8cSRavi Bangoria 502290f7d8cSRavi Bangoria ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 503290f7d8cSRavi Bangoria return ret; 504290f7d8cSRavi Bangoria } 505290f7d8cSRavi Bangoria 506290f7d8cSRavi Bangoria static int test13(pid_t child_pid) 507290f7d8cSRavi Bangoria { 508290f7d8cSRavi Bangoria int perf_fd; 509290f7d8cSRavi Bangoria int ptrace_fd; 510290f7d8cSRavi Bangoria int ret = 0; 511290f7d8cSRavi Bangoria 512290f7d8cSRavi Bangoria /* Test: 513290f7d8cSRavi Bangoria * if (new per thread and per cpu event by perf) 514290f7d8cSRavi Bangoria * if (existing thread event by ptrace on the same thread) 515290f7d8cSRavi Bangoria * if (addr range does not overlap) 516290f7d8cSRavi Bangoria * allow; 517290f7d8cSRavi Bangoria */ 518290f7d8cSRavi Bangoria ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2)); 519290f7d8cSRavi Bangoria if (ptrace_fd < 0) 520290f7d8cSRavi Bangoria return -1; 521290f7d8cSRavi Bangoria 522290f7d8cSRavi Bangoria perf_fd = perf_thread_cpu_event_open(child_pid, 0, (__u64)perf_data2, sizeof(*perf_data2)); 523290f7d8cSRavi Bangoria if (perf_fd < 0) { 524290f7d8cSRavi Bangoria ret = -1; 525290f7d8cSRavi Bangoria goto ptrace_close; 526290f7d8cSRavi Bangoria } 527290f7d8cSRavi Bangoria close(perf_fd); 528290f7d8cSRavi Bangoria 529290f7d8cSRavi Bangoria ptrace_close: 530290f7d8cSRavi Bangoria ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 531290f7d8cSRavi Bangoria return ret; 532290f7d8cSRavi Bangoria } 533290f7d8cSRavi Bangoria 534290f7d8cSRavi Bangoria static int test14(pid_t child_pid) 535290f7d8cSRavi Bangoria { 536290f7d8cSRavi Bangoria int perf_fd; 537290f7d8cSRavi Bangoria int ptrace_fd; 538290f7d8cSRavi Bangoria int cpid; 539290f7d8cSRavi Bangoria int ret = 0; 540290f7d8cSRavi Bangoria 541290f7d8cSRavi Bangoria /* Test: 542290f7d8cSRavi Bangoria * if (new per thread and per cpu event by perf) 543290f7d8cSRavi Bangoria * if (existing thread event by ptrace on the other thread) 544290f7d8cSRavi Bangoria * allow; 545290f7d8cSRavi Bangoria */ 546290f7d8cSRavi Bangoria ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 547290f7d8cSRavi Bangoria if (ptrace_fd < 0) 548290f7d8cSRavi Bangoria return -1; 549290f7d8cSRavi Bangoria 550290f7d8cSRavi Bangoria cpid = fork(); 551290f7d8cSRavi Bangoria if (!cpid) { 552290f7d8cSRavi Bangoria /* Temporary Child */ 553290f7d8cSRavi Bangoria pause(); 554290f7d8cSRavi Bangoria exit(EXIT_SUCCESS); 555290f7d8cSRavi Bangoria } 556290f7d8cSRavi Bangoria 557290f7d8cSRavi Bangoria perf_fd = perf_thread_cpu_event_open(cpid, 0, (__u64)perf_data1, 558290f7d8cSRavi Bangoria sizeof(*perf_data1)); 559290f7d8cSRavi Bangoria if (perf_fd < 0) { 560290f7d8cSRavi Bangoria ret = -1; 561290f7d8cSRavi Bangoria goto kill_child; 562290f7d8cSRavi Bangoria } 563290f7d8cSRavi Bangoria close(perf_fd); 564290f7d8cSRavi Bangoria 565290f7d8cSRavi Bangoria kill_child: 566290f7d8cSRavi Bangoria kill(cpid, SIGINT); 567290f7d8cSRavi Bangoria ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 568290f7d8cSRavi Bangoria return ret; 569290f7d8cSRavi Bangoria } 570290f7d8cSRavi Bangoria 571290f7d8cSRavi Bangoria static int do_test(const char *msg, int (*fun)(pid_t arg), pid_t arg) 572290f7d8cSRavi Bangoria { 573290f7d8cSRavi Bangoria int ret; 574290f7d8cSRavi Bangoria 575290f7d8cSRavi Bangoria ret = fun(arg); 576290f7d8cSRavi Bangoria if (ret) 577290f7d8cSRavi Bangoria printf("%s: Error\n", msg); 578290f7d8cSRavi Bangoria else 579290f7d8cSRavi Bangoria printf("%s: Ok\n", msg); 580290f7d8cSRavi Bangoria return ret; 581290f7d8cSRavi Bangoria } 582290f7d8cSRavi Bangoria 583290f7d8cSRavi Bangoria char *desc[14] = { 584290f7d8cSRavi Bangoria "perf cpu event -> ptrace thread event (Overlapping)", 585290f7d8cSRavi Bangoria "perf cpu event -> ptrace thread event (Non-overlapping)", 586290f7d8cSRavi Bangoria "perf thread event -> ptrace same thread event (Overlapping)", 587290f7d8cSRavi Bangoria "perf thread event -> ptrace same thread event (Non-overlapping)", 588290f7d8cSRavi Bangoria "perf thread event -> ptrace other thread event", 589290f7d8cSRavi Bangoria "ptrace thread event -> perf kernel event", 590290f7d8cSRavi Bangoria "ptrace thread event -> perf same thread event (Overlapping)", 591290f7d8cSRavi Bangoria "ptrace thread event -> perf same thread event (Non-overlapping)", 592290f7d8cSRavi Bangoria "ptrace thread event -> perf other thread event", 593290f7d8cSRavi Bangoria "ptrace thread event -> perf cpu event (Overlapping)", 594290f7d8cSRavi Bangoria "ptrace thread event -> perf cpu event (Non-overlapping)", 595290f7d8cSRavi Bangoria "ptrace thread event -> perf same thread & cpu event (Overlapping)", 596290f7d8cSRavi Bangoria "ptrace thread event -> perf same thread & cpu event (Non-overlapping)", 597290f7d8cSRavi Bangoria "ptrace thread event -> perf other thread & cpu event", 598290f7d8cSRavi Bangoria }; 599290f7d8cSRavi Bangoria 600290f7d8cSRavi Bangoria static int test(pid_t child_pid) 601290f7d8cSRavi Bangoria { 602290f7d8cSRavi Bangoria int ret = TEST_PASS; 603290f7d8cSRavi Bangoria 604290f7d8cSRavi Bangoria ret |= do_test(desc[0], test1, child_pid); 605290f7d8cSRavi Bangoria ret |= do_test(desc[1], test2, child_pid); 606290f7d8cSRavi Bangoria ret |= do_test(desc[2], test3, child_pid); 607290f7d8cSRavi Bangoria ret |= do_test(desc[3], test4, child_pid); 608290f7d8cSRavi Bangoria ret |= do_test(desc[4], test5, child_pid); 609290f7d8cSRavi Bangoria ret |= do_test(desc[5], test6, child_pid); 610290f7d8cSRavi Bangoria ret |= do_test(desc[6], test7, child_pid); 611290f7d8cSRavi Bangoria ret |= do_test(desc[7], test8, child_pid); 612290f7d8cSRavi Bangoria ret |= do_test(desc[8], test9, child_pid); 613290f7d8cSRavi Bangoria ret |= do_test(desc[9], test10, child_pid); 614290f7d8cSRavi Bangoria ret |= do_test(desc[10], test11, child_pid); 615290f7d8cSRavi Bangoria ret |= do_test(desc[11], test12, child_pid); 616290f7d8cSRavi Bangoria ret |= do_test(desc[12], test13, child_pid); 617290f7d8cSRavi Bangoria ret |= do_test(desc[13], test14, child_pid); 618290f7d8cSRavi Bangoria 619290f7d8cSRavi Bangoria return ret; 620290f7d8cSRavi Bangoria } 621290f7d8cSRavi Bangoria 622290f7d8cSRavi Bangoria static void get_dbginfo(pid_t child_pid, struct ppc_debug_info *dbginfo) 623290f7d8cSRavi Bangoria { 624290f7d8cSRavi Bangoria if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, dbginfo)) { 625290f7d8cSRavi Bangoria perror("Can't get breakpoint info"); 626290f7d8cSRavi Bangoria exit(-1); 627290f7d8cSRavi Bangoria } 628290f7d8cSRavi Bangoria } 629290f7d8cSRavi Bangoria 630290f7d8cSRavi Bangoria static int ptrace_perf_hwbreak(void) 631290f7d8cSRavi Bangoria { 632290f7d8cSRavi Bangoria int ret; 633290f7d8cSRavi Bangoria pid_t child_pid; 634290f7d8cSRavi Bangoria struct ppc_debug_info dbginfo; 635290f7d8cSRavi Bangoria 636290f7d8cSRavi Bangoria child_pid = fork(); 637290f7d8cSRavi Bangoria if (!child_pid) 638290f7d8cSRavi Bangoria return child(); 639290f7d8cSRavi Bangoria 640290f7d8cSRavi Bangoria /* parent */ 641290f7d8cSRavi Bangoria wait(NULL); /* <-- child (SIGUSR1) */ 642290f7d8cSRavi Bangoria 643290f7d8cSRavi Bangoria get_dbginfo(child_pid, &dbginfo); 644*68877ff2SBenjamin Gray SKIP_IF_MSG(dbginfo.num_data_bps <= 1, "Not enough data watchpoints (need at least 2)"); 645290f7d8cSRavi Bangoria 646290f7d8cSRavi Bangoria ret = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1)); 647*68877ff2SBenjamin Gray SKIP_IF_MSG(ret < 0, "perf_event_open syscall failed"); 648290f7d8cSRavi Bangoria close(ret); 649290f7d8cSRavi Bangoria 650290f7d8cSRavi Bangoria ret = test(child_pid); 651290f7d8cSRavi Bangoria 652290f7d8cSRavi Bangoria ptrace(PTRACE_CONT, child_pid, NULL, 0); 653290f7d8cSRavi Bangoria return ret; 654290f7d8cSRavi Bangoria } 655290f7d8cSRavi Bangoria 656290f7d8cSRavi Bangoria int main(int argc, char *argv[]) 657290f7d8cSRavi Bangoria { 658290f7d8cSRavi Bangoria return test_harness(ptrace_perf_hwbreak, "ptrace-perf-hwbreak"); 659290f7d8cSRavi Bangoria } 660