All,

Please review the attached changes (done by Dmitry -- CC'd) to add support for
PT_FOLLOW_EXEC and cleanup PT_FOLLOW_FORK.

I'll commit this when there are no comments/objections.
Thanks,

-- 
Marcel Moolenaar
marc...@juniper.net

Index: sys/kern/kern_exit.c

===================================================================

--- sys/kern/kern_exit.c	(revision 225189)

+++ sys/kern/kern_exit.c	(working copy)

@@ -680,7 +680,7 @@ wait4(struct thread *td, struct wait_args *uap)

  */

 void

 proc_reap(struct thread *td, struct proc *p, int *status, int options,

-    struct rusage *rusage)

+    struct rusage *rusage, int child)

 {

 	struct proc *q, *t;

 

@@ -720,7 +720,6 @@ proc_reap(struct thread *td, struct proc *p, int *

 	if (p->p_oppid && (t = pfind(p->p_oppid)) != NULL) {

 		PROC_LOCK(p);

 		proc_reparent(p, t);

-		p->p_pptr->p_dbg_child--;

 		p->p_oppid = 0;

 		PROC_UNLOCK(p);

 		pksignal(t, SIGCHLD, p->p_ksi);

@@ -738,7 +737,10 @@ proc_reap(struct thread *td, struct proc *p, int *

 	sx_xlock(&allproc_lock);

 	LIST_REMOVE(p, p_list);	/* off zombproc */

 	sx_xunlock(&allproc_lock);

-	LIST_REMOVE(p, p_sibling);

+	if (child)

+		LIST_REMOVE(p, p_sibling);

+	else

+		LIST_REMOVE(p, p_orphan);

 	leavepgrp(p);

 #ifdef PROCDESC

 	if (p->p_procdesc != NULL)

@@ -859,7 +861,7 @@ loop:

 		nfound++;

 		PROC_SLOCK(p);

 		if (p->p_state == PRS_ZOMBIE) {

-			proc_reap(td, p, status, options, rusage);

+			proc_reap(td, p, status, options, rusage, 1);

 			return (0);

 		}

 		if ((p->p_flag & P_STOPPED_SIG) &&

@@ -893,16 +895,47 @@ loop:

 

 			if (status)

 				*status = SIGCONT;

+		}

+		PROC_UNLOCK(p);

+	}

+	LIST_FOREACH(p, &q->p_orphans, p_orphan) {

+		PROC_LOCK(p);

+		if (pid != WAIT_ANY &&

+		    p->p_pid != pid && p->p_pgid != -pid) {

+			PROC_UNLOCK(p);

+			continue;

+		}

+		if (p_canwait(td, p)) {

+			PROC_UNLOCK(p);

+			continue;

+		}

+

+		/*

+		 * This special case handles a kthread spawned by linux_clone

+		 * (see linux_misc.c).  The linux_wait4 and linux_waitpid

+		 * functions need to be able to distinguish between waiting

+		 * on a process and waiting on a thread.  It is a thread if

+		 * p_sigparent is not SIGCHLD, and the WLINUXCLONE option

+		 * signifies we want to wait for threads and not processes.

+		 */

+		if ((p->p_sigparent != SIGCHLD) ^

+		    ((options & WLINUXCLONE) != 0)) {

+			PROC_UNLOCK(p);

+			continue;

+		}

+

+		nfound++;

+		PROC_SLOCK(p);

+		if (p->p_state == PRS_ZOMBIE) {

+		  proc_reap(td, p, status, options, rusage, 0);

 			return (0);

 		}

+		PROC_SUNLOCK(p);

 		PROC_UNLOCK(p);

 	}

 	if (nfound == 0) {

 		sx_xunlock(&proctree_lock);

-		if (td->td_proc->p_dbg_child)

-			return (0);

-		else

-			return (ECHILD);

+		return (ECHILD);

 	}

 	if (options & WNOHANG) {

 		sx_xunlock(&proctree_lock);

@@ -932,6 +965,7 @@ proc_reparent(struct proc *child, struct proc *par

 #ifdef RACCT

 	int locked;

 #endif

+	struct proc *p;

 

 	sx_assert(&proctree_lock, SX_XLOCKED);

 	PROC_LOCK_ASSERT(child, MA_OWNED);

@@ -952,5 +986,17 @@ proc_reparent(struct proc *child, struct proc *par

 	PROC_UNLOCK(child->p_pptr);

 	LIST_REMOVE(child, p_sibling);

 	LIST_INSERT_HEAD(&parent->p_children, child, p_sibling);

+

+	LIST_FOREACH(p, &parent->p_orphans, p_orphan) {

+		if (p == child) {

+			LIST_REMOVE(child, p_orphan);

+			break;

+		}

+	}

+	if (child->p_flag & P_TRACED) {

+		LIST_INSERT_HEAD(&child->p_pptr->p_orphans, child, p_orphan);

+		PROC_UNLOCK(child);

+		PROC_LOCK(child);

+	}

 	child->p_pptr = parent;

 }

Index: sys/kern/kern_exec.c

===================================================================

--- sys/kern/kern_exec.c	(revision 225189)

+++ sys/kern/kern_exec.c	(working copy)

@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");

 #include <sys/priv.h>

 #include <sys/proc.h>

 #include <sys/pioctl.h>

+#include <sys/ptrace.h>

 #include <sys/namei.h>

 #include <sys/resourcevar.h>

 #include <sys/sdt.h>

@@ -895,16 +896,22 @@ exec_fail_dealloc:

 	free(imgp->freepath, M_TEMP);

 

 	if (error == 0) {

+		if ((p->p_flag & (P_TRACED | P_FOLLOWEXEC)) == 

+		    (P_TRACED |	P_FOLLOWEXEC)) {

+			PROC_LOCK(p);

+			td->td_dbgflags |= TDB_EXEC;

+			PROC_UNLOCK(p);

+		}

+ 		/*

+ 		 * Stop the process here if its stop event mask has

+ 		 * the S_EXEC bit set.

+ 		 */

+ 		STOPEVENT(p, S_EXEC, 0);

+		PTRACESTOP_SC(p, td, S_PT_EXEC);

 		PROC_LOCK(p);

-		td->td_dbgflags |= TDB_EXEC;

+		td->td_dbgflags &= ~TDB_EXEC;

 		PROC_UNLOCK(p);

-

-		/*

-		 * Stop the process here if its stop event mask has

-		 * the S_EXEC bit set.

-		 */

-		STOPEVENT(p, S_EXEC, 0);

-		goto done2;

+ 		goto done2;

 	}

 

 exec_fail:

Index: sys/kern/kern_fork.c

===================================================================

--- sys/kern/kern_fork.c	(revision 225189)

+++ sys/kern/kern_fork.c	(working copy)

@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");

 #include <sys/proc.h>

 #include <sys/procdesc.h>

 #include <sys/pioctl.h>

+#include <sys/ptrace.h>

 #include <sys/racct.h>

 #include <sys/resourcevar.h>

 #include <sys/sched.h>

@@ -590,6 +591,7 @@ do_fork(struct thread *td, int flags, struct proc

 	LIST_INSERT_AFTER(p1, p2, p_pglist);

 	PGRP_UNLOCK(p1->p_pgrp);

 	LIST_INIT(&p2->p_children);

+	LIST_INIT(&p2->p_orphans);

 

 	callout_init(&p2->p_itcallout, CALLOUT_MPSAFE);

 

@@ -702,7 +704,8 @@ do_fork(struct thread *td, int flags, struct proc

 		 * for runaway child.

 		 */

 		td->td_dbgflags |= TDB_FORK;

-		td->td_dbg_forked = p2->p_pid;

+		td2->td_dbgflags |= TDB_FORK;

+		td->td_dbg_forked = td2->td_dbg_forked = p2->p_pid;

 		td2->td_dbgflags |= TDB_STOPATFORK;

 		_PHOLD(p2);

 		p2_held = 1;

@@ -731,6 +734,13 @@ do_fork(struct thread *td, int flags, struct proc

 	knote_fork(&p1->p_klist, p2->p_pid);

 	SDT_PROBE(proc, kernel, , create, p2, p1, flags, 0, 0);

 

+	if (td->td_dbgflags & TDB_FORK) {

+		PTRACESTOP_SC(p1, td, S_PT_FORK);

+		PROC_LOCK(p1);

+		td->td_dbgflags &= ~TDB_FORK;

+		PROC_UNLOCK(p1);

+	}

+

 	/*

 	 * Wait until debugger is attached to child.

 	 */

@@ -797,6 +807,10 @@ fork1(struct thread *td, int flags, int pages, str

 

 	p1 = td->td_proc;

 

+	/* Don't do vfork while being traced. */

+	if (p1->p_flag & P_TRACED)

+		flags &= ~(RFPPWAIT | RFMEM);

+

 	/*

 	 * Here we don't create a new process, but we divorce

 	 * certain parts of a process from itself.

@@ -1066,6 +1080,7 @@ fork_return(struct thread *td, struct trapframe *f

 			proc_reparent(p, dbg);

 			sx_xunlock(&proctree_lock);

 			ptracestop(td, SIGSTOP);

+			td->td_dbgflags &= ~TDB_FORK;

 		} else {

 			/*

 			 * ... otherwise clear the request.

Index: sys/kern/sys_process.c

===================================================================

--- sys/kern/sys_process.c	(revision 225189)

+++ sys/kern/sys_process.c	(working copy)

@@ -660,6 +660,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid,

 	case PT_TO_SCX:

 	case PT_SYSCALL:

 	case PT_FOLLOW_FORK:

+	case PT_FOLLOW_EXEC:

 	case PT_DETACH:

 		sx_xlock(&proctree_lock);

 		proctree_locked = 1;

@@ -841,8 +842,6 @@ kern_ptrace(struct thread *td, int req, pid_t pid,

 		p->p_flag |= P_TRACED;

 		p->p_oppid = p->p_pptr->p_pid;

 		if (p->p_pptr != td->td_proc) {

-			/* Remember that a child is being debugged(traced). */

-			p->p_pptr->p_dbg_child++;

 			proc_reparent(p, td->td_proc);

 		}

 		data = SIGSTOP;

@@ -868,12 +867,28 @@ kern_ptrace(struct thread *td, int req, pid_t pid,

 		break;

 

 	case PT_FOLLOW_FORK:

-		if (data)

+		if (data) {

 			p->p_flag |= P_FOLLOWFORK;

-		else

+			p->p_stops |= S_PT_FORK;

+		}

+		else {

 			p->p_flag &= ~P_FOLLOWFORK;

+			p->p_stops &= ~S_PT_FORK;

+		}

 		break;

 

+	case PT_FOLLOW_EXEC:

+		if (data) {

+			p->p_flag |= P_FOLLOWEXEC;

+			p->p_stops |= S_PT_EXEC;

+		}

+		else {

+			p->p_flag &= ~P_FOLLOWEXEC;

+			p->p_stops &= ~S_PT_EXEC;

+		}

+		break;

+

+

 	case PT_STEP:

 	case PT_CONTINUE:

 	case PT_TO_SCE:

@@ -931,12 +946,12 @@ kern_ptrace(struct thread *td, int req, pid_t pid,

 					PROC_UNLOCK(pp);

 				PROC_LOCK(p);

 				proc_reparent(p, pp);

-				p->p_pptr->p_dbg_child--;

 				if (pp == initproc)

 					p->p_sigparent = SIGCHLD;

 			}

 			p->p_oppid = 0;

-			p->p_flag &= ~(P_TRACED | P_WAITED | P_FOLLOWFORK);

+			p->p_flag &= ~(P_TRACED | P_WAITED | P_FOLLOWFORK | 

+				       P_FOLLOWEXEC);

 

 			/* should we send SIGCHLD? */

 			/* childproc_continued(p); */

Index: sys/kern/sys_procdesc.c

===================================================================

--- sys/kern/sys_procdesc.c	(revision 225189)

+++ sys/kern/sys_procdesc.c	(working copy)

@@ -367,7 +367,7 @@ procdesc_close(struct file *fp, struct thread *td)

 		 * procdesc_reap().

 		 */

 		PROC_SLOCK(p);

-		proc_reap(curthread, p, NULL, 0, NULL);

+		proc_reap(curthread, p, NULL, 0, NULL, 0);

 	} else {

 		/*

 		 * If the process is not yet dead, we need to kill it, but we

Index: sys/sys/proc.h

===================================================================

--- sys/sys/proc.h	(revision 225189)

+++ sys/sys/proc.h	(working copy)

@@ -504,8 +504,6 @@ struct proc {

 /* The following fields are all zeroed upon creation in fork. */

 #define	p_startzero	p_oppid

 	pid_t		p_oppid;	/* (c + e) Save ppid in ptrace. XXX */

-	int		p_dbg_child;	/* (c + e) # of debugged children in

-							ptrace. */

 	struct vmspace	*p_vmspace;	/* (b) Address space. */

 	u_int		p_swtick;	/* (c) Tick when swapped in or out. */

 	struct itimerval p_realtimer;	/* (c) Alarm timer. */

@@ -573,6 +571,8 @@ struct proc {

 					   after fork. */

 	uint64_t	p_prev_runtime;	/* (c) Resource usage accounting. */

 	struct racct	*p_racct;	/* (b) Resource accounting. */

+	LIST_ENTRY(proc) p_orphan;	/* (e) List of orphan processes. */

+	LIST_HEAD(, proc) p_orphans;	/* (e) Pointer to list of orphans. */

 };

 

 #define	p_session	p_pgrp->pg_session

@@ -616,6 +616,7 @@ struct proc {

 #define	P_INMEM		0x10000000 /* Loaded into memory. */

 #define	P_SWAPPINGOUT	0x20000000 /* Process is being swapped out. */

 #define	P_SWAPPINGIN	0x40000000 /* Process is being swapped in. */

+#define	P_FOLLOWEXEC	0x80000000 /* Notify debugger of exec events. */

 

 #define	P_STOPPED	(P_STOPPED_SIG|P_STOPPED_SINGLE|P_STOPPED_TRACE)

 #define	P_SHOULDSTOP(p)	((p)->p_flag & P_STOPPED)

@@ -847,7 +848,7 @@ void	procinit(void);

 void	proc_linkup0(struct proc *p, struct thread *td);

 void	proc_linkup(struct proc *p, struct thread *td);

 void	proc_reap(struct thread *td, struct proc *p, int *status, int options,

-	    struct rusage *rusage);

+	    struct rusage *rusage, int child);

 void	proc_reparent(struct proc *child, struct proc *newparent);

 struct	pstats *pstats_alloc(void);

 void	pstats_fork(struct pstats *src, struct pstats *dst);

Index: sys/sys/ptrace.h

===================================================================

--- sys/sys/ptrace.h	(revision 225189)

+++ sys/sys/ptrace.h	(working copy)

@@ -64,6 +64,7 @@

 #define	PT_SYSCALL	22

 

 #define	PT_FOLLOW_FORK	23

+#define	PT_FOLLOW_EXEC  24

 

 #define PT_GETREGS      33	/* get general-purpose registers */

 #define PT_SETREGS      34	/* set general-purpose registers */

@@ -106,7 +107,7 @@ 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 */

+#define	PL_FLAG_FORKED	0x40	/* new child from fork() */

 	sigset_t	pl_sigmask;	/* LWP signal mask */

 	sigset_t	pl_siglist;	/* LWP pending signal */

 	struct __siginfo pl_siginfo;	/* siginfo for signal */

@@ -142,6 +143,8 @@ struct ptrace_vm_entry {

  */

 #define	S_PT_SCE	0x000010000

 #define	S_PT_SCX	0x000020000

+#define	S_PT_FORK	0x000040000

+#define	S_PT_EXEC	0x000080000

 

 int	ptrace_set_pc(struct thread *_td, unsigned long _addr);

 int	ptrace_single_step(struct thread *_td);

_______________________________________________
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "freebsd-current-unsubscr...@freebsd.org"

Reply via email to