Saat program C crash karena sinyal fatal seperti SIGSEGV (segmentation fault) atau SIGABRT, kernel Linux bisa menyimpan snapshot memori proses ke file yang disebut core dump. File ini berisi seluruh memori proses saat crash, tumpukan pemanggilan fungsi, isi register CPU, dan daftar file yang dipetakan. Dengan file core dan binary yang dikompilasi dengan simbol debug, kita bisa membongkar penyebab crash setelah kejadian—bahkan bila crash baru terjadi sekali dan sulit direproduksi. Pada chapter ini kita akan mengaktifkan core dump via ulimit, membuat program yang crash, memeriksa file core dengan file dan readelf, lalu menganalisisnya dengan addr2line dan (secara konseptual) gdb.
Mengaktifkan Core Dump #
Secara default, banyak distribusi Linux mematikan pembuatan core dump karena ukuran file bisa sangat besar. Dua pengaturan mengendalikan perilaku ini:
ulimit -c <ukuran>: batas ukuran file core dalam blok 512 byte. Nilai0berarti core dimatikan;unlimitedberarti tanpa batas./proc/sys/kernel/core_pattern: template lokasi dan nama file core. Bila diawali karakter|, core disalurkan ke program external (misalnyasystemd-coredump); bila hanyacoreatau path polos, file core ditulis langsung ke direktori kerja.
# Lihat batas saat ini
ulimit -c
# Aktifkan core dump tanpa batas ukuran
ulimit -c unlimited
# Verifikasi
ulimit -c
# Lihat pola lokasi core
cat /proc/sys/kernel/core_patternOutput yang Dihasilkan:
0
unlimited
coreMari kita bedah tiga output di atas:
0(output pertama): batas awal ukuran core adalah0blok—core dump dimatikan. Karakter inilah yang membuat banyak program crash tanpa meninggalkan jejak.unlimited(output kedua): setelahulimit -c unlimited, batas berubah menjadi tak terbatas. Sekarang crash akan menghasilkan file core dengan ukuran penuh sesuai memori proses.core(output ketiga): pola lokasi file core adalahcore, artinya file akan ditulis di direktori kerja proses dengan namacore. Bila nilainya|/usr/lib/systemd/systemd-coredump, core ditangani oleh systemd-coredump dan disimpan di/var/lib/systemd/coredump/.
Program yang Menghasilkan Core Dump #
Kita akan memakai program berikut yang berisi bug use-after-free. Program mengalokasikan sebuah Node di heap, membebaskannya, lalu mencoba membaca field value dari pointer yang sudah tidak valid. Karena pointer kemudian diset ke NULL sebelum dibaca, crash yang terjadi adalah null pointer dereference.
/* File: /tmp/test_core_dump.c */
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int value;
struct Node *next;
} Node;
static Node *buat_node(int v) {
Node *n = (Node *)malloc(sizeof(Node));
if (n) {
n->value = v;
n->next = NULL;
}
return n;
}
static int baca_node_value(Node *n) {
/* Bug: tidak cek n == NULL */
return n->value;
}
int main(void) {
Node *head = buat_node(10);
free(head);
head = NULL;
int v = baca_node_value(head); /* null deref */
printf("v = %d\n", v);
return 0;
}gcc -g -O0 -std=c11 -Wall -Wextra /tmp/test_core_dump.c -o /tmp/test_core_dump
ulimit -c unlimited
cd /tmp && /tmp/test_core_dumpOutput yang Dihasilkan:
Segmentation fault (core dumped)Shell menampilkan pesan Segmentation fault (core dumped) dengan kode keluar 139 (128 + 11, di mana 11 adalah nomor sinyal SIGSEGV). Verifikasi file core telah dibuat:
ls -la /tmp/core
file /tmp/coreOutput yang Dihasilkan:
-rw------- 1 z z 450560 Oct 13 08:04 /tmp/core
/tmp/core: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from '/tmp/test_core_dump', real uid: 1001, effective uid: 1001, real gid: 1001, effective gid: 1001, execfn: '/tmp/test_core_dump', platform: 'x86_64'Ukuran 450560 byte (sekitar 440 KB) adalah ukuran tipikal core dump program kecil. Perintah file mengonfirmasi formatnya ELF core file untuk arsitektur x86-64, lengkap dengan UID dan GID proses pemilik.
Inspeksi Core dengan readelf #
Core dump adalah file ELF dengan tipe ET_CORE. Kita bisa memeriksa isinya menggunakan readelf yang tersedia di hampir semua sistem Linux. Catatan ELF (notes) menyimpan metadata penting seperti sinyal yang menyebabkan crash dan daftar file yang dipetakan ke memori.
readelf --notes --wide /tmp/core | head -10Output yang Dihasilkan:
Displaying notes found at file offset 0x000005b8 with length 0x000034b0:
Owner Data size Description
CORE 0x00000150 NT_PRSTATUS (prstatus structure)
CORE 0x00000088 NT_PRPSINFO (prpsinfo structure)
CORE 0x00000080 NT_SIGINFO (siginfo_t data)
CORE 0x00000150 NT_AUXV (auxiliary vector)
CORE 0x0000037b NT_FILE (mapped files)Mari kita uraikan tipe catatan utama pada output readelf di atas:
NT_PRSTATUS: berisi strukturprstatusyang menyimpan nilai register CPU (RIP, RSP, RBP, dst.) pada saat crash. Catatan ini adalah sumber utama alamat instruksi yang menyebabkan crash.NT_PRPSINFO: informasi proses seperti PID, PPID, command line, dan nama user.NT_SIGINFO: struktursiginfo_tyang menjelaskan sinyal: nomor sinyal (SIGSEGV= 11), kode (SEGV_MAPERR= akses ke halaman tidak terpetakan), dan alamat yang diakses.NT_AUXV: vektor auxiliary yang dipakai dynamic linker saat proses dimuat.NT_FILE: daftar file yang dipetakan ke memori—binary utama, shared library (libc.so.6, ld-linux.so.2), beserta alamat awal dan akhir tiap mapping.
Analisis dengan addr2line #
addr2line menerjemahkan alamat instruksi menjadi nama fungsi dan baris kode sumber. Tool ini memerlukan binary yang dikompilasi dengan -g. Untuk menemukan alamat instruksi yang menyebabkan crash, kita bisa memakai objdump -d pada binary.
objdump -d /tmp/test_core_dump | grep -A8 '<baca_node_value>'Output yang Dihasilkan:
0000000000001194 <baca_node_value>:
1194: 55 push %rbp
1195: 48 89 e5 mov %rsp,%rbp
1198: 48 89 7d f8 mov %rdi,-0x8(%rbp)
119c: 48 8b 45 f8 mov -0x8(%rbp),%rax
11a0: 8b 00 mov (%rax),%eax
11a2: 5d pop %rbp
11a3: c3 retInstruksi pada alamat 0x11a0 adalah mov (%rax),%eax— instruksi yang membaca 4 byte dari alamat di register RAX. Karena RAX berisi 0 (NULL), instruksi inilah yang menyebabkan SIGSEGV. Mari konversi alamat tersebut ke baris sumber:
addr2line -e /tmp/test_core_dump -f 0x11a0Output yang Dihasilkan:
baca_node_value
/tmp/test_core_dump.c:17Hasil addr2line menunjukkan fungsi baca_node_value pada baris 17 file /tmp/test_core_dump.c. Baris 17 adalah return n->value;—tepat baris yang melakukan dereference n->value ketika n == NULL.
Analisis dengan gdb (Konseptual) #
Cara paling lengkap menganalisis core dump adalah dengan gdb. Sintaks dasarnya adalah gdb <binary> <core-file>. gdb memuat kedua file, lalu memberi prompt untuk inspeksi. Perintah bt langsung menampilkan backtrace lengkap tanpa perlu mengulang eksekusi.
gdb /tmp/test_core_dump /tmp/coreOutput yang Dihasilkan (format resmi gdb):
GNU gdb (Debian 15.x) 15.x
...
Reading symbols from /tmp/test_core_dump...
[New LWP 9027]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `/tmp/test_core_dump'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000... in baca_node_value (n=0x0) at /tmp/test_core_dump.c:17
17 return n->value;
[Current thread is 1 (LWP 9027)]
(gdb)Mari kita bedah elemen kunci pada output gdb di atas:
[New LWP 9027]: gdb menemukan satu Light Weight Process (thread) dengan ID 9027. LWP adalah ID thread level kernel. Untuk program single-threaded seperti contoh ini, hanya satu LWP.Core was generated by '/tmp/test_core_dump': gdb menampilkan command line yang dipakai menjalankan program. Informasi ini berasal dari catatanNT_PRPSINFOdi core file.Program terminated with signal SIGSEGV, Segmentation fault.: sinyal yang menyebabkan crash. gdb menampilkan nama sinyal dan deskripsi singkat.#0 0x0000... in baca_node_value (n=0x0) at /tmp/test_core_dump.c:17: frame paling dalam (#0) menunjukkan fungsibaca_node_valuemenerima argumenn=0x0(NULL) dan berhenti di baris 17. Penyebab crash jelas: dereferensin->valueketikan == NULL.
Setelah prompt (gdb), kita bisa memakai perintah interaktif seperti bt full (backtrace dengan semua variabel lokal), info locals, frame 1, atau print *head untuk inspeksi mendalam.
Strategi Penanganan Core Dump di Produksi #
Pada server produksi, core dump bisa sangat besar (gigabyte untuk proses dengan memori besar) dan menumpuk cepat. Strategi praktis:
- Pakai
systemd-coredumpyang mengompresi core dengan zstd dan menyimpannya di/var/lib/systemd/coredump/dengan rotasi otomatis. - Batas ukuran via
ulimit -c <bytes>untuk membatasi core maksimum (misalnya 100 MB—cukup untuk backtrace, tidak cukup untuk memori penuh). - Compile dengan
-gdan simpan binary yang dipakai produksi untuk dianalisis kemudian. Binary tanpa simbol debug membuat core dump hampir tidak bisa dianalisis. - Pasang ASan/UBSan sebagai opsi pertama untuk bug memori—core dump adalah opsi fallback untuk kasus yang lolos sanitizer.