What is a Core Dump?
When a signal causes a process to crash, the Linux kernel can save a snapshot of the entire process memory to a file on disk. This file is called a core dump (or core file). A debugger like gdb can later load this file and show you exactly what the program was doing at the moment it crashed — which variables had which values, where in the code it was, what the call stack looked like.
The word core comes from old magnetic core memory technology used in early computers. The name stuck even though modern machines use RAM.
A core dump is your most powerful debugging tool when a program crashes in production where you cannot attach a debugger directly.
Which Signals Cause a Core Dump?
Not all signals create a core dump. Only specific signals do so — they are listed in Table 20-1 of TLPI. Common ones you will see in practice:
| Signal | Default Action | Typical Cause |
|---|---|---|
| SIGQUIT | Core dump + terminate | User types Ctrl+\ in terminal |
| SIGABRT | Core dump + terminate | abort() called in program |
| SIGSEGV | Core dump + terminate | Invalid memory access (null pointer, buffer overflow) |
| SIGBUS | Core dump + terminate | Bus error (misaligned memory access) |
| SIGFPE | Core dump + terminate | Floating point / integer divide-by-zero |
| SIGILL | Core dump + terminate | Illegal CPU instruction executed |
Trying It Out: Generating a Core Dump
By default, most Linux distributions set the core dump size limit to 0 (disabled). You must first enable it with ulimit.
## Step 1: Check current core dump size limit
$ ulimit -c
0 <-- 0 means core dumps are DISABLED
## Step 2: Enable unlimited core dumps (in current shell only)
$ ulimit -c unlimited
## Step 3: Run a program and force it to crash with SIGQUIT
$ sleep 30
## Press Ctrl+\
Quit (core dumped)
## Step 4: Inspect the core file created
$ ls -lh core
-rw------- 1 ravi ravi 252K Jun 1 10:00 core
## Step 5: Load into gdb to analyse
$ gdb /bin/sleep core
(gdb) bt <-- show backtrace (call stack at crash time)
ulimit -c unlimited only applies to the current shell session. To make it permanent, add it to your ~/.bashrc or /etc/security/limits.conf.Example 1: Program That Forces a Core Dump
The simplest way to force a core dump from inside your program is to call abort() or raise SIGABRT. This is useful for assertion failures or unrecoverable errors.
/* core_demo.c - Demonstrates core dump with abort() */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void check_value(int x) {
if (x < 0) {
fprintf(stderr, "Fatal: negative value %d, dumping core\n", x);
abort(); /* sends SIGABRT, causes core dump */
}
}
int main(void) {
int arr[5] = {10, 20, -5, 40, 50};
for (int i = 0; i < 5; i++) {
printf("Checking arr[%d] = %d\n", i, arr[i]);
check_value(arr[i]);
}
return 0;
}
## Build and run
$ gcc -g core_demo.c -o core_demo # -g adds debug symbols
$ ulimit -c unlimited
$ ./core_demo
Checking arr[0] = 10
Checking arr[1] = 20
Checking arr[2] = -5
Fatal: negative value -5, dumping core
Aborted (core dumped)
## Debug the crash
$ gdb ./core_demo core
(gdb) bt
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 __GI_abort () at abort.c:79
#2 check_value (x=-5) at core_demo.c:8
#3 main () at core_demo.c:16
GDB shows exactly which function called abort and the full call stack. This is invaluable in production debugging.
Example 2: SIGSEGV Core Dump (Null Pointer)
/* sigsegv_demo.c - Classic null pointer dereference */
#include <stdio.h>
int main(void) {
int *ptr = NULL;
printf("About to dereference a null pointer...\n");
*ptr = 42; /* This causes SIGSEGV */
printf("This line is never reached\n");
return 0;
}
$ gcc -g sigsegv_demo.c -o sigsegv_demo
$ ulimit -c unlimited
$ ./sigsegv_demo
About to dereference a null pointer...
Segmentation fault (core dumped)
$ gdb ./sigsegv_demo core
(gdb) bt
#0 main () at sigsegv_demo.c:7
(gdb) info locals
ptr = 0x0 <-- gdb shows ptr is NULL
Example 3: Programmatic Core Dump with prctl()
For set-user-ID programs, core dumps are suppressed by default for security reasons. The prctl() system call with PR_SET_DUMPABLE can re-enable it.
/* prctl_dumpable.c - Re-enable core dumps for set-uid process */
#include <stdio.h>
#include <stdlib.h>
#include <sys/prctl.h>
int main(void) {
/* Check current dumpable flag */
int dumpable = prctl(PR_GET_DUMPABLE);
printf("Current dumpable flag: %d\n", dumpable);
/* Set dumpable = 1 so core dump is produced even if
this is a set-uid program running as another user */
if (prctl(PR_SET_DUMPABLE, 1) == -1) {
perror("prctl PR_SET_DUMPABLE");
exit(EXIT_FAILURE);
}
printf("Dumpable flag set to 1\n");
/* Now trigger a crash — core will be produced */
raise(SIGQUIT);
return 0;
}
$ gcc -g prctl_dumpable.c -o prctl_dumpable
$ ulimit -c unlimited
$ ./prctl_dumpable
Current dumpable flag: 1
Dumpable flag set to 1
Quit (core dumped)
When is a Core Dump NOT Produced?
Even when a crash-inducing signal is received, the kernel will skip the core dump under several conditions:
| Condition | Reason |
|---|---|
| Process has no write permission in the directory | Cannot create the file |
| A non-writable file named “core” already exists | Cannot overwrite |
| RLIMIT_CORE resource limit is 0 | Kernel enforces the limit |
| RLIMIT_FSIZE resource limit is 0 | File size limit hit |
| Set-user-ID program run by non-owner | Security: prevents password extraction from memory |
| Binary has no read permission | Prevents indirect read of protected binary |
| Filesystem full or out of inodes | Disk I/O failure |
| File has more than one hard link | Would overwrite linked file |
Controlling Core Dump File Naming
The file /proc/sys/kernel/core_pattern controls the name (and location) of core dump files. By default it contains the string core.
## Check current pattern
$ cat /proc/sys/kernel/core_pattern
core
## Set a richer naming pattern (needs root)
$ echo "core.%e.%p.%t" | sudo tee /proc/sys/kernel/core_pattern
## Now after a crash, the file will be named like:
## core.sleep.12345.1685000000
| Specifier | Replaced With |
|---|---|
| %e | Executable filename (without path) |
| %p | Process ID (PID) of the crashed process |
| %t | Time of crash (seconds since Epoch) |
| %u | Real user ID of the process |
| %g | Real group ID of the process |
| %s | Signal number that caused the crash |
| %h | Hostname of the machine |
| %c | Core file size soft resource limit (bytes) |
| %% | A literal % character |
## Redirect core dumps to a specific directory
$ echo "/var/cores/core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern
## Make sure the directory exists and is writable:
$ sudo mkdir -p /var/cores
$ sudo chmod 1777 /var/cores
## Pipe core dump to a program (kernel 2.6.19+)
## This sends the core to a crash handler program's stdin
$ echo "|/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %e" \
| sudo tee /proc/sys/kernel/core_pattern
systemd-coredump by default. Use coredumpctl list to view them and coredumpctl gdb to debug.Controlling Which Memory Regions Are Dumped
Since kernel 2.6.23, each process has a /proc/PID/coredump_filter file that is a bitmask controlling which memory mappings go into the core dump.
## Check the filter for a running process
$ cat /proc/$$/coredump_filter
00000033
## The bits mean:
## Bit 0 (0x01) - private anonymous mappings (stack, heap) -- usually WANT this
## Bit 1 (0x02) - private file-backed mappings
## Bit 2 (0x04) - shared anonymous mappings (shared memory)
## Bit 3 (0x08) - shared file-backed mappings (mmap'd files)
## Default 0x33 = bits 0,1,4,5 -- dumps anonymous + ELF headers
## Dump EVERYTHING (useful for full diagnosis)
$ echo 0xff > /proc/$$/coredump_filter
/* Set coredump_filter from within a C program */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int set_coredump_filter(unsigned int filter) {
char path[64];
FILE *f;
snprintf(path, sizeof(path), "/proc/%d/coredump_filter", getpid());
f = fopen(path, "w");
if (f == NULL) return -1;
fprintf(f, "%x", filter);
fclose(f);
return 0;
}
int main(void) {
/* Include all anonymous + file-backed mappings */
set_coredump_filter(0x3f);
printf("Core dump filter set. PID=%d\n", getpid());
abort(); /* trigger core dump */
return 0;
}
Interview Questions — Core Dump Files
A core dump is a snapshot of a process’s memory (stack, heap, registers, open file info) saved to disk at the moment a fatal signal is received. It is useful because you can load it into gdb later — even after the process is gone — and inspect variables, the call stack, and the program state at the time of crash. This is essential for debugging crashes in production environments where you cannot attach a debugger live.
The first thing to check is the core dump size limit: ulimit -c. If it shows 0, core dumps are disabled. Run ulimit -c unlimited to enable. Other reasons: the working directory is not writable, the filesystem is full, the process is set-user-ID, or RLIMIT_CORE is set to 0 in /etc/security/limits.conf.
It is a Linux-specific file that controls the filename and location of core dump files. It supports format specifiers: %e (executable name), %p (PID), %t (timestamp). Example: setting it to /var/cores/core.%e.%p.%t saves all core files to /var/cores/ with descriptive names. Since kernel 2.6.19 it can start with | to pipe core data to a program like systemd-coredump.
Security. A set-user-ID program runs with elevated privileges and may have sensitive data (passwords, private keys) in memory. If a malicious user could trigger a crash and read the core file, they could extract that sensitive data. The kernel suppresses core dumps for such programs by default. The prctl(PR_SET_DUMPABLE, 1) call can override this when required for debugging.
Run gdb ./program_binary core_file. Once inside gdb, use bt (backtrace) to see the call stack, info locals to see local variable values, print varname to inspect specific variables, and frame N to switch between stack frames. The binary must have been compiled with -g flag for meaningful symbol information.
It is a per-process bitmask (available since kernel 2.6.23) that controls which types of memory mappings are included in the core dump. Bit 0 covers private anonymous mappings (stack, heap), bit 1 covers private file-backed mappings, bits 2-3 cover shared mappings. The default value (0x33) dumps anonymous mappings which is usually sufficient. Setting it to 0xff includes everything.
Next Topic
Learn about special signal delivery rules for SIGKILL, SIGSTOP, and SIGCONT.
