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.6 1994/08/18 22:35:05 wollman 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 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 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 rv = vm_fault (map, pageno, VM_PROT_WRITE, FALSE); 160 if (rv != KERN_SUCCESS) 161 return EFAULT; 162 163 /* 164 * The page may need to be faulted in again, it seems. 165 * This covers COW pages, I believe. 166 */ 167 168 if (!rv) 169 rv = vm_fault (map, pageno, VM_PROT_WRITE, 0); 170 171 /* Find space in kernel_map for the page we're interested in */ 172 rv = vm_map_find (kernel_map, object, off, &kva, PAGE_SIZE, 1); 173 174 if (!rv) { 175 vm_object_reference (object); 176 177 rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 178 if (!rv) { 179 bcopy (&datum, (caddr_t)kva + page_offset, sizeof datum); 180 } 181 vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 182 } 183 184 if (fix_prot) 185 vm_map_protect (map, pageno, pageno + PAGE_SIZE, 186 VM_PROT_READ|VM_PROT_EXECUTE, 0); 187 return rv; 188 } 189 190 /* 191 * Process debugging system call. 192 */ 193 struct ptrace_args { 194 int req; 195 pid_t pid; 196 caddr_t addr; 197 int data; 198 }; 199 200 int 201 ptrace(curp, uap, retval) 202 struct proc *curp; 203 struct ptrace_args *uap; 204 int *retval; 205 { 206 struct proc *p; 207 int error = 0; 208 209 *retval = 0; 210 if (uap->req == PT_TRACE_ME) { 211 curp->p_flag |= P_TRACED; 212 return 0; 213 } 214 if ((p = pfind(uap->pid)) == NULL) { 215 return ESRCH; 216 } 217 218 #ifdef PT_ATTACH 219 if (uap->req != PT_ATTACH && ( 220 (p->p_flag & P_TRACED) == 0 || 221 (p->p_tptr && curp != p->p_tptr) || 222 (!p->p_tptr && curp != p->p_pptr))) 223 224 return ESRCH; 225 #endif 226 #ifdef PT_ATTACH 227 if (uap->req != PT_ATTACH) { 228 #endif 229 if ((p->p_flag & P_TRACED) == 0) 230 return EPERM; 231 if (p->p_stat != SSTOP || (p->p_flag & P_WAITED) == 0) 232 return EBUSY; 233 #ifdef PT_ATTACH 234 } 235 #endif 236 /* 237 * XXX The PT_ATTACH code is completely broken. It will 238 * be obsoleted by a /proc filesystem, so is it worth it 239 * to fix it? (Answer, probably. So that'll be next, 240 * I guess.) 241 */ 242 243 switch (uap->req) { 244 #ifdef PT_ATTACH 245 case PT_ATTACH: 246 if (curp->p_ucred->cr_uid != 0 && ( 247 curp->p_ucred->cr_uid != p->p_ucred->cr_uid || 248 curp->p_ucred->cr_uid != p->p_cred->p_svuid)) 249 return EACCES; 250 251 p->p_tptr = curp; 252 p->p_flag |= P_TRACED; 253 psignal(p, SIGSTOP); 254 return 0; 255 256 case PT_DETACH: 257 if ((unsigned)uap->data >= NSIG) 258 return EINVAL; 259 p->p_flag &= ~P_TRACED; 260 p->p_tptr = NULL; 261 psignal(p->p_pptr, SIGCHLD); 262 wakeup((caddr_t)p->p_pptr); 263 s = splhigh(); 264 if (p->p_stat == SSTOP) { 265 p->p_xstat = uap->data; 266 setrunnable(p); 267 } else if (uap->data) { 268 psignal(p, uap->data); 269 } 270 splx(s); 271 return 0; 272 273 # ifdef PT_INHERIT 274 case PT_INHERIT: 275 if ((p->p_flag & P_TRACED) == 0) 276 return ESRCH; 277 return 0; 278 # endif /* PT_INHERIT */ 279 #endif /* PT_ATTACH */ 280 281 case PT_READ_I: 282 case PT_READ_D: 283 if ((error = pread (p, (unsigned int)uap->addr, retval))) 284 return error; 285 return 0; 286 case PT_WRITE_I: 287 case PT_WRITE_D: 288 if ((error = pwrite (p, (unsigned int)uap->addr, 289 (unsigned int)uap->data))) 290 return error; 291 return 0; 292 case PT_STEP: 293 if ((error = ptrace_single_step (p))) 294 return error; 295 /* fallthrough */ 296 case PT_CONTINUE: 297 /* 298 * Continue at addr uap->addr with signal 299 * uap->data; if uap->addr is 1, then we just 300 * let the chips fall where they may. 301 * 302 * The only check I'll make right now is for 303 * uap->data to be larger than NSIG; if so, we return 304 * EINVAL. 305 */ 306 if (uap->data >= NSIG) 307 return EINVAL; 308 309 if (uap->addr != (caddr_t)1) { 310 fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 311 if ((error = ptrace_set_pc (p, uap->addr))) 312 return error; 313 } 314 315 p->p_xstat = uap->data; 316 317 /* if (p->p_stat == SSTOP) */ 318 setrunnable (p); 319 return 0; 320 case PT_READ_U: 321 if ((u_int)uap->addr > (UPAGES * NBPG - sizeof(int))) { 322 return EFAULT; 323 } 324 p->p_addr->u_kproc.kp_proc = *p; 325 fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 326 *retval = *(int*)((u_int)p->p_addr + (u_int)uap->addr); 327 return 0; 328 case PT_WRITE_U: 329 if ((u_int)uap->addr > (UPAGES * NBPG - sizeof(int))) { 330 return EFAULT; 331 } 332 p->p_addr->u_kproc.kp_proc = *p; 333 fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 334 *(int*)((u_int)p->p_addr + (u_int)uap->addr) = uap->data; 335 return 0; 336 case PT_KILL: 337 p->p_xstat = SIGKILL; 338 setrunnable(p); 339 return 0; 340 #ifdef PT_GETREGS 341 case PT_GETREGS: 342 /* 343 * copyout the registers into addr. There's no 344 * size constraint!!! *GRRR* 345 */ 346 return ptrace_getregs(p, uap->addr); 347 case PT_SETREGS: 348 /* 349 * copyin the registers from addr. Again, no 350 * size constraint!!! *GRRRR* 351 */ 352 return ptrace_setregs (p, uap->addr); 353 #endif /* PT_GETREGS */ 354 default: 355 break; 356 } 357 358 return 0; 359 } 360 361 int 362 trace_req(p) 363 struct proc *p; 364 { 365 return 1; 366 } 367