pet*_*ohn 7 c c++ linux ptrace fork
我正在使用ptrace跟踪进程的系统调用.在分支过程之后,我PTRACE_TRACEME用来开始跟踪过程.代码如下所示:
while (true) {
int status;
int gotPid;
gotPid = waitpid(pid, &status, 0);
if (WIFEXITED(status) || WIFSIGNALED(status)) {
break;
}
if (WIFSTOPPED(status)) {
handleTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
然后有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);
Run Code Online (Sandbox Code Playgroud)
这一切都很好,但如果程序分叉(或创建一个新线程),我还想跟踪跟踪进程创建的子进程(以及进程创建的线程).我知道它可以使用PTRACE_O_TRACEFORK,PTRACE_O_TRACEVFORK并且PTRACE_O_TRACECLONE,但是从man文档中,很难弄清楚它是如何完成的.我需要一些这方面的例子.
编辑:
我在这里找到了一个类似的问题:如何ptrace多线程应用程序?我用以下代码尝试了它.此代码跟踪已启动进程的系统调用,并且它也应该跟踪分叉进程.它fork()在父进程中运行(子进程调用a PTRACE_TRACEME和a exec()).
EDIT2:
我对代码做了一些修改,取得了一些进展.
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));
}
}
Run Code Online (Sandbox Code Playgroud)
CHECK_ERROR_VALUE只是一个宏,它检查结果代码并抛出一个带有其中描述的异常errno.
显然,当我得到fork/clone事件时,新进程还不存在,如果我尝试ptrace它,我会得到一个"进程不存在"错误消息.如果我在尝试ptrace新进程之前暂时休眠,我不会收到错误消息.现在当程序到达fork/clone时,它开始跟踪新进程,但它永远不会到达clone()父进程中syscall 的返回点,这意味着子进程成功完成,但是父进程挂起它的叉点.
Strace 执行此操作,其 README-linux-ptrace 文件包含有关该主题的一些信息:
https://github.com/strace/strace/blob/master/README-linux-ptrace
它似乎确实在抱怨这个平台上的内核错误,所以 YMMV。
该代码解释了如何获取子进程的 pid。但是,由于在其调用的二进制文件上设置了 setuid 或 setgid 位,子级可能会获得另一个用户 ID。所以答案是您对子 PID 调用 ptrace 并查看是否可以访问。
这是相关部分:
PTRACE_EVENT当 waitpid 返回 , 时,跟踪器会观察到WIFSTOPPED(status) == true停止WSTOPSIG(status) == SIGTRAP。附加位设置在状态字的高字节中:值((status >> 8) & 0xffff)将为(SIGTRAP | PTRACE_EVENT_foo << 8)。存在以下事件:
PTRACE_EVENT_VFORK- 从 vfork/clone+CLONE_VFORK 返回之前停止。当tracee在此之后继续时,它将等待子进程退出/执行,然后再继续执行(IOW:vfork上的通常行为)。PTRACE_EVENT_FORK- 在从 fork/clone+SIGCHLD 返回之前停止PTRACE_EVENT_CLONE- 从克隆返回之前停止PTRACE_EVENT_VFORK_DONE- 在从 vfork/clone+CLONE_VFORK 返回之前停止,但在 vfork 子进程通过退出或执行解除阻止此被跟踪之后。对于上述所有四个停止:停止发生在父线程中,而不是在新创建的线程中。
PTRACE_GETEVENTMSG可用于检索新线程的 tid。