| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /* |
| 2 | * Copyright (c) 2001 Alexander Kabaev | |
| 3 | * All rights reserved. | |
| 4 | * | |
| 5 | * Redistribution and use in source and binary forms, with or without | |
| 6 | * modification, are permitted provided that the following conditions | |
| 7 | * are met: | |
| 8 | * 1. Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer | |
| 10 | * in this position and unchanged. | |
| 11 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 12 | * notice, this list of conditions and the following disclaimer in the | |
| 13 | * documentation and/or other materials provided with the distribution. | |
| 14 | * 3. The name of the author may not be used to endorse or promote products | |
| 15 | * derived from this software without specific prior written permission. | |
| 16 | * | |
| 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
| 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
| 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
| 20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
| 22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
| 26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 27 | * | |
| 28 | * $FreeBSD: src/sys/i386/linux/linux_ptrace.c,v 1.7.4.3 2003/01/03 17:13:23 kan Exp $ | |
| c7e98b2f | 29 | * $DragonFly: src/sys/emulation/linux/i386/linux_ptrace.c,v 1.15 2007/02/19 01:14:23 corecode Exp $ |
| 984263bc MD |
30 | */ |
| 31 | ||
| 32 | #include "opt_cpu.h" | |
| 33 | ||
| 34 | #include <sys/param.h> | |
| 35 | #include <sys/lock.h> | |
| 36 | #include <sys/proc.h> | |
| 37 | #include <sys/ptrace.h> | |
| 38 | #include <sys/systm.h> | |
| 39 | ||
| 40 | #include <vm/vm.h> | |
| 41 | #include <vm/pmap.h> | |
| 42 | #include <vm/vm_map.h> | |
| 43 | #include <sys/user.h> | |
| 527fddf7 | 44 | #include <sys/reg.h> |
| 984263bc MD |
45 | |
| 46 | #include <machine/md_var.h> | |
| 47 | #include <machine/pcb.h> | |
| 984263bc | 48 | |
| 1f2de5d4 MD |
49 | #include "linux.h" |
| 50 | #include "linux_proto.h" | |
| 984263bc MD |
51 | |
| 52 | /* | |
| 53 | * Linux ptrace requests numbers. Mostly identical to FreeBSD, | |
| 54 | * except for MD ones and PT_ATTACH/PT_DETACH. | |
| 55 | */ | |
| 56 | #define PTRACE_TRACEME 0 | |
| 57 | #define PTRACE_PEEKTEXT 1 | |
| 58 | #define PTRACE_PEEKDATA 2 | |
| 59 | #define PTRACE_PEEKUSR 3 | |
| 60 | #define PTRACE_POKETEXT 4 | |
| 61 | #define PTRACE_POKEDATA 5 | |
| 62 | #define PTRACE_POKEUSR 6 | |
| 63 | #define PTRACE_CONT 7 | |
| 64 | #define PTRACE_KILL 8 | |
| 65 | #define PTRACE_SINGLESTEP 9 | |
| 66 | ||
| 67 | #define PTRACE_ATTACH 16 | |
| 68 | #define PTRACE_DETACH 17 | |
| 69 | ||
| 70 | #define PTRACE_SYSCALL 24 | |
| 71 | ||
| 72 | #define PTRACE_GETREGS 12 | |
| 73 | #define PTRACE_SETREGS 13 | |
| 74 | #define PTRACE_GETFPREGS 14 | |
| 75 | #define PTRACE_SETFPREGS 15 | |
| 76 | #define PTRACE_GETFPXREGS 18 | |
| 77 | #define PTRACE_SETFPXREGS 19 | |
| 78 | ||
| 79 | #define PTRACE_SETOPTIONS 21 | |
| 80 | ||
| 81 | /* | |
| 82 | * Linux keeps debug registers at the following | |
| 83 | * offset in the user struct | |
| 84 | */ | |
| 85 | #define LINUX_DBREG_OFFSET 252 | |
| 86 | #define LINUX_DBREG_SIZE (8*sizeof(l_int)) | |
| 87 | ||
| 88 | static __inline__ int | |
| 89 | map_signum(int signum) | |
| 90 | { | |
| 91 | ||
| 92 | if (signum > 0 && signum <= LINUX_SIGTBLSZ) | |
| 93 | signum = linux_to_bsd_signal[_SIG_IDX(signum)]; | |
| 94 | return ((signum == SIGSTOP)? 0 : signum); | |
| 95 | } | |
| 96 | ||
| 97 | struct linux_pt_reg { | |
| 98 | l_long ebx; | |
| 99 | l_long ecx; | |
| 100 | l_long edx; | |
| 101 | l_long esi; | |
| 102 | l_long edi; | |
| 103 | l_long ebp; | |
| 104 | l_long eax; | |
| 105 | l_int xds; | |
| 106 | l_int xes; | |
| 107 | l_int xfs; | |
| 108 | l_int xgs; | |
| 109 | l_long orig_eax; | |
| 110 | l_long eip; | |
| 111 | l_int xcs; | |
| 112 | l_long eflags; | |
| 113 | l_long esp; | |
| 114 | l_int xss; | |
| 115 | }; | |
| 116 | ||
| 117 | /* | |
| 118 | * Translate i386 ptrace registers between Linux and FreeBSD formats. | |
| 119 | * The translation is pretty straighforward, for all registers, but | |
| 120 | * orig_eax on Linux side and r_trapno and r_err in FreeBSD | |
| 121 | */ | |
| 122 | static void | |
| 123 | map_regs_to_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r) | |
| 124 | { | |
| 125 | linux_r->ebx = bsd_r->r_ebx; | |
| 126 | linux_r->ecx = bsd_r->r_ecx; | |
| 127 | linux_r->edx = bsd_r->r_edx; | |
| 128 | linux_r->esi = bsd_r->r_esi; | |
| 129 | linux_r->edi = bsd_r->r_edi; | |
| 130 | linux_r->ebp = bsd_r->r_ebp; | |
| 131 | linux_r->eax = bsd_r->r_eax; | |
| 132 | linux_r->xds = bsd_r->r_ds; | |
| 133 | linux_r->xes = bsd_r->r_es; | |
| 134 | linux_r->xfs = bsd_r->r_fs; | |
| 135 | linux_r->xgs = bsd_r->r_gs; | |
| 136 | linux_r->orig_eax = bsd_r->r_eax; | |
| 137 | linux_r->eip = bsd_r->r_eip; | |
| 138 | linux_r->xcs = bsd_r->r_cs; | |
| 139 | linux_r->eflags = bsd_r->r_eflags; | |
| 140 | linux_r->esp = bsd_r->r_esp; | |
| 141 | linux_r->xss = bsd_r->r_ss; | |
| 142 | } | |
| 143 | ||
| 144 | static void | |
| 145 | map_regs_from_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r) | |
| 146 | { | |
| 147 | bsd_r->r_ebx = linux_r->ebx; | |
| 148 | bsd_r->r_ecx = linux_r->ecx; | |
| 149 | bsd_r->r_edx = linux_r->edx; | |
| 150 | bsd_r->r_esi = linux_r->esi; | |
| 151 | bsd_r->r_edi = linux_r->edi; | |
| 152 | bsd_r->r_ebp = linux_r->ebp; | |
| 153 | bsd_r->r_eax = linux_r->eax; | |
| 154 | bsd_r->r_ds = linux_r->xds; | |
| 155 | bsd_r->r_es = linux_r->xes; | |
| 156 | bsd_r->r_fs = linux_r->xfs; | |
| 157 | bsd_r->r_gs = linux_r->xgs; | |
| 158 | bsd_r->r_eip = linux_r->eip; | |
| 159 | bsd_r->r_cs = linux_r->xcs; | |
| 160 | bsd_r->r_eflags = linux_r->eflags; | |
| 161 | bsd_r->r_esp = linux_r->esp; | |
| 162 | bsd_r->r_ss = linux_r->xss; | |
| 163 | } | |
| 164 | ||
| 165 | struct linux_pt_fpreg { | |
| 166 | l_long cwd; | |
| 167 | l_long swd; | |
| 168 | l_long twd; | |
| 169 | l_long fip; | |
| 170 | l_long fcs; | |
| 171 | l_long foo; | |
| 172 | l_long fos; | |
| 173 | l_long st_space[2*10]; | |
| 174 | }; | |
| 175 | ||
| 176 | static void | |
| 177 | map_fpregs_to_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r) | |
| 178 | { | |
| 179 | linux_r->cwd = bsd_r->fpr_env[0]; | |
| 180 | linux_r->swd = bsd_r->fpr_env[1]; | |
| 181 | linux_r->twd = bsd_r->fpr_env[2]; | |
| 182 | linux_r->fip = bsd_r->fpr_env[3]; | |
| 183 | linux_r->fcs = bsd_r->fpr_env[4]; | |
| 184 | linux_r->foo = bsd_r->fpr_env[5]; | |
| 185 | linux_r->fos = bsd_r->fpr_env[6]; | |
| 186 | bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(linux_r->st_space)); | |
| 187 | } | |
| 188 | ||
| 189 | static void | |
| 190 | map_fpregs_from_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r) | |
| 191 | { | |
| 192 | bsd_r->fpr_env[0] = linux_r->cwd; | |
| 193 | bsd_r->fpr_env[1] = linux_r->swd; | |
| 194 | bsd_r->fpr_env[2] = linux_r->twd; | |
| 195 | bsd_r->fpr_env[3] = linux_r->fip; | |
| 196 | bsd_r->fpr_env[4] = linux_r->fcs; | |
| 197 | bsd_r->fpr_env[5] = linux_r->foo; | |
| 198 | bsd_r->fpr_env[6] = linux_r->fos; | |
| 199 | bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(bsd_r->fpr_acc)); | |
| 200 | } | |
| 201 | ||
| 202 | struct linux_pt_fpxreg { | |
| 203 | l_ushort cwd; | |
| 204 | l_ushort swd; | |
| 205 | l_ushort twd; | |
| 206 | l_ushort fop; | |
| 207 | l_long fip; | |
| 208 | l_long fcs; | |
| 209 | l_long foo; | |
| 210 | l_long fos; | |
| 211 | l_long mxcsr; | |
| 212 | l_long reserved; | |
| 213 | l_long st_space[32]; | |
| 214 | l_long xmm_space[32]; | |
| 215 | l_long padding[56]; | |
| 216 | }; | |
| 217 | ||
| 642a6e88 | 218 | #ifndef CPU_DISABLE_SSE |
| 984263bc | 219 | static int |
| c7e98b2f | 220 | linux_proc_read_fpxregs(struct lwp *lp, struct linux_pt_fpxreg *fpxregs) |
| 984263bc MD |
221 | { |
| 222 | int error; | |
| 223 | ||
| 224 | error = 0; | |
| bb3cd951 | 225 | if (cpu_fxsr == 0) |
| 984263bc MD |
226 | error = EIO; |
| 227 | else | |
| 08f2f1bb | 228 | bcopy(&lp->lwp_thread->td_pcb->pcb_save.sv_xmm, |
| 984263bc MD |
229 | fpxregs, sizeof(*fpxregs)); |
| 230 | return (error); | |
| 231 | } | |
| 232 | ||
| 233 | static int | |
| c7e98b2f | 234 | linux_proc_write_fpxregs(struct lwp *lp, struct linux_pt_fpxreg *fpxregs) |
| 984263bc MD |
235 | { |
| 236 | int error; | |
| 237 | ||
| 238 | error = 0; | |
| bb3cd951 | 239 | if (cpu_fxsr == 0) |
| 984263bc MD |
240 | error = EIO; |
| 241 | else | |
| 08f2f1bb | 242 | bcopy(fpxregs, &lp->lwp_thread->td_pcb->pcb_save.sv_xmm, |
| 984263bc MD |
243 | sizeof(*fpxregs)); |
| 244 | return (error); | |
| 245 | } | |
| 246 | #endif | |
| 247 | ||
| 3919ced0 MD |
248 | /* |
| 249 | * MPALMOSTSAFE | |
| 250 | */ | |
| 984263bc | 251 | int |
| 753fd850 | 252 | sys_linux_ptrace(struct linux_ptrace_args *uap) |
| 984263bc | 253 | { |
| bb3cd951 SS |
254 | struct thread *td = curthread; |
| 255 | struct proc *curp = td->td_proc; | |
| 984263bc MD |
256 | union { |
| 257 | struct linux_pt_reg reg; | |
| 258 | struct linux_pt_fpreg fpreg; | |
| 259 | struct linux_pt_fpxreg fpxreg; | |
| 260 | } r; | |
| 261 | union { | |
| 262 | struct reg bsd_reg; | |
| 263 | struct fpreg bsd_fpreg; | |
| 264 | struct dbreg bsd_dbreg; | |
| 265 | } u; | |
| 266 | void *addr; | |
| 267 | pid_t pid; | |
| 268 | int error, req; | |
| 58c2553a | 269 | struct proc *p = NULL; /* held process */ |
| 984263bc MD |
270 | |
| 271 | error = 0; | |
| 272 | ||
| 273 | /* by default, just copy data intact */ | |
| 274 | req = uap->req; | |
| 275 | pid = (pid_t)uap->pid; | |
| 276 | addr = (void *)uap->addr; | |
| 277 | ||
| 278 | switch (req) { | |
| 279 | case PTRACE_TRACEME: | |
| 280 | case PTRACE_POKETEXT: | |
| 281 | case PTRACE_POKEDATA: | |
| 282 | case PTRACE_KILL: | |
| 90b9818c | 283 | error = kern_ptrace(curp, req, pid, addr, uap->data, |
| e54488bb | 284 | &uap->sysmsg_iresult); |
| 984263bc MD |
285 | break; |
| 286 | case PTRACE_PEEKTEXT: | |
| 287 | case PTRACE_PEEKDATA: { | |
| 90b9818c MD |
288 | /* need to preserve return value, use dummy */ |
| 289 | l_int rval = 0; | |
| 290 | error = kern_ptrace(curp, req, pid, addr, 0, &rval); | |
| 291 | if (error == 0) { | |
| 292 | error = copyout(&rval, (caddr_t)uap->data, sizeof(l_int)); | |
| 293 | } | |
| 984263bc MD |
294 | break; |
| 295 | } | |
| 296 | case PTRACE_DETACH: | |
| 297 | error = kern_ptrace(curp, PT_DETACH, pid, (void *)1, | |
| e54488bb MD |
298 | map_signum(uap->data), |
| 299 | &uap->sysmsg_iresult); | |
| 984263bc MD |
300 | break; |
| 301 | case PTRACE_SINGLESTEP: | |
| 302 | case PTRACE_CONT: | |
| 303 | error = kern_ptrace(curp, req, pid, (void *)1, | |
| e54488bb MD |
304 | map_signum(uap->data), |
| 305 | &uap->sysmsg_iresult); | |
| 984263bc MD |
306 | break; |
| 307 | case PTRACE_ATTACH: | |
| 90b9818c | 308 | error = kern_ptrace(curp, PT_ATTACH, pid, addr, uap->data, |
| e54488bb | 309 | &uap->sysmsg_iresult); |
| 984263bc MD |
310 | break; |
| 311 | case PTRACE_GETREGS: | |
| 312 | /* Linux is using data where FreeBSD is using addr */ | |
| 90b9818c | 313 | error = kern_ptrace(curp, PT_GETREGS, pid, &u.bsd_reg, 0, |
| e54488bb | 314 | &uap->sysmsg_iresult); |
| 984263bc MD |
315 | if (error == 0) { |
| 316 | map_regs_to_linux(&u.bsd_reg, &r.reg); | |
| d557216f MD |
317 | error = copyout(&r.reg, (void *)uap->data, |
| 318 | sizeof(r.reg)); | |
| 984263bc MD |
319 | } |
| 320 | break; | |
| 321 | case PTRACE_SETREGS: | |
| 322 | /* Linux is using data where FreeBSD is using addr */ | |
| 323 | error = copyin((caddr_t)uap->data, &r.reg, sizeof(r.reg)); | |
| 324 | if (error == 0) { | |
| 325 | map_regs_from_linux(&u.bsd_reg, &r.reg); | |
| e54488bb MD |
326 | error = kern_ptrace(curp, PT_SETREGS, pid, &u.bsd_reg, |
| 327 | 0, &uap->sysmsg_iresult); | |
| 984263bc MD |
328 | } |
| 329 | break; | |
| 330 | case PTRACE_GETFPREGS: | |
| 331 | /* Linux is using data where FreeBSD is using addr */ | |
| e54488bb MD |
332 | error = kern_ptrace(curp, PT_GETFPREGS, pid, &u.bsd_fpreg, |
| 333 | 0, &uap->sysmsg_iresult); | |
| 984263bc MD |
334 | if (error == 0) { |
| 335 | map_fpregs_to_linux(&u.bsd_fpreg, &r.fpreg); | |
| 336 | error = copyout(&r.fpreg, (caddr_t)uap->data, | |
| 337 | sizeof(r.fpreg)); | |
| 338 | } | |
| 339 | break; | |
| 340 | case PTRACE_SETFPREGS: | |
| 341 | /* Linux is using data where FreeBSD is using addr */ | |
| 342 | error = copyin((caddr_t)uap->data, &r.fpreg, sizeof(r.fpreg)); | |
| 343 | if (error == 0) { | |
| 344 | map_fpregs_from_linux(&u.bsd_fpreg, &r.fpreg); | |
| 345 | error = kern_ptrace(curp, PT_SETFPREGS, pid, | |
| e54488bb MD |
346 | &u.bsd_fpreg, |
| 347 | 0, &uap->sysmsg_iresult); | |
| 984263bc MD |
348 | } |
| 349 | break; | |
| 350 | case PTRACE_SETFPXREGS: | |
| 642a6e88 | 351 | #ifndef CPU_DISABLE_SSE |
| 984263bc MD |
352 | error = copyin((caddr_t)uap->data, &r.fpxreg, |
| 353 | sizeof(r.fpxreg)); | |
| 354 | if (error) | |
| 355 | break; | |
| 356 | #endif | |
| 357 | /* FALL THROUGH */ | |
| 358 | case PTRACE_GETFPXREGS: { | |
| 642a6e88 | 359 | #ifndef CPU_DISABLE_SSE |
| 984263bc | 360 | struct proc *p; |
| c7e98b2f | 361 | struct lwp *lp; |
| 984263bc MD |
362 | |
| 363 | if (sizeof(struct linux_pt_fpxreg) != sizeof(struct savexmm)) { | |
| 364 | static int once = 0; | |
| 365 | if (!once) { | |
| 26be20a0 | 366 | kprintf("linux: savexmm != linux_pt_fpxreg\n"); |
| 984263bc MD |
367 | once = 1; |
| 368 | } | |
| 369 | error = EIO; | |
| 370 | break; | |
| 371 | } | |
| 372 | ||
| 373 | if ((p = pfind(uap->pid)) == NULL) { | |
| 374 | error = ESRCH; | |
| 375 | break; | |
| 376 | } | |
| 377 | ||
| 41c20dac | 378 | if (!PRISON_CHECK(curp->p_ucred, p->p_ucred)) { |
| 984263bc MD |
379 | error = ESRCH; |
| 380 | goto fail; | |
| 381 | } | |
| 382 | ||
| 383 | /* System processes can't be debugged. */ | |
| 4643740a | 384 | if ((p->p_flags & P_SYSTEM) != 0) { |
| 984263bc MD |
385 | error = EINVAL; |
| 386 | goto fail; | |
| 387 | } | |
| 388 | ||
| 389 | /* not being traced... */ | |
| 4643740a | 390 | if ((p->p_flags & P_TRACED) == 0) { |
| 984263bc MD |
391 | error = EPERM; |
| 392 | goto fail; | |
| 393 | } | |
| 394 | ||
| 395 | /* not being traced by YOU */ | |
| 396 | if (p->p_pptr != curp) { | |
| 397 | error = EBUSY; | |
| 398 | goto fail; | |
| 399 | } | |
| 400 | ||
| 401 | /* not currently stopped */ | |
| 4643740a | 402 | if ((p->p_flags & (P_TRACED|P_WAITED)) == 0) { |
| 984263bc MD |
403 | error = EBUSY; |
| 404 | goto fail; | |
| 405 | } | |
| 406 | ||
| c7e98b2f SS |
407 | /* XXX lwp */ |
| 408 | lp = FIRST_LWP_IN_PROC(p); | |
| 409 | ||
| 984263bc | 410 | if (req == PTRACE_GETFPXREGS) { |
| c7e98b2f SS |
411 | LWPHOLD(lp); |
| 412 | error = linux_proc_read_fpxregs(lp, &r.fpxreg); | |
| 413 | LWPRELE(lp); | |
| 984263bc MD |
414 | if (error == 0) |
| 415 | error = copyout(&r.fpxreg, (caddr_t)uap->data, | |
| 416 | sizeof(r.fpxreg)); | |
| 417 | } else { | |
| 418 | /* clear dangerous bits exactly as Linux does*/ | |
| 419 | r.fpxreg.mxcsr &= 0xffbf; | |
| c7e98b2f SS |
420 | LWPHOLD(lp); |
| 421 | error = linux_proc_write_fpxregs(lp, &r.fpxreg); | |
| 422 | LWPRELE(lp); | |
| 984263bc MD |
423 | } |
| 424 | break; | |
| 425 | ||
| 426 | fail: | |
| 427 | #else | |
| 428 | error = EIO; | |
| 429 | #endif | |
| 430 | break; | |
| 431 | } | |
| 432 | case PTRACE_PEEKUSR: | |
| 433 | case PTRACE_POKEUSR: { | |
| 434 | error = EIO; | |
| 435 | ||
| 436 | /* check addr for alignment */ | |
| 437 | if (uap->addr < 0 || uap->addr & (sizeof(l_int) - 1)) | |
| 438 | break; | |
| 439 | /* | |
| 440 | * Allow linux programs to access register values in | |
| 441 | * user struct. We simulate this through PT_GET/SETREGS | |
| 442 | * as necessary. | |
| 443 | */ | |
| 444 | if (uap->addr < sizeof(struct linux_pt_reg)) { | |
| e54488bb MD |
445 | error = kern_ptrace(curp, PT_GETREGS, pid, &u.bsd_reg, |
| 446 | 0, &uap->sysmsg_iresult); | |
| 984263bc MD |
447 | if (error != 0) |
| 448 | break; | |
| 449 | ||
| 450 | map_regs_to_linux(&u.bsd_reg, &r.reg); | |
| 451 | if (req == PTRACE_PEEKUSR) { | |
| 452 | error = copyout((char *)&r.reg + uap->addr, | |
| 453 | (caddr_t)uap->data, sizeof(l_int)); | |
| 454 | break; | |
| 455 | } | |
| 456 | ||
| 457 | *(l_int *)((char *)&r.reg + uap->addr) = | |
| 458 | (l_int)uap->data; | |
| 459 | ||
| 460 | map_regs_from_linux(&u.bsd_reg, &r.reg); | |
| e54488bb MD |
461 | error = kern_ptrace(curp, PT_SETREGS, pid, &u.bsd_reg, |
| 462 | 0, &uap->sysmsg_iresult); | |
| 984263bc MD |
463 | } |
| 464 | ||
| 465 | /* | |
| 466 | * Simulate debug registers access | |
| 467 | */ | |
| 468 | if (uap->addr >= LINUX_DBREG_OFFSET && | |
| 469 | uap->addr <= LINUX_DBREG_OFFSET + LINUX_DBREG_SIZE) { | |
| 90b9818c | 470 | error = kern_ptrace(curp, PT_GETDBREGS, pid, |
| e54488bb MD |
471 | &u.bsd_dbreg, |
| 472 | 0, &uap->sysmsg_iresult); | |
| 984263bc MD |
473 | if (error != 0) |
| 474 | break; | |
| 475 | ||
| 476 | uap->addr -= LINUX_DBREG_OFFSET; | |
| 477 | if (req == PTRACE_PEEKUSR) { | |
| 478 | error = copyout((char *)&u.bsd_dbreg + | |
| 479 | uap->addr, (caddr_t)uap->data, | |
| 480 | sizeof(l_int)); | |
| 481 | break; | |
| 482 | } | |
| 483 | ||
| 484 | *(l_int *)((char *)&u.bsd_dbreg + uap->addr) = | |
| 485 | uap->data; | |
| 486 | error = kern_ptrace(curp, PT_SETDBREGS, pid, | |
| e54488bb MD |
487 | &u.bsd_dbreg, |
| 488 | 0, &uap->sysmsg_iresult); | |
| 984263bc MD |
489 | } |
| 490 | ||
| 491 | break; | |
| 492 | } | |
| 493 | case PTRACE_SYSCALL: | |
| 494 | /* fall through */ | |
| 495 | default: | |
| 26be20a0 | 496 | kprintf("linux: ptrace(%u, ...) not implemented\n", |
| 984263bc MD |
497 | (unsigned int)uap->req); |
| 498 | error = EINVAL; | |
| 499 | break; | |
| 500 | } | |
| 501 | ||
| 58c2553a MD |
502 | /* |
| 503 | * Release held proces (if any) before returning. | |
| 504 | */ | |
| 505 | if (p) | |
| 506 | PRELE(p); | |
| 984263bc MD |
507 | return (error); |
| 508 | } |