首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >跟踪进程和所有分叉进程的系统

跟踪进程和所有分叉进程的系统
EN

Stack Overflow用户
提问于 2012-11-23 15:42:28
回答 1查看 4.4K关注 0票数 9

我使用ptrace来跟踪进程的系统。分叉处理后,我使用PTRACE_TRACEME开始跟踪该进程。代码如下所示:

代码语言:javascript
运行
复制
while (true) {
    int status;
    int gotPid;
    gotPid = waitpid(pid, &status, 0);

    if (WIFEXITED(status) || WIFSIGNALED(status)) {
        break;
    }

    if (WIFSTOPPED(status)) {
        handleTrace();
    }
}

然后是handleTrace函数,它如下所示。

代码语言:javascript
运行
复制
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_TRACEFORKPTRACE_O_TRACEVFORKPTRACE_O_TRACECLONE来完成它,但是从man文档中,很难确定它是如何完成的。我需要一些这方面的例子。

编辑:

我在这里发现了一个类似的问题:How to ptrace a multi-threaded application?,我用下面的代码进行了尝试。此代码跟踪已启动进程的系统调用,并跟踪分叉进程。它在父进程中的fork()之后运行(子进程调用PTRACE_TRACEMEexec())。

Edit2:

我对代码做了更多的修改,并取得了一些进展。

代码语言:javascript
运行
复制
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描述的异常。

显然,当我得到叉/克隆事件时,新的进程还不存在,如果我试图跟踪它,就会得到一个"Process不存在“错误消息。如果我在尝试删除新进程之前先睡一觉,我就不会收到错误消息。现在,当程序到达叉/克隆点时,它开始跟踪新进程,但它永远不会到达父进程中的clone() syscall的返回点,这意味着子进程成功完成,但是父进程挂起。

EN

回答 1

Stack Overflow用户

发布于 2012-11-25 08:20:19

Strace会这样做,并且它的自述文件linux文件中有一些关于这个主题的信息:

https://github.com/strace/strace/blob/master/README-linux-ptrace

它似乎在抱怨这个平台中的内核错误,所以YMMV。

代码解释了如何获得孩子的pid。但是,由于在它调用的二进制文件上设置了setuid或setgid位,子用户可能会获得另一个userid。因此,答案是对子PID调用ptrace,并查看是否有访问权限。

以下是相关章节:

跟踪器观察到PTRACE_EVENT停止,WIFSTOPPED(status) == trueWSTOPSIG(status) == SIGTRAP作为等待返回。在状态字的较高字节中设置了附加位:值((status >> 8) & 0xffff)将是(SIGTRAP | PTRACE_EVENT_foo << 8)。存在下列事件:

  • PTRACE_EVENT_VFORK -从VFORK/CLONE返回之前停止+CLONE_VFORK。在此之后,当tracee继续运行时,它将等待子程序退出/执行,然后继续执行它(IOW: v叉上的通常行为)。
  • PTRACE_EVENT_FORK -从fork/克隆返回之前停止+SIGCHLD
  • PTRACE_EVENT_CLONE -克隆人返回前停止
  • PTRACE_EVENT_VFORK_DONE -在从vfork /CLONE返回之前停止,但在vfork子节点通过退出或执行来解除对此tracee的阻塞之后。

对于上述所有四个停止:停止发生在父线程中,而不是在新创建的线程中。PTRACE_GETEVENTMSG可用于检索新线程的tid。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13532137

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档