1 // SPDX-License-Identifier: GPL-2.0+ 2 #include <stdio.h> 3 #include <string.h> 4 #include <signal.h> 5 #include <stdlib.h> 6 #include <unistd.h> 7 #include <errno.h> 8 #include <linux/hw_breakpoint.h> 9 #include <linux/perf_event.h> 10 #include <asm/unistd.h> 11 #include <sys/ptrace.h> 12 #include <sys/wait.h> 13 #include "ptrace.h" 14 15 char data[16]; 16 17 /* Overlapping address range */ 18 volatile __u64 *ptrace_data1 = (__u64 *)&data[0]; 19 volatile __u64 *perf_data1 = (__u64 *)&data[4]; 20 21 /* Non-overlapping address range */ 22 volatile __u64 *ptrace_data2 = (__u64 *)&data[0]; 23 volatile __u64 *perf_data2 = (__u64 *)&data[8]; 24 25 static unsigned long pid_max_addr(void) 26 { 27 FILE *fp; 28 char *line, *c; 29 char addr[100]; 30 size_t len = 0; 31 32 fp = fopen("/proc/kallsyms", "r"); 33 if (!fp) { 34 printf("Failed to read /proc/kallsyms. Exiting..\n"); 35 exit(EXIT_FAILURE); 36 } 37 38 while (getline(&line, &len, fp) != -1) { 39 if (!strstr(line, "pid_max") || strstr(line, "pid_max_max") || 40 strstr(line, "pid_max_min")) 41 continue; 42 43 strncpy(addr, line, len < 100 ? len : 100); 44 c = strchr(addr, ' '); 45 *c = '\0'; 46 return strtoul(addr, &c, 16); 47 } 48 fclose(fp); 49 printf("Could not find pix_max. Exiting..\n"); 50 exit(EXIT_FAILURE); 51 return -1; 52 } 53 54 static void perf_user_event_attr_set(struct perf_event_attr *attr, __u64 addr, __u64 len) 55 { 56 memset(attr, 0, sizeof(struct perf_event_attr)); 57 attr->type = PERF_TYPE_BREAKPOINT; 58 attr->size = sizeof(struct perf_event_attr); 59 attr->bp_type = HW_BREAKPOINT_R; 60 attr->bp_addr = addr; 61 attr->bp_len = len; 62 attr->exclude_kernel = 1; 63 attr->exclude_hv = 1; 64 } 65 66 static void perf_kernel_event_attr_set(struct perf_event_attr *attr) 67 { 68 memset(attr, 0, sizeof(struct perf_event_attr)); 69 attr->type = PERF_TYPE_BREAKPOINT; 70 attr->size = sizeof(struct perf_event_attr); 71 attr->bp_type = HW_BREAKPOINT_R; 72 attr->bp_addr = pid_max_addr(); 73 attr->bp_len = sizeof(unsigned long); 74 attr->exclude_user = 1; 75 attr->exclude_hv = 1; 76 } 77 78 static int perf_cpu_event_open(int cpu, __u64 addr, __u64 len) 79 { 80 struct perf_event_attr attr; 81 82 perf_user_event_attr_set(&attr, addr, len); 83 return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0); 84 } 85 86 static int perf_thread_event_open(pid_t child_pid, __u64 addr, __u64 len) 87 { 88 struct perf_event_attr attr; 89 90 perf_user_event_attr_set(&attr, addr, len); 91 return syscall(__NR_perf_event_open, &attr, child_pid, -1, -1, 0); 92 } 93 94 static int perf_thread_cpu_event_open(pid_t child_pid, int cpu, __u64 addr, __u64 len) 95 { 96 struct perf_event_attr attr; 97 98 perf_user_event_attr_set(&attr, addr, len); 99 return syscall(__NR_perf_event_open, &attr, child_pid, cpu, -1, 0); 100 } 101 102 static int perf_thread_kernel_event_open(pid_t child_pid) 103 { 104 struct perf_event_attr attr; 105 106 perf_kernel_event_attr_set(&attr); 107 return syscall(__NR_perf_event_open, &attr, child_pid, -1, -1, 0); 108 } 109 110 static int perf_cpu_kernel_event_open(int cpu) 111 { 112 struct perf_event_attr attr; 113 114 perf_kernel_event_attr_set(&attr); 115 return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0); 116 } 117 118 static int child(void) 119 { 120 int ret; 121 122 ret = ptrace(PTRACE_TRACEME, 0, NULL, 0); 123 if (ret) { 124 printf("Error: PTRACE_TRACEME failed\n"); 125 return 0; 126 } 127 kill(getpid(), SIGUSR1); /* --> parent (SIGUSR1) */ 128 129 return 0; 130 } 131 132 static void ptrace_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type, 133 __u64 addr, int len) 134 { 135 info->version = 1; 136 info->trigger_type = type; 137 info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE; 138 info->addr = addr; 139 info->addr2 = addr + len; 140 info->condition_value = 0; 141 if (!len) 142 info->addr_mode = PPC_BREAKPOINT_MODE_EXACT; 143 else 144 info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE; 145 } 146 147 static int ptrace_open(pid_t child_pid, __u64 wp_addr, int len) 148 { 149 struct ppc_hw_breakpoint info; 150 151 ptrace_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len); 152 return ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, &info); 153 } 154 155 static int test1(pid_t child_pid) 156 { 157 int perf_fd; 158 int ptrace_fd; 159 int ret = 0; 160 161 /* Test: 162 * if (new per thread event by ptrace) 163 * if (existing cpu event by perf) 164 * if (addr range overlaps) 165 * fail; 166 */ 167 168 perf_fd = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1)); 169 if (perf_fd < 0) 170 return -1; 171 172 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 173 if (ptrace_fd > 0 || errno != ENOSPC) 174 ret = -1; 175 176 close(perf_fd); 177 return ret; 178 } 179 180 static int test2(pid_t child_pid) 181 { 182 int perf_fd; 183 int ptrace_fd; 184 int ret = 0; 185 186 /* Test: 187 * if (new per thread event by ptrace) 188 * if (existing cpu event by perf) 189 * if (addr range does not overlaps) 190 * allow; 191 */ 192 193 perf_fd = perf_cpu_event_open(0, (__u64)perf_data2, sizeof(*perf_data2)); 194 if (perf_fd < 0) 195 return -1; 196 197 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2)); 198 if (ptrace_fd < 0) { 199 ret = -1; 200 goto perf_close; 201 } 202 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 203 204 perf_close: 205 close(perf_fd); 206 return ret; 207 } 208 209 static int test3(pid_t child_pid) 210 { 211 int perf_fd; 212 int ptrace_fd; 213 int ret = 0; 214 215 /* Test: 216 * if (new per thread event by ptrace) 217 * if (existing thread event by perf on the same thread) 218 * if (addr range overlaps) 219 * fail; 220 */ 221 perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data1, 222 sizeof(*perf_data1)); 223 if (perf_fd < 0) 224 return -1; 225 226 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 227 if (ptrace_fd > 0 || errno != ENOSPC) 228 ret = -1; 229 230 close(perf_fd); 231 return ret; 232 } 233 234 static int test4(pid_t child_pid) 235 { 236 int perf_fd; 237 int ptrace_fd; 238 int ret = 0; 239 240 /* Test: 241 * if (new per thread event by ptrace) 242 * if (existing thread event by perf on the same thread) 243 * if (addr range does not overlaps) 244 * fail; 245 */ 246 perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data2, 247 sizeof(*perf_data2)); 248 if (perf_fd < 0) 249 return -1; 250 251 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2)); 252 if (ptrace_fd < 0) { 253 ret = -1; 254 goto perf_close; 255 } 256 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 257 258 perf_close: 259 close(perf_fd); 260 return ret; 261 } 262 263 static int test5(pid_t child_pid) 264 { 265 int perf_fd; 266 int ptrace_fd; 267 int cpid; 268 int ret = 0; 269 270 /* Test: 271 * if (new per thread event by ptrace) 272 * if (existing thread event by perf on the different thread) 273 * allow; 274 */ 275 cpid = fork(); 276 if (!cpid) { 277 /* Temporary Child */ 278 pause(); 279 exit(EXIT_SUCCESS); 280 } 281 282 perf_fd = perf_thread_event_open(cpid, (__u64)perf_data1, sizeof(*perf_data1)); 283 if (perf_fd < 0) { 284 ret = -1; 285 goto kill_child; 286 } 287 288 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 289 if (ptrace_fd < 0) { 290 ret = -1; 291 goto perf_close; 292 } 293 294 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 295 perf_close: 296 close(perf_fd); 297 kill_child: 298 kill(cpid, SIGINT); 299 return ret; 300 } 301 302 static int test6(pid_t child_pid) 303 { 304 int perf_fd; 305 int ptrace_fd; 306 int ret = 0; 307 308 /* Test: 309 * if (new per thread kernel event by perf) 310 * if (existing thread event by ptrace on the same thread) 311 * allow; 312 * -- OR -- 313 * if (new per cpu kernel event by perf) 314 * if (existing thread event by ptrace) 315 * allow; 316 */ 317 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 318 if (ptrace_fd < 0) 319 return -1; 320 321 perf_fd = perf_thread_kernel_event_open(child_pid); 322 if (perf_fd < 0) { 323 ret = -1; 324 goto ptrace_close; 325 } 326 close(perf_fd); 327 328 perf_fd = perf_cpu_kernel_event_open(0); 329 if (perf_fd < 0) { 330 ret = -1; 331 goto ptrace_close; 332 } 333 close(perf_fd); 334 335 ptrace_close: 336 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 337 return ret; 338 } 339 340 static int test7(pid_t child_pid) 341 { 342 int perf_fd; 343 int ptrace_fd; 344 int ret = 0; 345 346 /* Test: 347 * if (new per thread event by perf) 348 * if (existing thread event by ptrace on the same thread) 349 * if (addr range overlaps) 350 * fail; 351 */ 352 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 353 if (ptrace_fd < 0) 354 return -1; 355 356 perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data1, 357 sizeof(*perf_data1)); 358 if (perf_fd > 0 || errno != ENOSPC) 359 ret = -1; 360 361 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 362 return ret; 363 } 364 365 static int test8(pid_t child_pid) 366 { 367 int perf_fd; 368 int ptrace_fd; 369 int ret = 0; 370 371 /* Test: 372 * if (new per thread event by perf) 373 * if (existing thread event by ptrace on the same thread) 374 * if (addr range does not overlaps) 375 * allow; 376 */ 377 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2)); 378 if (ptrace_fd < 0) 379 return -1; 380 381 perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data2, 382 sizeof(*perf_data2)); 383 if (perf_fd < 0) { 384 ret = -1; 385 goto ptrace_close; 386 } 387 close(perf_fd); 388 389 ptrace_close: 390 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 391 return ret; 392 } 393 394 static int test9(pid_t child_pid) 395 { 396 int perf_fd; 397 int ptrace_fd; 398 int cpid; 399 int ret = 0; 400 401 /* Test: 402 * if (new per thread event by perf) 403 * if (existing thread event by ptrace on the other thread) 404 * allow; 405 */ 406 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 407 if (ptrace_fd < 0) 408 return -1; 409 410 cpid = fork(); 411 if (!cpid) { 412 /* Temporary Child */ 413 pause(); 414 exit(EXIT_SUCCESS); 415 } 416 417 perf_fd = perf_thread_event_open(cpid, (__u64)perf_data1, sizeof(*perf_data1)); 418 if (perf_fd < 0) { 419 ret = -1; 420 goto kill_child; 421 } 422 close(perf_fd); 423 424 kill_child: 425 kill(cpid, SIGINT); 426 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 427 return ret; 428 } 429 430 static int test10(pid_t child_pid) 431 { 432 int perf_fd; 433 int ptrace_fd; 434 int ret = 0; 435 436 /* Test: 437 * if (new per cpu event by perf) 438 * if (existing thread event by ptrace on the same thread) 439 * if (addr range overlaps) 440 * fail; 441 */ 442 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 443 if (ptrace_fd < 0) 444 return -1; 445 446 perf_fd = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1)); 447 if (perf_fd > 0 || errno != ENOSPC) 448 ret = -1; 449 450 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 451 return ret; 452 } 453 454 static int test11(pid_t child_pid) 455 { 456 int perf_fd; 457 int ptrace_fd; 458 int ret = 0; 459 460 /* Test: 461 * if (new per cpu event by perf) 462 * if (existing thread event by ptrace on the same thread) 463 * if (addr range does not overlap) 464 * allow; 465 */ 466 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2)); 467 if (ptrace_fd < 0) 468 return -1; 469 470 perf_fd = perf_cpu_event_open(0, (__u64)perf_data2, sizeof(*perf_data2)); 471 if (perf_fd < 0) { 472 ret = -1; 473 goto ptrace_close; 474 } 475 close(perf_fd); 476 477 ptrace_close: 478 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 479 return ret; 480 } 481 482 static int test12(pid_t child_pid) 483 { 484 int perf_fd; 485 int ptrace_fd; 486 int ret = 0; 487 488 /* Test: 489 * if (new per thread and per cpu event by perf) 490 * if (existing thread event by ptrace on the same thread) 491 * if (addr range overlaps) 492 * fail; 493 */ 494 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 495 if (ptrace_fd < 0) 496 return -1; 497 498 perf_fd = perf_thread_cpu_event_open(child_pid, 0, (__u64)perf_data1, sizeof(*perf_data1)); 499 if (perf_fd > 0 || errno != ENOSPC) 500 ret = -1; 501 502 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 503 return ret; 504 } 505 506 static int test13(pid_t child_pid) 507 { 508 int perf_fd; 509 int ptrace_fd; 510 int ret = 0; 511 512 /* Test: 513 * if (new per thread and per cpu event by perf) 514 * if (existing thread event by ptrace on the same thread) 515 * if (addr range does not overlap) 516 * allow; 517 */ 518 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2)); 519 if (ptrace_fd < 0) 520 return -1; 521 522 perf_fd = perf_thread_cpu_event_open(child_pid, 0, (__u64)perf_data2, sizeof(*perf_data2)); 523 if (perf_fd < 0) { 524 ret = -1; 525 goto ptrace_close; 526 } 527 close(perf_fd); 528 529 ptrace_close: 530 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 531 return ret; 532 } 533 534 static int test14(pid_t child_pid) 535 { 536 int perf_fd; 537 int ptrace_fd; 538 int cpid; 539 int ret = 0; 540 541 /* Test: 542 * if (new per thread and per cpu event by perf) 543 * if (existing thread event by ptrace on the other thread) 544 * allow; 545 */ 546 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); 547 if (ptrace_fd < 0) 548 return -1; 549 550 cpid = fork(); 551 if (!cpid) { 552 /* Temporary Child */ 553 pause(); 554 exit(EXIT_SUCCESS); 555 } 556 557 perf_fd = perf_thread_cpu_event_open(cpid, 0, (__u64)perf_data1, 558 sizeof(*perf_data1)); 559 if (perf_fd < 0) { 560 ret = -1; 561 goto kill_child; 562 } 563 close(perf_fd); 564 565 kill_child: 566 kill(cpid, SIGINT); 567 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 568 return ret; 569 } 570 571 static int do_test(const char *msg, int (*fun)(pid_t arg), pid_t arg) 572 { 573 int ret; 574 575 ret = fun(arg); 576 if (ret) 577 printf("%s: Error\n", msg); 578 else 579 printf("%s: Ok\n", msg); 580 return ret; 581 } 582 583 char *desc[14] = { 584 "perf cpu event -> ptrace thread event (Overlapping)", 585 "perf cpu event -> ptrace thread event (Non-overlapping)", 586 "perf thread event -> ptrace same thread event (Overlapping)", 587 "perf thread event -> ptrace same thread event (Non-overlapping)", 588 "perf thread event -> ptrace other thread event", 589 "ptrace thread event -> perf kernel event", 590 "ptrace thread event -> perf same thread event (Overlapping)", 591 "ptrace thread event -> perf same thread event (Non-overlapping)", 592 "ptrace thread event -> perf other thread event", 593 "ptrace thread event -> perf cpu event (Overlapping)", 594 "ptrace thread event -> perf cpu event (Non-overlapping)", 595 "ptrace thread event -> perf same thread & cpu event (Overlapping)", 596 "ptrace thread event -> perf same thread & cpu event (Non-overlapping)", 597 "ptrace thread event -> perf other thread & cpu event", 598 }; 599 600 static int test(pid_t child_pid) 601 { 602 int ret = TEST_PASS; 603 604 ret |= do_test(desc[0], test1, child_pid); 605 ret |= do_test(desc[1], test2, child_pid); 606 ret |= do_test(desc[2], test3, child_pid); 607 ret |= do_test(desc[3], test4, child_pid); 608 ret |= do_test(desc[4], test5, child_pid); 609 ret |= do_test(desc[5], test6, child_pid); 610 ret |= do_test(desc[6], test7, child_pid); 611 ret |= do_test(desc[7], test8, child_pid); 612 ret |= do_test(desc[8], test9, child_pid); 613 ret |= do_test(desc[9], test10, child_pid); 614 ret |= do_test(desc[10], test11, child_pid); 615 ret |= do_test(desc[11], test12, child_pid); 616 ret |= do_test(desc[12], test13, child_pid); 617 ret |= do_test(desc[13], test14, child_pid); 618 619 return ret; 620 } 621 622 static void get_dbginfo(pid_t child_pid, struct ppc_debug_info *dbginfo) 623 { 624 if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, dbginfo)) { 625 perror("Can't get breakpoint info"); 626 exit(-1); 627 } 628 } 629 630 static int ptrace_perf_hwbreak(void) 631 { 632 int ret; 633 pid_t child_pid; 634 struct ppc_debug_info dbginfo; 635 636 child_pid = fork(); 637 if (!child_pid) 638 return child(); 639 640 /* parent */ 641 wait(NULL); /* <-- child (SIGUSR1) */ 642 643 get_dbginfo(child_pid, &dbginfo); 644 SKIP_IF(dbginfo.num_data_bps <= 1); 645 646 ret = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1)); 647 SKIP_IF(ret < 0); 648 close(ret); 649 650 ret = test(child_pid); 651 652 ptrace(PTRACE_CONT, child_pid, NULL, 0); 653 return ret; 654 } 655 656 int main(int argc, char *argv[]) 657 { 658 return test_harness(ptrace_perf_hwbreak, "ptrace-perf-hwbreak"); 659 } 660