From owner-svn-src-head@FreeBSD.ORG Tue Jan 25 10:59:21 2011 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id B9FAD106567A; Tue, 25 Jan 2011 10:59:21 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id A86188FC19; Tue, 25 Jan 2011 10:59:21 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id p0PAxLGo029335; Tue, 25 Jan 2011 10:59:21 GMT (envelope-from kib@svn.freebsd.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id p0PAxLTG029327; Tue, 25 Jan 2011 10:59:21 GMT (envelope-from kib@svn.freebsd.org) Message-Id: <201101251059.p0PAxLTG029327@svn.freebsd.org> From: Konstantin Belousov Date: Tue, 25 Jan 2011 10:59:21 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r217819 - in head/sys: kern sys X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 25 Jan 2011 10:59:21 -0000 Author: kib Date: Tue Jan 25 10:59:21 2011 New Revision: 217819 URL: http://svn.freebsd.org/changeset/base/217819 Log: Allow debugger to specify that children of the traced process should be automatically traced. Extend the ptrace(PL_LWPINFO) to report that child just forked. Reviewed by: davidxu, jhb MFC after: 2 weeks Modified: head/sys/kern/kern_fork.c head/sys/kern/kern_proc.c head/sys/kern/kern_sig.c head/sys/kern/subr_trap.c head/sys/kern/sys_process.c head/sys/sys/proc.h head/sys/sys/ptrace.h Modified: head/sys/kern/kern_fork.c ============================================================================== --- head/sys/kern/kern_fork.c Tue Jan 25 10:20:36 2011 (r217818) +++ head/sys/kern/kern_fork.c Tue Jan 25 10:59:21 2011 (r217819) @@ -338,7 +338,7 @@ do_fork(struct thread *td, int flags, st struct vmspace *vm2) { struct proc *p1, *pptr; - int trypid; + int p2_held, trypid; struct filedesc *fd; struct filedesc_to_leader *fdtol; struct sigacts *newsigacts; @@ -346,6 +346,7 @@ do_fork(struct thread *td, int flags, st sx_assert(&proctree_lock, SX_SLOCKED); sx_assert(&allproc_lock, SX_XLOCKED); + p2_held = 0; p1 = td->td_proc; /* @@ -632,6 +633,8 @@ do_fork(struct thread *td, int flags, st PROC_SLOCK(p2); p2->p_state = PRS_NORMAL; PROC_SUNLOCK(p2); + + PROC_LOCK(p1); #ifdef KDTRACE_HOOKS /* * Tell the DTrace fasttrap provider about the new process @@ -640,19 +643,33 @@ do_fork(struct thread *td, int flags, st * later on. */ if (dtrace_fasttrap_fork) { - PROC_LOCK(p1); PROC_LOCK(p2); dtrace_fasttrap_fork(p1, p2); PROC_UNLOCK(p2); - PROC_UNLOCK(p1); } #endif - - /* - * If RFSTOPPED not requested, make child runnable and add to - * run queue. - */ + if ((p1->p_flag & (P_TRACED | P_FOLLOWFORK)) == (P_TRACED | + P_FOLLOWFORK)) { + /* + * Arrange for debugger to receive the fork event. + * + * We can report PL_FLAG_FORKED regardless of + * P_FOLLOWFORK settings, but it does not make a sense + * for runaway child. + */ + td->td_dbgflags |= TDB_FORK; + td->td_dbg_forked = p2->p_pid; + PROC_LOCK(p2); + td2->td_dbgflags |= TDB_STOPATFORK; + _PHOLD(p2); + p2_held = 1; + PROC_UNLOCK(p2); + } if ((flags & RFSTOPPED) == 0) { + /* + * If RFSTOPPED not requested, make child runnable and + * add to run queue. + */ thread_lock(td2); TD_SET_CAN_RUN(td2); sched_add(td2, SRQ_BORING); @@ -662,7 +679,6 @@ do_fork(struct thread *td, int flags, st /* * Now can be swapped. */ - PROC_LOCK(p1); _PRELE(p1); PROC_UNLOCK(p1); @@ -673,11 +689,19 @@ do_fork(struct thread *td, int flags, st SDT_PROBE(proc, kernel, , create, p2, p1, flags, 0, 0); /* + * Wait until debugger is attached to child. + */ + PROC_LOCK(p2); + while ((td2->td_dbgflags & TDB_STOPATFORK) != 0) + cv_wait(&p2->p_dbgwait, &p2->p_mtx); + if (p2_held) + _PRELE(p2); + + /* * Preserve synchronization semantics of vfork. If waiting for * child to exec or exit, set P_PPWAIT on child, and sleep on our * proc (in case of exit). */ - PROC_LOCK(p2); while (p2->p_flag & P_PPWAIT) cv_wait(&p2->p_pwait, &p2->p_mtx); PROC_UNLOCK(p2); @@ -883,8 +907,37 @@ fork_exit(void (*callout)(void *, struct void fork_return(struct thread *td, struct trapframe *frame) { + struct proc *p, *dbg; + + if (td->td_dbgflags & TDB_STOPATFORK) { + p = td->td_proc; + sx_xlock(&proctree_lock); + PROC_LOCK(p); + if ((p->p_pptr->p_flag & (P_TRACED | P_FOLLOWFORK)) == + (P_TRACED | P_FOLLOWFORK)) { + /* + * If debugger still wants auto-attach for the + * parent's children, do it now. + */ + dbg = p->p_pptr->p_pptr; + p->p_flag |= P_TRACED; + p->p_oppid = p->p_pptr->p_pid; + proc_reparent(p, dbg); + sx_xunlock(&proctree_lock); + ptracestop(td, SIGSTOP); + } else { + /* + * ... otherwise clear the request. + */ + sx_xunlock(&proctree_lock); + td->td_dbgflags &= ~TDB_STOPATFORK; + cv_broadcast(&p->p_dbgwait); + } + PROC_UNLOCK(p); + } userret(td, frame); + #ifdef KTRACE if (KTRPOINT(td, KTR_SYSRET)) ktrsysret(SYS_fork, 0, 0); Modified: head/sys/kern/kern_proc.c ============================================================================== --- head/sys/kern/kern_proc.c Tue Jan 25 10:20:36 2011 (r217818) +++ head/sys/kern/kern_proc.c Tue Jan 25 10:59:21 2011 (r217819) @@ -230,6 +230,7 @@ proc_init(void *mem, int size, int flags mtx_init(&p->p_mtx, "process lock", NULL, MTX_DEF | MTX_DUPOK); mtx_init(&p->p_slock, "process slock", NULL, MTX_SPIN | MTX_RECURSE); cv_init(&p->p_pwait, "ppwait"); + cv_init(&p->p_dbgwait, "dbgwait"); TAILQ_INIT(&p->p_threads); /* all threads in proc */ EVENTHANDLER_INVOKE(process_init, p); p->p_stats = pstats_alloc(); Modified: head/sys/kern/kern_sig.c ============================================================================== --- head/sys/kern/kern_sig.c Tue Jan 25 10:20:36 2011 (r217818) +++ head/sys/kern/kern_sig.c Tue Jan 25 10:59:21 2011 (r217819) @@ -2393,6 +2393,10 @@ ptracestop(struct thread *td, int sig) p->p_xthread = td; p->p_flag |= (P_STOPPED_SIG|P_STOPPED_TRACE); sig_suspend_threads(td, p, 0); + if ((td->td_dbgflags & TDB_STOPATFORK) != 0) { + td->td_dbgflags &= ~TDB_STOPATFORK; + cv_broadcast(&p->p_dbgwait); + } stopme: thread_suspend_switch(td); if (!(p->p_flag & P_TRACED)) { Modified: head/sys/kern/subr_trap.c ============================================================================== --- head/sys/kern/subr_trap.c Tue Jan 25 10:20:36 2011 (r217818) +++ head/sys/kern/subr_trap.c Tue Jan 25 10:59:21 2011 (r217819) @@ -392,9 +392,9 @@ syscallret(struct thread *td, int error, */ STOPEVENT(p, S_SCX, sa->code); PTRACESTOP_SC(p, td, S_PT_SCX); - if (traced || (td->td_dbgflags & TDB_EXEC) != 0) { + if (traced || (td->td_dbgflags & (TDB_EXEC | TDB_FORK)) != 0) { PROC_LOCK(p); - td->td_dbgflags &= ~(TDB_SCX | TDB_EXEC); + td->td_dbgflags &= ~(TDB_SCX | TDB_EXEC | TDB_FORK); PROC_UNLOCK(p); } } Modified: head/sys/kern/sys_process.c ============================================================================== --- head/sys/kern/sys_process.c Tue Jan 25 10:20:36 2011 (r217818) +++ head/sys/kern/sys_process.c Tue Jan 25 10:59:21 2011 (r217819) @@ -94,6 +94,7 @@ struct ptrace_lwpinfo32 { sigset_t pl_siglist; /* LWP pending signal */ struct siginfo32 pl_siginfo; /* siginfo for signal */ char pl_tdname[MAXCOMLEN + 1]; /* LWP name. */ + int pl_child_pid; /* New child pid */ }; #endif @@ -476,6 +477,7 @@ ptrace_lwpinfo_to32(const struct ptrace_ pl32->pl_siglist = pl->pl_siglist; siginfo_to_siginfo32(&pl->pl_siginfo, &pl32->pl_siginfo); strcpy(pl32->pl_tdname, pl->pl_tdname); + pl32->pl_child_pid = pl->pl_child_pid; } #endif /* COMPAT_FREEBSD32 */ @@ -657,6 +659,7 @@ kern_ptrace(struct thread *td, int req, case PT_TO_SCE: case PT_TO_SCX: case PT_SYSCALL: + case PT_FOLLOW_FORK: case PT_DETACH: sx_xlock(&proctree_lock); proctree_locked = 1; @@ -852,6 +855,13 @@ kern_ptrace(struct thread *td, int req, td2->td_dbgflags &= ~TDB_SUSPEND; break; + case PT_FOLLOW_FORK: + if (data) + p->p_flag |= P_FOLLOWFORK; + else + p->p_flag &= ~P_FOLLOWFORK; + break; + case PT_STEP: case PT_CONTINUE: case PT_TO_SCE: @@ -912,7 +922,7 @@ kern_ptrace(struct thread *td, int req, if (pp == initproc) p->p_sigparent = SIGCHLD; } - p->p_flag &= ~(P_TRACED | P_WAITED); + p->p_flag &= ~(P_TRACED | P_WAITED | P_FOLLOWFORK); p->p_oppid = 0; /* should we send SIGCHLD? */ @@ -1118,6 +1128,10 @@ kern_ptrace(struct thread *td, int req, pl->pl_flags |= PL_FLAG_SCX; if (td2->td_dbgflags & TDB_EXEC) pl->pl_flags |= PL_FLAG_EXEC; + if (td2->td_dbgflags & TDB_FORK) { + pl->pl_flags |= PL_FLAG_FORKED; + pl->pl_child_pid = td2->td_dbg_forked; + } pl->pl_sigmask = td2->td_sigmask; pl->pl_siglist = td2->td_siglist; strcpy(pl->pl_tdname, td2->td_name); Modified: head/sys/sys/proc.h ============================================================================== --- head/sys/sys/proc.h Tue Jan 25 10:20:36 2011 (r217818) +++ head/sys/sys/proc.h Tue Jan 25 10:59:21 2011 (r217819) @@ -265,6 +265,7 @@ struct thread { int td_ng_outbound; /* (k) Thread entered ng from above. */ struct osd td_osd; /* (k) Object specific data. */ struct vm_map_entry *td_map_def_user; /* (k) Deferred entries. */ + pid_t td_dbg_forked; /* (c) Child pid for debugger. */ #define td_endzero td_rqindex /* Copied during fork1() or thread_sched_upcall(). */ @@ -374,6 +375,10 @@ do { \ #define TDB_SCE 0x00000008 /* Thread performs syscall enter */ #define TDB_SCX 0x00000010 /* Thread performs syscall exit */ #define TDB_EXEC 0x00000020 /* TDB_SCX from exec(2) family */ +#define TDB_FORK 0x00000040 /* TDB_SCX from fork(2) that created new + process */ +#define TDB_STOPATFORK 0x00000080 /* Stop at the return from fork (child + only) */ /* * "Private" flags kept in td_pflags: @@ -557,7 +562,9 @@ struct proc { STAILQ_HEAD(, ktr_request) p_ktr; /* (o) KTR event queue. */ LIST_HEAD(, mqueue_notifier) p_mqnotifier; /* (c) mqueue notifiers.*/ struct kdtrace_proc *p_dtrace; /* (*) DTrace-specific data. */ - struct cv p_pwait; /* (*) wait cv for exit/exec */ + struct cv p_pwait; /* (*) wait cv for exit/exec. */ + struct cv p_dbgwait; /* (*) wait cv for debugger attach + after fork. */ }; #define p_session p_pgrp->pg_session @@ -573,7 +580,7 @@ struct proc { #define P_ADVLOCK 0x00001 /* Process may hold a POSIX advisory lock. */ #define P_CONTROLT 0x00002 /* Has a controlling terminal. */ #define P_KTHREAD 0x00004 /* Kernel thread (*). */ -#define P_UNUSED0 0x00008 /* available. */ +#define P_FOLLOWFORK 0x00008 /* Attach parent debugger to children. */ #define P_PPWAIT 0x00010 /* Parent is waiting for child to exec/exit. */ #define P_PROFIL 0x00020 /* Has started profiling. */ #define P_STOPPROF 0x00040 /* Has thread requesting to stop profiling. */ Modified: head/sys/sys/ptrace.h ============================================================================== --- head/sys/sys/ptrace.h Tue Jan 25 10:20:36 2011 (r217818) +++ head/sys/sys/ptrace.h Tue Jan 25 10:59:21 2011 (r217819) @@ -63,6 +63,8 @@ #define PT_TO_SCX 21 #define PT_SYSCALL 22 +#define PT_FOLLOW_FORK 23 + #define PT_GETREGS 33 /* get general-purpose registers */ #define PT_SETREGS 34 /* set general-purpose registers */ #define PT_GETFPREGS 35 /* get floating-point registers */ @@ -104,10 +106,12 @@ struct ptrace_lwpinfo { #define PL_FLAG_SCX 0x08 /* syscall leave point */ #define PL_FLAG_EXEC 0x10 /* exec(2) succeeded */ #define PL_FLAG_SI 0x20 /* siginfo is valid */ +#define PL_FLAG_FORKED 0x40 /* new child */ sigset_t pl_sigmask; /* LWP signal mask */ sigset_t pl_siglist; /* LWP pending signal */ struct __siginfo pl_siginfo; /* siginfo for signal */ char pl_tdname[MAXCOMLEN + 1]; /* LWP name */ + int pl_child_pid; /* New child pid */ }; /* Argument structure for PT_VM_ENTRY. */