+#if defined LINUX
+
+#include <sys/syscall.h>
+#ifndef CLONE_PTRACE
+# define CLONE_PTRACE 0x00002000
+#endif
+
+#ifdef IA64
+
+/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
+ subsystem has them for x86... */
+#define SYS_fork 2
+#define SYS_vfork 190
+
+typedef unsigned long *arg_setup_state;
+
+static int
+arg_setup(struct tcb *tcp, arg_setup_state *state)
+{
+ unsigned long *bsp, cfm, sof, sol;
+
+ if (ia32)
+ return 0;
+
+ if (upeek(tcp->pid, PT_AR_BSP, (long *) &bsp) < 0)
+ return -1;
+ if (upeek(tcp->pid, PT_CFM, (long *) &cfm) < 0)
+ return -1;
+
+ sof = (cfm >> 0) & 0x7f;
+ sol = (cfm >> 7) & 0x7f;
+ bsp = ia64_rse_skip_regs(bsp, -sof + sol);
+
+ *state = bsp;
+ return 0;
+}
+
+# define arg_finish_change(tcp, state) 0
+
+#ifdef SYS_fork
+static int
+get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp)
+{
+ int ret;
+
+ if (ia32)
+ 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 (ia32)
+ 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;
+}
+#endif
+
+static int
+set_arg0 (struct tcb *tcp, arg_setup_state *state, long val)
+{
+ int req = PTRACE_POKEDATA;
+ void *ap;
+
+ if (ia32) {
+ 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 (ia32) {
+ 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;
+}
+
+#elif defined (SPARC) || defined (SPARC64)
+
+typedef struct 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)->r_o0, 0)
+# define get_arg1(tcp, state, valp) (*(valp) = (state)->r_o1, 0)
+# define set_arg0(tcp, state, val) ((state)->r_o0 = (val), 0)
+# define set_arg1(tcp, state, val) ((state)->r_o1 = (val), 0)
+# define restore_arg0(tcp, state, val) 0
+
+#else
+
+# 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)
+# 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
+# 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
+
+#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
+
+int
+setbpt(tcp)
+struct tcb *tcp;
+{
+ extern int change_syscall(struct tcb *, int);
+ arg_setup_state state;
+
+ if (tcp->flags & TCB_BPTSET) {
+ fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
+ return -1;
+ }
+
+ switch (tcp->scno) {
+#ifdef SYS_vfork
+ case SYS_vfork:
+#endif
+#ifdef SYS_fork
+ case SYS_fork:
+#endif
+#if defined SYS_fork || defined SYS_vfork
+ 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, SYS_clone) < 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;
+#endif
+
+ case SYS_clone:
+#ifdef SYS_clone2
+ case SYS_clone2:
+#endif
+ if ((tcp->u_arg[arg0_index] & CLONE_PTRACE) == 0
+ && (arg_setup (tcp, &state) < 0
+ || set_arg0 (tcp, &state,
+ tcp->u_arg[arg0_index] | CLONE_PTRACE) < 0
+ || arg_finish_change (tcp, &state) < 0))
+ return -1;
+ tcp->flags |= TCB_BPTSET;
+ tcp->inst[0] = tcp->u_arg[arg0_index];
+ tcp->inst[1] = tcp->u_arg[arg1_index];
+ return 0;
+
+ default:
+ fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
+ tcp->scno, tcp->pid);
+ break;
+ }
+
+ return -1;
+}
+
+int
+clearbpt(tcp)
+struct tcb *tcp;
+{
+ arg_setup_state state;
+ if (arg_setup (tcp, &state) < 0
+ || restore_arg0 (tcp, &state, tcp->inst[0]) < 0
+ || restore_arg1 (tcp, &state, tcp->inst[1]) < 0
+ || arg_finish_change (tcp, &state))
+ return -1;
+ tcp->flags &= ~TCB_BPTSET;
+ return 0;
+}
+
+#else
+