ptrace-perf-hwbreak.c (15055B)
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 15char data[16]; 16 17/* Overlapping address range */ 18volatile __u64 *ptrace_data1 = (__u64 *)&data[0]; 19volatile __u64 *perf_data1 = (__u64 *)&data[4]; 20 21/* Non-overlapping address range */ 22volatile __u64 *ptrace_data2 = (__u64 *)&data[0]; 23volatile __u64 *perf_data2 = (__u64 *)&data[8]; 24 25static 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 54static 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 66static 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 78static 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 86static 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 94static 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 102static 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 110static 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 118static 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 132static 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 147static 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 155static 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 180static 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 204perf_close: 205 close(perf_fd); 206 return ret; 207} 208 209static 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 234static 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 258perf_close: 259 close(perf_fd); 260 return ret; 261} 262 263static 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); 295perf_close: 296 close(perf_fd); 297kill_child: 298 kill(cpid, SIGINT); 299 return ret; 300} 301 302static 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 335ptrace_close: 336 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 337 return ret; 338} 339 340static 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 365static 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 389ptrace_close: 390 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 391 return ret; 392} 393 394static 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 424kill_child: 425 kill(cpid, SIGINT); 426 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 427 return ret; 428} 429 430static 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 454static 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 477ptrace_close: 478 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 479 return ret; 480} 481 482static 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 506static 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 529ptrace_close: 530 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 531 return ret; 532} 533 534static 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 565kill_child: 566 kill(cpid, SIGINT); 567 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); 568 return ret; 569} 570 571static 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 583char *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 600static 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 622static 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 630static 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 656int main(int argc, char *argv[]) 657{ 658 return test_harness(ptrace_perf_hwbreak, "ptrace-perf-hwbreak"); 659}