]> granicus.if.org Git - strace/commitdiff
x86: zero-extend 32-bit args in syscall entry instead of sign-extension
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 15 Feb 2013 14:01:38 +0000 (15:01 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Fri, 15 Feb 2013 14:01:38 +0000 (15:01 +0100)
Zero-extension is slightly more common that sign-extension:
all pointers are zero-extended, and some other params are unsigned.

Whereas signed ones (fds, pids, etc) are often treated as
_32-bit ints_ even by kernel, so just unconditionally casting
such tcp->u_arg[N] to int works.

* syscall.c (get_syscall_args): [X86] Zero-extend 32-bit args
instead of sign-extension.

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

index 7ed0bdcdb98c5377ea1744e70571fdbbbf90c346..448f37d631fe8b120172e1752167f9431fe3816a 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -1768,6 +1768,15 @@ get_syscall_args(struct tcb *tcp)
        for (i = 0; i < nargs; ++i)
                if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
                        return -1;
+#elif defined(I386)
+       (void)i;
+       (void)nargs;
+       tcp->u_arg[0] = i386_regs.ebx;
+       tcp->u_arg[1] = i386_regs.ecx;
+       tcp->u_arg[2] = i386_regs.edx;
+       tcp->u_arg[3] = i386_regs.esi;
+       tcp->u_arg[4] = i386_regs.edi;
+       tcp->u_arg[5] = i386_regs.ebp;
 #elif defined(X86_64) || defined(X32)
        (void)i;
        (void)nargs;
@@ -1789,13 +1798,16 @@ get_syscall_args(struct tcb *tcp)
 #  endif
        } else {
                /* i386 ABI */
-               /* Sign-extend from 32 bits */
-               tcp->u_arg[0] = (long)(int32_t)i386_regs.ebx;
-               tcp->u_arg[1] = (long)(int32_t)i386_regs.ecx;
-               tcp->u_arg[2] = (long)(int32_t)i386_regs.edx;
-               tcp->u_arg[3] = (long)(int32_t)i386_regs.esi;
-               tcp->u_arg[4] = (long)(int32_t)i386_regs.edi;
-               tcp->u_arg[5] = (long)(int32_t)i386_regs.ebp;
+               /* Zero-extend from 32 bits */
+               /* Use widen_to_long(tcp->u_arg[N]) in syscall handlers
+                * if you need to use *sign-extended* parameter.
+                */
+               tcp->u_arg[0] = (long)(uint32_t)i386_regs.ebx;
+               tcp->u_arg[1] = (long)(uint32_t)i386_regs.ecx;
+               tcp->u_arg[2] = (long)(uint32_t)i386_regs.edx;
+               tcp->u_arg[3] = (long)(uint32_t)i386_regs.esi;
+               tcp->u_arg[4] = (long)(uint32_t)i386_regs.edi;
+               tcp->u_arg[5] = (long)(uint32_t)i386_regs.ebp;
        }
 #elif defined(MICROBLAZE)
        for (i = 0; i < nargs; ++i)
@@ -1817,15 +1829,6 @@ get_syscall_args(struct tcb *tcp)
        for (i = 0; i < nargs; ++i)
                if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
                        return -1;
-#elif defined(I386)
-       (void)i;
-       (void)nargs;
-       tcp->u_arg[0] = i386_regs.ebx;
-       tcp->u_arg[1] = i386_regs.ecx;
-       tcp->u_arg[2] = i386_regs.edx;
-       tcp->u_arg[3] = i386_regs.esi;
-       tcp->u_arg[4] = i386_regs.edi;
-       tcp->u_arg[5] = i386_regs.ebp;
 #elif defined(OR1K)
        (void)nargs;
        for (i = 0; i < 6; ++i)