通常,在激活特定探测器时对进程线程的栈进行跟踪,可以更详细地检查问题。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) 命令设置重新运行已停止进程,否则系统中将聚集许多已停止进程。