1
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
18volatile __u64 *ptrace_data1 = (__u64 *)&data[0];
19volatile __u64 *perf_data1 = (__u64 *)&data[4];
20
21
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);
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
162
163
164
165
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
187
188
189
190
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
216
217
218
219
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
241
242
243
244
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
271
272
273
274
275 cpid = fork();
276 if (!cpid) {
277
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
309
310
311
312
313
314
315
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
347
348
349
350
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
372
373
374
375
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
402
403
404
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
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
437
438
439
440
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
461
462
463
464
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
489
490
491
492
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
513
514
515
516
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
542
543
544
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
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
641 wait(NULL);
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}
660