Date: Mon, 6 Feb 2012 13:19:30 -0800 From: Dmitry Mikulin <dmitrym@juniper.net> To: Konstantin Belousov <kostikbel@gmail.com> Cc: freebsd-current Current <freebsd-current@freebsd.org>, Marcel Moolenaar <marcelm@juniper.net> Subject: Re: [ptrace] please review follow fork/exec changes Message-ID: <4F3043E2.6090607@juniper.net> In-Reply-To: <20120204204218.GC3283@deviant.kiev.zoral.com.ua> References: <749E238A-A85F-4264-9DEB-BCE1BBD21C9D@juniper.net> <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>
next in thread | previous in thread | raw e-mail | index | archive | help
--------------000108040008060709070606
Content-Type: text/plain; charset="ISO-8859-1"; format=flowed
Content-Transfer-Encoding: 7bit
> 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.
--------------000108040008060709070606
Content-Type: text/x-patch; name="follow-exec-2.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="follow-exec-2.diff"
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 */
--------------000108040008060709070606--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4F3043E2.6090607>
