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