xref: /linux/tools/testing/selftests/breakpoints/breakpoint_test.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
14f19048fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
285bbddc3SFrederic Weisbecker /*
385bbddc3SFrederic Weisbecker  * Copyright (C) 2011 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
485bbddc3SFrederic Weisbecker  *
585bbddc3SFrederic Weisbecker  * Selftests for breakpoints (and more generally the do_debug() path) in x86.
685bbddc3SFrederic Weisbecker  */
785bbddc3SFrederic Weisbecker 
885bbddc3SFrederic Weisbecker 
985bbddc3SFrederic Weisbecker #include <sys/ptrace.h>
1085bbddc3SFrederic Weisbecker #include <unistd.h>
1185bbddc3SFrederic Weisbecker #include <stddef.h>
1285bbddc3SFrederic Weisbecker #include <sys/user.h>
1385bbddc3SFrederic Weisbecker #include <stdio.h>
1485bbddc3SFrederic Weisbecker #include <stdlib.h>
1585bbddc3SFrederic Weisbecker #include <signal.h>
1685bbddc3SFrederic Weisbecker #include <sys/types.h>
1785bbddc3SFrederic Weisbecker #include <sys/wait.h>
184ca56287SShuah Khan #include <errno.h>
194ca56287SShuah Khan #include <string.h>
2085bbddc3SFrederic Weisbecker 
21b3616904SShuah Khan #include "../kselftest.h"
22b3616904SShuah Khan 
235821ba96SKees Cook #define COUNT_ISN_BPS	4
245821ba96SKees Cook #define COUNT_WPS	4
2585bbddc3SFrederic Weisbecker 
2685bbddc3SFrederic Weisbecker /* Breakpoint access modes */
2785bbddc3SFrederic Weisbecker enum {
2885bbddc3SFrederic Weisbecker 	BP_X = 1,
2985bbddc3SFrederic Weisbecker 	BP_RW = 2,
3085bbddc3SFrederic Weisbecker 	BP_W = 4,
3185bbddc3SFrederic Weisbecker };
3285bbddc3SFrederic Weisbecker 
3385bbddc3SFrederic Weisbecker static pid_t child_pid;
3485bbddc3SFrederic Weisbecker 
3585bbddc3SFrederic Weisbecker /*
3685bbddc3SFrederic Weisbecker  * Ensures the child and parent are always "talking" about
3785bbddc3SFrederic Weisbecker  * the same test sequence. (ie: that we haven't forgotten
3885bbddc3SFrederic Weisbecker  * to call check_trapped() somewhere).
3985bbddc3SFrederic Weisbecker  */
4085bbddc3SFrederic Weisbecker static int nr_tests;
4185bbddc3SFrederic Weisbecker 
set_breakpoint_addr(void * addr,int n)4285bbddc3SFrederic Weisbecker static void set_breakpoint_addr(void *addr, int n)
4385bbddc3SFrederic Weisbecker {
4485bbddc3SFrederic Weisbecker 	int ret;
4585bbddc3SFrederic Weisbecker 
4685bbddc3SFrederic Weisbecker 	ret = ptrace(PTRACE_POKEUSER, child_pid,
4785bbddc3SFrederic Weisbecker 		     offsetof(struct user, u_debugreg[n]), addr);
48748e84b7SPaul Elder 	if (ret)
494ca56287SShuah Khan 		ksft_exit_fail_msg("Can't set breakpoint addr: %s\n",
504ca56287SShuah Khan 			strerror(errno));
5185bbddc3SFrederic Weisbecker }
5285bbddc3SFrederic Weisbecker 
toggle_breakpoint(int n,int type,int len,int local,int global,int set)5385bbddc3SFrederic Weisbecker static void toggle_breakpoint(int n, int type, int len,
5485bbddc3SFrederic Weisbecker 			      int local, int global, int set)
5585bbddc3SFrederic Weisbecker {
5685bbddc3SFrederic Weisbecker 	int ret;
5785bbddc3SFrederic Weisbecker 
5885bbddc3SFrederic Weisbecker 	int xtype, xlen;
5985bbddc3SFrederic Weisbecker 	unsigned long vdr7, dr7;
6085bbddc3SFrederic Weisbecker 
6185bbddc3SFrederic Weisbecker 	switch (type) {
6285bbddc3SFrederic Weisbecker 	case BP_X:
6385bbddc3SFrederic Weisbecker 		xtype = 0;
6485bbddc3SFrederic Weisbecker 		break;
6585bbddc3SFrederic Weisbecker 	case BP_W:
6685bbddc3SFrederic Weisbecker 		xtype = 1;
6785bbddc3SFrederic Weisbecker 		break;
6885bbddc3SFrederic Weisbecker 	case BP_RW:
6985bbddc3SFrederic Weisbecker 		xtype = 3;
7085bbddc3SFrederic Weisbecker 		break;
7185bbddc3SFrederic Weisbecker 	}
7285bbddc3SFrederic Weisbecker 
7385bbddc3SFrederic Weisbecker 	switch (len) {
7485bbddc3SFrederic Weisbecker 	case 1:
7585bbddc3SFrederic Weisbecker 		xlen = 0;
7685bbddc3SFrederic Weisbecker 		break;
7785bbddc3SFrederic Weisbecker 	case 2:
7885bbddc3SFrederic Weisbecker 		xlen = 4;
7985bbddc3SFrederic Weisbecker 		break;
8085bbddc3SFrederic Weisbecker 	case 4:
8185bbddc3SFrederic Weisbecker 		xlen = 0xc;
8285bbddc3SFrederic Weisbecker 		break;
8385bbddc3SFrederic Weisbecker 	case 8:
8485bbddc3SFrederic Weisbecker 		xlen = 8;
8585bbddc3SFrederic Weisbecker 		break;
8685bbddc3SFrederic Weisbecker 	}
8785bbddc3SFrederic Weisbecker 
8885bbddc3SFrederic Weisbecker 	dr7 = ptrace(PTRACE_PEEKUSER, child_pid,
8985bbddc3SFrederic Weisbecker 		     offsetof(struct user, u_debugreg[7]), 0);
9085bbddc3SFrederic Weisbecker 
9185bbddc3SFrederic Weisbecker 	vdr7 = (xlen | xtype) << 16;
9285bbddc3SFrederic Weisbecker 	vdr7 <<= 4 * n;
9385bbddc3SFrederic Weisbecker 
9485bbddc3SFrederic Weisbecker 	if (local) {
9585bbddc3SFrederic Weisbecker 		vdr7 |= 1 << (2 * n);
9685bbddc3SFrederic Weisbecker 		vdr7 |= 1 << 8;
9785bbddc3SFrederic Weisbecker 	}
9885bbddc3SFrederic Weisbecker 	if (global) {
9985bbddc3SFrederic Weisbecker 		vdr7 |= 2 << (2 * n);
10085bbddc3SFrederic Weisbecker 		vdr7 |= 1 << 9;
10185bbddc3SFrederic Weisbecker 	}
10285bbddc3SFrederic Weisbecker 
10385bbddc3SFrederic Weisbecker 	if (set)
10485bbddc3SFrederic Weisbecker 		dr7 |= vdr7;
10585bbddc3SFrederic Weisbecker 	else
10685bbddc3SFrederic Weisbecker 		dr7 &= ~vdr7;
10785bbddc3SFrederic Weisbecker 
10885bbddc3SFrederic Weisbecker 	ret = ptrace(PTRACE_POKEUSER, child_pid,
10985bbddc3SFrederic Weisbecker 		     offsetof(struct user, u_debugreg[7]), dr7);
1104ca56287SShuah Khan 	if (ret) {
1114ca56287SShuah Khan 		ksft_print_msg("Can't set dr7: %s\n", strerror(errno));
1124ca56287SShuah Khan 		exit(-1);
1134ca56287SShuah Khan 	}
11485bbddc3SFrederic Weisbecker }
11585bbddc3SFrederic Weisbecker 
11685bbddc3SFrederic Weisbecker /* Dummy variables to test read/write accesses */
11785bbddc3SFrederic Weisbecker static unsigned long long dummy_var[4];
11885bbddc3SFrederic Weisbecker 
11985bbddc3SFrederic Weisbecker /* Dummy functions to test execution accesses */
dummy_func(void)12085bbddc3SFrederic Weisbecker static void dummy_func(void) { }
dummy_func1(void)12185bbddc3SFrederic Weisbecker static void dummy_func1(void) { }
dummy_func2(void)12285bbddc3SFrederic Weisbecker static void dummy_func2(void) { }
dummy_func3(void)12385bbddc3SFrederic Weisbecker static void dummy_func3(void) { }
12485bbddc3SFrederic Weisbecker 
12585bbddc3SFrederic Weisbecker static void (*dummy_funcs[])(void) = {
12685bbddc3SFrederic Weisbecker 	dummy_func,
12785bbddc3SFrederic Weisbecker 	dummy_func1,
12885bbddc3SFrederic Weisbecker 	dummy_func2,
12985bbddc3SFrederic Weisbecker 	dummy_func3,
13085bbddc3SFrederic Weisbecker };
13185bbddc3SFrederic Weisbecker 
13285bbddc3SFrederic Weisbecker static int trapped;
13385bbddc3SFrederic Weisbecker 
check_trapped(void)13485bbddc3SFrederic Weisbecker static void check_trapped(void)
13585bbddc3SFrederic Weisbecker {
13685bbddc3SFrederic Weisbecker 	/*
13785bbddc3SFrederic Weisbecker 	 * If we haven't trapped, wake up the parent
13885bbddc3SFrederic Weisbecker 	 * so that it notices the failure.
13985bbddc3SFrederic Weisbecker 	 */
14085bbddc3SFrederic Weisbecker 	if (!trapped)
14185bbddc3SFrederic Weisbecker 		kill(getpid(), SIGUSR1);
14285bbddc3SFrederic Weisbecker 	trapped = 0;
14385bbddc3SFrederic Weisbecker 
14485bbddc3SFrederic Weisbecker 	nr_tests++;
14585bbddc3SFrederic Weisbecker }
14685bbddc3SFrederic Weisbecker 
write_var(int len)14785bbddc3SFrederic Weisbecker static void write_var(int len)
14885bbddc3SFrederic Weisbecker {
14985bbddc3SFrederic Weisbecker 	char *pcval; short *psval; int *pival; long long *plval;
15085bbddc3SFrederic Weisbecker 	int i;
15185bbddc3SFrederic Weisbecker 
15285bbddc3SFrederic Weisbecker 	for (i = 0; i < 4; i++) {
15385bbddc3SFrederic Weisbecker 		switch (len) {
15485bbddc3SFrederic Weisbecker 		case 1:
15585bbddc3SFrederic Weisbecker 			pcval = (char *)&dummy_var[i];
15685bbddc3SFrederic Weisbecker 			*pcval = 0xff;
15785bbddc3SFrederic Weisbecker 			break;
15885bbddc3SFrederic Weisbecker 		case 2:
15985bbddc3SFrederic Weisbecker 			psval = (short *)&dummy_var[i];
16085bbddc3SFrederic Weisbecker 			*psval = 0xffff;
16185bbddc3SFrederic Weisbecker 			break;
16285bbddc3SFrederic Weisbecker 		case 4:
16385bbddc3SFrederic Weisbecker 			pival = (int *)&dummy_var[i];
16485bbddc3SFrederic Weisbecker 			*pival = 0xffffffff;
16585bbddc3SFrederic Weisbecker 			break;
16685bbddc3SFrederic Weisbecker 		case 8:
16785bbddc3SFrederic Weisbecker 			plval = (long long *)&dummy_var[i];
16885bbddc3SFrederic Weisbecker 			*plval = 0xffffffffffffffffLL;
16985bbddc3SFrederic Weisbecker 			break;
17085bbddc3SFrederic Weisbecker 		}
17185bbddc3SFrederic Weisbecker 		check_trapped();
17285bbddc3SFrederic Weisbecker 	}
17385bbddc3SFrederic Weisbecker }
17485bbddc3SFrederic Weisbecker 
read_var(int len)17585bbddc3SFrederic Weisbecker static void read_var(int len)
17685bbddc3SFrederic Weisbecker {
17785bbddc3SFrederic Weisbecker 	char cval; short sval; int ival; long long lval;
17885bbddc3SFrederic Weisbecker 	int i;
17985bbddc3SFrederic Weisbecker 
18085bbddc3SFrederic Weisbecker 	for (i = 0; i < 4; i++) {
18185bbddc3SFrederic Weisbecker 		switch (len) {
18285bbddc3SFrederic Weisbecker 		case 1:
18385bbddc3SFrederic Weisbecker 			cval = *(char *)&dummy_var[i];
18485bbddc3SFrederic Weisbecker 			break;
18585bbddc3SFrederic Weisbecker 		case 2:
18685bbddc3SFrederic Weisbecker 			sval = *(short *)&dummy_var[i];
18785bbddc3SFrederic Weisbecker 			break;
18885bbddc3SFrederic Weisbecker 		case 4:
18985bbddc3SFrederic Weisbecker 			ival = *(int *)&dummy_var[i];
19085bbddc3SFrederic Weisbecker 			break;
19185bbddc3SFrederic Weisbecker 		case 8:
19285bbddc3SFrederic Weisbecker 			lval = *(long long *)&dummy_var[i];
19385bbddc3SFrederic Weisbecker 			break;
19485bbddc3SFrederic Weisbecker 		}
19585bbddc3SFrederic Weisbecker 		check_trapped();
19685bbddc3SFrederic Weisbecker 	}
19785bbddc3SFrederic Weisbecker }
19885bbddc3SFrederic Weisbecker 
19985bbddc3SFrederic Weisbecker /*
20085bbddc3SFrederic Weisbecker  * Do the r/w/x accesses to trigger the breakpoints. And run
20185bbddc3SFrederic Weisbecker  * the usual traps.
20285bbddc3SFrederic Weisbecker  */
trigger_tests(void)20385bbddc3SFrederic Weisbecker static void trigger_tests(void)
20485bbddc3SFrederic Weisbecker {
20585bbddc3SFrederic Weisbecker 	int len, local, global, i;
20685bbddc3SFrederic Weisbecker 	char val;
20785bbddc3SFrederic Weisbecker 	int ret;
20885bbddc3SFrederic Weisbecker 
20985bbddc3SFrederic Weisbecker 	ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
21085bbddc3SFrederic Weisbecker 	if (ret) {
2114ca56287SShuah Khan 		ksft_print_msg("Can't be traced? %s\n", strerror(errno));
21285bbddc3SFrederic Weisbecker 		return;
21385bbddc3SFrederic Weisbecker 	}
21485bbddc3SFrederic Weisbecker 
21585bbddc3SFrederic Weisbecker 	/* Wake up father so that it sets up the first test */
21685bbddc3SFrederic Weisbecker 	kill(getpid(), SIGUSR1);
21785bbddc3SFrederic Weisbecker 
21885bbddc3SFrederic Weisbecker 	/* Test instruction breakpoints */
21985bbddc3SFrederic Weisbecker 	for (local = 0; local < 2; local++) {
22085bbddc3SFrederic Weisbecker 		for (global = 0; global < 2; global++) {
22185bbddc3SFrederic Weisbecker 			if (!local && !global)
22285bbddc3SFrederic Weisbecker 				continue;
22385bbddc3SFrederic Weisbecker 
2245821ba96SKees Cook 			for (i = 0; i < COUNT_ISN_BPS; i++) {
22585bbddc3SFrederic Weisbecker 				dummy_funcs[i]();
22685bbddc3SFrederic Weisbecker 				check_trapped();
22785bbddc3SFrederic Weisbecker 			}
22885bbddc3SFrederic Weisbecker 		}
22985bbddc3SFrederic Weisbecker 	}
23085bbddc3SFrederic Weisbecker 
23185bbddc3SFrederic Weisbecker 	/* Test write watchpoints */
23285bbddc3SFrederic Weisbecker 	for (len = 1; len <= sizeof(long); len <<= 1) {
23385bbddc3SFrederic Weisbecker 		for (local = 0; local < 2; local++) {
23485bbddc3SFrederic Weisbecker 			for (global = 0; global < 2; global++) {
23585bbddc3SFrederic Weisbecker 				if (!local && !global)
23685bbddc3SFrederic Weisbecker 					continue;
23785bbddc3SFrederic Weisbecker 				write_var(len);
23885bbddc3SFrederic Weisbecker 			}
23985bbddc3SFrederic Weisbecker 		}
24085bbddc3SFrederic Weisbecker 	}
24185bbddc3SFrederic Weisbecker 
24285bbddc3SFrederic Weisbecker 	/* Test read/write watchpoints (on read accesses) */
24385bbddc3SFrederic Weisbecker 	for (len = 1; len <= sizeof(long); len <<= 1) {
24485bbddc3SFrederic Weisbecker 		for (local = 0; local < 2; local++) {
24585bbddc3SFrederic Weisbecker 			for (global = 0; global < 2; global++) {
24685bbddc3SFrederic Weisbecker 				if (!local && !global)
24785bbddc3SFrederic Weisbecker 					continue;
24885bbddc3SFrederic Weisbecker 				read_var(len);
24985bbddc3SFrederic Weisbecker 			}
25085bbddc3SFrederic Weisbecker 		}
25185bbddc3SFrederic Weisbecker 	}
25285bbddc3SFrederic Weisbecker 
25385bbddc3SFrederic Weisbecker 	/* Icebp trap */
25485bbddc3SFrederic Weisbecker 	asm(".byte 0xf1\n");
25585bbddc3SFrederic Weisbecker 	check_trapped();
25685bbddc3SFrederic Weisbecker 
25785bbddc3SFrederic Weisbecker 	/* Int 3 trap */
25885bbddc3SFrederic Weisbecker 	asm("int $3\n");
25985bbddc3SFrederic Weisbecker 	check_trapped();
26085bbddc3SFrederic Weisbecker 
26185bbddc3SFrederic Weisbecker 	kill(getpid(), SIGUSR1);
26285bbddc3SFrederic Weisbecker }
26385bbddc3SFrederic Weisbecker 
check_success(const char * msg)26485bbddc3SFrederic Weisbecker static void check_success(const char *msg)
26585bbddc3SFrederic Weisbecker {
26685bbddc3SFrederic Weisbecker 	int child_nr_tests;
26785bbddc3SFrederic Weisbecker 	int status;
268748e84b7SPaul Elder 	int ret;
26985bbddc3SFrederic Weisbecker 
27085bbddc3SFrederic Weisbecker 	/* Wait for the child to SIGTRAP */
27185bbddc3SFrederic Weisbecker 	wait(&status);
27285bbddc3SFrederic Weisbecker 
273748e84b7SPaul Elder 	ret = 0;
27485bbddc3SFrederic Weisbecker 
27585bbddc3SFrederic Weisbecker 	if (WSTOPSIG(status) == SIGTRAP) {
27685bbddc3SFrederic Weisbecker 		child_nr_tests = ptrace(PTRACE_PEEKDATA, child_pid,
27785bbddc3SFrederic Weisbecker 					&nr_tests, 0);
27885bbddc3SFrederic Weisbecker 		if (child_nr_tests == nr_tests)
279748e84b7SPaul Elder 			ret = 1;
280748e84b7SPaul Elder 		if (ptrace(PTRACE_POKEDATA, child_pid, &trapped, 1))
2814ca56287SShuah Khan 			ksft_exit_fail_msg("Can't poke: %s\n", strerror(errno));
28285bbddc3SFrederic Weisbecker 	}
28385bbddc3SFrederic Weisbecker 
28485bbddc3SFrederic Weisbecker 	nr_tests++;
28585bbddc3SFrederic Weisbecker 
286748e84b7SPaul Elder 	if (ret)
287*e1c0b9efSangquan yu 		ksft_test_result_pass("%s", msg);
288748e84b7SPaul Elder 	else
289*e1c0b9efSangquan yu 		ksft_test_result_fail("%s", msg);
29085bbddc3SFrederic Weisbecker }
29185bbddc3SFrederic Weisbecker 
launch_instruction_breakpoints(char * buf,int local,int global)29285bbddc3SFrederic Weisbecker static void launch_instruction_breakpoints(char *buf, int local, int global)
29385bbddc3SFrederic Weisbecker {
29485bbddc3SFrederic Weisbecker 	int i;
29585bbddc3SFrederic Weisbecker 
2965821ba96SKees Cook 	for (i = 0; i < COUNT_ISN_BPS; i++) {
29785bbddc3SFrederic Weisbecker 		set_breakpoint_addr(dummy_funcs[i], i);
29885bbddc3SFrederic Weisbecker 		toggle_breakpoint(i, BP_X, 1, local, global, 1);
29985bbddc3SFrederic Weisbecker 		ptrace(PTRACE_CONT, child_pid, NULL, 0);
3004ca56287SShuah Khan 		sprintf(buf, "Test breakpoint %d with local: %d global: %d\n",
30185bbddc3SFrederic Weisbecker 			i, local, global);
30285bbddc3SFrederic Weisbecker 		check_success(buf);
30385bbddc3SFrederic Weisbecker 		toggle_breakpoint(i, BP_X, 1, local, global, 0);
30485bbddc3SFrederic Weisbecker 	}
30585bbddc3SFrederic Weisbecker }
30685bbddc3SFrederic Weisbecker 
launch_watchpoints(char * buf,int mode,int len,int local,int global)30785bbddc3SFrederic Weisbecker static void launch_watchpoints(char *buf, int mode, int len,
30885bbddc3SFrederic Weisbecker 			       int local, int global)
30985bbddc3SFrederic Weisbecker {
31085bbddc3SFrederic Weisbecker 	const char *mode_str;
31185bbddc3SFrederic Weisbecker 	int i;
31285bbddc3SFrederic Weisbecker 
31385bbddc3SFrederic Weisbecker 	if (mode == BP_W)
31485bbddc3SFrederic Weisbecker 		mode_str = "write";
31585bbddc3SFrederic Weisbecker 	else
31685bbddc3SFrederic Weisbecker 		mode_str = "read";
31785bbddc3SFrederic Weisbecker 
3185821ba96SKees Cook 	for (i = 0; i < COUNT_WPS; i++) {
31985bbddc3SFrederic Weisbecker 		set_breakpoint_addr(&dummy_var[i], i);
32085bbddc3SFrederic Weisbecker 		toggle_breakpoint(i, mode, len, local, global, 1);
32185bbddc3SFrederic Weisbecker 		ptrace(PTRACE_CONT, child_pid, NULL, 0);
3224ca56287SShuah Khan 		sprintf(buf,
3234ca56287SShuah Khan 			"Test %s watchpoint %d with len: %d local: %d global: %d\n",
3244ca56287SShuah Khan 			mode_str, i, len, local, global);
32585bbddc3SFrederic Weisbecker 		check_success(buf);
32685bbddc3SFrederic Weisbecker 		toggle_breakpoint(i, mode, len, local, global, 0);
32785bbddc3SFrederic Weisbecker 	}
32885bbddc3SFrederic Weisbecker }
32985bbddc3SFrederic Weisbecker 
33085bbddc3SFrederic Weisbecker /* Set the breakpoints and check the child successfully trigger them */
launch_tests(void)33185bbddc3SFrederic Weisbecker static void launch_tests(void)
33285bbddc3SFrederic Weisbecker {
33385bbddc3SFrederic Weisbecker 	char buf[1024];
3345821ba96SKees Cook 	unsigned int tests = 0;
33585bbddc3SFrederic Weisbecker 	int len, local, global, i;
33685bbddc3SFrederic Weisbecker 
3375821ba96SKees Cook 	tests += 3 * COUNT_ISN_BPS;
3385821ba96SKees Cook 	tests += sizeof(long) / 2 * 3 * COUNT_WPS;
3395821ba96SKees Cook 	tests += sizeof(long) / 2 * 3 * COUNT_WPS;
3405821ba96SKees Cook 	tests += 2;
3415821ba96SKees Cook 	ksft_set_plan(tests);
3425821ba96SKees Cook 
34385bbddc3SFrederic Weisbecker 	/* Instruction breakpoints */
34485bbddc3SFrederic Weisbecker 	for (local = 0; local < 2; local++) {
34585bbddc3SFrederic Weisbecker 		for (global = 0; global < 2; global++) {
34685bbddc3SFrederic Weisbecker 			if (!local && !global)
34785bbddc3SFrederic Weisbecker 				continue;
34885bbddc3SFrederic Weisbecker 			launch_instruction_breakpoints(buf, local, global);
34985bbddc3SFrederic Weisbecker 		}
35085bbddc3SFrederic Weisbecker 	}
35185bbddc3SFrederic Weisbecker 
35285bbddc3SFrederic Weisbecker 	/* Write watchpoint */
35385bbddc3SFrederic Weisbecker 	for (len = 1; len <= sizeof(long); len <<= 1) {
35485bbddc3SFrederic Weisbecker 		for (local = 0; local < 2; local++) {
35585bbddc3SFrederic Weisbecker 			for (global = 0; global < 2; global++) {
35685bbddc3SFrederic Weisbecker 				if (!local && !global)
35785bbddc3SFrederic Weisbecker 					continue;
35885bbddc3SFrederic Weisbecker 				launch_watchpoints(buf, BP_W, len,
35985bbddc3SFrederic Weisbecker 						   local, global);
36085bbddc3SFrederic Weisbecker 			}
36185bbddc3SFrederic Weisbecker 		}
36285bbddc3SFrederic Weisbecker 	}
36385bbddc3SFrederic Weisbecker 
36485bbddc3SFrederic Weisbecker 	/* Read-Write watchpoint */
36585bbddc3SFrederic Weisbecker 	for (len = 1; len <= sizeof(long); len <<= 1) {
36685bbddc3SFrederic Weisbecker 		for (local = 0; local < 2; local++) {
36785bbddc3SFrederic Weisbecker 			for (global = 0; global < 2; global++) {
36885bbddc3SFrederic Weisbecker 				if (!local && !global)
36985bbddc3SFrederic Weisbecker 					continue;
37085bbddc3SFrederic Weisbecker 				launch_watchpoints(buf, BP_RW, len,
37185bbddc3SFrederic Weisbecker 						   local, global);
37285bbddc3SFrederic Weisbecker 			}
37385bbddc3SFrederic Weisbecker 		}
37485bbddc3SFrederic Weisbecker 	}
37585bbddc3SFrederic Weisbecker 
37685bbddc3SFrederic Weisbecker 	/* Icebp traps */
37785bbddc3SFrederic Weisbecker 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
378bc3e2ad3SShuah Khan 	check_success("Test icebp\n");
37985bbddc3SFrederic Weisbecker 
38085bbddc3SFrederic Weisbecker 	/* Int 3 traps */
38185bbddc3SFrederic Weisbecker 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
382bc3e2ad3SShuah Khan 	check_success("Test int 3 trap\n");
38385bbddc3SFrederic Weisbecker 
38485bbddc3SFrederic Weisbecker 	ptrace(PTRACE_CONT, child_pid, NULL, 0);
38585bbddc3SFrederic Weisbecker }
38685bbddc3SFrederic Weisbecker 
main(int argc,char ** argv)38785bbddc3SFrederic Weisbecker int main(int argc, char **argv)
38885bbddc3SFrederic Weisbecker {
38985bbddc3SFrederic Weisbecker 	pid_t pid;
39085bbddc3SFrederic Weisbecker 	int ret;
39185bbddc3SFrederic Weisbecker 
392748e84b7SPaul Elder 	ksft_print_header();
393748e84b7SPaul Elder 
39485bbddc3SFrederic Weisbecker 	pid = fork();
39585bbddc3SFrederic Weisbecker 	if (!pid) {
39685bbddc3SFrederic Weisbecker 		trigger_tests();
3974ca56287SShuah Khan 		exit(0);
39885bbddc3SFrederic Weisbecker 	}
39985bbddc3SFrederic Weisbecker 
40085bbddc3SFrederic Weisbecker 	child_pid = pid;
40185bbddc3SFrederic Weisbecker 
40285bbddc3SFrederic Weisbecker 	wait(NULL);
40385bbddc3SFrederic Weisbecker 
40485bbddc3SFrederic Weisbecker 	launch_tests();
40585bbddc3SFrederic Weisbecker 
40685bbddc3SFrederic Weisbecker 	wait(NULL);
40785bbddc3SFrederic Weisbecker 
4084ca56287SShuah Khan 	ksft_exit_pass();
40985bbddc3SFrederic Weisbecker }
410