From 907a148c9fb470dbf8e24ed46c37ef13788929e6 Mon Sep 17 00:00:00 2001 From: zont Date: Wed, 12 Sep 2012 13:06:57 +0000 Subject: - 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 --- usr.bin/truss/main.c | 13 +++++++++---- usr.bin/truss/setup.c | 37 +++++++++++++++++++++++++++---------- usr.bin/truss/truss.h | 1 + 3 files changed, 37 insertions(+), 14 deletions(-) (limited to 'usr.bin') diff --git a/usr.bin/truss/main.c b/usr.bin/truss/main.c index d6a1edc..cb97293 100644 --- a/usr.bin/truss/main.c +++ b/usr.bin/truss/main.c @@ -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 { diff --git a/usr.bin/truss/setup.c b/usr.bin/truss/setup.c index 1ae300a..c855c33 100644 --- a/usr.bin/truss/setup.c +++ b/usr.bin/truss/setup.c @@ -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; diff --git a/usr.bin/truss/truss.h b/usr.bin/truss/truss.h index d09886e..7dd87f5 100644 --- a/usr.bin/truss/truss.h +++ b/usr.bin/truss/truss.h @@ -87,3 +87,4 @@ struct trussinfo #define S_EXIT 3 #define S_SIG 4 #define S_EXEC 5 +#define S_DETACHED 6 -- cgit v1.1