#include <sys/user.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void
set_debugregs(unsigned long *v)
{
	if (!fork()) {
		int i, *p = ((struct user *)0)->u_debugreg;
		pid_t ppid = getppid();
		ptrace(PTRACE_ATTACH, ppid, NULL, NULL);
		waitpid(ppid, NULL, 0);
		for (i = 0; i < 8; i++, p++, v++) {
			if (i == 4 || i == 5)
				continue;
			if (ptrace(PTRACE_POKEUSER, ppid, p, *v) < 0)
				fprintf(stderr,
					"ptrace failed: dr%d = %08lx\n", i, *v);
		}
		ptrace(PTRACE_DETACH, ppid, NULL, NULL);
		exit(0);
	}
	wait(NULL);
}

#include <signal.h>
#include <asm/ucontext.h>

#define TRY(x) do { fputs("Trying " #x "\n", stderr); x; } while (0)

static void
trap_handler(int n, siginfo_t *si, struct ucontext *uc)
{
	fprintf(stderr, "  Trapped at 0x%08lx\n", uc->uc_mcontext.eip);
	uc->uc_mcontext.eflags |= 1<<16; /* Set RF; helpless */
}

int tmp, data0, data1;
void func(void) {}

int
main(void)
{
	unsigned long regs[] = {
		(unsigned long)&data0,
		(unsigned long)&data1,
		(unsigned long)func,
		0, /* unused */
		0, /* reserved */
		0, /* reserved */
		0, /* cant read */
		0x00fd013f, /* Trap conditions
				0: write, 1: read/write, 2: exec, 3: unused */
	};

	struct sigaction sa = {
		.sa_sigaction = (void *)trap_handler,
		.sa_flags = SA_RESTART | SA_SIGINFO,
	};

	sigemptyset(&sa.sa_mask);
	sigaction(SIGTRAP, &sa, NULL);
	set_debugregs(regs);

	TRY(tmp = data0);
	TRY(tmp = data1);
	TRY(data0 = 1);
	TRY(data1 = 1);
	TRY(func());

	return 0;
}

