我将使用
那么接下来就是
这很好,但如果程序分叉(或创建新线程),我还想跟踪所跟踪进程创建的子进程(以及由进程创建的线程)。我知道可以使用
编辑:
我在这里找到了一个类似的问题:如何追踪多线程应用程序? 我尝试了以下代码。该代码跟踪启动进程的系统调用,并应该跟踪分叉的进程。它在父进程的
编辑2:
我对代码进行了一些修改,取得了一些进展。
ptrace
来跟踪进程的系统调用。在fork进程后,我使用PTRACE_TRACEME
开始跟踪进程。代码如下所示:
while (true) {
int status;
int gotPid;
gotPid = waitpid(pid, &status, 0);
if (WIFEXITED(status) || WIFSIGNALED(status)) {
break;
}
if (WIFSTOPPED(status)) {
handleTrace();
}
}
那么接下来就是
handleTrace
函数,它看起来像这样。long syscall;
syscall = ptrace(PTRACE_PEEKUSER,
pid, 8 * ORIG_RAX, NULL);
// do something with the syscall
// continue program
ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
这很好,但如果程序分叉(或创建新线程),我还想跟踪所跟踪进程创建的子进程(以及由进程创建的线程)。我知道可以使用
PTRACE_O_TRACEFORK
、PTRACE_O_TRACEVFORK
和 PTRACE_O_TRACECLONE
来完成,但从 man
文档中很难弄清楚具体如何实现。我需要一些示例代码。编辑:
我在这里找到了一个类似的问题:如何追踪多线程应用程序? 我尝试了以下代码。该代码跟踪启动进程的系统调用,并应该跟踪分叉的进程。它在父进程的
fork()
之后运行(子进程调用 PTRACE_TRACEME
和 exec()
)。编辑2:
我对代码进行了一些修改,取得了一些进展。
long orig_eax;
int status;
int numPrograms = 1;
while(1) {
int pid;
CHECK_ERROR_VALUE(pid = waitpid(-1, &status, __WALL));
std::cout << pid << ": Got event." << std::endl;
if(WIFEXITED(status) || WIFSIGNALED(status)) {
std::cout << pid << ": Program exited." << std::endl;
if (--numPrograms == 0) {
break;
}
continue;
}
if (status >> 16 == PTRACE_EVENT_FORK || status >> 16 == PTRACE_EVENT_VFORK ||
status >> 16 == PTRACE_EVENT_CLONE) {
int newpid;
CHECK_ERROR_VALUE(ptrace(PTRACE_GETEVENTMSG, child, NULL, (long) &newpid));
std::cout << pid << ": Attached to offspring " << newpid << std::endl;
boost::this_thread::sleep(boost::posix_time::millisec(100));
CHECK_ERROR_VALUE(ptrace(PTRACE_SETOPTIONS,
newpid, NULL, PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE));
CHECK_ERROR_VALUE(ptrace(PTRACE_SYSCALL, newpid, NULL, NULL));
++numPrograms;
} else {
CHECK_ERROR_VALUE(ptrace(PTRACE_SETOPTIONS,
pid, NULL, PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE));
CHECK_ERROR_VALUE(orig_eax = ptrace(PTRACE_PEEKUSER,
pid, 8 * ORIG_RAX, NULL));
std::cout << pid << ": Syscall called: " <<
SyscallMap::instance().get().right.at(orig_eax) <<
std::endl;
CHECK_ERROR_VALUE(ptrace(PTRACE_SYSCALL,
pid, NULL, NULL));
}
}
CHECK_ERROR_VALUE
是一个宏,用于检查结果代码并抛出带有 errno
描述的异常。
显然,当我获得 fork/clone 事件时,新进程还不存在,如果尝试对其进行 ptrace,则会收到 "进程不存在" 错误消息。如果在尝试 ptrace 新进程之前加上 sleep,就不会收到错误消息。现在,当程序到达 fork/clone 点时,它开始跟踪新进程,但是父进程中的 clone()
系统调用的返回点永远无法到达,这意味着子进程成功完成,但父进程挂起在其 fork 点处。