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