Author: zont
Date: Wed Sep 12 13:06:57 2012
New Revision: 240393
URL: http://svn.freebsd.org/changeset/base/240393

Log:
  - 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

Modified:
  head/usr.bin/truss/main.c
  head/usr.bin/truss/setup.c
  head/usr.bin/truss/truss.h

Modified: head/usr.bin/truss/main.c
==============================================================================
--- head/usr.bin/truss/main.c   Wed Sep 12 12:14:50 2012        (r240392)
+++ head/usr.bin/truss/main.c   Wed Sep 12 13:06:57 2012        (r240393)
@@ -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 {

Modified: head/usr.bin/truss/setup.c
==============================================================================
--- head/usr.bin/truss/setup.c  Wed Sep 12 12:14:50 2012        (r240392)
+++ head/usr.bin/truss/setup.c  Wed Sep 12 13:06:57 2012        (r240393)
@@ -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;

Modified: head/usr.bin/truss/truss.h
==============================================================================
--- head/usr.bin/truss/truss.h  Wed Sep 12 12:14:50 2012        (r240392)
+++ head/usr.bin/truss/truss.h  Wed Sep 12 13:06:57 2012        (r240393)
@@ -87,3 +87,4 @@ struct trussinfo
 #define        S_EXIT  3
 #define        S_SIG   4
 #define        S_EXEC  5
+#define        S_DETACHED      6
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to