]> granicus.if.org Git - strace/blobdiff - process.c
2005-05-31 Dmitry V. Levin <ldv@altlinux.org>
[strace] / process.c
index 8c7ca1280a13aca9bd059f2b374fa95687b25fc2..bc116a4778077e8f0d70fbad517cb6d0ea5d6d7a 100644 (file)
--- a/process.c
+++ b/process.c
 #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
+#endif /* SPARC || SPARC64 */
 #endif /* HAVE_ASM_REG_H */
 
 #ifdef HAVE_SYS_REG_H
 
 #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
 # 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
@@ -368,6 +390,12 @@ struct tcb *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 (tcp->scno == __NR_exit_group)
                        tcp->flags |= TCB_GROUP_EXITING;
 #endif
@@ -382,27 +410,10 @@ static int
 fork_tcb(struct tcb *tcp)
 {
        if (nprocs == tcbtabsize) {
-               /* Allocate some more TCBs and expand the table.
-                  We don't want to relocate the TCBs because our
-                  callers have pointers and it would be a pain.
-                  So tcbtab is a table of pointers.  Since we never
-                  free the TCBs, we allocate a single chunk of many.  */
-               struct tcb **newtab = (struct tcb **)
-                       realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
-               struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
-                                                           sizeof *newtcbs);
-               int i;
-               if (newtab == NULL || newtcbs == NULL) {
-                       if (newtab != NULL)
-                               free(newtab);
+               if (expand_tcbtab()) {
                        tcp->flags &= ~TCB_FOLLOWFORK;
                        fprintf(stderr, "sys_fork: tcb table full\n");
-                       return 1;
                }
-               for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
-                       newtab[i] = &newtcbs[i - tcbtabsize];
-               tcbtabsize *= 2;
-               tcbtab = newtab;
        }
 
        tcp->flags |= TCB_FOLLOWFORK;
@@ -499,7 +510,7 @@ struct tcb *tcp;
 #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 struct xlat clone_flags[] = {
+static const struct xlat clone_flags[] = {
     { CLONE_VM,                "CLONE_VM"      },
     { CLONE_FS,                "CLONE_FS"      },
     { CLONE_FILES,     "CLONE_FILES"   },
@@ -522,6 +533,9 @@ static struct xlat clone_flags[] = {
 
 # 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
 
@@ -532,13 +546,13 @@ extern void print_ldt_entry();
 #  define ARG_PTID     (tcp->scno == SYS_clone2 ? 3 : 2)
 #  define ARG_CTID     (tcp->scno == SYS_clone2 ? 4 : 3)
 #  define ARG_TLS      (tcp->scno == SYS_clone2 ? 5 : 4)
-# elif defined S390
+# elif defined S390 || defined S390X
 #  define ARG_STACK    0
 #  define ARG_FLAGS    1
 #  define ARG_PTID     2
-#  define ARG_TLS      3
-#  define ARG_CTID     4
-# elif defined X86_64
+#  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
@@ -565,19 +579,14 @@ struct tcb *tcp;
                                tcp->u_arg[ARG_STACKSIZE]);
 # endif
                tprintf("flags=");
-               if (printflags(clone_flags, flags) == 0)
-                       tprintf("0");
+               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) {
-                       int pid;
-                       if (umove(tcp, tcp->u_arg[ARG_PTID], &pid) == 0)
-                               tprintf(", parent_tidptr=[%d]", pid);
-                       else
-                               tprintf(", parent_tidptr=%#lx",
-                                       tcp->u_arg[ARG_PTID]);
-               }
+               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;
@@ -639,7 +648,7 @@ int new;
        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;
@@ -656,7 +665,18 @@ int new;
                return -1;
        return 0;
 #elif defined(IA64)
-       if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R15), new)<0)
+       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)
@@ -664,9 +684,16 @@ int new;
                return -1;
        return 0;
 #elif defined(SH)
-       if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_SYSCALL), new)<0)
+       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;
 #else
 #warning Do not know how to handle change_syscall for this architecture
 #endif /* architecture */
@@ -851,29 +878,37 @@ Process %u resumed (parent %d ready)\n",
                }
 
 #ifdef TCB_CLONE_THREAD
-               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->u_arg[0] = tcp->parent->u_arg[0];
-                       tcp = tcp->parent;
-                       tcpchild->parent = tcp;
-                       ++tcp->nchildren;
-               }
-
-               if (tcp->u_arg[0] & CLONE_THREAD) {
-                       tcpchild->flags |= TCB_CLONE_THREAD;
-                       ++tcp->nclone_threads;
-               }
-               if (tcp->u_arg[0] & CLONE_DETACHED) {
-                       tcpchild->flags |= TCB_CLONE_DETACHED;
-                       ++tcp->nclone_detached;
+               {
+                       /*
+                        * 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
 
@@ -1095,15 +1130,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);
+                               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);
+                               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;
@@ -1122,15 +1157,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);
+                               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);
+                               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;
@@ -1143,9 +1178,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;
 }
@@ -1155,9 +1189,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;
 }
@@ -1168,10 +1201,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;
 }
@@ -1180,10 +1212,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;
 }
@@ -1194,34 +1225,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;
+               }
+               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;
 }
@@ -1230,41 +1280,182 @@ 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;
+               }
+               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;
                }
-               free((char *)gidset);
+               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 */
 
 int
 sys_setpgrp(tcp)
@@ -1332,7 +1523,7 @@ struct tcb *tcp;
 #include <sys/privilege.h>
 
 
-static struct xlat procpriv_cmds [] = {
+static const struct xlat procpriv_cmds [] = {
        { SETPRV,       "SETPRV"        },
        { CLRPRV,       "CLRPRV"        },
        { PUTPRV,       "PUTPRV"        },
@@ -1342,7 +1533,7 @@ static struct xlat procpriv_cmds [] = {
 };
 
 
-static struct xlat procpriv_priv [] = {
+static const struct xlat procpriv_priv [] = {
        { P_OWNER,      "P_OWNER"       },
        { P_AUDIT,      "P_AUDIT"       },
        { P_COMPAT,     "P_COMPAT"      },
@@ -1375,7 +1566,7 @@ static struct xlat procpriv_priv [] = {
 };
 
 
-static struct xlat procpriv_type [] = {
+static const struct xlat procpriv_type [] = {
        { PS_FIX,       "PS_FIX"        },
        { PS_INH,       "PS_INH"        },
        { PS_MAX,       "PS_MAX"        },
@@ -1389,7 +1580,7 @@ printpriv(tcp, addr, len, opt)
 struct tcb *tcp;
 long addr;
 int len;
-struct xlat *opt;
+const struct xlat *opt;
 {
        priv_t buf [128];
        int max = verbose (tcp) ? sizeof buf / sizeof buf [0] : 10;
@@ -1465,39 +1656,6 @@ struct tcb *tcp;
 #endif
 
 
-void
-fake_execve(tcp, program, argv, envp)
-struct tcb *tcp;
-char *program;
-char *argv[];
-char *envp[];
-{
-       int i;
-
-#ifdef ARM
-       if (!(qual_flags[SYS_execve - __NR_SYSCALL_BASE] & QUAL_TRACE))
-               return;
-#else
-       if (!(qual_flags[SYS_execve] & QUAL_TRACE))
-               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);
-}
-
 static void
 printargv(tcp, addr)
 struct tcb *tcp;
@@ -1587,9 +1745,6 @@ struct tcb *tcp;
                        tprintf("]");
                }
        }
-#if defined LINUX && defined TCB_WAITEXECVE
-       tcp->flags |= TCB_WAITEXECVE;
-#endif /* LINUX && TCB_WAITEXECVE */
        return 0;
 }
 
@@ -1615,6 +1770,12 @@ 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;
 }
 
@@ -1630,7 +1791,7 @@ struct tcb *tcp;
 #endif
 #endif /* LINUX */
 
-static struct xlat wait4_options[] = {
+static const struct xlat wait4_options[] = {
        { WNOHANG,      "WNOHANG"       },
 #ifndef WSTOPPED
        { WUNTRACED,    "WUNTRACED"     },
@@ -1662,6 +1823,20 @@ static struct xlat wait4_options[] = {
        { 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;
@@ -1673,20 +1848,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;
 }
 
@@ -1713,8 +1901,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 */
@@ -1742,8 +1929,9 @@ int bitness;
 }
 
 int
-internal_wait(tcp)
+internal_wait(tcp, flagarg)
 struct tcb *tcp;
+int flagarg;
 {
        int got_kids;
 
@@ -1769,8 +1957,38 @@ struct tcb *tcp;
 
                /* ??? WTA: fix bug with hanging children */
 
-               if (!(tcp->u_arg[2] & WNOHANG)) {
-                       /* There are traced 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))
+                                       return 0;
+                       }
                        tcp->flags |= TCB_SUSPENDED;
                        tcp->waitpid = tcp->u_arg[0];
 #ifdef TCB_CLONE_THREAD
@@ -1780,16 +1998,20 @@ struct tcb *tcp;
                }
        }
        if (exiting(tcp) && tcp->u_error == ECHILD && got_kids) {
-               if (tcp->u_arg[2] & WNOHANG) {
+               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
-                       fprintf(stderr,
-                               "internal_wait: should not have resumed %d\n",
-                               tcp->pid);
+       }
+       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;
 }
@@ -1852,16 +2074,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"       },
@@ -1879,11 +2111,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 */
@@ -1898,13 +2125,22 @@ struct tcb *tcp;
                        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)
@@ -1949,7 +2185,7 @@ struct tcb *tcp;
 
 #ifndef SVR4
 
-static struct xlat ptrace_cmds[] = {
+static const struct xlat ptrace_cmds[] = {
 #ifndef FREEBSD
        { PTRACE_TRACEME,       "PTRACE_TRACEME"        },
        { PTRACE_PEEKTEXT,      "PTRACE_PEEKTEXT",      },
@@ -1981,6 +2217,12 @@ static struct xlat ptrace_cmds[] = {
 #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"      },
@@ -2038,7 +2280,7 @@ 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
 #if defined(S390) || defined(S390X)
        { PT_PSWMASK,           "psw_mask"                              },
@@ -2296,16 +2538,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_B0, "kb0" },
        { PT_B1, "b1" }, { PT_B2, "b2" }, { PT_B3, "b3" },
        { PT_B4, "b4" }, { PT_B5, "b5" },
-       { PT_AR_PFS, "kar.pfs" },
-       { PT_AR_LC, "ar.lc" }, { PT_AR_UNAT, "kar.unat" },
-       { PT_AR_RNAT, "kar.rnat" }, { PT_AR_BSPSTORE, "kar.bspstore" },
-       { PT_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" },
@@ -2321,6 +2559,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"                                 },
@@ -2433,6 +2678,7 @@ struct xlat struct_user_offsets[] = {
        { 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"                          },
@@ -2441,10 +2687,184 @@ struct xlat struct_user_offsets[] = {
        { 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 */
-
-#if !defined(S390) && !defined(S390X) && !defined(MIPS)
+#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
 #if  defined(I386) || defined(X86_64)
@@ -2457,14 +2877,23 @@ 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(S390X) && !defined(MIPS) && !defined(SH)
+#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) && !defined(S390X)
+#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)"          },
@@ -2534,7 +2963,7 @@ int
 sys_ptrace(tcp)
 struct tcb *tcp;
 {
-       struct xlat *x;
+       const struct xlat *x;
        long addr;
 
        if (entering(tcp)) {
@@ -2619,10 +3048,11 @@ struct tcb *tcp;
 #endif /* !SVR4 */
 
 #ifdef LINUX
-static struct xlat futexops[] = {
+static const struct xlat futexops[] = {
        { FUTEX_WAIT,   "FUTEX_WAIT" },
        { FUTEX_WAKE,   "FUTEX_WAKE" },
        { FUTEX_FD,     "FUTEX_FD" },
+       { FUTEX_REQUEUE,"FUTEX_REQUEUE" },
        { 0,            NULL }
 };
 
@@ -2632,27 +3062,32 @@ struct tcb *tcp;
 {
     if (entering(tcp)) {
        tprintf("%p, ", (void *) tcp->u_arg[0]);
-       printflags(futexops, tcp->u_arg[1]);
+       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(list, len)
-unsigned long *list;
+print_affinitylist(tcp, list, len)
+struct tcb *tcp;
+long list;
 unsigned int len;
 {
     int first = 1;
     tprintf(" {");
-    while (len > sizeof (unsigned long)) {
-       tprintf("%s %lx", first ? "" : ",", *list++);
+    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(" }");
 }
@@ -2663,7 +3098,7 @@ struct tcb *tcp;
 {
     if (entering(tcp)) {
        tprintf("%ld, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
-       print_affinitylist((unsigned long *) tcp->u_arg[2], tcp->u_arg[1]);
+       print_affinitylist(tcp, tcp->u_arg[2], tcp->u_arg[1]);
     }
     return 0;
 }
@@ -2675,8 +3110,123 @@ struct tcb *tcp;
     if (entering(tcp)) {
        tprintf("%ld, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
     } else {
-       print_affinitylist((unsigned long *) tcp->u_arg[2], tcp->u_rval);
+       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