Remove support for systems without PTRACE_SETOPTIONS

Assume that the kernel is v2.5.46 or newer, i.e. PTRACE_SETOPTIONS
and PTRACE_O_TRACESYSGOOD|PTRACE_O_TRACEEXEC|PTRACE_O_TRACECLONE
are universally available.

This change removes all code that implemented post-execve SIGTRAP
handling and fork/vfork/clone->CLONE_PTRACE substitution.

* defs.h (TCB_BPTSET, TCB_WAITEXECVE): Remove macros.
(need_fork_exec_workarounds, setbpt, clearbpt): Remove declarations.
* strace.c (need_fork_exec_workarounds,
test_ptrace_setoptions_followfork, test_ptrace_setoptions_for_all):
Remove.
(syscall_trap_sig): Set to (SIGTRAP | 0x80).
(ptrace_setoptions): Set to (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC).
(detach): Do not test for TCB_BPTSET.
(init): Do not call test_ptrace_setoptions_followfork and
test_ptrace_setoptions_for_all.  Do not test for TCB_BPTSET.
* syscall.c (syscall_fixup_on_sysenter, internal_fork, internal_exec,
syscall_fixup_for_fork_exec, syscall_fixup_on_sysexit): Remove.
(trace_syscall_entering): Do not test for TCB_WAITEXECVE.  Do not call
syscall_fixup_on_sysenter and syscall_fixup_for_fork_exec.
(trace_syscall_exiting): Do not call syscall_fixup_on_sysexit and
syscall_fixup_for_fork_exec.
[IA64] (ia64_ia32mode): Make static.
* linux/ia64/arch_regs.h (ia64_ia32mode): Remove declaration.
* util.c: Do not include "syscall.h".
(arg_setup, get_arg0, get_arg1, set_arg0, set_arg1, restore_arg0,
restore_arg1, arg_finish_change, change_syscall, setbpt, clearbpt):
Remove.
* tests/ptrace_setoptions.test: Remove.
* tests/Makefile.am (TESTS): Remove it.
diff --git a/defs.h b/defs.h
index 18cce3f..85c79f5 100644
--- a/defs.h
+++ b/defs.h
@@ -274,41 +274,13 @@
  * are limited to trace(), this condition is never observed in trace_syscall()
  * and below.
  * The bit is cleared after all syscall exit processing is done.
- * User-generated SIGTRAPs and post-execve SIGTRAP make it necessary
- * to be very careful and NOT set TCB_INSYSCALL bit when they are encountered.
- * TCB_WAITEXECVE bit is used for this purpose (see below).
  *
  * Use entering(tcp) / exiting(tcp) to check this bit to make code more readable.
  */
 #define TCB_INSYSCALL	0x04
 #define TCB_ATTACHED	0x08	/* We attached to it already */
-#define TCB_BPTSET	0x10	/* "Breakpoint" set after fork(2) */
-#define TCB_REPRINT	0x20	/* We should reprint this syscall on exit */
-#define TCB_FILTERED	0x40	/* This system call has been filtered out */
-/*
- * x86 does not need TCB_WAITEXECVE.
- * It can detect post-execve SIGTRAP by looking at eax/rax.
- * See "not a syscall entry (eax = %ld)\n" message.
- *
- * Note! On new kernels (about 2.5.46+), we use PTRACE_O_TRACEEXEC, which
- * suppresses post-execve SIGTRAP. If you are adding a new arch which is
- * only supported by newer kernels, you most likely don't need to define
- * TCB_WAITEXECVE!
- */
-#if defined(ALPHA) \
- || defined(SPARC) || defined(SPARC64) \
- || defined(POWERPC) \
- || defined(IA64) \
- || defined(HPPA) \
- || defined(SH) || defined(SH64) \
- || defined(S390) || defined(S390X) \
- || defined(ARM) \
- || defined(MIPS)
-/* This tracee has entered into execve syscall. Expect post-execve SIGTRAP
- * to happen. (When it is detected, tracee is continued and this bit is cleared.)
- */
-# define TCB_WAITEXECVE	0x80
-#endif
+#define TCB_REPRINT	0x10	/* We should reprint this syscall on exit */
+#define TCB_FILTERED	0x20	/* This system call has been filtered out */
 
 /* qualifier flags */
 #define QUAL_TRACE	0x001	/* this system call should be traced */
@@ -405,7 +377,6 @@
 /* are we filtering traces based on paths? */
 extern const char **paths_selected;
 #define tracing_paths (paths_selected != NULL)
-extern bool need_fork_exec_workarounds;
 extern unsigned xflag;
 extern unsigned followfork;
 #ifdef USE_LIBUNWIND
@@ -455,14 +426,6 @@
 #if defined(SPARC) || defined(SPARC64) || defined(IA64) || defined(SH)
 extern long getrval2(struct tcb *);
 #endif
-/*
- * On Linux, "setbpt" is a misnomer: we don't set a breakpoint
- * (IOW: no poking in user's text segment),
- * instead we change fork/vfork/clone into clone(CLONE_PTRACE).
- * On newer kernels, we use PTRACE_O_TRACECLONE/TRACE[V]FORK instead.
- */
-extern int setbpt(struct tcb *);
-extern int clearbpt(struct tcb *);
 
 extern const char *signame(const int);
 extern void pathtrace_select(const char *);
diff --git a/linux/ia64/arch_regs.h b/linux/ia64/arch_regs.h
index 519b24f..9855caf 100644
--- a/linux/ia64/arch_regs.h
+++ b/linux/ia64/arch_regs.h
@@ -1,4 +1,2 @@
 #include <asm/ptrace_offsets.h>
 #include <asm/rse.h>
-
-extern bool ia64_ia32mode;
diff --git a/strace.c b/strace.c
index 0e131a1..fccf4ad 100644
--- a/strace.c
+++ b/strace.c
@@ -74,18 +74,17 @@
 # define fork() vfork()
 #endif
 
+const unsigned int syscall_trap_sig = SIGTRAP | 0x80;
+
 cflag_t cflag = CFLAG_NONE;
 unsigned int followfork = 0;
-unsigned int ptrace_setoptions = 0;
+unsigned int ptrace_setoptions = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC;
 unsigned int xflag = 0;
-bool need_fork_exec_workarounds = 0;
 bool debug_flag = 0;
 bool Tflag = 0;
 bool iflag = 0;
 bool count_wallclock = 0;
 unsigned int qflag = 0;
-/* Which WSTOPSIG(status) value marks syscall traps? */
-static unsigned int syscall_trap_sig = SIGTRAP;
 static unsigned int tflag = 0;
 static bool rflag = 0;
 static bool print_pid_pfx = 0;
@@ -347,7 +346,7 @@
 	int r;
 	if (!use_seize)
 		return ptrace(PTRACE_ATTACH, pid, 0L, 0L);
-	r = ptrace(PTRACE_SEIZE, pid, 0L, (unsigned long)ptrace_setoptions);
+	r = ptrace(PTRACE_SEIZE, pid, 0L, (unsigned long) ptrace_setoptions);
 	if (r)
 		return r;
 	r = ptrace(PTRACE_INTERRUPT, pid, 0L, 0L);
@@ -766,9 +765,6 @@
 	int error;
 	int status;
 
-	if (tcp->flags & TCB_BPTSET)
-		clearbpt(tcp);
-
 	/*
 	 * Linux wrongly insists the child be stopped
 	 * before detaching.  Arghh.  We go through hoops
@@ -1321,219 +1317,6 @@
 	}
 }
 
-/*
- * Test whether the kernel support PTRACE_O_TRACECLONE et al options.
- * First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
- * and then see which options are supported by the kernel.
- */
-static int
-test_ptrace_setoptions_followfork(void)
-{
-	int pid, expected_grandchild = 0, found_grandchild = 0;
-	const unsigned int test_options = PTRACE_O_TRACECLONE |
-					  PTRACE_O_TRACEFORK |
-					  PTRACE_O_TRACEVFORK;
-
-	/* Need fork for test. NOMMU has no forks */
-	if (NOMMU_SYSTEM)
-		goto worked; /* be bold, and pretend that test succeeded */
-
-	pid = fork();
-	if (pid < 0)
-		perror_msg_and_die("fork");
-	if (pid == 0) {
-		pid = getpid();
-		if (ptrace(PTRACE_TRACEME, 0L, 0L, 0L) < 0)
-			perror_msg_and_die("%s: PTRACE_TRACEME doesn't work",
-					   __func__);
-		kill_save_errno(pid, SIGSTOP);
-		if (fork() < 0)
-			perror_msg_and_die("fork");
-		_exit(0);
-	}
-
-	while (1) {
-		int status, tracee_pid;
-
-		errno = 0;
-		tracee_pid = wait(&status);
-		if (tracee_pid <= 0) {
-			if (errno == EINTR)
-				continue;
-			if (errno == ECHILD)
-				break;
-			kill_save_errno(pid, SIGKILL);
-			perror_msg_and_die("%s: unexpected wait result %d",
-					   __func__, tracee_pid);
-		}
-		if (WIFEXITED(status)) {
-			if (WEXITSTATUS(status)) {
-				if (tracee_pid != pid)
-					kill_save_errno(pid, SIGKILL);
-				error_msg_and_die("%s: unexpected exit status %u",
-						  __func__, WEXITSTATUS(status));
-			}
-			continue;
-		}
-		if (WIFSIGNALED(status)) {
-			if (tracee_pid != pid)
-				kill_save_errno(pid, SIGKILL);
-			error_msg_and_die("%s: unexpected signal %u",
-					  __func__, WTERMSIG(status));
-		}
-		if (!WIFSTOPPED(status)) {
-			if (tracee_pid != pid)
-				kill_save_errno(tracee_pid, SIGKILL);
-			kill_save_errno(pid, SIGKILL);
-			error_msg_and_die("%s: unexpected wait status %x",
-					  __func__, status);
-		}
-		if (tracee_pid != pid) {
-			found_grandchild = tracee_pid;
-			if (ptrace(PTRACE_CONT, tracee_pid, 0, 0) < 0) {
-				kill_save_errno(tracee_pid, SIGKILL);
-				kill_save_errno(pid, SIGKILL);
-				perror_msg_and_die("PTRACE_CONT doesn't work");
-			}
-			continue;
-		}
-		switch (WSTOPSIG(status)) {
-		case SIGSTOP:
-			if (ptrace(PTRACE_SETOPTIONS, pid, 0, test_options) < 0
-			    && errno != EINVAL && errno != EIO)
-				perror_msg("PTRACE_SETOPTIONS");
-			break;
-		case SIGTRAP:
-			if (status >> 16 == PTRACE_EVENT_FORK) {
-				long msg = 0;
-
-				if (ptrace(PTRACE_GETEVENTMSG, pid,
-					   NULL, (long) &msg) == 0)
-					expected_grandchild = msg;
-			}
-			break;
-		}
-		if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) {
-			kill_save_errno(pid, SIGKILL);
-			perror_msg_and_die("PTRACE_SYSCALL doesn't work");
-		}
-	}
-	if (expected_grandchild && expected_grandchild == found_grandchild) {
- worked:
-		ptrace_setoptions |= test_options;
-		if (debug_flag)
-			fprintf(stderr, "ptrace_setoptions = %#x\n",
-				ptrace_setoptions);
-		return 0;
-	}
-	error_msg("Test for PTRACE_O_TRACECLONE failed, "
-		  "giving up using this feature.");
-	return 1;
-}
-
-/*
- * Test whether the kernel support PTRACE_O_TRACESYSGOOD.
- * First fork a new child, call ptrace(PTRACE_SETOPTIONS) on it,
- * and then see whether it will stop with (SIGTRAP | 0x80).
- *
- * Use of this option enables correct handling of user-generated SIGTRAPs,
- * and SIGTRAPs generated by special instructions such as int3 on x86:
-
-# compile with: gcc -nostartfiles -nostdlib -o int3 int3.S
-_start:		.globl	_start
-		int3
-		movl	$42, %ebx
-		movl	$1, %eax
-		int	$0x80
- */
-static int
-test_ptrace_setoptions_for_all(void)
-{
-	const unsigned int test_options = PTRACE_O_TRACESYSGOOD |
-					  PTRACE_O_TRACEEXEC;
-	int pid;
-	int it_worked = 0;
-
-	/* Need fork for test. NOMMU has no forks */
-	if (NOMMU_SYSTEM)
-		goto worked; /* be bold, and pretend that test succeeded */
-
-	pid = fork();
-	if (pid < 0)
-		perror_msg_and_die("fork");
-
-	if (pid == 0) {
-		pid = getpid();
-		if (ptrace(PTRACE_TRACEME, 0L, 0L, 0L) < 0)
-			/* Note: exits with exitcode 1 */
-			perror_msg_and_die("%s: PTRACE_TRACEME doesn't work",
-					   __func__);
-		kill(pid, SIGSTOP);
-		_exit(0); /* parent should see entry into this syscall */
-	}
-
-	while (1) {
-		int status, tracee_pid;
-
-		errno = 0;
-		tracee_pid = wait(&status);
-		if (tracee_pid <= 0) {
-			if (errno == EINTR)
-				continue;
-			kill_save_errno(pid, SIGKILL);
-			perror_msg_and_die("%s: unexpected wait result %d",
-					   __func__, tracee_pid);
-		}
-		if (WIFEXITED(status)) {
-			if (WEXITSTATUS(status) == 0)
-				break;
-			error_msg_and_die("%s: unexpected exit status %u",
-					  __func__, WEXITSTATUS(status));
-		}
-		if (WIFSIGNALED(status)) {
-			error_msg_and_die("%s: unexpected signal %u",
-					  __func__, WTERMSIG(status));
-		}
-		if (!WIFSTOPPED(status)) {
-			kill(pid, SIGKILL);
-			error_msg_and_die("%s: unexpected wait status %x",
-					  __func__, status);
-		}
-		if (WSTOPSIG(status) == SIGSTOP) {
-			/*
-			 * We don't check "options aren't accepted" error.
-			 * If it happens, we'll never get (SIGTRAP | 0x80),
-			 * and thus will decide to not use the option.
-			 * IOW: the outcome of the test will be correct.
-			 */
-			if (ptrace(PTRACE_SETOPTIONS, pid, 0L, test_options) < 0
-			    && errno != EINVAL && errno != EIO)
-				perror_msg("PTRACE_SETOPTIONS");
-		}
-		if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
-			it_worked = 1;
-		}
-		if (ptrace(PTRACE_SYSCALL, pid, 0L, 0L) < 0) {
-			kill_save_errno(pid, SIGKILL);
-			perror_msg_and_die("PTRACE_SYSCALL doesn't work");
-		}
-	}
-
-	if (it_worked) {
- worked:
-		syscall_trap_sig = (SIGTRAP | 0x80);
-		ptrace_setoptions |= test_options;
-		if (debug_flag)
-			fprintf(stderr, "ptrace_setoptions = %#x\n",
-				ptrace_setoptions);
-		return 0;
-	}
-
-	error_msg("Test for PTRACE_O_TRACESYSGOOD failed, "
-		  "giving up using this feature.");
-	return 1;
-}
-
 #if USE_SEIZE
 static void
 test_ptrace_seize(void)
@@ -1871,14 +1654,12 @@
 		run_gid = getgid();
 	}
 
-	/*
-	 * On any reasonably recent Linux kernel (circa about 2.5.46)
-	 * need_fork_exec_workarounds should stay 0 after these tests:
-	 */
-	/*need_fork_exec_workarounds = 0; - already is */
 	if (followfork)
-		need_fork_exec_workarounds = test_ptrace_setoptions_followfork();
-	need_fork_exec_workarounds |= test_ptrace_setoptions_for_all();
+		ptrace_setoptions |= PTRACE_O_TRACECLONE |
+				     PTRACE_O_TRACEFORK |
+				     PTRACE_O_TRACEVFORK;
+	if (debug_flag)
+		fprintf(stderr, "ptrace_setoptions = %#x\n", ptrace_setoptions);
 	test_ptrace_seize();
 
 	/* Check if they want to redirect the output. */
@@ -2226,20 +2007,7 @@
 
 	tcp->flags &= ~TCB_STARTUP;
 
-	if (tcp->flags & TCB_BPTSET) {
-		/*
-		 * One example is a breakpoint inherited from
-		 * parent through fork().
-		 */
-		if (clearbpt(tcp) < 0) {
-			/* Pretty fatal */
-			droptcb(tcp);
-			exit_code = 1;
-			return false;
-		}
-	}
-
-	if (!use_seize && ptrace_setoptions) {
+	if (!use_seize) {
 		if (debug_flag)
 			fprintf(stderr, "setting opts 0x%x on pid %d\n",
 				ptrace_setoptions, tcp->pid);
@@ -2460,7 +2228,6 @@
 
 	/*
 	 * This should be syscall entry or exit.
-	 * (Or it still can be that pesky post-execve SIGTRAP!)
 	 * Handle it.
 	 */
 	if (trace_syscall(tcp) < 0) {
diff --git a/syscall.c b/syscall.c
index c805774..70ba8a0 100644
--- a/syscall.c
+++ b/syscall.c
@@ -702,10 +702,10 @@
 # define ARCH_REGS_FOR_GETREGSET x86_regs_union
 # define ARCH_IOVEC_FOR_GETREGSET x86_io
 #elif defined(IA64)
-bool ia64_ia32mode = 0; /* not static */
+static bool ia64_ia32mode;
 static long ia64_r8, ia64_r10;
 #elif defined(POWERPC)
-struct pt_regs ppc_regs;
+struct pt_regs ppc_regs; /* not static */
 # define ARCH_REGS_FOR_GETREGS ppc_regs
 #elif defined(M68K)
 static long m68k_d0;
@@ -771,7 +771,7 @@
 #elif defined(CRISV10) || defined(CRISV32)
 static long cris_r10;
 #elif defined(TILE)
-struct pt_regs tile_regs;
+struct pt_regs tile_regs; /* not static */
 # define ARCH_REGS_FOR_GETREGS tile_regs
 #elif defined(MICROBLAZE)
 static long microblaze_r3;
@@ -1607,173 +1607,6 @@
 	return val >= max;
 }
 
-/* Called at each syscall entry.
- * Returns:
- * 0: "ignore this ptrace stop", bail out of trace_syscall_entering() silently.
- * 1: ok, continue in trace_syscall_entering().
- * other: error, trace_syscall_entering() should print error indicator
- *    ("????" etc) and bail out.
- */
-static int
-syscall_fixup_on_sysenter(struct tcb *tcp)
-{
-	/* Do we have post-execve SIGTRAP suppressed? */
-	if (ptrace_setoptions & PTRACE_O_TRACEEXEC)
-		return 1;
-
-	/*
-	 * No, unfortunately.  Apply -ENOSYS heuristics.
-	 * We don't have to workaround SECCOMP_RET_ERRNO side effects
-	 * because any kernel with SECCOMP_RET_ERRNO support surely
-	 * implements PTRACE_O_TRACEEXEC.
-	 */
-#if defined(I386)
-	if (i386_regs.eax != -ENOSYS) {
-		if (debug_flag)
-			fprintf(stderr, "not a syscall entry (eax = %ld)\n",
-				i386_regs.eax);
-		return 0;
-	}
-#elif defined(X86_64) || defined(X32)
-	if (x86_io.iov_len == sizeof(i386_regs)) {
-		if ((int) i386_regs.eax != -ENOSYS) {
-			if (debug_flag)
-				fprintf(stderr,
-					"not a syscall entry (eax = %d)\n",
-					(int) i386_regs.eax);
-			return 0;
-		}
-	} else {
-		if ((long long) x86_64_regs.rax != -ENOSYS) {
-			if (debug_flag)
-				fprintf(stderr,
-					"not a syscall entry (rax = %lld)\n",
-					(long long) x86_64_regs.rax);
-			return 0;
-		}
-	}
-#elif defined(M68K)
-	/* TODO? Eliminate upeek's in arches below like we did in x86 */
-	if (upeek(tcp->pid, 4*PT_D0, &m68k_d0) < 0)
-		return -1;
-	if (m68k_d0 != -ENOSYS) {
-		if (debug_flag)
-			fprintf(stderr, "not a syscall entry (d0 = %ld)\n", m68k_d0);
-		return 0;
-	}
-#elif defined(IA64)
-	if (upeek(tcp->pid, PT_R10, &ia64_r10) < 0)
-		return -1;
-	if (upeek(tcp->pid, PT_R8, &ia64_r8) < 0)
-		return -1;
-	if (ia64_ia32mode && ia64_r8 != -ENOSYS) {
-		if (debug_flag)
-			fprintf(stderr, "not a syscall entry (r8 = %ld)\n", ia64_r8);
-		return 0;
-	}
-#elif defined(CRISV10) || defined(CRISV32)
-	if (upeek(tcp->pid, 4*PT_R10, &cris_r10) < 0)
-		return -1;
-	if (cris_r10 != -ENOSYS) {
-		if (debug_flag)
-			fprintf(stderr, "not a syscall entry (r10 = %ld)\n", cris_r10);
-		return 0;
-	}
-#elif defined(MICROBLAZE)
-	if (upeek(tcp->pid, 3 * 4, &microblaze_r3) < 0)
-		return -1;
-	if (microblaze_r3 != -ENOSYS) {
-		if (debug_flag)
-			fprintf(stderr, "not a syscall entry (r3 = %ld)\n", microblaze_r3);
-		return 0;
-	}
-#endif
-	return 1;
-}
-
-static void
-internal_fork(struct tcb *tcp)
-{
-#if defined S390 || defined S390X || defined CRISV10 || defined CRISV32
-# define ARG_FLAGS	1
-#else
-# define ARG_FLAGS	0
-#endif
-#ifndef CLONE_UNTRACED
-# define CLONE_UNTRACED	0x00800000
-#endif
-	if ((ptrace_setoptions
-	    & (PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK))
-	   == (PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK))
-		return;
-
-	if (!followfork)
-		return;
-
-	if (entering(tcp)) {
-		/*
-		 * We won't see the new child if clone is called with
-		 * CLONE_UNTRACED, so we keep the same logic with that option
-		 * and don't trace it.
-		 */
-		if ((tcp->s_ent->sys_func == sys_clone)
-		 && (tcp->u_arg[ARG_FLAGS] & CLONE_UNTRACED)
-		)
-			return;
-		setbpt(tcp);
-	} else {
-		if (tcp->flags & TCB_BPTSET)
-			clearbpt(tcp);
-	}
-}
-
-#if defined(TCB_WAITEXECVE)
-static void
-internal_exec(struct tcb *tcp)
-{
-	/* Maybe we have post-execve SIGTRAP suppressed? */
-	if (ptrace_setoptions & PTRACE_O_TRACEEXEC)
-		return; /* yes, no need to do anything */
-
-	if (exiting(tcp) && syserror(tcp))
-		/* Error in execve, no post-execve SIGTRAP expected */
-		tcp->flags &= ~TCB_WAITEXECVE;
-	else
-		tcp->flags |= TCB_WAITEXECVE;
-}
-#endif
-
-static void
-syscall_fixup_for_fork_exec(struct tcb *tcp)
-{
-	/*
-	 * We must always trace a few critical system calls in order to
-	 * correctly support following forks in the presence of tracing
-	 * qualifiers.
-	 */
-	int (*func)();
-
-	func = tcp->s_ent->sys_func;
-
-	if (   sys_fork == func
-	    || sys_clone == func
-	   ) {
-		internal_fork(tcp);
-		return;
-	}
-
-#if defined(TCB_WAITEXECVE)
-	if (   sys_execve == func
-# if defined(SPARC) || defined(SPARC64)
-	    || sys_execv == func
-# endif
-	   ) {
-		internal_exec(tcp);
-		return;
-	}
-#endif
-}
-
 /* Return -1 on error or 1 on success (never 0!) */
 static int
 get_syscall_args(struct tcb *tcp)
@@ -2008,24 +1841,11 @@
 {
 	int res, scno_good;
 
-#if defined TCB_WAITEXECVE
-	if (tcp->flags & TCB_WAITEXECVE) {
-		/* This is the post-execve SIGTRAP. */
-		tcp->flags &= ~TCB_WAITEXECVE;
-		return 0;
-	}
-#endif
-
 	scno_good = res = (get_regs_error ? -1 : get_scno(tcp));
 	if (res == 0)
 		return res;
-	if (res == 1) {
-		res = syscall_fixup_on_sysenter(tcp);
-		if (res == 0)
-			return res;
-		if (res == 1)
-			res = get_syscall_args(tcp);
-	}
+	if (res == 1)
+		res = get_syscall_args(tcp);
 
 	if (res != 1) {
 		printleader(tcp);
@@ -2068,9 +1888,6 @@
 	}
 #endif
 
-	if (need_fork_exec_workarounds)
-		syscall_fixup_for_fork_exec(tcp);
-
 	if (!(tcp->qual_flg & QUAL_TRACE)
 	 || (tracing_paths && !pathtrace_match(tcp))
 	) {
@@ -2170,23 +1987,6 @@
 	return 1;
 }
 
-/* Called at each syscall exit */
-static void
-syscall_fixup_on_sysexit(struct tcb *tcp)
-{
-#if defined(S390) || defined(S390X)
-	if ((tcp->flags & TCB_WAITEXECVE)
-		 && (s390_gpr2 == -ENOSYS || s390_gpr2 == tcp->scno)) {
-		/*
-		 * Return from execve.
-		 * Fake a return value of zero.  We leave the TCB_WAITEXECVE
-		 * flag set for the post-execve SIGTRAP to see and reset.
-		 */
-		s390_gpr2 = 0;
-	}
-#endif
-}
-
 /* Returns:
  * 1: ok, continue in trace_syscall_exiting().
  * -1: error, trace_syscall_exiting() should print error indicator
@@ -2510,10 +2310,7 @@
 #endif
 	res = (get_regs_error ? -1 : get_syscall_result(tcp));
 	if (res == 1) {
-		syscall_fixup_on_sysexit(tcp); /* never fails */
 		get_error(tcp); /* never fails */
-		if (need_fork_exec_workarounds)
-			syscall_fixup_for_fork_exec(tcp);
 		if (filtered(tcp) || hide_log_until_execve)
 			goto ret;
 	}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 1d19d60..21f7361 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -41,7 +41,6 @@
 	stack-fcall-0.c stack-fcall-1.c stack-fcall-2.c stack-fcall-3.c
 
 TESTS = \
-	ptrace_setoptions.test \
 	strace-f.test \
 	qual_syscall.test \
 	bexecve.test \
diff --git a/tests/ptrace_setoptions.test b/tests/ptrace_setoptions.test
deleted file mode 100755
index 87651b8..0000000
--- a/tests/ptrace_setoptions.test
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-
-# Ensure that strace tests kernel PTRACE_O_TRACECLONE
-# and PTRACE_O_TRACESYSGOOD support properly.
-
-. "${srcdir=.}/init.sh"
-
-check_prog grep
-
-[ "$(uname -s)" = Linux ] ||
-	skip_ 'The kernel is not a Linux kernel'
-case "$(uname -r)" in
-	2.[6-9]*|2.[1-5][0-9]*|[3-9].*|[12][0-9]*) ;;
-	*) skip_ 'The kernel is not Linux 2.6.* or newer' ;;
-esac
-
-$STRACE -df -enone / > /dev/null 2> $LOG
-grep -F -x 'ptrace_setoptions = 0xe' $LOG > /dev/null || {
-	cat $LOG
-	fail_ 'strace -f failed to recognize proper kernel PTRACE_O_TRACECLONE support'
-}
-
-grep -F -x 'ptrace_setoptions = 0x1f' $LOG > /dev/null || {
-	cat $LOG
-	fail_ 'strace -f failed to recognize proper kernel PTRACE_O_TRACESYSGOOD support'
-}
-
-$STRACE -d -enone / > /dev/null 2> $LOG
-grep -F -x 'ptrace_setoptions = 0x11' $LOG > /dev/null || {
-	cat $LOG
-	fail_ 'strace failed to recognize proper kernel PTRACE_O_TRACESYSGOOD support'
-}
diff --git a/util.c b/util.c
index b8bbf49..8916040 100644
--- a/util.c
+++ b/util.c
@@ -1257,427 +1257,3 @@
 	*res = val;
 	return 0;
 }
-
-/* Note! On new kernels (about 2.5.46+), we use PTRACE_O_TRACECLONE
- * and PTRACE_O_TRACE[V]FORK for tracing children.
- * If you are adding a new arch which is only supported by newer kernels,
- * you most likely don't need to add any code below
- * beside a dummy "return 0" block in change_syscall().
- */
-
-/*
- * These #if's are huge, please indent them correctly.
- * It's easy to get confused otherwise.
- */
-
-#include "syscall.h"
-
-#ifndef CLONE_PTRACE
-# define CLONE_PTRACE    0x00002000
-#endif
-#ifndef CLONE_VFORK
-# define CLONE_VFORK     0x00004000
-#endif
-#ifndef CLONE_VM
-# define CLONE_VM        0x00000100
-#endif
-
-#ifdef IA64
-
-typedef unsigned long *arg_setup_state;
-
-static int
-arg_setup(struct tcb *tcp, arg_setup_state *state)
-{
-	unsigned long cfm, sof, sol;
-	long bsp;
-
-	if (ia64_ia32mode) {
-		/* Satisfy a false GCC warning.  */
-		*state = NULL;
-		return 0;
-	}
-
-	if (upeek(tcp->pid, PT_AR_BSP, &bsp) < 0)
-		return -1;
-	if (upeek(tcp->pid, PT_CFM, (long *) &cfm) < 0)
-		return -1;
-
-	sof = (cfm >> 0) & 0x7f;
-	sol = (cfm >> 7) & 0x7f;
-	bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
-
-	*state = (unsigned long *) bsp;
-	return 0;
-}
-
-# define arg_finish_change(tcp, state)	0
-
-static int
-get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
-{
-	int ret;
-
-	if (ia64_ia32mode)
-		ret = upeek(tcp->pid, PT_R11, valp);
-	else
-		ret = umoven(tcp,
-			      (unsigned long) ia64_rse_skip_regs(*state, 0),
-			      sizeof(long), (void *) valp);
-	return ret;
-}
-
-static int
-get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
-{
-	int ret;
-
-	if (ia64_ia32mode)
-		ret = upeek(tcp->pid, PT_R9, valp);
-	else
-		ret = umoven(tcp,
-			      (unsigned long) ia64_rse_skip_regs(*state, 1),
-			      sizeof(long), (void *) valp);
-	return ret;
-}
-
-static int
-set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
-{
-	int req = PTRACE_POKEDATA;
-	void *ap;
-
-	if (ia64_ia32mode) {
-		ap = (void *) (intptr_t) PT_R11;	 /* r11 == EBX */
-		req = PTRACE_POKEUSER;
-	} else
-		ap = ia64_rse_skip_regs(*state, 0);
-	errno = 0;
-	ptrace(req, tcp->pid, ap, val);
-	return errno ? -1 : 0;
-}
-
-static int
-set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
-{
-	int req = PTRACE_POKEDATA;
-	void *ap;
-
-	if (ia64_ia32mode) {
-		ap = (void *) (intptr_t) PT_R9;		/* r9 == ECX */
-		req = PTRACE_POKEUSER;
-	} else
-		ap = ia64_rse_skip_regs(*state, 1);
-	errno = 0;
-	ptrace(req, tcp->pid, ap, val);
-	return errno ? -1 : 0;
-}
-
-/* ia64 does not return the input arguments from functions (and syscalls)
-   according to ia64 RSE (Register Stack Engine) behavior.  */
-
-# define restore_arg0(tcp, state, val) ((void) (state), 0)
-# define restore_arg1(tcp, state, val) ((void) (state), 0)
-
-#elif defined(SPARC) || defined(SPARC64)
-
-# if defined(SPARC64)
-#  undef PTRACE_GETREGS
-#  define PTRACE_GETREGS PTRACE_GETREGS64
-#  undef PTRACE_SETREGS
-#  define PTRACE_SETREGS PTRACE_SETREGS64
-# endif
-
-typedef struct pt_regs arg_setup_state;
-
-# define arg_setup(tcp, state) \
-    (ptrace(PTRACE_GETREGS, (tcp)->pid, (char *) (state), 0))
-# define arg_finish_change(tcp, state) \
-    (ptrace(PTRACE_SETREGS, (tcp)->pid, (char *) (state), 0))
-
-# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
-# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
-# define set_arg0(tcp, state, val)  ((state)->u_regs[U_REG_O0] = (val), 0)
-# define set_arg1(tcp, state, val)  ((state)->u_regs[U_REG_O1] = (val), 0)
-# define restore_arg0(tcp, state, val) 0
-
-#else /* other architectures */
-
-# if defined S390 || defined S390X
-/* Note: this is only true for the `clone' system call, which handles
-   arguments specially.  We could as well say that its first two arguments
-   are swapped relative to other architectures, but that would just be
-   another #ifdef in the calls.  */
-#  define arg0_offset	PT_GPR3
-#  define arg1_offset	PT_ORIGGPR2
-#  define restore_arg0(tcp, state, val) ((void) (state), 0)
-#  define restore_arg1(tcp, state, val) ((void) (state), 0)
-#  define arg0_index	1
-#  define arg1_index	0
-# elif defined(ALPHA) || defined(MIPS)
-#  define arg0_offset	REG_A0
-#  define arg1_offset	(REG_A0+1)
-# elif defined(POWERPC)
-#  define arg0_offset	(sizeof(unsigned long)*PT_R3)
-#  define arg1_offset	(sizeof(unsigned long)*PT_R4)
-#  define restore_arg0(tcp, state, val) ((void) (state), 0)
-# elif defined(HPPA)
-#  define arg0_offset	PT_GR26
-#  define arg1_offset	(PT_GR26-4)
-# elif defined(X86_64) || defined(X32)
-#  define arg0_offset	((long)(8*(current_personality ? RBX : RDI)))
-#  define arg1_offset	((long)(8*(current_personality ? RCX : RSI)))
-# elif defined(SH)
-#  define arg0_offset	(4*(REG_REG0+4))
-#  define arg1_offset	(4*(REG_REG0+5))
-# elif defined(SH64)
-   /* ABI defines arg0 & 1 in r2 & r3 */
-#  define arg0_offset	(REG_OFFSET+16)
-#  define arg1_offset	(REG_OFFSET+24)
-#  define restore_arg0(tcp, state, val) 0
-# elif defined CRISV10 || defined CRISV32
-#  define arg0_offset	(4*PT_R11)
-#  define arg1_offset	(4*PT_ORIG_R10)
-#  define restore_arg0(tcp, state, val) 0
-#  define restore_arg1(tcp, state, val) 0
-#  define arg0_index	1
-#  define arg1_index	0
-# else
-#  define arg0_offset	0
-#  define arg1_offset	4
-#  if defined ARM
-#   define restore_arg0(tcp, state, val) 0
-#  endif
-# endif
-
-typedef int arg_setup_state;
-
-# define arg_setup(tcp, state)         (0)
-# define arg_finish_change(tcp, state) 0
-# define get_arg0(tcp, cookie, valp)   (upeek((tcp)->pid, arg0_offset, (valp)))
-# define get_arg1(tcp, cookie, valp)   (upeek((tcp)->pid, arg1_offset, (valp)))
-
-static int
-set_arg0(struct tcb *tcp, void *cookie, long val)
-{
-	return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
-}
-
-static int
-set_arg1(struct tcb *tcp, void *cookie, long val)
-{
-	return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
-}
-
-#endif /* architectures */
-
-#ifndef restore_arg0
-# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
-#endif
-#ifndef restore_arg1
-# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
-#endif
-
-#ifndef arg0_index
-# define arg0_index 0
-# define arg1_index 1
-#endif
-
-static int
-change_syscall(struct tcb *tcp, arg_setup_state *state, int new)
-{
-#if defined(I386)
-	if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_EAX * 4), new) < 0)
-		return -1;
-	return 0;
-#elif defined(X86_64)
-	if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_RAX * 8), new) < 0)
-		return -1;
-	return 0;
-#elif defined(X32)
-	/* setbpt/clearbpt never used: */
-	/* X32 is only supported since about linux-3.0.30 */
-#elif defined(POWERPC)
-	if (ptrace(PTRACE_POKEUSER, tcp->pid,
-		   (char*)(sizeof(unsigned long)*PT_R0), new) < 0)
-		return -1;
-	return 0;
-#elif defined(S390) || defined(S390X)
-	/* s390 linux after 2.4.7 has a hook in entry.S to allow this */
-	if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GPR2), new) < 0)
-		return -1;
-	return 0;
-#elif defined(M68K)
-	if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_ORIG_D0), new) < 0)
-		return -1;
-	return 0;
-#elif defined(SPARC) || defined(SPARC64)
-	state->u_regs[U_REG_G1] = new;
-	return 0;
-#elif defined(MIPS)
-	if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), new) < 0)
-		return -1;
-	return 0;
-#elif defined(ALPHA)
-	if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), new) < 0)
-		return -1;
-	return 0;
-#elif defined(AVR32)
-	/* setbpt/clearbpt never used: */
-	/* AVR32 is only supported since about linux-2.6.19 */
-#elif defined(BFIN)
-	/* setbpt/clearbpt never used: */
-	/* Blackfin is only supported since about linux-2.6.23 */
-#elif defined(IA64)
-	if (ia64_ia32mode) {
-		switch (new) {
-		case 2:
-			break;	/* x86 SYS_fork */
-		case SYS_clone:
-			new = 120;
-			break;
-		default:
-			fprintf(stderr, "%s: unexpected syscall %d\n",
-				__FUNCTION__, new);
-			return -1;
-		}
-		if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R1), new) < 0)
-			return -1;
-	} else if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R15), new) < 0)
-		return -1;
-	return 0;
-#elif defined(HPPA)
-	if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR20), new) < 0)
-		return -1;
-	return 0;
-#elif defined(SH)
-	if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*(REG_REG0+3)), new) < 0)
-		return -1;
-	return 0;
-#elif defined(SH64)
-	/* Top half of reg encodes the no. of args n as 0x1n.
-	   Assume 0 args as kernel never actually checks... */
-	if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_SYSCALL),
-				0x100000 | new) < 0)
-		return -1;
-	return 0;
-#elif defined(CRISV10) || defined(CRISV32)
-	if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_R9), new) < 0)
-		return -1;
-	return 0;
-#elif defined(ARM)
-	/* Some kernels support this, some (pre-2.6.16 or so) don't.  */
-# ifndef PTRACE_SET_SYSCALL
-#  define PTRACE_SET_SYSCALL 23
-# endif
-	if (ptrace(PTRACE_SET_SYSCALL, tcp->pid, 0, new & 0xffff) != 0)
-		return -1;
-	return 0;
-#elif defined(AARCH64)
-	/* setbpt/clearbpt never used: */
-	/* AARCH64 is only supported since about linux-3.0.31 */
-#elif defined(TILE)
-	/* setbpt/clearbpt never used: */
-	/* Tilera CPUs are only supported since about linux-2.6.34 */
-#elif defined(MICROBLAZE)
-	/* setbpt/clearbpt never used: */
-	/* microblaze is only supported since about linux-2.6.30 */
-#elif defined(OR1K)
-	/* never reached; OR1K is only supported by kernels since 3.1.0. */
-#elif defined(METAG)
-	/* setbpt/clearbpt never used: */
-	/* Meta is only supported since linux-3.7 */
-#elif defined(XTENSA)
-	/* setbpt/clearbpt never used: */
-	/* Xtensa is only supported since linux 2.6.13 */
-#elif defined(ARC)
-	/* setbpt/clearbpt never used: */
-	/* ARC only supported since 3.9 */
-#else
-#warning Do not know how to handle change_syscall for this architecture
-#endif /* architecture */
-	return -1;
-}
-
-int
-setbpt(struct tcb *tcp)
-{
-	static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
-	arg_setup_state state;
-
-	if (tcp->flags & TCB_BPTSET) {
-		fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
-		return -1;
-	}
-
-	/*
-	 * It's a silly kludge to initialize this with a search at runtime.
-	 * But it's better than maintaining another magic thing in the
-	 * godforsaken tables.
-	 */
-	if (clone_scno[current_personality] == 0) {
-		unsigned int i;
-		for (i = 0; i < nsyscalls; ++i)
-			if (sysent[i].sys_func == sys_clone) {
-				clone_scno[current_personality] = i;
-				break;
-			}
-	}
-
-	if (tcp->s_ent->sys_func == sys_fork) {
-		if (arg_setup(tcp, &state) < 0
-		    || get_arg0(tcp, &state, &tcp->inst[0]) < 0
-		    || get_arg1(tcp, &state, &tcp->inst[1]) < 0
-		    || change_syscall(tcp, &state,
-				      clone_scno[current_personality]) < 0
-		    || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
-		    || set_arg1(tcp, &state, 0) < 0
-		    || arg_finish_change(tcp, &state) < 0)
-			return -1;
-		tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
-		tcp->u_arg[arg1_index] = 0;
-		tcp->flags |= TCB_BPTSET;
-		return 0;
-	}
-
-	if (tcp->s_ent->sys_func == sys_clone) {
-		/* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
-		   contrary to x86 vfork above.  Even on x86 we turn the
-		   vfork semantics into plain fork - each application must not
-		   depend on the vfork specifics according to POSIX.  We would
-		   hang waiting for the parent resume otherwise.  We need to
-		   clear also CLONE_VM but only in the CLONE_VFORK case as
-		   otherwise we would break pthread_create.  */
-
-		long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
-		if (new_arg0 & CLONE_VFORK)
-			new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
-		if (arg_setup(tcp, &state) < 0
-		 || set_arg0(tcp, &state, new_arg0) < 0
-		 || arg_finish_change(tcp, &state) < 0)
-			return -1;
-		tcp->inst[0] = tcp->u_arg[arg0_index];
-		tcp->inst[1] = tcp->u_arg[arg1_index];
-		tcp->flags |= TCB_BPTSET;
-		return 0;
-	}
-
-	fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
-		tcp->scno, tcp->pid);
-	return -1;
-}
-
-int
-clearbpt(struct tcb *tcp)
-{
-	arg_setup_state state;
-	if (arg_setup(tcp, &state) < 0
-	    || change_syscall(tcp, &state, tcp->scno) < 0
-	    || restore_arg0(tcp, &state, tcp->inst[0]) < 0
-	    || restore_arg1(tcp, &state, tcp->inst[1]) < 0
-	    || arg_finish_change(tcp, &state))
-		if (errno != ESRCH)
-			return -1;
-	tcp->flags &= ~TCB_BPTSET;
-	return 0;
-}