]> granicus.if.org Git - strace/blobdiff - process.c
2006-12-12 Dmitry V. Levin <ldv@altlinux.org>
[strace] / process.c
index 76d0deb7b57cfe73b83e1646b3e9a0c58d4e5772..8e25640d99036b6b80c70f541e6a98b6cbf58fbd 100644 (file)
--- a/process.c
+++ b/process.c
@@ -6,6 +6,9 @@
  * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *                     Linux for s390 port by D.J. Barrow
  *                    <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
+ * Copyright (c) 2000 PocketPenguins Inc.  Linux for Hitachi SuperH
+ *                    port by Greg Banks <gbanks@pocketpenguins.com>
+
  *
  * All rights reserved.
  *
 #endif
 
 #if HAVE_ASM_REG_H
-#ifdef SPARC
+#if defined (SPARC) || defined (SPARC64)
 #  define fpq kernel_fpq
 #  define fq kernel_fq
 #  define fpu kernel_fpu
-#endif
+#endif /* SPARC || SPARC64 */
 #include <asm/reg.h>
-#ifdef SPARC
+#if defined (SPARC) || defined (SPARC64)
 #  undef fpq
 #  undef fq
-#  undef fpu 
-#endif
+#  undef fpu
+#endif /* SPARC || SPARC64 */
 #endif /* HAVE_ASM_REG_H */
 
 #ifdef HAVE_SYS_REG_H
 #ifndef PTRACE_POKEUSR
 # define PTRACE_POKEUSR PTRACE_POKEUSER
 #endif
-#elif defined(HAVE_LINUX_PTRACE_H)
+#endif
+
+#ifdef HAVE_LINUX_PTRACE_H
 #undef PTRACE_SYSCALL
+# ifdef HAVE_STRUCT_IA64_FPREG
+#  define ia64_fpreg XXX_ia64_fpreg
+# endif
+# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
+#  define pt_all_user_regs XXX_pt_all_user_regs
+# endif
 #include <linux/ptrace.h>
+# undef ia64_fpreg
+# undef pt_all_user_regs
+#endif
+
+#if defined (LINUX) && defined (SPARC64)
+# define r_pc r_tpc
+# undef PTRACE_GETREGS
+# define PTRACE_GETREGS PTRACE_GETREGS64
+# undef PTRACE_SETREGS
+# define PTRACE_SETREGS PTRACE_SETREGS64
+#endif /* LINUX && SPARC64 */
+
+#ifdef HAVE_LINUX_FUTEX_H
+#include <linux/futex.h>
+#endif
+#if defined LINUX
+# ifndef FUTEX_WAIT
+#  define FUTEX_WAIT 0
+# endif
+# ifndef FUTEX_WAKE
+#  define FUTEX_WAKE 1
+# endif
+# ifndef FUTEX_FD
+#  define FUTEX_FD 2
+# endif
+# ifndef FUTEX_REQUEUE
+#  define FUTEX_REQUEUE 3
+# endif
 #endif
 
-
 #ifdef LINUX
+#include <sched.h>
 #include <asm/posix_types.h>
 #undef GETGROUPS_T
 #define GETGROUPS_T __kernel_gid_t
+#undef GETGROUPS32_T
+#define GETGROUPS32_T __kernel_gid32_t
 #endif /* LINUX */
 
 #if defined(LINUX) && defined(IA64)
 
 /* WTA: this was `&& !defined(LINUXSPARC)', this seems unneeded though? */
 #if defined(HAVE_PRCTL)
-static struct xlat prctl_options[] = {
+static const struct xlat prctl_options[] = {
 #ifdef PR_MAXPROCS
        { PR_MAXPROCS,          "PR_MAXPROCS"           },
 #endif
@@ -179,7 +220,7 @@ static struct xlat prctl_options[] = {
 };
 
 
-const char *
+static const char *
 unalignctl_string (unsigned int ctl)
 {
        static char buf[16];
@@ -264,6 +305,7 @@ struct tcb *tcp;
 
 #endif /* HAVE_PRCTL */
 
+#if defined(FREEBSD) || defined(SUNOS4) || defined(SVR4)
 int
 sys_gethostid(tcp)
 struct tcb *tcp;
@@ -272,6 +314,7 @@ struct tcb *tcp;
                return RVAL_HEX;
        return 0;
 }
+#endif /* FREEBSD || SUNOS4 || SVR4 */
 
 int
 sys_sethostname(tcp)
@@ -284,6 +327,7 @@ struct tcb *tcp;
        return 0;
 }
 
+#if defined(ALPHA) || defined(FREEBSD) || defined(SUNOS4) || defined(SVR4)
 int
 sys_gethostname(tcp)
 struct tcb *tcp;
@@ -297,6 +341,7 @@ struct tcb *tcp;
        }
        return 0;
 }
+#endif /* ALPHA || FREEBSD || SUNOS4 || SVR4 */
 
 int
 sys_setdomainname(tcp)
@@ -346,8 +391,36 @@ int
 internal_exit(tcp)
 struct tcb *tcp;
 {
-       if (entering(tcp))
+       if (entering(tcp)) {
                tcp->flags |= TCB_EXITING;
+#ifdef __NR_exit_group
+# ifdef IA64
+               if (ia32) {
+                       if (tcp->scno == 252)
+                               tcp->flags |= TCB_GROUP_EXITING;
+               } else
+# endif
+               if (known_scno(tcp) == __NR_exit_group)
+                       tcp->flags |= TCB_GROUP_EXITING;
+#endif
+       }
+       return 0;
+}
+
+/* TCP is creating a child we want to follow.
+   If there will be space in tcbtab for it, set TCB_FOLLOWFORK and return 0.
+   If not, clear TCB_FOLLOWFORK, print an error, and return 1.  */
+static int
+fork_tcb(struct tcb *tcp)
+{
+       if (nprocs == tcbtabsize) {
+               if (expand_tcbtab()) {
+                       tcp->flags &= ~TCB_FOLLOWFORK;
+                       return 1;
+               }
+       }
+
+       tcp->flags |= TCB_FOLLOWFORK;
        return 0;
 }
 
@@ -393,23 +466,20 @@ struct tcb *tcp;
        struct tcb *tcpchild;
 
        if (exiting(tcp)) {
+#ifdef SYS_rfork
+               if (known_scno(tcp) == SYS_rfork && !(tcp->u_arg[0]&RFPROC))
+                       return 0;
+#endif
                if (getrval2(tcp))
                        return 0;
                if (!followfork)
                        return 0;
-               if (nprocs == MAX_PROCS) {
-                       tcp->flags &= ~TCB_FOLLOWFORK;
-                       fprintf(stderr, "sys_fork: tcb table full\n");
+               if (fork_tcb(tcp))
                        return 0;
-               }
-               else
-                       tcp->flags |= TCB_FOLLOWFORK;
                if (syserror(tcp))
                        return 0;
-               if ((tcpchild = alloctcb(tcp->u_rval)) == NULL) {
-                       fprintf(stderr, "sys_fork: tcb table full\n");
+               if ((tcpchild = alloctcb(tcp->u_rval)) == NULL)
                        return 0;
-               }
                if (proc_open(tcpchild, 2) < 0)
                        droptcb(tcpchild);
        }
@@ -428,35 +498,125 @@ struct tcb *tcp;
 #define CLONE_FS        0x00000200      /* set if fs info shared between processes */
 #define CLONE_FILES     0x00000400      /* set if open files shared between processes */
 #define CLONE_SIGHAND   0x00000800      /* set if signal handlers shared */
-#define CLONE_PID       0x00001000      /* set if pid shared */
+#define CLONE_IDLETASK  0x00001000      /* kernel-only flag */
 #define CLONE_PTRACE    0x00002000      /* set if we want to let tracing continue on the child too */
 #define CLONE_VFORK     0x00004000      /* set if the parent wants the child to wake it up on mm_release */
 #define CLONE_PARENT    0x00008000      /* set if we want to have the same parent as the cloner */
-
-static struct xlat clone_flags[] = {
+#define CLONE_THREAD   0x00010000      /* Same thread group? */
+#define CLONE_NEWNS    0x00020000      /* New namespace group? */
+#define CLONE_SYSVSEM  0x00040000      /* share system V SEM_UNDO semantics */
+#define CLONE_SETTLS   0x00080000      /* create a new TLS for the child */
+#define CLONE_PARENT_SETTID    0x00100000      /* set the TID in the parent */
+#define CLONE_CHILD_CLEARTID   0x00200000      /* clear the TID in the child */
+#define CLONE_DETACHED         0x00400000      /* parent wants no child-exit signal */
+#define CLONE_UNTRACED         0x00800000      /* set if the tracing process can't force CLONE_PTRACE on this clone */
+#define CLONE_CHILD_SETTID     0x01000000      /* set the TID in the child */
+
+static const struct xlat clone_flags[] = {
     { CLONE_VM,                "CLONE_VM"      },
     { CLONE_FS,                "CLONE_FS"      },
     { CLONE_FILES,     "CLONE_FILES"   },
     { CLONE_SIGHAND,   "CLONE_SIGHAND" },
-    { CLONE_PID,       "CLONE_PID"     },
+    { CLONE_IDLETASK,  "CLONE_IDLETASK"},
     { CLONE_PTRACE,    "CLONE_PTRACE"  },
     { CLONE_VFORK,     "CLONE_VFORK"   },
     { CLONE_PARENT,    "CLONE_PARENT"  },
+    { CLONE_THREAD,    "CLONE_THREAD" },
+    { CLONE_NEWNS,     "CLONE_NEWNS" },
+    { CLONE_SYSVSEM,   "CLONE_SYSVSEM" },
+    { CLONE_SETTLS,    "CLONE_SETTLS" },
+    { CLONE_PARENT_SETTID,"CLONE_PARENT_SETTID" },
+    { CLONE_CHILD_CLEARTID,"CLONE_CHILD_CLEARTID" },
+    { CLONE_DETACHED,  "CLONE_DETACHED" },
+    { CLONE_UNTRACED,  "CLONE_UNTRACED" },
+    { CLONE_CHILD_SETTID,"CLONE_CHILD_SETTID" },
     { 0,               NULL            },
 };
 
+# ifdef I386
+#  include <asm/ldt.h>
+#   ifdef HAVE_STRUCT_USER_DESC
+#    define modify_ldt_ldt_s user_desc
+#   endif
+extern void print_ldt_entry();
+# endif
+
+# if defined IA64
+#  define ARG_FLAGS    0
+#  define ARG_STACK    1
+#  define ARG_STACKSIZE        (known_scno(tcp) == SYS_clone2 ? 2 : -1)
+#  define ARG_PTID     (known_scno(tcp) == SYS_clone2 ? 3 : 2)
+#  define ARG_CTID     (known_scno(tcp) == SYS_clone2 ? 4 : 3)
+#  define ARG_TLS      (known_scno(tcp) == SYS_clone2 ? 5 : 4)
+# elif defined S390 || defined S390X
+#  define ARG_STACK    0
+#  define ARG_FLAGS    1
+#  define ARG_PTID     2
+#  define ARG_CTID     3
+#  define ARG_TLS      4
+# elif defined X86_64 || defined ALPHA
+#  define ARG_FLAGS    0
+#  define ARG_STACK    1
+#  define ARG_PTID     2
+#  define ARG_CTID     3
+#  define ARG_TLS      4
+# else
+#  define ARG_FLAGS    0
+#  define ARG_STACK    1
+#  define ARG_PTID     2
+#  define ARG_TLS      3
+#  define ARG_CTID     4
+# endif
+
 int
 sys_clone(tcp)
 struct tcb *tcp;
 {
        if (exiting(tcp)) {
-               tprintf("child_stack=%#lx, flags=", tcp->u_arg[1]);
-               if (printflags(clone_flags, tcp->u_arg[0]) == 0)
-                       tprintf("0");
+               unsigned long flags = tcp->u_arg[ARG_FLAGS];
+               tprintf("child_stack=%#lx, ", tcp->u_arg[ARG_STACK]);
+# ifdef ARG_STACKSIZE
+               if (ARG_STACKSIZE != -1)
+                       tprintf("stack_size=%#lx, ",
+                               tcp->u_arg[ARG_STACKSIZE]);
+# endif
+               tprintf("flags=");
+               printflags(clone_flags, flags &~ CSIGNAL, NULL);
+               if ((flags & CSIGNAL) != 0)
+                       tprintf("|%s", signame(flags & CSIGNAL));
+               if ((flags & (CLONE_PARENT_SETTID|CLONE_CHILD_SETTID
+                             |CLONE_CHILD_CLEARTID|CLONE_SETTLS)) == 0)
+                       return 0;
+               if (flags & CLONE_PARENT_SETTID)
+                       tprintf(", parent_tidptr=%#lx", tcp->u_arg[ARG_PTID]);
+               if (flags & CLONE_SETTLS) {
+# ifdef I386
+                       struct modify_ldt_ldt_s copy;
+                       if (umove(tcp, tcp->u_arg[ARG_TLS], &copy) != -1) {
+                               tprintf(", {entry_number:%d, ",
+                                       copy.entry_number);
+                               if (!verbose(tcp))
+                                       tprintf("...}");
+                               else
+                                       print_ldt_entry(&copy);
+                       }
+                       else
+# endif
+                               tprintf(", tls=%#lx", tcp->u_arg[ARG_TLS]);
+               }
+               if (flags & (CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID))
+                       tprintf(", child_tidptr=%#lx", tcp->u_arg[ARG_CTID]);
        }
        return 0;
 }
 
+int
+sys_unshare(struct tcb *tcp)
+{
+       if (entering(tcp))
+               printflags(clone_flags, tcp->u_arg[0], "CLONE_???");
+       return 0;
+}
 #endif
 
 int
@@ -476,24 +636,29 @@ 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) 
+       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*)(4*PT_R0), new) < 0)
+       if (ptrace(PTRACE_POKEUSER, tcp->pid,
+                  (char*)(sizeof(unsigned long)*PT_R0), new) < 0)
                return -1;
-#elif defined(S390)
-       long    pc;
-       if (upeek(tcp->pid, PT_PSWADDR,&pc)<0)
-               return -1;
-       if (ptrace(PTRACE_POKETEXT, tcp->pid, (char*)(pc-4), 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)
+#elif defined(SPARC) || defined(SPARC64)
        struct regs regs;
        if (ptrace(PTRACE_GETREGS, tcp->pid, (char*)&regs, 0)<0)
                return -1;
@@ -509,10 +674,46 @@ int new;
        if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), 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(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) != 0)
+               return -1;
+
+       return 0;
 #else
 #warning Do not know how to handle change_syscall for this architecture
 #endif /* architecture */
@@ -520,6 +721,7 @@ int new;
        return -1;
 }
 
+#if 0
 int
 setarg(tcp, argnum)
        struct tcb *tcp;
@@ -534,7 +736,7 @@ setarg(tcp, argnum)
 
                ap = ia64_rse_skip_regs(bsp, argnum);
                errno = 0;
-               ptrace(PTRACE_POKEDATA, tcp->pid, ap, tcp->u_arg[argnum]);
+               ptrace(PTRACE_POKEDATA, tcp->pid, (char *) ap, tcp->u_arg[argnum]);
                if (errno)
                        return -1;
 
@@ -545,6 +747,23 @@ setarg(tcp, 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;
@@ -563,13 +782,26 @@ setarg(tcp, 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
 
-#ifdef SYS_clone
+#if defined SYS_clone || defined SYS_clone2
 int
 internal_clone(tcp)
 struct tcb *tcp;
@@ -579,14 +811,8 @@ struct tcb *tcp;
        if (entering(tcp)) {
                if (!followfork)
                        return 0;
-               if (nprocs == MAX_PROCS) {
-                       tcp->flags &= ~TCB_FOLLOWFORK;
-                       fprintf(stderr, "sys_fork: tcb table full\n");
+               if (fork_tcb(tcp))
                        return 0;
-               }
-               tcp->flags |= TCB_FOLLOWFORK;
-
-
                if (setbpt(tcp) < 0)
                        return 0;
        } else {
@@ -595,39 +821,118 @@ struct tcb *tcp;
                if (!(tcp->flags & TCB_FOLLOWFORK))
                        return 0;
 
-               if (bpt)
-                       clearbpt(tcp);
-
-               if (syserror(tcp))
+               if (syserror(tcp)) {
+                       if (bpt)
+                               clearbpt(tcp);
                        return 0;
+               }
 
                pid = tcp->u_rval;
-               if ((tcpchild = alloctcb(pid)) == NULL) {
-                       fprintf(stderr, " [tcb table full]\n");
+
+#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
+               if (fork_tcb(tcp) || (tcpchild = alloctcb(pid)) == NULL) {
+                       if (bpt)
+                               clearbpt(tcp);
                        kill(pid, SIGKILL); /* XXX */
                        return 0;
                }
 
+#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);
                }
-               newoutf(tcpchild);
-               tcp->nchildren++;
-               if (!qflag)
-                       fprintf(stderr, "Process %d attached\n", pid);
-       }
+               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(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
+                               perror("resume: ptrace(PTRACE_SYSCALL, ...)");
+                               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
@@ -636,14 +941,19 @@ 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 (tcp->scno == SYS_vfork) {
+       if (known_scno(tcp) == SYS_vfork) {
                /* Attempt to make vfork into fork, which we can follow. */
-               if (!followvfork || 
+               if (!followvfork ||
                    change_syscall(tcp, SYS_fork) < 0)
                        dont_follow = 1;
        }
@@ -651,12 +961,8 @@ struct tcb *tcp;
        if (entering(tcp)) {
                if (!followfork || dont_follow)
                        return 0;
-               if (nprocs == MAX_PROCS) {
-                       tcp->flags &= ~TCB_FOLLOWFORK;
-                       fprintf(stderr, "sys_fork: tcb table full\n");
+               if (fork_tcb(tcp))
                        return 0;
-               }
-               tcp->flags |= TCB_FOLLOWFORK;
                if (setbpt(tcp) < 0)
                        return 0;
        }
@@ -672,8 +978,7 @@ struct tcb *tcp;
                        return 0;
 
                pid = tcp->u_rval;
-               if ((tcpchild = alloctcb(pid)) == NULL) {
-                       fprintf(stderr, " [tcb table full]\n");
+               if (fork_tcb(tcp) || (tcpchild = alloctcb(pid)) == NULL) {
                        kill(pid, SIGKILL); /* XXX */
                        return 0;
                }
@@ -742,13 +1047,13 @@ struct tcb *tcp;
                        memcpy(tcpchild->inst, tcp->inst,
                                sizeof tcpchild->inst);
                }
-               newoutf(tcpchild);
                tcpchild->parent = tcp;
                tcp->nchildren++;
                if (!qflag)
                        fprintf(stderr, "Process %d attached\n", pid);
        }
        return 0;
+#endif
 }
 
 #endif /* !USE_PROCFS */
@@ -843,15 +1148,15 @@ sys_getresuid(tcp)
                        if (umove(tcp, tcp->u_arg[0], &uid) < 0)
                                tprintf("%#lx, ", tcp->u_arg[0]);
                        else
-                               tprintf("ruid %lu, ", (unsigned long) uid);
-                       if (umove(tcp, tcp->u_arg[0], &uid) < 0)
-                               tprintf("%#lx, ", tcp->u_arg[0]);
+                               tprintf("[%lu], ", (unsigned long) uid);
+                       if (umove(tcp, tcp->u_arg[1], &uid) < 0)
+                               tprintf("%#lx, ", tcp->u_arg[1]);
                        else
-                               tprintf("euid %lu, ", (unsigned long) uid);
-                       if (umove(tcp, tcp->u_arg[0], &uid) < 0)
-                               tprintf("%#lx", tcp->u_arg[0]);
+                               tprintf("[%lu], ", (unsigned long) uid);
+                       if (umove(tcp, tcp->u_arg[2], &uid) < 0)
+                               tprintf("%#lx", tcp->u_arg[2]);
                        else
-                               tprintf("suid %lu", (unsigned long) uid);
+                               tprintf("[%lu]", (unsigned long) uid);
                }
        }
        return 0;
@@ -870,15 +1175,15 @@ struct tcb *tcp;
                        if (umove(tcp, tcp->u_arg[0], &gid) < 0)
                                tprintf("%#lx, ", tcp->u_arg[0]);
                        else
-                               tprintf("rgid %lu, ", (unsigned long) gid);
-                       if (umove(tcp, tcp->u_arg[0], &gid) < 0)
-                               tprintf("%#lx, ", tcp->u_arg[0]);
+                               tprintf("[%lu], ", (unsigned long) gid);
+                       if (umove(tcp, tcp->u_arg[1], &gid) < 0)
+                               tprintf("%#lx, ", tcp->u_arg[1]);
                        else
-                               tprintf("egid %lu, ", (unsigned long) gid);
-                       if (umove(tcp, tcp->u_arg[0], &gid) < 0)
-                               tprintf("%#lx", tcp->u_arg[0]);
+                               tprintf("[%lu], ", (unsigned long) gid);
+                       if (umove(tcp, tcp->u_arg[2], &gid) < 0)
+                               tprintf("%#lx", tcp->u_arg[2]);
                        else
-                               tprintf("sgid %lu", (unsigned long) gid);
+                               tprintf("[%lu]", (unsigned long) gid);
                }
        }
        return 0;
@@ -891,9 +1196,8 @@ sys_setreuid(tcp)
 struct tcb *tcp;
 {
        if (entering(tcp)) {
-               tprintf("%lu, %lu",
-                       (unsigned long) (uid_t) tcp->u_arg[0],
-                       (unsigned long) (uid_t) tcp->u_arg[1]);
+               printuid("", tcp->u_arg[0]);
+               printuid(", ", tcp->u_arg[1]);
        }
        return 0;
 }
@@ -903,9 +1207,8 @@ sys_setregid(tcp)
 struct tcb *tcp;
 {
        if (entering(tcp)) {
-               tprintf("%lu, %lu",
-                       (unsigned long) (gid_t) tcp->u_arg[0],
-                       (unsigned long) (gid_t) tcp->u_arg[1]);
+               printuid("", tcp->u_arg[0]);
+               printuid(", ", tcp->u_arg[1]);
        }
        return 0;
 }
@@ -916,10 +1219,9 @@ sys_setresuid(tcp)
      struct tcb *tcp;
 {
        if (entering(tcp)) {
-               tprintf("ruid %u, euid %u, suid %u",
-                               (uid_t) tcp->u_arg[0],
-                               (uid_t) tcp->u_arg[1],
-                               (uid_t) tcp->u_arg[2]);
+               printuid("", tcp->u_arg[0]);
+               printuid(", ", tcp->u_arg[1]);
+               printuid(", ", tcp->u_arg[2]);
        }
        return 0;
 }
@@ -928,10 +1230,9 @@ sys_setresgid(tcp)
      struct tcb *tcp;
 {
        if (entering(tcp)) {
-               tprintf("rgid %u, egid %u, sgid %u",
-                               (uid_t) tcp->u_arg[0],
-                               (uid_t) tcp->u_arg[1],
-                               (uid_t) tcp->u_arg[2]);
+               printuid("", tcp->u_arg[0]);
+               printuid(", ", tcp->u_arg[1]);
+               printuid(", ", tcp->u_arg[2]);
        }
        return 0;
 }
@@ -942,34 +1243,53 @@ int
 sys_setgroups(tcp)
 struct tcb *tcp;
 {
-       int i, len;
-       GETGROUPS_T *gidset;
-
        if (entering(tcp)) {
+               unsigned long len, size, start, cur, end, abbrev_end;
+               GETGROUPS_T gid;
+               int failed = 0;
+
                len = tcp->u_arg[0];
-               tprintf("%u, ", len);
-               if (len <= 0) {
+               tprintf("%lu, ", len);
+               if (len == 0) {
                        tprintf("[]");
                        return 0;
                }
-               gidset = (GETGROUPS_T *) malloc(len * sizeof(GETGROUPS_T));
-               if (gidset == NULL) {
-                       fprintf(stderr, "sys_setgroups: out of memory\n");
-                       return -1;
+               start = tcp->u_arg[1];
+               if (start == 0) {
+                       tprintf("NULL");
+                       return 0;
                }
-               if (!verbose(tcp))
-                       tprintf("%#lx", tcp->u_arg[1]);
-               else if (umoven(tcp, tcp->u_arg[1],
-                   len * sizeof(GETGROUPS_T), (char *) gidset) < 0)
-                       tprintf("[?]");
-               else {
-                       tprintf("[");
-                       for (i = 0; i < len; i++)
-                               tprintf("%s%lu", i ? ", " : "",
-                                       (unsigned long) gidset[i]);
-                       tprintf("]");
+               size = len * sizeof(gid);
+               end = start + size;
+               if (!verbose(tcp) || size / sizeof(gid) != len || end < start) {
+                       tprintf("%#lx", start);
+                       return 0;
                }
-               free((char *) gidset);
+               if (abbrev(tcp)) {
+                       abbrev_end = start + max_strlen * sizeof(gid);
+                       if (abbrev_end < start)
+                               abbrev_end = end;
+               } else {
+                       abbrev_end = end;
+               }
+               tprintf("[");
+               for (cur = start; cur < end; cur += sizeof(gid)) {
+                       if (cur > start)
+                               tprintf(", ");
+                       if (cur >= abbrev_end) {
+                               tprintf("...");
+                               break;
+                       }
+                       if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
+                               tprintf("?");
+                               failed = 1;
+                               break;
+                       }
+                       tprintf("%lu", (unsigned long) gid);
+               }
+               tprintf("]");
+               if (failed)
+                       tprintf(" %#lx", tcp->u_arg[1]);
        }
        return 0;
 }
@@ -978,42 +1298,184 @@ int
 sys_getgroups(tcp)
 struct tcb *tcp;
 {
-       int i, len;
-       GETGROUPS_T *gidset;
+       unsigned long len;
 
        if (entering(tcp)) {
                len = tcp->u_arg[0];
-               tprintf("%u, ", len);
+               tprintf("%lu, ", len);
        } else {
+               unsigned long size, start, cur, end, abbrev_end;
+               GETGROUPS_T gid;
+               int failed = 0;
+
                len = tcp->u_rval;
-               if (len <= 0) {
+               if (len == 0) {
                        tprintf("[]");
                        return 0;
                }
-               gidset = (GETGROUPS_T *) malloc(len * sizeof(GETGROUPS_T));
-               if (gidset == NULL) {
-                       fprintf(stderr, "sys_getgroups: out of memory\n");
-                       return -1;
+               start = tcp->u_arg[1];
+               if (start == 0) {
+                       tprintf("NULL");
+                       return 0;
                }
-               if (!tcp->u_arg[1])
+               if (tcp->u_arg[0] == 0) {
+                       tprintf("%#lx", start);
+                       return 0;
+               }
+               size = len * sizeof(gid);
+               end = start + size;
+               if (!verbose(tcp) || tcp->u_arg[0] == 0 ||
+                   size / sizeof(gid) != len || end < start) {
+                       tprintf("%#lx", start);
+                       return 0;
+               }
+               if (abbrev(tcp)) {
+                       abbrev_end = start + max_strlen * sizeof(gid);
+                       if (abbrev_end < start)
+                               abbrev_end = end;
+               } else {
+                       abbrev_end = end;
+               }
+               tprintf("[");
+               for (cur = start; cur < end; cur += sizeof(gid)) {
+                       if (cur > start)
+                               tprintf(", ");
+                       if (cur >= abbrev_end) {
+                               tprintf("...");
+                               break;
+                       }
+                       if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
+                               tprintf("?");
+                               failed = 1;
+                               break;
+                       }
+                       tprintf("%lu", (unsigned long) gid);
+               }
+               tprintf("]");
+               if (failed)
+                       tprintf(" %#lx", tcp->u_arg[1]);
+       }
+       return 0;
+}
+
+#ifdef LINUX
+int
+sys_setgroups32(tcp)
+struct tcb *tcp;
+{
+       if (entering(tcp)) {
+               unsigned long len, size, start, cur, end, abbrev_end;
+               GETGROUPS32_T gid;
+               int failed = 0;
+
+               len = tcp->u_arg[0];
+               tprintf("%lu, ", len);
+               if (len == 0) {
+                       tprintf("[]");
+                       return 0;
+               }
+               start = tcp->u_arg[1];
+               if (start == 0) {
                        tprintf("NULL");
-               else if (!verbose(tcp) || tcp->u_arg[0] == 0)
-                       tprintf("%#lx", tcp->u_arg[1]);
-               else if (umoven(tcp, tcp->u_arg[1],
-                   len * sizeof(GETGROUPS_T), (char *) gidset) < 0)
-                       tprintf("[?]");
-               else {
-                       tprintf("[");
-                       for (i = 0; i < len; i++)
-                               tprintf("%s%lu", i ? ", " : "",
-                                       (unsigned long) gidset[i]);
-                       tprintf("]");
+                       return 0;
+               }
+               size = len * sizeof(gid);
+               end = start + size;
+               if (!verbose(tcp) || size / sizeof(gid) != len || end < start) {
+                       tprintf("%#lx", start);
+                       return 0;
+               }
+               if (abbrev(tcp)) {
+                       abbrev_end = start + max_strlen * sizeof(gid);
+                       if (abbrev_end < start)
+                               abbrev_end = end;
+               } else {
+                       abbrev_end = end;
                }
-               free((char *)gidset);
+               tprintf("[");
+               for (cur = start; cur < end; cur += sizeof(gid)) {
+                       if (cur > start)
+                               tprintf(", ");
+                       if (cur >= abbrev_end) {
+                               tprintf("...");
+                               break;
+                       }
+                       if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
+                               tprintf("?");
+                               failed = 1;
+                               break;
+                       }
+                       tprintf("%lu", (unsigned long) gid);
+               }
+               tprintf("]");
+               if (failed)
+                       tprintf(" %#lx", tcp->u_arg[1]);
        }
        return 0;
 }
 
+int
+sys_getgroups32(tcp)
+struct tcb *tcp;
+{
+       unsigned long len;
+
+       if (entering(tcp)) {
+               len = tcp->u_arg[0];
+               tprintf("%lu, ", len);
+       } else {
+               unsigned long size, start, cur, end, abbrev_end;
+               GETGROUPS32_T gid;
+               int failed = 0;
+
+               len = tcp->u_rval;
+               if (len == 0) {
+                       tprintf("[]");
+                       return 0;
+               }
+               start = tcp->u_arg[1];
+               if (start == 0) {
+                       tprintf("NULL");
+                       return 0;
+               }
+               size = len * sizeof(gid);
+               end = start + size;
+               if (!verbose(tcp) || tcp->u_arg[0] == 0 ||
+                   size / sizeof(gid) != len || end < start) {
+                       tprintf("%#lx", start);
+                       return 0;
+               }
+               if (abbrev(tcp)) {
+                       abbrev_end = start + max_strlen * sizeof(gid);
+                       if (abbrev_end < start)
+                               abbrev_end = end;
+               } else {
+                       abbrev_end = end;
+               }
+               tprintf("[");
+               for (cur = start; cur < end; cur += sizeof(gid)) {
+                       if (cur > start)
+                               tprintf(", ");
+                       if (cur >= abbrev_end) {
+                               tprintf("...");
+                               break;
+                       }
+                       if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
+                               tprintf("?");
+                               failed = 1;
+                               break;
+                       }
+                       tprintf("%lu", (unsigned long) gid);
+               }
+               tprintf("]");
+               if (failed)
+                       tprintf(" %#lx", tcp->u_arg[1]);
+       }
+       return 0;
+}
+#endif /* LINUX */
+
+#if defined(ALPHA) || defined(SUNOS4) || defined(SVR4)
 int
 sys_setpgrp(tcp)
 struct tcb *tcp;
@@ -1025,6 +1487,7 @@ struct tcb *tcp;
        }
        return 0;
 }
+#endif /* ALPHA || SUNOS4 || SVR4 */
 
 int
 sys_getpgrp(tcp)
@@ -1075,39 +1538,144 @@ struct tcb *tcp;
        return 0;
 }
 
-void
-fake_execve(tcp, program, argv, envp)
+#if UNIXWARE >= 2
+
+#include <sys/privilege.h>
+
+
+static const struct xlat procpriv_cmds [] = {
+       { SETPRV,       "SETPRV"        },
+       { CLRPRV,       "CLRPRV"        },
+       { PUTPRV,       "PUTPRV"        },
+       { GETPRV,       "GETPRV"        },
+       { CNTPRV,       "CNTPRV"        },
+       { 0,            NULL            },
+};
+
+
+static const struct xlat procpriv_priv [] = {
+       { P_OWNER,      "P_OWNER"       },
+       { P_AUDIT,      "P_AUDIT"       },
+       { P_COMPAT,     "P_COMPAT"      },
+       { P_DACREAD,    "P_DACREAD"     },
+       { P_DACWRITE,   "P_DACWRITE"    },
+       { P_DEV,        "P_DEV"         },
+       { P_FILESYS,    "P_FILESYS"     },
+       { P_MACREAD,    "P_MACREAD"     },
+       { P_MACWRITE,   "P_MACWRITE"    },
+       { P_MOUNT,      "P_MOUNT"       },
+       { P_MULTIDIR,   "P_MULTIDIR"    },
+       { P_SETPLEVEL,  "P_SETPLEVEL"   },
+       { P_SETSPRIV,   "P_SETSPRIV"    },
+       { P_SETUID,     "P_SETUID"      },
+       { P_SYSOPS,     "P_SYSOPS"      },
+       { P_SETUPRIV,   "P_SETUPRIV"    },
+       { P_DRIVER,     "P_DRIVER"      },
+       { P_RTIME,      "P_RTIME"       },
+       { P_MACUPGRADE, "P_MACUPGRADE"  },
+       { P_FSYSRANGE,  "P_FSYSRANGE"   },
+       { P_SETFLEVEL,  "P_SETFLEVEL"   },
+       { P_AUDITWR,    "P_AUDITWR"     },
+       { P_TSHAR,      "P_TSHAR"       },
+       { P_PLOCK,      "P_PLOCK"       },
+       { P_CORE,       "P_CORE"        },
+       { P_LOADMOD,    "P_LOADMOD"     },
+       { P_BIND,       "P_BIND"        },
+       { P_ALLPRIVS,   "P_ALLPRIVS"    },
+       { 0,            NULL            },
+};
+
+
+static const struct xlat procpriv_type [] = {
+       { PS_FIX,       "PS_FIX"        },
+       { PS_INH,       "PS_INH"        },
+       { PS_MAX,       "PS_MAX"        },
+       { PS_WKG,       "PS_WKG"        },
+       { 0,            NULL            },
+};
+
+
+static void
+printpriv(tcp, addr, len, opt)
 struct tcb *tcp;
-char *program;
-char *argv[];
-char *envp[];
+long addr;
+int len;
+const struct xlat *opt;
 {
+       priv_t buf [128];
+       int max = verbose (tcp) ? sizeof buf / sizeof buf [0] : 10;
+       int dots = len > max;
        int i;
 
-#ifdef ARM
-       if (!(qual_flags[SYS_execve - __NR_SYSCALL_BASE] & QUAL_TRACE))
-               return;
-#else
-       if (!(qual_flags[SYS_execve] & QUAL_TRACE))
+       if (len > max) len = max;
+
+       if (len <= 0 ||
+           umoven (tcp, addr, len * sizeof buf[0], (char *) buf) < 0)
+       {
+               tprintf ("%#lx", addr);
                return;
-#endif /* !ARM */
-       printleader(tcp);
-       tprintf("execve(");
-       string_quote(program);
-       tprintf(", [");
-       for (i = 0; argv[i] != NULL; i++) {
-               if (i != 0)
-                       tprintf(", ");
-               string_quote(argv[i]);
        }
-       for (i = 0; envp[i] != NULL; i++)
-               ;
-       tprintf("], [/* %d var%s */]) ", i, (i != 1) ? "s" : "");
-       tabto(acolumn);
-       tprintf("= 0");
-       printtrailer(tcp);
+
+       tprintf ("[");
+
+       for (i = 0; i < len; ++i) {
+               char *t, *p;
+
+               if (i) tprintf (", ");
+
+               if ((t = xlookup (procpriv_type, buf [i] & PS_TYPE)) &&
+                   (p = xlookup (procpriv_priv, buf [i] & ~PS_TYPE)))
+               {
+                       tprintf ("%s|%s", t, p);
+               }
+               else {
+                       tprintf ("%#lx", buf [i]);
+               }
+       }
+
+       if (dots) tprintf (" ...");
+
+       tprintf ("]");
+}
+
+
+int
+sys_procpriv(tcp)
+struct tcb *tcp;
+{
+       if (entering(tcp)) {
+               printxval(procpriv_cmds, tcp->u_arg[0], "???PRV");
+               switch (tcp->u_arg[0]) {
+                   case CNTPRV:
+                       tprintf(", %#lx, %ld", tcp->u_arg[1], tcp->u_arg[2]);
+                       break;
+
+                   case GETPRV:
+                       break;
+
+                   default:
+                       tprintf (", ");
+                       printpriv (tcp, tcp->u_arg[1], tcp->u_arg[2]);
+                       tprintf (", %ld", tcp->u_arg[2]);
+               }
+       }
+       else if (tcp->u_arg[0] == GETPRV) {
+               if (syserror (tcp)) {
+                       tprintf(", %#lx, %ld", tcp->u_arg[1], tcp->u_arg[2]);
+               }
+               else {
+                       tprintf (", ");
+                       printpriv (tcp, tcp->u_arg[1], tcp->u_rval);
+                       tprintf (", %ld", tcp->u_arg[2]);
+               }
+       }
+
+       return 0;
 }
 
+#endif
+
+
 static void
 printargv(tcp, addr)
 struct tcb *tcp;
@@ -1149,6 +1717,7 @@ long addr;
        tprintf(fmt, count, count == 1 ? "" : "s");
 }
 
+#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
 int
 sys_execv(tcp)
 struct tcb *tcp;
@@ -1169,6 +1738,7 @@ struct tcb *tcp;
        }
        return 0;
 }
+#endif /* SPARC || SPARC64 || SUNOS4 */
 
 int
 sys_execve(tcp)
@@ -1197,11 +1767,6 @@ struct tcb *tcp;
                        tprintf("]");
                }
        }
-#ifdef LINUX
-#if defined(ALPHA) || defined(SPARC) || defined(POWERPC) || defined(HPPA)
-       tcp->flags |= TCB_WAITEXECVE;
-#endif /* ALPHA || SPARC || POWERPC */
-#endif /* LINUX */
        return 0;
 }
 
@@ -1227,16 +1792,28 @@ struct tcb *tcp;
        if (exiting(tcp) && !syserror(tcp) && followfork)
                fixvfork(tcp);
 #endif /* SUNOS4 */
+#if defined LINUX && defined TCB_WAITEXECVE
+       if (exiting(tcp) && syserror(tcp))
+               tcp->flags &= ~TCB_WAITEXECVE;
+       else
+               tcp->flags |= TCB_WAITEXECVE;
+#endif /* LINUX && TCB_WAITEXECVE */
        return 0;
 }
 
 #ifdef LINUX
+#ifndef __WNOTHREAD
+#define __WNOTHREAD    0x20000000
+#endif
+#ifndef __WALL
+#define __WALL         0x40000000
+#endif
 #ifndef __WCLONE
-#define __WCLONE       0x8000000
+#define __WCLONE       0x80000000
 #endif
 #endif /* LINUX */
 
-static struct xlat wait4_options[] = {
+static const struct xlat wait4_options[] = {
        { WNOHANG,      "WNOHANG"       },
 #ifndef WSTOPPED
        { WUNTRACED,    "WUNTRACED"     },
@@ -1258,10 +1835,30 @@ static struct xlat wait4_options[] = {
 #endif
 #ifdef __WCLONE
        { __WCLONE,     "__WCLONE"      },
+#endif
+#ifdef __WALL
+       { __WALL,       "__WALL"        },
+#endif
+#ifdef __WNOTHREAD
+       { __WNOTHREAD,  "__WNOTHREAD"   },
 #endif
        { 0,            NULL            },
 };
 
+#if !defined WCOREFLAG && defined WCOREFLG
+# define WCOREFLAG WCOREFLG
+#endif
+#ifndef WCOREFLAG
+#define WCOREFLAG 0x80
+#endif
+
+#ifndef W_STOPCODE
+#define W_STOPCODE(sig)                ((sig) << 8 | 0x7f)
+#endif
+#ifndef W_EXITCODE
+#define W_EXITCODE(ret, sig)   ((ret) << 8 | (sig))
+#endif
+
 static int
 printstatus(status)
 int status;
@@ -1273,20 +1870,33 @@ int status;
         * is still not entirely satisfactory but since there
         * are no wait status constructors it will have to do.
         */
-       if (WIFSTOPPED(status))
-               tprintf("[WIFSTOPPED(s) && WSTOPSIG(s) == %s]",
+       if (WIFSTOPPED(status)) {
+               tprintf("[{WIFSTOPPED(s) && WSTOPSIG(s) == %s}",
                        signame(WSTOPSIG(status)));
-       else if WIFSIGNALED(status)
-               tprintf("[WIFSIGNALED(s) && WTERMSIG(s) == %s%s]",
+               status &= ~W_STOPCODE(WSTOPSIG(status));
+       }
+       else if (WIFSIGNALED(status)) {
+               tprintf("[{WIFSIGNALED(s) && WTERMSIG(s) == %s%s}",
                        signame(WTERMSIG(status)),
                        WCOREDUMP(status) ? " && WCOREDUMP(s)" : "");
-       else if WIFEXITED(status) {
-               tprintf("[WIFEXITED(s) && WEXITSTATUS(s) == %d]",
+               status &= ~(W_EXITCODE(0, WTERMSIG(status)) | WCOREFLAG);
+       }
+       else if (WIFEXITED(status)) {
+               tprintf("[{WIFEXITED(s) && WEXITSTATUS(s) == %d}",
                        WEXITSTATUS(status));
                exited = 1;
+               status &= ~W_EXITCODE(WEXITSTATUS(status), 0);
        }
-       else
+       else {
                tprintf("[%#x]", status);
+               return 0;
+       }
+
+       if (status == 0)
+               tprintf("]");
+       else
+               tprintf(" | %#x]", status);
+
        return exited;
 }
 
@@ -1313,8 +1923,7 @@ int bitness;
                        exited = printstatus(status);
                /* options */
                tprintf(", ");
-               if (!printflags(wait4_options, tcp->u_arg[2]))
-                       tprintf("0");
+               printflags(wait4_options, tcp->u_arg[2], "W???");
                if (n == 4) {
                        tprintf(", ");
                        /* usage */
@@ -1342,17 +1951,91 @@ int bitness;
 }
 
 int
-internal_wait(tcp)
+internal_wait(tcp, flagarg)
 struct tcb *tcp;
+int flagarg;
 {
-       if (entering(tcp)) {
-               /* WTA: fix bug with hanging children */
-               if (!(tcp->u_arg[2] & WNOHANG) && tcp->nchildren > 0) {
-                       /* There are traced children */
+       int got_kids;
+
+#ifdef TCB_CLONE_THREAD
+       if (tcp->flags & TCB_CLONE_THREAD)
+               /* The children we wait for are our parent's children.  */
+               got_kids = (tcp->parent->nchildren
+                           > tcp->parent->nclone_detached);
+       else
+               got_kids = (tcp->nchildren > tcp->nclone_detached);
+#else
+       got_kids = tcp->nchildren > 0;
+#endif
+
+       if (entering(tcp) && got_kids) {
+               /* There are children that this parent should block for.
+                  But ptrace made us the parent of the traced children
+                  and the real parent will get ECHILD from the wait call.
+
+                  XXX If we attached with strace -f -p PID, then there
+                  may be untraced dead children the parent could be reaping
+                  now, but we make him block.  */
+
+               /* ??? WTA: fix bug with hanging children */
+
+               if (!(tcp->u_arg[flagarg] & WNOHANG)) {
+                       /*
+                        * There are traced children.  We'll make the parent
+                        * block to avoid a false ECHILD error due to our
+                        * ptrace having stolen the children.  However,
+                        * we shouldn't block if there are zombies to reap.
+                        * XXX doesn't handle pgrp matches (u_arg[0]==0,<-1)
+                        */
+                       struct tcb *child = NULL;
+                       if (tcp->nzombies > 0 &&
+                           (tcp->u_arg[0] == -1 ||
+                            (child = pid2tcb(tcp->u_arg[0])) == NULL))
+                               return 0;
+                       if (tcp->u_arg[0] > 0) {
+                               /*
+                                * If the parent waits for a specified child
+                                * PID, then it must get ECHILD right away
+                                * if that PID is not one of its children.
+                                * Make sure that the requested PID matches
+                                * one of the parent's children that we are
+                                * tracing, and don't suspend it otherwise.
+                                */
+                               if (child == NULL)
+                                       child = pid2tcb(tcp->u_arg[0]);
+                               if (child == NULL || child->parent != (
+#ifdef TCB_CLONE_THREAD
+                                           (tcp->flags & TCB_CLONE_THREAD)
+                                           ? tcp->parent :
+#endif
+                                           tcp) ||
+                                   (child->flags & TCB_EXITING))
+                                       return 0;
+                       }
                        tcp->flags |= TCB_SUSPENDED;
                        tcp->waitpid = tcp->u_arg[0];
+#ifdef TCB_CLONE_THREAD
+                       if (tcp->flags & TCB_CLONE_THREAD)
+                               tcp->parent->nclone_waiting++;
+#endif
                }
        }
+       if (exiting(tcp) && tcp->u_error == ECHILD && got_kids) {
+               if (tcp->u_arg[flagarg] & WNOHANG) {
+                       /* We must force a fake result of 0 instead of
+                          the ECHILD error.  */
+                       extern int force_result();
+                       return force_result(tcp, 0, 0);
+               }
+       }
+       else if (exiting(tcp) && tcp->u_error == 0 && tcp->u_rval > 0 &&
+                tcp->nzombies > 0 && pid2tcb(tcp->u_rval) == NULL) {
+               /*
+                * We just reaped a child we don't know about,
+                * presumably a zombie we already droptcb'd.
+                */
+               tcp->nzombies--;
+       }
        return 0;
 }
 
@@ -1378,7 +2061,7 @@ sys_wait(tcp)
 struct tcb *tcp;
 {
        int status;
-       
+
        if (exiting(tcp)) {
                if (!syserror(tcp)) {
                        if (umove(tcp, tcp->u_arg[0], &status) < 0)
@@ -1414,16 +2097,26 @@ struct tcb *tcp;
 }
 #endif
 
-#ifdef SVR4
+#if defined SVR4 || defined LINUX
 
-static struct xlat waitid_types[] = {
+static const struct xlat waitid_types[] = {
        { P_PID,        "P_PID"         },
+#ifdef P_PPID
        { P_PPID,       "P_PPID"        },
+#endif
        { P_PGID,       "P_PGID"        },
+#ifdef P_SID
        { P_SID,        "P_SID"         },
+#endif
+#ifdef P_CID
        { P_CID,        "P_CID"         },
+#endif
+#ifdef P_UID
        { P_UID,        "P_UID"         },
+#endif
+#ifdef P_GID
        { P_GID,        "P_GID"         },
+#endif
        { P_ALL,        "P_ALL"         },
 #ifdef P_LWPID
        { P_LWPID,      "P_LWPID"       },
@@ -1431,213 +2124,6 @@ static struct xlat waitid_types[] = {
        { 0,            NULL            },
 };
 
-static struct xlat siginfo_codes[] = {
-#ifdef SI_NOINFO
-       { SI_NOINFO,    "SI_NOINFO"     },
-#endif
-#ifdef SI_USER
-       { SI_USER,      "SI_USER"       },
-#endif
-#ifdef SI_LWP
-       { SI_LWP,       "SI_LWP"        },
-#endif
-#ifdef SI_QUEUE
-       { SI_QUEUE,     "SI_QUEUE"      },
-#endif
-#ifdef SI_TIMER
-       { SI_TIMER,     "SI_TIMER"      },
-#endif
-#ifdef SI_ASYNCIO
-       { SI_ASYNCIO,   "SI_ASYNCIO"    },
-#endif
-#ifdef SI_MESGQ
-       { SI_MESGQ,     "SI_MESGQ"      },
-#endif
-       { 0,            NULL            },
-};
-
-static struct xlat sigtrap_codes[] = {
-       { TRAP_BRKPT,   "TRAP_BRKPT"    },
-       { TRAP_TRACE,   "TRAP_TRACE"    },
-       { 0,            NULL            },
-};
-
-static struct xlat sigcld_codes[] = {
-       { CLD_EXITED,   "CLD_EXITED"    },
-       { CLD_KILLED,   "CLD_KILLED"    },
-       { CLD_DUMPED,   "CLD_DUMPED"    },
-       { CLD_TRAPPED,  "CLD_TRAPPED"   },
-       { CLD_STOPPED,  "CLD_STOPPED"   },
-       { CLD_CONTINUED,"CLD_CONTINUED" },
-       { 0,            NULL            },
-};
-
-static struct xlat sigpoll_codes[] = {
-       { POLL_IN,      "POLL_IN"       },
-       { POLL_OUT,     "POLL_OUT"      },
-       { POLL_MSG,     "POLL_MSG"      },
-       { POLL_ERR,     "POLL_ERR"      },
-       { POLL_PRI,     "POLL_PRI"      },
-       { POLL_HUP,     "POLL_HUP"      },
-       { 0,            NULL            },
-};
-
-static struct xlat sigprof_codes[] = {
-#ifdef PROF_SIG
-       { PROF_SIG,     "PROF_SIG"      },
-#endif
-       { 0,            NULL            },
-};
-
-static struct xlat sigill_codes[] = {
-       { ILL_ILLOPC,   "ILL_ILLOPC"    },
-       { ILL_ILLOPN,   "ILL_ILLOPN"    },
-       { ILL_ILLADR,   "ILL_ILLADR"    },
-       { ILL_ILLTRP,   "ILL_ILLTRP"    },
-       { ILL_PRVOPC,   "ILL_PRVOPC"    },
-       { ILL_PRVREG,   "ILL_PRVREG"    },
-       { ILL_COPROC,   "ILL_COPROC"    },
-       { ILL_BADSTK,   "ILL_BADSTK"    },
-       { 0,            NULL            },
-};
-
-static struct xlat sigemt_codes[] = {
-#ifdef EMT_TAGOVF
-       { EMT_TAGOVF,   "EMT_TAGOVF"    },
-#endif
-       { 0,            NULL            },
-};
-
-static struct xlat sigfpe_codes[] = {
-       { FPE_INTDIV,   "FPE_INTDIV"    },
-       { FPE_INTOVF,   "FPE_INTOVF"    },
-       { FPE_FLTDIV,   "FPE_FLTDIV"    },
-       { FPE_FLTOVF,   "FPE_FLTOVF"    },
-       { FPE_FLTUND,   "FPE_FLTUND"    },
-       { FPE_FLTRES,   "FPE_FLTRES"    },
-       { FPE_FLTINV,   "FPE_FLTINV"    },
-       { FPE_FLTSUB,   "FPE_FLTSUB"    },
-       { 0,            NULL            },
-};
-
-static struct xlat sigsegv_codes[] = {
-       { SEGV_MAPERR,  "SEGV_MAPERR"   },
-       { SEGV_ACCERR,  "SEGV_ACCERR"   },
-       { 0,            NULL            },
-};
-
-static struct xlat sigbus_codes[] = {
-       { BUS_ADRALN,   "BUS_ADRALN"    },
-       { BUS_ADRERR,   "BUS_ADRERR"    },
-       { BUS_OBJERR,   "BUS_OBJERR"    },
-       { 0,            NULL            },
-};
-
-void
-printsiginfo(sip)
-siginfo_t *sip;
-{
-       char *code;
-
-       tprintf("{si_signo=");
-       printsignal(sip->si_signo);
-       code = xlookup(siginfo_codes, sip->si_code);
-       if (!code) {
-               switch (sip->si_signo) {
-               case SIGTRAP:
-                       code = xlookup(sigtrap_codes, sip->si_code);
-                       break;
-               case SIGCHLD:
-                       code = xlookup(sigcld_codes, sip->si_code);
-                       break;
-               case SIGPOLL:
-                       code = xlookup(sigpoll_codes, sip->si_code);
-                       break;
-               case SIGPROF:
-                       code = xlookup(sigprof_codes, sip->si_code);
-                       break;
-               case SIGILL:
-                       code = xlookup(sigill_codes, sip->si_code);
-                       break;
-               case SIGEMT:
-                       code = xlookup(sigemt_codes, sip->si_code);
-                       break;
-               case SIGFPE:
-                       code = xlookup(sigfpe_codes, sip->si_code);
-                       break;
-               case SIGSEGV:
-                       code = xlookup(sigsegv_codes, sip->si_code);
-                       break;
-               case SIGBUS:
-                       code = xlookup(sigbus_codes, sip->si_code);
-                       break;
-               }
-       }
-       if (code)
-               tprintf(", si_code=%s", code);
-       else
-               tprintf(", si_code=%#x", sip->si_code);
-#ifdef SI_NOINFO
-       if (sip->si_code != SI_NOINFO) {
-#endif
-               if (sip->si_errno) {
-                       if (sip->si_errno < 0 || sip->si_errno >= nerrnos)
-                               tprintf(", si_errno=%d", sip->si_errno);
-                       else
-                               tprintf(", si_errno=%s",
-                                       errnoent[sip->si_errno]);
-               }
-               if (SI_FROMUSER(sip)) {
-#ifdef SI_QUEUE
-                       tprintf(", si_pid=%ld, si_uid=%ld",
-                               sip->si_pid, sip->si_uid);
-                       switch (sip->si_code) {
-                       case SI_QUEUE:
-#ifdef SI_TIMER
-                       case SI_TIMER:
-#endif /* SI_QUEUE */
-                       case SI_ASYNCIO:
-#ifdef SI_MESGQ
-                       case SI_MESGQ:
-#endif /* SI_MESGQ */
-                               tprintf(", si_value=%d",
-                                       sip->si_value.sival_int);
-                               break;
-                       }
-#endif /* SI_QUEUE */
-               }
-               else {
-                       switch (sip->si_signo) {
-                       case SIGCHLD:
-                               tprintf(", si_pid=%ld, si_status=",
-                                       sip->si_pid);
-                               if (sip->si_code == CLD_EXITED)
-                                       tprintf("%d", sip->si_status);
-                               else
-                                       printsignal(sip->si_status);
-                               break;
-                       case SIGILL: case SIGFPE:
-                       case SIGSEGV: case SIGBUS:
-                               tprintf(", si_addr=%#lx",
-                                       (unsigned long) sip->si_addr);
-                               break;
-                       case SIGPOLL:
-                               switch (sip->si_code) {
-                               case POLL_IN: case POLL_OUT: case POLL_MSG:
-                                       tprintf(", si_band=%ld",
-                                               (long) sip->si_band);
-                                       break;
-                               }
-                               break;
-                       }
-               }
-               tprintf(", ...");
-#ifdef SI_NOINFO
-       }
-#endif
-       tprintf("}");
-}
-
 int
 sys_waitid(tcp)
 struct tcb *tcp;
@@ -1648,11 +2134,6 @@ struct tcb *tcp;
        if (entering(tcp)) {
                printxval(waitid_types, tcp->u_arg[0], "P_???");
                tprintf(", %ld, ", tcp->u_arg[1]);
-               if (tcp->nchildren > 0) {
-                       /* There are traced children */
-                       tcp->flags |= TCB_SUSPENDED;
-                       tcp->waitpid = tcp->u_arg[0];
-               }
        }
        else {
                /* siginfo */
@@ -1664,16 +2145,25 @@ struct tcb *tcp;
                else if (umove(tcp, tcp->u_arg[2], &si) < 0)
                        tprintf("{???}");
                else
-                       printsiginfo(&si);
+                       printsiginfo(&si, verbose (tcp));
                /* options */
                tprintf(", ");
-               if (!printflags(wait4_options, tcp->u_arg[3]))
-                       tprintf("0");
+               printflags(wait4_options, tcp->u_arg[3], "W???");
+               if (tcp->u_nargs > 4) {
+                       /* usage */
+                       tprintf(", ");
+                       if (!tcp->u_arg[4])
+                               tprintf("NULL");
+                       else if (tcp->u_error)
+                               tprintf("%#lx", tcp->u_arg[4]);
+                       else
+                               printrusage(tcp, tcp->u_arg[4]);
+               }
        }
        return 0;
 }
 
-#endif /* SVR4 */
+#endif /* SVR4 or LINUX */
 
 int
 sys_alarm(tcp)
@@ -1718,8 +2208,8 @@ struct tcb *tcp;
 
 #ifndef SVR4
 
-static struct xlat ptrace_cmds[] = {
-#ifndef FREEBSD        
+static const struct xlat ptrace_cmds[] = {
+#ifndef FREEBSD
        { PTRACE_TRACEME,       "PTRACE_TRACEME"        },
        { PTRACE_PEEKTEXT,      "PTRACE_PEEKTEXT",      },
        { PTRACE_PEEKDATA,      "PTRACE_PEEKDATA",      },
@@ -1732,11 +2222,31 @@ static struct xlat ptrace_cmds[] = {
        { PTRACE_SINGLESTEP,    "PTRACE_SINGLESTEP"     },
        { PTRACE_ATTACH,        "PTRACE_ATTACH"         },
        { PTRACE_DETACH,        "PTRACE_DETACH"         },
-#ifdef SUNOS4
+#ifdef PTRACE_GETREGS
        { PTRACE_GETREGS,       "PTRACE_GETREGS"        },
+#endif
+#ifdef PTRACE_SETREGS
        { PTRACE_SETREGS,       "PTRACE_SETREGS"        },
+#endif
+#ifdef PTRACE_GETFPREGS
        { PTRACE_GETFPREGS,     "PTRACE_GETFPREGS",     },
+#endif
+#ifdef PTRACE_SETFPREGS
        { PTRACE_SETFPREGS,     "PTRACE_SETFPREGS",     },
+#endif
+#ifdef PTRACE_GETFPXREGS
+       { PTRACE_GETFPXREGS,    "PTRACE_GETFPXREGS",    },
+#endif
+#ifdef PTRACE_SETFPXREGS
+       { PTRACE_SETFPXREGS,    "PTRACE_SETFPXREGS",    },
+#endif
+#ifdef PTRACE_GETVRREGS
+       { PTRACE_GETVRREGS,     "PTRACE_GETVRREGS",     },
+#endif
+#ifdef PTRACE_SETVRREGS
+       { PTRACE_SETVRREGS,     "PTRACE_SETVRREGS",     },
+#endif
+#ifdef SUNOS4
        { PTRACE_READDATA,      "PTRACE_READDATA"       },
        { PTRACE_WRITEDATA,     "PTRACE_WRITEDATA"      },
        { PTRACE_READTEXT,      "PTRACE_READTEXT"       },
@@ -1771,7 +2281,9 @@ static struct xlat ptrace_cmds[] = {
        { PT_READ_D,            "PT_READ_D"             },
        { PT_WRITE_I,           "PT_WRITE_I"            },
        { PT_WRITE_D,           "PT_WRITE_D"            },
-       { PT_READ_U,            "PT_WRITE_U"            },
+#ifdef PT_READ_U
+       { PT_READ_U,            "PT_READ_U"             },
+#endif
        { PT_CONTINUE,          "PT_CONTINUE"           },
        { PT_KILL,              "PT_KILL"               },
        { PT_STEP,              "PT_STEP"               },
@@ -1791,9 +2303,9 @@ static struct xlat ptrace_cmds[] = {
 #ifndef SUNOS4_KERNEL_ARCH_KLUDGE
 static
 #endif /* !SUNOS4_KERNEL_ARCH_KLUDGE */
-struct xlat struct_user_offsets[] = {
+const struct xlat struct_user_offsets[] = {
 #ifdef LINUX
-#ifdef S390
+#if defined(S390) || defined(S390X)
        { PT_PSWMASK,           "psw_mask"                              },
        { PT_PSWADDR,           "psw_addr"                              },
        { PT_GPR0,              "gpr0"                                  },
@@ -1830,6 +2342,7 @@ struct xlat struct_user_offsets[] = {
        { PT_ACR15,             "acr15"                                 },
        { PT_ORIGGPR2,          "orig_gpr2"                             },
        { PT_FPC,               "fpc"                                   },
+#if defined(S390)
        { PT_FPR0_HI,           "fpr0.hi"                               },
        { PT_FPR0_LO,           "fpr0.lo"                               },
        { PT_FPR1_HI,           "fpr1.hi"                               },
@@ -1862,56 +2375,81 @@ struct xlat struct_user_offsets[] = {
        { PT_FPR14_LO,          "fpr14.lo"                              },
        { PT_FPR15_HI,          "fpr15.hi"                              },
        { PT_FPR15_LO,          "fpr15.lo"                              },
+#endif
+#if defined(S390X)
+       { PT_FPR0,              "fpr0"                                  },
+       { PT_FPR1,              "fpr1"                                  },
+       { PT_FPR2,              "fpr2"                                  },
+       { PT_FPR3,              "fpr3"                                  },
+       { PT_FPR4,              "fpr4"                                  },
+       { PT_FPR5,              "fpr5"                                  },
+       { PT_FPR6,              "fpr6"                                  },
+       { PT_FPR7,              "fpr7"                                  },
+       { PT_FPR8,              "fpr8"                                  },
+       { PT_FPR9,              "fpr9"                                  },
+       { PT_FPR10,             "fpr10"                                 },
+       { PT_FPR11,             "fpr11"                                 },
+       { PT_FPR12,             "fpr12"                                 },
+       { PT_FPR13,             "fpr13"                                 },
+       { PT_FPR14,             "fpr14"                                 },
+       { PT_FPR15,             "fpr15"                                 },
+#endif
        { PT_CR_9,              "cr9"                                   },
        { PT_CR_10,             "cr10"                                  },
        { PT_CR_11,             "cr11"                                  },
+       { PT_IEEE_IP,           "ieee_exception_ip"                     },
 #endif
 #if defined(SPARC)
        /* XXX No support for these offsets yet. */
 #elif defined(HPPA)
        /* XXX No support for these offsets yet. */
 #elif defined(POWERPC)
-       { 4*PT_R0,              "4*PT_R0"                               },
-       { 4*PT_R1,              "4*PT_R1"                               },
-       { 4*PT_R2,              "4*PT_R2"                               },
-       { 4*PT_R3,              "4*PT_R3"                               },
-       { 4*PT_R4,              "4*PT_R4"                               },
-       { 4*PT_R5,              "4*PT_R5"                               },
-       { 4*PT_R6,              "4*PT_R6"                               },
-       { 4*PT_R7,              "4*PT_R7"                               },
-       { 4*PT_R8,              "4*PT_R8"                               },
-       { 4*PT_R9,              "4*PT_R9"                               },
-       { 4*PT_R10,             "4*PT_R10"                              },
-       { 4*PT_R11,             "4*PT_R11"                              },
-       { 4*PT_R12,             "4*PT_R12"                              },
-       { 4*PT_R13,             "4*PT_R13"                              },
-       { 4*PT_R14,             "4*PT_R14"                              },
-       { 4*PT_R15,             "4*PT_R15"                              },
-       { 4*PT_R16,             "4*PT_R16"                              },
-       { 4*PT_R17,             "4*PT_R17"                              },
-       { 4*PT_R18,             "4*PT_R18"                              },
-       { 4*PT_R19,             "4*PT_R19"                              },
-       { 4*PT_R20,             "4*PT_R20"                              },
-       { 4*PT_R21,             "4*PT_R21"                              },
-       { 4*PT_R22,             "4*PT_R22"                              },
-       { 4*PT_R23,             "4*PT_R23"                              },
-       { 4*PT_R24,             "4*PT_R24"                              },
-       { 4*PT_R25,             "4*PT_R25"                              },
-       { 4*PT_R26,             "4*PT_R26"                              },
-       { 4*PT_R27,             "4*PT_R27"                              },
-       { 4*PT_R28,             "4*PT_R28"                              },
-       { 4*PT_R29,             "4*PT_R29"                              },
-       { 4*PT_R30,             "4*PT_R30"                              },
-       { 4*PT_R31,             "4*PT_R31"                              },
-       { 4*PT_NIP,             "4*PT_NIP"                              },
-       { 4*PT_MSR,             "4*PT_MSR"                              },
-       { 4*PT_ORIG_R3,         "4*PT_ORIG_R3"                          },
-       { 4*PT_CTR,             "4*PT_CTR"                              },
-       { 4*PT_LNK,             "4*PT_LNK"                              },
-       { 4*PT_XER,             "4*PT_XER"                              },
-       { 4*PT_CCR,             "4*PT_CCR"                              },
-       { 4*PT_FPR0,            "4*PT_FPR0"                             },
-#else  
+#ifndef PT_ORIG_R3
+#define PT_ORIG_R3 34
+#endif
+#define REGSIZE (sizeof(unsigned long))
+       { REGSIZE*PT_R0,                "r0"                            },
+       { REGSIZE*PT_R1,                "r1"                            },
+       { REGSIZE*PT_R2,                "r2"                            },
+       { REGSIZE*PT_R3,                "r3"                            },
+       { REGSIZE*PT_R4,                "r4"                            },
+       { REGSIZE*PT_R5,                "r5"                            },
+       { REGSIZE*PT_R6,                "r6"                            },
+       { REGSIZE*PT_R7,                "r7"                            },
+       { REGSIZE*PT_R8,                "r8"                            },
+       { REGSIZE*PT_R9,                "r9"                            },
+       { REGSIZE*PT_R10,               "r10"                           },
+       { REGSIZE*PT_R11,               "r11"                           },
+       { REGSIZE*PT_R12,               "r12"                           },
+       { REGSIZE*PT_R13,               "r13"                           },
+       { REGSIZE*PT_R14,               "r14"                           },
+       { REGSIZE*PT_R15,               "r15"                           },
+       { REGSIZE*PT_R16,               "r16"                           },
+       { REGSIZE*PT_R17,               "r17"                           },
+       { REGSIZE*PT_R18,               "r18"                           },
+       { REGSIZE*PT_R19,               "r19"                           },
+       { REGSIZE*PT_R20,               "r20"                           },
+       { REGSIZE*PT_R21,               "r21"                           },
+       { REGSIZE*PT_R22,               "r22"                           },
+       { REGSIZE*PT_R23,               "r23"                           },
+       { REGSIZE*PT_R24,               "r24"                           },
+       { REGSIZE*PT_R25,               "r25"                           },
+       { REGSIZE*PT_R26,               "r26"                           },
+       { REGSIZE*PT_R27,               "r27"                           },
+       { REGSIZE*PT_R28,               "r28"                           },
+       { REGSIZE*PT_R29,               "r29"                           },
+       { REGSIZE*PT_R30,               "r30"                           },
+       { REGSIZE*PT_R31,               "r31"                           },
+       { REGSIZE*PT_NIP,               "NIP"                           },
+       { REGSIZE*PT_MSR,               "MSR"                           },
+       { REGSIZE*PT_ORIG_R3,           "ORIG_R3"                       },
+       { REGSIZE*PT_CTR,               "CTR"                           },
+       { REGSIZE*PT_LNK,               "LNK"                           },
+       { REGSIZE*PT_XER,               "XER"                           },
+       { REGSIZE*PT_CCR,               "CCR"                           },
+       { REGSIZE*PT_FPR0,              "FPR0"                          },
+#undef REGSIZE
+#else
 #ifdef ALPHA
        { 0,                    "r0"                                    },
        { 1,                    "r1"                                    },
@@ -2023,16 +2561,12 @@ struct xlat struct_user_offsets[] = {
        { PT_F27, "f27" }, { PT_F28, "f28" }, { PT_F29, "f29" },
        { PT_F30, "f30" }, { PT_F31, "f31" }, { PT_R4, "r4" },
        { PT_R5, "r5" }, { PT_R6, "r6" }, { PT_R7, "r7" },
-       { PT_K_B0, "kb0" },
        { PT_B1, "b1" }, { PT_B2, "b2" }, { PT_B3, "b3" },
        { PT_B4, "b4" }, { PT_B5, "b5" },
-       { PT_K_AR_PFS, "kar.pfs" },
-       { PT_AR_LC, "ar.lc" }, { PT_K_AR_UNAT, "kar.unat" },
-       { PT_K_AR_RNAT, "kar.rnat" }, { PT_K_AR_BSPSTORE, "kar.bspstore" },
-       { PT_K_PR, "k.pr" },
+       { PT_AR_EC, "ar.ec" }, { PT_AR_LC, "ar.lc" },
        /* pt_regs */
-       { PT_CR_IPSR, "cr.ipsr" }, { PT_CR_IIP, "cr.iip" },
-       { PT_CR_IFS, "cr.ifs" }, { PT_AR_UNAT, "ar.unat" },
+       { PT_CR_IPSR, "psr" }, { PT_CR_IIP, "ip" },
+       { PT_CFM, "cfm" }, { PT_AR_UNAT, "ar.unat" },
        { PT_AR_PFS, "ar.pfs" }, { PT_AR_RSC, "ar.rsc" },
        { PT_AR_RNAT, "ar.rnat" }, { PT_AR_BSPSTORE, "ar.bspstore" },
        { PT_PR, "pr" }, { PT_B6, "b6" }, { PT_AR_BSP, "ar.bsp" },
@@ -2048,6 +2582,13 @@ struct xlat struct_user_offsets[] = {
        { PT_AR_CCV, "ar.ccv" }, { PT_AR_FPSR, "ar.fpsr" },
        { PT_B0, "b0" }, { PT_B7, "b7" }, { PT_F6, "f6" },
        { PT_F7, "f7" }, { PT_F8, "f8" }, { PT_F9, "f9" },
+# ifdef PT_AR_CSD
+       { PT_AR_CSD, "ar.csd" },
+# endif
+# ifdef PT_AR_SSD
+       { PT_AR_SSD, "ar.ssd" },
+# endif
+       { PT_DBR, "dbr" }, { PT_IBR, "ibr" }, { PT_PMD, "pmd" },
 #else /* !IA64 */
 #ifdef I386
        { 4*EBX,                "4*EBX"                                 },
@@ -2068,6 +2609,35 @@ struct xlat struct_user_offsets[] = {
        { 4*UESP,               "4*UESP"                                },
        { 4*SS,                 "4*SS"                                  },
 #else /* !I386 */
+#ifdef X86_64
+       { 8*R15,                "8*R15"                                 },
+       { 8*R14,                "8*R14"                                 },
+       { 8*R13,                "8*R13"                                 },
+       { 8*R12,                "8*R12"                                 },
+       { 8*RBP,                "8*RBP"                                 },
+       { 8*RBX,                "8*RBX"                                 },
+       { 8*R11,                "8*R11"                                 },
+       { 8*R10,                "8*R10"                                 },
+       { 8*R9,                 "8*R9"                                  },
+       { 8*R8,                 "8*R8"                                  },
+       { 8*RAX,                "8*RAX"                                 },
+       { 8*RCX,                "8*RCX"                                 },
+       { 8*RDX,                "8*RDX"                                 },
+       { 8*RSI,                "8*RSI"                                 },
+       { 8*RDI,                "8*RDI"                                 },
+#if 0
+       { DS,                   "DS"                                    },
+       { ES,                   "ES"                                    },
+       { FS,                   "FS"                                    },
+       { GS,                   "GS"                                    },
+#endif
+       { 8*ORIG_RAX,           "8*ORIG_RAX"                            },
+       { 8*RIP,                "8*RIP"                                 },
+       { 8*CS,                 "8*CS"                                  },
+       { 8*EFLAGS,             "8*EFL"                                 },
+       { 8*RSP,                "8*RSP"                                 },
+       { 8*SS,                 "8*SS"                                  },
+#endif
 #ifdef M68K
        { 4*PT_D1,              "4*PT_D1"                               },
        { 4*PT_D2,              "4*PT_D2"                               },
@@ -2090,10 +2660,237 @@ struct xlat struct_user_offsets[] = {
        { 4*PT_PC,              "4*PT_PC"                               },
 #endif /* M68K */
 #endif /* !I386 */
-#if !defined(S390) && !defined(MIPS)
+#ifdef SH
+       { 4*REG_REG0,           "4*REG_REG0"                            },
+       { 4*(REG_REG0+1),       "4*REG_REG1"                            },
+       { 4*(REG_REG0+2),       "4*REG_REG2"                            },
+       { 4*(REG_REG0+3),       "4*REG_REG3"                            },
+       { 4*(REG_REG0+4),       "4*REG_REG4"                            },
+       { 4*(REG_REG0+5),       "4*REG_REG5"                            },
+       { 4*(REG_REG0+6),       "4*REG_REG6"                            },
+       { 4*(REG_REG0+7),       "4*REG_REG7"                            },
+       { 4*(REG_REG0+8),       "4*REG_REG8"                            },
+       { 4*(REG_REG0+9),       "4*REG_REG9"                            },
+       { 4*(REG_REG0+10),      "4*REG_REG10"                           },
+       { 4*(REG_REG0+11),      "4*REG_REG11"                           },
+       { 4*(REG_REG0+12),      "4*REG_REG12"                           },
+       { 4*(REG_REG0+13),      "4*REG_REG13"                           },
+       { 4*(REG_REG0+14),      "4*REG_REG14"                           },
+       { 4*REG_REG15,          "4*REG_REG15"                           },
+       { 4*REG_PC,             "4*REG_PC"                              },
+       { 4*REG_PR,             "4*REG_PR"                              },
+       { 4*REG_SR,             "4*REG_SR"                              },
+       { 4*REG_GBR,            "4*REG_GBR"                             },
+       { 4*REG_MACH,           "4*REG_MACH"                            },
+       { 4*REG_MACL,           "4*REG_MACL"                            },
+       { 4*REG_SYSCALL,        "4*REG_SYSCALL"                         },
+       { 4*REG_FPUL,           "4*REG_FPUL"                            },
+       { 4*REG_FPREG0,         "4*REG_FPREG0"                          },
+       { 4*(REG_FPREG0+1),     "4*REG_FPREG1"                          },
+       { 4*(REG_FPREG0+2),     "4*REG_FPREG2"                          },
+       { 4*(REG_FPREG0+3),     "4*REG_FPREG3"                          },
+       { 4*(REG_FPREG0+4),     "4*REG_FPREG4"                          },
+       { 4*(REG_FPREG0+5),     "4*REG_FPREG5"                          },
+       { 4*(REG_FPREG0+6),     "4*REG_FPREG6"                          },
+       { 4*(REG_FPREG0+7),     "4*REG_FPREG7"                          },
+       { 4*(REG_FPREG0+8),     "4*REG_FPREG8"                          },
+       { 4*(REG_FPREG0+9),     "4*REG_FPREG9"                          },
+       { 4*(REG_FPREG0+10),    "4*REG_FPREG10"                         },
+       { 4*(REG_FPREG0+11),    "4*REG_FPREG11"                         },
+       { 4*(REG_FPREG0+12),    "4*REG_FPREG12"                         },
+       { 4*(REG_FPREG0+13),    "4*REG_FPREG13"                         },
+       { 4*(REG_FPREG0+14),    "4*REG_FPREG14"                         },
+       { 4*REG_FPREG15,        "4*REG_FPREG15"                         },
+#ifdef REG_XDREG0
+       { 4*REG_XDREG0,         "4*REG_XDREG0"                          },
+       { 4*(REG_XDREG0+2),     "4*REG_XDREG2"                          },
+       { 4*(REG_XDREG0+4),     "4*REG_XDREG4"                          },
+       { 4*(REG_XDREG0+6),     "4*REG_XDREG6"                          },
+       { 4*(REG_XDREG0+8),     "4*REG_XDREG8"                          },
+       { 4*(REG_XDREG0+10),    "4*REG_XDREG10"                         },
+       { 4*(REG_XDREG0+12),    "4*REG_XDREG12"                         },
+       { 4*REG_XDREG14,        "4*REG_XDREG14"                         },
+#endif
+       { 4*REG_FPSCR,          "4*REG_FPSCR"                           },
+#endif /* SH */
+#ifdef SH64
+       { 0,                    "PC(L)"                                 },
+       { 4,                    "PC(U)"                                 },
+       { 8,                    "SR(L)"                                 },
+       { 12,                   "SR(U)"                                 },
+       { 16,                   "syscall no.(L)"                        },
+       { 20,                   "syscall_no.(U)"                        },
+       { 24,                   "R0(L)"                                 },
+       { 28,                   "R0(U)"                                 },
+       { 32,                   "R1(L)"                                 },
+       { 36,                   "R1(U)"                                 },
+       { 40,                   "R2(L)"                                 },
+       { 44,                   "R2(U)"                                 },
+       { 48,                   "R3(L)"                                 },
+       { 52,                   "R3(U)"                                 },
+       { 56,                   "R4(L)"                                 },
+       { 60,                   "R4(U)"                                 },
+       { 64,                   "R5(L)"                                 },
+       { 68,                   "R5(U)"                                 },
+       { 72,                   "R6(L)"                                 },
+       { 76,                   "R6(U)"                                 },
+       { 80,                   "R7(L)"                                 },
+       { 84,                   "R7(U)"                                 },
+       { 88,                   "R8(L)"                                 },
+       { 92,                   "R8(U)"                                 },
+       { 96,                   "R9(L)"                                 },
+       { 100,                  "R9(U)"                                 },
+       { 104,                  "R10(L)"                                },
+       { 108,                  "R10(U)"                                },
+       { 112,                  "R11(L)"                                },
+       { 116,                  "R11(U)"                                },
+       { 120,                  "R12(L)"                                },
+       { 124,                  "R12(U)"                                },
+       { 128,                  "R13(L)"                                },
+       { 132,                  "R13(U)"                                },
+       { 136,                  "R14(L)"                                },
+       { 140,                  "R14(U)"                                },
+       { 144,                  "R15(L)"                                },
+       { 148,                  "R15(U)"                                },
+       { 152,                  "R16(L)"                                },
+       { 156,                  "R16(U)"                                },
+       { 160,                  "R17(L)"                                },
+       { 164,                  "R17(U)"                                },
+       { 168,                  "R18(L)"                                },
+       { 172,                  "R18(U)"                                },
+       { 176,                  "R19(L)"                                },
+       { 180,                  "R19(U)"                                },
+       { 184,                  "R20(L)"                                },
+       { 188,                  "R20(U)"                                },
+       { 192,                  "R21(L)"                                },
+       { 196,                  "R21(U)"                                },
+       { 200,                  "R22(L)"                                },
+       { 204,                  "R22(U)"                                },
+       { 208,                  "R23(L)"                                },
+       { 212,                  "R23(U)"                                },
+       { 216,                  "R24(L)"                                },
+       { 220,                  "R24(U)"                                },
+       { 224,                  "R25(L)"                                },
+       { 228,                  "R25(U)"                                },
+       { 232,                  "R26(L)"                                },
+       { 236,                  "R26(U)"                                },
+       { 240,                  "R27(L)"                                },
+       { 244,                  "R27(U)"                                },
+       { 248,                  "R28(L)"                                },
+       { 252,                  "R28(U)"                                },
+       { 256,                  "R29(L)"                                },
+       { 260,                  "R29(U)"                                },
+       { 264,                  "R30(L)"                                },
+       { 268,                  "R30(U)"                                },
+       { 272,                  "R31(L)"                                },
+       { 276,                  "R31(U)"                                },
+       { 280,                  "R32(L)"                                },
+       { 284,                  "R32(U)"                                },
+       { 288,                  "R33(L)"                                },
+       { 292,                  "R33(U)"                                },
+       { 296,                  "R34(L)"                                },
+       { 300,                  "R34(U)"                                },
+       { 304,                  "R35(L)"                                },
+       { 308,                  "R35(U)"                                },
+       { 312,                  "R36(L)"                                },
+       { 316,                  "R36(U)"                                },
+       { 320,                  "R37(L)"                                },
+       { 324,                  "R37(U)"                                },
+       { 328,                  "R38(L)"                                },
+       { 332,                  "R38(U)"                                },
+       { 336,                  "R39(L)"                                },
+       { 340,                  "R39(U)"                                },
+       { 344,                  "R40(L)"                                },
+       { 348,                  "R40(U)"                                },
+       { 352,                  "R41(L)"                                },
+       { 356,                  "R41(U)"                                },
+       { 360,                  "R42(L)"                                },
+       { 364,                  "R42(U)"                                },
+       { 368,                  "R43(L)"                                },
+       { 372,                  "R43(U)"                                },
+       { 376,                  "R44(L)"                                },
+       { 380,                  "R44(U)"                                },
+       { 384,                  "R45(L)"                                },
+       { 388,                  "R45(U)"                                },
+       { 392,                  "R46(L)"                                },
+       { 396,                  "R46(U)"                                },
+       { 400,                  "R47(L)"                                },
+       { 404,                  "R47(U)"                                },
+       { 408,                  "R48(L)"                                },
+       { 412,                  "R48(U)"                                },
+       { 416,                  "R49(L)"                                },
+       { 420,                  "R49(U)"                                },
+       { 424,                  "R50(L)"                                },
+       { 428,                  "R50(U)"                                },
+       { 432,                  "R51(L)"                                },
+       { 436,                  "R51(U)"                                },
+       { 440,                  "R52(L)"                                },
+       { 444,                  "R52(U)"                                },
+       { 448,                  "R53(L)"                                },
+       { 452,                  "R53(U)"                                },
+       { 456,                  "R54(L)"                                },
+       { 460,                  "R54(U)"                                },
+       { 464,                  "R55(L)"                                },
+       { 468,                  "R55(U)"                                },
+       { 472,                  "R56(L)"                                },
+       { 476,                  "R56(U)"                                },
+       { 480,                  "R57(L)"                                },
+       { 484,                  "R57(U)"                                },
+       { 488,                  "R58(L)"                                },
+       { 492,                  "R58(U)"                                },
+       { 496,                  "R59(L)"                                },
+       { 500,                  "R59(U)"                                },
+       { 504,                  "R60(L)"                                },
+       { 508,                  "R60(U)"                                },
+       { 512,                  "R61(L)"                                },
+       { 516,                  "R61(U)"                                },
+       { 520,                  "R62(L)"                                },
+       { 524,                  "R62(U)"                                },
+       { 528,                  "TR0(L)"                                },
+       { 532,                  "TR0(U)"                                },
+       { 536,                  "TR1(L)"                                },
+       { 540,                  "TR1(U)"                                },
+       { 544,                  "TR2(L)"                                },
+       { 548,                  "TR2(U)"                                },
+       { 552,                  "TR3(L)"                                },
+       { 556,                  "TR3(U)"                                },
+       { 560,                  "TR4(L)"                                },
+       { 564,                  "TR4(U)"                                },
+       { 568,                  "TR5(L)"                                },
+       { 572,                  "TR5(U)"                                },
+       { 576,                  "TR6(L)"                                },
+       { 580,                  "TR6(U)"                                },
+       { 584,                  "TR7(L)"                                },
+       { 588,                  "TR7(U)"                                },
+        /* This entry is in case pt_regs contains dregs (depends on
+           the kernel build options). */
+       { uoff(regs),           "offsetof(struct user, regs)"           },
+       { uoff(fpu),            "offsetof(struct user, fpu)"            },
+#endif
+#ifdef ARM
+       { uoff(regs.ARM_r0),    "r0"                                    },
+       { uoff(regs.ARM_r1),    "r1"                                    },
+       { uoff(regs.ARM_r2),    "r2"                                    },
+       { uoff(regs.ARM_r3),    "r3"                                    },
+       { uoff(regs.ARM_r4),    "r4"                                    },
+       { uoff(regs.ARM_r5),    "r5"                                    },
+       { uoff(regs.ARM_r6),    "r6"                                    },
+       { uoff(regs.ARM_r7),    "r7"                                    },
+       { uoff(regs.ARM_r8),    "r8"                                    },
+       { uoff(regs.ARM_r9),    "r9"                                    },
+       { uoff(regs.ARM_r10),   "r10"                                   },
+       { uoff(regs.ARM_fp),    "fp"                                    },
+       { uoff(regs.ARM_ip),    "ip"                                    },
+       { uoff(regs.ARM_sp),    "sp"                                    },
+       { uoff(regs.ARM_lr),    "lr"                                    },
+       { uoff(regs.ARM_pc),    "pc"                                    },
+       { uoff(regs.ARM_cpsr),  "cpsr"                                  },
+#endif
+
+#if !defined(S390) && !defined(S390X) && !defined(MIPS) && !defined(SPARC64)
        { uoff(u_fpvalid),      "offsetof(struct user, u_fpvalid)"      },
 #endif
-#ifdef I386
+#if  defined(I386) || defined(X86_64)
        { uoff(i387),           "offsetof(struct user, i387)"           },
 #else /* !I386 */
 #ifdef M68K
@@ -2103,19 +2900,28 @@ struct xlat struct_user_offsets[] = {
        { uoff(u_tsize),        "offsetof(struct user, u_tsize)"        },
        { uoff(u_dsize),        "offsetof(struct user, u_dsize)"        },
        { uoff(u_ssize),        "offsetof(struct user, u_ssize)"        },
+#if !defined(SPARC64)
        { uoff(start_code),     "offsetof(struct user, start_code)"     },
+#endif
+#ifdef SH64
+       { uoff(start_data),     "offsetof(struct user, start_data)"     },
+#endif
+#if !defined(SPARC64)
        { uoff(start_stack),    "offsetof(struct user, start_stack)"    },
+#endif
        { uoff(signal),         "offsetof(struct user, signal)"         },
-#if !defined(S390) && !defined(MIPS)
+#if !defined(S390) && !defined(S390X) && !defined(MIPS) && !defined(SH) && !defined(SH64) && !defined(SPARC64)
        { uoff(reserved),       "offsetof(struct user, reserved)"       },
 #endif
+#if !defined(SPARC64)
        { uoff(u_ar0),          "offsetof(struct user, u_ar0)"          },
-#if !defined(ARM) && !defined(MIPS) && !defined(S390)
+#endif
+#if !defined(ARM) && !defined(MIPS) && !defined(S390) && !defined(S390X) && !defined(SPARC64)
        { uoff(u_fpstate),      "offsetof(struct user, u_fpstate)"      },
 #endif
        { uoff(magic),          "offsetof(struct user, magic)"          },
        { uoff(u_comm),         "offsetof(struct user, u_comm)"         },
-#ifdef I386
+#if defined(I386) || defined(X86_64)
        { uoff(u_debugreg),     "offsetof(struct user, u_debugreg)"     },
 #endif /* I386 */
 #endif /* !IA64 */
@@ -2180,19 +2986,18 @@ int
 sys_ptrace(tcp)
 struct tcb *tcp;
 {
-       char *cmd;
-       struct xlat *x;
+       const struct xlat *x;
        long addr;
 
-       cmd = xlookup(ptrace_cmds, tcp->u_arg[0]);
-       if (!cmd)
+       if (entering(tcp)) {
+               printxval(ptrace_cmds, tcp->u_arg[0],
 #ifndef FREEBSD
-               cmd = "PTRACE_???";
+                         "PTRACE_???"
 #else
-               cmd = "PT_???";
-#endif         
-       if (entering(tcp)) {
-               tprintf("%s, %lu, ", cmd, tcp->u_arg[1]);
+                         "PT_???"
+#endif
+                       );
+               tprintf(", %lu, ", tcp->u_arg[1]);
                addr = tcp->u_arg[2];
 #ifndef FREEBSD
                if (tcp->u_arg[0] == PTRACE_PEEKUSER
@@ -2234,7 +3039,7 @@ struct tcb *tcp;
                case PTRACE_PEEKDATA:
                case PTRACE_PEEKTEXT:
                case PTRACE_PEEKUSER:
-                       printnum(tcp, tcp->u_arg[3], "%#x");
+                       printnum(tcp, tcp->u_arg[3], "%#lx");
                        break;
                }
        }
@@ -2264,3 +3069,187 @@ struct tcb *tcp;
 }
 
 #endif /* !SVR4 */
+
+#ifdef LINUX
+static const struct xlat futexops[] = {
+       { FUTEX_WAIT,   "FUTEX_WAIT" },
+       { FUTEX_WAKE,   "FUTEX_WAKE" },
+       { FUTEX_FD,     "FUTEX_FD" },
+       { FUTEX_REQUEUE,"FUTEX_REQUEUE" },
+       { 0,            NULL }
+};
+
+int
+sys_futex(tcp)
+struct tcb *tcp;
+{
+    if (entering(tcp)) {
+       tprintf("%p, ", (void *) tcp->u_arg[0]);
+       printxval(futexops, tcp->u_arg[1], "FUTEX_???");
+       tprintf(", %ld", tcp->u_arg[2]);
+       if (tcp->u_arg[1] == FUTEX_WAIT) {
+               tprintf(", ");
+               printtv(tcp, tcp->u_arg[3]);
+       } else if (tcp->u_arg[1] == FUTEX_REQUEUE)
+               tprintf(", %ld, %p", tcp->u_arg[3], (void *) tcp->u_arg[4]);
+    }
+    return 0;
+}
+
+static void
+print_affinitylist(tcp, list, len)
+struct tcb *tcp;
+long list;
+unsigned int len;
+{
+    int first = 1;
+    tprintf(" {");
+    while (len >= sizeof (unsigned long)) {
+       unsigned long w;
+       umove(tcp, list, &w);
+       tprintf("%s %lx", first ? "" : ",", w);
+       first = 0;
+       len -= sizeof (unsigned long);
+       list += sizeof(unsigned long);
+    }
+    tprintf(" }");
+}
+
+int
+sys_sched_setaffinity(tcp)
+struct tcb *tcp;
+{
+    if (entering(tcp)) {
+       tprintf("%ld, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
+       print_affinitylist(tcp, tcp->u_arg[2], tcp->u_arg[1]);
+    }
+    return 0;
+}
+
+int
+sys_sched_getaffinity(tcp)
+struct tcb *tcp;
+{
+    if (entering(tcp)) {
+       tprintf("%ld, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
+    } else {
+       if (tcp->u_rval == -1)
+           tprintf("%#lx", tcp->u_arg[2]);
+       else
+           print_affinitylist(tcp, tcp->u_arg[2], tcp->u_rval);
+    }
+    return 0;
+}
+
+static const struct xlat schedulers[] = {
+       { SCHED_OTHER,  "SCHED_OTHER" },
+       { SCHED_RR,     "SCHED_RR" },
+       { SCHED_FIFO,   "SCHED_FIFO" },
+       { 0,            NULL }
+};
+
+int
+sys_sched_getscheduler(tcp)
+struct tcb *tcp;
+{
+    if (entering(tcp)) {
+       tprintf("%d", (int) tcp->u_arg[0]);
+    } else if (! syserror(tcp)) {
+       tcp->auxstr = xlookup (schedulers, tcp->u_rval);
+       if (tcp->auxstr != NULL)
+           return RVAL_STR;
+    }
+    return 0;
+}
+
+int
+sys_sched_setscheduler(tcp)
+struct tcb *tcp;
+{
+    if (entering(tcp)) {
+       struct sched_param p;
+       tprintf("%d, ", (int) tcp->u_arg[0]);
+       printxval(schedulers, tcp->u_arg[1], "SCHED_???");
+       if (umove(tcp, tcp->u_arg[2], &p) < 0)
+           tprintf(", %#lx", tcp->u_arg[2]);
+       else
+           tprintf(", { %d }", p.__sched_priority);
+    }
+    return 0;
+}
+
+int
+sys_sched_getparam(tcp)
+struct tcb *tcp;
+{
+    if (entering(tcp)) {
+           tprintf("%d, ", (int) tcp->u_arg[0]);
+    } else {
+       struct sched_param p;
+       if (umove(tcp, tcp->u_arg[1], &p) < 0)
+           tprintf("%#lx", tcp->u_arg[1]);
+       else
+           tprintf("{ %d }", p.__sched_priority);
+    }
+    return 0;
+}
+
+int
+sys_sched_setparam(tcp)
+struct tcb *tcp;
+{
+    if (entering(tcp)) {
+       struct sched_param p;
+       if (umove(tcp, tcp->u_arg[1], &p) < 0)
+           tprintf("%d, %#lx", (int) tcp->u_arg[0], tcp->u_arg[1]);
+       else
+           tprintf("%d, { %d }", (int) tcp->u_arg[0], p.__sched_priority);
+    }
+    return 0;
+}
+
+int
+sys_sched_get_priority_min(tcp)
+struct tcb *tcp;
+{
+    if (entering(tcp)) {
+       printxval(schedulers, tcp->u_arg[0], "SCHED_???");
+    }
+    return 0;
+}
+
+#ifdef X86_64
+#include <asm/prctl.h>
+
+static const struct xlat archvals[] = {
+       { ARCH_SET_GS,          "ARCH_SET_GS"           },
+       { ARCH_SET_FS,          "ARCH_SET_FS"           },
+       { ARCH_GET_FS,          "ARCH_GET_FS"           },
+       { ARCH_GET_GS,          "ARCH_GET_GS"           },
+       { 0,                    NULL                    },
+};
+
+int
+sys_arch_prctl(tcp)
+struct tcb *tcp;
+{
+    if (entering(tcp)) {
+       printxval(archvals, tcp->u_arg[0], "ARCH_???");
+       if (tcp->u_arg[0] == ARCH_SET_GS
+           || tcp->u_arg[0] == ARCH_SET_FS)
+           tprintf(", %#lx", tcp->u_arg[1]);
+    } else {
+       if (tcp->u_arg[0] == ARCH_GET_GS
+           || tcp->u_arg[0] == ARCH_GET_FS) {
+           long int v;
+           if (!syserror(tcp) && umove(tcp, tcp->u_arg[1], &v) != -1)
+               tprintf(", [%#lx]", v);
+           else
+               tprintf(", %#lx", tcp->u_arg[1]);
+       }
+    }
+    return 0;
+}
+#endif
+
+#endif