Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 7 Feb 2012 14:10:22 +0200
From:      Konstantin Belousov <kostikbel@gmail.com>
To:        Dmitry Mikulin <dmitrym@juniper.net>
Cc:        freebsd-current Current <freebsd-current@freebsd.org>, Marcel Moolenaar <marcelm@juniper.net>
Subject:   Re: [ptrace] please review follow fork/exec changes
Message-ID:  <20120207121022.GC3283@deviant.kiev.zoral.com.ua>
In-Reply-To: <4F3043E2.6090607@juniper.net>
References:  <20120125074824.GD2726@deviant.kiev.zoral.com.ua> <4F2094B4.70707@juniper.net> <20120126122326.GT2726@deviant.kiev.zoral.com.ua> <4F22E8FD.6010201@juniper.net> <20120129074843.GL2726@deviant.kiev.zoral.com.ua> <4F26E0D1.8040100@juniper.net> <20120130192727.GZ2726@deviant.kiev.zoral.com.ua> <4F2C756A.80900@juniper.net> <20120204204218.GC3283@deviant.kiev.zoral.com.ua> <4F3043E2.6090607@juniper.net>

next in thread | previous in thread | raw e-mail | index | archive | help

--lmWPTIvm4M7zUP/T
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Mon, Feb 06, 2012 at 01:19:30PM -0800, Dmitry Mikulin wrote:
>=20
> >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.
>=20
> OK.
>=20
> >
> >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.
>=20
> You're right, the debugger needs to handle exec() events implicitly when =
it=20
> starts up executables. The problem is that there is OS-independent=20
> machinery in gdb which handles statup fork-exec sequence differently from=
=20
> when the debuggee itself does an exec(). Basically in the event handling=
=20
> code I need to be able to distinguish app startup by gdb from an exec don=
e=20
> by the app. Other OS-es have flags like PL_FLAG_EXEC set on demand: they=
=20
> have an equivalent of PT_FOLLOW_EXEC. I attached a modified patch that=20
> solves the problem. It tries to separate the always-on TDB_EXEC from the=
=20
> on-demand TDB_FOLLOWEXEC without changing existing functionality. Let me=
=20
> know if it's acceptable.

So, do you in fact need to distinguish exec stops from syscall exit
against exec stops from PT_FOLLOW_EXEC, or do you need to only get stops
at exec returns from PT_CONTINUE when explicitely requested them ?

I would prefer to not introduce another PL_FLAG_<something>EXEC with the
same semantic as PL_FLAG_EXEC. Instead, would the following patch be fine
for your purposes ? With it, stop on exec should only occur if PT_SCX
is requested, or PT_CONTINUE and PT_FOLLOW_EXEC.

[I am unable to fully test this until tomorrow].

diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 135f798..67cb1b2 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -56,6 +56,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/proc.h>
 #include <sys/pioctl.h>
 #include <sys/namei.h>
+#include <sys/ptrace.h>
 #include <sys/resourcevar.h>
 #include <sys/sdt.h>
 #include <sys/sf_buf.h>
@@ -889,7 +890,9 @@ exec_fail_dealloc:
=20
 	if (error =3D=3D 0) {
 		PROC_LOCK(p);
-		td->td_dbgflags |=3D TDB_EXEC;
+		if ((p->p_flag & P_TRACED) !=3D 0 &&
+		    ((P_FOLLOWEXEC) !=3D 0 || (p->p_stops & S_PT_SCX) !=3D 0))
+			td->td_dbgflags |=3D TDB_EXEC;
 		PROC_UNLOCK(p);
=20
 		/*
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 60639c9..e447c93 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1035,7 +1035,9 @@ fork_return(struct thread *td, struct trapframe *fram=
e)
 			p->p_oppid =3D p->p_pptr->p_pid;
 			proc_reparent(p, dbg);
 			sx_xunlock(&proctree_lock);
+			td->td_dbgflags |=3D TDB_CHILD;
 			ptracestop(td, SIGSTOP);
+			td->td_dbgflags &=3D ~TDB_CHILD;
 		} else {
 			/*
 			 * ... otherwise clear the request.
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 4510380..79bbaed 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -660,6 +660,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void=
 *addr, int data)
 	case PT_TO_SCX:
 	case PT_SYSCALL:
 	case PT_FOLLOW_FORK:
+	case PT_FOLLOW_EXEC:
 	case PT_DETACH:
 		sx_xlock(&proctree_lock);
 		proctree_locked =3D 1;
@@ -873,6 +874,12 @@ kern_ptrace(struct thread *td, int req, pid_t pid, voi=
d *addr, int data)
 		else
 			p->p_flag &=3D ~P_FOLLOWFORK;
 		break;
+	case PT_FOLLOW_EXEC:
+		if (data)
+			p->p_flag |=3D P_FOLLOWEXEC;
+		else
+			p->p_flag &=3D ~P_FOLLOWEXEC;
+		break;
=20
 	case PT_STEP:
 	case PT_CONTINUE:
@@ -936,7 +943,8 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void=
 *addr, int data)
 					p->p_sigparent =3D SIGCHLD;
 			}
 			p->p_oppid =3D 0;
-			p->p_flag &=3D ~(P_TRACED | P_WAITED | P_FOLLOWFORK);
+			p->p_flag &=3D ~(P_TRACED | P_WAITED | P_FOLLOWFORK |
+			    P_FOLLOWEXEC);
=20
 			/* should we send SIGCHLD? */
 			/* childproc_continued(p); */
@@ -1145,6 +1153,8 @@ kern_ptrace(struct thread *td, int req, pid_t pid, vo=
id *addr, int data)
 			pl->pl_flags |=3D PL_FLAG_FORKED;
 			pl->pl_child_pid =3D td2->td_dbg_forked;
 		}
+		if (td2->td_dbgflags & TDB_CHILD)
+			pl->pl_flags |=3D PL_FLAG_CHILD;
 		pl->pl_sigmask =3D td2->td_sigmask;
 		pl->pl_siglist =3D td2->td_siglist;
 		strcpy(pl->pl_tdname, td2->td_name);
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 9ebfe83..bec7223 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -384,6 +384,7 @@ do {									\
 				      process */
 #define	TDB_STOPATFORK	0x00000080 /* Stop at the return from fork (child
 				      only) */
+#define	TDB_CHILD	0x00000100 /* New child indicator for ptrace() */
=20
 /*
  * "Private" flags kept in td_pflags:
@@ -613,6 +614,7 @@ struct proc {
 #define	P_HWPMC		0x800000 /* Process is using HWPMCs */
=20
 #define	P_JAILED	0x1000000 /* Process is in jail. */
+#define	P_FOLLOWEXEC	0x2000000 /* 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. */
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
index 2583d59..05c758c 100644
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -64,6 +64,7 @@
 #define	PT_SYSCALL	22
=20
 #define	PT_FOLLOW_FORK	23
+#define	PT_FOLLOW_EXEC	24
=20
 #define PT_GETREGS      33	/* get general-purpose registers */
 #define PT_SETREGS      34	/* set general-purpose registers */
@@ -106,7 +107,8 @@ 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 */
 	sigset_t	pl_sigmask;	/* LWP signal mask */
 	sigset_t	pl_siglist;	/* LWP pending signal */
 	struct __siginfo pl_siginfo;	/* siginfo for signal */

--lmWPTIvm4M7zUP/T
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (FreeBSD)

iEYEARECAAYFAk8xFK4ACgkQC3+MBN1Mb4gpWwCbB1kzJxlazKuClYS12oyoeggT
gz8AoKZMLnE/W9E/eIzEzGJK7kP7I9fu
=EncL
-----END PGP SIGNATURE-----

--lmWPTIvm4M7zUP/T--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120207121022.GC3283>