1139790Simp/*-
296888Smarcel * Copyright (c) 2001 Alexander Kabaev
396888Smarcel * All rights reserved.
496888Smarcel *
596888Smarcel * Redistribution and use in source and binary forms, with or without
696888Smarcel * modification, are permitted provided that the following conditions
796888Smarcel * are met:
896888Smarcel * 1. Redistributions of source code must retain the above copyright
996888Smarcel *    notice, this list of conditions and the following disclaimer
1096888Smarcel *    in this position and unchanged.
1196888Smarcel * 2. Redistributions in binary form must reproduce the above copyright
1296888Smarcel *    notice, this list of conditions and the following disclaimer in the
1396888Smarcel *    documentation and/or other materials provided with the distribution.
1496888Smarcel * 3. The name of the author may not be used to endorse or promote products
1596888Smarcel *    derived from this software without specific prior written permission.
1696888Smarcel *
1796888Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1896888Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1996888Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2096888Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2196888Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2296888Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2396888Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2496888Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2596888Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2696888Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2796888Smarcel */
2896888Smarcel
29115705Sobrien#include <sys/cdefs.h>
30115705Sobrien__FBSDID("$FreeBSD$");
31115705Sobrien
32103064Speter#include "opt_cpu.h"
33103064Speter
3496888Smarcel#include <sys/param.h>
3596888Smarcel#include <sys/lock.h>
3696888Smarcel#include <sys/mutex.h>
3796888Smarcel#include <sys/proc.h>
3896888Smarcel#include <sys/ptrace.h>
39102946Siedowse#include <sys/syscallsubr.h>
40103352Sbde#include <sys/systm.h>
4196888Smarcel
4296888Smarcel#include <machine/md_var.h>
43103073Sbde#include <machine/pcb.h>
4496888Smarcel#include <machine/reg.h>
4596888Smarcel
4696888Smarcel#include <i386/linux/linux.h>
4796888Smarcel#include <i386/linux/linux_proto.h>
48246085Sjhb#include <compat/linux/linux_signal.h>
4996888Smarcel
50147741Sdelphij#if !defined(CPU_DISABLE_SSE) && defined(I686_CPU)
51103064Speter#define CPU_ENABLE_SSE
52103064Speter#endif
53103064Speter
5496888Smarcel/*
5596888Smarcel *   Linux ptrace requests numbers. Mostly identical to FreeBSD,
5696888Smarcel *   except for MD ones and PT_ATTACH/PT_DETACH.
5796888Smarcel */
5896888Smarcel#define	PTRACE_TRACEME		0
5996888Smarcel#define	PTRACE_PEEKTEXT		1
6096888Smarcel#define	PTRACE_PEEKDATA		2
6196888Smarcel#define	PTRACE_PEEKUSR		3
6296888Smarcel#define	PTRACE_POKETEXT		4
6396888Smarcel#define	PTRACE_POKEDATA		5
6496888Smarcel#define	PTRACE_POKEUSR		6
6596888Smarcel#define	PTRACE_CONT		7
6696888Smarcel#define	PTRACE_KILL		8
6796888Smarcel#define	PTRACE_SINGLESTEP	9
6896888Smarcel
6996888Smarcel#define PTRACE_ATTACH		16
7096888Smarcel#define PTRACE_DETACH		17
7196888Smarcel
7296888Smarcel#define	PTRACE_SYSCALL		24
7396888Smarcel
7496888Smarcel#define PTRACE_GETREGS		12
7596888Smarcel#define PTRACE_SETREGS		13
7696888Smarcel#define PTRACE_GETFPREGS	14
7796888Smarcel#define PTRACE_SETFPREGS	15
7896888Smarcel#define PTRACE_GETFPXREGS	18
7996888Smarcel#define PTRACE_SETFPXREGS	19
8096888Smarcel
8196888Smarcel#define PTRACE_SETOPTIONS	21
8296888Smarcel
8396888Smarcel/*
8496888Smarcel * Linux keeps debug registers at the following
8596888Smarcel * offset in the user struct
8696888Smarcel */
8796888Smarcel#define LINUX_DBREG_OFFSET	252
8896888Smarcel#define LINUX_DBREG_SIZE	(8*sizeof(l_int))
8996888Smarcel
90131575Sstefanfstatic __inline int
9196888Smarcelmap_signum(int signum)
9296888Smarcel{
9396888Smarcel
9496888Smarcel	if (signum > 0 && signum <= LINUX_SIGTBLSZ)
9596888Smarcel		signum = linux_to_bsd_signal[_SIG_IDX(signum)];
9696888Smarcel	return ((signum == SIGSTOP)? 0 : signum);
9796888Smarcel}
9896888Smarcel
9996888Smarcelstruct linux_pt_reg {
10096888Smarcel	l_long	ebx;
10196888Smarcel	l_long	ecx;
10296888Smarcel	l_long	edx;
10396888Smarcel	l_long	esi;
10496888Smarcel	l_long	edi;
10596888Smarcel	l_long	ebp;
10696888Smarcel	l_long	eax;
10796888Smarcel	l_int	xds;
10896888Smarcel	l_int	xes;
10996888Smarcel	l_int	xfs;
11096888Smarcel	l_int	xgs;
11196888Smarcel	l_long	orig_eax;
11296888Smarcel	l_long	eip;
11396888Smarcel	l_int	xcs;
11496888Smarcel	l_long	eflags;
11596888Smarcel	l_long	esp;
11696888Smarcel	l_int	xss;
11796888Smarcel};
11896888Smarcel
11996888Smarcel/*
12096888Smarcel *   Translate i386 ptrace registers between Linux and FreeBSD formats.
12196888Smarcel *   The translation is pretty straighforward, for all registers, but
12296888Smarcel *   orig_eax on Linux side and r_trapno and r_err in FreeBSD
12396888Smarcel */
12496888Smarcelstatic void
12596888Smarcelmap_regs_to_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r)
12696888Smarcel{
12796888Smarcel	linux_r->ebx = bsd_r->r_ebx;
12896888Smarcel	linux_r->ecx = bsd_r->r_ecx;
12996888Smarcel	linux_r->edx = bsd_r->r_edx;
13096888Smarcel	linux_r->esi = bsd_r->r_esi;
13196888Smarcel	linux_r->edi = bsd_r->r_edi;
13296888Smarcel	linux_r->ebp = bsd_r->r_ebp;
13396888Smarcel	linux_r->eax = bsd_r->r_eax;
13496888Smarcel	linux_r->xds = bsd_r->r_ds;
13596888Smarcel	linux_r->xes = bsd_r->r_es;
13696888Smarcel	linux_r->xfs = bsd_r->r_fs;
13796888Smarcel	linux_r->xgs = bsd_r->r_gs;
13896888Smarcel	linux_r->orig_eax = bsd_r->r_eax;
13996888Smarcel	linux_r->eip = bsd_r->r_eip;
14096888Smarcel	linux_r->xcs = bsd_r->r_cs;
14196888Smarcel	linux_r->eflags = bsd_r->r_eflags;
14296888Smarcel	linux_r->esp = bsd_r->r_esp;
14396888Smarcel	linux_r->xss = bsd_r->r_ss;
14496888Smarcel}
14596888Smarcel
14696888Smarcelstatic void
14796888Smarcelmap_regs_from_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r)
14896888Smarcel{
14996888Smarcel	bsd_r->r_ebx = linux_r->ebx;
15096888Smarcel	bsd_r->r_ecx = linux_r->ecx;
15196888Smarcel	bsd_r->r_edx = linux_r->edx;
15296888Smarcel	bsd_r->r_esi = linux_r->esi;
15396888Smarcel	bsd_r->r_edi = linux_r->edi;
15496888Smarcel	bsd_r->r_ebp = linux_r->ebp;
15596888Smarcel	bsd_r->r_eax = linux_r->eax;
15696888Smarcel	bsd_r->r_ds  = linux_r->xds;
15796888Smarcel	bsd_r->r_es  = linux_r->xes;
15896888Smarcel	bsd_r->r_fs  = linux_r->xfs;
15996888Smarcel	bsd_r->r_gs  = linux_r->xgs;
16096888Smarcel	bsd_r->r_eip = linux_r->eip;
16196888Smarcel	bsd_r->r_cs  = linux_r->xcs;
16296888Smarcel	bsd_r->r_eflags = linux_r->eflags;
16396888Smarcel	bsd_r->r_esp = linux_r->esp;
16496888Smarcel	bsd_r->r_ss = linux_r->xss;
16596888Smarcel}
16696888Smarcel
16796888Smarcelstruct linux_pt_fpreg {
16896888Smarcel	l_long cwd;
16996888Smarcel	l_long swd;
17096888Smarcel	l_long twd;
17196888Smarcel	l_long fip;
17296888Smarcel	l_long fcs;
17396888Smarcel	l_long foo;
17496888Smarcel	l_long fos;
17596888Smarcel	l_long st_space[2*10];
17696888Smarcel};
17796888Smarcel
17896888Smarcelstatic void
17996888Smarcelmap_fpregs_to_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r)
18096888Smarcel{
18196888Smarcel	linux_r->cwd = bsd_r->fpr_env[0];
18296888Smarcel	linux_r->swd = bsd_r->fpr_env[1];
18396888Smarcel	linux_r->twd = bsd_r->fpr_env[2];
18496888Smarcel	linux_r->fip = bsd_r->fpr_env[3];
18596888Smarcel	linux_r->fcs = bsd_r->fpr_env[4];
18696888Smarcel	linux_r->foo = bsd_r->fpr_env[5];
18796888Smarcel	linux_r->fos = bsd_r->fpr_env[6];
18896888Smarcel	bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(linux_r->st_space));
18996888Smarcel}
19096888Smarcel
19196888Smarcelstatic void
19296888Smarcelmap_fpregs_from_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r)
19396888Smarcel{
19496888Smarcel	bsd_r->fpr_env[0] = linux_r->cwd;
19596888Smarcel	bsd_r->fpr_env[1] = linux_r->swd;
19696888Smarcel	bsd_r->fpr_env[2] = linux_r->twd;
19796888Smarcel	bsd_r->fpr_env[3] = linux_r->fip;
19896888Smarcel	bsd_r->fpr_env[4] = linux_r->fcs;
19996888Smarcel	bsd_r->fpr_env[5] = linux_r->foo;
20096888Smarcel	bsd_r->fpr_env[6] = linux_r->fos;
20196888Smarcel	bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(bsd_r->fpr_acc));
20296888Smarcel}
20396888Smarcel
20496888Smarcelstruct linux_pt_fpxreg {
20596888Smarcel	l_ushort	cwd;
20696888Smarcel	l_ushort	swd;
20796888Smarcel	l_ushort	twd;
20896888Smarcel	l_ushort	fop;
20996888Smarcel	l_long		fip;
21096888Smarcel	l_long		fcs;
21196888Smarcel	l_long		foo;
21296888Smarcel	l_long		fos;
21396888Smarcel	l_long		mxcsr;
21496888Smarcel	l_long		reserved;
21596888Smarcel	l_long		st_space[32];
21696888Smarcel	l_long		xmm_space[32];
21796888Smarcel	l_long		padding[56];
21896888Smarcel};
21996888Smarcel
22096888Smarcel#ifdef CPU_ENABLE_SSE
22196888Smarcelstatic int
22296888Smarcellinux_proc_read_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs)
22396888Smarcel{
22496888Smarcel
225113868Sjhb	PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
226172207Sjeff	if (cpu_fxsr == 0 || (td->td_proc->p_flag & P_INMEM) == 0)
227113868Sjhb		return (EIO);
228208833Skib	bcopy(&td->td_pcb->pcb_user_save.sv_xmm, fpxregs, sizeof(*fpxregs));
229113868Sjhb	return (0);
23096888Smarcel}
23196888Smarcel
23296888Smarcelstatic int
23396888Smarcellinux_proc_write_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs)
23496888Smarcel{
23596888Smarcel
236113868Sjhb	PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
237172207Sjeff	if (cpu_fxsr == 0 || (td->td_proc->p_flag & P_INMEM) == 0)
238113868Sjhb		return (EIO);
239208833Skib	bcopy(fpxregs, &td->td_pcb->pcb_user_save.sv_xmm, sizeof(*fpxregs));
240113868Sjhb	return (0);
24196888Smarcel}
24296888Smarcel#endif
24396888Smarcel
24496888Smarcelint
24596888Smarcellinux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
24696888Smarcel{
24796888Smarcel	union {
24896888Smarcel		struct linux_pt_reg	reg;
24996888Smarcel		struct linux_pt_fpreg	fpreg;
25096888Smarcel		struct linux_pt_fpxreg	fpxreg;
25196888Smarcel	} r;
252102946Siedowse	union {
253102946Siedowse		struct reg		bsd_reg;
254102946Siedowse		struct fpreg		bsd_fpreg;
255102946Siedowse		struct dbreg		bsd_dbreg;
256102946Siedowse	} u;
257102946Siedowse	void *addr;
258102946Siedowse	pid_t pid;
259102946Siedowse	int error, req;
26096888Smarcel
26196888Smarcel	error = 0;
26296888Smarcel
26396888Smarcel	/* by default, just copy data intact */
264102946Siedowse	req  = uap->req;
265102946Siedowse	pid  = (pid_t)uap->pid;
266102946Siedowse	addr = (void *)uap->addr;
26796888Smarcel
268102946Siedowse	switch (req) {
26996888Smarcel	case PTRACE_TRACEME:
27096888Smarcel	case PTRACE_POKETEXT:
27196888Smarcel	case PTRACE_POKEDATA:
27296888Smarcel	case PTRACE_KILL:
273102946Siedowse		error = kern_ptrace(td, req, pid, addr, uap->data);
27496888Smarcel		break;
27596888Smarcel	case PTRACE_PEEKTEXT:
27696888Smarcel	case PTRACE_PEEKDATA: {
27796888Smarcel		/* need to preserve return value */
27896888Smarcel		int rval = td->td_retval[0];
279102946Siedowse		error = kern_ptrace(td, req, pid, addr, 0);
28096888Smarcel		if (error == 0)
281111797Sdes			error = copyout(td->td_retval, (void *)uap->data,
282102946Siedowse			    sizeof(l_int));
28396888Smarcel		td->td_retval[0] = rval;
28496888Smarcel		break;
28596888Smarcel	}
28696888Smarcel	case PTRACE_DETACH:
287102946Siedowse		error = kern_ptrace(td, PT_DETACH, pid, (void *)1,
288102946Siedowse		     map_signum(uap->data));
289102946Siedowse		break;
29096888Smarcel	case PTRACE_SINGLESTEP:
29196888Smarcel	case PTRACE_CONT:
292102946Siedowse		error = kern_ptrace(td, req, pid, (void *)1,
293102946Siedowse		     map_signum(uap->data));
29496888Smarcel		break;
29596888Smarcel	case PTRACE_ATTACH:
296102946Siedowse		error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
29796888Smarcel		break;
298102946Siedowse	case PTRACE_GETREGS:
29996888Smarcel		/* Linux is using data where FreeBSD is using addr */
300102946Siedowse		error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0);
30196888Smarcel		if (error == 0) {
302102946Siedowse			map_regs_to_linux(&u.bsd_reg, &r.reg);
303111797Sdes			error = copyout(&r.reg, (void *)uap->data,
30496888Smarcel			    sizeof(r.reg));
30596888Smarcel		}
30696888Smarcel		break;
307102946Siedowse	case PTRACE_SETREGS:
30896888Smarcel		/* Linux is using data where FreeBSD is using addr */
309111797Sdes		error = copyin((void *)uap->data, &r.reg, sizeof(r.reg));
31096888Smarcel		if (error == 0) {
311102946Siedowse			map_regs_from_linux(&u.bsd_reg, &r.reg);
312102946Siedowse			error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0);
31396888Smarcel		}
31496888Smarcel		break;
315102946Siedowse	case PTRACE_GETFPREGS:
31696888Smarcel		/* Linux is using data where FreeBSD is using addr */
317102946Siedowse		error = kern_ptrace(td, PT_GETFPREGS, pid, &u.bsd_fpreg, 0);
31896888Smarcel		if (error == 0) {
319102946Siedowse			map_fpregs_to_linux(&u.bsd_fpreg, &r.fpreg);
320111797Sdes			error = copyout(&r.fpreg, (void *)uap->data,
32196888Smarcel			    sizeof(r.fpreg));
32296888Smarcel		}
32396888Smarcel		break;
324102946Siedowse	case PTRACE_SETFPREGS:
32596888Smarcel		/* Linux is using data where FreeBSD is using addr */
326111797Sdes		error = copyin((void *)uap->data, &r.fpreg, sizeof(r.fpreg));
32796888Smarcel		if (error == 0) {
328102946Siedowse			map_fpregs_from_linux(&u.bsd_fpreg, &r.fpreg);
329102946Siedowse			error = kern_ptrace(td, PT_SETFPREGS, pid,
330102946Siedowse			    &u.bsd_fpreg, 0);
33196888Smarcel		}
33296888Smarcel		break;
33396888Smarcel	case PTRACE_SETFPXREGS:
334103064Speter#ifdef CPU_ENABLE_SSE
335111797Sdes		error = copyin((void *)uap->data, &r.fpxreg, sizeof(r.fpxreg));
33696955Smarcel		if (error)
33796955Smarcel			break;
33896955Smarcel#endif
33996955Smarcel		/* FALL THROUGH */
340111798Sdes	case PTRACE_GETFPXREGS: {
34196888Smarcel#ifdef CPU_ENABLE_SSE
34296888Smarcel		struct proc *p;
34396888Smarcel		struct thread *td2;
34496888Smarcel
34596888Smarcel		if (sizeof(struct linux_pt_fpxreg) != sizeof(struct savexmm)) {
34696888Smarcel			static int once = 0;
34796888Smarcel			if (!once) {
34896888Smarcel				printf("linux: savexmm != linux_pt_fpxreg\n");
34996888Smarcel				once = 1;
35096888Smarcel			}
35196888Smarcel			error = EIO;
35296888Smarcel			break;
35396888Smarcel		}
35496888Smarcel
35596888Smarcel		if ((p = pfind(uap->pid)) == NULL) {
35696888Smarcel			error = ESRCH;
35796888Smarcel			break;
35896888Smarcel		}
35996888Smarcel
360155922Sjhb		/* Exiting processes can't be debugged. */
361155922Sjhb		if ((p->p_flag & P_WEXIT) != 0) {
362155922Sjhb			error = ESRCH;
363155922Sjhb			goto fail;
364155922Sjhb		}
365155922Sjhb
36696955Smarcel		if ((error = p_candebug(td, p)) != 0)
36796955Smarcel			goto fail;
36896955Smarcel
36996955Smarcel		/* System processes can't be debugged. */
37096955Smarcel		if ((p->p_flag & P_SYSTEM) != 0) {
37196955Smarcel			error = EINVAL;
37296955Smarcel			goto fail;
37396955Smarcel		}
37496955Smarcel
37596955Smarcel		/* not being traced... */
37696955Smarcel		if ((p->p_flag & P_TRACED) == 0) {
37796955Smarcel			error = EPERM;
37896955Smarcel			goto fail;
37996955Smarcel		}
38096955Smarcel
38196955Smarcel		/* not being traced by YOU */
38296955Smarcel		if (p->p_pptr != td->td_proc) {
38396955Smarcel			error = EBUSY;
38496955Smarcel			goto fail;
38596955Smarcel		}
38696955Smarcel
38796955Smarcel		/* not currently stopped */
388113517Sjhb		if (!P_SHOULDSTOP(p) || (p->p_flag & P_WAITED) == 0) {
38996955Smarcel			error = EBUSY;
39096955Smarcel			goto fail;
39196955Smarcel		}
39296955Smarcel
393102946Siedowse		if (req == PTRACE_GETFPXREGS) {
394136003Sdas			_PHOLD(p);	/* may block */
395136003Sdas			td2 = FIRST_THREAD_IN_PROC(p);
39696888Smarcel			error = linux_proc_read_fpxregs(td2, &r.fpxreg);
39796888Smarcel			_PRELE(p);
39896888Smarcel			PROC_UNLOCK(p);
39996888Smarcel			if (error == 0)
400111797Sdes				error = copyout(&r.fpxreg, (void *)uap->data,
40196888Smarcel				    sizeof(r.fpxreg));
40296888Smarcel		} else {
40396955Smarcel			/* clear dangerous bits exactly as Linux does*/
40496955Smarcel			r.fpxreg.mxcsr &= 0xffbf;
405136003Sdas			_PHOLD(p);	/* may block */
406136003Sdas			td2 = FIRST_THREAD_IN_PROC(p);
40796955Smarcel			error = linux_proc_write_fpxregs(td2, &r.fpxreg);
40896955Smarcel			_PRELE(p);
40996955Smarcel			PROC_UNLOCK(p);
41096888Smarcel		}
41196955Smarcel		break;
41296955Smarcel
41396955Smarcel	fail:
41496955Smarcel		PROC_UNLOCK(p);
41596888Smarcel#else
41696888Smarcel		error = EIO;
41796888Smarcel#endif
41896888Smarcel		break;
41996888Smarcel	}
42096888Smarcel	case PTRACE_PEEKUSR:
42196888Smarcel	case PTRACE_POKEUSR: {
42296888Smarcel		error = EIO;
42396888Smarcel
42496888Smarcel		/* check addr for alignment */
42596888Smarcel		if (uap->addr < 0 || uap->addr & (sizeof(l_int) - 1))
42696888Smarcel			break;
42796888Smarcel		/*
42896888Smarcel		 * Allow linux programs to access register values in
42996888Smarcel		 * user struct. We simulate this through PT_GET/SETREGS
43096888Smarcel		 * as necessary.
43196888Smarcel		 */
43296888Smarcel		if (uap->addr < sizeof(struct linux_pt_reg)) {
433102946Siedowse			error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0);
43496888Smarcel			if (error != 0)
43596888Smarcel				break;
43696888Smarcel
437102946Siedowse			map_regs_to_linux(&u.bsd_reg, &r.reg);
438102946Siedowse			if (req == PTRACE_PEEKUSR) {
43996888Smarcel				error = copyout((char *)&r.reg + uap->addr,
440111797Sdes				    (void *)uap->data, sizeof(l_int));
44196888Smarcel				break;
44296888Smarcel			}
44396888Smarcel
44496888Smarcel			*(l_int *)((char *)&r.reg + uap->addr) =
44596888Smarcel			    (l_int)uap->data;
44696888Smarcel
447102946Siedowse			map_regs_from_linux(&u.bsd_reg, &r.reg);
448102946Siedowse			error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0);
44996888Smarcel		}
450111798Sdes
45196888Smarcel		/*
45296888Smarcel		 * Simulate debug registers access
45396888Smarcel		 */
45496888Smarcel		if (uap->addr >= LINUX_DBREG_OFFSET &&
45596888Smarcel		    uap->addr <= LINUX_DBREG_OFFSET + LINUX_DBREG_SIZE) {
456102946Siedowse			error = kern_ptrace(td, PT_GETDBREGS, pid, &u.bsd_dbreg,
457102946Siedowse			    0);
45896888Smarcel			if (error != 0)
45996888Smarcel				break;
460111798Sdes
46196888Smarcel			uap->addr -= LINUX_DBREG_OFFSET;
462102946Siedowse			if (req == PTRACE_PEEKUSR) {
463102946Siedowse				error = copyout((char *)&u.bsd_dbreg +
464111797Sdes				    uap->addr, (void *)uap->data,
465102946Siedowse				    sizeof(l_int));
46696888Smarcel				break;
46796888Smarcel			}
46896888Smarcel
469102946Siedowse			*(l_int *)((char *)&u.bsd_dbreg + uap->addr) =
470102946Siedowse			     uap->data;
471102946Siedowse			error = kern_ptrace(td, PT_SETDBREGS, pid,
472102946Siedowse			    &u.bsd_dbreg, 0);
47396888Smarcel		}
47496888Smarcel
47596888Smarcel		break;
47696888Smarcel	}
47796888Smarcel	case PTRACE_SYSCALL:
47896888Smarcel		/* fall through */
47996888Smarcel	default:
48096888Smarcel		printf("linux: ptrace(%u, ...) not implemented\n",
48196888Smarcel		    (unsigned int)uap->req);
48296888Smarcel		error = EINVAL;
48396888Smarcel		break;
48496888Smarcel	}
48596888Smarcel
48696888Smarcel	return (error);
48796888Smarcel}
488