Sun Studio 12:使用 dbx 调试程序

第 20 章 调试共享库

dbx 为使用动态链接库、共享库的程序提供全面的调试支持,只要这些库是使用 -g 选项编译的。

本章由以下部分组成:

动态链接程序

动态链接程序(亦称 rtld、运行时 ldld.so)安排将共享对象(装入对象)引入到正在执行的程序中。rtld 在两个主要区域处于活动状态:

dbx 使用术语装入对象 来表示共享对象 (.so) 或可执行文件 (a.out)。可以使用 loadobject 命令(请参见 loadobject 命令)列出和管理来自装入对象的符号信息。

链接映射

动态链接程序在称为链接映射的列表中保留有所有装入对象的列表。链接映射保留在正被调试程序的内存中,可通过 librtld_db.so 这一供调试器使用的特殊系统库来间接访问它。

启动序列和 .init

.init 段是一段属于共享对象的代码,装入共享对象时该代码将执行。例如,.init 段由 C++ 运行时系统用于调用 .so 中的所有静态初始化函数。

动态链接程序会先在所有共享对象中映射,从而将它们置于链接映射中。然后,动态链接程序将遍历链接映射并为每个共享对象执行 .init 段。syncrtld 事件(请参见syncrtld)发生在这两个阶段之间。

过程链接表

过程链接表(Procedure linkage table,PLT)是 rtld 为了实现跨共享对象边界调用所使用的结构。例如,对 printf 的调用便会通过这个间接表。可以在通用及处理器特定 SVR4 ABI 参考手册中找到对这一过程的详细说明。

要使 dbx 能够在各 PLT 中处理 stepnext 命令,它必须记录每个装入对象的 PLT 表。表信息的获得与 rtld 握手同时进行。

修复并继续

要将修复并继续用于通过 dlopen() 装入的共享对象,需要更改这些共享对象的打开方式,这样修复并继续才能正常运行。使用模式 RTLD_NOW|RTLD_GLOBALRTLD_LAZY|RTLD_GLOBAL

在共享库中设置断点

为了在共享库中设置断点,dbx 需要了解程序将在运行时使用该库,并且 dbx 需要为该库装入符号表。为了确定新装入的程序在运行时将使用哪些库,dbx 会将该程序执行足够长的时间,以便运行时链接程序装入所有启动库。然后,dbx 会读入已装入库的列表并终止进程。库会保持装入状态,这样便可以在重新运行程序进行调试前于库中设置断点。

无论程序是在命令行使用 dbx 命令装入,还是在 dbx 提示符处使用 debug 命令装入,抑或在 IDE 中装入,dbx 都会按相同的步骤装入库。

在显式装入的库中设置断点

dbx 会自动检测发生了 dlopen() 还是 dlclose(),然后装入装入对象的符号表。使用 dlopen() 装入共享对象后,即可在其中设置断点,然后像对待程序的任何部分一样进行调试。

如果共享对象是使用 dlclose() 卸下的,dbx 会记住其中设置的断点,并在使用 dlopen() 再次装入该共享对象时替换这些断点,即便应用程序再次运行也是如此。

但如果要在其中设置断点,或导航其函数和源代码,就不必等待使用 dlopen() 装入共享对象。如果知道正被调试的程序将使用 dlopen() 装入的共享对象的名称,可以使用 loadobject -load 命令请求 dbx 预装其符号表:


loadobject -load /usr/java1.1/lib/libjava_g.so

现在便可在此装入对象被 dlopen() 装入前在其中导航模块和函数及设置断点。程序装入装入对象后,dbx 即会自动设置断点。

在动态链接库中设置断点受以下限制: