From owner-svn-src-stable-8@FreeBSD.ORG Sat Feb 5 22:57:15 2011 Return-Path: Delivered-To: svn-src-stable-8@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 646291065673; Sat, 5 Feb 2011 22:57:15 +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 51D388FC0A; Sat, 5 Feb 2011 22:57:15 +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 p15MvFl5044234; Sat, 5 Feb 2011 22:57:15 GMT (envelope-from kib@svn.freebsd.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id p15MvFPN044224; Sat, 5 Feb 2011 22:57:15 GMT (envelope-from kib@svn.freebsd.org) Message-Id: <201102052257.p15MvFPN044224@svn.freebsd.org> From: Konstantin Belousov Date: Sat, 5 Feb 2011 22:57:15 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r218355 - in stable/8/sys: kern sys X-BeenThere: svn-src-stable-8@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for only the 8-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 05 Feb 2011 22:57:15 -0000 Author: kib Date: Sat Feb 5 22:57:14 2011 New Revision: 218355 URL: http://svn.freebsd.org/changeset/base/218355 Log: MFC r217819: 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. To not change the struct thread layout, td_dbg_forked was placed at the end of the structure. Modified: stable/8/sys/kern/kern_fork.c stable/8/sys/kern/kern_kthread.c stable/8/sys/kern/kern_proc.c stable/8/sys/kern/kern_sig.c stable/8/sys/kern/kern_thr.c stable/8/sys/kern/subr_trap.c stable/8/sys/kern/sys_process.c stable/8/sys/sys/proc.h stable/8/sys/sys/ptrace.h Directory Properties: stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) Modified: stable/8/sys/kern/kern_fork.c ============================================================================== --- stable/8/sys/kern/kern_fork.c Sat Feb 5 22:54:37 2011 (r218354) +++ stable/8/sys/kern/kern_fork.c Sat Feb 5 22:57:14 2011 (r218355) @@ -206,7 +206,7 @@ fork1(td, flags, pages, procp) { struct proc *p1, *p2, *pptr; struct proc *newproc; - int ok, trypid; + int ok, p2_held, trypid; static int curfail, pidchecked = 0; static struct timeval lastfail; struct filedesc *fd; @@ -221,6 +221,7 @@ fork1(td, flags, pages, procp) if ((flags & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG)) return (EINVAL); + p2_held = 0; p1 = td->td_proc; /* @@ -527,6 +528,7 @@ again: __rangeof(struct thread, td_startzero, td_endzero)); bzero(&td2->td_rux, sizeof(td2->td_rux)); td2->td_map_def_user = NULL; + td2->td_dbg_forked = 0; bcopy(&td->td_startcopy, &td2->td_startcopy, __rangeof(struct thread, td_startcopy, td_endcopy)); @@ -734,11 +736,29 @@ again: p2->p_state = PRS_NORMAL; PROC_SUNLOCK(p2); - /* - * If RFSTOPPED not requested, make child runnable and add to - * run queue. - */ + PROC_LOCK(p1); + 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); @@ -748,7 +768,6 @@ again: /* * Now can be swapped. */ - PROC_LOCK(p1); _PRELE(p1); PROC_UNLOCK(p1); @@ -759,11 +778,19 @@ again: 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); @@ -856,8 +883,37 @@ fork_return(td, frame) 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: stable/8/sys/kern/kern_kthread.c ============================================================================== --- stable/8/sys/kern/kern_kthread.c Sat Feb 5 22:54:37 2011 (r218354) +++ stable/8/sys/kern/kern_kthread.c Sat Feb 5 22:57:14 2011 (r218355) @@ -265,6 +265,7 @@ kthread_add(void (*func)(void *), void * __rangeof(struct thread, td_startzero, td_endzero)); bzero(&newtd->td_rux, sizeof(newtd->td_rux)); newtd->td_map_def_user = NULL; + newtd->td_dbg_forked = 0; /* XXX check if we should zero. */ bcopy(&oldtd->td_startcopy, &newtd->td_startcopy, __rangeof(struct thread, td_startcopy, td_endcopy)); Modified: stable/8/sys/kern/kern_proc.c ============================================================================== --- stable/8/sys/kern/kern_proc.c Sat Feb 5 22:54:37 2011 (r218354) +++ stable/8/sys/kern/kern_proc.c Sat Feb 5 22:57:14 2011 (r218355) @@ -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: stable/8/sys/kern/kern_sig.c ============================================================================== --- stable/8/sys/kern/kern_sig.c Sat Feb 5 22:54:37 2011 (r218354) +++ stable/8/sys/kern/kern_sig.c Sat Feb 5 22:57:14 2011 (r218355) @@ -2425,6 +2425,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: stable/8/sys/kern/kern_thr.c ============================================================================== --- stable/8/sys/kern/kern_thr.c Sat Feb 5 22:54:37 2011 (r218354) +++ stable/8/sys/kern/kern_thr.c Sat Feb 5 22:57:14 2011 (r218355) @@ -201,6 +201,7 @@ create_thread(struct thread *td, mcontex __rangeof(struct thread, td_startzero, td_endzero)); bzero(&newtd->td_rux, sizeof(newtd->td_rux)); newtd->td_map_def_user = NULL; + newtd->td_dbg_forked = 0; bcopy(&td->td_startcopy, &newtd->td_startcopy, __rangeof(struct thread, td_startcopy, td_endcopy)); newtd->td_proc = td->td_proc; Modified: stable/8/sys/kern/subr_trap.c ============================================================================== --- stable/8/sys/kern/subr_trap.c Sat Feb 5 22:54:37 2011 (r218354) +++ stable/8/sys/kern/subr_trap.c Sat Feb 5 22:57:14 2011 (r218355) @@ -388,9 +388,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: stable/8/sys/kern/sys_process.c ============================================================================== --- stable/8/sys/kern/sys_process.c Sat Feb 5 22:54:37 2011 (r218354) +++ stable/8/sys/kern/sys_process.c Sat Feb 5 22:57:14 2011 (r218355) @@ -93,6 +93,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 @@ -519,6 +520,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 */ @@ -700,6 +702,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; @@ -906,6 +909,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: @@ -966,7 +976,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? */ @@ -1172,6 +1182,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: stable/8/sys/sys/proc.h ============================================================================== --- stable/8/sys/sys/proc.h Sat Feb 5 22:54:37 2011 (r218354) +++ stable/8/sys/sys/proc.h Sat Feb 5 22:57:14 2011 (r218355) @@ -305,6 +305,7 @@ struct thread { const char *td_vnet_lpush; /* (k) Debugging vnet push / pop. */ struct rusage_ext td_rux; /* (t) Internal rusage information. */ struct vm_map_entry *td_map_def_user; /* (k) Deferred entries. */ + pid_t td_dbg_forked; /* (c) Child pid for debugger. */ }; struct mtx *thread_lock_block(struct thread *); @@ -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: stable/8/sys/sys/ptrace.h ============================================================================== --- stable/8/sys/sys/ptrace.h Sat Feb 5 22:54:37 2011 (r218354) +++ stable/8/sys/sys/ptrace.h Sat Feb 5 22:57:14 2011 (r218355) @@ -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. */