pid提供者匹配进程dtrace中的进程

时间:2018-04-29 14:42:28

标签: macos dtrace

我想在一个进程中跟踪给定库的所有函数调用,但是该进程将定期退出并重新打开,我想继续跟踪。

我现在正在这样做:

oneshot$target:LIBRARY::entry
{
    printf("%s\n", probefunc);
}

然而,这只能让我一次提供一个pid。我可以继续这样做吗?

我想要类似的东西:

*:LIBRARY::entry
/execname == "foo"/

但那*在那里不起作用。

谢谢!

1 个答案:

答案 0 :(得分:1)

我认为只用一个dtrace脚本就可以做到这一点。你需要两个(至少......)。您需要能够运行破坏性system()操作,这很可能意味着root访问。

假设您要在任何新的ls进程上运行此脚本:

#!/usr/sbin/dtrace -s

pid$1:libc::entry
{
    printf( "func: %s\n", probefunc );
}

假设该脚本的路径为/root/dtrace/tracelibc.d,则以下脚本将在任何已启动的新dtrace进程上启动ls。请注意,您需要#pragma D option destructive才能在新流程上启动dtrace

#!/usr/sbin/dtrace -s

#pragma D option destructive
#pragma D option quiet

proc:::exec-success
/ "ls" == basename( execname ) /
{
    printf( "tracing process %d\n", pid );
    system( "/root/dtrace/tracelibc.d %d", pid );
}

这应该有效,但在这种情况下ls是一个如此短暂的过程,这种情况经常发生:

dtrace: failed to compile script /root/dtrace/tracelibc.d: line 10:
    failed to grab process 12289

这个过程在dtrace开始的时候消失了。如果您正在跟踪长期存在的流程而不关心您可能会错过前几个探测因为dtrace需要一段时间来附加,那么您就完成了。

但是,如果要跟踪短期进程,则需要在启动时立即停止进程,然后在dtrace附加后重新启动它:

#!/usr/sbin/dtrace -s

#pragma D option destructive
#pragma D option quiet

proc:::exec-success
/ "ls" == basename( execname ) /
{
    printf( "stopping process %d\n", pid );
    system( "/root/dtrace/tracelibc.d %d", pid );
    stop();
}

并在tracelibc.d

中重启
#!/usr/sbin/dtrace -s

#pragma D option destructive

BEGIN
{
    system( "prun %d", $1 );
}

pid$1:libc::entry
{
    printf( "func: %s\n", probefunc );
}

请注意,我正在使用Solaris prun重新启动已停止的进程。您必须查看dtrace调用的Mac stop()文档才能获得与Solaris prun相当的Mac。

但是......哎呀。上面的两个脚本结合起来产生:

stopping process 12274
dtrace: failed to compile script /root/dtrace/tracelibc.d: line 10:
    probe description pid12274:libc::entry does not match any probes

为什么这说pid12274:libc::entry与任何探测都不匹配?哦,是的 - 当exec返回时,libc.so共享对象尚未加载到内存中。我们需要一个保证存在于目标进程中的探测器,并且在加载libc.so之后但在任何处理完成之前调用。 main应该足够了。因此,启动它的主要脚本变为:

#!/usr/sbin/dtrace -s

#pragma D option destructive
#pragma D option quiet

proc:::exec-success
/ "ls" == basename( execname ) /
{
    printf( "stopping process %d\n", pid );
    system( "/root/dtrace/tracemain.d %d", pid );
    stop();
}

启动tracemain.d脚本,重启进程,加载tracelibc.d脚本,然后再次停止进程:

#!/usr/sbin/dtrace -s

#pragma D option destructive
#pragma D option quiet

BEGIN
{
    system( "prun %d", $1 );
}

pid$1::main:entry
{
    system( "/root/dtrace/tracelibc.d %d", $1 );
    stop();
    /* this instance of dtrace is now done */
    exit( 0 );
}

并且tracelibc.dsystem( "prun %d", $1 );探针中添加了自己的BEGIN,它看起来像:

#!/usr/sbin/dtrace -s

#pragma D option destructive

BEGIN
{
    system( "prun %d", $1 );
}

pid$1:libc::entry
{
    printf( "func: %s\n", probefunc );
}

这三个确实会使ls进程放慢速度,但它们确实产生了预期的输出 - 而且正如预期的那样,有很多