brintos

brintos / linux-shallow public Read only

0
0
Text · 17.3 KiB · 75d30d6 Raw
628 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3/*4 * Ptrace test for hw breakpoints5 *6 * Based on tools/testing/selftests/breakpoints/breakpoint_test.c7 *8 * This test forks and the parent then traces the child doing various9 * types of ptrace enabled breakpoints10 *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	0x11F29#define PVR_8xx		0x0050000030 31bool is_8xx;32 33/*34 * Use volatile on all global var so that compiler doesn't35 * optimise their load/stores. Otherwise selftest can fail.36 */37static volatile __u64 glvar;38 39#define DAWR_MAX_LEN 51240static volatile __u8 big_var[DAWR_MAX_LEN] __attribute__((aligned(512)));41 42#define A_LEN 643#define B_LEN 644struct gstruct {45	__u8 a[A_LEN]; /* double word aligned */46	__u8 b[B_LEN]; /* double word unaligned */47};48static volatile struct gstruct gstruct __attribute__((aligned(512)));49 50static volatile char cwd[PATH_MAX] __attribute__((aligned(8)));51 52static 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 60static bool dawr_present(struct ppc_debug_info *dbginfo)61{62	return !!(dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_DAWR);63}64 65static 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 92static 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 115static 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		else142			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	else158		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	else173		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	else185		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	else191		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	else197		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 212static 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 generated238		 * before executing load/store. Singlestep the instruction239		 * and then continue the test.240		 */241		ptrace(PTRACE_SINGLESTEP, child_pid, NULL, 0);242		wait(NULL);243	}244}245 246static 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 254static 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 265static 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		0274#define DABR_WRITE_SHIFT	1275#define DABR_TRANSLATION_SHIFT	2276 277static 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 318static 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 336static 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	else348		info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;349}350 351static 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 381static 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 397static 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 433static 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 465static 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 496static 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 533static 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 551static 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 */570static void571run_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 591static 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. If617	 * it has reached here, it means all tests were successful.618	 */619	return TEST_PASS;620}621 622int 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