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.14 1995/05/30 08:05:58 rgrimes Exp $ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/sysproto.h> 37 #include <sys/proc.h> 38 #include <sys/vnode.h> 39 #include <sys/ptrace.h> 40 #include <sys/errno.h> 41 42 #include <machine/reg.h> 43 #include <machine/psl.h> 44 #include <vm/vm.h> 45 #include <vm/vm_page.h> 46 #include <vm/vm_kern.h> 47 48 #include <sys/user.h> 49 50 static int 51 pread (struct proc *procp, unsigned int addr, unsigned int *retval) { 52 int rv; 53 vm_map_t map, tmap; 54 vm_object_t object; 55 vm_offset_t kva = 0; 56 int page_offset; /* offset into page */ 57 vm_offset_t pageno; /* page number */ 58 vm_map_entry_t out_entry; 59 vm_prot_t out_prot; 60 boolean_t wired, single_use; 61 vm_offset_t off; 62 63 /* Map page into kernel space */ 64 65 map = &procp->p_vmspace->vm_map; 66 67 page_offset = addr - trunc_page(addr); 68 pageno = trunc_page(addr); 69 70 tmap = map; 71 rv = vm_map_lookup (&tmap, pageno, VM_PROT_READ, &out_entry, 72 &object, &off, &out_prot, &wired, &single_use); 73 74 if (rv != KERN_SUCCESS) 75 return EINVAL; 76 77 vm_map_lookup_done (tmap, out_entry); 78 79 /* Find space in kernel_map for the page we're interested in */ 80 rv = vm_map_find (kernel_map, object, off, &kva, PAGE_SIZE, 1); 81 82 if (!rv) { 83 vm_object_reference (object); 84 85 rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 86 if (!rv) { 87 *retval = 0; 88 bcopy ((caddr_t)kva + page_offset, 89 retval, sizeof *retval); 90 } 91 vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 92 } 93 94 return rv; 95 } 96 97 static int 98 pwrite (struct proc *procp, unsigned int addr, unsigned int datum) { 99 int rv; 100 vm_map_t map, tmap; 101 vm_object_t object; 102 vm_offset_t kva = 0; 103 int page_offset; /* offset into page */ 104 vm_offset_t pageno; /* page number */ 105 vm_map_entry_t out_entry; 106 vm_prot_t out_prot; 107 boolean_t wired, single_use; 108 vm_offset_t off; 109 boolean_t fix_prot = 0; 110 111 /* Map page into kernel space */ 112 113 map = &procp->p_vmspace->vm_map; 114 115 page_offset = addr - trunc_page(addr); 116 pageno = trunc_page(addr); 117 118 /* 119 * Check the permissions for the area we're interested in. 120 */ 121 122 if (vm_map_check_protection (map, pageno, pageno + PAGE_SIZE, 123 VM_PROT_WRITE) == FALSE) { 124 /* 125 * If the page was not writable, we make it so. 126 * XXX It is possible a page may *not* be read/executable, 127 * if a process changes that! 128 */ 129 fix_prot = 1; 130 /* The page isn't writable, so let's try making it so... */ 131 if ((rv = vm_map_protect (map, pageno, pageno + PAGE_SIZE, 132 VM_PROT_ALL, 0)) != KERN_SUCCESS) 133 return EFAULT; /* I guess... */ 134 } 135 136 /* 137 * Now we need to get the page. out_entry, out_prot, wired, and 138 * single_use aren't used. One would think the vm code would be 139 * a *bit* nicer... We use tmap because vm_map_lookup() can 140 * change the map argument. 141 */ 142 143 tmap = map; 144 rv = vm_map_lookup (&tmap, pageno, VM_PROT_WRITE, &out_entry, 145 &object, &off, &out_prot, &wired, &single_use); 146 if (rv != KERN_SUCCESS) { 147 return EINVAL; 148 } 149 150 /* 151 * Okay, we've got the page. Let's release tmap. 152 */ 153 154 vm_map_lookup_done (tmap, out_entry); 155 156 /* 157 * Fault the page in... 158 */ 159 160 vm_map_pageable(map, trunc_page(vtopte(pageno)), 161 trunc_page(vtopte(pageno)) + PAGE_SIZE, FALSE); 162 rv = vm_fault(map, pageno, VM_PROT_WRITE|VM_PROT_READ, FALSE); 163 vm_map_pageable(map, trunc_page(vtopte(pageno)), 164 trunc_page(vtopte(pageno)) + PAGE_SIZE, TRUE); 165 if (rv != KERN_SUCCESS) 166 return EFAULT; 167 168 /* Find space in kernel_map for the page we're interested in */ 169 rv = vm_map_find (kernel_map, object, off, &kva, PAGE_SIZE, 1); 170 171 if (!rv) { 172 vm_object_reference (object); 173 174 rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 175 if (!rv) { 176 bcopy (&datum, (caddr_t)kva + page_offset, sizeof datum); 177 } 178 vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 179 } 180 181 if (fix_prot) 182 vm_map_protect (map, pageno, pageno + PAGE_SIZE, 183 VM_PROT_READ|VM_PROT_EXECUTE, 0); 184 return rv; 185 } 186 187 /* 188 * Process debugging system call. 189 */ 190 #ifndef _SYS_SYSPROTO_H_ 191 struct ptrace_args { 192 int req; 193 pid_t pid; 194 caddr_t addr; 195 int data; 196 }; 197 #endif 198 199 int 200 ptrace(curp, uap, retval) 201 struct proc *curp; 202 struct ptrace_args *uap; 203 int *retval; 204 { 205 struct proc *p; 206 int error = 0; 207 208 *retval = 0; 209 if (uap->req == PT_TRACE_ME) { 210 curp->p_flag |= P_TRACED; 211 return 0; 212 } 213 if ((p = pfind(uap->pid)) == NULL) { 214 return ESRCH; 215 } 216 217 #ifdef PT_ATTACH 218 if (uap->req != PT_ATTACH && ( 219 (p->p_flag & P_TRACED) == 0 || 220 (p->p_tptr && curp != p->p_tptr) || 221 (!p->p_tptr && curp != p->p_pptr))) 222 223 return ESRCH; 224 #endif 225 #ifdef PT_ATTACH 226 if (uap->req != PT_ATTACH) { 227 #endif 228 if ((p->p_flag & P_TRACED) == 0) 229 return EPERM; 230 if (p->p_stat != SSTOP || (p->p_flag & P_WAITED) == 0) 231 return EBUSY; 232 #ifdef PT_ATTACH 233 } 234 #endif 235 /* 236 * XXX The PT_ATTACH code is completely broken. It will 237 * be obsoleted by a /proc filesystem, so is it worth it 238 * to fix it? (Answer, probably. So that'll be next, 239 * I guess.) 240 */ 241 242 switch (uap->req) { 243 #ifdef PT_ATTACH 244 case PT_ATTACH: 245 if (curp->p_ucred->cr_uid != 0 && ( 246 curp->p_ucred->cr_uid != p->p_ucred->cr_uid || 247 curp->p_ucred->cr_uid != p->p_cred->p_svuid)) 248 return EACCES; 249 250 p->p_tptr = curp; 251 p->p_flag |= P_TRACED; 252 psignal(p, SIGSTOP); 253 return 0; 254 255 case PT_DETACH: 256 if ((unsigned)uap->data >= NSIG) 257 return EINVAL; 258 p->p_flag &= ~P_TRACED; 259 p->p_tptr = NULL; 260 psignal(p->p_pptr, SIGCHLD); 261 wakeup((caddr_t)p->p_pptr); 262 s = splhigh(); 263 if (p->p_stat == SSTOP) { 264 p->p_xstat = uap->data; 265 setrunnable(p); 266 } else if (uap->data) { 267 psignal(p, uap->data); 268 } 269 splx(s); 270 return 0; 271 272 # ifdef PT_INHERIT 273 case PT_INHERIT: 274 if ((p->p_flag & P_TRACED) == 0) 275 return ESRCH; 276 return 0; 277 # endif /* PT_INHERIT */ 278 #endif /* PT_ATTACH */ 279 280 case PT_READ_I: 281 case PT_READ_D: 282 if ((error = pread (p, (unsigned int)uap->addr, retval))) 283 return error; 284 return 0; 285 case PT_WRITE_I: 286 case PT_WRITE_D: 287 if ((error = pwrite (p, (unsigned int)uap->addr, 288 (unsigned int)uap->data))) 289 return error; 290 return 0; 291 case PT_STEP: 292 if ((error = ptrace_single_step (p))) 293 return error; 294 /* fallthrough */ 295 case PT_CONTINUE: 296 /* 297 * Continue at addr uap->addr with signal 298 * uap->data; if uap->addr is 1, then we just 299 * let the chips fall where they may. 300 * 301 * The only check I'll make right now is for 302 * uap->data to be larger than NSIG; if so, we return 303 * EINVAL. 304 */ 305 if (uap->data >= NSIG) 306 return EINVAL; 307 308 if (uap->addr != (caddr_t)1) { 309 fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 310 if ((error = ptrace_set_pc (p, (u_int)uap->addr))) 311 return error; 312 } 313 314 p->p_xstat = uap->data; 315 316 /* if (p->p_stat == SSTOP) */ 317 setrunnable (p); 318 return 0; 319 case PT_READ_U: 320 if ((u_int)uap->addr > (UPAGES * NBPG - sizeof(int))) { 321 return EFAULT; 322 } 323 p->p_addr->u_kproc.kp_proc = *p; 324 fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 325 *retval = *(int*)((u_int)p->p_addr + (u_int)uap->addr); 326 return 0; 327 case PT_WRITE_U: 328 p->p_addr->u_kproc.kp_proc = *p; 329 fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 330 return ptrace_write_u(p, (vm_offset_t)uap->addr, uap->data); 331 case PT_KILL: 332 p->p_xstat = SIGKILL; 333 setrunnable(p); 334 return 0; 335 #ifdef PT_GETREGS 336 case PT_GETREGS: 337 /* 338 * copyout the registers into addr. There's no 339 * size constraint!!! *GRRR* 340 */ 341 return ptrace_getregs(p, uap->addr); 342 case PT_SETREGS: 343 /* 344 * copyin the registers from addr. Again, no 345 * size constraint!!! *GRRRR* 346 */ 347 return ptrace_setregs (p, uap->addr); 348 #endif /* PT_GETREGS */ 349 default: 350 break; 351 } 352 353 return 0; 354 } 355 356 int 357 trace_req(p) 358 struct proc *p; 359 { 360 return 1; 361 } 362