Solaris 动态跟踪指南

处理破坏性操作

一些破坏性操作仅对特定进程具有破坏性。具有 dtrace_procdtrace_user 权限的用户可以使用这些操作。有关 DTrace 安全权限的详细信息,请参见第 35 章

stop()

void stop(void)

当触发已启用的探测器的进程接下来退出内核时,stop() 操作将强制停止该进程,就像由 proc(4) 操作停止一样。prun(1) 实用程序可用于恢复由 stop() 操作停止的进程。stop() 操作可用于在任何 DTrace 探测器位置停止进程。此操作可用于在特定状态下,捕获难以使用简单断点获取的程序,然后将一个传统调试器(如 mdb(1))附加至该进程。您也可以使用 gcore(1) 实用程序将已停止进程的状态保存在一个核心转储文件中,供以后进行分析。

raise()

void raise(int signal)

raise() 操作将指定的信号发送至当前正在运行的进程。此操作与使用 kill(1) 命令向进程发送信号类似。raise() 操作可用于在进程执行过程中的一个准确时间点发送信号。

copyout()

void copyout(void *buf, uintptr_t addr, size_t nbytes)

copyout() 操作在与当前线程关联的进程的地址空间中,从 buf 指定的缓冲区中复制 nbytesaddr 指定的地址。如果用户空间地址与当前地址空间中有效的错误页面不对应,则将生成错误。

copyoutstr()

void copyoutstr(string str, uintptr_t addr, size_t maxlen)

copyoutstr() 操作在与当前线程关联的进程的地址空间中,将 str 指定的字符串复制到 addr 指定的地址。如果用户空间地址与当前地址空间中有效的错误页面不对应,则将生成错误。字符串长度限于 strsize 选项指定的值。有关详细信息,请参见第 16 章

system()

void system(string program, ...) 

system() 操作将导致执行 program 指定的程序,就像将该程序作为输入提供给 shell 一样。program 字符串可以包含任何 printf()/printa() 格式转换。指定的参数必须与格式转换匹配。有关有效的格式转换的详细信息,请参阅第 12 章

以下示例每秒运行 date(1) 命令一次:


# dtrace -wqn tick-1sec'{system("date")}'
 Tue Jul 20 11:56:26 CDT 2004
 Tue Jul 20 11:56:27 CDT 2004
 Tue Jul 20 11:56:28 CDT 2004
 Tue Jul 20 11:56:29 CDT 2004
 Tue Jul 20 11:56:30 CDT 2004

以下示例通过在 program 字符串中使用 printf() 转换,同时使用传统过滤工具(如管道),更详细地说明了该操作的用法。

#pragma D option destructive
#pragma D option quiet

proc:::signal-send
/args[2] == SIGINT/
{
	printf("SIGINT sent to %s by ", args[1]->pr_fname);
	system("getent passwd %d | cut -d: -f5", uid);
}

运行上面的脚本将会生成与以下示例类似的输出:


# ./whosend.d
SIGINT sent to MozillaFirebird- by Bryan Cantrill
SIGINT sent to run-mozilla.sh by Bryan Cantrill
^C
SIGINT sent to dtrace by Bryan Cantrill

在触发探测器的上下文中不会执行指定的命令,此命令是在用户级处理包含 system() 操作的详细信息的缓冲区时执行的。进行此处理的方式和时间取决于第 11 章中介绍的缓冲策略。使用缺省缓冲策略时,缓冲区处理速率由 switchrate 选项指定。如果将 switchrate 显式地调整到高于其缺省值(一秒),则将会看到 system() 中的固有延迟,如下例所示:

#pragma D option quiet
#pragma D option destructive
#pragma D option switchrate=5sec

tick-1sec
/n++ < 5/
{
	printf("walltime  : %Y\n", walltimestamp);
	printf("date      : ");
	system("date");
	printf("\n");
}

tick-1sec
/n == 5/
{
	exit(0);
}

运行上面的脚本将会生成与以下示例类似的输出:


# dtrace -s ./time.d
 walltime  : 2004 Jul 20 13:26:30
date      : Tue Jul 20 13:26:35 CDT 2004

walltime  : 2004 Jul 20 13:26:31
date      : Tue Jul 20 13:26:35 CDT 2004

walltime  : 2004 Jul 20 13:26:32
date      : Tue Jul 20 13:26:35 CDT 2004

walltime  : 2004 Jul 20 13:26:33
date      : Tue Jul 20 13:26:35 CDT 2004

walltime  : 2004 Jul 20 13:26:34
date      : Tue Jul 20 13:26:35 CDT 2004

请注意,walltime 值会不同,但 date 值相同。此结果反映了一个事实,即仅当处理缓冲区而不是记录 system() 操作时,才会执行 date(1) 命令。