Linker and Libraries Guide

Debugging Facility

The runtime linker provides a debugging facility that allows you to trace the runtime linking of applications and their dependencies in detail. The type of information that is displayed by using this facility is expected to remain constant. However, the exact format of the information might change slightly from release to release.

Some of the debugging output might be unfamiliar to users who do not have an intimate knowledge of the runtime linker. However, many aspects might be of general interest to you.

Debugging is enabled by using the environment variable LD_DEBUG. All debugging output is prefixed with the process identifier. This environment variable must be augmented with one or more tokens to indicate the type of debugging that is required.

The tokens that are available with LD_DEBUG can be displayed by using LD_DEBUG=help.


$ LD_DEBUG=help prog

prog can be any dynamic executable. The process is terminated following the display of the help information, before control transfers to prog. The choice of executable is unimportant.

By default, all debug output is sent to stderr, the standard error output file. Debug output can be directed to a file instead, using the output token. For example, the help text can be captured in a file named rtld-debug.txt.


$ LD_DEBUG=help,output=rtld-debug.txt prog

Alternatively, debug output can be redirected by setting the environment variable LD_DEBUG_OUTPUT. When LD_DEBUG_OUTPUT is used, the process identifier is added as a suffix to the output filename.

If LD_DEBUG_OUTPUT and the output token are both specified, LD_DEBUG_OUTPUT takes precedence. If LD_DEBUG_OUTPUT and the output token are both specified, LD_DEBUG_OUTPUT takes precedence. Use of the output token with programs that call fork(2) result in each process writing debug output to the same file. The debug output will become jumbled and incomplete. LD_DEBUG_OUTPUT should be used in such cases to direct debug output for each process to a unique file.

The debugging of secure applications is not allowed.

One of the most useful debugging options is to display the symbol bindings that occur at runtime. The following example uses a very trivial dynamic executable that has a dependency on two local shared objects.


$ cat bar.c
int bar = 10;
$ cc -o bar.so.1 -K pic -G bar.c
 
$ cat foo.c
int foo(int data)
{
        return (data);
}
$ cc -o foo.so.1 -K pic -G foo.c
 
$ cat main.c
extern  int     foo();
extern  int     bar;
 
int main()
{
        return (foo(bar));
}
$ cc -o prog main.c -R/tmp:. foo.so.1 bar.so.1

The runtime symbol bindings can be displayed by setting 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: .......

The symbol bar, which is required by an immediate relocation, is bound before the application gains control. Whereas the symbol foo, which is required by a lazy relocation, is bound after the application gains control on the first call to the function. This relocation demonstrates the default mode of lazy binding. If the environment variable LD_BIND_NOW is set, all symbol bindings occur before the application gains control.

By setting LD_DEBUG=bindings,detail, additional information regarding the real and relative addresses of the actual binding locations is provided.

You can use LD_DEBUG to display the various search paths used. For example, the search path mechanism used to locate any dependencies can be displayed by setting LD_DEBUG=libs.


$ LD_DEBUG=libs prog
11775:
11775: find object=foo.so.1; searching
11775:  search path=/tmp:.  (RUNPATH/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:.  (RUNPATH/RPATH from file prog)
11775:  trying path=/tmp/bar.so.1
11775:  trying path=./bar.so.1
11775: .......

The runpath recorded in the application prog affects the search for the two dependencies foo.so.1 and bar.so.1.

In a similar manner, the search paths of each symbol lookup can be displayed by setting LD_DEBUG=symbols. A combination of symbols and bindings produces a complete picture of the symbol relocation process.


$ 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: .......

In the previous example, the symbol bar is not searched for in the application prog. This omission of a data reference lookup is due to an optimization used when processing copy relocations. See Copy Relocations for more details of this relocation type.