Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
3.  Runtime Linker Debugging Aids Debugging Library  Previous   Contents   Next 
   
 

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 when the function is first called. This demonstrates the default mode of lazy binding. If the environment variable LD_BIND_NOW is set, all symbol bindings will occur before the application gains control.

Setting LD_DEBUG=bindings,detail, provides additional information regarding the real and relative addresses of the actual binding locations.

When the runtime linker performs a function relocation, it rewrites data associated with the functions .plt so that any subsequent calls will go directly to the function. The environment variable LD_BIND_NOT can be set to any value to prevent this data update. By using this variable together with the debugging request for detailed bindings, you can get a complete runtime account of all function binding. The output from this combination can be excessive, in which case the performance of the application will be degraded.

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

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. If this is combined with a bindings request, you can obtain a complete picture of the symbol relocation process.

$ LD_DEBUG=bindings,symbols
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 is due to an optimization used when processing copy relocations. See "Copy Relocations" for more details of this relocation type.

Debugger Module

The debugger module provides a set of dcmds and walkers that can be loaded under mdb(1) and used to inspect various internal data structures of the runtime linker. Much of this information requires familiarity with the internals of the runtime linker, and may change from one release to another. However, some elements of these data structures reveal the basic components of a dynamically linked process and may aid general debugging.

The following example provides some scenarios of how mdb(1) and this debugger module may be used.

$ cat main.c
#include  <dlfnc.h>

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. -ldl

If mdb(1) has not automatically loaded the debugger module, ld.so, explicitly do so. The capabilities of the debugger module can then be inspected.

$ mdb main
> ::load ld.so
> ::dmods -l ld.so

ld.so
-----------------------------------------------------------------
  dcmd Dl_handle            - display Dl_handle structure
  dcmd Dyn                  - display Dynamic entry
  dcmd List                 - display entries in a List
  dcmd ListRtmap            - display a List of Rt_Map's
  dcmd Lm_list              - display ld.so.1 Lm_list structure
  dcmd Permit               - display Permit structure
  dcmd Rt_map               - display ld.so.1 Rt_map structure
  dcmd Rt_maps              - display list of Rt_map structures
  walk List                 - walk List structure
  walk Rt_maps              - walk list of Rt_map structures
> ::bp main
> :r

Each dynamic object within a process is expressed as a link-map, Rt_map, which is maintained on a link-map list. All link-maps for the process can be displayed with Rt_maps.

> ::Rt_maps
Objects on linkmap: <base>
    rtmap*     ADDR       NAME
    ---------------------------------------------
    0xff3b0030 0x00010000 main
    0xff3b0434 0xff3a0000 /usr/lib/libdl.so.1
    0xff3b0734 0xff280000 /usr/lib/libc.so.1
Objects on linkmap: <ld.so.1>
    rtmap*     ADDR       NAME
    ---------------------------------------------
    0xff3f7c68 0xff3c0000 /usr/lib/ld.so.1

An individual link-map can be displayed with Rt_map.

> 0xff3b0030::Rt_map
Rt_map located at: 0xff3b0030
    NAME: main
    ADDR: 0x00010000   DYN: 0x000209d8
    NEXT: 0xff3b0434  PREV: 0x00000000
    .....
    LIST: 0xff3f60cc [ld.so.1`lml_main]

The object's .dynamic section can be displayed with the Dyn dcmd. The following example shows the first 4 entries.

> 0x000209d8,4::Dyn
Dyn located at: 209d8
0x209d8  NEEDED  0x000001d7
Dyn located at: 209e0
0x209e0  NEEDED  0x000001e2
Dyn located at: 209e8
0x209e8  INIT  0x00010870
Dyn located at: 209f0
0x209f0  FINI  0x000108c0

mdb(1) is also very useful for setting deferred break points. In this example it might be useful to put a break point on the function foo(). However, until the dlopen(3DL) of foo.so.1 occurs, this symbol isn't known to the debugger. Setting a deferred break point instructs the debugger to set a real breakpoint when the dynamic object is loaded.

> ::bp foo.so.1`foo
> :r
> mdb: You've got symbols!
> mdb: stop at foo.so.1`foo
mdb: target stopped at:
foo.so.1`foo:   save      %sp, -0x68, %sp
 
 
 
  Previous   Contents   Next