在这两个输出中,每个输出行对应于应用程序执行的一个函数调用,其中显示函数的参数和函数调用的返回值。与调试示例不同,列出的每个函数调用都是系统或系统库中的函数,因此表示调用的函数的更低层接口。例如,在应用程序中可能使用 C 或 C++ 中的 fpopen() 函数打开文件,但是这个函数实际上是更低层的 open() 函数的包装器。
了解应用程序正在执行的操作并不需要了解每个函数的情况。输出中的许多行与操作系统为装载和执行程序所做的初始化相关。这两个跟踪输出的基本结构是相同的:
调用 execve() 函数以启动一个新程序。
装载程序所需的库。在 Solaris 输出中,首先使用 resolvepath() 寻找库,然后使用 open() 打开库。对于 Linux,使用 stat() 检查库是否存在,然后使用 open() 打开它。
为进程保留和分配一些内存。其中一部分内存是为应用程序保留的堆栈空间,一部分用来保存程序,其他内存保存程序使用的变量。
最后,执行程序,调用 write() 函数输出年龄和生日信息。
如果执行跟踪并希望了解每个步骤的具体情况,可以使用 man 命令访问每个函数的手册页。
识别应用程序启动问题
在启动应用程序时的一个典型问题是,程序无法正确地初始化,但是在终止时给出一个不完整或导致误解的消息。对应用程序运行跟踪常常可以揭示这个问题的根源。例如,清单 5 显示一个测试应用程序运行失败了。
清单 5. 应用程序失败
$ ./errnoacc
ERROR: Application failed to initialize
错误消息并没有提供关于应用程序为什么会启动失败的具体信息。在这里,问题是故意引入的,但是您使用的任何命令或应用程序都可能出现相同的问题,而错误消息没什么帮助,有时候甚至没有错误消息。
标签: