跟踪器无法区分Syscall-enter-stop和syscall-exit-stop。跟踪器需要跟踪ptrace-stops的顺序,以便不会将syscall-enter-stop错误解释为syscall-exit-stop,反之亦然。
当我使用PTRACE_ATTACH
附加到进程时,如何知道tracee当前是否在系统调用中?换句话说,如果我使用PTRACE_SYSCALL
重新启动tracee,我怎么知道下一个系统调用停止是syscall-enter-stop
还是syscall-exit-stop
?
当我使用PTRACE_ATTACH附加到进程时,如何知道tracee当前是否在系统调用中?
使用PTRACE_ATTACH连接到进程时,将向tracee发送STOP信号。
STOP信号在执行用户空间代码时,进入系统调用时生效,同时在内核中“慢速”系统调用中阻塞,以及从系统调用返回用户空间时生效。
通过检查指令指针和指令指针周围的指令,您通常可以确定进程是否正在执行用户空间代码,但这是关于它的。
但是,因为停止点基本上是随机的,所以您可以等待进程停止,然后使用PTRACE_SINGLESTEP单步执行每个线程,直到指令指针发生变化。然后你知道线程正在执行用户空间代码。
或者,如果单步执行导致线程长时间阻塞,则意味着线程正在执行阻塞的慢速系统调用。
换句话说,如果我使用PTRACE_SYSCALL重新启动tracee,我怎么知道下一个系统调用停止是syscall-enter-stop还是syscall-exit-stop?
你没有,除非你知道tracee停止的状态。如上所述,您可以通过单步执行代码来执行此操作,直到指令指针发生更改。
当跟踪的进程在系统调用ENTRY上停止时,EAX寄存器将包含-ENOSYS,orig_rax具有该系统调用的编号。
以下代码示例演示了一个示例。
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);
}
}
我不相信你可以用ptrace
做到这一点。毕竟,ptrace
跟踪它显示事件并且无法检查历史记录(它没有被跟踪的进程堆栈的概念)。
但是,您可以使用gdb
以相同的方式附加到正在运行的进程。
$ gdb -p 20334
...
Attaching to process 20334
...
> bt
这将为您提供该过程的堆栈跟踪。如果安装了内核的调试符号,则可能会看到内核函数侦听(而不仅仅是“???”)。