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