]> granicus.if.org Git - strace/blobdiff - syscall.c
Update AF_*, PF_*, MSG_*, and TCP_* constants
[strace] / syscall.c
index ef14a0afa04b2554f2d830cecec17c54871b1d30..7efee0e43e132c8827199c03f379ae3f636dfbab 100644 (file)
--- a/syscall.c
+++ b/syscall.c
 # include <asm/rse.h>
 #endif
 
-#if defined(X86_64) || defined(X32)
-# include <linux/ptrace.h>
-# include <sys/uio.h>
+/* for struct iovec */
+#include <sys/uio.h>
+/* for NT_PRSTATUS */
+#ifdef HAVE_ELF_H
 # include <elf.h>
 #endif
 
 #if defined(AARCH64)
 # include <asm/ptrace.h>
-# include <sys/uio.h>
-# include <elf.h>
 #endif
 
-#if defined(OR1K)
-# include <sys/uio.h>
-# include <elf.h>
+#if defined(XTENSA)
+# include <asm/ptrace.h>
 #endif
 
 #ifndef ERESTARTSYS
@@ -162,10 +160,6 @@ const char *const signalent0[] = {
 const struct_ioctlent ioctlent0[] = {
 #include "ioctlent.h"
 };
-enum { nsyscalls0 = ARRAY_SIZE(sysent0) };
-enum { nerrnos0 = ARRAY_SIZE(errnoent0) };
-enum { nsignals0 = ARRAY_SIZE(signalent0) };
-enum { nioctlents0 = ARRAY_SIZE(ioctlent0) };
 
 #if SUPPORTED_PERSONALITIES > 1
 static const char *const errnoent1[] = {
@@ -177,10 +171,6 @@ static const char *const signalent1[] = {
 static const struct_ioctlent ioctlent1[] = {
 # include "ioctlent1.h"
 };
-enum { nsyscalls1 = ARRAY_SIZE(sysent1) };
-enum { nerrnos1 = ARRAY_SIZE(errnoent1) };
-enum { nsignals1 = ARRAY_SIZE(signalent1) };
-enum { nioctlents1 = ARRAY_SIZE(ioctlent1) };
 #endif
 
 #if SUPPORTED_PERSONALITIES > 2
@@ -193,12 +183,48 @@ static const char *const signalent2[] = {
 static const struct_ioctlent ioctlent2[] = {
 # include "ioctlent2.h"
 };
-enum { nsyscalls2 = ARRAY_SIZE(sysent2) };
-enum { nerrnos2 = ARRAY_SIZE(errnoent2) };
-enum { nsignals2 = ARRAY_SIZE(signalent2) };
-enum { nioctlents2 = ARRAY_SIZE(ioctlent2) };
 #endif
 
+enum {
+       nsyscalls0 = ARRAY_SIZE(sysent0)
+#if SUPPORTED_PERSONALITIES > 1
+       , nsyscalls1 = ARRAY_SIZE(sysent1)
+# if SUPPORTED_PERSONALITIES > 2
+       , nsyscalls2 = ARRAY_SIZE(sysent2)
+# endif
+#endif
+};
+
+enum {
+       nerrnos0 = ARRAY_SIZE(errnoent0)
+#if SUPPORTED_PERSONALITIES > 1
+       , nerrnos1 = ARRAY_SIZE(errnoent1)
+# if SUPPORTED_PERSONALITIES > 2
+       , nerrnos2 = ARRAY_SIZE(errnoent2)
+# endif
+#endif
+};
+
+enum {
+       nsignals0 = ARRAY_SIZE(signalent0)
+#if SUPPORTED_PERSONALITIES > 1
+       , nsignals1 = ARRAY_SIZE(signalent1)
+# if SUPPORTED_PERSONALITIES > 2
+       , nsignals2 = ARRAY_SIZE(signalent2)
+# endif
+#endif
+};
+
+enum {
+       nioctlents0 = ARRAY_SIZE(ioctlent0)
+#if SUPPORTED_PERSONALITIES > 1
+       , nioctlents1 = ARRAY_SIZE(ioctlent1)
+# if SUPPORTED_PERSONALITIES > 2
+       , nioctlents2 = ARRAY_SIZE(ioctlent2)
+# endif
+#endif
+};
+
 #if SUPPORTED_PERSONALITIES > 1
 const struct_sysent *sysent = sysent0;
 const char *const *errnoent = errnoent0;
@@ -423,7 +449,7 @@ qual_syscall(const char *s, int bitflag, int not)
 
        if (*s >= '0' && *s <= '9') {
                i = string_to_uint(s);
-               if (i > MAX_NSYSCALLS)
+               if (i >= MAX_NSYSCALLS)
                        return -1;
                qualify_one(i, bitflag, not, -1);
                return 0;
@@ -434,7 +460,7 @@ qual_syscall(const char *s, int bitflag, int not)
                        if (sysent_vec[p][i].sys_name
                         && strcmp(s, sysent_vec[p][i].sys_name) == 0
                        ) {
-                               qualify_one(i, bitflag, not, 0);
+                               qualify_one(i, bitflag, not, p);
                                rc = 0;
                        }
                }
@@ -547,7 +573,7 @@ qualify(const char *s)
                        for (pers = 0; pers < SUPPORTED_PERSONALITIES; pers++) {
                                for (i = 0; i < nsyscall_vec[pers]; i++)
                                        if (sysent_vec[pers][i].sys_flags & n)
-                                               qualify_one(i, opt->bitflag, not, 0);
+                                               qualify_one(i, opt->bitflag, not, pers);
                        }
                        continue;
                }
@@ -685,6 +711,7 @@ is_restart_error(struct tcb *tcp)
 
 #if defined(I386)
 struct user_regs_struct i386_regs;
+# define ARCH_REGS_FOR_GETREGSET i386_regs
 #elif defined(X86_64) || defined(X32)
 /*
  * On i386, pt_regs and user_regs_struct are the same,
@@ -731,6 +758,7 @@ static long m68k_d0;
 static long bfin_r0;
 #elif defined(ARM)
 struct pt_regs arm_regs; /* not static */
+# define ARCH_REGS_FOR_GETREGSET arm_regs
 #elif defined(AARCH64)
 static union {
        struct user_pt_regs aarch64_r;
@@ -771,9 +799,12 @@ struct pt_regs tile_regs;
 static long microblaze_r3;
 #elif defined(OR1K)
 static struct user_regs_struct or1k_regs;
-static struct iovec or1k_io = {
-       .iov_base = &or1k_regs
-};
+# define ARCH_REGS_FOR_GETREGSET or1k_regs
+#elif defined(METAG)
+static struct user_gp_regs metag_regs;
+# define ARCH_REGS_FOR_GETREGSET metag_regs
+#elif defined(XTENSA)
+static long xtensa_a2;
 #endif
 
 void
@@ -909,6 +940,15 @@ printcall(struct tcb *tcp)
 # endif
 #elif defined(OR1K)
        tprintf("[%08lx] ", or1k_regs.pc);
+#elif defined(METAG)
+       tprintf("[%08lx] ", metag_regs.pc);
+#elif defined(XTENSA)
+       long pc;
+       if (upeek(tcp, REG_PC, &pc) < 0) {
+               PRINTBADPC;
+               return;
+       }
+       tprintf("[%08lx] ", pc);
 #endif /* architecture */
 }
 
@@ -959,83 +999,107 @@ undefined_scno_name(struct tcb *tcp)
 
 #ifndef get_regs
 long get_regs_error;
-void
-get_regs(pid_t pid)
+
+#if defined(PTRACE_GETREGSET) && defined(NT_PRSTATUS)
+static void get_regset(pid_t pid)
 {
-# if defined(AVR32)
-       get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, &avr32_regs);
-# elif defined(I386)
-       get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, (long) &i386_regs);
+/* constant iovec */
+# if defined(ARM) \
+  || defined(I386) \
+  || defined(METAG) \
+  || defined(OR1K)
+       static struct iovec io = {
+               .iov_base = &ARCH_REGS_FOR_GETREGSET,
+               .iov_len = sizeof(ARCH_REGS_FOR_GETREGSET)
+       };
+       get_regs_error = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &io);
+
+/* variable iovec */
 # elif defined(X86_64) || defined(X32)
-       /*
-        * PTRACE_GETREGSET was introduced in 2.6.33.
-        * Let's be paranoid and require a bit later kernel.
-        */
-       if (os_release >= KERNEL_VERSION(2,6,35)) {
-               /*x86_io.iov_base = &x86_regs_union; - already is */
-               x86_io.iov_len = sizeof(x86_regs_union);
-               get_regs_error = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, (long) &x86_io);
-       } else {
-               /* Use old method, with heuristical detection of 32-bitness */
-               x86_io.iov_len = sizeof(x86_64_regs);
-               get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, (long) &x86_64_regs);
-               if (!get_regs_error && x86_64_regs.cs == 0x23) {
-                       x86_io.iov_len = sizeof(i386_regs);
-                       /*
-                        * The order is important: i386_regs and x86_64_regs
-                        * are overlaid in memory!
-                        */
-                       i386_regs.ebx = x86_64_regs.rbx;
-                       i386_regs.ecx = x86_64_regs.rcx;
-                       i386_regs.edx = x86_64_regs.rdx;
-                       i386_regs.esi = x86_64_regs.rsi;
-                       i386_regs.edi = x86_64_regs.rdi;
-                       i386_regs.ebp = x86_64_regs.rbp;
-                       i386_regs.eax = x86_64_regs.rax;
-                       /*i386_regs.xds = x86_64_regs.ds; unused by strace */
-                       /*i386_regs.xes = x86_64_regs.es; ditto... */
-                       /*i386_regs.xfs = x86_64_regs.fs;*/
-                       /*i386_regs.xgs = x86_64_regs.gs;*/
-                       i386_regs.orig_eax = x86_64_regs.orig_rax;
-                       i386_regs.eip = x86_64_regs.rip;
-                       /*i386_regs.xcs = x86_64_regs.cs;*/
-                       /*i386_regs.eflags = x86_64_regs.eflags;*/
-                       i386_regs.esp = x86_64_regs.rsp;
-                       /*i386_regs.xss = x86_64_regs.ss;*/
-               }
-       }
-# elif defined(ARM)
-       get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, (void *)&arm_regs);
+       /* x86_io.iov_base = &x86_regs_union; - already is */
+       x86_io.iov_len = sizeof(x86_regs_union);
+       get_regs_error = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &x86_io);
 # elif defined(AARCH64)
-       /*aarch64_io.iov_base = &arm_regs_union; - already is */
+       /* aarch64_io.iov_base = &arm_regs_union; - already is */
        aarch64_io.iov_len = sizeof(arm_regs_union);
-       get_regs_error = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, (void *)&aarch64_io);
-#  if 0
-       /* Paranoia checks */
-       if (get_regs_error)
-               return;
-       switch (aarch64_io.iov_len) {
-               case sizeof(aarch64_regs):
-                       /* We are in 64-bit mode */
-                       break;
-               case sizeof(arm_regs):
-                       /* We are in 32-bit mode */
-                       break;
-               default:
-                       get_regs_error = -1;
-                       break;
-       }
-#  endif
+       get_regs_error = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &aarch64_io);
+# else
+#  warning both PTRACE_GETREGSET and NT_PRSTATUS are available but not yet used
+# endif
+}
+#endif /* PTRACE_GETREGSET && NT_PRSTATUS */
+
+void
+get_regs(pid_t pid)
+{
+/* PTRACE_GETREGSET only */
+# if defined(METAG) || defined(OR1K) || defined(X32) || defined(AARCH64)
+       get_regset(pid);
+
+/* PTRACE_GETREGS only */
+# elif defined(AVR32)
+       get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, &avr32_regs);
+# elif defined(TILE)
+       get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, &tile_regs);
 # elif defined(SPARC) || defined(SPARC64)
        get_regs_error = ptrace(PTRACE_GETREGS, pid, (char *)&sparc_regs, 0);
-# elif defined(TILE)
-       get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, (long) &tile_regs);
-# elif defined(OR1K)
-       or1k_io.iov_len = sizeof(or1k_regs);
-       get_regs_error = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &or1k_io);
+
+/* try PTRACE_GETREGSET first, fallback to PTRACE_GETREGS */
+# else
+#  if defined(PTRACE_GETREGSET) && defined(NT_PRSTATUS)
+       static int getregset_support;
+
+       if (getregset_support >= 0) {
+               get_regset(pid);
+               if (getregset_support > 0)
+                       return;
+               if (get_regs_error >= 0) {
+                       getregset_support = 1;
+                       return;
+               }
+               if (errno == EPERM || errno == ESRCH)
+                       return;
+               getregset_support = -1;
+       }
+#  endif /* PTRACE_GETREGSET && NT_PRSTATUS */
+#  if defined(ARM)
+       get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, &arm_regs);
+#  elif defined(I386)
+       get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, &i386_regs);
+#  elif defined(X86_64)
+       /* Use old method, with unreliable heuristical detection of 32-bitness. */
+       x86_io.iov_len = sizeof(x86_64_regs);
+       get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, &x86_64_regs);
+       if (!get_regs_error && x86_64_regs.cs == 0x23) {
+               x86_io.iov_len = sizeof(i386_regs);
+               /*
+                * The order is important: i386_regs and x86_64_regs
+                * are overlaid in memory!
+                */
+               i386_regs.ebx = x86_64_regs.rbx;
+               i386_regs.ecx = x86_64_regs.rcx;
+               i386_regs.edx = x86_64_regs.rdx;
+               i386_regs.esi = x86_64_regs.rsi;
+               i386_regs.edi = x86_64_regs.rdi;
+               i386_regs.ebp = x86_64_regs.rbp;
+               i386_regs.eax = x86_64_regs.rax;
+               /* i386_regs.xds = x86_64_regs.ds; unused by strace */
+               /* i386_regs.xes = x86_64_regs.es; ditto... */
+               /* i386_regs.xfs = x86_64_regs.fs; */
+               /* i386_regs.xgs = x86_64_regs.gs; */
+               i386_regs.orig_eax = x86_64_regs.orig_rax;
+               i386_regs.eip = x86_64_regs.rip;
+               /* i386_regs.xcs = x86_64_regs.cs; */
+               /* i386_regs.eflags = x86_64_regs.eflags; */
+               i386_regs.esp = x86_64_regs.rsp;
+               /* i386_regs.xss = x86_64_regs.ss; */
+       }
+#  else
+#   error unhandled architecture
+#  endif /* ARM || I386 || X86_64 */
 # endif
 }
-#endif
+#endif /* !get_regs */
 
 /* Returns:
  * 0: "ignore this ptrace stop", bail out of trace_syscall_entering() silently.
@@ -1076,7 +1140,7 @@ get_scno(struct tcb *tcp)
                errno = 0;
                opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(psw - sizeof(long)), 0);
                if (errno) {
-                       perror_msg("%s", "peektext(psw-oneword)");
+                       perror_msg("peektext(psw-oneword)");
                        return -1;
                }
 
@@ -1463,6 +1527,11 @@ get_scno(struct tcb *tcp)
                return -1;
 #elif defined(OR1K)
        scno = or1k_regs.gpr[11];
+#elif defined(METAG)
+       scno = metag_regs.dx[0][1];     /* syscall number in D1Re0 (D1.0) */
+#elif defined(XTENSA)
+       if (upeek(tcp, SYSCALL_NR, &scno) < 0)
+               return -1;
 #endif
 
        tcp->scno = scno;
@@ -1859,6 +1928,16 @@ get_syscall_args(struct tcb *tcp)
        (void)nargs;
        for (i = 0; i < 6; ++i)
                tcp->u_arg[i] = or1k_regs.gpr[3 + i];
+#elif defined(METAG)
+       for (i = 0; i < nargs; i++)
+               /* arguments go backwards from D1Ar1 (D1.3) */
+               tcp->u_arg[i] = ((unsigned long *)&metag_regs.dx[3][1])[-i];
+#elif defined(XTENSA)
+       /* arg0: a6, arg1: a3, arg2: a4, arg3: a5, arg4: a8, arg5: a9 */
+       static const int xtensaregs[MAX_ARGS] = { 6, 3, 4, 5, 8, 9 };
+       for (i = 0; i < nargs; ++i)
+               if (upeek(tcp, REG_A_BASE + xtensaregs[i], &tcp->u_arg[i]) < 0)
+                       return -1;
 #else /* Other architecture (32bits specific) */
        for (i = 0; i < nargs; ++i)
                if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
@@ -1906,6 +1985,14 @@ trace_syscall_entering(struct tcb *tcp)
                goto ret;
        }
 
+       if (   sys_execve == tcp->s_ent->sys_func
+# if defined(SPARC) || defined(SPARC64)
+           || sys_execv == tcp->s_ent->sys_func
+# endif
+          ) {
+               hide_log_until_execve = 0;
+       }
+
 #if defined(SYS_socket_subcall) || defined(SYS_ipc_subcall)
        while (1) {
 # ifdef SYS_socket_subcall
@@ -1936,7 +2023,7 @@ trace_syscall_entering(struct tcb *tcp)
 
        tcp->flags &= ~TCB_FILTERED;
 
-       if (cflag == CFLAG_ONLY_STATS) {
+       if (cflag == CFLAG_ONLY_STATS || hide_log_until_execve) {
                res = 0;
                goto ret;
        }
@@ -2053,6 +2140,11 @@ get_syscall_result(struct tcb *tcp)
                return -1;
 #elif defined(OR1K)
        /* already done by get_regs */
+#elif defined(METAG)
+       /* already done by get_regs */
+#elif defined(XTENSA)
+       if (upeek(tcp, REG_A_BASE + 2, &xtensa_a2) < 0)
+               return -1;
 #endif
        return 1;
 }
@@ -2306,6 +2398,15 @@ get_error(struct tcb *tcp)
        else {
                tcp->u_rval = sh64_r9;
        }
+#elif defined(METAG)
+       /* result pointer in D0Re0 (D0.0) */
+       if (check_errno && is_negated_errno(metag_regs.dx[0][0])) {
+               tcp->u_rval = -1;
+               u_error = -metag_regs.dx[0][0];
+       }
+       else {
+               tcp->u_rval = metag_regs.dx[0][0];
+       }
 #elif defined(CRISV10) || defined(CRISV32)
        if (check_errno && cris_r10 && (unsigned) -cris_r10 < nerrnos) {
                tcp->u_rval = -1;
@@ -2343,6 +2444,14 @@ get_error(struct tcb *tcp)
        else {
                tcp->u_rval = or1k_regs.gpr[11];
        }
+#elif defined(XTENSA)
+       if (check_errno && is_negated_errno(xtensa_a2)) {
+               tcp->u_rval = -1;
+               u_error = -xtensa_a2;
+       }
+       else {
+               tcp->u_rval = xtensa_a2;
+       }
 #endif
        tcp->u_error = u_error;
 }
@@ -2402,7 +2511,7 @@ trace_syscall_exiting(struct tcb *tcp)
                get_error(tcp); /* never fails */
                if (need_fork_exec_workarounds)
                        syscall_fixup_for_fork_exec(tcp);
-               if (filtered(tcp))
+               if (filtered(tcp) || hide_log_until_execve)
                        goto ret;
        }
 
@@ -2508,7 +2617,7 @@ trace_syscall_exiting(struct tcb *tcp)
                         * after SIG_IGN or SIG_DFL signal it will restart
                         * (thus the name "restart only if has no handler").
                         */
-                       tprints("= ? ERESTARTNOHAND (Interrupted by signal)");
+                       tprints("= ? ERESTARTNOHAND (To be restarted if no handler)");
                        break;
                case ERESTART_RESTARTBLOCK:
                        /* Syscalls like nanosleep(), poll() which can't be