]> granicus.if.org Git - strace/commitdiff
Introduce PTRACE_GET_SYSCALL_INFO support
authorDmitry V. Levin <ldv@altlinux.org>
Wed, 21 Nov 2018 01:44:16 +0000 (01:44 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Thu, 13 Dec 2018 22:07:26 +0000 (22:07 +0000)
When PTRACE_GET_SYSCALL_INFO API works,
use it instead of traditional upeek/get_regs API.

Tested on x86_64 and x86.

* get_personality.c: New file.
* get_personality.h: Likewise.
* Makefile.am (strace_SOURCES): Add them.
* linux/aarch64/arch_get_personality.c: New file.
* linux/powerpc64/arch_get_personality.c: Likewise.
* linux/riscv/arch_get_personality.c: Likewise.
* linux/s390x/arch_get_personality.c: Likewise.
* linux/sparc64/arch_get_personality.c: Likewise.
* linux/tile/arch_get_personality.c: Likewise.
* linux/x32/arch_get_personality.c: Likewise.
* linux/x86_64/arch_get_personality.c: Likewise.
* linux/check_scno.c: Likewise.
* linux/x32/check_scno.c: Likewise.
* Makefile.am (EXTRA_DIST): Add them.
* linux/ia64/arch_getrval2.c (getrval2): Invoke get_regs()
if ptrace_syscall_info is in use.
* linux/mips/arch_getrval2.c: Likewise.
* linux/sparc/arch_getrval2.c: Likewise.
* defs.h (get_personality_from_syscall_info): New prototype.
* syscall.c: Include "get_personality.h" and "ptrace_syscall_info.h".
(get_regs_error): Define unconditionally.
(ptrace_sci): New static variable.
(clear_regs): Reset ptrace_sci.op.
(ptrace_syscall_info_is_valid, ptrace_get_syscall_info,
get_syscall_regs): New functions.
(get_syscall_result_regs): Change to get_syscall_regs.
(get_instruction_pointer, get_stack_pointer, get_scno, get_syscall_args,
get_error, set_error, set_success): Add ptrace_syscall_info support.
* tests/int_0x80.test: New test.
* tests/Makefile.am (DECODER_TESTS): Add int_0x80.test.
(XFAIL_TESTS_x86_64, XFAIL_TESTS_x32): Remove.
* tests/gen_tests.in (int_0x80): Remove.

20 files changed:
Makefile.am
get_personality.c [new file with mode: 0644]
get_personality.h [new file with mode: 0644]
linux/aarch64/arch_get_personality.c [new file with mode: 0644]
linux/check_scno.c [new file with mode: 0644]
linux/ia64/arch_getrval2.c
linux/mips/arch_getrval2.c
linux/powerpc64/arch_get_personality.c [new file with mode: 0644]
linux/riscv/arch_get_personality.c [new file with mode: 0644]
linux/s390x/arch_get_personality.c [new file with mode: 0644]
linux/sparc/arch_getrval2.c
linux/sparc64/arch_get_personality.c [new file with mode: 0644]
linux/tile/arch_get_personality.c [new file with mode: 0644]
linux/x32/arch_get_personality.c [new file with mode: 0644]
linux/x32/check_scno.c [new file with mode: 0644]
linux/x86_64/arch_get_personality.c [new file with mode: 0644]
syscall.c
tests/Makefile.am
tests/gen_tests.in
tests/int_0x80.test [new file with mode: 0755]

index e13c925828c5e57d554abcf3355f7c11a8f4f1ce..1bc77bb724ceb65d3a039d8ca99248e81346c6e5 100644 (file)
@@ -134,6 +134,8 @@ strace_SOURCES =    \
        fs_x_ioctl.c    \
        futex.c         \
        gcc_compat.h    \
+       get_personality.c \
+       get_personality.h \
        get_robust_list.c \
        getcpu.c        \
        getcwd.c        \
@@ -417,6 +419,7 @@ EXTRA_DIST =                                \
        linux/64/ioctls_inc.h           \
        linux/64/syscallent.h           \
        linux/aarch64/arch_defs_.h      \
+       linux/aarch64/arch_get_personality.c \
        linux/aarch64/arch_regs.c       \
        linux/aarch64/arch_sigreturn.c  \
        linux/aarch64/get_error.c       \
@@ -505,6 +508,7 @@ EXTRA_DIST =                                \
        linux/bfin/set_scno.c           \
        linux/bfin/syscallent.h         \
        linux/bfin/userent.h            \
+       linux/check_scno.c              \
        linux/dummy.h                   \
        linux/errnoent.h                \
        linux/getregs_old.h             \
@@ -524,8 +528,8 @@ EXTRA_DIST =                                \
        linux/hppa/set_scno.c           \
        linux/hppa/signalent.h          \
        linux/hppa/syscallent.h         \
-       linux/i386/arch_kvm.c           \
        linux/i386/arch_defs_.h         \
+       linux/i386/arch_kvm.c           \
        linux/i386/arch_regs.c          \
        linux/i386/arch_rt_sigframe.c   \
        linux/i386/arch_sigreturn.c     \
@@ -663,6 +667,7 @@ EXTRA_DIST =                                \
        linux/powerpc/syscallent.h      \
        linux/powerpc/userent.h         \
        linux/powerpc64/arch_defs_.h    \
+       linux/powerpc64/arch_get_personality.c \
        linux/powerpc64/arch_regs.c     \
        linux/powerpc64/arch_rt_sigframe.c      \
        linux/powerpc64/arch_sigreturn.c        \
@@ -686,6 +691,7 @@ EXTRA_DIST =                                \
        linux/ptrace_pokeuser.c         \
        linux/raw_syscall.h             \
        linux/riscv/arch_defs_.h        \
+       linux/riscv/arch_get_personality.c \
        linux/riscv/arch_regs.c         \
        linux/riscv/get_error.c         \
        linux/riscv/get_scno.c          \
@@ -717,6 +723,7 @@ EXTRA_DIST =                                \
        linux/s390/userent0.h           \
        linux/s390/userent1.h           \
        linux/s390x/arch_defs_.h        \
+       linux/s390x/arch_get_personality.c \
        linux/s390x/arch_regs.c         \
        linux/s390x/arch_sigreturn.c    \
        linux/s390x/get_error.c         \
@@ -786,6 +793,7 @@ EXTRA_DIST =                                \
        linux/sparc/syscallent.h        \
        linux/sparc/userent.h           \
        linux/sparc64/arch_defs_.h      \
+       linux/sparc64/arch_get_personality.c \
        linux/sparc64/arch_getrval2.c   \
        linux/sparc64/arch_regs.c       \
        linux/sparc64/arch_rt_sigframe.c        \
@@ -809,6 +817,7 @@ EXTRA_DIST =                                \
        linux/subcall.h                 \
        linux/syscall.h                 \
        linux/tile/arch_defs_.h         \
+       linux/tile/arch_get_personality.c \
        linux/tile/arch_regs.c          \
        linux/tile/arch_sigreturn.c     \
        linux/tile/get_error.c          \
@@ -829,11 +838,13 @@ EXTRA_DIST =                              \
        linux/userent.h                 \
        linux/userent0.h                \
        linux/x32/arch_defs_.h          \
+       linux/x32/arch_get_personality.c \
        linux/x32/arch_kvm.c            \
        linux/x32/arch_regs.c           \
        linux/x32/arch_regs.h           \
        linux/x32/arch_rt_sigframe.c    \
        linux/x32/arch_sigreturn.c      \
+       linux/x32/check_scno.c          \
        linux/x32/get_error.c           \
        linux/x32/get_scno.c            \
        linux/x32/get_syscall_args.c    \
@@ -851,6 +862,7 @@ EXTRA_DIST =                                \
        linux/x32/syscallent1.h         \
        linux/x32/userent.h             \
        linux/x86_64/arch_defs_.h       \
+       linux/x86_64/arch_get_personality.c \
        linux/x86_64/arch_kvm.c         \
        linux/x86_64/arch_regs.c        \
        linux/x86_64/arch_regs.h        \
diff --git a/get_personality.c b/get_personality.c
new file mode 100644 (file)
index 0000000..4fa0969
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "defs.h"
+
+#if SUPPORTED_PERSONALITIES > 1
+# include "get_personality.h"
+# include <linux/audit.h>
+# include "arch_get_personality.c"
+#endif
diff --git a/get_personality.h b/get_personality.h
new file mode 100644 (file)
index 0000000..7571e43
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef STRACE_GET_PERSONALITY_H
+#define STRACE_GET_PERSONALITY_H
+
+#include "ptrace.h"
+
+extern int
+get_personality_from_syscall_info(const struct ptrace_syscall_info *);
+
+#endif /* !STRACE_GET_PERSONALITY_H */
diff --git a/linux/aarch64/arch_get_personality.c b/linux/aarch64/arch_get_personality.c
new file mode 100644 (file)
index 0000000..534d7f4
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef AUDIT_ARCH_ARM
+# define AUDIT_ARCH_ARM 0x40000028
+#endif
+
+int
+get_personality_from_syscall_info(const struct ptrace_syscall_info *sci)
+{
+       return sci->arch == AUDIT_ARCH_ARM;
+}
diff --git a/linux/check_scno.c b/linux/check_scno.c
new file mode 100644 (file)
index 0000000..cdeff67
--- /dev/null
@@ -0,0 +1,6 @@
+/* Return codes: 1 - ok, 0 - ignore, other - error. */
+static int
+arch_check_scno(struct tcb *tcp)
+{
+       return 1;
+}
index 7a6875f0bb36749ad27ac493f0a1fd9e6077945b..f4ea78cc178ea42f276dbfb23a71925681161361 100644 (file)
@@ -1,5 +1,7 @@
 long
 getrval2(struct tcb *tcp)
 {
+       if (ptrace_syscall_info_is_valid() && get_regs(tcp) < 0)
+               return -1;
        return ia64_regs.gr[9];
 }
index 332f2706afca06a3030bf04fc3cc74ced7e4df72..fd73a79cc4f03d1f81db47e42c7e740892d3b6ba 100644 (file)
@@ -1,5 +1,7 @@
 long
 getrval2(struct tcb *tcp)
 {
+       if (ptrace_syscall_info_is_valid() && get_regs(tcp) < 0)
+               return -1;
        return mips_regs.uregs[3];
 }
diff --git a/linux/powerpc64/arch_get_personality.c b/linux/powerpc64/arch_get_personality.c
new file mode 100644 (file)
index 0000000..9817d44
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef AUDIT_ARCH_PPC
+# define AUDIT_ARCH_PPC 0x14
+#endif
+
+int
+get_personality_from_syscall_info(const struct ptrace_syscall_info *sci)
+{
+       return sci->arch == AUDIT_ARCH_PPC;
+}
diff --git a/linux/riscv/arch_get_personality.c b/linux/riscv/arch_get_personality.c
new file mode 100644 (file)
index 0000000..78cf432
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef AUDIT_ARCH_RISCV32
+# define AUDIT_ARCH_RISCV32 0x400000f3
+#endif
+
+int
+get_personality_from_syscall_info(const struct ptrace_syscall_info *sci)
+{
+       return sci->arch == AUDIT_ARCH_RISCV32;
+}
diff --git a/linux/s390x/arch_get_personality.c b/linux/s390x/arch_get_personality.c
new file mode 100644 (file)
index 0000000..8b12132
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef AUDIT_ARCH_S390
+# define AUDIT_ARCH_S390 0x16
+#endif
+
+int
+get_personality_from_syscall_info(const struct ptrace_syscall_info *sci)
+{
+       return sci->arch == AUDIT_ARCH_S390;
+}
index 9079482c6017a06a2316b27ee8d8f83c300d9461..f8783533841f72c8e9d7877a248efc8aea2afd71 100644 (file)
@@ -1,5 +1,7 @@
 long
 getrval2(struct tcb *tcp)
 {
+       if (ptrace_syscall_info_is_valid() && get_regs(tcp) < 0)
+               return -1;
        return sparc_regs.u_regs[U_REG_O1];
 }
diff --git a/linux/sparc64/arch_get_personality.c b/linux/sparc64/arch_get_personality.c
new file mode 100644 (file)
index 0000000..36d1191
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef AUDIT_ARCH_SPARC
+# define AUDIT_ARCH_SPARC 0x2
+#endif
+
+int
+get_personality_from_syscall_info(const struct ptrace_syscall_info *sci)
+{
+       return sci->arch == AUDIT_ARCH_SPARC;
+}
diff --git a/linux/tile/arch_get_personality.c b/linux/tile/arch_get_personality.c
new file mode 100644 (file)
index 0000000..0a88242
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef AUDIT_ARCH_TILEGX32
+# define AUDIT_ARCH_TILEGX32 0x400000bf
+#endif
+#ifndef AUDIT_ARCH_TILEPRO
+# define AUDIT_ARCH_TILEPRO 0x400000bc
+#endif
+
+int
+get_personality_from_syscall_info(const struct ptrace_syscall_info *sci)
+{
+       return sci->arch == AUDIT_ARCH_TILEGX32 ||
+              sci->arch == AUDIT_ARCH_TILEPRO;
+}
diff --git a/linux/x32/arch_get_personality.c b/linux/x32/arch_get_personality.c
new file mode 100644 (file)
index 0000000..a8ede47
--- /dev/null
@@ -0,0 +1 @@
+#include "x86_64/arch_get_personality.c"
diff --git a/linux/x32/check_scno.c b/linux/x32/check_scno.c
new file mode 100644 (file)
index 0000000..4238701
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2010-2018 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+/* Return codes: 1 - ok, 0 - ignore, other - error. */
+static int
+arch_check_scno(struct tcb *tcp)
+{
+
+       const kernel_ulong_t scno = ptrace_sci.entry.nr;
+
+       if (tcp->currpers == 0 && !(scno & __X32_SYSCALL_BIT)) {
+               error_msg("syscall_%" PRI_klu "(...) in unsupported "
+                         "64-bit mode of process PID=%d", scno, tcp->pid);
+               return 0;
+       }
+
+       return 1;
+}
diff --git a/linux/x86_64/arch_get_personality.c b/linux/x86_64/arch_get_personality.c
new file mode 100644 (file)
index 0000000..fc313a8
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010-2018 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef AUDIT_ARCH_I386
+# define AUDIT_ARCH_I386 0x40000003
+#endif
+
+int
+get_personality_from_syscall_info(const struct ptrace_syscall_info *sci)
+{
+       unsigned int pers = sci->arch == AUDIT_ARCH_I386;
+
+#ifndef X32
+       switch(sci->op) {
+               case PTRACE_SYSCALL_INFO_ENTRY:
+               case PTRACE_SYSCALL_INFO_SECCOMP:
+                       break;
+               default:
+                       return -1;
+       }
+
+       kernel_ulong_t scno = sci->entry.nr;
+
+#ifndef __X32_SYSCALL_BIT
+# define __X32_SYSCALL_BIT     0x40000000
+#endif
+
+       if (pers == 0 && (scno & __X32_SYSCALL_BIT)) {
+               /*
+                * Syscall number -1 requires special treatment:
+                * it might be a side effect of SECCOMP_RET_ERRNO
+                * filtering that sets orig_rax to -1
+                * in some versions of linux kernel.
+                * If that is the case, then
+                * __X32_SYSCALL_BIT logic does not apply.
+                */
+               if (scno != (kernel_ulong_t) -1)
+                       pers = 2;
+       }
+#endif /* !X32 */
+
+       return pers;
+}
index dfddde7b74b7090f28e17d28d07c4e53bc933110..a4e3ea54c088c32e367e81f3b4691b0936a50333 100644 (file)
--- a/syscall.c
+++ b/syscall.c
  */
 
 #include "defs.h"
+#include "get_personality.h"
 #include "mmap_notify.h"
 #include "native_defs.h"
 #include "ptrace.h"
+#include "ptrace_syscall_info.h"
 #include "nsig.h"
 #include "number_set.h"
 #include "delay.h"
@@ -461,6 +463,7 @@ static void get_error(struct tcb *, bool);
 static void set_error(struct tcb *, unsigned long);
 static void set_success(struct tcb *, kernel_long_t);
 static int arch_get_scno(struct tcb *);
+static int arch_check_scno(struct tcb *);
 static int arch_set_scno(struct tcb *, kernel_ulong_t);
 static int arch_get_syscall_args(struct tcb *);
 static void arch_get_error(struct tcb *, bool);
@@ -943,11 +946,21 @@ restore_cleared_syserror(struct tcb *tcp)
        tcp->u_error = saved_u_error;
 }
 
+static struct ptrace_syscall_info ptrace_sci;
+
+static bool
+ptrace_syscall_info_is_valid(void)
+{
+       return ptrace_get_syscall_info_supported &&
+              ptrace_sci.op <= PTRACE_SYSCALL_INFO_SECCOMP;
+}
+
 #define XLAT_MACROS_ONLY
 # include "xlat/nt_descriptor_types.h"
 #undef XLAT_MACROS_ONLY
 
 #define ARCH_MIGHT_USE_SET_REGS 1
+
 #include "arch_regs.c"
 
 #if HAVE_ARCH_GETRVAL2
@@ -1035,16 +1048,13 @@ ptrace_setregs(pid_t pid)
 
 #endif /* ARCH_REGS_FOR_GETREGSET || ARCH_REGS_FOR_GETREGS */
 
-#ifdef ptrace_getregset_or_getregs
-static long get_regs_error;
-#endif
+static long get_regs_error = -1;
 
 void
 clear_regs(struct tcb *tcp)
 {
-#ifdef ptrace_getregset_or_getregs
+       ptrace_sci.op = 0xff;
        get_regs_error = -1;
-#endif
 }
 
 static long
@@ -1139,9 +1149,59 @@ free_sysent_buf(void *ptr)
        free(ptr);
 }
 
+static bool
+ptrace_get_syscall_info(struct tcb *tcp)
+{
+       /*
+        * ptrace_get_syscall_info_supported should have been checked
+        * by the caller.
+        */
+       if (ptrace_sci.op == 0xff) {
+               const size_t size = sizeof(ptrace_sci);
+               if (ptrace(PTRACE_GET_SYSCALL_INFO, tcp->pid,
+                          (void *) size, &ptrace_sci) < 0) {
+                       get_regs_error = -2;
+                       return false;
+               }
+#if SUPPORTED_PERSONALITIES > 1
+               int newpers = get_personality_from_syscall_info(&ptrace_sci);
+               if (newpers >= 0)
+                       update_personality(tcp, newpers);
+#endif
+       }
+
+       if (entering(tcp)) {
+               if (ptrace_sci.op == PTRACE_SYSCALL_INFO_EXIT) {
+                       error_msg("pid %d: entering"
+                                 ", ptrace_syscall_info.op == %u",
+                                 tcp->pid, ptrace_sci.op);
+                       /* TODO: handle this.  */
+               }
+       } else {
+               if (ptrace_sci.op == PTRACE_SYSCALL_INFO_ENTRY) {
+                       error_msg("pid %d: exiting"
+                                 ", ptrace_syscall_info.op == %u",
+                                 tcp->pid, ptrace_sci.op);
+                       /* TODO: handle this.  */
+               }
+       }
+
+       return true;
+}
+
 bool
 get_instruction_pointer(struct tcb *tcp, kernel_ulong_t *ip)
 {
+       if (get_regs_error < -1)
+               return false;
+
+       if (ptrace_get_syscall_info_supported) {
+               if (!ptrace_get_syscall_info(tcp))
+                       return false;
+               *ip = (kernel_ulong_t) ptrace_sci.instruction_pointer;
+               return true;
+       }
+
 #if defined ARCH_PC_REG
        if (get_regs(tcp) < 0)
                return false;
@@ -1159,6 +1219,16 @@ get_instruction_pointer(struct tcb *tcp, kernel_ulong_t *ip)
 bool
 get_stack_pointer(struct tcb *tcp, kernel_ulong_t *sp)
 {
+       if (get_regs_error < -1)
+               return false;
+
+       if (ptrace_get_syscall_info_supported) {
+               if (!ptrace_get_syscall_info(tcp))
+                       return false;
+               *sp = (kernel_ulong_t) ptrace_sci.stack_pointer;
+               return true;
+       }
+
 #if defined ARCH_SP_REG
        if (get_regs(tcp) < 0)
                return false;
@@ -1173,6 +1243,18 @@ get_stack_pointer(struct tcb *tcp, kernel_ulong_t *sp)
 #endif
 }
 
+static int
+get_syscall_regs(struct tcb *tcp)
+{
+       if (get_regs_error != -1)
+               return get_regs_error;
+
+       if (ptrace_get_syscall_info_supported)
+               return ptrace_get_syscall_info(tcp) ? 0 : get_regs_error;
+
+       return get_regs(tcp);
+}
+
 /*
  * Returns:
  * 0: "ignore this ptrace stop", syscall_entering_decode() should return a "bail
@@ -1184,12 +1266,23 @@ get_stack_pointer(struct tcb *tcp, kernel_ulong_t *sp)
 int
 get_scno(struct tcb *tcp)
 {
-       if (get_regs(tcp) < 0)
+       if (get_syscall_regs(tcp) < 0)
                return -1;
 
-       int rc = arch_get_scno(tcp);
-       if (rc != 1)
-               return rc;
+       if (ptrace_syscall_info_is_valid()) {
+               /*
+                * So far it's just a workaround for x32,
+                * but let's pretend it could be used elsewhere.
+                */
+               int rc = arch_check_scno(tcp);
+               if (rc != 1)
+                       return rc;
+               tcp->scno = ptrace_sci.entry.nr;
+       } else {
+               int rc = arch_get_scno(tcp);
+               if (rc != 1)
+                       return rc;
+       }
 
        tcp->scno = shuffle_scno(tcp->scno);
 
@@ -1229,11 +1322,22 @@ get_scno(struct tcb *tcp)
 static int
 get_syscall_args(struct tcb *tcp)
 {
+       if (ptrace_syscall_info_is_valid()) {
+               for (unsigned int i = 0; i < ARRAY_SIZE(tcp->u_arg); ++i)
+                       tcp->u_arg[i] = ptrace_sci.entry.args[i];
+#if SUPPORTED_PERSONALITIES > 1
+               if (tcp->s_ent->sys_flags & COMPAT_SYSCALL_TYPES) {
+                       for (unsigned int i = 0; i < ARRAY_SIZE(tcp->u_arg); ++i)
+                               tcp->u_arg[i] = (uint32_t) tcp->u_arg[i];
+               }
+#endif
+               return 1;
+       }
        return arch_get_syscall_args(tcp);
 }
 
 #ifdef ptrace_getregset_or_getregs
-# define get_syscall_result_regs get_regs
+# define get_syscall_result_regs get_syscall_regs
 #else
 static int get_syscall_result_regs(struct tcb *);
 #endif
@@ -1259,8 +1363,18 @@ get_syscall_result(struct tcb *tcp)
 static void
 get_error(struct tcb *tcp, const bool check_errno)
 {
-       tcp->u_error = 0;
-       arch_get_error(tcp, check_errno);
+       if (ptrace_syscall_info_is_valid()) {
+               if (ptrace_sci.exit.is_error) {
+                       tcp->u_rval = -1;
+                       tcp->u_error = -ptrace_sci.exit.rval;
+               } else {
+                       tcp->u_error = 0;
+                       tcp->u_rval = ptrace_sci.exit.rval;
+               }
+       } else {
+               tcp->u_error = 0;
+               arch_get_error(tcp, check_errno);
+       }
 }
 
 static void
@@ -1271,12 +1385,22 @@ set_error(struct tcb *tcp, unsigned long new_error)
        if (new_error == old_error || new_error > MAX_ERRNO_VALUE)
                return;
 
+#ifdef ptrace_setregset_or_setregs
+       /* if we are going to invoke set_regs, call get_regs first */
+       if (get_regs(tcp) < 0)
+               return;
+#endif
+
        tcp->u_error = new_error;
        if (arch_set_error(tcp)) {
                tcp->u_error = old_error;
                /* arch_set_error does not update u_rval */
        } else {
-               get_error(tcp, !(tcp->s_ent->sys_flags & SYSCALL_NEVER_FAILS));
+               if (ptrace_syscall_info_is_valid())
+                       tcp->u_rval = -1;
+               else
+                       get_error(tcp, !(tcp->s_ent->sys_flags &
+                                        SYSCALL_NEVER_FAILS));
        }
 }
 
@@ -1285,16 +1409,27 @@ set_success(struct tcb *tcp, kernel_long_t new_rval)
 {
        const kernel_long_t old_rval = tcp->u_rval;
 
+#ifdef ptrace_setregset_or_setregs
+       /* if we are going to invoke set_regs, call get_regs first */
+       if (get_regs(tcp) < 0)
+               return;
+#endif
+
        tcp->u_rval = new_rval;
        if (arch_set_success(tcp)) {
                tcp->u_rval = old_rval;
-               /* arch_set_error does not update u_error */
+               /* arch_set_success does not update u_error */
        } else {
-               get_error(tcp, !(tcp->s_ent->sys_flags & SYSCALL_NEVER_FAILS));
+               if (ptrace_syscall_info_is_valid())
+                       tcp->u_error = 0;
+               else
+                       get_error(tcp, !(tcp->s_ent->sys_flags &
+                                        SYSCALL_NEVER_FAILS));
        }
 }
 
 #include "get_scno.c"
+#include "check_scno.c"
 #include "set_scno.c"
 #include "get_syscall_args.c"
 #ifndef ptrace_getregset_or_getregs
index b784f21a487a35dc66e16d3314dc9b7a8393291c..1f0e5a9c2e1a13605a4d78e49cf6e7219a06a2ba 100644 (file)
@@ -228,6 +228,7 @@ DECODER_TESTS = \
        fadvise64.test \
        futex.test \
        getuid.test \
+       int_0x80.test \
        ioctl.test \
        ioctl_evdev-success.test \
        ioctl_evdev-success-v.test \
@@ -347,8 +348,6 @@ TESTS = $(GEN_TESTS) $(DECODER_TESTS) $(MISC_TESTS) $(STACKTRACE_TESTS)
 XFAIL_TESTS_ =
 XFAIL_TESTS_m32 = $(STACKTRACE_TESTS)
 XFAIL_TESTS_mx32 = $(STACKTRACE_TESTS)
-XFAIL_TESTS_x86_64 = int_0x80.gen.test
-XFAIL_TESTS_x32 = int_0x80.gen.test
 XFAIL_TESTS = $(XFAIL_TESTS_$(MPERS_NAME)) $(XFAIL_TESTS_$(ARCH))
 
 TEST_LOG_COMPILER = env
index b77a36af1ee0927e9d52150219932fc6fe683571..31a06274f4b2936433c06c93c77b33c66a7f584f 100644 (file)
@@ -118,7 +118,6 @@ inet-cmsg   -e trace=recvmsg
 init_module    -a27
 inotify        -a23 -e trace=inotify_add_watch,inotify_rm_watch
 inotify_init1  -a27
-int_0x80       -a11 -e trace=getgid32
 ioctl_block    +ioctl.test
 ioctl_dm       +ioctl.test -s9
 ioctl_dm-v     +ioctl.test -v -s9
diff --git a/tests/int_0x80.test b/tests/int_0x80.test
new file mode 100755 (executable)
index 0000000..1188d98
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+#
+# Check decoding of int 0x80 on x86_64, x32, and x86.
+
+. "${srcdir=.}/init.sh"
+
+$STRACE -d -enone / > /dev/null 2> "$LOG"
+grep -x "[^:]*strace: PTRACE_GET_SYSCALL_INFO works" "$LOG" > /dev/null ||
+       skip_ 'PTRACE_GET_SYSCALL_INFO does not work'
+
+run_strace_match_diff -a11 -e trace=getgid32