1 /* 2 * Copyright (c) 1994, Sean Eric Fagan 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 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Sean Eric Fagan. 16 * 4. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $Id: sys_process.c,v 1.12 1995/03/16 18:12:42 bde Exp $ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/proc.h> 37 #include <sys/vnode.h> 38 #include <sys/ptrace.h> 39 #include <sys/errno.h> 40 41 #include <machine/reg.h> 42 #include <machine/psl.h> 43 #include <vm/vm.h> 44 #include <vm/vm_page.h> 45 #include <vm/vm_kern.h> 46 47 #include <sys/user.h> 48 49 static int 50 pread (struct proc *procp, unsigned int addr, unsigned int *retval) { 51 int rv; 52 vm_map_t map, tmap; 53 vm_object_t object; 54 vm_offset_t kva = 0; 55 int page_offset; /* offset into page */ 56 vm_offset_t pageno; /* page number */ 57 vm_map_entry_t out_entry; 58 vm_prot_t out_prot; 59 boolean_t wired, single_use; 60 vm_offset_t off; 61 62 /* Map page into kernel space */ 63 64 map = &procp->p_vmspace->vm_map; 65 66 page_offset = addr - trunc_page(addr); 67 pageno = trunc_page(addr); 68 69 tmap = map; 70 rv = vm_map_lookup (&tmap, pageno, VM_PROT_READ, &out_entry, 71 &object, &off, &out_prot, &wired, &single_use); 72 73 if (rv != KERN_SUCCESS) 74 return EINVAL; 75 76 vm_map_lookup_done (tmap, out_entry); 77 78 /* Find space in kernel_map for the page we're interested in */ 79 rv = vm_map_find (kernel_map, object, off, &kva, PAGE_SIZE, 1); 80 81 if (!rv) { 82 vm_object_reference (object); 83 84 rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 85 if (!rv) { 86 *retval = 0; 87 bcopy ((caddr_t)kva + page_offset, 88 retval, sizeof *retval); 89 } 90 vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 91 } 92 93 return rv; 94 } 95 96 static int 97 pwrite (struct proc *procp, unsigned int addr, unsigned int datum) { 98 int rv; 99 vm_map_t map, tmap; 100 vm_object_t object; 101 vm_offset_t kva = 0; 102 int page_offset; /* offset into page */ 103 vm_offset_t pageno; /* page number */ 104 vm_map_entry_t out_entry; 105 vm_prot_t out_prot; 106 boolean_t wired, single_use; 107 vm_offset_t off; 108 boolean_t fix_prot = 0; 109 110 /* Map page into kernel space */ 111 112 map = &procp->p_vmspace->vm_map; 113 114 page_offset = addr - trunc_page(addr); 115 pageno = trunc_page(addr); 116 117 /* 118 * Check the permissions for the area we're interested in. 119 */ 120 121 if (vm_map_check_protection (map, pageno, pageno + PAGE_SIZE, 122 VM_PROT_WRITE) == FALSE) { 123 /* 124 * If the page was not writable, we make it so. 125 * XXX It is possible a page may *not* be read/executable, 126 * if a process changes that! 127 */ 128 fix_prot = 1; 129 /* The page isn't writable, so let's try making it so... */ 130 if ((rv = vm_map_protect (map, pageno, pageno + PAGE_SIZE, 131 VM_PROT_ALL, 0)) != KERN_SUCCESS) 132 return EFAULT; /* I guess... */ 133 } 134 135 /* 136 * Now we need to get the page. out_entry, out_prot, wired, and 137 * single_use aren't used. One would think the vm code would be 138 * a *bit* nicer... We use tmap because vm_map_lookup() can 139 * change the map argument. 140 */ 141 142 tmap = map; 143 rv = vm_map_lookup (&tmap, pageno, VM_PROT_WRITE, &out_entry, 144 &object, &off, &out_prot, &wired, &single_use); 145 if (rv != KERN_SUCCESS) { 146 return EINVAL; 147 } 148 149 /* 150 * Okay, we've got the page. Let's release tmap. 151 */ 152 153 vm_map_lookup_done (tmap, out_entry); 154 155 /* 156 * Fault the page in... 157 */ 158 159 vm_map_pageable(map, trunc_page(vtopte(pageno)), 160 trunc_page(vtopte(pageno)) + PAGE_SIZE, FALSE); 161 rv = vm_fault(map, pageno, VM_PROT_WRITE|VM_PROT_READ, FALSE); 162 vm_map_pageable(map, trunc_page(vtopte(pageno)), 163 trunc_page(vtopte(pageno)) + PAGE_SIZE, TRUE); 164 if (rv != KERN_SUCCESS) 165 return EFAULT; 166 167 /* Find space in kernel_map for the page we're interested in */ 168 rv = vm_map_find (kernel_map, object, off, &kva, PAGE_SIZE, 1); 169 170 if (!rv) { 171 vm_object_reference (object); 172 173 rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 174 if (!rv) { 175 bcopy (&datum, (caddr_t)kva + page_offset, sizeof datum); 176 } 177 vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 178 } 179 180 if (fix_prot) 181 vm_map_protect (map, pageno, pageno + PAGE_SIZE, 182 VM_PROT_READ|VM_PROT_EXECUTE, 0); 183 return rv; 184 } 185 186 /* 187 * Process debugging system call. 188 */ 189 struct ptrace_args { 190 int req; 191 pid_t pid; 192 caddr_t addr; 193 int data; 194 }; 195 196 int 197 ptrace(curp, uap, retval) 198 struct proc *curp; 199 struct ptrace_args *uap; 200 int *retval; 201 { 202 struct proc *p; 203 int error = 0; 204 205 *retval = 0; 206 if (uap->req == PT_TRACE_ME) { 207 curp->p_flag |= P_TRACED; 208 return 0; 209 } 210 if ((p = pfind(uap->pid)) == NULL) { 211 return ESRCH; 212 } 213 214 #ifdef PT_ATTACH 215 if (uap->req != PT_ATTACH && ( 216 (p->p_flag & P_TRACED) == 0 || 217 (p->p_tptr && curp != p->p_tptr) || 218 (!p->p_tptr && curp != p->p_pptr))) 219 220 return ESRCH; 221 #endif 222 #ifdef PT_ATTACH 223 if (uap->req != PT_ATTACH) { 224 #endif 225 if ((p->p_flag & P_TRACED) == 0) 226 return EPERM; 227 if (p->p_stat != SSTOP || (p->p_flag & P_WAITED) == 0) 228 return EBUSY; 229 #ifdef PT_ATTACH 230 } 231 #endif 232 /* 233 * XXX The PT_ATTACH code is completely broken. It will 234 * be obsoleted by a /proc filesystem, so is it worth it 235 * to fix it? (Answer, probably. So that'll be next, 236 * I guess.) 237 */ 238 239 switch (uap->req) { 240 #ifdef PT_ATTACH 241 case PT_ATTACH: 242 if (curp->p_ucred->cr_uid != 0 && ( 243 curp->p_ucred->cr_uid != p->p_ucred->cr_uid || 244 curp->p_ucred->cr_uid != p->p_cred->p_svuid)) 245 return EACCES; 246 247 p->p_tptr = curp; 248 p->p_flag |= P_TRACED; 249 psignal(p, SIGSTOP); 250 return 0; 251 252 case PT_DETACH: 253 if ((unsigned)uap->data >= NSIG) 254 return EINVAL; 255 p->p_flag &= ~P_TRACED; 256 p->p_tptr = NULL; 257 psignal(p->p_pptr, SIGCHLD); 258 wakeup((caddr_t)p->p_pptr); 259 s = splhigh(); 260 if (p->p_stat == SSTOP) { 261 p->p_xstat = uap->data; 262 setrunnable(p); 263 } else if (uap->data) { 264 psignal(p, uap->data); 265 } 266 splx(s); 267 return 0; 268 269 # ifdef PT_INHERIT 270 case PT_INHERIT: 271 if ((p->p_flag & P_TRACED) == 0) 272 return ESRCH; 273 return 0; 274 # endif /* PT_INHERIT */ 275 #endif /* PT_ATTACH */ 276 277 case PT_READ_I: 278 case PT_READ_D: 279 if ((error = pread (p, (unsigned int)uap->addr, retval))) 280 return error; 281 return 0; 282 case PT_WRITE_I: 283 case PT_WRITE_D: 284 if ((error = pwrite (p, (unsigned int)uap->addr, 285 (unsigned int)uap->data))) 286 return error; 287 return 0; 288 case PT_STEP: 289 if ((error = ptrace_single_step (p))) 290 return error; 291 /* fallthrough */ 292 case PT_CONTINUE: 293 /* 294 * Continue at addr uap->addr with signal 295 * uap->data; if uap->addr is 1, then we just 296 * let the chips fall where they may. 297 * 298 * The only check I'll make right now is for 299 * uap->data to be larger than NSIG; if so, we return 300 * EINVAL. 301 */ 302 if (uap->data >= NSIG) 303 return EINVAL; 304 305 if (uap->addr != (caddr_t)1) { 306 fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 307 if ((error = ptrace_set_pc (p, (u_int)uap->addr))) 308 return error; 309 } 310 311 p->p_xstat = uap->data; 312 313 /* if (p->p_stat == SSTOP) */ 314 setrunnable (p); 315 return 0; 316 case PT_READ_U: 317 if ((u_int)uap->addr > (UPAGES * NBPG - sizeof(int))) { 318 return EFAULT; 319 } 320 p->p_addr->u_kproc.kp_proc = *p; 321 fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 322 *retval = *(int*)((u_int)p->p_addr + (u_int)uap->addr); 323 return 0; 324 case PT_WRITE_U: 325 p->p_addr->u_kproc.kp_proc = *p; 326 fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 327 return ptrace_write_u(p, (vm_offset_t)uap->addr, uap->data); 328 case PT_KILL: 329 p->p_xstat = SIGKILL; 330 setrunnable(p); 331 return 0; 332 #ifdef PT_GETREGS 333 case PT_GETREGS: 334 /* 335 * copyout the registers into addr. There's no 336 * size constraint!!! *GRRR* 337 */ 338 return ptrace_getregs(p, uap->addr); 339 case PT_SETREGS: 340 /* 341 * copyin the registers from addr. Again, no 342 * size constraint!!! *GRRRR* 343 */ 344 return ptrace_setregs (p, uap->addr); 345 #endif /* PT_GETREGS */ 346 default: 347 break; 348 } 349 350 return 0; 351 } 352 353 int 354 trace_req(p) 355 struct proc *p; 356 { 357 return 1; 358 } 359