]> granicus.if.org Git - strace/commitdiff
x86-64: enhance PTRACE_GETREGSET test
authorDmitry V. Levin <ldv@altlinux.org>
Sun, 17 Mar 2013 23:18:35 +0000 (23:18 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Mon, 18 Mar 2013 11:46:36 +0000 (11:46 +0000)
* syscall.c (get_regs) [X86_64]: Check whether PTRACE_GETREGSET
works regardless of the kernel version.

syscall.c

index 4d72f42b36a91d5753a68dd4d584125bbbd88274..42aad40add514acb8d0f63e8cb5b21873562f77c 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -1011,42 +1011,51 @@ get_regs(pid_t pid)
        get_regs_error = ptrace(PTRACE_GETREGSET, pid,
                                NT_PRSTATUS, (long) &x86_io);
 # elif defined(X86_64)
-       /*
-        * PTRACE_GETREGSET was introduced in 2.6.33.
-        * Let's be paranoid and require a bit later kernel.
-        */
-       if (os_release >= KERNEL_VERSION(2,6,35)) {
-               /*x86_io.iov_base = &x86_regs_union; - already is */
+#  if defined(PTRACE_GETREGSET) && defined(NT_PRSTATUS)
+       static int getregset_support;
+
+       if (getregset_support >= 0) {
+               /* x86_io.iov_base = &x86_regs_union; - already is */
                x86_io.iov_len = sizeof(x86_regs_union);
-               get_regs_error = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, (long) &x86_io);
-       } else {
-               /* Use old method, with heuristical detection of 32-bitness */
-               x86_io.iov_len = sizeof(x86_64_regs);
-               get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, (long) &x86_64_regs);
-               if (!get_regs_error && x86_64_regs.cs == 0x23) {
-                       x86_io.iov_len = sizeof(i386_regs);
-                       /*
-                        * The order is important: i386_regs and x86_64_regs
-                        * are overlaid in memory!
-                        */
-                       i386_regs.ebx = x86_64_regs.rbx;
-                       i386_regs.ecx = x86_64_regs.rcx;
-                       i386_regs.edx = x86_64_regs.rdx;
-                       i386_regs.esi = x86_64_regs.rsi;
-                       i386_regs.edi = x86_64_regs.rdi;
-                       i386_regs.ebp = x86_64_regs.rbp;
-                       i386_regs.eax = x86_64_regs.rax;
-                       /*i386_regs.xds = x86_64_regs.ds; unused by strace */
-                       /*i386_regs.xes = x86_64_regs.es; ditto... */
-                       /*i386_regs.xfs = x86_64_regs.fs;*/
-                       /*i386_regs.xgs = x86_64_regs.gs;*/
-                       i386_regs.orig_eax = x86_64_regs.orig_rax;
-                       i386_regs.eip = x86_64_regs.rip;
-                       /*i386_regs.xcs = x86_64_regs.cs;*/
-                       /*i386_regs.eflags = x86_64_regs.eflags;*/
-                       i386_regs.esp = x86_64_regs.rsp;
-                       /*i386_regs.xss = x86_64_regs.ss;*/
+               get_regs_error = ptrace(PTRACE_GETREGSET, pid,
+                                       NT_PRSTATUS, (long) &x86_io);
+               if (getregset_support > 0)
+                       return;
+               if (get_regs_error >= 0) {
+                       getregset_support = 1;
+                       return;
                }
+               if (errno == EPERM || errno == ESRCH)
+                       return;
+               getregset_support = -1;
+       }
+#  endif /* PTRACE_GETREGSET && NT_PRSTATUS */
+       /* Use old method, with unreliable heuristical detection of 32-bitness. */
+       x86_io.iov_len = sizeof(x86_64_regs);
+       get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, (long) &x86_64_regs);
+       if (!get_regs_error && x86_64_regs.cs == 0x23) {
+               x86_io.iov_len = sizeof(i386_regs);
+               /*
+                * The order is important: i386_regs and x86_64_regs
+                * are overlaid in memory!
+                */
+               i386_regs.ebx = x86_64_regs.rbx;
+               i386_regs.ecx = x86_64_regs.rcx;
+               i386_regs.edx = x86_64_regs.rdx;
+               i386_regs.esi = x86_64_regs.rsi;
+               i386_regs.edi = x86_64_regs.rdi;
+               i386_regs.ebp = x86_64_regs.rbp;
+               i386_regs.eax = x86_64_regs.rax;
+               /* i386_regs.xds = x86_64_regs.ds; unused by strace */
+               /* i386_regs.xes = x86_64_regs.es; ditto... */
+               /* i386_regs.xfs = x86_64_regs.fs; */
+               /* i386_regs.xgs = x86_64_regs.gs; */
+               i386_regs.orig_eax = x86_64_regs.orig_rax;
+               i386_regs.eip = x86_64_regs.rip;
+               /* i386_regs.xcs = x86_64_regs.cs; */
+               /* i386_regs.eflags = x86_64_regs.eflags; */
+               i386_regs.esp = x86_64_regs.rsp;
+               /* i386_regs.xss = x86_64_regs.ss; */
        }
 # elif defined(ARM)
        get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, (void *)&arm_regs);