[ptrace] please review follow fork/exec changes
Konstantin Belousov
kostikbel at gmail.com
Tue Feb 7 12:10:37 UTC 2012
On Mon, Feb 06, 2012 at 01:19:30PM -0800, Dmitry Mikulin wrote:
>
> >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.
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:
if (error == 0) {
PROC_LOCK(p);
- td->td_dbgflags |= TDB_EXEC;
+ if ((p->p_flag & P_TRACED) != 0 &&
+ ((P_FOLLOWEXEC) != 0 || (p->p_stops & S_PT_SCX) != 0))
+ td->td_dbgflags |= TDB_EXEC;
PROC_UNLOCK(p);
/*
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 *frame)
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.
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 = 1;
@@ -873,6 +874,12 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
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, void *addr, int data)
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); */
@@ -1145,6 +1153,8 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
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);
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() */
/*
* "Private" flags kept in td_pflags:
@@ -613,6 +614,7 @@ struct proc {
#define P_HWPMC 0x800000 /* Process is using HWPMCs */
#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
#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,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 */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 196 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-current/attachments/20120207/18e48e71/attachment.pgp
More information about the freebsd-current
mailing list