summaryrefslogtreecommitdiff
path: root/syscall.c
diff options
context:
space:
mode:
authorDmitry V. Levin <ldv@altlinux.org>2013-03-17 23:18:35 +0000
committerDmitry V. Levin <ldv@altlinux.org>2013-03-18 11:46:36 +0000
commit27e3ae973af5c70b469a1febe88f1c383fdd323e (patch)
treebf04c0dcf453fe6c3817e1a0f6481d0af271f5e8 /syscall.c
parentee348c60735e35730c3e95b89a4dd89bbcb4e7b5 (diff)
downloadstrace-27e3ae973af5c70b469a1febe88f1c383fdd323e.tar.gz
strace-27e3ae973af5c70b469a1febe88f1c383fdd323e.tar.bz2
strace-27e3ae973af5c70b469a1febe88f1c383fdd323e.tar.xz
x86-64: enhance PTRACE_GETREGSET test
* syscall.c (get_regs) [X86_64]: Check whether PTRACE_GETREGSET works regardless of the kernel version.
Diffstat (limited to 'syscall.c')
-rw-r--r--syscall.c77
1 files changed, 43 insertions, 34 deletions
diff --git a/syscall.c b/syscall.c
index 4d72f42..42aad40 100644
--- 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);