diff options
author | jhb <jhb@FreeBSD.org> | 2016-08-19 20:17:57 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2016-08-19 20:17:57 +0000 |
commit | 55e600d7fb35ccff5c2a024b2f3392ba31cf48ab (patch) | |
tree | cbecbc986582be3d6cd89eaffbb67fb7f39cc6c5 /sys | |
parent | 434d74d442c17b75001187964603fd65517dc77c (diff) | |
download | FreeBSD-src-55e600d7fb35ccff5c2a024b2f3392ba31cf48ab.zip FreeBSD-src-55e600d7fb35ccff5c2a024b2f3392ba31cf48ab.tar.gz |
MFC 303001: Add PTRACE_VFORK to trace vfork events.
First, PL_FLAG_FORKED events now also set a PL_FLAG_VFORKED flag when
the new child was created via vfork() rather than fork(). Second, a
new PL_FLAG_VFORK_DONE event can now be enabled via the PTRACE_VFORK
event mask. This new stop is reported after the vfork parent resumes
due to the child calling exit or exec. Debuggers can use this stop to
reinsert breakpoints in the vfork parent process before it resumes.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_fork.c | 1 | ||||
-rw-r--r-- | sys/kern/subr_syscall.c | 8 | ||||
-rw-r--r-- | sys/kern/sys_process.c | 8 | ||||
-rw-r--r-- | sys/sys/proc.h | 1 | ||||
-rw-r--r-- | sys/sys/ptrace.h | 3 |
5 files changed, 19 insertions, 2 deletions
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index c7447fb..0f7dd2e 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -736,6 +736,7 @@ do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread * if (fr->fr_flags & RFPPWAIT) { td->td_pflags |= TDP_RFPPWAIT; td->td_rfppwait_p = p2; + td->td_dbgflags |= TDB_VFORK; } PROC_UNLOCK(p2); diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c index aad2a1e..3e2a3b3 100644 --- a/sys/kern/subr_syscall.c +++ b/sys/kern/subr_syscall.c @@ -242,5 +242,13 @@ again: cv_timedwait(&p2->p_pwait, &p2->p_mtx, hz); } PROC_UNLOCK(p2); + + if (td->td_dbgflags & TDB_VFORK) { + PROC_LOCK(p); + if (p->p_ptevents & PTRACE_VFORK) + ptracestop(td, SIGTRAP); + td->td_dbgflags &= ~TDB_VFORK; + PROC_UNLOCK(p); + } } } diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 751db15..7d2fd72 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -1000,7 +1000,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) } tmp = *(int *)addr; if ((tmp & ~(PTRACE_EXEC | PTRACE_SCE | PTRACE_SCX | - PTRACE_FORK | PTRACE_LWP)) != 0) { + PTRACE_FORK | PTRACE_LWP | PTRACE_VFORK)) != 0) { error = EINVAL; break; } @@ -1321,7 +1321,11 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) 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_VFORK) + pl->pl_flags |= PL_FLAG_VFORKED; + } else if ((td2->td_dbgflags & (TDB_SCX | TDB_VFORK)) == + TDB_VFORK) + pl->pl_flags |= PL_FLAG_VFORK_DONE; if (td2->td_dbgflags & TDB_CHILD) pl->pl_flags |= PL_FLAG_CHILD; if (td2->td_dbgflags & TDB_BORN) diff --git a/sys/sys/proc.h b/sys/sys/proc.h index e25a64b..6ab638b 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -422,6 +422,7 @@ do { \ #define TDB_CHILD 0x00000100 /* New child indicator for ptrace() */ #define TDB_BORN 0x00000200 /* New LWP indicator for ptrace() */ #define TDB_EXIT 0x00000400 /* Exiting LWP indicator for ptrace() */ +#define TDB_VFORK 0x00000800 /* vfork indicator for ptrace() */ #define TDB_FSTP 0x00001000 /* The thread is PT_ATTACH leader */ /* diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h index 0cf25e8..e2045c8 100644 --- a/sys/sys/ptrace.h +++ b/sys/sys/ptrace.h @@ -89,6 +89,7 @@ #define PTRACE_SYSCALL (PTRACE_SCE | PTRACE_SCX) #define PTRACE_FORK 0x0008 #define PTRACE_LWP 0x0010 +#define PTRACE_VFORK 0x0020 #define PTRACE_DEFAULT (PTRACE_EXEC) @@ -124,6 +125,8 @@ struct ptrace_lwpinfo { #define PL_FLAG_CHILD 0x80 /* I am from child */ #define PL_FLAG_BORN 0x100 /* new LWP */ #define PL_FLAG_EXITED 0x200 /* exiting LWP */ +#define PL_FLAG_VFORKED 0x400 /* new child via vfork */ +#define PL_FLAG_VFORK_DONE 0x800 /* vfork parent has resumed */ sigset_t pl_sigmask; /* LWP signal mask */ sigset_t pl_siglist; /* LWP pending signal */ struct __siginfo pl_siginfo; /* siginfo for signal */ |