]> granicus.if.org Git - strace/commitdiff
Reorder functions in syscall.c. No code changes.
authorDenys Vlasenko <dvlasenk@redhat.com>
Wed, 24 Aug 2011 16:07:22 +0000 (18:07 +0200)
committerDenys Vlasenko <dvlasenk@redhat.com>
Wed, 24 Aug 2011 16:07:22 +0000 (18:07 +0200)
Old order (basically "in no particular order"):
    dumpio
    decode_subcall
    internal_syscall
    get_scno
    get_syscall_result
    known_scno
    syscall_fixup
    is_negated_errno
    get_error
    syscall_enter
    trace_syscall_entering
    trace_syscall_exiting
    trace_syscall
    printargs
    getrval2
    sys_indir
    is_restart_error

New order:
various utility functions:
    decode_subcall
    printargs
    getrval2
    sys_indir
    is_restart_error
syscall enter handling functions:
    get_scno
    known_scno
    syscall_fixup (also used in syscall exit code)
    internal_syscall (also used in syscall exit code)
    syscall_enter
    trace_syscall_entering
syscall exit handling functions:
    get_syscall_result
    is_negated_errno
    get_error
    dumpio
    trace_syscall_exiting
main syscall enter/exit function:
    trace_syscall

* syscall.c: Reorder functions so that related ones are closer
in the source.

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
syscall.c

index 3951066d1845028a174eba41bfc0cfa3b44b143c..ed1041709636088c7614c184bb3ab80bfd1f05ea 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -507,41 +507,6 @@ qualify(const char *s)
        return;
 }
 
-static void
-dumpio(struct tcb *tcp)
-{
-       if (syserror(tcp))
-               return;
-       if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
-               return;
-       if (tcp->scno < 0 || tcp->scno >= nsyscalls)
-               return;
-       if (sysent[tcp->scno].sys_func == printargs)
-               return;
-       if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
-               if (sysent[tcp->scno].sys_func == sys_read ||
-                   sysent[tcp->scno].sys_func == sys_pread ||
-                   sysent[tcp->scno].sys_func == sys_pread64 ||
-                   sysent[tcp->scno].sys_func == sys_recv ||
-                   sysent[tcp->scno].sys_func == sys_recvfrom)
-                       dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
-               else if (sysent[tcp->scno].sys_func == sys_readv)
-                       dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
-               return;
-       }
-       if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
-               if (sysent[tcp->scno].sys_func == sys_write ||
-                   sysent[tcp->scno].sys_func == sys_pwrite ||
-                   sysent[tcp->scno].sys_func == sys_pwrite64 ||
-                   sysent[tcp->scno].sys_func == sys_send ||
-                   sysent[tcp->scno].sys_func == sys_sendto)
-                       dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
-               else if (sysent[tcp->scno].sys_func == sys_writev)
-                       dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
-               return;
-       }
-}
-
 #ifndef FREEBSD
 enum subcall_style { shift_style, deref_style, mask_style, door_style };
 #else /* FREEBSD */
@@ -642,51 +607,111 @@ decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style s
 }
 #endif
 
-struct tcb *tcp_last = NULL;
-
-static int
-internal_syscall(struct tcb *tcp)
+int
+printargs(struct tcb *tcp)
 {
-       /*
-        * We must always trace a few critical system calls in order to
-        * correctly support following forks in the presence of tracing
-        * qualifiers.
-        */
-       int (*func)();
+       if (entering(tcp)) {
+               int i;
 
-       if (tcp->scno < 0 || tcp->scno >= nsyscalls)
-               return 0;
+               for (i = 0; i < tcp->u_nargs; i++)
+                       tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
+       }
+       return 0;
+}
 
-       func = sysent[tcp->scno].sys_func;
+long
+getrval2(struct tcb *tcp)
+{
+       long val = -1;
 
-       if (   sys_fork == func
-#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
-           || sys_vfork == func
-#endif
 #ifdef LINUX
-           || sys_clone == func
-#endif
-#if UNIXWARE > 2
-           || sys_rfork == func
+#if defined (SPARC) || defined (SPARC64)
+       struct pt_regs regs;
+       if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
+               return -1;
+       val = regs.u_regs[U_REG_O1];
+#elif defined(SH)
+       if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
+               return -1;
+#elif defined(IA64)
+       if (upeek(tcp, PT_R9, &val) < 0)
+               return -1;
 #endif
-          )
-               return internal_fork(tcp);
+#endif /* LINUX */
 
-#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
-       if (   sys_execve == func
-# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
-           || sys_execv == func
-# endif
-# if UNIXWARE > 2
-           || sys_rexecve == func
-# endif
-          )
-               return internal_exec(tcp);
+#ifdef SUNOS4
+       if (upeek(tcp, uoff(u_rval2), &val) < 0)
+               return -1;
+#endif /* SUNOS4 */
+
+#ifdef SVR4
+#ifdef SPARC
+       val = tcp->status.PR_REG[R_O1];
+#endif /* SPARC */
+#ifdef I386
+       val = tcp->status.PR_REG[EDX];
+#endif /* I386 */
+#ifdef X86_64
+       val = tcp->status.PR_REG[RDX];
+#endif /* X86_64 */
+#ifdef MIPS
+       val = tcp->status.PR_REG[CTX_V1];
+#endif /* MIPS */
+#endif /* SVR4 */
+
+#ifdef FREEBSD
+       struct reg regs;
+       pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
+       val = regs.r_edx;
 #endif
+       return val;
+}
+
+#ifdef SUNOS4
+/*
+ * Apparently, indirect system calls have already be converted by ptrace(2),
+ * so if you see "indir" this program has gone astray.
+ */
+int
+sys_indir(struct tcb *tcp)
+{
+       int i, scno, nargs;
+
+       if (entering(tcp)) {
+               scno = tcp->u_arg[0];
+               if (scno > nsyscalls) {
+                       fprintf(stderr, "Bogus syscall: %u\n", scno);
+                       return 0;
+               }
+               nargs = sysent[scno].nargs;
+               tprintf("%s", sysent[scno].sys_name);
+               for (i = 0; i < nargs; i++)
+                       tprintf(", %#lx", tcp->u_arg[i+1]);
+       }
+       return 0;
+}
+#endif /* SUNOS4 */
 
+int
+is_restart_error(struct tcb *tcp)
+{
+#ifdef LINUX
+       if (!syserror(tcp))
+               return 0;
+       switch (tcp->u_error) {
+               case ERESTARTSYS:
+               case ERESTARTNOINTR:
+               case ERESTARTNOHAND:
+               case ERESTART_RESTARTBLOCK:
+                       return 1;
+               default:
+                       break;
+       }
+#endif /* LINUX */
        return 0;
 }
 
+struct tcb *tcp_last = NULL;
 
 #ifdef LINUX
 # if defined (I386)
@@ -1198,97 +1223,6 @@ get_scno(struct tcb *tcp)
        return 1;
 }
 
-/* Returns:
- * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
- * 1: ok, continue in trace_syscall().
- * other: error, trace_syscall() should print error indicator
- *    ("????" etc) and bail out.
- */
-static int
-get_syscall_result(struct tcb *tcp)
-{
-#ifdef LINUX
-# if defined(S390) || defined(S390X)
-# elif defined (POWERPC)
-# elif defined(AVR32)
-       /* Read complete register set in one go. */
-       if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
-               return -1;
-# elif defined(BFIN)
-# elif defined (I386)
-       if (upeek(tcp, 4*EAX, &eax) < 0)
-               return -1;
-# elif defined (X86_64)
-       if (upeek(tcp, 8*RAX, &rax) < 0)
-               return -1;
-# elif defined(IA64)
-#      define IA64_PSR_IS      ((long)1 << 34)
-       if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
-               ia32 = (psr & IA64_PSR_IS) != 0;
-       if (upeek(tcp, PT_R8, &r8) < 0)
-               return -1;
-       if (upeek(tcp, PT_R10, &r10) < 0)
-               return -1;
-# elif defined (ARM)
-       /* Read complete register set in one go. */
-       if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
-               return -1;
-# elif defined (M68K)
-# elif defined (LINUX_MIPSN32)
-       unsigned long long regs[38];
-
-       if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
-               return -1;
-       a3 = regs[REG_A3];
-       r2 = regs[REG_V0];
-# elif defined (MIPS)
-       if (upeek(tcp, REG_A3, &a3) < 0)
-               return -1;
-       if (upeek(tcp, REG_V0, &r2) < 0)
-               return -1;
-# elif defined (ALPHA)
-       if (upeek(tcp, REG_A3, &a3) < 0)
-               return -1;
-       if (upeek(tcp, REG_R0, &r0) < 0)
-               return -1;
-# elif defined (SPARC) || defined (SPARC64)
-       /* Everything we need is in the current register set. */
-       if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
-               return -1;
-# elif defined(HPPA)
-# elif defined(SH)
-# elif defined(SH64)
-# elif defined(CRISV10) || defined(CRISV32)
-# elif defined(TILE)
-# elif defined(MICROBLAZE)
-# endif
-#endif /* LINUX */
-
-#ifdef SUNOS4
-#elif defined(SH)
-       /* new syscall ABI returns result in R0 */
-       if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
-               return -1;
-#elif defined(SH64)
-       /* ABI defines result returned in r9 */
-       if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
-               return -1;
-#endif
-
-#ifdef USE_PROCFS
-# ifndef HAVE_PR_SYSCALL
-#  ifdef FREEBSD
-       if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
-               perror("pread");
-               return -1;
-       }
-#  endif /* FREEBSD */
-# endif /* !HAVE_PR_SYSCALL */
-#endif /* USE_PROCFS */
-
-       return 1;
-}
-
 long
 known_scno(struct tcb *tcp)
 {
@@ -1481,544 +1415,292 @@ syscall_fixup(struct tcb *tcp)
        return 1;
 }
 
-#ifdef LINUX
-/*
- * Check the syscall return value register value for whether it is
- * a negated errno code indicating an error, or a success return value.
- */
-static inline int
-is_negated_errno(unsigned long int val)
+static int
+internal_syscall(struct tcb *tcp)
 {
-       unsigned long int max = -(long int) nerrnos;
-# if SUPPORTED_PERSONALITIES > 1
-       if (personality_wordsize[current_personality] < sizeof(val)) {
-               val = (unsigned int) val;
-               max = (unsigned int) max;
-       }
+       /*
+        * We must always trace a few critical system calls in order to
+        * correctly support following forks in the presence of tracing
+        * qualifiers.
+        */
+       int (*func)();
+
+       if (tcp->scno < 0 || tcp->scno >= nsyscalls)
+               return 0;
+
+       func = sysent[tcp->scno].sys_func;
+
+       if (   sys_fork == func
+#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
+           || sys_vfork == func
+#endif
+#ifdef LINUX
+           || sys_clone == func
+#endif
+#if UNIXWARE > 2
+           || sys_rfork == func
+#endif
+          )
+               return internal_fork(tcp);
+
+#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
+       if (   sys_execve == func
+# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
+           || sys_execv == func
 # endif
-       return val > max;
-}
+# if UNIXWARE > 2
+           || sys_rexecve == func
+# endif
+          )
+               return internal_exec(tcp);
 #endif
 
+       return 0;
+}
+
 static int
-get_error(struct tcb *tcp)
+syscall_enter(struct tcb *tcp)
 {
-       int u_error = 0;
 #ifdef LINUX
-       int check_errno = 1;
-       if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
-           sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
-               check_errno = 0;
-       }
+       int i, nargs;
+
+       if (tcp->scno >= 0 && tcp->scno < nsyscalls)
+               nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
+       else
+               nargs = tcp->u_nargs = MAX_ARGS;
+
 # if defined(S390) || defined(S390X)
-       if (check_errno && is_negated_errno(gpr2)) {
-               tcp->u_rval = -1;
-               u_error = -gpr2;
-       }
-       else {
-               tcp->u_rval = gpr2;
-               u_error = 0;
-       }
-# elif defined(I386)
-       if (check_errno && is_negated_errno(eax)) {
-               tcp->u_rval = -1;
-               u_error = -eax;
-       }
-       else {
-               tcp->u_rval = eax;
-               u_error = 0;
-       }
-# elif defined(X86_64)
-       if (check_errno && is_negated_errno(rax)) {
-               tcp->u_rval = -1;
-               u_error = -rax;
-       }
-       else {
-               tcp->u_rval = rax;
-               u_error = 0;
-       }
+       for (i = 0; i < nargs; ++i)
+               if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
+                       return -1;
+# elif defined(ALPHA)
+       for (i = 0; i < nargs; ++i)
+               if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
+                       return -1;
 # elif defined(IA64)
-       if (ia32) {
-               int err;
+       if (!ia32) {
+               unsigned long *out0, cfm, sof, sol;
+               long rbs_end;
+               /* be backwards compatible with kernel < 2.4.4... */
+#              ifndef PT_RBS_END
+#                define PT_RBS_END     PT_AR_BSP
+#              endif
 
-               err = (int)r8;
-               if (check_errno && is_negated_errno(err)) {
-                       tcp->u_rval = -1;
-                       u_error = -err;
-               }
-               else {
-                       tcp->u_rval = err;
-                       u_error = 0;
+               if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
+                       return -1;
+               if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
+                       return -1;
+
+               sof = (cfm >> 0) & 0x7f;
+               sol = (cfm >> 7) & 0x7f;
+               out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
+
+               for (i = 0; i < nargs; ++i) {
+                       if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
+                                  sizeof(long), (char *) &tcp->u_arg[i]) < 0)
+                               return -1;
                }
        } else {
-               if (check_errno && r10) {
-                       tcp->u_rval = -1;
-                       u_error = r8;
-               } else {
-                       tcp->u_rval = r8;
-                       u_error = 0;
+               static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
+                                                     PT_R9  /* ECX = out1 */,
+                                                     PT_R10 /* EDX = out2 */,
+                                                     PT_R14 /* ESI = out3 */,
+                                                     PT_R15 /* EDI = out4 */,
+                                                     PT_R13 /* EBP = out5 */};
+
+               for (i = 0; i < nargs; ++i) {
+                       if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
+                               return -1;
+                       /* truncate away IVE sign-extension */
+                       tcp->u_arg[i] &= 0xffffffff;
                }
        }
+# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
+       /* N32 and N64 both use up to six registers.  */
+       unsigned long long regs[38];
+
+       if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
+               return -1;
+
+       for (i = 0; i < nargs; ++i) {
+               tcp->u_arg[i] = regs[REG_A0 + i];
+#  if defined(LINUX_MIPSN32)
+               tcp->ext_arg[i] = regs[REG_A0 + i];
+#  endif
+       }
 # elif defined(MIPS)
-       if (check_errno && a3) {
-               tcp->u_rval = -1;
-               u_error = r2;
+       if (nargs > 4) {
+               long sp;
+
+               if (upeek(tcp, REG_SP, &sp) < 0)
+                       return -1;
+               for (i = 0; i < 4; ++i)
+                       if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
+                               return -1;
+               umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
+                      (char *)(tcp->u_arg + 4));
        } else {
-               tcp->u_rval = r2;
-               u_error = 0;
+               for (i = 0; i < nargs; ++i)
+                       if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
+                               return -1;
        }
 # elif defined(POWERPC)
-       if (check_errno && is_negated_errno(result)) {
-               tcp->u_rval = -1;
-               u_error = -result;
-       }
-       else {
-               tcp->u_rval = result;
-               u_error = 0;
-       }
-# elif defined(M68K)
-       if (check_errno && is_negated_errno(d0)) {
-               tcp->u_rval = -1;
-               u_error = -d0;
-       }
-       else {
-               tcp->u_rval = d0;
-               u_error = 0;
+#  ifndef PT_ORIG_R3
+#   define PT_ORIG_R3 34
+#  endif
+       for (i = 0; i < nargs; ++i) {
+               if (upeek(tcp, (i==0) ?
+                       (sizeof(unsigned long) * PT_ORIG_R3) :
+                       ((i+PT_R3) * sizeof(unsigned long)),
+                               &tcp->u_arg[i]) < 0)
+                       return -1;
        }
+# elif defined(SPARC) || defined(SPARC64)
+       for (i = 0; i < nargs; ++i)
+               tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
+# elif defined(HPPA)
+       for (i = 0; i < nargs; ++i)
+               if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
+                       return -1;
 # elif defined(ARM)
-       if (check_errno && is_negated_errno(regs.ARM_r0)) {
-               tcp->u_rval = -1;
-               u_error = -regs.ARM_r0;
-       }
-       else {
-               tcp->u_rval = regs.ARM_r0;
-               u_error = 0;
-       }
+       for (i = 0; i < nargs; ++i)
+               tcp->u_arg[i] = regs.uregs[i];
 # elif defined(AVR32)
-       if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
-               tcp->u_rval = -1;
-               u_error = -regs.r12;
-       }
-       else {
-               tcp->u_rval = regs.r12;
-               u_error = 0;
-       }
+       static const unsigned long *argregp[MAX_ARGS] = { &regs.r12,
+                                                         &regs.r11,
+                                                         &regs.r10,
+                                                         &regs.r9,
+                                                         &regs.r5,
+                                                         &regs.r3 };
+       for (i = 0; i < nargs; ++i)
+               tcp->u_arg[i] = *argregp[i];
 # elif defined(BFIN)
-       if (check_errno && is_negated_errno(r0)) {
-               tcp->u_rval = -1;
-               u_error = -r0;
-       } else {
-               tcp->u_rval = r0;
-               u_error = 0;
-       }
-# elif defined(ALPHA)
-       if (check_errno && a3) {
-               tcp->u_rval = -1;
-               u_error = r0;
-       }
-       else {
-               tcp->u_rval = r0;
-               u_error = 0;
-       }
-# elif defined(SPARC)
-       if (check_errno && regs.psr & PSR_C) {
-               tcp->u_rval = -1;
-               u_error = regs.u_regs[U_REG_O0];
-       }
-       else {
-               tcp->u_rval = regs.u_regs[U_REG_O0];
-               u_error = 0;
-       }
-# elif defined(SPARC64)
-       if (check_errno && regs.tstate & 0x1100000000UL) {
-               tcp->u_rval = -1;
-               u_error = regs.u_regs[U_REG_O0];
-       }
-       else {
-               tcp->u_rval = regs.u_regs[U_REG_O0];
-               u_error = 0;
-       }
-# elif defined(HPPA)
-       if (check_errno && is_negated_errno(r28)) {
-               tcp->u_rval = -1;
-               u_error = -r28;
-       }
-       else {
-               tcp->u_rval = r28;
-               u_error = 0;
-       }
+       static const int argreg[MAX_ARGS] = { PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5 };
+
+       for (i = 0; i < nargs; ++i)
+               if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
+                       return -1;
 # elif defined(SH)
-       /* interpret R0 as return value or error number */
-       if (check_errno && is_negated_errno(r0)) {
-               tcp->u_rval = -1;
-               u_error = -r0;
-       }
-       else {
-               tcp->u_rval = r0;
-               u_error = 0;
-       }
+       static const int syscall_regs[MAX_ARGS] = {
+               4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
+               4 * (REG_REG0+7), 4 * (REG_REG0  ), 4 * (REG_REG0+1)
+       };
+
+       for (i = 0; i < nargs; ++i)
+               if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
+                       return -1;
 # elif defined(SH64)
-       /* interpret result as return value or error number */
-       if (check_errno && is_negated_errno(r9)) {
-               tcp->u_rval = -1;
-               u_error = -r9;
-       }
-       else {
-               tcp->u_rval = r9;
-               u_error = 0;
-       }
+       int i;
+       /* Registers used by SH5 Linux system calls for parameters */
+       static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
+
+       for (i = 0; i < nargs; ++i)
+               if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
+                       return -1;
+# elif defined(X86_64)
+       static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
+               { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9  }, /* x86-64 ABI */
+               { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP }  /* i386 ABI */
+       };
+
+       for (i = 0; i < nargs; ++i)
+               if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
+                       return -1;
+# elif defined(MICROBLAZE)
+       for (i = 0; i < nargs; ++i)
+               if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
+                       return -1;
 # elif defined(CRISV10) || defined(CRISV32)
-       if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
-               tcp->u_rval = -1;
-               u_error = -r10;
-       }
-       else {
-               tcp->u_rval = r10;
-               u_error = 0;
-       }
+       static const int crisregs[MAX_ARGS] = {
+               4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
+               4*PT_R13     , 4*PT_MOF, 4*PT_SRP
+       };
+
+       for (i = 0; i < nargs; ++i)
+               if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
+                       return -1;
 # elif defined(TILE)
-       long rval;
-       /* interpret result as return value or error number */
-       if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
-               return -1;
-       if (check_errno && rval < 0 && rval > -nerrnos) {
-               tcp->u_rval = -1;
-               u_error = -rval;
-       }
-       else {
-               tcp->u_rval = rval;
-               u_error = 0;
-       }
-# elif defined(MICROBLAZE)
-       /* interpret result as return value or error number */
-       if (check_errno && is_negated_errno(r3)) {
-               tcp->u_rval = -1;
-               u_error = -r3;
-       }
-       else {
-               tcp->u_rval = r3;
-               u_error = 0;
-       }
+       for (i = 0; i < nargs; ++i)
+               if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
+                       return -1;
+# elif defined(M68K)
+       for (i = 0; i < nargs; ++i)
+               if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
+                       return -1;
+# else /* Other architecture (like i386) (32bits specific) */
+       for (i = 0; i < nargs; ++i)
+               if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
+                       return -1;
 # endif
 #endif /* LINUX */
 #ifdef SUNOS4
-       /* get error code from user struct */
-       if (upeek(tcp, uoff(u_error), &u_error) < 0)
-               return -1;
-       u_error >>= 24; /* u_error is a char */
+       int i, nargs;
+       if (tcp->scno >= 0 && tcp->scno < nsyscalls)
+               nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
+       else
+               nargs = tcp->u_nargs = MAX_ARGS;
+       for (i = 0; i < nargs; i++) {
+               struct user *u;
 
-       /* get system call return value */
-       if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
-               return -1;
+               if (upeek(tcp, uoff(u_arg[0]) +
+                   (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
+                       return -1;
+       }
 #endif /* SUNOS4 */
 #ifdef SVR4
-# ifdef SPARC
-       /* Judicious guessing goes a long way. */
-       if (tcp->status.pr_reg[R_PSR] & 0x100000) {
-               tcp->u_rval = -1;
-               u_error = tcp->status.pr_reg[R_O0];
-       }
-       else {
-               tcp->u_rval = tcp->status.pr_reg[R_O0];
-               u_error = 0;
-       }
-# endif /* SPARC */
-# ifdef I386
-       /* Wanna know how to kill an hour single-stepping? */
-       if (tcp->status.PR_REG[EFL] & 0x1) {
-               tcp->u_rval = -1;
-               u_error = tcp->status.PR_REG[EAX];
-       }
-       else {
-               tcp->u_rval = tcp->status.PR_REG[EAX];
-#  ifdef HAVE_LONG_LONG
-               tcp->u_lrval =
-                       ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
-                       tcp->status.PR_REG[EAX];
-#  endif
-               u_error = 0;
-       }
-# endif /* I386 */
-# ifdef X86_64
-       /* Wanna know how to kill an hour single-stepping? */
-       if (tcp->status.PR_REG[EFLAGS] & 0x1) {
-               tcp->u_rval = -1;
-               u_error = tcp->status.PR_REG[RAX];
-       }
-       else {
-               tcp->u_rval = tcp->status.PR_REG[RAX];
-               u_error = 0;
-       }
-# endif /* X86_64 */
 # ifdef MIPS
-       if (tcp->status.pr_reg[CTX_A3]) {
-               tcp->u_rval = -1;
-               u_error = tcp->status.pr_reg[CTX_V0];
+       /*
+        * SGI is broken: even though it has pr_sysarg, it doesn't
+        * set them on system call entry.  Get a clue.
+        */
+       if (tcp->scno >= 0 && tcp->scno < nsyscalls)
+               tcp->u_nargs = sysent[tcp->scno].nargs;
+       else
+               tcp->u_nargs = tcp->status.pr_nsysarg;
+       if (tcp->u_nargs > 4) {
+               memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
+                       4 * sizeof(tcp->u_arg[0]));
+               umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
+                       (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
        }
        else {
-               tcp->u_rval = tcp->status.pr_reg[CTX_V0];
-               u_error = 0;
+               memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
+                       tcp->u_nargs * sizeof(tcp->u_arg[0]));
        }
-# endif /* MIPS */
+# elif UNIXWARE >= 2
+       /*
+        * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
+        */
+       if (tcp->scno >= 0 && tcp->scno < nsyscalls)
+               tcp->u_nargs = sysent[tcp->scno].nargs;
+       else
+               tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
+       umoven(tcp, tcp->status.PR_REG[UESP] + 4,
+               tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
+# elif defined(HAVE_PR_SYSCALL)
+       int i;
+       if (tcp->scno >= 0 && tcp->scno < nsyscalls)
+               tcp->u_nargs = sysent[tcp->scno].nargs;
+       else
+               tcp->u_nargs = tcp->status.pr_nsysarg;
+       for (i = 0; i < tcp->u_nargs; i++)
+               tcp->u_arg[i] = tcp->status.pr_sysarg[i];
+# elif defined(I386)
+       if (tcp->scno >= 0 && tcp->scno < nsyscalls)
+               tcp->u_nargs = sysent[tcp->scno].nargs;
+       else
+               tcp->u_nargs = 5;
+       if (tcp->u_nargs > 0)
+               umoven(tcp, tcp->status.PR_REG[UESP] + 4,
+                       tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
+# else
+       I DONT KNOW WHAT TO DO
+# endif
 #endif /* SVR4 */
 #ifdef FREEBSD
-       if (regs.r_eflags & PSL_C) {
-               tcp->u_rval = -1;
-               u_error = regs.r_eax;
-       } else {
-               tcp->u_rval = regs.r_eax;
-               tcp->u_lrval =
-                 ((unsigned long long) regs.r_edx << 32) +  regs.r_eax;
-               u_error = 0;
-       }
-#endif /* FREEBSD */
-       tcp->u_error = u_error;
-       return 1;
-}
-
-static int
-syscall_enter(struct tcb *tcp)
-{
-#ifdef LINUX
-       int i, nargs;
-
-       if (tcp->scno >= 0 && tcp->scno < nsyscalls)
-               nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
-       else
-               nargs = tcp->u_nargs = MAX_ARGS;
-
-# if defined(S390) || defined(S390X)
-       for (i = 0; i < nargs; ++i)
-               if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
-                       return -1;
-# elif defined(ALPHA)
-       for (i = 0; i < nargs; ++i)
-               if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
-                       return -1;
-# elif defined(IA64)
-       if (!ia32) {
-               unsigned long *out0, cfm, sof, sol;
-               long rbs_end;
-               /* be backwards compatible with kernel < 2.4.4... */
-#              ifndef PT_RBS_END
-#                define PT_RBS_END     PT_AR_BSP
-#              endif
-
-               if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
-                       return -1;
-               if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
-                       return -1;
-
-               sof = (cfm >> 0) & 0x7f;
-               sol = (cfm >> 7) & 0x7f;
-               out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
-
-               for (i = 0; i < nargs; ++i) {
-                       if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
-                                  sizeof(long), (char *) &tcp->u_arg[i]) < 0)
-                               return -1;
-               }
-       } else {
-               static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
-                                                     PT_R9  /* ECX = out1 */,
-                                                     PT_R10 /* EDX = out2 */,
-                                                     PT_R14 /* ESI = out3 */,
-                                                     PT_R15 /* EDI = out4 */,
-                                                     PT_R13 /* EBP = out5 */};
-
-               for (i = 0; i < nargs; ++i) {
-                       if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
-                               return -1;
-                       /* truncate away IVE sign-extension */
-                       tcp->u_arg[i] &= 0xffffffff;
-               }
-       }
-# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
-       /* N32 and N64 both use up to six registers.  */
-       unsigned long long regs[38];
-
-       if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
-               return -1;
-
-       for (i = 0; i < nargs; ++i) {
-               tcp->u_arg[i] = regs[REG_A0 + i];
-#  if defined(LINUX_MIPSN32)
-               tcp->ext_arg[i] = regs[REG_A0 + i];
-#  endif
-       }
-# elif defined(MIPS)
-       if (nargs > 4) {
-               long sp;
-
-               if (upeek(tcp, REG_SP, &sp) < 0)
-                       return -1;
-               for (i = 0; i < 4; ++i)
-                       if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
-                               return -1;
-               umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
-                      (char *)(tcp->u_arg + 4));
-       } else {
-               for (i = 0; i < nargs; ++i)
-                       if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
-                               return -1;
-       }
-# elif defined(POWERPC)
-#  ifndef PT_ORIG_R3
-#   define PT_ORIG_R3 34
-#  endif
-       for (i = 0; i < nargs; ++i) {
-               if (upeek(tcp, (i==0) ?
-                       (sizeof(unsigned long) * PT_ORIG_R3) :
-                       ((i+PT_R3) * sizeof(unsigned long)),
-                               &tcp->u_arg[i]) < 0)
-                       return -1;
-       }
-# elif defined(SPARC) || defined(SPARC64)
-       for (i = 0; i < nargs; ++i)
-               tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
-# elif defined(HPPA)
-       for (i = 0; i < nargs; ++i)
-               if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
-                       return -1;
-# elif defined(ARM)
-       for (i = 0; i < nargs; ++i)
-               tcp->u_arg[i] = regs.uregs[i];
-# elif defined(AVR32)
-       static const unsigned long *argregp[MAX_ARGS] = { &regs.r12,
-                                                         &regs.r11,
-                                                         &regs.r10,
-                                                         &regs.r9,
-                                                         &regs.r5,
-                                                         &regs.r3 };
-       for (i = 0; i < nargs; ++i)
-               tcp->u_arg[i] = *argregp[i];
-# elif defined(BFIN)
-       static const int argreg[MAX_ARGS] = { PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5 };
-
-       for (i = 0; i < nargs; ++i)
-               if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
-                       return -1;
-# elif defined(SH)
-       static const int syscall_regs[MAX_ARGS] = {
-               4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
-               4 * (REG_REG0+7), 4 * (REG_REG0  ), 4 * (REG_REG0+1)
-       };
-
-       for (i = 0; i < nargs; ++i)
-               if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
-                       return -1;
-# elif defined(SH64)
-       int i;
-       /* Registers used by SH5 Linux system calls for parameters */
-       static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
-
-       for (i = 0; i < nargs; ++i)
-               if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
-                       return -1;
-# elif defined(X86_64)
-       static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
-               { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9  }, /* x86-64 ABI */
-               { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP }  /* i386 ABI */
-       };
-
-       for (i = 0; i < nargs; ++i)
-               if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
-                       return -1;
-# elif defined(MICROBLAZE)
-       for (i = 0; i < nargs; ++i)
-               if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
-                       return -1;
-# elif defined(CRISV10) || defined(CRISV32)
-       static const int crisregs[MAX_ARGS] = {
-               4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
-               4*PT_R13     , 4*PT_MOF, 4*PT_SRP
-       };
-
-       for (i = 0; i < nargs; ++i)
-               if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
-                       return -1;
-# elif defined(TILE)
-       for (i = 0; i < nargs; ++i)
-               if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
-                       return -1;
-# elif defined(M68K)
-       for (i = 0; i < nargs; ++i)
-               if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
-                       return -1;
-# else /* Other architecture (like i386) (32bits specific) */
-       for (i = 0; i < nargs; ++i)
-               if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
-                       return -1;
-# endif
-#endif /* LINUX */
-#ifdef SUNOS4
-       int i, nargs;
-       if (tcp->scno >= 0 && tcp->scno < nsyscalls)
-               nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
-       else
-               nargs = tcp->u_nargs = MAX_ARGS;
-       for (i = 0; i < nargs; i++) {
-               struct user *u;
-
-               if (upeek(tcp, uoff(u_arg[0]) +
-                   (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
-                       return -1;
-       }
-#endif /* SUNOS4 */
-#ifdef SVR4
-# ifdef MIPS
-       /*
-        * SGI is broken: even though it has pr_sysarg, it doesn't
-        * set them on system call entry.  Get a clue.
-        */
-       if (tcp->scno >= 0 && tcp->scno < nsyscalls)
-               tcp->u_nargs = sysent[tcp->scno].nargs;
-       else
-               tcp->u_nargs = tcp->status.pr_nsysarg;
-       if (tcp->u_nargs > 4) {
-               memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
-                       4 * sizeof(tcp->u_arg[0]));
-               umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
-                       (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
-       }
-       else {
-               memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
-                       tcp->u_nargs * sizeof(tcp->u_arg[0]));
-       }
-# elif UNIXWARE >= 2
-       /*
-        * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
-        */
-       if (tcp->scno >= 0 && tcp->scno < nsyscalls)
-               tcp->u_nargs = sysent[tcp->scno].nargs;
-       else
-               tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
-       umoven(tcp, tcp->status.PR_REG[UESP] + 4,
-               tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
-# elif defined(HAVE_PR_SYSCALL)
-       int i;
-       if (tcp->scno >= 0 && tcp->scno < nsyscalls)
-               tcp->u_nargs = sysent[tcp->scno].nargs;
-       else
-               tcp->u_nargs = tcp->status.pr_nsysarg;
-       for (i = 0; i < tcp->u_nargs; i++)
-               tcp->u_arg[i] = tcp->status.pr_sysarg[i];
-# elif defined(I386)
-       if (tcp->scno >= 0 && tcp->scno < nsyscalls)
-               tcp->u_nargs = sysent[tcp->scno].nargs;
-       else
-               tcp->u_nargs = 5;
-       if (tcp->u_nargs > 0)
-               umoven(tcp, tcp->status.PR_REG[UESP] + 4,
-                       tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
-# else
-       I DONT KNOW WHAT TO DO
-# endif
-#endif /* SVR4 */
-#ifdef FREEBSD
-       if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
-           sysent[tcp->scno].nargs > tcp->status.val)
-               tcp->u_nargs = sysent[tcp->scno].nargs;
+       if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
+           sysent[tcp->scno].nargs > tcp->status.val)
+               tcp->u_nargs = sysent[tcp->scno].nargs;
        else
                tcp->u_nargs = tcp->status.val;
        if (tcp->u_nargs < 0)
@@ -2151,66 +1833,487 @@ trace_syscall_entering(struct tcb *tcp)
 #endif
 #endif /* SVR4 */
 #ifdef FREEBSD
-       case SYS_msgsys:
-       case SYS_shmsys:
-       case SYS_semsys:
-               decode_subcall(tcp, 0, 0, table_style);
-               break;
-#endif
-#ifdef SUNOS4
-       case SYS_semsys:
-               decode_subcall(tcp, SYS_semsys_subcall,
-                       SYS_semsys_nsubcalls, shift_style);
-               break;
-       case SYS_msgsys:
-               decode_subcall(tcp, SYS_msgsys_subcall,
-                       SYS_msgsys_nsubcalls, shift_style);
-               break;
-       case SYS_shmsys:
-               decode_subcall(tcp, SYS_shmsys_subcall,
-                       SYS_shmsys_nsubcalls, shift_style);
-               break;
-#endif
+       case SYS_msgsys:
+       case SYS_shmsys:
+       case SYS_semsys:
+               decode_subcall(tcp, 0, 0, table_style);
+               break;
+#endif
+#ifdef SUNOS4
+       case SYS_semsys:
+               decode_subcall(tcp, SYS_semsys_subcall,
+                       SYS_semsys_nsubcalls, shift_style);
+               break;
+       case SYS_msgsys:
+               decode_subcall(tcp, SYS_msgsys_subcall,
+                       SYS_msgsys_nsubcalls, shift_style);
+               break;
+       case SYS_shmsys:
+               decode_subcall(tcp, SYS_shmsys_subcall,
+                       SYS_shmsys_nsubcalls, shift_style);
+               break;
+#endif
+       }
+
+       internal_syscall(tcp);
+
+       if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
+            !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
+           (tracing_paths && !pathtrace_match(tcp))) {
+               tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
+               return 0;
+       }
+
+       tcp->flags &= ~TCB_FILTERED;
+
+       if (cflag == CFLAG_ONLY_STATS) {
+               res = 0;
+               goto ret;
+       }
+
+       printleader(tcp);
+       tcp->flags &= ~TCB_REPRINT;
+       tcp_last = tcp;
+       if (tcp->scno >= nsyscalls || tcp->scno < 0)
+               tprintf("syscall_%lu(", tcp->scno);
+       else
+               tprintf("%s(", sysent[tcp->scno].sys_name);
+       if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
+           ((qual_flags[tcp->scno] & QUAL_RAW) &&
+            sysent[tcp->scno].sys_func != sys_exit))
+               res = printargs(tcp);
+       else
+               res = (*sysent[tcp->scno].sys_func)(tcp);
+
+       if (fflush(tcp->outf) == EOF)
+               return -1;
+ ret:
+       tcp->flags |= TCB_INSYSCALL;
+       /* Measure the entrance time as late as possible to avoid errors. */
+       if (dtime || cflag)
+               gettimeofday(&tcp->etime, NULL);
+       return res;
+}
+
+/* Returns:
+ * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
+ * 1: ok, continue in trace_syscall().
+ * other: error, trace_syscall() should print error indicator
+ *    ("????" etc) and bail out.
+ */
+static int
+get_syscall_result(struct tcb *tcp)
+{
+#ifdef LINUX
+# if defined(S390) || defined(S390X)
+# elif defined (POWERPC)
+# elif defined(AVR32)
+       /* Read complete register set in one go. */
+       if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
+               return -1;
+# elif defined(BFIN)
+# elif defined (I386)
+       if (upeek(tcp, 4*EAX, &eax) < 0)
+               return -1;
+# elif defined (X86_64)
+       if (upeek(tcp, 8*RAX, &rax) < 0)
+               return -1;
+# elif defined(IA64)
+#      define IA64_PSR_IS      ((long)1 << 34)
+       if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
+               ia32 = (psr & IA64_PSR_IS) != 0;
+       if (upeek(tcp, PT_R8, &r8) < 0)
+               return -1;
+       if (upeek(tcp, PT_R10, &r10) < 0)
+               return -1;
+# elif defined (ARM)
+       /* Read complete register set in one go. */
+       if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
+               return -1;
+# elif defined (M68K)
+# elif defined (LINUX_MIPSN32)
+       unsigned long long regs[38];
+
+       if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
+               return -1;
+       a3 = regs[REG_A3];
+       r2 = regs[REG_V0];
+# elif defined (MIPS)
+       if (upeek(tcp, REG_A3, &a3) < 0)
+               return -1;
+       if (upeek(tcp, REG_V0, &r2) < 0)
+               return -1;
+# elif defined (ALPHA)
+       if (upeek(tcp, REG_A3, &a3) < 0)
+               return -1;
+       if (upeek(tcp, REG_R0, &r0) < 0)
+               return -1;
+# elif defined (SPARC) || defined (SPARC64)
+       /* Everything we need is in the current register set. */
+       if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
+               return -1;
+# elif defined(HPPA)
+# elif defined(SH)
+# elif defined(SH64)
+# elif defined(CRISV10) || defined(CRISV32)
+# elif defined(TILE)
+# elif defined(MICROBLAZE)
+# endif
+#endif /* LINUX */
+
+#ifdef SUNOS4
+#elif defined(SH)
+       /* new syscall ABI returns result in R0 */
+       if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
+               return -1;
+#elif defined(SH64)
+       /* ABI defines result returned in r9 */
+       if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
+               return -1;
+#endif
+
+#ifdef USE_PROCFS
+# ifndef HAVE_PR_SYSCALL
+#  ifdef FREEBSD
+       if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
+               perror("pread");
+               return -1;
+       }
+#  endif /* FREEBSD */
+# endif /* !HAVE_PR_SYSCALL */
+#endif /* USE_PROCFS */
+
+       return 1;
+}
+
+#ifdef LINUX
+/*
+ * Check the syscall return value register value for whether it is
+ * a negated errno code indicating an error, or a success return value.
+ */
+static inline int
+is_negated_errno(unsigned long int val)
+{
+       unsigned long int max = -(long int) nerrnos;
+# if SUPPORTED_PERSONALITIES > 1
+       if (personality_wordsize[current_personality] < sizeof(val)) {
+               val = (unsigned int) val;
+               max = (unsigned int) max;
+       }
+# endif
+       return val > max;
+}
+#endif
+
+static int
+get_error(struct tcb *tcp)
+{
+       int u_error = 0;
+#ifdef LINUX
+       int check_errno = 1;
+       if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
+           sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
+               check_errno = 0;
+       }
+# if defined(S390) || defined(S390X)
+       if (check_errno && is_negated_errno(gpr2)) {
+               tcp->u_rval = -1;
+               u_error = -gpr2;
+       }
+       else {
+               tcp->u_rval = gpr2;
+               u_error = 0;
+       }
+# elif defined(I386)
+       if (check_errno && is_negated_errno(eax)) {
+               tcp->u_rval = -1;
+               u_error = -eax;
+       }
+       else {
+               tcp->u_rval = eax;
+               u_error = 0;
+       }
+# elif defined(X86_64)
+       if (check_errno && is_negated_errno(rax)) {
+               tcp->u_rval = -1;
+               u_error = -rax;
+       }
+       else {
+               tcp->u_rval = rax;
+               u_error = 0;
+       }
+# elif defined(IA64)
+       if (ia32) {
+               int err;
+
+               err = (int)r8;
+               if (check_errno && is_negated_errno(err)) {
+                       tcp->u_rval = -1;
+                       u_error = -err;
+               }
+               else {
+                       tcp->u_rval = err;
+                       u_error = 0;
+               }
+       } else {
+               if (check_errno && r10) {
+                       tcp->u_rval = -1;
+                       u_error = r8;
+               } else {
+                       tcp->u_rval = r8;
+                       u_error = 0;
+               }
+       }
+# elif defined(MIPS)
+       if (check_errno && a3) {
+               tcp->u_rval = -1;
+               u_error = r2;
+       } else {
+               tcp->u_rval = r2;
+               u_error = 0;
+       }
+# elif defined(POWERPC)
+       if (check_errno && is_negated_errno(result)) {
+               tcp->u_rval = -1;
+               u_error = -result;
+       }
+       else {
+               tcp->u_rval = result;
+               u_error = 0;
+       }
+# elif defined(M68K)
+       if (check_errno && is_negated_errno(d0)) {
+               tcp->u_rval = -1;
+               u_error = -d0;
+       }
+       else {
+               tcp->u_rval = d0;
+               u_error = 0;
+       }
+# elif defined(ARM)
+       if (check_errno && is_negated_errno(regs.ARM_r0)) {
+               tcp->u_rval = -1;
+               u_error = -regs.ARM_r0;
+       }
+       else {
+               tcp->u_rval = regs.ARM_r0;
+               u_error = 0;
+       }
+# elif defined(AVR32)
+       if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
+               tcp->u_rval = -1;
+               u_error = -regs.r12;
+       }
+       else {
+               tcp->u_rval = regs.r12;
+               u_error = 0;
+       }
+# elif defined(BFIN)
+       if (check_errno && is_negated_errno(r0)) {
+               tcp->u_rval = -1;
+               u_error = -r0;
+       } else {
+               tcp->u_rval = r0;
+               u_error = 0;
+       }
+# elif defined(ALPHA)
+       if (check_errno && a3) {
+               tcp->u_rval = -1;
+               u_error = r0;
+       }
+       else {
+               tcp->u_rval = r0;
+               u_error = 0;
+       }
+# elif defined(SPARC)
+       if (check_errno && regs.psr & PSR_C) {
+               tcp->u_rval = -1;
+               u_error = regs.u_regs[U_REG_O0];
+       }
+       else {
+               tcp->u_rval = regs.u_regs[U_REG_O0];
+               u_error = 0;
+       }
+# elif defined(SPARC64)
+       if (check_errno && regs.tstate & 0x1100000000UL) {
+               tcp->u_rval = -1;
+               u_error = regs.u_regs[U_REG_O0];
+       }
+       else {
+               tcp->u_rval = regs.u_regs[U_REG_O0];
+               u_error = 0;
+       }
+# elif defined(HPPA)
+       if (check_errno && is_negated_errno(r28)) {
+               tcp->u_rval = -1;
+               u_error = -r28;
+       }
+       else {
+               tcp->u_rval = r28;
+               u_error = 0;
+       }
+# elif defined(SH)
+       /* interpret R0 as return value or error number */
+       if (check_errno && is_negated_errno(r0)) {
+               tcp->u_rval = -1;
+               u_error = -r0;
+       }
+       else {
+               tcp->u_rval = r0;
+               u_error = 0;
+       }
+# elif defined(SH64)
+       /* interpret result as return value or error number */
+       if (check_errno && is_negated_errno(r9)) {
+               tcp->u_rval = -1;
+               u_error = -r9;
+       }
+       else {
+               tcp->u_rval = r9;
+               u_error = 0;
+       }
+# elif defined(CRISV10) || defined(CRISV32)
+       if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
+               tcp->u_rval = -1;
+               u_error = -r10;
+       }
+       else {
+               tcp->u_rval = r10;
+               u_error = 0;
+       }
+# elif defined(TILE)
+       long rval;
+       /* interpret result as return value or error number */
+       if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
+               return -1;
+       if (check_errno && rval < 0 && rval > -nerrnos) {
+               tcp->u_rval = -1;
+               u_error = -rval;
+       }
+       else {
+               tcp->u_rval = rval;
+               u_error = 0;
+       }
+# elif defined(MICROBLAZE)
+       /* interpret result as return value or error number */
+       if (check_errno && is_negated_errno(r3)) {
+               tcp->u_rval = -1;
+               u_error = -r3;
+       }
+       else {
+               tcp->u_rval = r3;
+               u_error = 0;
+       }
+# endif
+#endif /* LINUX */
+#ifdef SUNOS4
+       /* get error code from user struct */
+       if (upeek(tcp, uoff(u_error), &u_error) < 0)
+               return -1;
+       u_error >>= 24; /* u_error is a char */
+
+       /* get system call return value */
+       if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
+               return -1;
+#endif /* SUNOS4 */
+#ifdef SVR4
+# ifdef SPARC
+       /* Judicious guessing goes a long way. */
+       if (tcp->status.pr_reg[R_PSR] & 0x100000) {
+               tcp->u_rval = -1;
+               u_error = tcp->status.pr_reg[R_O0];
+       }
+       else {
+               tcp->u_rval = tcp->status.pr_reg[R_O0];
+               u_error = 0;
+       }
+# endif /* SPARC */
+# ifdef I386
+       /* Wanna know how to kill an hour single-stepping? */
+       if (tcp->status.PR_REG[EFL] & 0x1) {
+               tcp->u_rval = -1;
+               u_error = tcp->status.PR_REG[EAX];
+       }
+       else {
+               tcp->u_rval = tcp->status.PR_REG[EAX];
+#  ifdef HAVE_LONG_LONG
+               tcp->u_lrval =
+                       ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
+                       tcp->status.PR_REG[EAX];
+#  endif
+               u_error = 0;
+       }
+# endif /* I386 */
+# ifdef X86_64
+       /* Wanna know how to kill an hour single-stepping? */
+       if (tcp->status.PR_REG[EFLAGS] & 0x1) {
+               tcp->u_rval = -1;
+               u_error = tcp->status.PR_REG[RAX];
+       }
+       else {
+               tcp->u_rval = tcp->status.PR_REG[RAX];
+               u_error = 0;
+       }
+# endif /* X86_64 */
+# ifdef MIPS
+       if (tcp->status.pr_reg[CTX_A3]) {
+               tcp->u_rval = -1;
+               u_error = tcp->status.pr_reg[CTX_V0];
+       }
+       else {
+               tcp->u_rval = tcp->status.pr_reg[CTX_V0];
+               u_error = 0;
+       }
+# endif /* MIPS */
+#endif /* SVR4 */
+#ifdef FREEBSD
+       if (regs.r_eflags & PSL_C) {
+               tcp->u_rval = -1;
+               u_error = regs.r_eax;
+       } else {
+               tcp->u_rval = regs.r_eax;
+               tcp->u_lrval =
+                 ((unsigned long long) regs.r_edx << 32) +  regs.r_eax;
+               u_error = 0;
        }
+#endif /* FREEBSD */
+       tcp->u_error = u_error;
+       return 1;
+}
 
-       internal_syscall(tcp);
-
-       if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
-            !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
-           (tracing_paths && !pathtrace_match(tcp))) {
-               tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
-               return 0;
+static void
+dumpio(struct tcb *tcp)
+{
+       if (syserror(tcp))
+               return;
+       if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
+               return;
+       if (tcp->scno < 0 || tcp->scno >= nsyscalls)
+               return;
+       if (sysent[tcp->scno].sys_func == printargs)
+               return;
+       if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
+               if (sysent[tcp->scno].sys_func == sys_read ||
+                   sysent[tcp->scno].sys_func == sys_pread ||
+                   sysent[tcp->scno].sys_func == sys_pread64 ||
+                   sysent[tcp->scno].sys_func == sys_recv ||
+                   sysent[tcp->scno].sys_func == sys_recvfrom)
+                       dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
+               else if (sysent[tcp->scno].sys_func == sys_readv)
+                       dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
+               return;
        }
-
-       tcp->flags &= ~TCB_FILTERED;
-
-       if (cflag == CFLAG_ONLY_STATS) {
-               res = 0;
-               goto ret;
+       if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
+               if (sysent[tcp->scno].sys_func == sys_write ||
+                   sysent[tcp->scno].sys_func == sys_pwrite ||
+                   sysent[tcp->scno].sys_func == sys_pwrite64 ||
+                   sysent[tcp->scno].sys_func == sys_send ||
+                   sysent[tcp->scno].sys_func == sys_sendto)
+                       dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
+               else if (sysent[tcp->scno].sys_func == sys_writev)
+                       dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
+               return;
        }
-
-       printleader(tcp);
-       tcp->flags &= ~TCB_REPRINT;
-       tcp_last = tcp;
-       if (tcp->scno >= nsyscalls || tcp->scno < 0)
-               tprintf("syscall_%lu(", tcp->scno);
-       else
-               tprintf("%s(", sysent[tcp->scno].sys_name);
-       if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
-           ((qual_flags[tcp->scno] & QUAL_RAW) &&
-            sysent[tcp->scno].sys_func != sys_exit))
-               res = printargs(tcp);
-       else
-               res = (*sysent[tcp->scno].sys_func)(tcp);
-
-       if (fflush(tcp->outf) == EOF)
-               return -1;
- ret:
-       tcp->flags |= TCB_INSYSCALL;
-       /* Measure the entrance time as late as possible to avoid errors. */
-       if (dtime || cflag)
-               gettimeofday(&tcp->etime, NULL);
-       return res;
 }
 
 static int
@@ -2390,107 +2493,3 @@ trace_syscall(struct tcb *tcp)
        return exiting(tcp) ?
                trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
 }
-
-int
-printargs(struct tcb *tcp)
-{
-       if (entering(tcp)) {
-               int i;
-
-               for (i = 0; i < tcp->u_nargs; i++)
-                       tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
-       }
-       return 0;
-}
-
-long
-getrval2(struct tcb *tcp)
-{
-       long val = -1;
-
-#ifdef LINUX
-#if defined (SPARC) || defined (SPARC64)
-       struct pt_regs regs;
-       if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
-               return -1;
-       val = regs.u_regs[U_REG_O1];
-#elif defined(SH)
-       if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
-               return -1;
-#elif defined(IA64)
-       if (upeek(tcp, PT_R9, &val) < 0)
-               return -1;
-#endif
-#endif /* LINUX */
-
-#ifdef SUNOS4
-       if (upeek(tcp, uoff(u_rval2), &val) < 0)
-               return -1;
-#endif /* SUNOS4 */
-
-#ifdef SVR4
-#ifdef SPARC
-       val = tcp->status.PR_REG[R_O1];
-#endif /* SPARC */
-#ifdef I386
-       val = tcp->status.PR_REG[EDX];
-#endif /* I386 */
-#ifdef X86_64
-       val = tcp->status.PR_REG[RDX];
-#endif /* X86_64 */
-#ifdef MIPS
-       val = tcp->status.PR_REG[CTX_V1];
-#endif /* MIPS */
-#endif /* SVR4 */
-
-#ifdef FREEBSD
-       struct reg regs;
-       pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
-       val = regs.r_edx;
-#endif
-       return val;
-}
-
-#ifdef SUNOS4
-/*
- * Apparently, indirect system calls have already be converted by ptrace(2),
- * so if you see "indir" this program has gone astray.
- */
-int
-sys_indir(struct tcb *tcp)
-{
-       int i, scno, nargs;
-
-       if (entering(tcp)) {
-               scno = tcp->u_arg[0];
-               if (scno > nsyscalls) {
-                       fprintf(stderr, "Bogus syscall: %u\n", scno);
-                       return 0;
-               }
-               nargs = sysent[scno].nargs;
-               tprintf("%s", sysent[scno].sys_name);
-               for (i = 0; i < nargs; i++)
-                       tprintf(", %#lx", tcp->u_arg[i+1]);
-       }
-       return 0;
-}
-#endif /* SUNOS4 */
-
-int
-is_restart_error(struct tcb *tcp)
-{
-#ifdef LINUX
-       if (!syserror(tcp))
-               return 0;
-       switch (tcp->u_error) {
-               case ERESTARTSYS:
-               case ERESTARTNOINTR:
-               case ERESTARTNOHAND:
-               case ERESTART_RESTARTBLOCK:
-                       return 1;
-               default:
-                       break;
-       }
-#endif /* LINUX */
-       return 0;
-}