You are here: Home / Support / HOWTOs / 
2025-10-20 - 19:08
OSADL HOWTOs

HOWTO: Integrate a post-mortem debugger into a user space program

Background

Practically all major causes of a program crash in user space lead to so-called exception processing, whereby the microprocessor is forced to continue its program execution at a previously defined address and terminate the program in such a way that the other currently running processes can continue their work unhindered. As a rule, not only is a single address defined in advance, but different sections of code are programmed for the various causes that lead to exception processing, so that the operating system can react in a typical manner. However, the processor not only continues its program sequence, but a data structure with information on the cause of the exception is also stored on the stack. In the event of an error, this information can be used to reconstruct the crash and, if the program has been compiled with the necessary debug information, can even help to determine the responsible line in the source code. This type of functionality, which enables debugging even after a program has crashed, is known as a post-mortem debugger.

Post-mortem debugger

The post-mortem debugger that is part of the example C program in the provided archive, consists of a signalhandler and a decoder trace_it(). In case of exception processing, the signalhandler calls the decoder that examines the stack frames and prints them out. In particular, the stack frame with the address where the exception was triggered is examined and an attempt is made to retrieve the corresponding source code line. The latter, however, requires that the program was compiled with debug symbols.

Artifical exception trigger

The program also contains an artificial exception trigger crash_it() that can be configured via command line argument:

Command line symbol Exception Signal number
a Invalid address 11
p Privileged instruction 11
i Illegal instruction 11
0 Integer division by 0 8
. Floating point division by 0.0 8
n Square root of a negative number 8

In a real word, however, the trigger function crash_it(), of course, must not be used, but only the signal handler and the stack frame decoder trace_it().

Example of exception processing after trying to access an invaliud address

./backtrace a
Forcing exception handling by dereferencing 0x00000000
Caught signal 11
Stacktrace:
Frame 1: 0x00401373 (./backtrace() [0x401373])
Frame 2: 0x00401481 (./backtrace(signal_handler+0x15) [0x401481])
Frame 3: 0xe775b490 (/lib64/libc.so.6(+0x1a490) [0x7f4be775b490])
Frame 4: 0x00401246 (./backtrace() [0x401246])
Frame 5: 0x004014dd (./backtrace(main+0x52) [0x4014dd])
Frame 6: 0xe7744488 (/lib64/libc.so.6(+0x3488) [0x7f4be7744488])
Frame 7: 0xe774454b (/lib64/libc.so.6(__libc_start_main+0x8b) [0x7f4be774454b])
Frame 8: 0x00401115 (./backtrace(_start+0x25) [0x401115])
Executing
  addr2line -e backtrace 0x00401246
locates the problem
  /usr/src/backtrace/backtrace.c:48

Link to source code archive

An archive with the complete source code and a related Makefile is available online here.

To top