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
pid_max_addr(void)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
perf_user_event_attr_set(struct perf_event_attr * attr,__u64 addr,__u64 len)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
perf_kernel_event_attr_set(struct perf_event_attr * attr)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
perf_cpu_event_open(int cpu,__u64 addr,__u64 len)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
perf_thread_event_open(pid_t child_pid,__u64 addr,__u64 len)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
perf_thread_cpu_event_open(pid_t child_pid,int cpu,__u64 addr,__u64 len)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
perf_thread_kernel_event_open(pid_t child_pid)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
perf_cpu_kernel_event_open(int cpu)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
child(void)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
ptrace_ppc_hw_breakpoint(struct ppc_hw_breakpoint * info,int type,__u64 addr,int len)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
ptrace_open(pid_t child_pid,__u64 wp_addr,int len)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
test1(pid_t child_pid)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
test2(pid_t child_pid)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
test3(pid_t child_pid)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
test4(pid_t child_pid)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
test5(pid_t child_pid)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
test6(pid_t child_pid)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
test7(pid_t child_pid)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
test8(pid_t child_pid)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
test9(pid_t child_pid)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
test10(pid_t child_pid)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
test11(pid_t child_pid)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
test12(pid_t child_pid)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
test13(pid_t child_pid)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
test14(pid_t child_pid)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
do_test(const char * msg,int (* fun)(pid_t arg),pid_t arg)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
test(pid_t child_pid)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
get_dbginfo(pid_t child_pid,struct ppc_debug_info * dbginfo)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
ptrace_perf_hwbreak(void)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
main(int argc,char * argv[])656 int main(int argc, char *argv[])
657 {
658 return test_harness(ptrace_perf_hwbreak, "ptrace-perf-hwbreak");
659 }
660