连接到进程后,如何检查跟踪程序是否处于系统调用中?

10
根据ptrace手册页面:http://man7.org/linux/man-pages/man2/ptrace.2.html
系统调用进入停止和系统调用退出停止对于跟踪程序来说是无法区分的。跟踪程序需要跟踪ptrace停止的顺序,以免将系统调用进入停止误解为系统调用退出停止,反之亦然。
当我使用PTRACE_ATTACH附加到一个进程时,如何知道被跟踪的进程当前是否在系统调用中?换句话说,如果我使用PTRACE_SYSCALL重新启动被跟踪的进程,如何知道下一个系统调用停止是syscall-enter-stop还是syscall-exit-stop?

1
这是一个好问题。我一直认为在跟踪的进程处于系统调用时,附件不会成功,但我没有任何证据来支持这个假设。 - Daniel Pryden
1
我想象一下,在附加后,系统调用的进入/退出报告只会在当前系统调用返回之后开始(并且很可能会通过EINTR中断它,如果它是可中断的),这样你就可以始终假定第一个系统调用停止是一个进入。我没有验证过,但很容易检查。 - davmac
4个回答

2
当被跟踪的进程在系统调用ENTRY处停止时,EAX寄存器将包含-ENOSYS,并且orig_rax将包含该系统调用的编号。
以下代码示例演示了一个例子。
最初的回答中说,当一个进程在执行系统调用时被追踪,如果它停在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);
                }
        }

0
如果pt_regs.orig_rax != -1,则表示被跟踪的进程在系统调用期间被停止。

0
当我使用PTRACE_ATTACH附加到进程时,如何知道被跟踪的进程当前是否在系统调用中?
当您使用PTRACE_ATTACH附加到进程时,被跟踪的进程会收到一个STOP信号。
STOP信号可能在执行用户空间代码时生效,在进入系统调用时,在内核中阻塞“慢”系统调用时以及从系统调用返回用户空间时。
通过检查指令指针及其周围的指令,通常可以确定进程是否正在执行用户空间代码,但仅限于此。
然而,由于停止点本质上是随机的,因此您可以等待进程停止,然后使用PTRACE_SINGLESTEP单步执行其每个线程,直到指令指针发生变化。然后您就知道该线程正在执行用户空间代码。
或者,如果单步执行导致线程长时间阻塞,则表示该线程正在执行阻塞的慢系统调用。
换句话说,如果我使用PTRACE_SYSCALL重新启动被跟踪的进程,如何知道下一个系统调用停止是系统调用进入停止还是系统调用退出停止?

除非您知道被跟踪程序停止的状态,否则您无法这样做。如上所述,您可以通过单步执行代码,直到指令指针发生变化来实现。


在ARM架构中,如何知道你是进入系统调用还是退出系统调用(使用PTRACE_SYSCALL)?ARM中没有PTRACE_SINGLESTEP,请看一下https://stackoverflow.com/questions/63053111/how-to-know-when-syscall-is-enter-or-exist-with-ptrace - paramikoooo

-1

我不相信你可以用ptrace做到那一点。ptrace只是追踪,它显示事件但没有办法检查历史(它没有被追踪进程的堆栈概念)。

但是,你可以使用gdb以同样的方式附加到正在运行的进程。

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

这将为您提供进程的堆栈跟踪。如果您已安装了内核的调试符号,您可能能够看到列出的内核函数(而不仅仅是“???”)。


1
gdb(或者一般使用ptrace机制的任何工具)无法知道进程当前在内核中执行的位置 - 这个信息不会通过机制暴露出来。 - davmac

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接