9

According to the ptrace manual page:

Syscall-enter-stop and syscall-exit-stop are indistinguishable from each other by the tracer. The tracer needs to keep track of the sequence of ptrace-stops in order to not misinterpret syscall-enter- stop as syscall-exit-stop or vice versa.

When I attach to a process using PTRACE_ATTACH, how do I know whether the tracee is currently in a syscall or not? Put differently, if I restart the tracee using PTRACE_SYSCALL, how do I know whether the next syscall-stop is a syscall-enter-stop or a syscall-exit-stop?

melpomene
  • 84,125
  • 8
  • 85
  • 148
secretpow
  • 315
  • 2
  • 11
  • 1
    This is a good question. I've always assumed that the attachment wouldn't succeed while the traced process was in a syscall, but I don't have any proof to back up that assumption. – Daniel Pryden Aug 28 '18 at 11:51
  • 1
    I would imagine that the reporting of syscall entry/exit would only begin (after attaching) after the current syscall returns (and quite possibly interrupts it with EINTR if it is interruptible), so that you can always assume the first syscall-stop is an enter. Not verified myself, but would be easy to check. – davmac Aug 28 '18 at 11:58

3 Answers3

2

When the traced process stops on a system call ENTRY, the EAX register will contain -ENOSYS and orig_rax has the number of that system call.

Following code sample demonstrate an example.

if (registers.rax == -ENOSYS)
                { switch (registers.orig_rax)
                        {
                          case _NR_open: //Example
                          break;
                          default:
                    // to get the arguments

                        fprintf(stderr, "%#08x, %#08x, %#08x",
                                registers.rbx, registers.rcx, 
                                                registers.rdx);
                     break;
                     }
              }
              else
              {
                if (registers.rax < 0)
                {
                        // error condition
                        fprintf(stderr, "#Err: %s\n", 
                 errors[abs(registers.rax)]);
                }
                else
                {
                        // return code
                        fprintf(stderr, "%#08x\n", registers.rax);
                }
        }
Faizan Sh
  • 96
  • 1
  • 13
0

When I attach to a process using PTRACE_ATTACH, how do I know whether the tracee is currently in a syscall or not?

When you attach to a process using PTRACE_ATTACH, the tracee is sent a STOP signal.

The STOP signal can take effect while executing userspace code, when entering a syscall, while blocking in a "slow" syscall in kernel, and when returning to userspace from a syscall.

By examining the instruction pointer, and the instructions around the instruction pointer, you can usually determine whether the process was executing userspace code, but that's about it.

However, because the stop point is essentially random, you can wait for the process to stop, then single-step each of its threads using PTRACE_SINGLESTEP, until the instruction pointer changes. Then you know the thread is executing userspace code.

Alternatively, if the singlestep causes the thread to block for a long time, it means the thread is executing a slow system call that is blocking.

Put differently, if I restart the tracee using PTRACE_SYSCALL, how do I know whether the next syscall-stop is a syscall-enter-stop or a syscall-exit-stop?

You don't, unless you know the state where the tracee stopped. As I noted above, you can do that by single-stepping the code, until the instruction pointer changes.

Nominal Animal
  • 38,216
  • 5
  • 59
  • 86
  • And how can you know in ARM arch. if you are in enter to syscall or exit (while `PTRACE_SYSCALL` ) ? there is no `PTRACE_SINGLESTEP` in ARM take a look please on https://stackoverflow.com/questions/63053111/how-to-know-when-syscall-is-enter-or-exist-with-ptrace – paramikoooo Jul 26 '20 at 13:01
-1

I don't believe that you can do that with ptrace. ptrace traces, after all, that is it displays events and has no way to check the history (it has no concept of the stack of the process being traced).

But then, you could use gdb to attach to a running process in the same way.

$ gdb -p 20334
...
Attaching to process 20334
...
> bt

This would give you the stack trace of the process. Provided you have the debugging symbols of your kernel installed, you may be able to see the kernel function listet (instead of just "???").

AnoE
  • 8,048
  • 1
  • 21
  • 36
  • 1
    It's not possible for gdb (or anything using the ptrace mechanism in general) to know where in the kernel a process is currently executing - it's not exposed via the mechanism. – davmac Aug 31 '18 at 10:39