【问题标题】:pid provider matching processes that come and go in dtracedtrace 中来来去去的 pid 提供者匹配进程
【发布时间】:2018-05-01 17:25:11
【问题描述】:

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

我现在正在这样做:

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

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

我想要类似的东西:

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

但是那个 * 在那里不起作用。

谢谢!

【问题讨论】:

    标签: macos dtrace


    【解决方案1】:

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

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

    #!/usr/sbin/dtrace -s
    
    pid$1:libc::entry
    {
        printf( "func: %s\n", probefunc );
    }
    

    假设该脚本的路径是/root/dtrace/tracelibc.d,以下脚本将在任何新的ls 启动进程上启动dtrace。请注意,您需要 #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 attaches 后重新启动它:

    #!/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 重新启动已停止的进程。您必须查看 Mac dtrace 文档中的 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.dBEGIN 探测中添加了自己的system( "prun %d", $1 );,它看起来像:

    #!/usr/sbin/dtrace -s
    
    #pragma D option destructive
    
    BEGIN
    {
        system( "prun %d", $1 );
    }
    
    pid$1:libc::entry
    {
        printf( "func: %s\n", probefunc );
    }
    

    这三个确实减慢了ls 进程,但它们确实产生了预期的输出 - 并且有很多,正如预期的那样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-15
      • 1970-01-01
      • 2020-08-22
      相关资源
      最近更新 更多