Solaris 动态跟踪指南

ustack() 操作

通常,在激活特定探测器时对进程线程的栈进行跟踪,可以更详细地检查问题。ustack() 操作可跟踪用户线程的栈。例如,如果打开多个文件的进程在 open(2) 系统调用中偶尔出现故障,则可使用 ustack() 操作来搜索执行出现故障的 open() 的代码路径:

syscall::open:entry
/pid == $1/
{
	self->path = copyinstr(arg0);
}

syscall::open:return
/self->path != NULL && arg1 == -1/
{
	printf("open for '%s' failed", self->path);
	ustack();
}

此脚本还说明了 $1 宏变量的用法,该变量将采用在 dtrace(1M) 命令行中指定的第一个操作数的值:


# dtrace -s ./badopen.d 31337
dtrace: script './badopen.d' matched 2 probes
CPU     ID                    FUNCTION:NAME
  0     40                      open:return open for '/usr/lib/foo' failed
              libc.so.1`__open+0x4
              libc.so.1`open+0x6c
              420b0
              tcsh`dosource+0xe0
              tcsh`execute+0x978
              tcsh`execute+0xba0
              tcsh`process+0x50c
              tcsh`main+0x1d54
              tcsh`_start+0xdc

ustack() 操作将记录栈的程序计数器 (PC) 值,dtrace(1M) 则通过查找进程符号表,将这些 PC 值解析为符号名。如果 dtrace 无法将 PC 值解析为符号,便会将该值列显为十六进制整数。

如果在设置 ustack() 数据输出格式之前退出或中止进程,dtrace 可能无法将栈跟踪内的 PC 值转换为符号名,并且会强制将其显示为十六进制整数。为处理此限制,请使用 dtrace-c-p 选项指定所关注的进程。有关这些选项和其他选项的详细信息,请参见第 14 章。如果事先不了解进程 ID 或命令,可使用以下 D 程序示例来处理限制:

/*
 * This example uses the open(2) system call probe, but this technique
 * is applicable to any script using the ustack() action where the stack
 * being traced is in a process that may exit soon.
 */
 syscall::open:entry
{
	ustack();
	stop_pids[pid] = 1;
}

syscall::rexit:entry
/stop_pids[pid] != 0/
{
	printf("stopping pid %d", pid);
	stop();
	stop_pids[pid] = 0;
}

如果对以上脚本的进程中的线程应用 ustack() 操作,则以上脚本将在该进程退出之前停止它。此方法可确保 dtrace 命令将 PC 值解析为符号名。请注意,在使用 stop_pids[pid] 清除动态变量之后,其值将设置为 0。请记住使用 prun(1) 命令设置重新运行已停止进程,否则系统中将聚集许多已停止进程。