编程接口指南

使用 apptrace 进行应用程序验证

apptrace 实用程序是一个 C 程序,用于在应用程序运行时动态跟踪对 Solaris 库例程的调用。apptrace 可以在 SPARC 或 x86 平台上运行。apptrace 既可以跟踪 SPARC 和 x86 的 32 位接口调用,也可以跟踪 SPARC 平台上的 64 位接口调用。与 appcert 一样,apptrace 仅检查 C 语言接口。

应用程序验证

使用 appcert 确定应用程序面临二进制不稳定性风险之后,可以借助 apptrace 评估每种情况下的风险程度。要确定应用程序与给定发行版的二进制兼容性,请通过 apptrace 验证是否可以成功使用应用程序所用的每个接口。

apptrace 实用程序可以验证应用程序是否正确使用公共接口。例如,使用 open() 直接打开管理文件 /etc/passwd 的应用程序应改用相应的编程接口。这种检查 Solaris ABI 使用情况的能力使您能够轻松快速地识别潜在的接口问题。

运行 apptrace

apptrace 实用程序不要求对所跟踪的应用程序进行任何修改。要使用 apptrace,请键入 apptrace,后跟所需的任何选项以及用于运行有用的应用程序的命令行。apptrace 实用程序运行时可使用运行时链接程序的链接审计功能来拦截应用程序对 Solaris 库接口的调用。然后,apptrace 实用程序会通过列显调用参数的名称和值来跟踪调用并返回值。跟踪输出可以显示为一行,也可以分为多行以便于阅读。公共接口按人工可读的形式进行列显。专用接口以十六进制进行列显。

apptrace 实用程序允许有选择性跟踪调用,既可以跟踪各接口级调用,也可以跟踪库级调用。例如,apptrace 可以跟踪来自 libnslprintf() 调用,也可以跟踪特定库内某个范围的调用。apptrace 实用程序还可以详细跟踪用户指定的调用。指示 apptrace 行为的规范会通过语法进行制约,此语法与 truss(1) 的用法一致。-f 选项用于指示 apptrace 遵循派生的子进程。-o 选项用于指定存储 apptrace 结果的输出文件。

apptrace 实用程序仅跟踪库级调用,并可装入运行的应用程序进程中,从而可以提高性能(比使用 truss 时的性能要高)。但使用 printf 则除外,在这种情况下 apptrace 无法跟踪对接受变量列表的函数的调用,也无法检查栈或其他调用方信息,例如 setcontextgetcontextsetjmplongjmpvfork

解释 apptrace 输出

以下示例包含跟踪简单的单二进制应用程序 ls 所产生的 apptrace 输出样例。


示例 11–1 缺省跟踪行为


% apptrace ls /etc/passwd

ls       -> libc.so.1:atexit(func = 0xff3cb8f0) = 0x0

ls       -> libc.so.1:atexit(func = 0x129a4) = 0x0

ls       -> libc.so.1:getuid() = 0x32c3

ls       -> libc.so.1:time(tloc = 0x23918) = 0x3b2fe4ef

ls       -> libc.so.1:isatty(fildes = 0x1) = 0x1

ls       -> libc.so.1:ioctl(0x1, 0x540d, 0xffbff7ac)

ls       -> libc.so.1:ioctl(0x1, 0x5468, 0x23908)

ls       -> libc.so.1:setlocale(category = 0x6, locale = "") = "C"

ls       -> libc.so.1:calloc(nelem = 0x1, elsize = 0x40) = 0x23cd0

ls       -> libc.so.1:lstat64(path = "/etc/passwd", buf = 0xffbff6b0) = 0x0

ls       -> libc.so.1:acl(pathp = "/etc/passwd", cmd = 0x3, nentries = 0x0,

             aclbufp = 0x0) = 0x4

ls       -> libc.so.1:qsort(base = 0x23cd0, nel = 0x1, width = 0x40,

             compar = 0x12038)

ls       -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0

ls       -> libc.so.1:strlen(s = "") = 0x0

ls       -> libc.so.1:strlen(s = "/etc/passwd") = 0xb

ls       -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0

ls       -> libc.so.1:strlen(s = "") = 0x0

ls       -> libc.so.1:printf(format = 0x12ab8, ...) = 11

ls       -> libc.so.1:printf(/etc/passwd

format = 0x12abc, ...) = 1

ls       -> libc.so.1:exit(status = 0)

以上示例显示了缺省跟踪行为,即跟踪 ls /etc/passwd 命令的每个库调用。apptrace 实用程序针对每个系统调用列显一行输出,指明以下信息:

ls 的输出与 apptrace 输出混在一起。


示例 11–2 选择性跟踪


% apptrace -t \*printf ls /etc/passwd

ls       -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0

ls       -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0

ls       -> libc.so.1:printf(format = 0x12ab8, ...) = 11

ls       -> libc.so.1:printf(/etc/passwd

format = 0x12abc, ...) = 1

以上示例说明了 apptrace 如何能够有选择性地跟踪使用正则表达式语法的调用。在此示例中,在 printf(包括 sprintf)中结束的接口调用与以前一样,都是在 ls 命令中进行跟踪。 因此,apptrace 仅跟踪 printfsprintf 调用。


示例 11–3 详细跟踪


% apptrace -v sprintf ls /etc/passwd

ls       -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0

  buf =    (char *) 0x233d0 ""

  format = (char *) 0x12af8 "%s%s%s"

ls       -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0

  buf =    (char *) 0x233d0 ""

  format = (char *) 0x12af8 "%s%s%s"

/etc/passwd

以上示例显示了详细跟踪模式,在这种模式下,sprintf 的参数会列显在多行中以便于阅读。 最后,apptrace 会显示 ls 命令的输出。