From: Denys Vlasenko Date: Tue, 12 Feb 2013 10:52:35 +0000 (+0100) Subject: Fix is_negated_errno() check for X32 X-Git-Tag: v4.8~176 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=afea7dd4a597e15e74ec3de5a78288056296311b;p=strace 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 --- diff --git a/syscall.c b/syscall.c index f403c441..c4e19932 100644 --- 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) {