xref: /openbmc/linux/tools/testing/selftests/powerpc/ptrace/ptrace-hwbreak.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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