Previous Next Contents Index Doc Set Home


dbx and the Dynamic Linker

19


dbx provides full debugging support for programs that use dynamically-linked, shared libraries, provided that the libraries are compiled using the -g option.

This chapter is organized into the following sections:

Basic Concepts

page 223

Debugging Support for Shared Objects

page 224

Setting a Breakpoint in a Dynamically Linked Library

page 226


Basic Concepts

The dynamic linker, also known as rtld, RunTime ld, or ld.so, arranges to bring shared objects (load objects) into an executing application. There are two primary areas where rtld is active:

1. Program startup

At program startup, rtld runs first and dynamically loads all shared objects specified at link time. These are preloaded shared objects and commonly include libc.so, libC.so, and libX.so. (Use ldd(1) to find out what shared objects a program will load.)

2. Application Requests

The application uses the function calls dlopen(3) and dlclose(3) to dynamically load and unload shared objects or executables. dbx uses the term load objects to refer to a shared object (.so) or executable (a.out).

The dynamic linker maintains a list of all loaded objects in a list called a link map, which maintained in user memory, and is indirectly accessed through libthread_db.so, a special system library for thread debugging.

dbx traverses the link map to see:

Corruption of these data structures can at times confuse dbx.


Debugging Support for Shared Objects

dbx can debug shared objects, both preloaded and those opened with dlopen(). Some restrictions and limitations are described in the following sections.

Startup Sequence

To put breakpoints in preloaded shared objects, the address of the routines has to be known to dbx. For dbx to know the address of the routines, it must know the shared object base address. Doing something as simple as:

stop in printf
run

requires special consideration by dbx. Whenever you load a new program, dbx automatically executes the program up to the point where rtld has completed construction of the link map. dbx then reads the link map and stores the base addresses. After that, the process is killed and you see messages and the prompt. These dbx tasks are completed silently.

At this point, the symbol table for libc.so is available as well as its base load address. Therefore, the address of printf is known.

The activity of dbx waiting for rtld to construct the link map and accessing the head of the link map is known as the rtld handshake. The event syncrtld occurs when rtld is done with the link map and dbx has read all of the symbol tables.

With this scheme, dbx depends on the fact that when the program is rerun, the shared libraries are loaded at the same base address. The assumption that shared libraries are loaded at the same base address is seldom violated; usually only if you change LD_LIBRARY_PATH between loading of the program and running it. In such cases, dbx takes note of the new address and prints a message. However, breakpoints in the moved shared object may be incorrect.

Startup Sequence and .init Sections

A .init section is a piece of code belonging to a shared object that is executed when the shared object is loaded. For example, the .init section is used by the C++ runtime system to call all static initializers in a .so.

The dynamic linker first maps in all the shared objects, putting them on the link map. Then, the dynamic linker traverses the link map and executes the .init section for each shared object.

dlopen() and dlclose()

dbx automatically detects that a dlopen or a dlclose has occurred and loads the symbol table of the loaded object. You can put breakpoints in and debug the loaded object like any part of your program.

When a shared object is unloaded, the symbol table is discarded and the breakpoints are marked as "(defunct)" when you request status. There is no way to automatically re-enable the breakpoints if the object is opened again on a consecutive run.

Two events, dlopen and dlclose, can be used with the when command and some shell programming, to help ease the burden of managing breakpoints in dlopen type shared objects.

fix and continue

Using fix and continue with shared objects requires a change in how they are opened in order for fix and continue to work correctly. Use mode RTLD_NOW|RTLD_GLOBAL or RTLD_LAZY|RTLD_GLOBAL.

Procedure Linkage Tables (PLT)

PLTs are structures used by the rtld to facilitate calls across shared object boundaries. For instance, the call to printf goes via this indirect table. The details of how this is done can be found in the generic and processor specific SVR4 ABI reference manuals.

For dbx to handle step and next commands across PLTs, it has to keep track of the PLT table of each load object. The table information is acquired at the same time as the rtld handshake.


Setting a Breakpoint in a Dynamically Linked Library

dbx provides full debugging support for code that makes use of the programmatic interface to the run-time linker; that is, code that calls dlopen(), dlclose() and their associated functions. The run-time linker binds and unbinds shared libraries during program execution. Debugging support for dlopen()/dlclose() allows you to step into a function or set a breakpoint in functions in a dynamically shared library just as you can in a library linked when the program is started.

Three Exceptions




Previous Next Contents Index Doc Set Home