Search code examples
linuxdebuggingsystem-callsptrace

how to get correct orig_eax value when stopped in syscall?


I'm attaching to a process with ptrace(PTRACE_ATTACH...) while it is in a syscall (like nanosleep()). I can use PTRACE_GETREGS to get the register contents, and eip is at expected location (in __kernel_vsyscall). However, eax and orig_eax registers have unexpected contents: eax usually contains -516, and orig_eax is usually 0.

This is the test program I used (taken from http://www.linuxjournal.com/article/6210 and slightly modified):

    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/ptrace.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <sys/user.h>

    int main(int argc, char *argv[])
    {
        pid_t traced_process;
        struct user_regs_struct regs;
        long ins;
        if(argc != 2) {
            printf("Usage: %s <pid to be traced>\n",
                   argv[0]);
            exit(1);
        }
        traced_process = atoi(argv[1]);
        ptrace(PTRACE_ATTACH, traced_process,
               NULL, NULL);
        wait(NULL);
        ptrace(PTRACE_GETREGS, traced_process,
               NULL, &regs);
        printf("eax: %lx (%d); orig_eax: %lx\n",
               regs.eax, (int)regs.eax, regs.orig_eax);
        ins = ptrace(PTRACE_PEEKTEXT, traced_process,
                     regs.eip, NULL);
        printf("EIP: %lx Instruction executed: %lx\n",
               regs.eip, ins);
        ptrace(PTRACE_DETACH, traced_process,
               NULL, NULL);
        return 0;
    }

Output when attaching to a "sleep 10000" command running in another terminal:

    eax: fffffdfc (-516); orig_eax: 0
    EIP: b7711424 Instruction executed: c3595a5d

What does the value in eax mean? Why doesn't orig_eax contain the original syscall number (like 162)? And how do I actually get the system call number in this case?

Also, why does gdb correctly shows "162" for "print $orig_eax"?

Btw. this is on Ubuntu 12.04, with kernel 3.2.0:

  • uname -a: "Linux edgebox 3.2.0-24-generic-pae #37-Ubuntu SMP Wed Apr 25 10:47:59 UTC 2012 i686 athlon i386 GNU/Linux"
  • /proc/cpuinfo: "AMD Athlon(tm) II Neo K345 Dual-Core Processor"
  • file which sleep: "/bin/sleep: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x0965431bde4d183eaa2fa3e3989098ce46b92129, stripped".

So it's a 32-bit PAE kernel and 32-bit Ubuntu installation on 64-bit CPU.


Solution

  • This is on Ubuntu 12.04, with kernel 3.2.0

    This doesn't uniquely identify your system. What processor?

    My crystal ball tells me that sleep you are invoking is a 64-bit program, while your tracer program is not. Or vice versa.