Handle followfork using ptrace_setoptions if available

If PTRACE_O_TRACECLONE et al options are supported by kernel,
use them to do followfork rather than the original setbpt
method that changes registers ourselves.

* defs.h [LINUX] (handle_new_child): New function prototype.
* process.c [LINUX] (handle_new_child): New function based on the
code from internal_fork(), with a trivial change: do reparent only
for sys_clone.
[LINUX] (internal_fork): Use handle_new_child().  Do nothing if
ptrace_setoptions is in effect.
* strace.c [LINUX] (handle_ptrace_event): New function.
[LINUX] (trace): If ptrace_setoptions is in effect, then
call the new function to handle PTRACE_EVENT_* status, and
set PTRACE_SETOPTIONS when we see the initial stop of tracee.

Signed-off-by: Wang Chao <wang.chao@cn.fujitsu.com>
diff --git a/strace.c b/strace.c
index 09aedac..6f63ee9 100644
--- a/strace.c
+++ b/strace.c
@@ -2363,6 +2363,31 @@
 }
 #endif
 
+#ifdef LINUX
+static int
+handle_ptrace_event(int status, struct tcb *tcp)
+{
+	if (status >> 16 == PTRACE_EVENT_VFORK ||
+	    status >> 16 == PTRACE_EVENT_CLONE ||
+	    status >> 16 == PTRACE_EVENT_FORK) {
+		int childpid;
+
+		if (do_ptrace(PTRACE_GETEVENTMSG, tcp, NULL, &childpid) < 0) {
+			if (errno != ESRCH) {
+				fprintf(stderr, "\
+%s: handle_ptrace_event: ptrace cannot get new child's pid\n",
+					progname);
+				cleanup();
+				exit(1);
+			}
+			return -1;
+		}
+		return handle_new_child(tcp, childpid, 0);
+	}
+	return 1;
+}
+#endif
+
 static int
 trace()
 {
@@ -2548,6 +2573,11 @@
 			fprintf(stderr, "pid %u stopped, [%s]\n",
 				pid, signame(WSTOPSIG(status)));
 
+		if (ptrace_setoptions && (status >> 16)) {
+			if (handle_ptrace_event(status, tcp) != 1)
+				goto tracing;
+		}
+
 		/*
 		 * Interestingly, the process may stop
 		 * with STOPSIG equal to some other signal
@@ -2575,6 +2605,13 @@
 					return -1;
 				}
 			}
+#ifdef LINUX
+			if (followfork && (tcp->parent == NULL) && ptrace_setoptions)
+				if (ptrace(PTRACE_SETOPTIONS, tcp->pid,
+					   NULL, ptrace_setoptions) < 0 &&
+				    errno != ESRCH)
+					ptrace_setoptions = 0;
+#endif
 			goto tracing;
 		}