On Fri, 2011-08-26 at 14:27 +0400, Dmitry V. Levin wrote:
> > > > +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;
> > > 
> > > I suppose we shouldn't hurry with this.  There is a <asm/ptrace.h> where
> > > all this stuff is defined and supported for all linux architectures.
> > > So I think migrating from <sys/ptrace.h> to <linux/ptrace.h> is the right
> > > way to go.
> > 
> > Something tells me that we _will_ get bitten by header include problems
> > if we start including more asm/* and linux/* stuff. Every now and again
> > as new kernels are released there are breakage in their headers.
> > Typically easily fixable, yes, but still, it's a PITA.
> 
> Yes, this is a risk of using linux/* headers.
> 
> > Defining a correct structure ourselves has no such problems.
> 
> Yes, but we will have to do it for each linux arch.
> 
> > It's not like this structure is going to ever change.
> 
> We already do not quite rely upon sys/ptrace.h (see e.g. those multitple
> PTRACE_* definitions in defs.h).  If we have to avoid linux/ptrace.h as well,
> we might end up with homegrown ptrace.h-like files.


This version which uses asm/ptrace.h and its struct pt_regs.

Also, I decided to bite the bullet and convert x86-64 too.
Especially that on it we also get rid of extra CS read!

Not yet tested on x86-64.

Let me know whether this patch is good enough for git.

-- 
vda


diff -d -urpN strace.6/defs.h strace.7/defs.h
--- strace.6/defs.h     2011-08-26 18:32:46.578974479 +0200
+++ strace.7/defs.h     2011-08-26 18:33:32.901195713 +0200
@@ -193,6 +193,12 @@ extern int ptrace(int, int, char *, int,
 #define        PTRACE_PEEKUSER PTRACE_PEEKUSR
 #define        PTRACE_POKEUSER PTRACE_POKEUSR
 #endif
+#if defined(X86_64) || defined(I386)
+/* For struct pt_regs. x86 strace uses PTRACE_GETREGS.
+ * PTRACE_GETREGS returns regs in the layout of this struct.
+ */
+#  include <asm/ptrace.h>
+#endif
 #ifdef ALPHA
 #  define REG_R0 0
 #  define REG_A0 16
diff -d -urpN strace.6/syscall.c strace.7/syscall.c
--- strace.6/syscall.c  2011-08-25 10:39:36.000000000 +0200
+++ strace.7/syscall.c  2011-08-26 18:36:12.908950236 +0200
@@ -716,7 +716,9 @@ struct tcb *tcp_last = NULL;
 
 #ifdef LINUX
 # if defined (I386)
-static long eax;
+static struct pt_regs i386_regs;
+# elif defined(X86_64)
+static struct pt_regs x86_64_regs;
 # elif defined (IA64)
 long r8, r10, psr; /* TODO: make static? */
 long ia32 = 0; /* not static */
@@ -752,8 +754,6 @@ static long r28;
 static long r0;
 # elif defined(SH64)
 static long r9;
-# elif defined(X86_64)
-static long rax;
 # elif defined(CRISV10) || defined(CRISV32)
 static long r10;
 # elif defined(MICROBLAZE)
@@ -895,34 +895,26 @@ 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;
-
-       /* TODO: speed up strace by not doing this at every syscall.
-        * We only need to do it after execve.
-        */
        int currpers;
-       long val;
-       int pid = tcp->pid;
+       if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
+               return -1;
+       scno = x86_64_regs.orig_rax;
 
        /* Check CS register value. On x86-64 linux it is:
         *      0x33    for long mode (64 bit)
         *      0x23    for compatibility mode (32 bit)
-        * It takes only one ptrace and thus doesn't need
-        * to be cached.
         */
-       if (upeek(tcp, 8*CS, &val) < 0)
-               return -1;
-       switch (val) {
+       switch (x86_64_regs.xcs) {
                case 0x23: currpers = 1; break;
                case 0x33: currpers = 0; break;
                default:
-                       fprintf(stderr, "Unknown value CS=0x%02X while "
+                       fprintf(stderr, "Unknown value CS=0x%08X while "
                                 "detecting personality of process "
-                                "PID=%d\n", (int)val, pid);
+                                "PID=%d\n", (int)x86_64_regs.xcs, tcp->pid);
                        currpers = current_personality;
                        break;
        }
@@ -933,14 +925,13 @@ get_scno(struct tcb *tcp)
         */
        unsigned long val, rip, i;
 
-       if (upeek(tcp, 8*RIP, &rip) < 0)
-               perror("upeek(RIP)");
+       rip = x86_64_regs.rip;
 
        /* sizeof(syscall) == sizeof(int 0x80) == 2 */
        rip -= 2;
        errno = 0;
 
-       call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
+       call = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)rip, (char *)0);
        if (errno)
                fprintf(stderr, "ptrace_peektext failed: %s\n",
                                strerror(errno));
@@ -954,7 +945,7 @@ get_scno(struct tcb *tcp)
                        fprintf(stderr,
                                "Unknown syscall opcode (0x%04X) while "
                                "detecting personality of process "
-                               "PID=%d\n", (int)call, pid);
+                               "PID=%d\n", (int)call, tcp->pid);
                        break;
        }
 #  endif
@@ -969,7 +960,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,26 +1282,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)
-       /* With PTRACE_O_TRACEEXEC, post-execve SIGTRAP is disabled.
-        * Every extra ptrace call is expensive, so check EAX
-        * 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;
-               }
+       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)
-       if (!(ptrace_setoptions & PTRACE_O_TRACEEXEC)) {
-               if (upeek(tcp, 8*RAX, &rax) < 0)
-                       return -1;
+       {
+               long rax = x86_64_regs.rax;
                if (current_personality == 1)
-                       rax = (long int)(int)rax; /* sign extend from 32 bits */
-               if (rax != -ENOSYS && entering(tcp)) {
+                       rax = (int)rax; /* sign extend from 32 bits */
+               if (rax != -ENOSYS) {
                        if (debug)
                                fprintf(stderr, "not a syscall entry (rax = 
%ld)\n", rax);
                        return 0;
@@ -1521,6 +1503,7 @@ syscall_enter(struct tcb *tcp)
        for (i = 0; i < nargs; ++i)
                tcp->u_arg[i] = regs.uregs[i];
 # elif defined(AVR32)
+       /* TODO: make it faster by unrolling into 6 direct assignments */
        static const unsigned long *argregp[MAX_ARGS] = { &regs.r12,
                                                          &regs.r11,
                                                          &regs.r10,
@@ -1553,14 +1536,26 @@ syscall_enter(struct tcb *tcp)
                if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 
0)
                        return -1;
 # elif defined(X86_64)
-       static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
-               { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9  }, /* 
x86-64 ABI */
-               { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP }  /* 
i386 ABI */
-       };
-
-       for (i = 0; i < nargs; ++i)
-               if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) 
< 0)
-                       return -1;
+       (void)i;
+       (void)nargs;
+       if (current_personality == 0) { /* x86-64 ABI */
+               tcp->u_arg[0] = x86_64_regs.rdi;
+               tcp->u_arg[1] = x86_64_regs.rsi;
+               tcp->u_arg[2] = x86_64_regs.rdx;
+               tcp->u_arg[3] = x86_64_regs.r10;
+               tcp->u_arg[4] = x86_64_regs.r8;
+               tcp->u_arg[5] = x86_64_regs.r9;
+       } else { /* i386 ABI */
+               /* TODO: sign-extend lower 32 bit halves here,
+                * instead of doing it in every syscall handler?
+                */
+               tcp->u_arg[0] = x86_64_regs.rbx;
+               tcp->u_arg[1] = x86_64_regs.rcx;
+               tcp->u_arg[2] = x86_64_regs.rdx;
+               tcp->u_arg[3] = x86_64_regs.rsi;
+               tcp->u_arg[4] = x86_64_regs.rdi;
+               tcp->u_arg[5] = x86_64_regs.rbp;
+       }
 # elif defined(MICROBLAZE)
        for (i = 0; i < nargs; ++i)
                if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
@@ -1582,7 +1577,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,10 +1886,10 @@ 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)
+       if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
                return -1;
 # elif defined(IA64)
 #      define IA64_PSR_IS      ((long)1 << 34)
@@ -2053,20 +2057,20 @@ 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)) {
+       if (check_errno && is_negated_errno(x86_64_regs.rax)) {
                tcp->u_rval = -1;
-               u_error = -rax;
+               u_error = -x86_64_regs.rax;
        }
        else {
-               tcp->u_rval = rax;
+               tcp->u_rval = x86_64_regs.rax;
        }
 # elif defined(IA64)
        if (ia32) {


------------------------------------------------------------------------------
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