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