- Fix detaching under some circumstances.

When truss is detaching from very active process it is possible to
  hang on waitpid(2) in restore_proc() forever, because
  ptrace(PT_SYSCALL) must be called before detaching, to allow the
  debugging process to continue execution.  Also when truss called with
  '-c' argument, it does not print anything after detach, because it
  immediately exits from restore_proc().

  To fix these two problems make detaching deferred, but then it is
  impossible to detach from a process which does not do any system call.
  To fix this issue use sigaction(2) instead of signal(3) to disable
  SA_RESTART flag for waitpid(2) that makes it non-restartable.  Remove
  global variable child_pid, because now detaching is handled in context
  where child's pid is known.

Reported by:	mjg
Tested by:	mjg, swills
Approved by:	kib (mentor)
MFC after:	2 weeks
This commit is contained in:
Andrey Zonov 2012-09-12 13:06:57 +00:00
parent d1b835208a
commit 896fc4638a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=240393
3 changed files with 37 additions and 14 deletions

View File

@ -163,6 +163,7 @@ strsig(int sig)
int
main(int ac, char **av)
{
struct sigaction sa;
struct ex_types *funcs;
struct trussinfo *trussinfo;
char *fname;
@ -257,10 +258,13 @@ main(int ac, char **av)
signal(SIGTERM, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
} else {
sa.sa_handler = restore_proc;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
start_tracing(trussinfo->pid);
signal(SIGINT, restore_proc);
signal(SIGTERM, restore_proc);
signal(SIGQUIT, restore_proc);
}
@ -366,7 +370,8 @@ START_TRACE:
default:
break;
}
} while (trussinfo->pr_why != S_EXIT);
} while (trussinfo->pr_why != S_EXIT &&
trussinfo->pr_why != S_DETACHED);
if (trussinfo->flags & FOLLOWFORKS) {
do {

View File

@ -57,7 +57,7 @@ __FBSDID("$FreeBSD$");
#include "truss.h"
#include "extern.h"
static pid_t child_pid;
static sig_atomic_t detaching;
/*
* setup_and_wait() is called to start a process. All it really does
@ -84,8 +84,6 @@ setup_and_wait(char *command[])
if (waitpid(pid, NULL, 0) < 0)
err(1, "unexpect stop in waitpid");
child_pid = pid;
return (pid);
}
@ -108,7 +106,6 @@ start_tracing(pid_t pid)
if (ret)
err(1, "can not attach to target process");
child_pid = pid;
if (waitpid(pid, NULL, 0) < 0)
err(1, "Unexpect stop in waitpid");
@ -121,21 +118,30 @@ start_tracing(pid_t pid)
* applies if truss was told to monitor an already-existing
* process.
*/
void
restore_proc(int signo __unused)
{
detaching = 1;
}
static int
detach_proc(pid_t pid)
{
int waitval;
/* stop the child so that we can detach */
kill(child_pid, SIGSTOP);
if (waitpid(child_pid, &waitval, 0) < 0)
kill(pid, SIGSTOP);
if (waitpid(pid, &waitval, 0) < 0)
err(1, "Unexpected stop in waitpid");
if (ptrace(PT_DETACH, child_pid, (caddr_t)1, 0) < 0)
if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0)
err(1, "Can not detach the process");
kill(child_pid, SIGCONT);
exit(0);
kill(pid, SIGCONT);
return (waitval);
}
/*
@ -180,8 +186,19 @@ waitevent(struct trussinfo *info)
ptrace(PT_SYSCALL, info->pid, (caddr_t)1, pending_signal);
pending_signal = 0;
if (waitpid(info->pid, &waitval, 0) < 0)
detach:
if (detaching) {
waitval = detach_proc(info->pid);
info->pr_why = S_DETACHED;
info->pr_data = WEXITSTATUS(waitval);
return;
}
if (waitpid(info->pid, &waitval, 0) == -1) {
if (errno == EINTR)
goto detach;
err(1, "Unexpected stop in waitpid");
}
if (WIFCONTINUED(waitval)) {
info->pr_why = S_NONE;

View File

@ -87,3 +87,4 @@ struct trussinfo
#define S_EXIT 3
#define S_SIG 4
#define S_EXEC 5
#define S_DETACHED 6