svn commit: r218355 - in stable/8/sys: kern sys
Konstantin Belousov
kib at FreeBSD.org
Sat Feb 5 22:57:15 UTC 2011
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. */
More information about the svn-src-stable-8
mailing list