Chapter 5. Debugging

Useful, well-written software generally goes through several different phases of application development, allowing ample opportunity for mistakes to be made. Some phases come with their own set of mechanisms to detect errors. For example, during compilation an elementary semantic analysis is often performed to make sure objects, such as variables and functions, are adequately described.
The error-checking mechanisms performed during each application development phase aims to catch simple and obvious mistakes in code. The debugging phase helps to bring more subtle errors to light that fell through the cracks during routine code inspection.

5.1. ELF Executable Binaries

Red Hat Enterprise Linux uses ELF for executable binaries, shared libraries, or debuginfo files. Within these debuginfo ELF files, the DWARF format is used. Version 3 of DWARF is used in ELF files (that is, gcc -g is equivalent to gcc -gdwarf-3). DWARF debuginfo includes:
  • names of all the compiled functions and variables, including their target addresses in binaries
  • source files used for compilation, including their source line numbers
  • local variables location

Important

STABS is occasionally used with UNIX. STABS is an older, less capable format. Its use is discouraged by Red Hat. GCC and GDB support STABS production and consumption on a best effort basis only.
Within these ELF files, the GCC debuginfo level is also used. The default is level 2, where macro information is not present; level 3 has C/C++ macro definitions included, but the debuginfo can be very large with this setting. The command for the default gcc -g is the same as gcc -g2. To change the macro information to level three, use gcc -g3.
There are multiple levels of debuginfo available. Use the command readelf -WS file to see which sections are used in a file.

Table 5.1. debuginfo levels

Binary State
Command
Notes
Stripped
strip file
or
gcc -s -o file
Only the symbols required for runtime linkage with shared libraries are present.
ELF section in use: .dynsym
ELF symbols
gcc -o file
Only the names of functions and variables are present, no binding to the source files and no types.
ELF section in use: .symtab
DWARF debuginfo with macros
gcc -g -o file
The source file names and line numbers are known, including types.
ELF section in use: .debug_*
DWARF debuginfo with macros
gcc -g3 -o file
Similar to gcc -g but the macros are known to GDB.
ELF section in use: .debug_macro

Note

GDB never interprets the source files, it only displays them as text. Use gcc -g and its variants to store the information into DWARF.
Compiling a program or library with gcc -rdynamic is discouraged. For specific symbols, use gcc -Wl, --dynamic-list=... instead. If gcc -rdynamic is used, the strip command or -s gcc option have no effect. This is because all ELF symbols are kept in the binary for possible runtime linkage with shared libraries.
ELF symbols can be read by the readelf -s file command.
DWARF symbols are read by the readelf -w file command.
The command readelf -wi file is a good verification of debuginfo, compiled within your program. The commands strip file or gcc -s are commonly accidentally executed on the output during various compilation stages of the program.
The readelf -w file command can also be used to show a special section called .eh_frame with a format and purpose is similar to the DWARF section .debug_frame. The .eh_frame section is used for runtime C++ exception resolution and is present even if -g gcc option was not used. It is kept in the primary RPM and is never present in the debuginfo RPMs.
Debuginfo RPMs contain the sections .symtab and .debug_*. Neither .eh_frame, .eh_frame_hdr, nor .dynsym are moved or present in debuginfo RPMs as those sections are needed during program runtime.