链接程序和库指南

调试帮助

Solaris 链接程序附带有调试库和 mdb(1) 模块。使用调试库,可以更详细地跟踪运行时链接过程。使用 mdb(1) 模块,可以进行交互式进程调试。

调试库

此调试库有助于了解或调试应用程序和依赖项的执行。使用此库显示的信息类型应保持不变。不过,信息的确切格式可能随发行版的不同而有所变化。

不了解运行时链接程序的用户可能不熟悉某些调试输出。不过,也许您希望大概了解其中许多方面。

可使用环境变量 LD_DEBUG 来启用调试。所有调试输出都使用进程标识符作为前缀,并且在缺省情况下会指示为标准错误。必须使用一个或多个标记来扩充此环境变量,以指示所需调试的类型。

使用 LD_DEBUG=help,可以显示 LD_DEBUG 中可用的标记。当进程在显示信息后终止时,可以使用任何动态可执行文件请求此信息。


$ LD_DEBUG=help prog

11693:

11693:           For debugging the runtime linking of an application:

11693:                  LD_DEBUG=token1,token2  prog

11693:           enables diagnostics to the stderr.  The additional

11693:           option:

11693:                  LD_DEBUG_OUTPUT=file

11693:           redirects the diagnostics to an output file created

11593:           using the specified name and the process id as a

11693:           suffix.  All diagnostics are prepended with the

11693:           process id.

11693:

11693:

11693: audit     display runtime link-audit processing

11693: basic     provide basic trace information/warnings

11693: bindings  display symbol binding; detail flag shows

11693:             absolute:relative addresses

11693: cap       display hardware/software capability processing

11693: detail    provide more information in conjunction with other

11693:             options

11693: files     display input file processing (files and libraries)

11693: help      display this help message

11693: init      display init and fini processing

11693: libs      display library search paths

11693: move      display move section processing

11693: reloc     display relocation processing

11693: symbols   display symbol table processing

11693: tls       display TLS processing info

11693: unused    display unused/unreferenced files

11693: versions  display version processing

此示例显示对运行时链接程序有意义的选项。确切选项可能随发行版的不同而有所变化。

环境变量 LD_DEBUG_OUTPUT 可用来指定使用输出文件来代替标准错误。进程标识符将作为后缀添加到输出文件。

对于安全的应用程序,不允许进行调试。

其中一个最有用的调试选项是显示运行时进行的符号绑定。以下示例使用很简单的动态可执行文件,该可执行文件依赖于两个局部共享库。


$ cat bar.c

int bar = 10;

$ cc -o bar.so.1 -K pic -G bar.c

 

$ cat foo.c

foo(int data)

{

        return (data);

}

$ cc -o foo.so.1 -K pic -G foo.c

 

$ cat main.c

extern  int     foo();

extern  int     bar;

 

main()

{

        return (foo(bar));

}

$ cc -o prog main.c -R/tmp:. foo.so.1 bar.so.1

通过设置 LD_DEBUG=bindings,可以显示运行时符号绑定。


$ LD_DEBUG=bindings prog

11753: .......

11753: binding file=prog to file=./bar.so.1: symbol bar

11753: .......

11753: transferring control: prog

11753: .......

11753: binding file=prog to file=./foo.so.1: symbol foo

11753: .......

符号 bar 是即时重定位所需的,将在应用程序获取控制权之前绑定。然而,符号 foo 是延迟重定位所需的,将在应用程序获得第一次调用函数的控制权之后绑定。此重定位说明了延迟绑定的缺省模式。如果设置了环境变量 LD_BIND_NOW,则所有符号绑定都会在应用程序获取控制权之前进行。

通过设置 LD_DEBUG=bindings,detail,可提供有关实际绑定位置的实际地址和相对地址的其他信息。

当运行时链接程序执行函数重定位时,将重写与函数 .plt 关联的数据。通过 .plt 进行的后续调用将直接转至该函数。环境变量 LD_BIND_NOT 可设置为任何值以免更新此数据。通过将此变量与对详细绑定的调试请求一起使用,可以全盘了解所有函数绑定的运行时情况。此组合可能会产生大量输出,从而导致应用程序性能下降。

可以使用 LD_DEBUG 来显示使用的各个搜索路径。例如,通过设置 LD_DEBUG=libs,可以显示用于查找所有依赖项的搜索路径机制。


$ LD_DEBUG=libs prog

11775:

11775: find object=foo.so.1; searching

11775:  search path=/tmp:.  (RPATH from file prog)

11775:  trying path=/tmp/foo.so.1

11775:  trying path=./foo.so.1

11775:

11775: find object=bar.so.1; searching

11775:  search path=/tmp:.  (RPATH from file prog)

11775:  trying path=/tmp/bar.so.1

11775:  trying path=./bar.so.1

11775: .......

应用程序 prog 中记录的运行路径将影响两个依赖项 foo.so.1bar.so.1 的搜索。

同样,可通过设置 LD_DEBUG=symbols 来显示每个符号查找的搜索路径。组合使用 symbolsbindings 可生成符号重定位进程的完整信息。


$ LD_DEBUG=bindings,symbols prog

11782: .......

11782: symbol=bar;  lookup in file=./foo.so.1  [ ELF ]

11782: symbol=bar;  lookup in file=./bar.so.1  [ ELF ]

11782: binding file=prog to file=./bar.so.1: symbol bar

11782: .......

11782: transferring control: prog

11782: .......

11782: symbol=foo;  lookup in file=prog  [ ELF ]

11782: symbol=foo;  lookup in file=./foo.so.1  [ ELF ]

11782: binding file=prog to file=./foo.so.1: symbol foo

11782: .......

在前面的示例中,未在应用程序 prog 中搜索符号 bar。省略数据引用查找是因为在处理复制重定位时使用了优化。有关此重定位类型的更多详细信息,请参见复制重定位

调试器模块

调试器模块提供了一组可在 mdb(1) 下装入的 dcmdswalkers。此模块可用于检查运行时链接程序的各种内部数据结构。许多调试信息都要求您熟悉运行时链接程序的内部构造,并且该信息会随发行版的不同而有所变化。但是,这些数据结构中的某些元素显示了动态链接进程的基本组件,有助于进行一般调试。

以下示例显示了一些将 mdb(1) 与运行时链接程序调试器模块一起使用的简单情况。


$ cat main.c

#include  <dlfnc.h>



int main()

{

        void *  handle;

        void (* fptr)();



        if ((handle = dlopen("foo.so.1", RTLD_LAZY)) == NULL)

                return (1);



        if ((fptr = (void (*)())dlsym(handle, "foo")) == NULL)

                return (1);



        (*fptr)();

        return (0);

}

$ cc -o main main.c -R.

如果 mdb(1) 尚未自动装入调试器模块 ld.so,则显式装入该模块。之后可以检查调试器模块的功能。


$ mdb main

> ::load ld.so

> ::dmods -l ld.so



ld.so

-----------------------------------------------------------------

  dcmd Bind                 - Display a Binding descriptor

  dcmd Callers              - Display Rt_map CALLERS binding descriptors

  dcmd Depends              - Display Rt_map DEPENDS binding descriptors

  dcmd ElfDyn               - Display Elf_Dyn entry

  dcmd ElfEhdr              - Display Elf_Ehdr entry

  dcmd ElfPhdr              - Display Elf_Phdr entry

  dcmd Groups               - Display Rt_map GROUPS group handles

  dcmd GrpDesc              - Display a Group Descriptor

  dcmd GrpHdl               - Display a Group Handle

  dcmd Handles              - Display Rt_map HANDLES group descriptors

  ....

> ::bp main

> :r

进程中的每个动态库都表示为链接映射 Rt_map,该映射在链接映射列表中对其进行维护。可使用 Rt_maps 显示进程的所有链接映射。


> ::Rt_maps

Link-map lists (dynlm_list): 0xffbfe0d0

----------------------------------------------

  Lm_list: 0xff3f6f60  (LM_ID_BASE)

  ----------------------------------------------

    lmco        rtmap       ADDR()     NAME()

    ----------------------------------------------

    [0xc]       0xff3f0fdc 0x00010000 main

    [0xc]       0xff3f1394 0xff280000 /lib/libc.so.1

  ----------------------------------------------

  Lm_list: 0xff3f6f88  (LM_ID_LDSO)

  ----------------------------------------------

    [0xc]       0xff3f0c78 0xff3b0000 /lib/ld.so.1

可使用 Rt_map 显示单个链接映射。


> 0xff3f9040::Rt_map

Rt_map located at: 0xff3f9040

     NAME: main

 PATHNAME: /export/home/user/main

     ADDR: 0x00010000         DYN: 0x000207bc

     NEXT: 0xff3f9460        PREV: 0x00000000

      FCT: 0xff3f6f18    TLSMODID:          0

     INIT: 0x00010710        FINI: 0x0001071c

   GROUPS: 0x00000000     HANDLES: 0x00000000

  DEPENDS: 0xff3f96e8     CALLERS: 0x00000000

    .....

可使用 ElfDyn dcmd 显示目标文件的 .dynamic 节。以下示例显示了前 4 项。


> 0x000207bc,4::ElfDyn

Elf_Dyn located at: 0x207bc

    0x207bc  NEEDED       0x0000010f

Elf_Dyn located at: 0x207c4

    0x207c4  NEEDED       0x00000124

Elf_Dyn located at: 0x207cc

    0x207cc  INIT         0x00010710

Elf_Dyn located at: 0x207d4

    0x207d4  FINI         0x0001071c

mdb(1) 在设置推迟断点时也很有用。在此示例中,函数 foo() 中的断点可能会很有用。但是,在对 foo.so.1 执行 dlopen(3C) 之前,调试器不知道此符号。推迟断点会指示调试器在装入动态库时设置实际断点。


> ::bp foo.so.1`foo

> :c

> mdb: You've got symbols!

> mdb: stop at foo.so.1`foo

mdb: target stopped at:

foo.so.1`foo:   save      %sp, -0x68, %sp

此时,已经装入了新目标文件:


> *ld.so`lml_main::Rt_maps

lmco    rtmap       ADDR()     NAME()

----------------------------------------------

[0xc]   0xff3f0fdc 0x00010000 main

[0xc]   0xff3f1394 0xff280000 /lib/libc.so.1

[0xc]   0xff3f9ca4 0xff380000 ./foo.so.1

[0xc]   0xff37006c 0xff260000 ./bar.so.1

foo.so.1 的链接映射显示了 dlopen(3C) 返回的句柄。可使用 Handles 来扩展此结构。


> 0xff3f9ca4::Handles -v

HANDLES for ./foo.so.1

----------------------------------------------

  HANDLE: 0xff3f9f60 Alist[used 1: total 1]

    ----------------------------------------------

    Group Handle located at: 0xff3f9f28

    ----------------------------------------------

        owner:               ./foo.so.1

        flags: 0x00000000    [ 0 ]

       refcnt:          1    depends: 0xff3f9fa0 Alist[used 2: total 4]

        ----------------------------------------------

        Group Descriptor located at: 0xff3f9fac

           depend: 0xff3f9ca4    ./foo.so.1

            flags: 0x00000003    [ AVAIL-TO-DLSYM,ADD-DEPENDENCIES ]

        ----------------------------------------------

        Group Descriptor located at: 0xff3f9fd8

           depend: 0xff37006c    ./bar.so.1

            flags: 0x00000003    [ AVAIL-TO-DLSYM,ADD-DEPENDENCIES ]

句柄的依赖项由一组链接映射组成,这些链接映射表示可满足 dlsym(3C) 请求的句柄的目标文件。在此情况下,依赖项为 foo.so.1bar.so.1


注 –

前面的示例提供了调试器模块功能的基本指南,但确切的命令、用法和输出可能会随发行版的不同而有所变化。有关系统中可用的确切功能,请参阅用法和帮助信息。