1 // SPDX-License-Identifier: GPL-2.0+
2 
3 /*
4  * Ptrace test for hw breakpoints
5  *
6  * Based on tools/testing/selftests/breakpoints/breakpoint_test.c
7  *
8  * This test forks and the parent then traces the child doing various
9  * types of ptrace enabled breakpoints
10  *
11  * Copyright (C) 2018 Michael Neuling, IBM Corporation.
12  */
13 
14 #include <sys/ptrace.h>
15 #include <unistd.h>
16 #include <stddef.h>
17 #include <sys/user.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <signal.h>
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include <sys/syscall.h>
24 #include <linux/limits.h>
25 #include "ptrace.h"
26 #include "reg.h"
27 
28 #define SPRN_PVR	0x11F
29 #define PVR_8xx		0x00500000
30 
31 bool is_8xx;
32 
33 /*
34  * Use volatile on all global var so that compiler doesn't
35  * optimise their load/stores. Otherwise selftest can fail.
36  */
37 static volatile __u64 glvar;
38 
39 #define DAWR_MAX_LEN 512
40 static volatile __u8 big_var[DAWR_MAX_LEN] __attribute__((aligned(512)));
41 
42 #define A_LEN 6
43 #define B_LEN 6
44 struct gstruct {
45 	__u8 a[A_LEN]; /* double word aligned */
46 	__u8 b[B_LEN]; /* double word unaligned */
47 };
48 static volatile struct gstruct gstruct __attribute__((aligned(512)));
49 
50 static volatile char cwd[PATH_MAX] __attribute__((aligned(8)));
51 
get_dbginfo(pid_t child_pid,struct ppc_debug_info * dbginfo)52 static void get_dbginfo(pid_t child_pid, struct ppc_debug_info *dbginfo)
53 {
54 	if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, dbginfo)) {
55 		perror("Can't get breakpoint info");
56 		exit(-1);
57 	}
58 }
59 
dawr_present(struct ppc_debug_info * dbginfo)60 static bool dawr_present(struct ppc_debug_info *dbginfo)
61 {
62 	return !!(dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_DAWR);
63 }
64 
write_var(int len)65 static void write_var(int len)
66 {
67 	volatile __u8 *pcvar;
68 	volatile __u16 *psvar;
69 	volatile __u32 *pivar;
70 	volatile __u64 *plvar;
71 
72 	switch (len) {
73 	case 1:
74 		pcvar = (volatile __u8 *)&glvar;
75 		*pcvar = 0xff;
76 		break;
77 	case 2:
78 		psvar = (volatile __u16 *)&glvar;
79 		*psvar = 0xffff;
80 		break;
81 	case 4:
82 		pivar = (volatile __u32 *)&glvar;
83 		*pivar = 0xffffffff;
84 		break;
85 	case 8:
86 		plvar = (volatile __u64 *)&glvar;
87 		*plvar = 0xffffffffffffffffLL;
88 		break;
89 	}
90 }
91 
read_var(int len)92 static void read_var(int len)
93 {
94 	__u8 cvar __attribute__((unused));
95 	__u16 svar __attribute__((unused));
96 	__u32 ivar __attribute__((unused));
97 	__u64 lvar __attribute__((unused));
98 
99 	switch (len) {
100 	case 1:
101 		cvar = (volatile __u8)glvar;
102 		break;
103 	case 2:
104 		svar = (volatile __u16)glvar;
105 		break;
106 	case 4:
107 		ivar = (volatile __u32)glvar;
108 		break;
109 	case 8:
110 		lvar = (volatile __u64)glvar;
111 		break;
112 	}
113 }
114 
test_workload(void)115 static void test_workload(void)
116 {
117 	__u8 cvar __attribute__((unused));
118 	__u32 ivar __attribute__((unused));
119 	int len = 0;
120 
121 	if (ptrace(PTRACE_TRACEME, 0, NULL, 0)) {
122 		perror("Child can't be traced?");
123 		exit(-1);
124 	}
125 
126 	/* Wake up father so that it sets up the first test */
127 	kill(getpid(), SIGUSR1);
128 
129 	/* PTRACE_SET_DEBUGREG, WO test */
130 	for (len = 1; len <= sizeof(glvar); len <<= 1)
131 		write_var(len);
132 
133 	/* PTRACE_SET_DEBUGREG, RO test */
134 	for (len = 1; len <= sizeof(glvar); len <<= 1)
135 		read_var(len);
136 
137 	/* PTRACE_SET_DEBUGREG, RW test */
138 	for (len = 1; len <= sizeof(glvar); len <<= 1) {
139 		if (rand() % 2)
140 			read_var(len);
141 		else
142 			write_var(len);
143 	}
144 
145 	/* PTRACE_SET_DEBUGREG, Kernel Access Userspace test */
146 	syscall(__NR_getcwd, &cwd, PATH_MAX);
147 
148 	/* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */
149 	write_var(1);
150 
151 	/* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RO test */
152 	read_var(1);
153 
154 	/* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RW test */
155 	if (rand() % 2)
156 		write_var(1);
157 	else
158 		read_var(1);
159 
160 	/* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, Kernel Access Userspace test */
161 	syscall(__NR_getcwd, &cwd, PATH_MAX);
162 
163 	/* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */
164 	gstruct.a[rand() % A_LEN] = 'a';
165 
166 	/* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RO test */
167 	cvar = gstruct.a[rand() % A_LEN];
168 
169 	/* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RW test */
170 	if (rand() % 2)
171 		gstruct.a[rand() % A_LEN] = 'a';
172 	else
173 		cvar = gstruct.a[rand() % A_LEN];
174 
175 	/* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, WO test */
176 	gstruct.b[rand() % B_LEN] = 'b';
177 
178 	/* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RO test */
179 	cvar = gstruct.b[rand() % B_LEN];
180 
181 	/* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RW test */
182 	if (rand() % 2)
183 		gstruct.b[rand() % B_LEN] = 'b';
184 	else
185 		cvar = gstruct.b[rand() % B_LEN];
186 
187 	/* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE, RW test */
188 	if (rand() % 2)
189 		*((int *)(gstruct.a + 4)) = 10;
190 	else
191 		ivar = *((int *)(gstruct.a + 4));
192 
193 	/* PPC_PTRACE_SETHWDEBUG. DAWR_MAX_LEN. RW test */
194 	if (rand() % 2)
195 		big_var[rand() % DAWR_MAX_LEN] = 'a';
196 	else
197 		cvar = big_var[rand() % DAWR_MAX_LEN];
198 
199 	/* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED, WO test */
200 	gstruct.a[rand() % A_LEN] = 'a';
201 
202 	/* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED, RO test */
203 	cvar = gstruct.b[rand() % B_LEN];
204 
205 	/* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, WO test */
206 	gstruct.a[rand() % A_LEN] = 'a';
207 
208 	/* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, RO test */
209 	cvar = gstruct.a[rand() % A_LEN];
210 }
211 
check_success(pid_t child_pid,const char * name,const char * type,unsigned long saddr,int len)212 static void check_success(pid_t child_pid, const char *name, const char *type,
213 			  unsigned long saddr, int len)
214 {
215 	int status;
216 	siginfo_t siginfo;
217 	unsigned long eaddr = (saddr + len - 1) | 0x7;
218 
219 	saddr &= ~0x7;
220 
221 	/* Wait for the child to SIGTRAP */
222 	wait(&status);
223 
224 	ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &siginfo);
225 
226 	if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP ||
227 	    (unsigned long)siginfo.si_addr < saddr ||
228 	    (unsigned long)siginfo.si_addr > eaddr) {
229 		printf("%s, %s, len: %d: Fail\n", name, type, len);
230 		exit(-1);
231 	}
232 
233 	printf("%s, %s, len: %d: Ok\n", name, type, len);
234 
235 	if (!is_8xx) {
236 		/*
237 		 * For ptrace registered watchpoint, signal is generated
238 		 * before executing load/store. Singlestep the instruction
239 		 * and then continue the test.
240 		 */
241 		ptrace(PTRACE_SINGLESTEP, child_pid, NULL, 0);
242 		wait(NULL);
243 	}
244 }
245 
ptrace_set_debugreg(pid_t child_pid,unsigned long wp_addr)246 static void ptrace_set_debugreg(pid_t child_pid, unsigned long wp_addr)
247 {
248 	if (ptrace(PTRACE_SET_DEBUGREG, child_pid, 0, wp_addr)) {
249 		perror("PTRACE_SET_DEBUGREG failed");
250 		exit(-1);
251 	}
252 }
253 
ptrace_sethwdebug(pid_t child_pid,struct ppc_hw_breakpoint * info)254 static int ptrace_sethwdebug(pid_t child_pid, struct ppc_hw_breakpoint *info)
255 {
256 	int wh = ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, info);
257 
258 	if (wh <= 0) {
259 		perror("PPC_PTRACE_SETHWDEBUG failed");
260 		exit(-1);
261 	}
262 	return wh;
263 }
264 
ptrace_delhwdebug(pid_t child_pid,int wh)265 static void ptrace_delhwdebug(pid_t child_pid, int wh)
266 {
267 	if (ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, wh) < 0) {
268 		perror("PPC_PTRACE_DELHWDEBUG failed");
269 		exit(-1);
270 	}
271 }
272 
273 #define DABR_READ_SHIFT		0
274 #define DABR_WRITE_SHIFT	1
275 #define DABR_TRANSLATION_SHIFT	2
276 
test_set_debugreg(pid_t child_pid)277 static int test_set_debugreg(pid_t child_pid)
278 {
279 	unsigned long wp_addr = (unsigned long)&glvar;
280 	char *name = "PTRACE_SET_DEBUGREG";
281 	int len;
282 
283 	/* PTRACE_SET_DEBUGREG, WO test*/
284 	wp_addr &= ~0x7UL;
285 	wp_addr |= (1UL << DABR_WRITE_SHIFT);
286 	wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
287 	for (len = 1; len <= sizeof(glvar); len <<= 1) {
288 		ptrace_set_debugreg(child_pid, wp_addr);
289 		ptrace(PTRACE_CONT, child_pid, NULL, 0);
290 		check_success(child_pid, name, "WO", wp_addr, len);
291 	}
292 
293 	/* PTRACE_SET_DEBUGREG, RO test */
294 	wp_addr &= ~0x7UL;
295 	wp_addr |= (1UL << DABR_READ_SHIFT);
296 	wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
297 	for (len = 1; len <= sizeof(glvar); len <<= 1) {
298 		ptrace_set_debugreg(child_pid, wp_addr);
299 		ptrace(PTRACE_CONT, child_pid, NULL, 0);
300 		check_success(child_pid, name, "RO", wp_addr, len);
301 	}
302 
303 	/* PTRACE_SET_DEBUGREG, RW test */
304 	wp_addr &= ~0x7UL;
305 	wp_addr |= (1Ul << DABR_READ_SHIFT);
306 	wp_addr |= (1UL << DABR_WRITE_SHIFT);
307 	wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
308 	for (len = 1; len <= sizeof(glvar); len <<= 1) {
309 		ptrace_set_debugreg(child_pid, wp_addr);
310 		ptrace(PTRACE_CONT, child_pid, NULL, 0);
311 		check_success(child_pid, name, "RW", wp_addr, len);
312 	}
313 
314 	ptrace_set_debugreg(child_pid, 0);
315 	return 0;
316 }
317 
test_set_debugreg_kernel_userspace(pid_t child_pid)318 static int test_set_debugreg_kernel_userspace(pid_t child_pid)
319 {
320 	unsigned long wp_addr = (unsigned long)cwd;
321 	char *name = "PTRACE_SET_DEBUGREG";
322 
323 	/* PTRACE_SET_DEBUGREG, Kernel Access Userspace test */
324 	wp_addr &= ~0x7UL;
325 	wp_addr |= (1Ul << DABR_READ_SHIFT);
326 	wp_addr |= (1UL << DABR_WRITE_SHIFT);
327 	wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
328 	ptrace_set_debugreg(child_pid, wp_addr);
329 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
330 	check_success(child_pid, name, "Kernel Access Userspace", wp_addr, 8);
331 
332 	ptrace_set_debugreg(child_pid, 0);
333 	return 0;
334 }
335 
get_ppc_hw_breakpoint(struct ppc_hw_breakpoint * info,int type,unsigned long addr,int len)336 static void get_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type,
337 				  unsigned long addr, int len)
338 {
339 	info->version = 1;
340 	info->trigger_type = type;
341 	info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
342 	info->addr = (__u64)addr;
343 	info->addr2 = (__u64)addr + len;
344 	info->condition_value = 0;
345 	if (!len)
346 		info->addr_mode = PPC_BREAKPOINT_MODE_EXACT;
347 	else
348 		info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
349 }
350 
test_sethwdebug_exact(pid_t child_pid)351 static void test_sethwdebug_exact(pid_t child_pid)
352 {
353 	struct ppc_hw_breakpoint info;
354 	unsigned long wp_addr = (unsigned long)&glvar;
355 	char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT";
356 	int len = 1; /* hardcoded in kernel */
357 	int wh;
358 
359 	/* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */
360 	get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0);
361 	wh = ptrace_sethwdebug(child_pid, &info);
362 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
363 	check_success(child_pid, name, "WO", wp_addr, len);
364 	ptrace_delhwdebug(child_pid, wh);
365 
366 	/* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RO test */
367 	get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, 0);
368 	wh = ptrace_sethwdebug(child_pid, &info);
369 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
370 	check_success(child_pid, name, "RO", wp_addr, len);
371 	ptrace_delhwdebug(child_pid, wh);
372 
373 	/* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RW test */
374 	get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, 0);
375 	wh = ptrace_sethwdebug(child_pid, &info);
376 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
377 	check_success(child_pid, name, "RW", wp_addr, len);
378 	ptrace_delhwdebug(child_pid, wh);
379 }
380 
test_sethwdebug_exact_kernel_userspace(pid_t child_pid)381 static void test_sethwdebug_exact_kernel_userspace(pid_t child_pid)
382 {
383 	struct ppc_hw_breakpoint info;
384 	unsigned long wp_addr = (unsigned long)&cwd;
385 	char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT";
386 	int len = 1; /* hardcoded in kernel */
387 	int wh;
388 
389 	/* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, Kernel Access Userspace test */
390 	get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0);
391 	wh = ptrace_sethwdebug(child_pid, &info);
392 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
393 	check_success(child_pid, name, "Kernel Access Userspace", wp_addr, len);
394 	ptrace_delhwdebug(child_pid, wh);
395 }
396 
test_sethwdebug_range_aligned(pid_t child_pid)397 static void test_sethwdebug_range_aligned(pid_t child_pid)
398 {
399 	struct ppc_hw_breakpoint info;
400 	unsigned long wp_addr;
401 	char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED";
402 	int len;
403 	int wh;
404 
405 	/* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */
406 	wp_addr = (unsigned long)&gstruct.a;
407 	len = A_LEN;
408 	get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
409 	wh = ptrace_sethwdebug(child_pid, &info);
410 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
411 	check_success(child_pid, name, "WO", wp_addr, len);
412 	ptrace_delhwdebug(child_pid, wh);
413 
414 	/* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RO test */
415 	wp_addr = (unsigned long)&gstruct.a;
416 	len = A_LEN;
417 	get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len);
418 	wh = ptrace_sethwdebug(child_pid, &info);
419 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
420 	check_success(child_pid, name, "RO", wp_addr, len);
421 	ptrace_delhwdebug(child_pid, wh);
422 
423 	/* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RW test */
424 	wp_addr = (unsigned long)&gstruct.a;
425 	len = A_LEN;
426 	get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
427 	wh = ptrace_sethwdebug(child_pid, &info);
428 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
429 	check_success(child_pid, name, "RW", wp_addr, len);
430 	ptrace_delhwdebug(child_pid, wh);
431 }
432 
test_multi_sethwdebug_range(pid_t child_pid)433 static void test_multi_sethwdebug_range(pid_t child_pid)
434 {
435 	struct ppc_hw_breakpoint info1, info2;
436 	unsigned long wp_addr1, wp_addr2;
437 	char *name1 = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED";
438 	char *name2 = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED";
439 	int len1, len2;
440 	int wh1, wh2;
441 
442 	wp_addr1 = (unsigned long)&gstruct.a;
443 	wp_addr2 = (unsigned long)&gstruct.b;
444 	len1 = A_LEN;
445 	len2 = B_LEN;
446 	get_ppc_hw_breakpoint(&info1, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr1, len1);
447 	get_ppc_hw_breakpoint(&info2, PPC_BREAKPOINT_TRIGGER_READ, wp_addr2, len2);
448 
449 	/* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED, WO test */
450 	wh1 = ptrace_sethwdebug(child_pid, &info1);
451 
452 	/* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED, RO test */
453 	wh2 = ptrace_sethwdebug(child_pid, &info2);
454 
455 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
456 	check_success(child_pid, name1, "WO", wp_addr1, len1);
457 
458 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
459 	check_success(child_pid, name2, "RO", wp_addr2, len2);
460 
461 	ptrace_delhwdebug(child_pid, wh1);
462 	ptrace_delhwdebug(child_pid, wh2);
463 }
464 
test_multi_sethwdebug_range_dawr_overlap(pid_t child_pid)465 static void test_multi_sethwdebug_range_dawr_overlap(pid_t child_pid)
466 {
467 	struct ppc_hw_breakpoint info1, info2;
468 	unsigned long wp_addr1, wp_addr2;
469 	char *name = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap";
470 	int len1, len2;
471 	int wh1, wh2;
472 
473 	wp_addr1 = (unsigned long)&gstruct.a;
474 	wp_addr2 = (unsigned long)&gstruct.a;
475 	len1 = A_LEN;
476 	len2 = A_LEN;
477 	get_ppc_hw_breakpoint(&info1, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr1, len1);
478 	get_ppc_hw_breakpoint(&info2, PPC_BREAKPOINT_TRIGGER_READ, wp_addr2, len2);
479 
480 	/* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, WO test */
481 	wh1 = ptrace_sethwdebug(child_pid, &info1);
482 
483 	/* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, RO test */
484 	wh2 = ptrace_sethwdebug(child_pid, &info2);
485 
486 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
487 	check_success(child_pid, name, "WO", wp_addr1, len1);
488 
489 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
490 	check_success(child_pid, name, "RO", wp_addr2, len2);
491 
492 	ptrace_delhwdebug(child_pid, wh1);
493 	ptrace_delhwdebug(child_pid, wh2);
494 }
495 
test_sethwdebug_range_unaligned(pid_t child_pid)496 static void test_sethwdebug_range_unaligned(pid_t child_pid)
497 {
498 	struct ppc_hw_breakpoint info;
499 	unsigned long wp_addr;
500 	char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED";
501 	int len;
502 	int wh;
503 
504 	/* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, WO test */
505 	wp_addr = (unsigned long)&gstruct.b;
506 	len = B_LEN;
507 	get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
508 	wh = ptrace_sethwdebug(child_pid, &info);
509 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
510 	check_success(child_pid, name, "WO", wp_addr, len);
511 	ptrace_delhwdebug(child_pid, wh);
512 
513 	/* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RO test */
514 	wp_addr = (unsigned long)&gstruct.b;
515 	len = B_LEN;
516 	get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len);
517 	wh = ptrace_sethwdebug(child_pid, &info);
518 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
519 	check_success(child_pid, name, "RO", wp_addr, len);
520 	ptrace_delhwdebug(child_pid, wh);
521 
522 	/* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RW test */
523 	wp_addr = (unsigned long)&gstruct.b;
524 	len = B_LEN;
525 	get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
526 	wh = ptrace_sethwdebug(child_pid, &info);
527 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
528 	check_success(child_pid, name, "RW", wp_addr, len);
529 	ptrace_delhwdebug(child_pid, wh);
530 
531 }
532 
test_sethwdebug_range_unaligned_dar(pid_t child_pid)533 static void test_sethwdebug_range_unaligned_dar(pid_t child_pid)
534 {
535 	struct ppc_hw_breakpoint info;
536 	unsigned long wp_addr;
537 	char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE";
538 	int len;
539 	int wh;
540 
541 	/* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE, RW test */
542 	wp_addr = (unsigned long)&gstruct.b;
543 	len = B_LEN;
544 	get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
545 	wh = ptrace_sethwdebug(child_pid, &info);
546 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
547 	check_success(child_pid, name, "RW", wp_addr, len);
548 	ptrace_delhwdebug(child_pid, wh);
549 }
550 
test_sethwdebug_dawr_max_range(pid_t child_pid)551 static void test_sethwdebug_dawr_max_range(pid_t child_pid)
552 {
553 	struct ppc_hw_breakpoint info;
554 	unsigned long wp_addr;
555 	char *name = "PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN";
556 	int len;
557 	int wh;
558 
559 	/* PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN, RW test */
560 	wp_addr = (unsigned long)big_var;
561 	len = DAWR_MAX_LEN;
562 	get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
563 	wh = ptrace_sethwdebug(child_pid, &info);
564 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
565 	check_success(child_pid, name, "RW", wp_addr, len);
566 	ptrace_delhwdebug(child_pid, wh);
567 }
568 
569 /* Set the breakpoints and check the child successfully trigger them */
570 static void
run_tests(pid_t child_pid,struct ppc_debug_info * dbginfo,bool dawr)571 run_tests(pid_t child_pid, struct ppc_debug_info *dbginfo, bool dawr)
572 {
573 	test_set_debugreg(child_pid);
574 	test_set_debugreg_kernel_userspace(child_pid);
575 	test_sethwdebug_exact(child_pid);
576 	test_sethwdebug_exact_kernel_userspace(child_pid);
577 	if (dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_RANGE) {
578 		test_sethwdebug_range_aligned(child_pid);
579 		if (dawr || is_8xx) {
580 			test_sethwdebug_range_unaligned(child_pid);
581 			test_sethwdebug_range_unaligned_dar(child_pid);
582 			test_sethwdebug_dawr_max_range(child_pid);
583 			if (dbginfo->num_data_bps > 1) {
584 				test_multi_sethwdebug_range(child_pid);
585 				test_multi_sethwdebug_range_dawr_overlap(child_pid);
586 			}
587 		}
588 	}
589 }
590 
ptrace_hwbreak(void)591 static int ptrace_hwbreak(void)
592 {
593 	pid_t child_pid;
594 	struct ppc_debug_info dbginfo;
595 	bool dawr;
596 
597 	child_pid = fork();
598 	if (!child_pid) {
599 		test_workload();
600 		return 0;
601 	}
602 
603 	wait(NULL);
604 
605 	get_dbginfo(child_pid, &dbginfo);
606 	SKIP_IF_MSG(dbginfo.num_data_bps == 0, "No data breakpoints present");
607 
608 	dawr = dawr_present(&dbginfo);
609 	run_tests(child_pid, &dbginfo, dawr);
610 
611 	/* Let the child exit first. */
612 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
613 	wait(NULL);
614 
615 	/*
616 	 * Testcases exits immediately with -1 on any failure. If
617 	 * it has reached here, it means all tests were successful.
618 	 */
619 	return TEST_PASS;
620 }
621 
main(int argc,char ** argv,char ** envp)622 int main(int argc, char **argv, char **envp)
623 {
624 	is_8xx = mfspr(SPRN_PVR) == PVR_8xx;
625 
626 	return test_harness(ptrace_hwbreak, "ptrace-hwbreak");
627 }
628