0001
0002 #include <stdio.h>
0003 #include <string.h>
0004 #include <signal.h>
0005 #include <stdlib.h>
0006 #include <unistd.h>
0007 #include <errno.h>
0008 #include <linux/hw_breakpoint.h>
0009 #include <linux/perf_event.h>
0010 #include <asm/unistd.h>
0011 #include <sys/ptrace.h>
0012 #include <sys/wait.h>
0013 #include "ptrace.h"
0014
0015 char data[16];
0016
0017
0018 volatile __u64 *ptrace_data1 = (__u64 *)&data[0];
0019 volatile __u64 *perf_data1 = (__u64 *)&data[4];
0020
0021
0022 volatile __u64 *ptrace_data2 = (__u64 *)&data[0];
0023 volatile __u64 *perf_data2 = (__u64 *)&data[8];
0024
0025 static unsigned long pid_max_addr(void)
0026 {
0027 FILE *fp;
0028 char *line, *c;
0029 char addr[100];
0030 size_t len = 0;
0031
0032 fp = fopen("/proc/kallsyms", "r");
0033 if (!fp) {
0034 printf("Failed to read /proc/kallsyms. Exiting..\n");
0035 exit(EXIT_FAILURE);
0036 }
0037
0038 while (getline(&line, &len, fp) != -1) {
0039 if (!strstr(line, "pid_max") || strstr(line, "pid_max_max") ||
0040 strstr(line, "pid_max_min"))
0041 continue;
0042
0043 strncpy(addr, line, len < 100 ? len : 100);
0044 c = strchr(addr, ' ');
0045 *c = '\0';
0046 return strtoul(addr, &c, 16);
0047 }
0048 fclose(fp);
0049 printf("Could not find pix_max. Exiting..\n");
0050 exit(EXIT_FAILURE);
0051 return -1;
0052 }
0053
0054 static void perf_user_event_attr_set(struct perf_event_attr *attr, __u64 addr, __u64 len)
0055 {
0056 memset(attr, 0, sizeof(struct perf_event_attr));
0057 attr->type = PERF_TYPE_BREAKPOINT;
0058 attr->size = sizeof(struct perf_event_attr);
0059 attr->bp_type = HW_BREAKPOINT_R;
0060 attr->bp_addr = addr;
0061 attr->bp_len = len;
0062 attr->exclude_kernel = 1;
0063 attr->exclude_hv = 1;
0064 }
0065
0066 static void perf_kernel_event_attr_set(struct perf_event_attr *attr)
0067 {
0068 memset(attr, 0, sizeof(struct perf_event_attr));
0069 attr->type = PERF_TYPE_BREAKPOINT;
0070 attr->size = sizeof(struct perf_event_attr);
0071 attr->bp_type = HW_BREAKPOINT_R;
0072 attr->bp_addr = pid_max_addr();
0073 attr->bp_len = sizeof(unsigned long);
0074 attr->exclude_user = 1;
0075 attr->exclude_hv = 1;
0076 }
0077
0078 static int perf_cpu_event_open(int cpu, __u64 addr, __u64 len)
0079 {
0080 struct perf_event_attr attr;
0081
0082 perf_user_event_attr_set(&attr, addr, len);
0083 return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0);
0084 }
0085
0086 static int perf_thread_event_open(pid_t child_pid, __u64 addr, __u64 len)
0087 {
0088 struct perf_event_attr attr;
0089
0090 perf_user_event_attr_set(&attr, addr, len);
0091 return syscall(__NR_perf_event_open, &attr, child_pid, -1, -1, 0);
0092 }
0093
0094 static int perf_thread_cpu_event_open(pid_t child_pid, int cpu, __u64 addr, __u64 len)
0095 {
0096 struct perf_event_attr attr;
0097
0098 perf_user_event_attr_set(&attr, addr, len);
0099 return syscall(__NR_perf_event_open, &attr, child_pid, cpu, -1, 0);
0100 }
0101
0102 static int perf_thread_kernel_event_open(pid_t child_pid)
0103 {
0104 struct perf_event_attr attr;
0105
0106 perf_kernel_event_attr_set(&attr);
0107 return syscall(__NR_perf_event_open, &attr, child_pid, -1, -1, 0);
0108 }
0109
0110 static int perf_cpu_kernel_event_open(int cpu)
0111 {
0112 struct perf_event_attr attr;
0113
0114 perf_kernel_event_attr_set(&attr);
0115 return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0);
0116 }
0117
0118 static int child(void)
0119 {
0120 int ret;
0121
0122 ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
0123 if (ret) {
0124 printf("Error: PTRACE_TRACEME failed\n");
0125 return 0;
0126 }
0127 kill(getpid(), SIGUSR1);
0128
0129 return 0;
0130 }
0131
0132 static void ptrace_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type,
0133 __u64 addr, int len)
0134 {
0135 info->version = 1;
0136 info->trigger_type = type;
0137 info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
0138 info->addr = addr;
0139 info->addr2 = addr + len;
0140 info->condition_value = 0;
0141 if (!len)
0142 info->addr_mode = PPC_BREAKPOINT_MODE_EXACT;
0143 else
0144 info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
0145 }
0146
0147 static int ptrace_open(pid_t child_pid, __u64 wp_addr, int len)
0148 {
0149 struct ppc_hw_breakpoint info;
0150
0151 ptrace_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
0152 return ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, &info);
0153 }
0154
0155 static int test1(pid_t child_pid)
0156 {
0157 int perf_fd;
0158 int ptrace_fd;
0159 int ret = 0;
0160
0161
0162
0163
0164
0165
0166
0167
0168 perf_fd = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1));
0169 if (perf_fd < 0)
0170 return -1;
0171
0172 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0173 if (ptrace_fd > 0 || errno != ENOSPC)
0174 ret = -1;
0175
0176 close(perf_fd);
0177 return ret;
0178 }
0179
0180 static int test2(pid_t child_pid)
0181 {
0182 int perf_fd;
0183 int ptrace_fd;
0184 int ret = 0;
0185
0186
0187
0188
0189
0190
0191
0192
0193 perf_fd = perf_cpu_event_open(0, (__u64)perf_data2, sizeof(*perf_data2));
0194 if (perf_fd < 0)
0195 return -1;
0196
0197 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
0198 if (ptrace_fd < 0) {
0199 ret = -1;
0200 goto perf_close;
0201 }
0202 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0203
0204 perf_close:
0205 close(perf_fd);
0206 return ret;
0207 }
0208
0209 static int test3(pid_t child_pid)
0210 {
0211 int perf_fd;
0212 int ptrace_fd;
0213 int ret = 0;
0214
0215
0216
0217
0218
0219
0220
0221 perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data1,
0222 sizeof(*perf_data1));
0223 if (perf_fd < 0)
0224 return -1;
0225
0226 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0227 if (ptrace_fd > 0 || errno != ENOSPC)
0228 ret = -1;
0229
0230 close(perf_fd);
0231 return ret;
0232 }
0233
0234 static int test4(pid_t child_pid)
0235 {
0236 int perf_fd;
0237 int ptrace_fd;
0238 int ret = 0;
0239
0240
0241
0242
0243
0244
0245
0246 perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data2,
0247 sizeof(*perf_data2));
0248 if (perf_fd < 0)
0249 return -1;
0250
0251 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
0252 if (ptrace_fd < 0) {
0253 ret = -1;
0254 goto perf_close;
0255 }
0256 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0257
0258 perf_close:
0259 close(perf_fd);
0260 return ret;
0261 }
0262
0263 static int test5(pid_t child_pid)
0264 {
0265 int perf_fd;
0266 int ptrace_fd;
0267 int cpid;
0268 int ret = 0;
0269
0270
0271
0272
0273
0274
0275 cpid = fork();
0276 if (!cpid) {
0277
0278 pause();
0279 exit(EXIT_SUCCESS);
0280 }
0281
0282 perf_fd = perf_thread_event_open(cpid, (__u64)perf_data1, sizeof(*perf_data1));
0283 if (perf_fd < 0) {
0284 ret = -1;
0285 goto kill_child;
0286 }
0287
0288 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0289 if (ptrace_fd < 0) {
0290 ret = -1;
0291 goto perf_close;
0292 }
0293
0294 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0295 perf_close:
0296 close(perf_fd);
0297 kill_child:
0298 kill(cpid, SIGINT);
0299 return ret;
0300 }
0301
0302 static int test6(pid_t child_pid)
0303 {
0304 int perf_fd;
0305 int ptrace_fd;
0306 int ret = 0;
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0318 if (ptrace_fd < 0)
0319 return -1;
0320
0321 perf_fd = perf_thread_kernel_event_open(child_pid);
0322 if (perf_fd < 0) {
0323 ret = -1;
0324 goto ptrace_close;
0325 }
0326 close(perf_fd);
0327
0328 perf_fd = perf_cpu_kernel_event_open(0);
0329 if (perf_fd < 0) {
0330 ret = -1;
0331 goto ptrace_close;
0332 }
0333 close(perf_fd);
0334
0335 ptrace_close:
0336 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0337 return ret;
0338 }
0339
0340 static int test7(pid_t child_pid)
0341 {
0342 int perf_fd;
0343 int ptrace_fd;
0344 int ret = 0;
0345
0346
0347
0348
0349
0350
0351
0352 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0353 if (ptrace_fd < 0)
0354 return -1;
0355
0356 perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data1,
0357 sizeof(*perf_data1));
0358 if (perf_fd > 0 || errno != ENOSPC)
0359 ret = -1;
0360
0361 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0362 return ret;
0363 }
0364
0365 static int test8(pid_t child_pid)
0366 {
0367 int perf_fd;
0368 int ptrace_fd;
0369 int ret = 0;
0370
0371
0372
0373
0374
0375
0376
0377 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
0378 if (ptrace_fd < 0)
0379 return -1;
0380
0381 perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data2,
0382 sizeof(*perf_data2));
0383 if (perf_fd < 0) {
0384 ret = -1;
0385 goto ptrace_close;
0386 }
0387 close(perf_fd);
0388
0389 ptrace_close:
0390 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0391 return ret;
0392 }
0393
0394 static int test9(pid_t child_pid)
0395 {
0396 int perf_fd;
0397 int ptrace_fd;
0398 int cpid;
0399 int ret = 0;
0400
0401
0402
0403
0404
0405
0406 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0407 if (ptrace_fd < 0)
0408 return -1;
0409
0410 cpid = fork();
0411 if (!cpid) {
0412
0413 pause();
0414 exit(EXIT_SUCCESS);
0415 }
0416
0417 perf_fd = perf_thread_event_open(cpid, (__u64)perf_data1, sizeof(*perf_data1));
0418 if (perf_fd < 0) {
0419 ret = -1;
0420 goto kill_child;
0421 }
0422 close(perf_fd);
0423
0424 kill_child:
0425 kill(cpid, SIGINT);
0426 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0427 return ret;
0428 }
0429
0430 static int test10(pid_t child_pid)
0431 {
0432 int perf_fd;
0433 int ptrace_fd;
0434 int ret = 0;
0435
0436
0437
0438
0439
0440
0441
0442 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0443 if (ptrace_fd < 0)
0444 return -1;
0445
0446 perf_fd = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1));
0447 if (perf_fd > 0 || errno != ENOSPC)
0448 ret = -1;
0449
0450 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0451 return ret;
0452 }
0453
0454 static int test11(pid_t child_pid)
0455 {
0456 int perf_fd;
0457 int ptrace_fd;
0458 int ret = 0;
0459
0460
0461
0462
0463
0464
0465
0466 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
0467 if (ptrace_fd < 0)
0468 return -1;
0469
0470 perf_fd = perf_cpu_event_open(0, (__u64)perf_data2, sizeof(*perf_data2));
0471 if (perf_fd < 0) {
0472 ret = -1;
0473 goto ptrace_close;
0474 }
0475 close(perf_fd);
0476
0477 ptrace_close:
0478 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0479 return ret;
0480 }
0481
0482 static int test12(pid_t child_pid)
0483 {
0484 int perf_fd;
0485 int ptrace_fd;
0486 int ret = 0;
0487
0488
0489
0490
0491
0492
0493
0494 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0495 if (ptrace_fd < 0)
0496 return -1;
0497
0498 perf_fd = perf_thread_cpu_event_open(child_pid, 0, (__u64)perf_data1, sizeof(*perf_data1));
0499 if (perf_fd > 0 || errno != ENOSPC)
0500 ret = -1;
0501
0502 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0503 return ret;
0504 }
0505
0506 static int test13(pid_t child_pid)
0507 {
0508 int perf_fd;
0509 int ptrace_fd;
0510 int ret = 0;
0511
0512
0513
0514
0515
0516
0517
0518 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
0519 if (ptrace_fd < 0)
0520 return -1;
0521
0522 perf_fd = perf_thread_cpu_event_open(child_pid, 0, (__u64)perf_data2, sizeof(*perf_data2));
0523 if (perf_fd < 0) {
0524 ret = -1;
0525 goto ptrace_close;
0526 }
0527 close(perf_fd);
0528
0529 ptrace_close:
0530 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0531 return ret;
0532 }
0533
0534 static int test14(pid_t child_pid)
0535 {
0536 int perf_fd;
0537 int ptrace_fd;
0538 int cpid;
0539 int ret = 0;
0540
0541
0542
0543
0544
0545
0546 ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0547 if (ptrace_fd < 0)
0548 return -1;
0549
0550 cpid = fork();
0551 if (!cpid) {
0552
0553 pause();
0554 exit(EXIT_SUCCESS);
0555 }
0556
0557 perf_fd = perf_thread_cpu_event_open(cpid, 0, (__u64)perf_data1,
0558 sizeof(*perf_data1));
0559 if (perf_fd < 0) {
0560 ret = -1;
0561 goto kill_child;
0562 }
0563 close(perf_fd);
0564
0565 kill_child:
0566 kill(cpid, SIGINT);
0567 ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0568 return ret;
0569 }
0570
0571 static int do_test(const char *msg, int (*fun)(pid_t arg), pid_t arg)
0572 {
0573 int ret;
0574
0575 ret = fun(arg);
0576 if (ret)
0577 printf("%s: Error\n", msg);
0578 else
0579 printf("%s: Ok\n", msg);
0580 return ret;
0581 }
0582
0583 char *desc[14] = {
0584 "perf cpu event -> ptrace thread event (Overlapping)",
0585 "perf cpu event -> ptrace thread event (Non-overlapping)",
0586 "perf thread event -> ptrace same thread event (Overlapping)",
0587 "perf thread event -> ptrace same thread event (Non-overlapping)",
0588 "perf thread event -> ptrace other thread event",
0589 "ptrace thread event -> perf kernel event",
0590 "ptrace thread event -> perf same thread event (Overlapping)",
0591 "ptrace thread event -> perf same thread event (Non-overlapping)",
0592 "ptrace thread event -> perf other thread event",
0593 "ptrace thread event -> perf cpu event (Overlapping)",
0594 "ptrace thread event -> perf cpu event (Non-overlapping)",
0595 "ptrace thread event -> perf same thread & cpu event (Overlapping)",
0596 "ptrace thread event -> perf same thread & cpu event (Non-overlapping)",
0597 "ptrace thread event -> perf other thread & cpu event",
0598 };
0599
0600 static int test(pid_t child_pid)
0601 {
0602 int ret = TEST_PASS;
0603
0604 ret |= do_test(desc[0], test1, child_pid);
0605 ret |= do_test(desc[1], test2, child_pid);
0606 ret |= do_test(desc[2], test3, child_pid);
0607 ret |= do_test(desc[3], test4, child_pid);
0608 ret |= do_test(desc[4], test5, child_pid);
0609 ret |= do_test(desc[5], test6, child_pid);
0610 ret |= do_test(desc[6], test7, child_pid);
0611 ret |= do_test(desc[7], test8, child_pid);
0612 ret |= do_test(desc[8], test9, child_pid);
0613 ret |= do_test(desc[9], test10, child_pid);
0614 ret |= do_test(desc[10], test11, child_pid);
0615 ret |= do_test(desc[11], test12, child_pid);
0616 ret |= do_test(desc[12], test13, child_pid);
0617 ret |= do_test(desc[13], test14, child_pid);
0618
0619 return ret;
0620 }
0621
0622 static void get_dbginfo(pid_t child_pid, struct ppc_debug_info *dbginfo)
0623 {
0624 if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, dbginfo)) {
0625 perror("Can't get breakpoint info");
0626 exit(-1);
0627 }
0628 }
0629
0630 static int ptrace_perf_hwbreak(void)
0631 {
0632 int ret;
0633 pid_t child_pid;
0634 struct ppc_debug_info dbginfo;
0635
0636 child_pid = fork();
0637 if (!child_pid)
0638 return child();
0639
0640
0641 wait(NULL);
0642
0643 get_dbginfo(child_pid, &dbginfo);
0644 SKIP_IF(dbginfo.num_data_bps <= 1);
0645
0646 ret = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1));
0647 SKIP_IF(ret < 0);
0648 close(ret);
0649
0650 ret = test(child_pid);
0651
0652 ptrace(PTRACE_CONT, child_pid, NULL, 0);
0653 return ret;
0654 }
0655
0656 int main(int argc, char *argv[])
0657 {
0658 return test_harness(ptrace_perf_hwbreak, "ptrace-perf-hwbreak");
0659 }