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 the
debugging information requires familiarity with the internals of the
runtime linker. These internals can change from release to release.
However, some elements of these data structures reveal the basic
components of a dynamically linked process and can aid general
debugging.
The following examples show some simple scenarios of using
mdb
(1) with the 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.
If
mdb
(1) has not automatically loaded the
debugger module, ld.so
, explicitly do so. The
facilities 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 .... > ::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)
----------------------------------------------
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
An individual link-map can be displayed with
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
....
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, a break point on the
function foo
() might be useful. However, until
the
dlopen
(3C) 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
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
The link-map for foo.so.1
shows the handle
returned by
dlopen
(3C). 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
(3C) request. In this case, the
dependencies are foo.so.1
and
bar.so.1
.
Note:
The previous examples provide a basic guide to the debugger module facilities, but the exact commands, usage, and output can change from release to release. Refer to the usage and help information frommdb
(1) for the exact facilities
that are available on your system.