-change_syscall(struct tcb *tcp, int new)
-{
-#if defined(LINUX)
-#if defined(I386)
- /* Attempt to make vfork into fork, which we can follow. */
- if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_EAX * 4), new) < 0)
- return -1;
- return 0;
-#elif defined(X86_64)
- /* Attempt to make vfork into fork, which we can follow. */
- if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_RAX * 8), new) < 0)
- return -1;
- return 0;
-#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)
- struct pt_regs regs;
- if (ptrace(PTRACE_GETREGS, tcp->pid, (char*)®s, 0)<0)
- return -1;
- regs.u_regs[U_REG_G1] = new;
- if (ptrace(PTRACE_SETREGS, tcp->pid, (char*)®s, 0)<0)
- return -1;
- 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)
- if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R8), new) < 0)
- return -1;
- return 0;
-#elif defined(BFIN)
- if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_P0), new)<0)
- return -1;
- return 0;
-#elif defined(IA64)
- if (ia32) {
- 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;
-#else
-#warning Do not know how to handle change_syscall for this architecture
-#endif /* architecture */
-#endif /* LINUX */
- return -1;
-}
-
-#if 0
-int
-setarg(tcp, argnum)
- struct tcb *tcp;
- int argnum;
-{
-#if defined(AVR32)
- {
- errno = 0;
- if (argnum == 0)
- ptrace(PTRACE_POKEUSER, tcp->pid,
- (char *)(REG_R12_ORIG),
- tcp->u_arg[argnum]);
- else if (argnum < 4)
- /* r11 .. r9 */
- ptrace(PTRACE_POKEUSER, tcp->pid,
- (char *)(REG_R12 - 4 * argnum),
- tcp->u_arg[argnum]);
- else if (argnum < 5)
- /* r5 */
- ptrace(PTRACE_POKEUSER, tcp->pid,
- (char *)(REG_R5),
- tcp->u_arg[argnum]);
- else if (argnum < 6)
- /* r3 */
- ptrace(PTRACE_POKEUSER, tcp->pid,
- (char *)(REG_R3),
- tcp->u_arg[argnum]);
- else
- return -E2BIG;
- if (errno)
- return -1;
- }
-#elif defined(IA64)
- {
- unsigned long *bsp, *ap;
-
- if (upeek(tcp, PT_AR_BSP, (long *) &bsp) , 0)
- return -1;
-
- ap = ia64_rse_skip_regs(bsp, argnum);
- errno = 0;
- ptrace(PTRACE_POKEDATA, tcp->pid, (char *) ap, tcp->u_arg[argnum]);
- if (errno)
- return -1;
-
- }
-#elif defined(I386)
- {
- ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*argnum), tcp->u_arg[argnum]);
- if (errno)
- return -1;
- }
-#elif defined(X86_64)
- {
- ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(8*(long)argnum), tcp->u_arg[argnum]);
- if (errno)
- return -1;
- }
-#elif defined(POWERPC)
-#ifndef PT_ORIG_R3
-#define PT_ORIG_R3 34
-#endif
- {
- ptrace(PTRACE_POKEUSER, tcp->pid,
- (char*)((argnum==0 ? PT_ORIG_R3 : argnum+PT_R3)*sizeof(unsigned long)),
- tcp->u_arg[argnum]);
- if (errno)
- return -1;
- }
-#elif defined(MIPS)
- {
- errno = 0;
- if (argnum < 4)
- ptrace(PTRACE_POKEUSER, tcp->pid,
- (char*)(REG_A0 + argnum), tcp->u_arg[argnum]);
- else {
- unsigned long *sp;
-
- if (upeek(tcp, REG_SP, (long *) &sp) , 0)
- return -1;
-
- ptrace(PTRACE_POKEDATA, tcp->pid,
- (char*)(sp + argnum - 4), tcp->u_arg[argnum]);
- }
- if (errno)
- return -1;
- }
-#elif defined(S390) || defined(S390X)
- {
- if(argnum <= 5)
- ptrace(PTRACE_POKEUSER, tcp->pid,
- (char *) (argnum==0 ? PT_ORIGGPR2 :
- PT_GPR2 + argnum*sizeof(long)),
- tcp->u_arg[argnum]);
- else
- return -E2BIG;
- if (errno)
- return -1;
- }
-#else
-# warning Sorry, setargs not implemented for this architecture.
-#endif
- return 0;
-}
-#endif
-
-#if defined SYS_clone || defined SYS_clone2
-int
-internal_clone(tcp)
-struct tcb *tcp;
-{
- struct tcb *tcpchild;
- int pid;
- if (entering(tcp)) {
- if (!followfork)
- return 0;
- fork_tcb(tcp);
- if (setbpt(tcp) < 0)
- return 0;
- } else {
- int bpt = tcp->flags & TCB_BPTSET;
-
- if (!(tcp->flags & TCB_FOLLOWFORK))
- return 0;
-
- if (syserror(tcp)) {
- if (bpt)
- clearbpt(tcp);
- return 0;
- }
-
- pid = tcp->u_rval;
-
-#ifdef CLONE_PTRACE /* See new setbpt code. */
- tcpchild = pid2tcb(pid);
- if (tcpchild != NULL) {
- /* The child already reported its startup trap
- before the parent reported its syscall return. */
- if ((tcpchild->flags
- & (TCB_STARTUP|TCB_ATTACHED|TCB_SUSPENDED))
- != (TCB_STARTUP|TCB_ATTACHED|TCB_SUSPENDED))
- fprintf(stderr, "\
-[preattached child %d of %d in weird state!]\n",
- pid, tcp->pid);
- }
- else
-#endif
- {
- fork_tcb(tcp);
- tcpchild = alloctcb(pid);
- }
-
-#ifndef CLONE_PTRACE
- /* Attach to the new child */
- if (ptrace(PTRACE_ATTACH, pid, (char *) 1, 0) < 0) {
- if (bpt)
- clearbpt(tcp);
- perror("PTRACE_ATTACH");
- fprintf(stderr, "Too late?\n");
- droptcb(tcpchild);
- return 0;
- }
-#endif
-
- if (bpt)
- clearbpt(tcp);
-
- tcpchild->flags |= TCB_ATTACHED;
- /* Child has BPT too, must be removed on first occasion. */
- if (bpt) {
- tcpchild->flags |= TCB_BPTSET;
- tcpchild->baddr = tcp->baddr;
- memcpy(tcpchild->inst, tcp->inst,
- sizeof tcpchild->inst);
- }
- tcpchild->parent = tcp;
- tcp->nchildren++;
- if (tcpchild->flags & TCB_SUSPENDED) {
- /* The child was born suspended, due to our having
- forced CLONE_PTRACE. */
- if (bpt)
- clearbpt(tcpchild);
-
- tcpchild->flags &= ~(TCB_SUSPENDED|TCB_STARTUP);
- if (ptrace_restart(PTRACE_SYSCALL, tcpchild, 0) < 0)
- return -1;
-
- if (!qflag)
- fprintf(stderr, "\
-Process %u resumed (parent %d ready)\n",
- pid, tcp->pid);
- }
- else {
- if (!qflag)
- fprintf(stderr, "Process %d attached\n", pid);
- }
-
-#ifdef TCB_CLONE_THREAD
- {
- /*
- * Save the flags used in this call,
- * in case we point TCP to our parent below.
- */
- int call_flags = tcp->u_arg[ARG_FLAGS];
- if ((tcp->flags & TCB_CLONE_THREAD) &&
- tcp->parent != NULL) {
- /* The parent in this clone is itself a
- thread belonging to another process.
- There is no meaning to the parentage
- relationship of the new child with the
- thread, only with the process. We
- associate the new thread with our
- parent. Since this is done for every
- new thread, there will never be a
- TCB_CLONE_THREAD process that has
- children. */
- --tcp->nchildren;
- tcp = tcp->parent;
- tcpchild->parent = tcp;
- ++tcp->nchildren;
- }
- if (call_flags & CLONE_THREAD) {
- tcpchild->flags |= TCB_CLONE_THREAD;
- ++tcp->nclone_threads;
- }
- if (call_flags & CLONE_DETACHED) {
- tcpchild->flags |= TCB_CLONE_DETACHED;
- ++tcp->nclone_detached;
- }
- }
-#endif
- }
- return 0;
-}
-#endif
-
-int
-internal_fork(tcp)
-struct tcb *tcp;
-{
-#ifdef LINUX
- /* We do special magic with clone for any clone or fork. */
- return internal_clone(tcp);
-#else
-
- struct tcb *tcpchild;
- int pid;
- int dont_follow = 0;
-
-#ifdef SYS_vfork
- if (known_scno(tcp) == SYS_vfork) {
- /* Attempt to make vfork into fork, which we can follow. */
- if (change_syscall(tcp, SYS_fork) < 0)
- dont_follow = 1;
- }
-#endif
- if (entering(tcp)) {
- if (!followfork || dont_follow)
- return 0;
- fork_tcb(tcp);
- if (setbpt(tcp) < 0)
- return 0;
- }
- else {
- int bpt = tcp->flags & TCB_BPTSET;
-
- if (!(tcp->flags & TCB_FOLLOWFORK))
- return 0;
- if (bpt)
- clearbpt(tcp);
-
- if (syserror(tcp))
- return 0;
-
- pid = tcp->u_rval;
- fork_tcb(tcp);
- tcpchild = alloctcb(pid);
-#ifdef LINUX
-#ifdef HPPA
- /* The child must have run before it can be attached. */
- /* This must be a bug in the parisc kernel, but I havn't
- * identified it yet. Seems to be an issue associated
- * with attaching to a process (which sends it a signal)
- * before that process has ever been scheduled. When
- * debugging, I started seeing crashes in
- * arch/parisc/kernel/signal.c:do_signal(), apparently
- * caused by r8 getting corrupt over the dequeue_signal()
- * call. Didn't make much sense though...
- */
- {
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 10000;
- select(0, NULL, NULL, NULL, &tv);
- }
-#endif
- if (ptrace(PTRACE_ATTACH, pid, (char *) 1, 0) < 0) {
- perror("PTRACE_ATTACH");
- fprintf(stderr, "Too late?\n");
- droptcb(tcpchild);
- return 0;
- }
-#endif /* LINUX */
-#ifdef SUNOS4
-#ifdef oldway
- /* The child must have run before it can be attached. */
- {
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 10000;
- select(0, NULL, NULL, NULL, &tv);
- }
- if (ptrace(PTRACE_ATTACH, pid, (char *)1, 0) < 0) {
- perror("PTRACE_ATTACH");
- fprintf(stderr, "Too late?\n");
- droptcb(tcpchild);
- return 0;
- }
-#else /* !oldway */
- /* Try to catch the new process as soon as possible. */
- {
- int i;
- for (i = 0; i < 1024; i++)
- if (ptrace(PTRACE_ATTACH, pid, (char *) 1, 0) >= 0)
- break;
- if (i == 1024) {
- perror("PTRACE_ATTACH");
- fprintf(stderr, "Too late?\n");
- droptcb(tcpchild);
- return 0;
- }
- }
-#endif /* !oldway */
-#endif /* SUNOS4 */
- tcpchild->flags |= TCB_ATTACHED;
- /* Child has BPT too, must be removed on first occasion */
- if (bpt) {
- tcpchild->flags |= TCB_BPTSET;
- tcpchild->baddr = tcp->baddr;
- memcpy(tcpchild->inst, tcp->inst,
- sizeof tcpchild->inst);
- }
- tcpchild->parent = tcp;
- tcp->nchildren++;
- if (!qflag)
- fprintf(stderr, "Process %d attached\n", pid);
- }
- return 0;
-#endif
-}
-
-#endif /* !USE_PROCFS */
-
-#if defined(SUNOS4) || defined(LINUX) || defined(FREEBSD)
-
-int
-sys_vfork(tcp)
-struct tcb *tcp;