How to Automatically Generate Stack Traces for Segmentation Faults in Linux Programs


1 views

When a Linux program crashes with a segmentation fault, the default behavior is far from helpful:

$ ./buggy_app
Segmentation fault (core dumped)

While this tells us that a crash occurred, it doesn't show where or why. Let's explore several professional-grade solutions to automatically capture stack traces.

For programs you control, the most robust solution is to build in stack trace functionality using glibc's backtrace features. Here's a complete implementation:

#include <execinfo.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void print_trace(int sig) {
    void *array[50];
    size_t size;
    char **strings;
    size_t i;

    size = backtrace(array, 50);
    strings = backtrace_symbols(array, size);

    fprintf(stderr, "Received signal %d:\n", sig);
    for(i = 0; i < size; i++) {
        fprintf(stderr, "%s\n", strings[i]);
    }

    free(strings);
    exit(1);
}

int main() {
    signal(SIGSEGV, print_trace);
    signal(SIGABRT, print_trace);
    
    // Your buggy code here
    int *p = NULL;
    *p = 42; // This will segfault
    
    return 0;
}

For existing binaries where you can't modify source code, Linux provides catchsegv:

$ catchsegv ./buggy_program

This utility:

  • Works with any ELF binary
  • Shows backtrace and register states
  • Comes pre-installed on most distributions

For production environments, configure proper core dumps:

# Enable core dumps
ulimit -c unlimited
echo "core.%e.%p" > /proc/sys/kernel/core_pattern

# When crash occurs:
gdb ./buggy_program core.1234
(gdb) bt

For modern development, compile with ASAN for detailed diagnostics:

gcc -fsanitize=address -g buggy_program.c -o buggy_program

ASAN provides:

  • Stack traces on crashes
  • Memory error detection
  • Heap corruption reports
Method Requires Recompile Works on Any Binary Production Ready
GNU backtrace Yes No Yes
catchsegv No Yes Limited
Core dumps No Yes Yes
ASAN Yes No Development Only



When a Linux program crashes with a segmentation fault, the default behavior is far from helpful:


$ ./buggy_program
Segmentation fault (core dumped)


This leaves developers guessing about the exact location and context of the crash. What we really want is immediate stack trace information:


Segfault at 0x7ffd4263a000 in function process_data() at src/core.c:42
Backtrace:
#0  0x00005555555551a9 in process_data (ptr=0x0) at src/core.c:42
#1  0x000055555555525b in main (argc=1, argv=0x7ffd4263a150) at src/main.c:89




First, ensure your system can generate core dumps:


ulimit -c unlimited
echo "core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern


For persistent configuration, add to /etc/security/limits.conf:


*               soft    core            unlimited




Create a wrapper script called 'debugrun':


#!/bin/bash
gdb -batch -ex "run" -ex "bt" --args "$@"


Usage:


$ ./debugrun ./buggy_program arg1 arg2




The glibc utility catchsegv provides stack traces:


$ catchsegv ./buggy_program


For more detailed output including memory maps:


$ catchsegv -v ./buggy_program




For built-in stack traces, add this to your program:


#include <execinfo.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void handler(int sig) {
  void *array[10];
  size_t size;

  size = backtrace(array, 10);
  fprintf(stderr, "Error: signal %d:\n", sig);
  backtrace_symbols_fd(array, size, STDERR_FILENO);
  exit(1);
}

int main() {
  signal(SIGSEGV, handler);
  // Your program logic here
}


Compile with debug symbols:


gcc -g -rdynamic -o program program.c




The glibc library includes a special loader:


$ LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so ./buggy_program


Or for more detailed output:


$ SEGFAULT_SIGNALS="all" LD_PRELOAD=libSegFault.so ./buggy_program




For all future crashes system-wide, create /etc/sysctl.d/10-coredump.conf:


kernel.core_pattern = /var/coredumps/core.%e.%p.%h.%t
kernel.core_uses_pid = 1
fs.suid_dumpable = 2


Then enable with:


sudo sysctl -p /etc/sysctl.d/10-coredump.conf