在Mac OS X上监控Cocoa应用程序是否执行外部实用程序(例如ffmpeg)?

4
有些Mac GUI应用程序提供了一个前端来使用更加极客的命令行工具(通常作为应用程序包的一部分)。我想看一看这样的GUI底层是如何运行的。
如何"附加"到一个应用程序,监视它对命令行实用程序的调用并记录这些调用的文件名和命令行参数?
解决方案也可以是一个记录Mac OS X上所有应用程序执行情况的应用程序(过滤掉最常见的系统调用)。
示例GUI前端:http://xact.sourceforge.net/ (因为它是开源的,所以可以直接进行调试,但是xACT只是一个例子。假设我们有一个现成的*.app来监视)。
更新:dtrace可以监视exec调用并打印调用的命令名称。这是解决方案的一半,另一半是获取它的命令行参数。这还未解决(除非有人确认他们已经让dtrace这样做了)。
4个回答

6

DTrace可以完成这项工作。根据我在此问题的其他评论中与Joey Hagedorn讨论的内容,10.6版本附带的脚本可以改进以处理合理数量的参数(50+)。由于脚本有很多重复部分,我将在此包含一个输出良好的DTrace脚本的脚本。这个脚本可以处理最多50个参数;您可能需要通过更改for循环来扩展参数数量。

#!/bin/bash

cat <<HEADER
#!/usr/sbin/dtrace -s
/*
 * newproc.d - snoop new processes as they are executed. DTrace OneLiner.
 *
 * This is a DTrace OneLiner from the DTraceToolkit.
 *
 * 15-May-2005  Brendan Gregg   Created this.
 */

/*
 * Updated to capture arguments in OS X. Unfortunately this isn't straight forward...
 */

#pragma D option quiet

this unsigned long long argv_ptr; /* Wide enough for 64 bit user procs */

proc:::exec-success
{
    print_pid[pid] = 1; /* This pid emerged from an exec, make a note of that. */
}

/*
 * The "this" variables are local to (all) of the following syscall::mmap:return probes,
 * and only those probes. They must be initialized before use in each new firing.
 */
syscall::mmap:return
{
    this->argc = 0; /* Disable argument collection until we notice an exec-success */
}

syscall::mmap:return
/ print_pid[pid] /
{
    print_pid[pid] = 0;

    this->is64Bit = curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? 0 : 1;
    this->wordsize = this->is64Bit ? 8 : 4;

    this->argc = curpsinfo->pr_argc; 
    this->argc = (this->argc < 0) ? 0 : this->argc; /* Safety */

    this->argv_ptr = curpsinfo->pr_argv;

    printf("%d %s ", pid, this->is64Bit ? "64b" : "32b");
}

HEADER

for ((i=0;i<50;++i)); do

cat <<REPEAT
syscall::mmap:return
/ this->argc /
{
    this->here_argv = copyin(this->argv_ptr, this->wordsize);
    this->arg = this->is64Bit ? *(unsigned long long*)(this->here_argv) : *(unsigned long*)(this->here_argv);
    printf("%s ", copyinstr(this->arg));
    this->argv_ptr += this->wordsize;
    this->argc--;
}

REPEAT
done

cat <<FOOTER
syscall::mmap:return
/ this->argv_ptr /
{
    printf("%s\n", this->argc > 0 ? "(...)" : "");
    this->argc = 0;
    this->argv_ptr = 0;
}
FOOTER

5

newproc.d 是又一个 DTrace 脚本,它还会将进程的命令行参数输出到进程名称中。运行它很简单:

sudo newproc.d

这对我来说在OS X Mountain Lion上有效。旧版本可能会有各种问题。有关Leopard和Snow Leopard上newproc.d的讨论,请参见 ServerFault答案的评论线程。
此外,您应该知道一些小的限制。如果您查看脚本的源代码,它指出它不会显示超过5个参数,并且不会显示长度超过128个字符的参数:
/*
 * Updated to capture arguments in OS X. Unfortunately this isn't straight forward... nor inexpensive ...
 * Bound the size of copyinstr()'s and printf incrementally to prevent "out of scratch space errors"
 * print "(...)" if the length of an argument exceeds COPYINSTRLIMIT.
 * print "<...>" if argc exceeds 5.
 */

inline int COPYINSTRLIMIT = 128;

3

1
能否给一个 DTrace 脚本的例子? - CaptSolo
这听起来太像“请给我代码”,但是我可以告诉你 - dtrace 可以打印任何系统调用的参数。在 exec*() 中运行的可执行文件的参数可以在参数中使用。 - user23743
3
好的,谢谢。我认为询问别人“给我看一下代码”并不是错的,因为示例代码通常是最好的解释,并且对于寻找答案的其他人来说具有最大的价值。(除非有人受雇编写代码,然后要求其他人代替完成。但这种情况并不适用。) - CaptSolo

2

Graham: dtrace在这里会非常完美。你(或者这里的任何其他人)能否展示一个dtrace脚本,可以打印进程的命令行?

这个一行代码会打印正在执行的进程的名称:

dtrace -qn 'syscall::exec*:return { printf("%Y %s\n",walltimestamp,curpsinfo->pr_psargs); }' 

但是如何获取/打印它们的命令行参数?


2
这个似乎行不通。在 Mac OS X 上的 dtrace 中似乎存在一个 bug,它没有暴露命令行参数。一个旨在解决此问题的脚本也只显示程序的名称(不带参数):http://www.brendangregg.com/DTrace/execsnoop.d - CaptSolo
1
这是关于DTrace未公开整个命令行的参考资料:“curpsinfo->ps_args不包含进程的整个命令行;它只包含第一个单词。”http://benjamin.smedbergs.us/blog/2008-11-20/282/ - CaptSolo
"sudo newproc.d" 将打印命令行参数。请阅读脚本以获取更多详细信息。 - Joey Hagedorn
@Joey - 不错的东西。然而,那个脚本有限制,因为它只能处理5个参数,并且如果你尝试使用相同的技术做更多的事情,它会用完缓冲空间。我会添加一个答案,其中包含我正在使用的脚本,可以处理更多的参数。 - Barry Kelly
@CaptSolo:newproc.d 是否符合你的需求? - user1377064
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接