When vforked child is traced, the debugging events are not generated

until child performs exec().  The behaviour is reasonable when a
debugger is the real parent, because the parent is stopped until
exec(), and sending a debugging event to the debugger would deadlock
both parent and child.

On the other hand, when debugger is not the parent of the vforked
child, not sending debugging signals makes it impossible to debug
across vfork.

Fix the issue by declining generating debug signals only when vfork()
was done and child called ptrace(PT_TRACEME).  Set a new process flag
P_PPTRACE from the attach code for PT_TRACEME, if P_PPWAIT flag is
set, which indicates that the process was created with vfork() and
still did not execed. Check P_PPTRACE from issignal(), instead of
refusing the trace outright for the P_PPWAIT case.  The scope of
P_PPTRACE is exactly contained in the scope of P_PPWAIT.

Found and tested by:  zont
Reviewed by:	pluknet
MFC after:	2 weeks
This commit is contained in:
Konstantin Belousov 2013-02-07 15:34:22 +00:00
parent ded5ea6a25
commit 888d4d4f86
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=246484
5 changed files with 6 additions and 3 deletions

View File

@ -640,7 +640,7 @@ do_execve(td, args, mac_p)
*/
p->p_flag |= P_EXEC;
if (p->p_pptr && (p->p_flag & P_PPWAIT)) {
p->p_flag &= ~P_PPWAIT;
p->p_flag &= ~(P_PPWAIT | P_PPTRACE);
cv_broadcast(&p->p_pwait);
}

View File

@ -266,7 +266,7 @@ exit1(struct thread *td, int rv)
PROC_LOCK(p);
rv = p->p_xstat; /* Event handler could change exit status */
stopprofclock(p);
p->p_flag &= ~(P_TRACED | P_PPWAIT);
p->p_flag &= ~(P_TRACED | P_PPWAIT | P_PPTRACE);
/*
* Stop the real interval timer. If the handler is currently

View File

@ -2618,7 +2618,7 @@ issignal(struct thread *td, int stop_allowed)
sigqueue_delete(&p->p_sigqueue, sig);
continue;
}
if (p->p_flag & P_TRACED && (p->p_flag & P_PPWAIT) == 0) {
if (p->p_flag & P_TRACED && (p->p_flag & P_PPTRACE) == 0) {
/*
* If traced, always stop.
* Remove old signal from queue before the stop.

View File

@ -822,6 +822,8 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
case PT_TRACE_ME:
/* set my trace flag and "owner" so it can read/write me */
p->p_flag |= P_TRACED;
if (p->p_flag & P_PPWAIT)
p->p_flag |= P_PPTRACE;
p->p_oppid = p->p_pptr->p_pid;
break;

View File

@ -636,6 +636,7 @@ struct proc {
#define P_INMEM 0x10000000 /* Loaded into memory. */
#define P_SWAPPINGOUT 0x20000000 /* Process is being swapped out. */
#define P_SWAPPINGIN 0x40000000 /* Process is being swapped in. */
#define P_PPTRACE 0x80000000 /* PT_TRACEME by vforked child. */
#define P_STOPPED (P_STOPPED_SIG|P_STOPPED_SINGLE|P_STOPPED_TRACE)
#define P_SHOULDSTOP(p) ((p)->p_flag & P_STOPPED)