149589Sbostic /*- 249589Sbostic * Copyright (c) 1982, 1986, 1989 The Regents of the University of California. 349589Sbostic * All rights reserved. 423385Smckusick * 549589Sbostic * %sccs.include.proprietary.c% 649589Sbostic * 7*54340Smckusick * @(#)sys_process.c 7.27 (Berkeley) 06/23/92 823385Smckusick */ 97426Sroot 1030376Skarels #define IPCREG 1117095Sbloom #include "param.h" 1217095Sbloom #include "proc.h" 1337728Smckusick #include "vnode.h" 1417095Sbloom #include "buf.h" 1526278Skarels #include "ptrace.h" 167426Sroot 1737520Smckusick #include "machine/reg.h" 1837520Smckusick #include "machine/psl.h" 1948438Skarels #include "vm/vm.h" 2047543Skarels #include "vm/vm_page.h" 2137520Smckusick 2248438Skarels #include "user.h" 2348438Skarels 247501Sroot /* 257501Sroot * Priority for tracing 267501Sroot */ 277501Sroot #define IPCPRI PZERO 287501Sroot 297501Sroot /* 307501Sroot * Tracing variables. 317501Sroot * Used to pass trace command from 327501Sroot * parent to child being traced. 337501Sroot * This data base cannot be 347501Sroot * shared and is locked 357501Sroot * per user. 367501Sroot */ 377501Sroot struct { 387501Sroot int ip_lock; 397501Sroot int ip_req; 407501Sroot int *ip_addr; 417501Sroot int ip_data; 427501Sroot } ipc; 437501Sroot 447501Sroot /* 4549674Smckusick * Process debugging system call. 467501Sroot */ 4743378Smckusick ptrace(curp, uap, retval) 4843378Smckusick struct proc *curp; 4943378Smckusick register struct args { 507501Sroot int req; 517501Sroot int pid; 527501Sroot int *addr; 537501Sroot int data; 547501Sroot } *uap; 5543378Smckusick int *retval; 5643378Smckusick { 5743378Smckusick register struct proc *p; 58*54340Smckusick int error; 597501Sroot 60*54340Smckusick p = pfind(uap->pid); 61*54340Smckusick if (uap->req == PT_ATTACH) { 62*54340Smckusick /* 63*54340Smckusick * Must be root if the process has used set user or 64*54340Smckusick * group privileges or does not belong to the real 65*54340Smckusick * user. Must not be already traced. 66*54340Smckusick */ 67*54340Smckusick if ((p->p_flag & SUGID || 68*54340Smckusick p->p_cred->p_ruid != curp->p_cred->p_ruid) && 69*54340Smckusick (error = suser(p->p_ucred, &p->p_acflag)) != 0) 70*54340Smckusick return (error); 71*54340Smckusick if (p->p_flag & STRC) 72*54340Smckusick return (EALREADY); /* ??? */ 73*54340Smckusick /* 74*54340Smckusick * It would be nice if the tracing relationship was separate 75*54340Smckusick * from the parent relationship but that would require 76*54340Smckusick * another set of links in the proc struct or for "wait" 77*54340Smckusick * to scan the entire proc table. To make life easier, 78*54340Smckusick * we just re-parent the process we're trying to trace. 79*54340Smckusick * The old parent is remembered so we can put things back 80*54340Smckusick * on a "detach". 81*54340Smckusick */ 82*54340Smckusick p->p_flag |= STRC; 83*54340Smckusick p->p_oppid = p->p_pptr->p_pid; 84*54340Smckusick proc_reparent(p, curp); 85*54340Smckusick psignal(p, SIGSTOP); 86*54340Smckusick return (0); 87*54340Smckusick } 887501Sroot if (uap->req <= 0) { 8943378Smckusick curp->p_flag |= STRC; 9044405Skarels return (0); 917501Sroot } 9247543Skarels if (p == 0 || p->p_stat != SSTOP || p->p_pptr != curp || 9343378Smckusick !(p->p_flag & STRC)) 9444405Skarels return (ESRCH); 957501Sroot while (ipc.ip_lock) 967501Sroot sleep((caddr_t)&ipc, IPCPRI); 977501Sroot ipc.ip_lock = p->p_pid; 987501Sroot ipc.ip_data = uap->data; 997501Sroot ipc.ip_addr = uap->addr; 1007501Sroot ipc.ip_req = uap->req; 1017501Sroot p->p_flag &= ~SWTED; 1027501Sroot while (ipc.ip_req > 0) { 1037501Sroot if (p->p_stat==SSTOP) 1047501Sroot setrun(p); 1057501Sroot sleep((caddr_t)&ipc, IPCPRI); 1067501Sroot } 10743378Smckusick *retval = ipc.ip_data; 1087501Sroot ipc.ip_lock = 0; 1097501Sroot wakeup((caddr_t)&ipc); 11043378Smckusick if (ipc.ip_req < 0) 11144405Skarels return (EIO); 11244405Skarels return (0); 1137501Sroot } 1147501Sroot 11549246Skarels #define PHYSOFF(p, o) ((caddr_t)(p) + (o)) 11649246Skarels 11745882Swilliam #if defined(i386) 11845882Swilliam #undef PC 11945882Swilliam #undef SP 12045882Swilliam #undef PS 12145882Swilliam #undef R0 12245882Swilliam #undef R1 1238952Sroot 12445882Swilliam #define PC tEIP 12545882Swilliam #define SP tESP 12645882Swilliam #define PS tEFLAGS 12745882Swilliam #define R0 tEDX 12845882Swilliam #define R1 tECX 12945882Swilliam #endif 13045882Swilliam 1317501Sroot /* 13249674Smckusick * Transmit a tracing request from the parent to the child process 13349674Smckusick * being debugged. This code runs in the context of the child process 13449674Smckusick * to fulfill the command requested by the parent. 1357501Sroot */ 13642928Smckusick procxmt(p) 13742928Smckusick register struct proc *p; 1387501Sroot { 13942928Smckusick register int i, *poff; 14049246Skarels extern char kstack[]; 1417501Sroot 14242928Smckusick if (ipc.ip_lock != p->p_pid) 1437501Sroot return (0); 14442928Smckusick p->p_slptime = 0; 14552374Smckusick p->p_addr->u_kproc.kp_proc.p_md.md_regs = p->p_md.md_regs; /* u.u_ar0 */ 1467501Sroot i = ipc.ip_req; 1477501Sroot ipc.ip_req = 0; 1487501Sroot switch (i) { 1497501Sroot 15026278Skarels case PT_READ_I: /* read the child's text space */ 1517501Sroot if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) 1527501Sroot goto error; 1537501Sroot ipc.ip_data = fuiword((caddr_t)ipc.ip_addr); 1547501Sroot break; 1557501Sroot 15626278Skarels case PT_READ_D: /* read the child's data space */ 1577501Sroot if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) 1587501Sroot goto error; 1597501Sroot ipc.ip_data = fuword((caddr_t)ipc.ip_addr); 1607501Sroot break; 1617501Sroot 16226278Skarels case PT_READ_U: /* read the child's u. */ 16341991Smckusick #ifdef HPUXCOMPAT 16449101Skarels if (p->p_addr->u_pcb.pcb_flags & PCB_HPUXTRACE) 16541991Smckusick i = hpuxtobsduoff(ipc.ip_addr); 16641991Smckusick else 16741991Smckusick #endif 1687501Sroot i = (int)ipc.ip_addr; 16949246Skarels if ((u_int) i > ctob(UPAGES)-sizeof(int) || (i & 1) != 0) 1707501Sroot goto error; 17149101Skarels ipc.ip_data = *(int *)PHYSOFF(p->p_addr, i); 1727501Sroot break; 1737501Sroot 17426278Skarels case PT_WRITE_I: /* write the child's text space */ 1758952Sroot if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) { 17645735Smckusick vm_offset_t sa, ea; 17745735Smckusick int rv; 17845735Smckusick 17945735Smckusick sa = trunc_page((vm_offset_t)ipc.ip_addr); 18045735Smckusick ea = round_page((vm_offset_t)ipc.ip_addr+sizeof(int)-1); 18147543Skarels rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea, 18245735Smckusick VM_PROT_DEFAULT, FALSE); 18345735Smckusick if (rv == KERN_SUCCESS) { 1848952Sroot i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data); 18547543Skarels (void) vm_map_protect(&p->p_vmspace->vm_map, 18647543Skarels sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, 18747543Skarels FALSE); 18845735Smckusick } 1898952Sroot } 1907501Sroot if (i < 0) 1917501Sroot goto error; 1927501Sroot break; 1937501Sroot 19426278Skarels case PT_WRITE_D: /* write the child's data space */ 1957501Sroot if (suword((caddr_t)ipc.ip_addr, 0) < 0) 1967501Sroot goto error; 1977501Sroot (void) suword((caddr_t)ipc.ip_addr, ipc.ip_data); 1987501Sroot break; 1997501Sroot 20026278Skarels case PT_WRITE_U: /* write the child's u. */ 20141991Smckusick #ifdef HPUXCOMPAT 20249101Skarels if (p->p_addr->u_pcb.pcb_flags & PCB_HPUXTRACE) 20341991Smckusick i = hpuxtobsduoff(ipc.ip_addr); 20441991Smckusick else 20541991Smckusick #endif 2067501Sroot i = (int)ipc.ip_addr; 20752178Smarc #ifdef mips 20852178Smarc poff = (int *)PHYSOFF(curproc->p_addr, i); 20952178Smarc #else 21049246Skarels poff = (int *)PHYSOFF(kstack, i); 21152178Smarc #endif 2128952Sroot for (i=0; i<NIPCREG; i++) 21352374Smckusick if (poff == &p->p_md.md_regs[ipcreg[i]]) 2147501Sroot goto ok; 21552374Smckusick if (poff == &p->p_md.md_regs[PS]) { 2168952Sroot ipc.ip_data |= PSL_USERSET; 21741991Smckusick ipc.ip_data &= ~PSL_USERCLR; 21832863Skarels #ifdef PSL_CM_CLR 21932863Skarels if (ipc.ip_data & PSL_CM) 22032863Skarels ipc.ip_data &= ~PSL_CM_CLR; 22132863Skarels #endif 2227501Sroot goto ok; 2237501Sroot } 22453873Smckusick #if defined(hp300) || defined(luna68k) 22541991Smckusick #ifdef FPCOPROC 22649246Skarels if (poff >= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_regs && 22749246Skarels poff <= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_fpiar) 22841991Smckusick goto ok; 22941991Smckusick #endif 23041991Smckusick #endif 2317501Sroot goto error; 2327501Sroot 2337501Sroot ok: 23442928Smckusick *poff = ipc.ip_data; 2357501Sroot break; 2367501Sroot 23726278Skarels case PT_STEP: /* single step the child */ 23826278Skarels case PT_CONTINUE: /* continue the child */ 239*54340Smckusick if ((unsigned)ipc.ip_data >= NSIG) 240*54340Smckusick goto error; 2417501Sroot if ((int)ipc.ip_addr != 1) 24252374Smckusick p->p_md.md_regs[PC] = (int)ipc.ip_addr; 24343895Skarels p->p_xstat = ipc.ip_data; /* see issig */ 24452178Smarc #ifdef PSL_T 24552178Smarc /* need something more machine independent here... */ 24626278Skarels if (i == PT_STEP) 24752374Smckusick p->p_md.md_regs[PS] |= PSL_T; 24852178Smarc #endif 2497501Sroot wakeup((caddr_t)&ipc); 2507501Sroot return (1); 2517501Sroot 25226278Skarels case PT_KILL: /* kill the child process */ 2537501Sroot wakeup((caddr_t)&ipc); 25445111Smckusick exit(p, (int)p->p_xstat); 2557501Sroot 256*54340Smckusick case PT_DETACH: /* stop tracing the child */ 257*54340Smckusick if ((unsigned)ipc.ip_data >= NSIG) 258*54340Smckusick goto error; 259*54340Smckusick if ((int)ipc.ip_addr != 1) 260*54340Smckusick p->p_md.md_regs[PC] = (int)ipc.ip_addr; 261*54340Smckusick p->p_xstat = ipc.ip_data; /* see issig */ 262*54340Smckusick p->p_flag &= ~STRC; 263*54340Smckusick if (p->p_oppid != p->p_pptr->p_pid) { 264*54340Smckusick register struct proc *pp = pfind(p->p_oppid); 265*54340Smckusick 266*54340Smckusick if (pp) 267*54340Smckusick proc_reparent(p, pp); 268*54340Smckusick } 269*54340Smckusick p->p_oppid = 0; 270*54340Smckusick wakeup((caddr_t)&ipc); 271*54340Smckusick return (1); 272*54340Smckusick 2737501Sroot default: 2747501Sroot error: 2757501Sroot ipc.ip_req = -1; 2767501Sroot } 2777501Sroot wakeup((caddr_t)&ipc); 2787501Sroot return (0); 2797501Sroot } 28049534Smckusick 28149674Smckusick /* 28249674Smckusick * Process debugging system call. 28349674Smckusick */ 28449534Smckusick /* ARGSUSED */ 28549534Smckusick profil(p, uap, retval) 28649534Smckusick struct proc *p; 28749534Smckusick register struct args { 28849534Smckusick short *bufbase; 28949534Smckusick unsigned bufsize; 29049534Smckusick unsigned pcoffset; 29149534Smckusick unsigned pcscale; 29249534Smckusick } *uap; 29349534Smckusick int *retval; 29449534Smckusick { 29549534Smckusick register struct uprof *upp = &p->p_stats->p_prof; 29649534Smckusick 29749534Smckusick upp->pr_base = uap->bufbase; 29849534Smckusick upp->pr_size = uap->bufsize; 29949534Smckusick upp->pr_off = uap->pcoffset; 30049534Smckusick upp->pr_scale = uap->pcscale; 30154131Smckusick if (uap->pcscale) 30254131Smckusick startprofclock(p); 30349534Smckusick return (0); 30449534Smckusick } 305