gdb (GNU Debugger) adalah debugger interaktif untuk program C dan C++ yang sudah terkompilasi dengan simbol debug. Tanpa simbol debug, gdb hanya bisa menampilkan alamat mentah; dengan flag -g saat kompilasi, gdb bisa menampilkan nama variabel, baris kode sumber, dan tumpukan pemanggilan fungsi yang dapat dibaca manusia. Pada chapter ini kita akan memulai sesi gdb, menjalankan program di dalamnya, memakai mode batch untuk skrip otomatis, dan membaca backtrace hasil crash. Karena gdb bersifat interaktif dan outputnya bergantung pada versi serta kode sumber, contoh output pada chapter ini mengikuti format resmi yang didokumentasikan di sourceware.org/gdb/current/onlinedocs/gdb.
Kompilasi dengan Simbol Debug #
Syarat pertama sebelum bisa memakai gdb adalah menyertakan simbol debug. gcc menyimpan informasi ini dalam format DWARF ketika flag -g dipakai. Tanpa -g, gdb hanya menampilkan alamat numerik seperti 0x55b9.. dan nama fungsi bila simbol tersebut tersisa di symbol table. Kombinasi -g -O0 adalah standar untuk sesi debugging: optimasi -O0 memastikan urutan baris sumber sesuai urutan eksekusi.
/* File: /tmp/test_gdb1.c */
#include <stdio.h>
static int faktorial(int n) {
if (n <= 1) return 1;
return n * faktorial(n - 1);
}
int main(void) {
int x = 5;
int hasil = faktorial(x);
printf("%d! = %d\n", x, hasil);
return 0;
}gcc -g -O0 -std=c11 -Wall -Wextra /tmp/test_gdb1.c -o /tmp/test_gdb1
/tmp/test_gdb1Output yang Dihasilkan:
5! = 120Mari kita telaah flag kompilasi pada perintah di atas:
-g: memerintahkan gcc menyertakan simbol debug DWARF versi terbaru yang didukung compiler. Hasilnya, file biner memuat pemetaan antara alamat mesin dan baris kode sumber.-O0: mematikan seluruh optimasi. Tanpa-O0, gcc mungkin menghilangkan variabel lokal, menggabungkan baris, atau menyusun ulang urutan instruksi, sehingga gdb sering menampilkan pesan “optimized out” saat kita mencoba inspeksi variabel.-std=c11 -Wall -Wextra: standar bahasa dan warning tetap aktif. Simbol debug tidak menggantikan praktik kode yang bersih.
Memulai Sesi gdb Interaktif #
Untuk memulai sesi interaktif, panggil gdb dengan path binary sebagai argumen. gdb memuat binary dan simbol DWARF, lalu menampilkan prompt (gdb) yang siap menerima perintah.
gdb /tmp/test_gdb1Output yang Dihasilkan (format resmi gdb):
GNU gdb (Debian 15.x) 15.x
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /tmp/test_gdb1...
(gdb)Prompt (gdb) menandakan gdb siap menerima perintah. Kita bisa menjalankan program dengan run, memasang breakpoint dengan break, melihat source dengan list, atau keluar dengan quit.
Mode Batch untuk Otomatisasi #
Sesi interaktif berguna untuk eksplorasi, tetapi kadang kita ingin gdb menjalankan rangkaian perintah tetap—misalnya dalam skrip CI untuk merekam backtrace saat tes crash. Flag --batch mematikan prompt interaktif; flag -ex '<perintah>' menambahkan satu perintah gdb yang dijalankan secara berurutan sebelum program keluar.
gdb --batch \
-ex 'break main' \
-ex 'run' \
-ex 'print x' \
-ex 'continue' \
/tmp/test_gdb1Output yang Dihasilkan (format resmi gdb):
Breakpoint 1 at 0x...: file /tmp/test_gdb1.c, line 8.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at /tmp/test_gdb1.c:8
8 int x = 5;
$1 = <optimized out>
5! = 120
[Inferior 1 (process ...) exited normally]Mari kita bedah baris-baris output gdb batch di atas:
Breakpoint 1 at 0x...: file ...: gdb menyiapkan breakpoint bernomor1pada alamat fungsimain. Nomor breakpoint dipakai untuk referensi pada perintahdeleteataudisablenanti.[Thread debugging using libthread_db enabled]: gdb memuat pustakalibthread_dbagar mampu menginspeksi state thread bila program multithread.Breakpoint 1, main () at /tmp/test_gdb1.c:8: program berhenti di baris ke-8 (int x = 5;). Prompt(gdb)tidak muncul karena mode batch, tetapi gdb tetap mengeksekusi perintah berikutnya.$1 = <optimized out>: hasilprint xadalah variabel history$1. Nilai<optimized out>muncul bila gcc menyisipkan optimasi walau kita memakai-g. Pastikan kompilasi dengan-O0agar inspeksi variabel selalu mengembalikan nilai aktual.5! = 120: setelahcontinue, program berjalan sampai selesai dan mencetak output normal ke stdout.[Inferior 1 (process ...) exited normally]: gdb menyatakan inferior (proses yang dikelola) keluar dengan status 0. Katanormallymenandakan tidak ada sinyal fatal.
Backtrace Saat Crash #
Saat program crash, gdb otomatis berhenti dan memberi prompt untuk kita investigasi. Perintah paling penting saat itu adalah bt (singkatan dari backtrace) yang mencetak tumpukan pemanggilan fungsi dari titik crash mundur ke main.
/* File: /tmp/test_gdb2.c - program dengan null dereference */
#include <stdio.h>
static void level3(void) {
int *p = (int *)0;
*p = 42; /* crash: null pointer dereference */
}
static void level2(void) {
level3();
}
static void level1(void) {
level2();
}
int main(void) {
level1();
return 0;
}gcc -g -O0 -std=c11 /tmp/test_gdb2.c -o /tmp/test_gdb2
gdb --batch -ex 'run' -ex 'bt' /tmp/test_gdb2Output yang Dihasilkan (format resmi gdb):
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x0000... in level3 () at /tmp/test_gdb2.c:4
4 *p = 42; /* crash: null pointer dereference */
#0 0x0000... in level3 () at /tmp/test_gdb2.c:4
#1 0x0000... in level2 () at /tmp/test_gdb2.c:8
#2 0x0000... in level1 () at /tmp/test_gdb2.c:12
#3 0x0000... in main () at /tmp/test_gdb2.c:15
[Inferior 1 (process ...) exited with code 01]Mari kita uraikan elemen kunci pada output backtrace di atas:
Program received signal SIGSEGV, Segmentation fault.: kernel mengirim sinyalSIGSEGVke proses karena mencoba menulis ke alamat tidak valid (0x0). gdb menangkap sinyal tersebut sebelum proses di-kill, sehingga kita bisa menginspeksi state.0x0000... in level3 () at /tmp/test_gdb2.c:4: baris pertama backtrace adalah innermost frame, yaitu fungsi yang sedang dieksekusi saat crash terjadi. gdb menampilkan alamat instruksi, nama fungsi, file sumber, dan nomor baris.#0sampai#3: nomor frame dari dalam (0) ke luar (3). Frame#3adalahmain—titik awal eksekusi. Kita bisa berpindah frame denganframe 1, lalu melihat variabel lokal dilevel2()denganinfo locals.exited with code 01: kode keluar 1 menandakan program tidak kembali normal. Nilai ini berasal dari default gdb yang menetapkan status 1 untuk proses yang berakhir karena sinyal.
Perintah gdb Esensial #
Beberapa perintah gdb membentuk vocabulary minimum yang dipakai hampir setiap sesi debugging. Tabel berikut merangkum perintah paling sering dipakai:
| Perintah | Singkatan | Fungsi |
|---|---|---|
run | r | jalankan program dari awal |
continue | c | lanjutkan eksekusi setelah breakpoint |
next | n | eksekusi baris berikutnya, lompati fungsi |
step | s | eksekusi baris berikutnya, masuk ke fungsi |
finish | fin | jalankan sampai fungsi saat ini kembali |
print expr | p expr | cetak nilai ekspresi |
backtrace | bt | tampilkan call stack |
info locals | i lo | tampilkan variabel lokal pada frame saat ini |
list | l | tampilkan baris source di sekitar posisi saat ini |
quit | q | keluar dari gdb |