]> granicus.if.org Git - strace/commitdiff
Fix is_negated_errno() check for X32
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 12 Feb 2013 10:52:35 +0000 (11:52 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 12 Feb 2013 10:52:35 +0000 (11:52 +0100)
X32's return value is 64-bit. We were truncating it to 32-bit long
before checking for -errno.

* syscall.c (is_negated_errno_x32): New function.
(get_error): Use is_negated_errno_x32 for X32 architecture.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
syscall.c

index f403c44187af6f48969f3fb3bd2f56153992a08a..c4e19932644742a8948eb120804e4d8c1163b144 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -1946,6 +1946,24 @@ is_negated_errno(unsigned long int val)
        return val > max;
 }
 
+#if defined(X32)
+static inline int
+is_negated_errno_x32(unsigned long long val)
+{
+       unsigned long long max = -(long long) nerrnos;
+       /*
+        * current_wordsize is 4 even in personality 0 (native X32)
+        * but truncation _must not_ be done in it.
+        * can't check current_wordsize here!
+        */
+       if (current_personality != 0) {
+               val = (uint32_t) val;
+               max = (uint32_t) max;
+       }
+       return val > max;
+}
+#endif
+
 /* Returns:
  * 1: ok, continue in trace_syscall_exiting().
  * -1: error, trace_syscall_exiting() should print error indicator
@@ -1976,16 +1994,23 @@ get_error(struct tcb *tcp)
        else {
                tcp->u_rval = i386_regs.eax;
        }
-#elif defined(X86_64) || defined(X32)
+#elif defined(X86_64)
        if (check_errno && is_negated_errno(x86_64_regs.rax)) {
                tcp->u_rval = -1;
                u_error = -x86_64_regs.rax;
        }
        else {
                tcp->u_rval = x86_64_regs.rax;
-# if defined(X32)
+       }
+#elif defined(X32)
+       /* Careful: is_negated_errno() works only on longs */
+       if (check_errno && is_negated_errno_x32(x86_64_regs.rax)) {
+               tcp->u_rval = -1;
+               u_error = -x86_64_regs.rax;
+       }
+       else {
+               tcp->u_rval = x86_64_regs.rax; /* truncating */
                tcp->u_lrval = x86_64_regs.rax;
-# endif
        }
 #elif defined(IA64)
        if (ia32) {