While discussing ptrace speedup, in one email Linus said
that it's stupid that strace doesn't even use already existing
speedups, such as PTRACE_GETREGS.

I decided to give it a try.
Stracing a strace running a strace running a strace running a static binary,
before patch:

$ time ./strace -s999 -o/dev/null ./strace -s999 -o/dev/null ./strace -s999 
-o/dev/null ./strace -s999 -o/dev/null ./strace ./true
execve("/bin/true", ["true"], [/* 51 vars */]) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 
{B38400 opost isig icanon echo ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 
{B38400 opost isig icanon echo ...}) = 0
getuid32()                              = 0
_exit(0)                                = ?
+++ exited with 0 +++

real    0m33.178s
user    0m6.753s
sys     0m28.798s


After the patch:

$ time ./strace -s999 -o/dev/null ./strace -s999 -o/dev/null ./strace -s999 
-o/dev/null ./strace -s999 -o/dev/null ./strace ./true
execve("/bin/true", ["true"], [/* 51 vars */]) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 
{B38400 opost isig icanon echo ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 
{B38400 opost isig icanon echo ...}) = 0
getuid32()                              = 0
_exit(0)                                = ?
+++ exited with 0 +++

real    0m14.608s
user    0m2.959s
sys     0m12.828s


Patch follows. Please review.

I guess we need to add a check on startup to make sure PTRACE_GETREGS works?

-- 
vda

diff -d -urpN strace.5/syscall.c strace.6/syscall.c
--- strace.5/syscall.c  2011-08-25 10:39:36.000000000 +0200
+++ strace.6/syscall.c  2011-08-25 11:51:32.148543603 +0200
@@ -716,7 +716,28 @@ struct tcb *tcp_last = NULL;
 
 #ifdef LINUX
 # if defined (I386)
-static long eax;
+struct i386_user_regs_struct {
+       long ebx;
+       long ecx;
+       long edx;
+       long esi;
+       long edi;
+       long ebp;
+       long eax;
+       long xds;
+       long xes;
+       long xfs;
+       long xgs;
+       long orig_eax;
+       long eip;
+       long xcs;
+       long eflags;
+       long esp;
+       long xss;
+       /* Just in case we forgot a few fields and kernel would write more... */
+       long paranoia[8];
+};
+static struct i386_user_regs_struct i386_regs;
 # elif defined (IA64)
 long r8, r10, psr; /* TODO: make static? */
 long ia32 = 0; /* not static */
@@ -895,8 +916,9 @@ get_scno(struct tcb *tcp)
        if (upeek(tcp, PT_ORIG_P0, &scno))
                return -1;
 # elif defined (I386)
-       if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
+       if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long)&i386_regs) < 0)
                return -1;
+       scno = i386_regs.orig_eax;
 # elif defined (X86_64)
        if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
                return -1;
@@ -969,7 +991,7 @@ get_scno(struct tcb *tcp)
        if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
                ia32 = (psr & IA64_PSR_IS) != 0;
        if (ia32) {
-               if (upeek(tcp, PT_R1, &scno) < 0)       /* orig eax */
+               if (upeek(tcp, PT_R1, &scno) < 0)
                        return -1;
        } else {
                if (upeek(tcp, PT_R15, &scno) < 0)
@@ -1291,21 +1313,17 @@ syscall_fixup_on_sysenter(struct tcb *tc
 #ifdef LINUX
        /* A common case of "not a syscall entry" is post-execve SIGTRAP */
 #if defined (I386)
+       if (i386_regs.eax != -ENOSYS) {
+               if (debug)
+                       fprintf(stderr, "not a syscall entry (eax = %ld)\n", 
i386_regs.eax);
+               return 0;
+       }
+#elif defined (X86_64)
        /* With PTRACE_O_TRACEEXEC, post-execve SIGTRAP is disabled.
-        * Every extra ptrace call is expensive, so check EAX
+        * Every extra ptrace call is expensive, so check RAX
         * on syscall entry only if PTRACE_O_TRACEEXEC is not enabled:
         */
        if (!(ptrace_setoptions & PTRACE_O_TRACEEXEC)) {
-               if (upeek(tcp, 4*EAX, &eax) < 0)
-                       return -1;
-               if (eax != -ENOSYS) {
-                       if (debug)
-                               fprintf(stderr, "not a syscall entry (eax = 
%ld)\n", eax);
-                       return 0;
-               }
-       }
-#elif defined (X86_64)
-       if (!(ptrace_setoptions & PTRACE_O_TRACEEXEC)) {
                if (upeek(tcp, 8*RAX, &rax) < 0)
                        return -1;
                if (current_personality == 1)
@@ -1582,7 +1600,16 @@ syscall_enter(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;
-# else /* Other architecture (like i386) (32bits specific) */
+# 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;
+# else /* Other architecture (32bits specific) */
        for (i = 0; i < nargs; ++i)
                if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
                        return -1;
@@ -1882,7 +1909,7 @@ get_syscall_result(struct tcb *tcp)
        if (upeek(tcp, PT_R0, &r0) < 0)
                return -1;
 # elif defined (I386)
-       if (upeek(tcp, 4*EAX, &eax) < 0)
+       if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long)&i386_regs) < 0)
                return -1;
 # elif defined (X86_64)
        if (upeek(tcp, 8*RAX, &rax) < 0)
@@ -2053,12 +2080,12 @@ get_error(struct tcb *tcp)
                tcp->u_rval = gpr2;
        }
 # elif defined(I386)
-       if (check_errno && is_negated_errno(eax)) {
+       if (check_errno && is_negated_errno(i386_regs.eax)) {
                tcp->u_rval = -1;
-               u_error = -eax;
+               u_error = -i386_regs.eax;
        }
        else {
-               tcp->u_rval = eax;
+               tcp->u_rval = i386_regs.eax;
        }
 # elif defined(X86_64)
        if (check_errno && is_negated_errno(rax)) {



------------------------------------------------------------------------------
EMC VNX: the world's simplest storage, starting under $10K
The only unified storage solution that offers unified management 
Up to 160% more powerful than alternatives and 25% more efficient. 
Guaranteed. http://p.sf.net/sfu/emc-vnx-dev2dev
_______________________________________________
Strace-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/strace-devel

Reply via email to