14dfd6122SEdward Tomasz Napierala /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 34dfd6122SEdward Tomasz Napierala * 44dfd6122SEdward Tomasz Napierala * Copyright (c) 2001 Alexander Kabaev 54dfd6122SEdward Tomasz Napierala * All rights reserved. 64dfd6122SEdward Tomasz Napierala * 74dfd6122SEdward Tomasz Napierala * Redistribution and use in source and binary forms, with or without 84dfd6122SEdward Tomasz Napierala * modification, are permitted provided that the following conditions 94dfd6122SEdward Tomasz Napierala * are met: 104dfd6122SEdward Tomasz Napierala * 1. Redistributions of source code must retain the above copyright 114dfd6122SEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer. 124dfd6122SEdward Tomasz Napierala * 2. Redistributions in binary form must reproduce the above copyright 134dfd6122SEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer in the 144dfd6122SEdward Tomasz Napierala * documentation and/or other materials provided with the distribution. 154dfd6122SEdward Tomasz Napierala * 164dfd6122SEdward Tomasz Napierala * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 174dfd6122SEdward Tomasz Napierala * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 184dfd6122SEdward Tomasz Napierala * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 194dfd6122SEdward Tomasz Napierala * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 204dfd6122SEdward Tomasz Napierala * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 214dfd6122SEdward Tomasz Napierala * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 224dfd6122SEdward Tomasz Napierala * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 234dfd6122SEdward Tomasz Napierala * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 244dfd6122SEdward Tomasz Napierala * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 254dfd6122SEdward Tomasz Napierala * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 264dfd6122SEdward Tomasz Napierala * SUCH DAMAGE. 274dfd6122SEdward Tomasz Napierala */ 284dfd6122SEdward Tomasz Napierala 294dfd6122SEdward Tomasz Napierala #include "opt_cpu.h" 304dfd6122SEdward Tomasz Napierala 314dfd6122SEdward Tomasz Napierala #include <sys/param.h> 32ce8e645aSDmitry Chagin #include <sys/systm.h> 334dfd6122SEdward Tomasz Napierala #include <sys/lock.h> 344dfd6122SEdward Tomasz Napierala #include <sys/mutex.h> 354dfd6122SEdward Tomasz Napierala #include <sys/proc.h> 364dfd6122SEdward Tomasz Napierala #include <sys/ptrace.h> 374dfd6122SEdward Tomasz Napierala #include <sys/syscallsubr.h> 384dfd6122SEdward Tomasz Napierala 394dfd6122SEdward Tomasz Napierala #include <machine/md_var.h> 404dfd6122SEdward Tomasz Napierala #include <machine/pcb.h> 414dfd6122SEdward Tomasz Napierala 424dfd6122SEdward Tomasz Napierala #include <i386/linux/linux.h> 434dfd6122SEdward Tomasz Napierala #include <i386/linux/linux_proto.h> 444dfd6122SEdward Tomasz Napierala #include <compat/linux/linux_signal.h> 454dfd6122SEdward Tomasz Napierala 464dfd6122SEdward Tomasz Napierala /* 474dfd6122SEdward Tomasz Napierala * Linux ptrace requests numbers. Mostly identical to FreeBSD, 484dfd6122SEdward Tomasz Napierala * except for MD ones and PT_ATTACH/PT_DETACH. 494dfd6122SEdward Tomasz Napierala */ 504dfd6122SEdward Tomasz Napierala #define PTRACE_TRACEME 0 514dfd6122SEdward Tomasz Napierala #define PTRACE_PEEKTEXT 1 524dfd6122SEdward Tomasz Napierala #define PTRACE_PEEKDATA 2 534dfd6122SEdward Tomasz Napierala #define PTRACE_PEEKUSR 3 544dfd6122SEdward Tomasz Napierala #define PTRACE_POKETEXT 4 554dfd6122SEdward Tomasz Napierala #define PTRACE_POKEDATA 5 564dfd6122SEdward Tomasz Napierala #define PTRACE_POKEUSR 6 574dfd6122SEdward Tomasz Napierala #define PTRACE_CONT 7 584dfd6122SEdward Tomasz Napierala #define PTRACE_KILL 8 594dfd6122SEdward Tomasz Napierala #define PTRACE_SINGLESTEP 9 604dfd6122SEdward Tomasz Napierala 614dfd6122SEdward Tomasz Napierala #define PTRACE_ATTACH 16 624dfd6122SEdward Tomasz Napierala #define PTRACE_DETACH 17 634dfd6122SEdward Tomasz Napierala 644dfd6122SEdward Tomasz Napierala #define LINUX_PTRACE_SYSCALL 24 654dfd6122SEdward Tomasz Napierala 664dfd6122SEdward Tomasz Napierala #define PTRACE_GETREGS 12 674dfd6122SEdward Tomasz Napierala #define PTRACE_SETREGS 13 684dfd6122SEdward Tomasz Napierala #define PTRACE_GETFPREGS 14 694dfd6122SEdward Tomasz Napierala #define PTRACE_SETFPREGS 15 704dfd6122SEdward Tomasz Napierala #define PTRACE_GETFPXREGS 18 714dfd6122SEdward Tomasz Napierala #define PTRACE_SETFPXREGS 19 724dfd6122SEdward Tomasz Napierala 734dfd6122SEdward Tomasz Napierala #define PTRACE_SETOPTIONS 21 744dfd6122SEdward Tomasz Napierala 754dfd6122SEdward Tomasz Napierala /* 764dfd6122SEdward Tomasz Napierala * Linux keeps debug registers at the following 774dfd6122SEdward Tomasz Napierala * offset in the user struct 784dfd6122SEdward Tomasz Napierala */ 794dfd6122SEdward Tomasz Napierala #define LINUX_DBREG_OFFSET 252 804dfd6122SEdward Tomasz Napierala #define LINUX_DBREG_SIZE (8*sizeof(l_int)) 814dfd6122SEdward Tomasz Napierala 824dfd6122SEdward Tomasz Napierala static __inline int 834dfd6122SEdward Tomasz Napierala map_signum(int signum) 844dfd6122SEdward Tomasz Napierala { 854dfd6122SEdward Tomasz Napierala 864dfd6122SEdward Tomasz Napierala signum = linux_to_bsd_signal(signum); 874dfd6122SEdward Tomasz Napierala return ((signum == SIGSTOP)? 0 : signum); 884dfd6122SEdward Tomasz Napierala } 894dfd6122SEdward Tomasz Napierala 904dfd6122SEdward Tomasz Napierala struct linux_pt_reg { 914dfd6122SEdward Tomasz Napierala l_long ebx; 924dfd6122SEdward Tomasz Napierala l_long ecx; 934dfd6122SEdward Tomasz Napierala l_long edx; 944dfd6122SEdward Tomasz Napierala l_long esi; 954dfd6122SEdward Tomasz Napierala l_long edi; 964dfd6122SEdward Tomasz Napierala l_long ebp; 974dfd6122SEdward Tomasz Napierala l_long eax; 984dfd6122SEdward Tomasz Napierala l_int xds; 994dfd6122SEdward Tomasz Napierala l_int xes; 1004dfd6122SEdward Tomasz Napierala l_int xfs; 1014dfd6122SEdward Tomasz Napierala l_int xgs; 1024dfd6122SEdward Tomasz Napierala l_long orig_eax; 1034dfd6122SEdward Tomasz Napierala l_long eip; 1044dfd6122SEdward Tomasz Napierala l_int xcs; 1054dfd6122SEdward Tomasz Napierala l_long eflags; 1064dfd6122SEdward Tomasz Napierala l_long esp; 1074dfd6122SEdward Tomasz Napierala l_int xss; 1084dfd6122SEdward Tomasz Napierala }; 1094dfd6122SEdward Tomasz Napierala 1104dfd6122SEdward Tomasz Napierala /* 1114dfd6122SEdward Tomasz Napierala * Translate i386 ptrace registers between Linux and FreeBSD formats. 1124dfd6122SEdward Tomasz Napierala * The translation is pretty straighforward, for all registers, but 1134dfd6122SEdward Tomasz Napierala * orig_eax on Linux side and r_trapno and r_err in FreeBSD 1144dfd6122SEdward Tomasz Napierala */ 1154dfd6122SEdward Tomasz Napierala static void 1164dfd6122SEdward Tomasz Napierala map_regs_to_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r) 1174dfd6122SEdward Tomasz Napierala { 1184dfd6122SEdward Tomasz Napierala linux_r->ebx = bsd_r->r_ebx; 1194dfd6122SEdward Tomasz Napierala linux_r->ecx = bsd_r->r_ecx; 1204dfd6122SEdward Tomasz Napierala linux_r->edx = bsd_r->r_edx; 1214dfd6122SEdward Tomasz Napierala linux_r->esi = bsd_r->r_esi; 1224dfd6122SEdward Tomasz Napierala linux_r->edi = bsd_r->r_edi; 1234dfd6122SEdward Tomasz Napierala linux_r->ebp = bsd_r->r_ebp; 1244dfd6122SEdward Tomasz Napierala linux_r->eax = bsd_r->r_eax; 1254dfd6122SEdward Tomasz Napierala linux_r->xds = bsd_r->r_ds; 1264dfd6122SEdward Tomasz Napierala linux_r->xes = bsd_r->r_es; 1274dfd6122SEdward Tomasz Napierala linux_r->xfs = bsd_r->r_fs; 1284dfd6122SEdward Tomasz Napierala linux_r->xgs = bsd_r->r_gs; 1294dfd6122SEdward Tomasz Napierala linux_r->orig_eax = bsd_r->r_eax; 1304dfd6122SEdward Tomasz Napierala linux_r->eip = bsd_r->r_eip; 1314dfd6122SEdward Tomasz Napierala linux_r->xcs = bsd_r->r_cs; 1324dfd6122SEdward Tomasz Napierala linux_r->eflags = bsd_r->r_eflags; 1334dfd6122SEdward Tomasz Napierala linux_r->esp = bsd_r->r_esp; 1344dfd6122SEdward Tomasz Napierala linux_r->xss = bsd_r->r_ss; 1354dfd6122SEdward Tomasz Napierala } 1364dfd6122SEdward Tomasz Napierala 1374dfd6122SEdward Tomasz Napierala static void 1384dfd6122SEdward Tomasz Napierala map_regs_from_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r) 1394dfd6122SEdward Tomasz Napierala { 1404dfd6122SEdward Tomasz Napierala bsd_r->r_ebx = linux_r->ebx; 1414dfd6122SEdward Tomasz Napierala bsd_r->r_ecx = linux_r->ecx; 1424dfd6122SEdward Tomasz Napierala bsd_r->r_edx = linux_r->edx; 1434dfd6122SEdward Tomasz Napierala bsd_r->r_esi = linux_r->esi; 1444dfd6122SEdward Tomasz Napierala bsd_r->r_edi = linux_r->edi; 1454dfd6122SEdward Tomasz Napierala bsd_r->r_ebp = linux_r->ebp; 1464dfd6122SEdward Tomasz Napierala bsd_r->r_eax = linux_r->eax; 1474dfd6122SEdward Tomasz Napierala bsd_r->r_ds = linux_r->xds; 1484dfd6122SEdward Tomasz Napierala bsd_r->r_es = linux_r->xes; 1494dfd6122SEdward Tomasz Napierala bsd_r->r_fs = linux_r->xfs; 1504dfd6122SEdward Tomasz Napierala bsd_r->r_gs = linux_r->xgs; 1514dfd6122SEdward Tomasz Napierala bsd_r->r_eip = linux_r->eip; 1524dfd6122SEdward Tomasz Napierala bsd_r->r_cs = linux_r->xcs; 1534dfd6122SEdward Tomasz Napierala bsd_r->r_eflags = linux_r->eflags; 1544dfd6122SEdward Tomasz Napierala bsd_r->r_esp = linux_r->esp; 1554dfd6122SEdward Tomasz Napierala bsd_r->r_ss = linux_r->xss; 1564dfd6122SEdward Tomasz Napierala } 1574dfd6122SEdward Tomasz Napierala 1584dfd6122SEdward Tomasz Napierala struct linux_pt_fpreg { 1594dfd6122SEdward Tomasz Napierala l_long cwd; 1604dfd6122SEdward Tomasz Napierala l_long swd; 1614dfd6122SEdward Tomasz Napierala l_long twd; 1624dfd6122SEdward Tomasz Napierala l_long fip; 1634dfd6122SEdward Tomasz Napierala l_long fcs; 1644dfd6122SEdward Tomasz Napierala l_long foo; 1654dfd6122SEdward Tomasz Napierala l_long fos; 1664dfd6122SEdward Tomasz Napierala l_long st_space[2*10]; 1674dfd6122SEdward Tomasz Napierala }; 1684dfd6122SEdward Tomasz Napierala 1694dfd6122SEdward Tomasz Napierala static void 1704dfd6122SEdward Tomasz Napierala map_fpregs_to_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r) 1714dfd6122SEdward Tomasz Napierala { 1724dfd6122SEdward Tomasz Napierala linux_r->cwd = bsd_r->fpr_env[0]; 1734dfd6122SEdward Tomasz Napierala linux_r->swd = bsd_r->fpr_env[1]; 1744dfd6122SEdward Tomasz Napierala linux_r->twd = bsd_r->fpr_env[2]; 1754dfd6122SEdward Tomasz Napierala linux_r->fip = bsd_r->fpr_env[3]; 1764dfd6122SEdward Tomasz Napierala linux_r->fcs = bsd_r->fpr_env[4]; 1774dfd6122SEdward Tomasz Napierala linux_r->foo = bsd_r->fpr_env[5]; 1784dfd6122SEdward Tomasz Napierala linux_r->fos = bsd_r->fpr_env[6]; 1794dfd6122SEdward Tomasz Napierala bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(linux_r->st_space)); 1804dfd6122SEdward Tomasz Napierala } 1814dfd6122SEdward Tomasz Napierala 1824dfd6122SEdward Tomasz Napierala static void 1834dfd6122SEdward Tomasz Napierala map_fpregs_from_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r) 1844dfd6122SEdward Tomasz Napierala { 1854dfd6122SEdward Tomasz Napierala bsd_r->fpr_env[0] = linux_r->cwd; 1864dfd6122SEdward Tomasz Napierala bsd_r->fpr_env[1] = linux_r->swd; 1874dfd6122SEdward Tomasz Napierala bsd_r->fpr_env[2] = linux_r->twd; 1884dfd6122SEdward Tomasz Napierala bsd_r->fpr_env[3] = linux_r->fip; 1894dfd6122SEdward Tomasz Napierala bsd_r->fpr_env[4] = linux_r->fcs; 1904dfd6122SEdward Tomasz Napierala bsd_r->fpr_env[5] = linux_r->foo; 1914dfd6122SEdward Tomasz Napierala bsd_r->fpr_env[6] = linux_r->fos; 1924dfd6122SEdward Tomasz Napierala bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(bsd_r->fpr_acc)); 1934dfd6122SEdward Tomasz Napierala } 1944dfd6122SEdward Tomasz Napierala 1954dfd6122SEdward Tomasz Napierala struct linux_pt_fpxreg { 1964dfd6122SEdward Tomasz Napierala l_ushort cwd; 1974dfd6122SEdward Tomasz Napierala l_ushort swd; 1984dfd6122SEdward Tomasz Napierala l_ushort twd; 1994dfd6122SEdward Tomasz Napierala l_ushort fop; 2004dfd6122SEdward Tomasz Napierala l_long fip; 2014dfd6122SEdward Tomasz Napierala l_long fcs; 2024dfd6122SEdward Tomasz Napierala l_long foo; 2034dfd6122SEdward Tomasz Napierala l_long fos; 2044dfd6122SEdward Tomasz Napierala l_long mxcsr; 2054dfd6122SEdward Tomasz Napierala l_long reserved; 2064dfd6122SEdward Tomasz Napierala l_long st_space[32]; 2074dfd6122SEdward Tomasz Napierala l_long xmm_space[32]; 2084dfd6122SEdward Tomasz Napierala l_long padding[56]; 2094dfd6122SEdward Tomasz Napierala }; 2104dfd6122SEdward Tomasz Napierala 2114dfd6122SEdward Tomasz Napierala static int 2124dfd6122SEdward Tomasz Napierala linux_proc_read_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs) 2134dfd6122SEdward Tomasz Napierala { 2144dfd6122SEdward Tomasz Napierala 2154dfd6122SEdward Tomasz Napierala PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 216*47288801SMark Johnston if (cpu_fxsr == 0) 2174dfd6122SEdward Tomasz Napierala return (EIO); 2184dfd6122SEdward Tomasz Napierala bcopy(&get_pcb_user_save_td(td)->sv_xmm, fpxregs, sizeof(*fpxregs)); 2194dfd6122SEdward Tomasz Napierala return (0); 2204dfd6122SEdward Tomasz Napierala } 2214dfd6122SEdward Tomasz Napierala 2224dfd6122SEdward Tomasz Napierala static int 2234dfd6122SEdward Tomasz Napierala linux_proc_write_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs) 2244dfd6122SEdward Tomasz Napierala { 2254dfd6122SEdward Tomasz Napierala 2264dfd6122SEdward Tomasz Napierala PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 227*47288801SMark Johnston if (cpu_fxsr == 0) 2284dfd6122SEdward Tomasz Napierala return (EIO); 2294dfd6122SEdward Tomasz Napierala bcopy(fpxregs, &get_pcb_user_save_td(td)->sv_xmm, sizeof(*fpxregs)); 2304dfd6122SEdward Tomasz Napierala return (0); 2314dfd6122SEdward Tomasz Napierala } 2324dfd6122SEdward Tomasz Napierala 2334dfd6122SEdward Tomasz Napierala int 2344dfd6122SEdward Tomasz Napierala linux_ptrace(struct thread *td, struct linux_ptrace_args *uap) 2354dfd6122SEdward Tomasz Napierala { 2364dfd6122SEdward Tomasz Napierala union { 2374dfd6122SEdward Tomasz Napierala struct linux_pt_reg reg; 2384dfd6122SEdward Tomasz Napierala struct linux_pt_fpreg fpreg; 2394dfd6122SEdward Tomasz Napierala struct linux_pt_fpxreg fpxreg; 2404dfd6122SEdward Tomasz Napierala } r; 2414dfd6122SEdward Tomasz Napierala union { 2424dfd6122SEdward Tomasz Napierala struct reg bsd_reg; 2434dfd6122SEdward Tomasz Napierala struct fpreg bsd_fpreg; 2444dfd6122SEdward Tomasz Napierala struct dbreg bsd_dbreg; 2454dfd6122SEdward Tomasz Napierala } u; 2464dfd6122SEdward Tomasz Napierala void *addr; 2474dfd6122SEdward Tomasz Napierala pid_t pid; 2484dfd6122SEdward Tomasz Napierala int error, req; 2494dfd6122SEdward Tomasz Napierala 2504dfd6122SEdward Tomasz Napierala error = 0; 2514dfd6122SEdward Tomasz Napierala 2524dfd6122SEdward Tomasz Napierala /* by default, just copy data intact */ 2534dfd6122SEdward Tomasz Napierala req = uap->req; 2544dfd6122SEdward Tomasz Napierala pid = (pid_t)uap->pid; 2554dfd6122SEdward Tomasz Napierala addr = (void *)uap->addr; 2564dfd6122SEdward Tomasz Napierala 2574dfd6122SEdward Tomasz Napierala switch (req) { 2584dfd6122SEdward Tomasz Napierala case PTRACE_TRACEME: 2594dfd6122SEdward Tomasz Napierala case PTRACE_POKETEXT: 2604dfd6122SEdward Tomasz Napierala case PTRACE_POKEDATA: 2614dfd6122SEdward Tomasz Napierala case PTRACE_KILL: 2624dfd6122SEdward Tomasz Napierala error = kern_ptrace(td, req, pid, addr, uap->data); 2634dfd6122SEdward Tomasz Napierala break; 2644dfd6122SEdward Tomasz Napierala case PTRACE_PEEKTEXT: 2654dfd6122SEdward Tomasz Napierala case PTRACE_PEEKDATA: { 2664dfd6122SEdward Tomasz Napierala /* need to preserve return value */ 2674dfd6122SEdward Tomasz Napierala int rval = td->td_retval[0]; 2684dfd6122SEdward Tomasz Napierala error = kern_ptrace(td, req, pid, addr, 0); 2694dfd6122SEdward Tomasz Napierala if (error == 0) 2704dfd6122SEdward Tomasz Napierala error = copyout(td->td_retval, (void *)uap->data, 2714dfd6122SEdward Tomasz Napierala sizeof(l_int)); 2724dfd6122SEdward Tomasz Napierala td->td_retval[0] = rval; 2734dfd6122SEdward Tomasz Napierala break; 2744dfd6122SEdward Tomasz Napierala } 2754dfd6122SEdward Tomasz Napierala case PTRACE_DETACH: 2764dfd6122SEdward Tomasz Napierala error = kern_ptrace(td, PT_DETACH, pid, (void *)1, 2774dfd6122SEdward Tomasz Napierala map_signum(uap->data)); 2784dfd6122SEdward Tomasz Napierala break; 2794dfd6122SEdward Tomasz Napierala case PTRACE_SINGLESTEP: 2804dfd6122SEdward Tomasz Napierala case PTRACE_CONT: 2814dfd6122SEdward Tomasz Napierala error = kern_ptrace(td, req, pid, (void *)1, 2824dfd6122SEdward Tomasz Napierala map_signum(uap->data)); 2834dfd6122SEdward Tomasz Napierala break; 2844dfd6122SEdward Tomasz Napierala case PTRACE_ATTACH: 2854dfd6122SEdward Tomasz Napierala error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data); 2864dfd6122SEdward Tomasz Napierala break; 2874dfd6122SEdward Tomasz Napierala case PTRACE_GETREGS: 2884dfd6122SEdward Tomasz Napierala /* Linux is using data where FreeBSD is using addr */ 2894dfd6122SEdward Tomasz Napierala error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0); 2904dfd6122SEdward Tomasz Napierala if (error == 0) { 2914dfd6122SEdward Tomasz Napierala map_regs_to_linux(&u.bsd_reg, &r.reg); 2924dfd6122SEdward Tomasz Napierala error = copyout(&r.reg, (void *)uap->data, 2934dfd6122SEdward Tomasz Napierala sizeof(r.reg)); 2944dfd6122SEdward Tomasz Napierala } 2954dfd6122SEdward Tomasz Napierala break; 2964dfd6122SEdward Tomasz Napierala case PTRACE_SETREGS: 2974dfd6122SEdward Tomasz Napierala /* Linux is using data where FreeBSD is using addr */ 2984dfd6122SEdward Tomasz Napierala error = copyin((void *)uap->data, &r.reg, sizeof(r.reg)); 2994dfd6122SEdward Tomasz Napierala if (error == 0) { 3004dfd6122SEdward Tomasz Napierala map_regs_from_linux(&u.bsd_reg, &r.reg); 3014dfd6122SEdward Tomasz Napierala error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0); 3024dfd6122SEdward Tomasz Napierala } 3034dfd6122SEdward Tomasz Napierala break; 3044dfd6122SEdward Tomasz Napierala case PTRACE_GETFPREGS: 3054dfd6122SEdward Tomasz Napierala /* Linux is using data where FreeBSD is using addr */ 3064dfd6122SEdward Tomasz Napierala error = kern_ptrace(td, PT_GETFPREGS, pid, &u.bsd_fpreg, 0); 3074dfd6122SEdward Tomasz Napierala if (error == 0) { 3084dfd6122SEdward Tomasz Napierala map_fpregs_to_linux(&u.bsd_fpreg, &r.fpreg); 3094dfd6122SEdward Tomasz Napierala error = copyout(&r.fpreg, (void *)uap->data, 3104dfd6122SEdward Tomasz Napierala sizeof(r.fpreg)); 3114dfd6122SEdward Tomasz Napierala } 3124dfd6122SEdward Tomasz Napierala break; 3134dfd6122SEdward Tomasz Napierala case PTRACE_SETFPREGS: 3144dfd6122SEdward Tomasz Napierala /* Linux is using data where FreeBSD is using addr */ 3154dfd6122SEdward Tomasz Napierala error = copyin((void *)uap->data, &r.fpreg, sizeof(r.fpreg)); 3164dfd6122SEdward Tomasz Napierala if (error == 0) { 3174dfd6122SEdward Tomasz Napierala map_fpregs_from_linux(&u.bsd_fpreg, &r.fpreg); 3184dfd6122SEdward Tomasz Napierala error = kern_ptrace(td, PT_SETFPREGS, pid, 3194dfd6122SEdward Tomasz Napierala &u.bsd_fpreg, 0); 3204dfd6122SEdward Tomasz Napierala } 3214dfd6122SEdward Tomasz Napierala break; 3224dfd6122SEdward Tomasz Napierala case PTRACE_SETFPXREGS: 3234dfd6122SEdward Tomasz Napierala error = copyin((void *)uap->data, &r.fpxreg, sizeof(r.fpxreg)); 3244dfd6122SEdward Tomasz Napierala if (error) 3254dfd6122SEdward Tomasz Napierala break; 3264dfd6122SEdward Tomasz Napierala /* FALL THROUGH */ 3274dfd6122SEdward Tomasz Napierala case PTRACE_GETFPXREGS: { 3284dfd6122SEdward Tomasz Napierala struct proc *p; 3294dfd6122SEdward Tomasz Napierala struct thread *td2; 3304dfd6122SEdward Tomasz Napierala 3314dfd6122SEdward Tomasz Napierala if (sizeof(struct linux_pt_fpxreg) != sizeof(struct savexmm)) { 3324dfd6122SEdward Tomasz Napierala static int once = 0; 3334dfd6122SEdward Tomasz Napierala if (!once) { 3344dfd6122SEdward Tomasz Napierala printf("linux: savexmm != linux_pt_fpxreg\n"); 3354dfd6122SEdward Tomasz Napierala once = 1; 3364dfd6122SEdward Tomasz Napierala } 3374dfd6122SEdward Tomasz Napierala error = EIO; 3384dfd6122SEdward Tomasz Napierala break; 3394dfd6122SEdward Tomasz Napierala } 3404dfd6122SEdward Tomasz Napierala 3414dfd6122SEdward Tomasz Napierala if ((p = pfind(uap->pid)) == NULL) { 3424dfd6122SEdward Tomasz Napierala error = ESRCH; 3434dfd6122SEdward Tomasz Napierala break; 3444dfd6122SEdward Tomasz Napierala } 3454dfd6122SEdward Tomasz Napierala 3464dfd6122SEdward Tomasz Napierala /* Exiting processes can't be debugged. */ 3474dfd6122SEdward Tomasz Napierala if ((p->p_flag & P_WEXIT) != 0) { 3484dfd6122SEdward Tomasz Napierala error = ESRCH; 3494dfd6122SEdward Tomasz Napierala goto fail; 3504dfd6122SEdward Tomasz Napierala } 3514dfd6122SEdward Tomasz Napierala 3524dfd6122SEdward Tomasz Napierala if ((error = p_candebug(td, p)) != 0) 3534dfd6122SEdward Tomasz Napierala goto fail; 3544dfd6122SEdward Tomasz Napierala 3554dfd6122SEdward Tomasz Napierala /* System processes can't be debugged. */ 3564dfd6122SEdward Tomasz Napierala if ((p->p_flag & P_SYSTEM) != 0) { 3574dfd6122SEdward Tomasz Napierala error = EINVAL; 3584dfd6122SEdward Tomasz Napierala goto fail; 3594dfd6122SEdward Tomasz Napierala } 3604dfd6122SEdward Tomasz Napierala 3614dfd6122SEdward Tomasz Napierala /* not being traced... */ 3624dfd6122SEdward Tomasz Napierala if ((p->p_flag & P_TRACED) == 0) { 3634dfd6122SEdward Tomasz Napierala error = EPERM; 3644dfd6122SEdward Tomasz Napierala goto fail; 3654dfd6122SEdward Tomasz Napierala } 3664dfd6122SEdward Tomasz Napierala 3674dfd6122SEdward Tomasz Napierala /* not being traced by YOU */ 3684dfd6122SEdward Tomasz Napierala if (p->p_pptr != td->td_proc) { 3694dfd6122SEdward Tomasz Napierala error = EBUSY; 3704dfd6122SEdward Tomasz Napierala goto fail; 3714dfd6122SEdward Tomasz Napierala } 3724dfd6122SEdward Tomasz Napierala 3734dfd6122SEdward Tomasz Napierala /* not currently stopped */ 3744dfd6122SEdward Tomasz Napierala if (!P_SHOULDSTOP(p) || (p->p_flag & P_WAITED) == 0) { 3754dfd6122SEdward Tomasz Napierala error = EBUSY; 3764dfd6122SEdward Tomasz Napierala goto fail; 3774dfd6122SEdward Tomasz Napierala } 3784dfd6122SEdward Tomasz Napierala 3794dfd6122SEdward Tomasz Napierala if (req == PTRACE_GETFPXREGS) { 3804dfd6122SEdward Tomasz Napierala _PHOLD(p); /* may block */ 3814dfd6122SEdward Tomasz Napierala td2 = FIRST_THREAD_IN_PROC(p); 3824dfd6122SEdward Tomasz Napierala error = linux_proc_read_fpxregs(td2, &r.fpxreg); 3834dfd6122SEdward Tomasz Napierala _PRELE(p); 3844dfd6122SEdward Tomasz Napierala PROC_UNLOCK(p); 3854dfd6122SEdward Tomasz Napierala if (error == 0) 3864dfd6122SEdward Tomasz Napierala error = copyout(&r.fpxreg, (void *)uap->data, 3874dfd6122SEdward Tomasz Napierala sizeof(r.fpxreg)); 3884dfd6122SEdward Tomasz Napierala } else { 3894dfd6122SEdward Tomasz Napierala /* clear dangerous bits exactly as Linux does*/ 3904dfd6122SEdward Tomasz Napierala r.fpxreg.mxcsr &= 0xffbf; 3914dfd6122SEdward Tomasz Napierala _PHOLD(p); /* may block */ 3924dfd6122SEdward Tomasz Napierala td2 = FIRST_THREAD_IN_PROC(p); 3934dfd6122SEdward Tomasz Napierala error = linux_proc_write_fpxregs(td2, &r.fpxreg); 3944dfd6122SEdward Tomasz Napierala _PRELE(p); 3954dfd6122SEdward Tomasz Napierala PROC_UNLOCK(p); 3964dfd6122SEdward Tomasz Napierala } 3974dfd6122SEdward Tomasz Napierala break; 3984dfd6122SEdward Tomasz Napierala 3994dfd6122SEdward Tomasz Napierala fail: 4004dfd6122SEdward Tomasz Napierala PROC_UNLOCK(p); 4014dfd6122SEdward Tomasz Napierala break; 4024dfd6122SEdward Tomasz Napierala } 4034dfd6122SEdward Tomasz Napierala case PTRACE_PEEKUSR: 4044dfd6122SEdward Tomasz Napierala case PTRACE_POKEUSR: { 4054dfd6122SEdward Tomasz Napierala error = EIO; 4064dfd6122SEdward Tomasz Napierala 4074dfd6122SEdward Tomasz Napierala /* check addr for alignment */ 4084dfd6122SEdward Tomasz Napierala if (uap->addr < 0 || uap->addr & (sizeof(l_int) - 1)) 4094dfd6122SEdward Tomasz Napierala break; 4104dfd6122SEdward Tomasz Napierala /* 4114dfd6122SEdward Tomasz Napierala * Allow Linux programs to access register values in 4124dfd6122SEdward Tomasz Napierala * user struct. We simulate this through PT_GET/SETREGS 4134dfd6122SEdward Tomasz Napierala * as necessary. 4144dfd6122SEdward Tomasz Napierala */ 4154dfd6122SEdward Tomasz Napierala if (uap->addr < sizeof(struct linux_pt_reg)) { 4164dfd6122SEdward Tomasz Napierala error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0); 4174dfd6122SEdward Tomasz Napierala if (error != 0) 4184dfd6122SEdward Tomasz Napierala break; 4194dfd6122SEdward Tomasz Napierala 4204dfd6122SEdward Tomasz Napierala map_regs_to_linux(&u.bsd_reg, &r.reg); 4214dfd6122SEdward Tomasz Napierala if (req == PTRACE_PEEKUSR) { 4224dfd6122SEdward Tomasz Napierala error = copyout((char *)&r.reg + uap->addr, 4234dfd6122SEdward Tomasz Napierala (void *)uap->data, sizeof(l_int)); 4244dfd6122SEdward Tomasz Napierala break; 4254dfd6122SEdward Tomasz Napierala } 4264dfd6122SEdward Tomasz Napierala 4274dfd6122SEdward Tomasz Napierala *(l_int *)((char *)&r.reg + uap->addr) = 4284dfd6122SEdward Tomasz Napierala (l_int)uap->data; 4294dfd6122SEdward Tomasz Napierala 4304dfd6122SEdward Tomasz Napierala map_regs_from_linux(&u.bsd_reg, &r.reg); 4314dfd6122SEdward Tomasz Napierala error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0); 4324dfd6122SEdward Tomasz Napierala } 4334dfd6122SEdward Tomasz Napierala 4344dfd6122SEdward Tomasz Napierala /* 4354dfd6122SEdward Tomasz Napierala * Simulate debug registers access 4364dfd6122SEdward Tomasz Napierala */ 4374dfd6122SEdward Tomasz Napierala if (uap->addr >= LINUX_DBREG_OFFSET && 4384dfd6122SEdward Tomasz Napierala uap->addr <= LINUX_DBREG_OFFSET + LINUX_DBREG_SIZE) { 4394dfd6122SEdward Tomasz Napierala error = kern_ptrace(td, PT_GETDBREGS, pid, &u.bsd_dbreg, 4404dfd6122SEdward Tomasz Napierala 0); 4414dfd6122SEdward Tomasz Napierala if (error != 0) 4424dfd6122SEdward Tomasz Napierala break; 4434dfd6122SEdward Tomasz Napierala 4444dfd6122SEdward Tomasz Napierala uap->addr -= LINUX_DBREG_OFFSET; 4454dfd6122SEdward Tomasz Napierala if (req == PTRACE_PEEKUSR) { 4464dfd6122SEdward Tomasz Napierala error = copyout((char *)&u.bsd_dbreg + 4474dfd6122SEdward Tomasz Napierala uap->addr, (void *)uap->data, 4484dfd6122SEdward Tomasz Napierala sizeof(l_int)); 4494dfd6122SEdward Tomasz Napierala break; 4504dfd6122SEdward Tomasz Napierala } 4514dfd6122SEdward Tomasz Napierala 4524dfd6122SEdward Tomasz Napierala *(l_int *)((char *)&u.bsd_dbreg + uap->addr) = 4534dfd6122SEdward Tomasz Napierala uap->data; 4544dfd6122SEdward Tomasz Napierala error = kern_ptrace(td, PT_SETDBREGS, pid, 4554dfd6122SEdward Tomasz Napierala &u.bsd_dbreg, 0); 4564dfd6122SEdward Tomasz Napierala } 4574dfd6122SEdward Tomasz Napierala 4584dfd6122SEdward Tomasz Napierala break; 4594dfd6122SEdward Tomasz Napierala } 4604dfd6122SEdward Tomasz Napierala case LINUX_PTRACE_SYSCALL: 4614dfd6122SEdward Tomasz Napierala /* fall through */ 4624dfd6122SEdward Tomasz Napierala default: 4634dfd6122SEdward Tomasz Napierala printf("linux: ptrace(%u, ...) not implemented\n", 4644dfd6122SEdward Tomasz Napierala (unsigned int)uap->req); 4654dfd6122SEdward Tomasz Napierala error = EINVAL; 4664dfd6122SEdward Tomasz Napierala break; 4674dfd6122SEdward Tomasz Napierala } 4684dfd6122SEdward Tomasz Napierala 4694dfd6122SEdward Tomasz Napierala return (error); 4704dfd6122SEdward Tomasz Napierala } 471