Debugging Linux Applications with Backtrace

Printing the stack trace is a common debugging technique, especially useful when a system encounters an exception. By capturing the stack at the time of the anomaly, it becomes much easier to pinpoint errors.

This article will focus on using backtrace for stack printing. More advanced techniques, such as analyzing core files with gdb, may be explored in future discussions.

Backtrace Stack Printing Method

To enable backtrace functionality, ensure the folllowing compilation flags are used:


CFLAGS ?= -O0 -rdynamic -g -funwind-tables -ffunction-sections
ASFLAGS += -O0

Code Implementation

Below is an example implementation that captures and prints the stack trace upon receiving specific signals.

#include <signal.h>       /* For signal handling */
#include <execinfo.h>     /* For backtrace() */

#define TRACE_BUFFER_SIZE 32

void print_stack_trace(void) {
    int i, count;
    void *trace_buffer[TRACE_BUFFER_SIZE];
    char **symbols;

    printf("Capturing stack trace...\n");

    count = backtrace(trace_buffer, TRACE_BUFFER_SIZE);

    printf("backtrace() captured %d addresses\n", count);

    symbols = backtrace_symbols(trace_buffer, count);
    if (symbols == NULL) {
        perror("backtrace_symbols");
        return;
    }

    for (i = 0; i < count; i++) {
        printf("[%02d] %s\n", i, symbols[i]);
    }

    free(symbols);
}

void handle_signal(int signum) {
    printf("\n=========>>> Caught signal %d <<<=========\n", signum);

    printf("Dumping stack trace...\n");
    print_stack_trace();
    printf("Stack trace dumped.\n");

    // Restore default signal handler and re-raise the signal
    signal(signum, SIG_DFL);
    raise(signum);

    printf("Application exiting...\n");
}

int main(void) {
    signal(SIGABRT, handle_signal);
    signal(SIGBUS, handle_signal);
    signal(SIGSEGV, handle_signal);

    return 0;
}

Execution Result

When the program receives a segmentation fault (signal 11), the output might look like this:


=========>>> Caught signal 11 <<<=========
Dumping stack trace...
Capturing stack trace...
backtrace() captured 7 addresses
[00] ./app-demo() [0xbf6e]
[01] ./app-demo() [0xc086]
[02] [0x2aac6000]
[03] /lib/libc.so.6(memcpy+0x30) [0x2ab516a0]
[04] ./app-demo() [0xbb62]
[05] ./app-demo() [0x9e92]
[06] /lib/libpthread.so.0(+0x61d0) [0x2aacd1d0]
Stack trace dumped.
Application exiting...
Segmentation fault

Analyzing the Output

To map the memory addresses from the stack trace to their respective source code locations, use the addr2line tool:


# addr2line -e app/app-demo 0xbb62
/home/cql/smb/fuxi_h/demo-linux-wjc-20201211/app/main.c:538

This reveals that the issue originates from line 538 of main.c.

Signal Reference

Below is a reference table for some commonly encountered signals in Linux:

Signal Number Description
SIGHUP 1 Terminal hangup or control process termination
SIGINT 2 Keyboard interrupt (e.g., break key)
SIGQUIT 3 Keyboard quit key pressed
SIGILL 4 Illegal instruction
SIGABRT 6 Abort signal from abort(3)
SIGKILL 9 Ultimate kill signal
SIGSEGV 11 Invalid memory reference
SIGPIPE 13 Broken pipe
SIGTERM 15 Termination signal
SIGUSR1 30,10,16 User-defined signal 1
SIGUSR2 31,12,17 User-defined signal 2

Tags: Linux backtrace gdb

Posted on Tue, 23 Jun 2026 17:57:15 +0000 by Madzz