I see what is going on. The wait loop for P_PPWAIT in do_fork() simply
do not allow the ptracestop() in the syscall return path to be reached.
There seems to be more problems. In particular, I do not see anything
which would prevent the child from being reapped while the loop is
executing (assume that the parent is multithreaded and other thread
processed SIGCHLD and called wait).

Lets deal with these bugs after your proposal for interface changes is
dealt with.

OK.


Yes, I agree with the proposal to add flag to the child lwp info.
I think it will be easier if the flag is different from PL_FLAG_FORKED.
I named it PL_FLAG_CHILD.

PT_FOLLOW_EXEC is easy to implement, but my question is, how can debugger
operate (correctly) if it ignores exec events ? After exec, the whole
cached state of the debuggee must be invalidated, and since debugger
ignores the notification when the invalidation shall be done, it probably
gets very confused.

You're right, the debugger needs to handle exec() events implicitly when it 
starts up executables. The problem is that there is OS-independent machinery in 
gdb which handles statup fork-exec sequence differently from when the debuggee 
itself does an exec(). Basically in the event handling code I need to be able 
to distinguish app startup by gdb from an exec done by the app. Other OS-es 
have flags like PL_FLAG_EXEC set on demand: they have an equivalent of 
PT_FOLLOW_EXEC. I attached a modified patch that solves the problem. It tries 
to separate the always-on TDB_EXEC from the on-demand TDB_FOLLOWEXEC without 
changing existing functionality. Let me know if it's acceptable.

Another issue I'm investigating is that after the switch-over to the child gdb 
gets a SIGHUP when it continues the child. I think it has to do with the 
re-parenting/orphan business. I'll let you know what I find, but if you have an 
idea what might be causing it, please let me know.

Thanks.
Dmitry.



Index: kern/kern_exec.c
===================================================================
--- kern/kern_exec.c	(revision 231088)
+++ kern/kern_exec.c	(working copy)
@@ -890,6 +890,8 @@ exec_fail_dealloc:
 	if (error == 0) {
 		PROC_LOCK(p);
 		td->td_dbgflags |= TDB_EXEC;
+		if (p->p_flag & P_FOLLOWEXEC)
+			td->td_dbgflags |= TDB_FOLLOWEXEC;
 		PROC_UNLOCK(p);
 
 		/*
Index: kern/kern_fork.c
===================================================================
--- kern/kern_fork.c	(revision 231088)
+++ kern/kern_fork.c	(working copy)
@@ -1035,7 +1035,9 @@ fork_return(struct thread *td, struct trapframe *f
 			p->p_oppid = p->p_pptr->p_pid;
 			proc_reparent(p, dbg);
 			sx_xunlock(&proctree_lock);
+			td->td_dbgflags |= TDB_CHILD;
 			ptracestop(td, SIGSTOP);
+			td->td_dbgflags &= ~TDB_CHILD;
 		} else {
 			/*
 			 * ... otherwise clear the request.
Index: kern/sys_process.c
===================================================================
--- kern/sys_process.c	(revision 231088)
+++ 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;
@@ -873,6 +874,12 @@ kern_ptrace(struct thread *td, int req, pid_t pid,
 		else
 			p->p_flag &= ~P_FOLLOWFORK;
 		break;
+	case PT_FOLLOW_EXEC:
+		if (data)
+			p->p_flag &= ~P_FOLLOWEXEC;
+		else
+			p->p_flag |= P_FOLLOWEXEC;
+		break;
 
 	case PT_STEP:
 	case PT_CONTINUE:
@@ -936,7 +943,8 @@ kern_ptrace(struct thread *td, int req, pid_t pid,
 					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); */
@@ -1141,10 +1149,14 @@ kern_ptrace(struct thread *td, int req, pid_t pid,
 			pl->pl_flags |= PL_FLAG_SCX;
 		if (td2->td_dbgflags & TDB_EXEC)
 			pl->pl_flags |= PL_FLAG_EXEC;
+		if (td2->td_dbgflags & TDB_FOLLOWEXEC)
+			pl->pl_flags |= PL_FLAG_FOLLOWEXEC;
 		if (td2->td_dbgflags & TDB_FORK) {
 			pl->pl_flags |= PL_FLAG_FORKED;
 			pl->pl_child_pid = td2->td_dbg_forked;
 		}
+		if (td2->td_dbgflags & TDB_CHILD)
+			pl->pl_flags |= PL_FLAG_CHILD;
 		pl->pl_sigmask = td2->td_sigmask;
 		pl->pl_siglist = td2->td_siglist;
 		strcpy(pl->pl_tdname, td2->td_name);
Index: kern/subr_syscall.c
===================================================================
--- kern/subr_syscall.c	(revision 230847)
+++ kern/subr_syscall.c	(working copy)
@@ -216,7 +216,8 @@ syscallret(struct thread *td, int error, struct sy
 		    ((td->td_dbgflags & (TDB_FORK | TDB_EXEC)) != 0 ||
 		    (p->p_stops & S_PT_SCX) != 0))
 			ptracestop(td, SIGTRAP);
-		td->td_dbgflags &= ~(TDB_SCX | TDB_EXEC | TDB_FORK);
+		td->td_dbgflags &= 
+			~(TDB_SCX | TDB_EXEC | TDB_FOLLOWEXEC | TDB_FORK);
 		PROC_UNLOCK(p);
 	}
 }
Index: sys/proc.h
===================================================================
--- sys/proc.h	(revision 231088)
+++ sys/proc.h	(working copy)
@@ -384,6 +384,8 @@ do {									\
 				      process */
 #define	TDB_STOPATFORK	0x00000080 /* Stop at the return from fork (child
 				      only) */
+#define	TDB_CHILD	0x00000100 /* New child indicator for ptrace() */
+#define	TDB_FOLLOWEXEC	0x00000200 /* follow exec(2) */
 
 /*
  * "Private" flags kept in td_pflags:
@@ -613,6 +615,7 @@ struct proc {
 #define	P_HWPMC		0x800000 /* Process is using HWPMCs */
 
 #define	P_JAILED	0x1000000 /* Process is in jail. */
+#define	P_FOLLOWEXEC	0x2000000 /* Do not report execs with ptrace. */
 #define	P_INEXEC	0x4000000 /* Process is in execve(). */
 #define	P_STATCHILD	0x8000000 /* Child process stopped or exited. */
 #define	P_INMEM		0x10000000 /* Loaded into memory. */
Index: sys/ptrace.h
===================================================================
--- sys/ptrace.h	(revision 231088)
+++ 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,9 @@ 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	/* child born */
+#define	PL_FLAG_CHILD	0x80	/* I am from child */
+#define	PL_FLAG_FOLLOWEXEC	0x100	/* follow exec(2) */
 	sigset_t	pl_sigmask;	/* LWP signal mask */
 	sigset_t	pl_siglist;	/* LWP pending signal */
 	struct __siginfo pl_siginfo;	/* siginfo for signal */
_______________________________________________
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