]> granicus.if.org Git - strace/blobdiff - syscall.c
mips n32: fix preadv/pwritev offset decoding
[strace] / syscall.c
index 29aa6d198741d994b3c8c85868f8285bcb4fb885..228536b479a7f51ac8dd4cb98fd69939c73e8f5a 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -37,6 +37,7 @@
 /* for struct iovec */
 #include <sys/uio.h>
 
+#include "regs.h"
 #include "ptrace.h"
 
 #if defined(SPARC64)
@@ -46,8 +47,6 @@
 # define PTRACE_SETREGS PTRACE_SETREGS64
 #endif
 
-#include "regs.h"
-
 #if defined SPARC64
 # include <asm/psrcompat.h>
 #elif defined SPARC
@@ -702,10 +701,10 @@ static struct iovec x86_io = {
 # define ARCH_REGS_FOR_GETREGSET x86_regs_union
 # define ARCH_IOVEC_FOR_GETREGSET x86_io
 #elif defined(IA64)
-bool ia64_ia32mode = 0; /* not static */
+static bool ia64_ia32mode;
 static long ia64_r8, ia64_r10;
 #elif defined(POWERPC)
-struct pt_regs ppc_regs;
+struct pt_regs ppc_regs; /* not static */
 # define ARCH_REGS_FOR_GETREGS ppc_regs
 #elif defined(M68K)
 static long m68k_d0;
@@ -771,7 +770,7 @@ static long sh64_r9;
 #elif defined(CRISV10) || defined(CRISV32)
 static long cris_r10;
 #elif defined(TILE)
-struct pt_regs tile_regs;
+struct pt_regs tile_regs; /* not static */
 # define ARCH_REGS_FOR_GETREGS tile_regs
 #elif defined(MICROBLAZE)
 static long microblaze_r3;
@@ -793,140 +792,143 @@ static long get_regs_error;
 void
 print_pc(struct tcb *tcp)
 {
-#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
-                          sizeof(long) == 8 ? "[????????????????] " : \
-                          NULL /* crash */)
+       const char *fmt;
+       const char *bad;
+
+#ifdef current_wordsize
+# define pc_wordsize current_wordsize
+#else
+# define pc_wordsize personality_wordsize[tcp->currpers]
+#endif
+
+       if (pc_wordsize == 4) {
+               fmt = "[%08lx] ";
+               bad = "[????????] ";
+       } else {
+               fmt = "[%016lx] ";
+               bad = "[????????????????] ";
+       }
+
+#undef pc_wordsize
+#define PRINTBADPC tprints(bad)
+
        if (get_regs_error) {
                PRINTBADPC;
                return;
        }
+
 #if defined(I386)
-       tprintf("[%08lx] ", i386_regs.eip);
+       tprintf(fmt, i386_regs.eip);
+#elif defined(X86_64) || defined(X32)
+       if (x86_io.iov_len == sizeof(i386_regs))
+               tprintf(fmt, (unsigned long) i386_regs.eip);
+       else
+               tprintf(fmt, (unsigned long) x86_64_regs.rip);
 #elif defined(S390) || defined(S390X)
        long psw;
        if (upeek(tcp->pid, PT_PSWADDR, &psw) < 0) {
                PRINTBADPC;
                return;
        }
-# ifdef S390
-       tprintf("[%08lx] ", psw);
-# elif S390X
-       tprintf("[%016lx] ", psw);
-# endif
-#elif defined(X86_64) || defined(X32)
-       if (x86_io.iov_len == sizeof(i386_regs)) {
-               tprintf("[%08x] ", (unsigned) i386_regs.eip);
-       } else {
-# if defined(X86_64)
-               tprintf("[%016lx] ", (unsigned long) x86_64_regs.rip);
-# elif defined(X32)
-               /* Note: this truncates 64-bit rip to 32 bits */
-               tprintf("[%08lx] ", (unsigned long) x86_64_regs.rip);
-# endif
-       }
+       tprintf(fmt, psw);
 #elif defined(IA64)
        long ip;
        if (upeek(tcp->pid, PT_B0, &ip) < 0) {
                PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", ip);
+       tprintf(fmt, ip);
 #elif defined(POWERPC)
-       long pc = ppc_regs.nip;
-# ifdef POWERPC64
-       tprintf("[%016lx] ", pc);
-# else
-       tprintf("[%08lx] ", pc);
-# endif
+       tprintf(fmt, ppc_regs.nip);
 #elif defined(M68K)
        long pc;
        if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
-               tprints("[????????] ");
+               PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
+       tprintf(fmt, pc);
 #elif defined(ALPHA)
        long pc;
        if (upeek(tcp->pid, REG_PC, &pc) < 0) {
-               tprints("[????????????????] ");
+               PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
+       tprintf(fmt, pc);
 #elif defined(SPARC)
-       tprintf("[%08lx] ", sparc_regs.pc);
+       tprintf(fmt, sparc_regs.pc);
 #elif defined(SPARC64)
-       tprintf("[%08lx] ", sparc_regs.tpc);
+       tprintf(fmt, sparc_regs.tpc);
 #elif defined(HPPA)
        long pc;
        if (upeek(tcp->pid, PT_IAOQ0, &pc) < 0) {
-               tprints("[????????] ");
+               PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
-#elif defined LINUX_MIPSN64
-       tprintf("[%016lx] ", mips_REG_EPC);
+       tprintf(fmt, pc);
 #elif defined MIPS
-       tprintf("[%08lx] ", (unsigned long) mips_REG_EPC);
+       tprintf(fmt, (unsigned long) mips_REG_EPC);
 #elif defined(SH)
        long pc;
        if (upeek(tcp->pid, 4*REG_PC, &pc) < 0) {
-               tprints("[????????] ");
+               PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
+       tprintf(fmt, pc);
 #elif defined(SH64)
        long pc;
        if (upeek(tcp->pid, REG_PC, &pc) < 0) {
-               tprints("[????????????????] ");
+               PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
-#elif defined(ARM)
-       tprintf("[%08lx] ", arm_regs.ARM_pc);
+       tprintf(fmt, pc);
 #elif defined(AARCH64)
-       /* tprintf("[%016lx] ", aarch64_regs.regs[???]); */
+       if (aarch64_io.iov_len == sizeof(arm_regs))
+               tprintf(fmt, (unsigned long) arm_regs.ARM_pc);
+       else
+               tprintf(fmt, (unsigned long) aarch64_regs.pc);
+#elif defined(ARM)
+       tprintf(fmt, arm_regs.ARM_pc);
 #elif defined(AVR32)
-       tprintf("[%08lx] ", avr32_regs.pc);
+       tprintf(fmt, avr32_regs.pc);
 #elif defined(BFIN)
        long pc;
        if (upeek(tcp->pid, PT_PC, &pc) < 0) {
                PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
+       tprintf(fmt, pc);
 #elif defined(CRISV10)
        long pc;
        if (upeek(tcp->pid, 4*PT_IRP, &pc) < 0) {
                PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
+       tprintf(fmt, pc);
 #elif defined(CRISV32)
        long pc;
        if (upeek(tcp->pid, 4*PT_ERP, &pc) < 0) {
                PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
+       tprintf(fmt, pc);
 #elif defined(TILE)
-# ifdef _LP64
-       tprintf("[%016lx] ", (unsigned long) tile_regs.pc);
-# else
-       tprintf("[%08lx] ", (unsigned long) tile_regs.pc);
-# endif
+       tprintf(fmt, (unsigned long) tile_regs.pc);
 #elif defined(OR1K)
-       tprintf("[%08lx] ", or1k_regs.pc);
+       tprintf(fmt, or1k_regs.pc);
 #elif defined(METAG)
-       tprintf("[%08lx] ", metag_regs.pc);
+       tprintf(fmt, metag_regs.pc);
 #elif defined(XTENSA)
        long pc;
        if (upeek(tcp->pid, REG_PC, &pc) < 0) {
                PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
+       tprintf(fmt, pc);
 #elif defined(ARC)
-       tprintf("[%08lx] ", arc_regs.efa);
+       tprintf(fmt, arc_regs.efa);
+#else
+# warning print_pc is not implemented for this architecture
+       PRINTBADPC;
 #endif /* architecture */
 }
 
@@ -1405,7 +1407,7 @@ get_scno(struct tcb *tcp)
        scno = mips_REG_V0;
 
        if (!SCNO_IN_RANGE(scno)) {
-               if (mips_REG_A3 == 0 || mips_REG_A3 == -1) {
+               if (mips_REG_A3 == 0 || mips_REG_A3 == (uint64_t) -1) {
                        if (debug_flag)
                                fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
                        return 0;
@@ -1586,12 +1588,8 @@ typedef unsigned long kernel_ulong_t;
 static inline bool
 is_negated_errno(kernel_ulong_t val)
 {
-       /*
-        * Thanks to SECCOMP_RET_DATA == 0xffff, abnormally large errno
-        * values could be easily seen when a seccomp filter is used, e.g.
-        * BPF_STMT(BPF_RET, SECCOMP_RET_ERRNO | SECCOMP_RET_DATA)
-        */
-       kernel_ulong_t max = -(kernel_long_t) 0x10000; /* SECCOMP_RET_DATA + 1 */
+       /* Linux kernel defines MAX_ERRNO to 4095. */
+       kernel_ulong_t max = -(kernel_long_t) 4095;
 
 #if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
        if (current_wordsize < sizeof(val)) {
@@ -1610,174 +1608,7 @@ is_negated_errno(kernel_ulong_t val)
        }
 #endif
 
-       return val > max;
-}
-
-/* Called at each syscall entry.
- * Returns:
- * 0: "ignore this ptrace stop", bail out of trace_syscall_entering() silently.
- * 1: ok, continue in trace_syscall_entering().
- * other: error, trace_syscall_entering() should print error indicator
- *    ("????" etc) and bail out.
- */
-static int
-syscall_fixup_on_sysenter(struct tcb *tcp)
-{
-       /* Do we have post-execve SIGTRAP suppressed? */
-       if (ptrace_setoptions & PTRACE_O_TRACEEXEC)
-               return 1;
-
-       /*
-        * No, unfortunately.  Apply -ENOSYS heuristics.
-        * We don't have to workaround SECCOMP_RET_ERRNO side effects
-        * because any kernel with SECCOMP_RET_ERRNO support surely
-        * implements PTRACE_O_TRACEEXEC.
-        */
-#if defined(I386)
-       if (i386_regs.eax != -ENOSYS) {
-               if (debug_flag)
-                       fprintf(stderr, "not a syscall entry (eax = %ld)\n",
-                               i386_regs.eax);
-               return 0;
-       }
-#elif defined(X86_64) || defined(X32)
-       if (x86_io.iov_len == sizeof(i386_regs)) {
-               if ((int) i386_regs.eax != -ENOSYS) {
-                       if (debug_flag)
-                               fprintf(stderr,
-                                       "not a syscall entry (eax = %d)\n",
-                                       (int) i386_regs.eax);
-                       return 0;
-               }
-       } else {
-               if ((long long) x86_64_regs.rax != -ENOSYS) {
-                       if (debug_flag)
-                               fprintf(stderr,
-                                       "not a syscall entry (rax = %lld)\n",
-                                       (long long) x86_64_regs.rax);
-                       return 0;
-               }
-       }
-#elif defined(M68K)
-       /* TODO? Eliminate upeek's in arches below like we did in x86 */
-       if (upeek(tcp->pid, 4*PT_D0, &m68k_d0) < 0)
-               return -1;
-       if (m68k_d0 != -ENOSYS) {
-               if (debug_flag)
-                       fprintf(stderr, "not a syscall entry (d0 = %ld)\n", m68k_d0);
-               return 0;
-       }
-#elif defined(IA64)
-       if (upeek(tcp->pid, PT_R10, &ia64_r10) < 0)
-               return -1;
-       if (upeek(tcp->pid, PT_R8, &ia64_r8) < 0)
-               return -1;
-       if (ia64_ia32mode && ia64_r8 != -ENOSYS) {
-               if (debug_flag)
-                       fprintf(stderr, "not a syscall entry (r8 = %ld)\n", ia64_r8);
-               return 0;
-       }
-#elif defined(CRISV10) || defined(CRISV32)
-       if (upeek(tcp->pid, 4*PT_R10, &cris_r10) < 0)
-               return -1;
-       if (cris_r10 != -ENOSYS) {
-               if (debug_flag)
-                       fprintf(stderr, "not a syscall entry (r10 = %ld)\n", cris_r10);
-               return 0;
-       }
-#elif defined(MICROBLAZE)
-       if (upeek(tcp->pid, 3 * 4, &microblaze_r3) < 0)
-               return -1;
-       if (microblaze_r3 != -ENOSYS) {
-               if (debug_flag)
-                       fprintf(stderr, "not a syscall entry (r3 = %ld)\n", microblaze_r3);
-               return 0;
-       }
-#endif
-       return 1;
-}
-
-static void
-internal_fork(struct tcb *tcp)
-{
-#if defined S390 || defined S390X || defined CRISV10 || defined CRISV32
-# define ARG_FLAGS     1
-#else
-# define ARG_FLAGS     0
-#endif
-#ifndef CLONE_UNTRACED
-# define CLONE_UNTRACED        0x00800000
-#endif
-       if ((ptrace_setoptions
-           & (PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK))
-          == (PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK))
-               return;
-
-       if (!followfork)
-               return;
-
-       if (entering(tcp)) {
-               /*
-                * We won't see the new child if clone is called with
-                * CLONE_UNTRACED, so we keep the same logic with that option
-                * and don't trace it.
-                */
-               if ((tcp->s_ent->sys_func == sys_clone)
-                && (tcp->u_arg[ARG_FLAGS] & CLONE_UNTRACED)
-               )
-                       return;
-               setbpt(tcp);
-       } else {
-               if (tcp->flags & TCB_BPTSET)
-                       clearbpt(tcp);
-       }
-}
-
-#if defined(TCB_WAITEXECVE)
-static void
-internal_exec(struct tcb *tcp)
-{
-       /* Maybe we have post-execve SIGTRAP suppressed? */
-       if (ptrace_setoptions & PTRACE_O_TRACEEXEC)
-               return; /* yes, no need to do anything */
-
-       if (exiting(tcp) && syserror(tcp))
-               /* Error in execve, no post-execve SIGTRAP expected */
-               tcp->flags &= ~TCB_WAITEXECVE;
-       else
-               tcp->flags |= TCB_WAITEXECVE;
-}
-#endif
-
-static void
-syscall_fixup_for_fork_exec(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)();
-
-       func = tcp->s_ent->sys_func;
-
-       if (   sys_fork == func
-           || sys_clone == func
-          ) {
-               internal_fork(tcp);
-               return;
-       }
-
-#if defined(TCB_WAITEXECVE)
-       if (   sys_execve == func
-# if defined(SPARC) || defined(SPARC64)
-           || sys_execv == func
-# endif
-          ) {
-               internal_exec(tcp);
-               return;
-       }
-#endif
+       return val >= max;
 }
 
 /* Return -1 on error or 1 on success (never 0!) */
@@ -2014,24 +1845,11 @@ trace_syscall_entering(struct tcb *tcp)
 {
        int res, scno_good;
 
-#if defined TCB_WAITEXECVE
-       if (tcp->flags & TCB_WAITEXECVE) {
-               /* This is the post-execve SIGTRAP. */
-               tcp->flags &= ~TCB_WAITEXECVE;
-               return 0;
-       }
-#endif
-
        scno_good = res = (get_regs_error ? -1 : get_scno(tcp));
        if (res == 0)
                return res;
-       if (res == 1) {
-               res = syscall_fixup_on_sysenter(tcp);
-               if (res == 0)
-                       return res;
-               if (res == 1)
-                       res = get_syscall_args(tcp);
-       }
+       if (res == 1)
+               res = get_syscall_args(tcp);
 
        if (res != 1) {
                printleader(tcp);
@@ -2074,9 +1892,6 @@ trace_syscall_entering(struct tcb *tcp)
        }
 #endif
 
-       if (need_fork_exec_workarounds)
-               syscall_fixup_for_fork_exec(tcp);
-
        if (!(tcp->qual_flg & QUAL_TRACE)
         || (tracing_paths && !pathtrace_match(tcp))
        ) {
@@ -2176,23 +1991,6 @@ get_syscall_result(struct tcb *tcp)
        return 1;
 }
 
-/* Called at each syscall exit */
-static void
-syscall_fixup_on_sysexit(struct tcb *tcp)
-{
-#if defined(S390) || defined(S390X)
-       if ((tcp->flags & TCB_WAITEXECVE)
-                && (s390_gpr2 == -ENOSYS || s390_gpr2 == tcp->scno)) {
-               /*
-                * Return from execve.
-                * Fake a return value of zero.  We leave the TCB_WAITEXECVE
-                * flag set for the post-execve SIGTRAP to see and reset.
-                */
-               s390_gpr2 = 0;
-       }
-#endif
-}
-
 /* Returns:
  * 1: ok, continue in trace_syscall_exiting().
  * -1: error, trace_syscall_exiting() should print error indicator
@@ -2516,10 +2314,7 @@ trace_syscall_exiting(struct tcb *tcp)
 #endif
        res = (get_regs_error ? -1 : get_syscall_result(tcp));
        if (res == 1) {
-               syscall_fixup_on_sysexit(tcp); /* never fails */
                get_error(tcp); /* never fails */
-               if (need_fork_exec_workarounds)
-                       syscall_fixup_for_fork_exec(tcp);
                if (filtered(tcp) || hide_log_until_execve)
                        goto ret;
        }
@@ -2642,13 +2437,12 @@ trace_syscall_exiting(struct tcb *tcp)
                        tprints("= ? ERESTART_RESTARTBLOCK (Interrupted by signal)");
                        break;
                default:
-                       if (u_error < 0)
-                               tprintf("= -1 E??? (errno %ld)", u_error);
-                       else if ((unsigned long) u_error < nerrnos)
+                       if ((unsigned long) u_error < nerrnos
+                           && errnoent[u_error])
                                tprintf("= -1 %s (%s)", errnoent[u_error],
                                        strerror(u_error));
                        else
-                               tprintf("= -1 ERRNO_%ld (%s)", u_error,
+                               tprintf("= -1 ERRNO_%lu (%s)", u_error,
                                        strerror(u_error));
                        break;
                }
@@ -2661,7 +2455,13 @@ trace_syscall_exiting(struct tcb *tcp)
                else {
                        switch (sys_res & RVAL_MASK) {
                        case RVAL_HEX:
-                               tprintf("= %#lx", tcp->u_rval);
+#if SUPPORTED_PERSONALITIES > 1
+                               if (current_wordsize < sizeof(long))
+                                       tprintf("= %#x",
+                                               (unsigned int) tcp->u_rval);
+                               else
+#endif
+                                       tprintf("= %#lx", tcp->u_rval);
                                break;
                        case RVAL_OCTAL:
                                tprintf("= %#lo", tcp->u_rval);