使用 truss 和 strace
在 Solaris 和 AIX 上可以使用 truss 工具,它能够跟踪应用程序中的系统调用和信号。可以在 Linux? 上使用的 strace 工具提供相似的功能。在不同的系统上,还有提供相似信息的其他工具,包括 ktrace (FreeBSD) 和 trace。
truss 和 strace 工具提供相似的信息,但是命令行选项稍有差异。使用这两种工具的标准方法都是把工具名放在要执行的命令前面。
例如,清单 3 给出 truss 对于本教程前面提到的 ageindays 程序的输出。
$ truss ./ageindays 24/1/1980 26/3/2009 |
清单 4 给出 Linux 上 strace 的输出。
$ strace ./ageindays 24/1/1980 26/3/2009 |
在这两个输出中,每个输出行对应于应用程序执行的一个函数调用,其中显示函数的参数和函数调用的返回值。与调试示例不同,列出的每个函数调用都是系统或系统库中的函数,因此表示调用的函数的更低层接口。例如,在应用程序中可能使用 C 或 C++ 中的
了解应用程序正在执行的操作并不需要了解每个函数的情况。输出中的许多行与操作系统为装载和执行程序所做的初始化相关。这两个跟踪输出的基本结构是相同的:
- 调用
de<execve() de< 函数以启动一个新程序。 - 装载程序所需的库。在 Solaris 输出中,首先使用
de<resolvepath() de< 寻找库,然后使用 de<open() de< 打开库。对于 Linux,使用 de<stat() de< 检查库是否存在,然后使用 de<open() de< 打开它。 - 为进程保留和分配一些内存。其中一部分内存是为应用程序保留的堆栈空间,一部分用来保存程序,其他内存保存程序使用的变量。
- 最后,执行程序,调用
de<write() de< 函数输出年龄和生日信息。
如果执行跟踪并希望了解每个步骤的具体情况,可以使用 man 命令访问每个函数的手册页。
在启动应用程序时的一个典型问题是,程序无法正确地初始化,但是在终止时给出一个不完整或导致误解的消息。对应用程序运行跟踪常常可以揭示这个问题的根源。例如,清单 5 显示一个测试应用程序运行失败了。
$ ./errnoacc |
错误消息并没有提供关于应用程序为什么会启动失败的具体信息。在这里,问题是故意引入的,但是您使用的任何命令或应用程序都可能出现相同的问题,而错误消息没什么帮助,有时候甚至没有错误消息。
对应用程序运行跟踪可能会提供一些线索(见清单 6)。
$ truss ./errnoacc |
问题出现在这一行上:
在这里,应用程序试图打开一个文件,但是因为有文件权限保护这个文件,运行应用程序的用户没有访问权。因为无法打开这个文件,应用程序终止并在进程中写错误消息。
希望跟踪应用程序常常是因为应用程序已经启动,而您希望查明应用程序为什么不工作了。与初始化示例一样,应用程序提供的错误消息或其他信息常常没有准确地指出问题。
试图锁定或访问另一个进程正在使用的资源会使应用程序看起来冻结了,没有响应。
strace 和 truss 都能够 “连接” 到正在运行的进程。连接到进程的跟踪与从命令行运行进程的跟踪相似,也产生程序正在执行的系统函数的列表。实际的跟踪从跟踪启动时执行的函数开始;对于在执行期间 “挂起” 的程序,跟踪应该会显示程序正在等待的函数。
要想跟踪正在运行的程序,需要指定要跟踪的进程的进程 ID (PID)。例如,在清单 6 中,跟踪的程序已经停止,但是没有报告错误。这里使用 ps 工具列出正在运行的进程(见清单 7)。
$ ps -ef|grep errlock |
在输出中可以看到,已经调用了
对 于这种情况,truss 有点儿局限性:它无法指出要锁住哪个文件,也无法指出当前锁住了哪个文件,从而阻碍了第二个程序的执行。这是因为跟踪过程是在已经调用了打开文件的函数之 后启动的。truss 和 strace 只跟踪在它们执行期间调用的函数;它们无法查明已经调用的函数。
可以看出,truss 对于监视整个程序很有用,但是对于监视已经启动的程序可能有点儿局限性。如果使用基于 SVR4 的 UNIX,比如 Solaris 或 AIX,那么 pstack 命令可能有帮助。
pstack 命令实际上属于一组进程检查命令,这些命令输出正在运行的进程的相关信息。其他工具包括 pfiles(输出进程使用的文件的列表)和 psig(显示信号和信号处理函数的列表)。
在使用这些命令时,需要指定进程的 PID。pstack 命令输出一个正在运行的进程的调用堆栈,显示在进程到达当前函数之前调用的函数。例如,对正在等待被锁住的文件的进程使用 pstack,会产生清单 8 中的输出。
$ pstack 15828 |
在这里,它没有提供我们需要的信息。现在试试 pfiles(见清单 9)。
$ pfiles 15856 |
这些输出就比较有用了。可以看到进程已经打开的文件称为 lockdemo ,因为 truss 显示正在等待文件锁,所以可能是这个文件导致了问题。
truss 和 strace 都是被动的跟踪。可以查看正在执行的函数,但是无法了解关于正在发生的情况的详细信息,也无法更有针对性地指定要跟踪的东西和跟踪时要输出的信息。