Index: kern/kern_fork.c =================================================================== RCS file: /cvsroot/src/sys/kern/kern_fork.c,v retrieving revision 1.185 diff -u -u -r1.185 kern_fork.c --- kern/kern_fork.c 23 Aug 2011 13:01:25 -0000 1.185 +++ kern/kern_fork.c 1 Sep 2011 23:02:17 -0000 @@ -92,6 +92,7 @@ #include <sys/syscallargs.h> #include <sys/uidinfo.h> #include <sys/sdt.h> +#include <sys/ptrace.h> #include <uvm/uvm_extern.h> @@ -458,6 +459,36 @@ LIST_INSERT_HEAD(&parent->p_children, p2, p_sibling); p2->p_exitsig = exitsig; /* signal for parent on exit */ + if ((p1->p_slflag & (PSL_TRACEFORK|PSL_TRACED)) == + (PSL_TRACEFORK|PSL_TRACED)) { + p2->p_slflag |= PSL_TRACED; + p2->p_opptr = p2->p_pptr; +printf("p2=%d pp2=%d p1=%d pp1=%d\n", p2->p_pid, p1->p_pid, + p2->p_pptr->p_pid, p1->p_pptr->p_pid); + if (p2->p_pptr != p1->p_pptr) { + struct proc *parent1 = p2->p_pptr; + + if (parent1->p_lock < p2->p_lock) { + if (!mutex_tryenter(parent1->p_lock)) { + mutex_exit(p2->p_lock); + mutex_enter(parent1->p_lock); + } + } else if (parent1->p_lock > p2->p_lock) { + mutex_enter(parent1->p_lock); + } + parent1->p_slflag |= PSL_CHTRACED; + proc_reparent(p2, p1->p_pptr); + if (parent1->p_lock != p2->p_lock) + mutex_exit(parent1->p_lock); + } + + /* + * Set ptrace status. + */ + p1->p_fpid = p2->p_pid; + p2->p_fpid = p1->p_pid; + } + LIST_INSERT_AFTER(p1, p2, p_pglist); LIST_INSERT_HEAD(&allproc, p2, p_list); @@ -537,6 +568,13 @@ */ while (p2->p_lflag & PL_PPWAIT) cv_wait(&p1->p_waitcv, proc_lock); + + /* + * If we're tracing the child, alert the parent too. + */ + if ((p1->p_slflag & (PSL_TRACEFORK|PSL_TRACED)) == + (PSL_TRACEFORK|PSL_TRACED)) + psignal(p1, SIGSTOP); mutex_exit(proc_lock); Index: kern/sys_process.c =================================================================== RCS file: /cvsroot/src/sys/kern/sys_process.c,v retrieving revision 1.160 diff -u -u -r1.160 sys_process.c --- kern/sys_process.c 31 Aug 2011 22:58:39 -0000 1.160 +++ kern/sys_process.c 1 Sep 2011 23:02:18 -0000 @@ -175,6 +175,9 @@ #ifdef PT_SETFPREGS case PT_SETFPREGS: #endif + case PT_SET_EVENT_MASK: + case PT_GET_EVENT_MASK: + case PT_GET_PROCESS_STATE: #ifdef __HAVE_PTRACE_MACHDEP PTRACE_MACHDEP_REQUEST_CASES #endif @@ -236,6 +239,8 @@ struct uio uio; struct iovec iov; struct ptrace_io_desc piod; + struct ptrace_event pe; + struct ptrace_state ps; struct ptrace_lwpinfo pl; struct vmspace *vm; int error, write, tmp, req, pheld; @@ -376,6 +381,9 @@ #ifdef PT_STEP case PT_STEP: #endif + case PT_SET_EVENT_MASK: + case PT_GET_EVENT_MASK: + case PT_GET_PROCESS_STATE: /* * You can't do what you want to the process if: * (1) It's not being traced at all, @@ -698,6 +706,7 @@ t->p_opptr = NULL; } sendsig: + t->p_fpid = 0; /* Finally, deliver the requested signal (or none). */ if (t->p_stat == SSTOP) { /* @@ -760,6 +769,37 @@ signo = SIGSTOP; goto sendsig; + case PT_GET_EVENT_MASK: + if (SCARG(uap, data) != sizeof(pe)) + return EINVAL; + memset(&pe, 0, sizeof(pe)); + pe.pe_set_event = ISSET(t->p_slflag, PSL_TRACEFORK) ? + PTRACE_FORK : 0; + error = copyout(&pe, SCARG(uap, addr), sizeof(pe)); + break; + + case PT_SET_EVENT_MASK: + if (SCARG(uap, data) != sizeof(pe)) + return EINVAL; + if ((error = copyin(SCARG(uap, addr), &pe, sizeof(pe))) != 0) + return error; + if (pe.pe_set_event & PTRACE_FORK) + SET(t->p_slflag, PSL_TRACEFORK); + else + CLR(t->p_slflag, PSL_TRACEFORK); + break; + + case PT_GET_PROCESS_STATE: + if (SCARG(uap, data) != sizeof(ps)) + return EINVAL; + memset(&ps, 0, sizeof(ps)); + if (t->p_fpid) { + ps.pe_report_event = PTRACE_FORK; + ps.pe_other_pid = t->p_fpid; + } + error = copyout(&ps, SCARG(uap, addr), sizeof(ps)); + break; + case PT_LWPINFO: if (SCARG(uap, data) != sizeof(pl)) { error = EINVAL; Index: sys/proc.h =================================================================== RCS file: /cvsroot/src/sys/sys/proc.h,v retrieving revision 1.309 diff -u -u -r1.309 proc.h --- sys/proc.h 31 Aug 2011 22:58:39 -0000 1.309 +++ sys/proc.h 1 Sep 2011 23:02:19 -0000 @@ -290,6 +290,7 @@ sigpend_t p_sigpend; /* p: pending signals */ struct lcproc *p_lwpctl; /* p, a: _lwp_ctl() information */ pid_t p_ppid; /* :: cached parent pid */ + pid_t p_fpid; /* :: forked pid */ /* * End area that is zeroed on creation @@ -374,6 +375,7 @@ * These flags are kept in p_sflag and are protected by the proc_lock * and p_lock. Access from process context only. */ +#define PSL_TRACEFORK 0x00000001 /* traced process wants fork events */ #define PSL_TRACED 0x00000800 /* Debugged process being traced */ #define PSL_FSTRACE 0x00010000 /* Debugger process being traced by procfs */ #define PSL_CHTRACED 0x00400000 /* Child has been traced & reparented */ Index: sys/ptrace.h =================================================================== RCS file: /cvsroot/src/sys/sys/ptrace.h,v retrieving revision 1.43 diff -u -u -r1.43 ptrace.h --- sys/ptrace.h 31 Aug 2011 22:58:39 -0000 1.43 +++ sys/ptrace.h 1 Sep 2011 23:02:19 -0000 @@ -34,22 +34,60 @@ #ifndef _SYS_PTRACE_H_ #define _SYS_PTRACE_H_ -#define PT_TRACE_ME 0 /* child declares it's being traced */ -#define PT_READ_I 1 /* read word in child's I space */ -#define PT_READ_D 2 /* read word in child's D space */ -#define PT_WRITE_I 4 /* write word in child's I space */ -#define PT_WRITE_D 5 /* write word in child's D space */ -#define PT_CONTINUE 7 /* continue the child */ -#define PT_KILL 8 /* kill the child process */ -#define PT_ATTACH 9 /* attach to running process */ -#define PT_DETACH 10 /* detach from running process */ -#define PT_IO 11 /* do I/O to/from the stopped process */ -#define PT_DUMPCORE 12 /* make the child generate a core dump */ -#define PT_LWPINFO 13 /* get info about the LWP */ -#define PT_SYSCALL 14 /* stop on syscall entry/exit */ -#define PT_SYSCALLEMU 15 /* cancel syscall, tracer will emulate it */ -#define PT_FIRSTMACH 32 /* for machine-specific requests */ -#include <machine/ptrace.h> /* machine-specific requests, if any */ +#define PT_TRACE_ME 0 /* child declares it's being traced */ +#define PT_READ_I 1 /* read word in child's I space */ +#define PT_READ_D 2 /* read word in child's D space */ +#define PT_WRITE_I 4 /* write word in child's I space */ +#define PT_WRITE_D 5 /* write word in child's D space */ +#define PT_CONTINUE 7 /* continue the child */ +#define PT_KILL 8 /* kill the child process */ +#define PT_ATTACH 9 /* attach to running process */ +#define PT_DETACH 10 /* detach from running process */ +#define PT_IO 11 /* do I/O to/from the stopped process */ +#define PT_DUMPCORE 12 /* make child generate a core dump */ +#define PT_LWPINFO 13 /* get info about the LWP */ +#define PT_SYSCALL 14 /* stop on syscall entry/exit */ +#define PT_SYSCALLEMU 15 /* cancel syscall, tracer emulates it */ +#define PT_SET_EVENT_MASK 16 /* set the event mask, defined below */ +#define PT_GET_EVENT_MASK 17 /* get the event mask, defined below */ +#define PT_GET_PROCESS_STATE 18 /* get process state, defined below */ + +#define PT_FIRSTMACH 32 /* for machine-specific requests */ +#include <machine/ptrace.h> /* machine-specific requests, if any */ + +#define PT_STRINGS \ +/* 0 */ "PT_TRACE_ME", \ +/* 1 */ "PT_READ_I", \ +/* 2 */ "PT_READ_D", \ +/* 3 */ "*PT_INVALID_3*", \ +/* 4 */ "PT_WRITE_I", \ +/* 5 */ "PT_WRITE_D", \ +/* 6 */ "*PT_INVALID_6*", \ +/* 7 */ "PT_CONTINUE", \ +/* 8 */ "PT_KILL", \ +/* 9 */ "PT_ATTACH", \ +/* 10 */ "PT_DETACH", \ +/* 11 */ "PT_IO", \ +/* 12 */ "PT_DUMPCORE", \ +/* 13 */ "PT_LWPINFO", \ +/* 14 */ "PT_SYSCALL", \ +/* 15 */ "PT_SYSCALLEMU", \ +/* 16 */ "PT_SET_EVENT_MASK", \ +/* 17 */ "PT_GET_EVENT_MASK", \ +/* 18 */ "PT_GET_PROCESS_STATE", + +/* PT_{G,S}EVENT_MASK */ +typedef struct ptrace_event { + int pe_set_event; +} ptrace_event_t; + +/* PT_GET_PROCESS_STATE */ +typedef struct ptrace_state { + int pe_report_event; + pid_t pe_other_pid; +} ptrace_state_t; + +#define PTRACE_FORK 0x0001 /* Report forks */ /* * Argument structure for PT_IO. Index: arch/x86/x86/syscall.c =================================================================== RCS file: /cvsroot/src/sys/arch/x86/x86/syscall.c,v retrieving revision 1.3 diff -u -u -r1.3 syscall.c --- arch/x86/x86/syscall.c 21 Nov 2009 03:11:02 -0000 1.3 +++ arch/x86/x86/syscall.c 1 Sep 2011 23:02:19 -0000 @@ -67,6 +67,13 @@ { struct lwp *l = arg; struct trapframe *tf = l->l_md.md_regs; + struct proc *p = l->l_proc; + + if (p->p_slflag & PSL_TRACED) { + mutex_enter(proc_lock); + psignal(p, SIGSTOP); + mutex_exit(proc_lock); + } X86_TF_RAX(tf) = 0; X86_TF_RFLAGS(tf) &= ~PSL_C;