我正在编写一个调用DTrace来跟踪用户指定的程序的工具。
如果我的工具使用dtrace -c将程序作为DTrace的子进程运行,我不仅不能将任何参数传递给程序,而且程序以DTrace的所有权限运行 - 即以root身份运行(I我在Mac OS X上。这使得某些事情应该有效,并且显然会产生许多不可行的事情。
我知道的另一个解决方案是自己启动程序,通过发送SIGSTOP
暂停它,将其PID传递给dtrace -p
,然后通过发送SIGCONT
继续它。问题是,当DTrace收集符号信息时,程序运行几秒钟而不进行跟踪,或者,如果我在继续该过程之前休眠几秒钟,则DTrace会抱怨objc<pid>:<class>:<method>:entry
与没有探测器匹配。
有没有办法可以在用户的帐户下运行程序,而不是root用户,但仍然可以让DTrace从头开始跟踪它?
答案 0 :(得分:6)
sudo dtruss -f sudo -u <original username> <command>
之类的东西对我有用,但事后我感觉很糟糕。
我提交了一个关于它的Radar错误,并将其作为#5108629的副本关闭。
答案 1 :(得分:3)
如果其他答案对你不起作用,你可以在gdb中运行程序,在main(甚至更早)中断,获取pid,然后启动脚本吗?我过去曾经尝试过,似乎有效。
答案 2 :(得分:3)
嗯,这有点旧,但为什么不呢: - )..
我认为没有办法简单地从命令行执行此操作,但正如所建议的那样,一个简单的启动器应用程序(如下所示)就可以执行此操作。手动附加当然也可以用一些libdtrace调用替换。
int main(int argc, char *argv[]) {
pid_t pid = fork();
if(pid == 0) {
setuid(123);
seteuid(123);
ptrace(PT_TRACE_ME, 0, NULL, 0);
execl("/bin/ls", "/bin/ls", NULL);
} else if(pid > 0) {
int status;
wait(&status);
printf("Process %d started. Attach now, and click enter.\n", pid);
getchar();
ptrace(PT_CONTINUE, pid, (caddr_t) 1, 0);
}
return 0;
}
答案 3 :(得分:3)
此脚本将您要监视的可执行文件的名称(对于应用程序,这是info.plist的CFBundleExecutable)作为参数(您可以在此脚本运行后启动目标应用程序):
string gTarget; /* the name of the target executable */
dtrace:::BEGIN
{
gTarget = $$1; /* get the target execname from 1st DTrace parameter */
/*
* Note: DTrace's execname is limited to 15 characters so if $$1 has more
* than 15 characters the simple string comparison "($$1 == execname)"
* will fail. We work around this by copying the parameter passed in $$1
* to gTarget and truncating that to 15 characters.
*/
gTarget[15] = 0; /* truncate to 15 bytes */
gTargetPID = -1; /* invalidate target pid */
}
/*
* capture target launch (success)
*/
proc:::exec-success
/
gTarget == execname
/
{
gTargetPID = pid;
}
/*
* detect when our target exits
*/
syscall::*exit:entry
/
pid == gTargetPID
/
{
gTargetPID = -1; /* invalidate target pid */
}
/*
* capture open arguments
*/
syscall::open*:entry
/
((pid == gTargetPID) || progenyof(gTargetPID))
/
{
self->arg0 = arg0;
self->arg1 = arg1;
}
/*
* track opens
*/
syscall::open*:return
/
((pid == gTargetPID) || progenyof(gTargetPID))
/
{
this->op_kind = ((self->arg1 & O_ACCMODE) == O_RDONLY) ? "READ" : "WRITE";
this->path0 = self->arg0 ? copyinstr(self->arg0) : "<nil>";
printf("open for %s: <%s> #%d",
this->op_kind,
this->path0,
arg0);
}
答案 4 :(得分:2)
创建一个启动器程序,它将等待某种信号(不一定是文字信号,只是表明它已准备就绪),然后exec()你的目标。现在dtrace -p启动程序,一旦dtrace启动,让发射器启动。
答案 5 :(得分:1)
dtruss具有-n
选项,您可以在其中指定要跟踪的进程名称,而无需启动它(在@ {3}}中归功于@ kenorb答案的后半部分)。所以类似下面的内容应该这样做:
sudo dtruss -n "$program"
$program
答案 6 :(得分:0)