Fix is_negated_errno() check for X32
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>
diff --git a/syscall.c b/syscall.c
index f403c44..c4e1993 100644
--- a/syscall.c
+++ b/syscall.c
@@ -1946,6 +1946,24 @@
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 @@
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) {