Linker and Libraries Guide

Debugger Module

The debugger module provides a set of dcmds and walkers that can be loaded under mdb(1). This module can be 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 release to release. However, some elements of these data structures reveal the basic components of a dynamically linked process and may aid general debugging.

The following examples show some simple scenarios of using mdb(1) with the runtime linker debugger module.


$ 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. -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 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
  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 Rt_map               - Display ld.so.1 Rt_map structure
  dcmd Rt_maps              - Display list of Rt_map structures
  walk List                 - Walk a List
  walk Rt_maps              - Walk a List of Rt_maps
> ::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
Link-map lists (dynlm_list): 0xffbfe0d0
----------------------------------------------
  Lm_list: 0xff3f6f60  (LM_ID_BASE)
  ----------------------------------------------
    Link-map*  ADDR()     NAME()
    ----------------------------------------------
    0xff3f9040 0x00010000 main
    0xff3f9460 0xff3b0000 /lib/libdl.so.1
    0xff3f977c 0xff280000 /lib/libc.so.1
  ----------------------------------------------
  Lm_list: 0xff3f6f88  (LM_ID_LDSO)
  ----------------------------------------------
    0xff3f8cc0 0xff3c0000 /lib/ld.so.1

An individual link-map can be displayed with Rt_map.


> 0xff3f9040::Rt_map
Rt_map located at: 0xff3f9040
     NAME: 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
    .....

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


> 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) 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. A deferred break point instructs the debugger to set a real breakpoint when the dynamic object is loaded.


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

At this point, new objects have been loaded:


> *ld.so`lml_main::Rt_maps
Link-map*  ADDR()     NAME()
----------------------------------------------
0xff3f9040 0x00010000 main
0xff3f9460 0xff3b0000 /lib/libdl.so.1
0xff3f977c 0xff280000 /lib/libc.so.1
0xff3f9ca4 0xff380000 ./foo.so.1
0xff37006c 0xff260000 ./bar.so.1

The link-map for foo.so.1 shows the handle returned by dlopen(3DL). You can expand this structure using 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 ]

The dependencies of a handle are a list of link-maps that represent the objects of the handle that can satisfy a dlsym(3DL) request. In this case, the dependencies are foo.so.1 and bar.so.1.


Note –

The above examples provide a basic guide to the debugger module capabilities, but the exact commands, usage, and output may change from release to release. Refer to usage and help information for the exact capabilities available on your system.