00 KGDB'ye Neden İhtiyaç Var?
Kullanıcı alanı uygulamaları için GDB sıradan bir araçtır. Kernel geliştirmede ise durum farklıdır:
bir kernel modülü yanlış davrandığında ya da bir sürücü belleği bozduğunda geleneksel
printk yaklaşımı çoğu zaman yetersiz kalır.
Linux çekirdeği kullanıcı alanından tamamen izole bir sanal bellek ortamında çalışır. Bir kullanıcı süreci çöktüğünde işletim sistemi onu öldürüp devam eder; ancak çekirdeğin kendisi çöktüğünde ya sistem yanıt vermez ya da kernel panic ile donar. Bu noktada geriye yalnızca önceden yazdırılmış log satırları kalır — sorun ise çoğunlukla log yazmadan çok önce gerçekleşmiştir.
printk'nin Sınırları
printk ile hata ayıklama aşağıdaki durumlarda etkisizdir:
KGDB Nedir?
KGDB (Kernel GNU Debugger), Linux çekirdeğinin içine entegre edilmiş bir hata ayıklama alt sistemidir. Etkinleştirildiğinde çekirdek bir gdb stub içerir. Bu stub, seri port (KGDBOC) veya ethernet (KGDBOE) üzerinden uzaktaki bir GDB oturumuna bağlanarak standart GDB Remote Serial Protocol (RSP) ile iletişim kurar.
[Host Makine] [Hedef (Gömülü) Kart] +--------------+ UART/USB +----------------------+ | gdb | <==========> | Linux Kernel | | vmlinux | ttyUSB0 | + KGDB Stub | | (debug sym) | | + KGDBOC (ttyS0) | +--------------+ +----------------------+
Kullanım Senaryoları
KGDB aşağıdaki durumlarda diğer araçlardan üstündür:
- Bir kernel modülünde NULL pointer dereference hatasının tam satırını bulmak
- Sürücü geliştirirken canlı çekirdek değişkenlerini gerçek zamanlı izlemek
- Use-after-free hatasını izleme noktası (watchpoint) ile yakalamak
- Karmaşık alt sistemlerde (ağ yığını, VFS) kontrol akışını adım adım izlemek
- QEMU ortamında çekirdek geliştirme döngüsünü hızlandırmak
KGDB ve JTAG Karşılaştırması
| Özellik | KGDB | JTAG |
|---|---|---|
| Ek donanım | Yok — seri port yeterli | JTAG probe (20–500 USD) |
| Kurulum süresi | Kernel config + birkaç komut | OpenOCD/J-Link kurulumu + pinout |
| Erişim seviyesi | Kernel sembolleri üzerinden | Register ve bellek tam erişim |
| Bootloader debug | Hayır (kernel sonrası) | Evet, reset vektöründen itibaren |
| SMP desteği | Evet — tüm CPU'lar durdurulur | Evet |
| Üretim kullanımı | Mümkün (dikkatli kullanım) | Genellikle geliştirme boardlarına özgü |
01 Kernel Yapılandırması
KGDB, derleme zamanında etkinleştirilmesi gereken bir kernel alt sistemidir. Doğru seçenekler belirlenmeden derlenen bir çekirdekte KGDB çalışmaz.
Gerekli CONFIG Seçenekleri
| CONFIG Seçeneği | Menü Yolu | Açıklama |
|---|---|---|
CONFIG_KGDB | Kernel hacking → KGDB | KGDB temel desteği — zorunlu |
CONFIG_KGDB_SERIAL_CONSOLE | Kernel hacking → KGDB → use kgdb over the serial console | UART üzerinden KGDBOC desteği |
CONFIG_KGDB_KDB | Kernel hacking → KGDB → include kdb frontend | Klavye hata ayıklayıcı arabirimi |
CONFIG_FRAME_POINTER | Kernel hacking → Compile with frame pointers | GDB'nin yığın çerçevelerini doğru görmesi için zorunlu |
CONFIG_DEBUG_INFO | Kernel hacking → Compile the kernel with debug info | DWARF hata ayıklama sembolleri kernel'a gömülür |
CONFIG_DEBUG_INFO_DWARF4 | Kernel hacking → Debug information → DWARF4 | GDB uyumluluğu için önerilir |
CONFIG_MAGIC_SYSRQ | Kernel hacking → Magic SysRq key | SysRq-g ile KGDB tetiklemek için gerekli |
CONFIG_RANDOMIZE_BASE | Security → Randomize the kernel image address (KASLR) | Geliştirmede kapatın — sembol adresleri tutarsız olur |
Minimum Kernel Fragment (Yocto)
Yocto projelerinde bir .cfg fragment dosyası oluşturun ve
SRC_URI ile kernel recipe'ye ekleyin:
# kgdb-debug.cfg
CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
CONFIG_KGDB_KDB=y
CONFIG_KDB_DEFAULT_ENABLE=0x1
CONFIG_FRAME_POINTER=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_INFO_DWARF4=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_RANDOMIZE_BASE=n
CONFIG_DEBUG_KERNEL=y
scripts/config ile Programatik Yapılandırma
cd /path/to/linux-source
./scripts/config --enable KGDB
./scripts/config --enable KGDB_SERIAL_CONSOLE
./scripts/config --enable KGDB_KDB
./scripts/config --enable DEBUG_INFO
./scripts/config --enable DEBUG_INFO_DWARF4
./scripts/config --enable FRAME_POINTER
./scripts/config --enable MAGIC_SYSRQ
./scripts/config --disable RANDOMIZE_BASE
# Eski değerler silinmesi için olddefconfig çalıştırın
make olddefconfig
Derleme Sonrası Doğrulama
# Hedef sistemde çalışan kernelde doğrula
zcat /proc/config.gz | grep -E "KGDB|DEBUG_INFO|FRAME_POINTER"
# CONFIG_KGDB=y
# CONFIG_KGDB_SERIAL_CONSOLE=y
# CONFIG_KGDB_KDB=y
# CONFIG_DEBUG_INFO=y
# CONFIG_FRAME_POINTER=y
# vmlinux debug sembolleri içeriyor mu? (host'ta)
file vmlinux
# vmlinux: ELF 64-bit LSB executable ... with debug_info, not stripped
# Sembol tablosu dolu mu?
nm vmlinux | grep " T do_sys_open" | head -3
KASLR'ın KGDB Üzerindeki Etkisi
KASLR her önyüklemede çekirdeği farklı bir bellek adresine yerleştirir. Bu güvenlik özelliği,
GDB'nin vmlinux dosyasındaki sabit sembol adreslerini geçersiz kılar. Geliştirme
ve test ortamlarında ya nokaslr boot parametresi ekleyin ya da
CONFIG_RANDOMIZE_BASE=n ile kapatın. Üretim hedeflerinde KGDB kullanmaktan
kaçının ya da adres kaydırmasını hesaplayarak GDB'ye bildirin.
02 KGDBOC Kurulumu
KGDBOC (KGDB Over Console), KGDB'nin seri konsol üzerinden haberleşmesini sağlayan taşıma katmanıdır. Gömülü sistemlerde UART en yaygın ve en güvenilir bağlantı yöntemidir.
Önyükleyici ile Kurulum
En basit ve önerilen yöntem, KGDBOC'u önyükleyici parametresiyle etkinleştirmektir. U-Boot örneği:
# U-Boot ortam değişkeni
setenv bootargs "console=ttyS0,115200 kgdboc=ttyS0,115200"
saveenv
# kgdbwait parametresi ile kernel GDB bağlantısı gelene kadar önyüklemeyi askıya alır.
# Yalnızca geliştirme imajlarında kullanın:
setenv bootargs "console=ttyS0,115200 kgdboc=ttyS0,115200 kgdbwait"
GRUB veya QEMU komut satırı için:
GRUB_CMDLINE_LINUX="console=ttyS0,115200 kgdboc=ttyS0,115200 nokaslr"
# Birden fazla konsolla — kgdboc hangi TTY'yi kullandığını açıkça belirtin
GRUB_CMDLINE_LINUX="console=tty0 console=ttyS0,115200 kgdboc=ttyS0,115200 nokaslr"
Sysfs ile Dinamik Kurulum
Sistem zaten çalışıyorken KGDBOC'u etkinleştirmek mümkündür; yeniden başlatma gerekmez:
# Hedef sistemde root olarak çalıştırın
echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc
# Baud hızı da belirtmek için
echo ttyS0,115200 > /sys/module/kgdboc/parameters/kgdboc
# Doğrulama
cat /sys/module/kgdboc/parameters/kgdboc
# ttyS0
# KGDBOC'u devre dışı bırakmak
echo "" > /sys/module/kgdboc/parameters/kgdboc
Donanım Bağlantı Topolojisi
[Host PC] [Gömülü Kart] +------------------+ +------------------+ | USB-UART Dongle | | UART Debug Port | | /dev/ttyUSB0 |<--TX/RX/GND-->| /dev/ttyS0 | +------------------+ | (kgdboc hedef) | | +------------------+ | gdb -q vmlinux | (gdb) target remote /dev/ttyUSB0 +------------------+
Yapılandırma Parametreleri
Yapılandırma Doğrulama
# Hedef sistemde KGDBOC başlatma mesajlarını kontrol et
dmesg | grep -i kgdb
# [ 0.543210] KGDB: Registered I/O driver kgdboc
# [ 0.543215] KGDB: Waiting for connection from remote gdb... (kgdbwait varsa)
# Sysfs parametre durumu
ls /sys/module/kgdboc/parameters/
# kgdboc
cat /sys/module/kgdboc/parameters/kgdboc
# ttyS0
03 İlk Bağlantı
KGDBOC yapılandırması tamamlandıktan sonra, çalışan çekirdeği durdurarak GDB oturumu başlatmak gerekir. Bu işlem için Magic SysRq mekanizması kullanılır.
Hedef Sistemde KGDB'yi Tetikleme
Çalışan bir Linux sistemini KGDB moduna almak için aşağıdaki yöntemlerden biri kullanılır. Sistem dondurulur ve GDB bağlantısı beklenir:
# Yöntem 1: /proc/sysrq-trigger (en yaygın)
echo g > /proc/sysrq-trigger
# SysRq etkin değilse önce etkinleştirin
echo 1 > /proc/sys/kernel/sysrq
echo g > /proc/sysrq-trigger
# Yöntem 2: Seri konsoldan break sinyali
# Minicom ile: Ctrl+A, F (break gönder)
# Picocom ile: Ctrl+A, Ctrl+\
# Yöntem 3: x86 fiziksel klavyeden
# Alt + SysRq + G tuş kombinasyonu
SysRq-g tetiklendikten sonra hedef konsolda aşağıdaki mesaj görünür:
[ 1234.567890] SysRq : DEBUG
[ 1234.567891] KGDB: Entering KGDB
Host'ta GDB Başlatma
Host makinede, çekirdeğin vmlinux dosyasıyla GDB başlatın. Bu dosya hedef üzerinde
çalışan kernel ile aynı derleme olmalıdır:
# ARM64 hedef için cross-GDB
aarch64-linux-gnu-gdb vmlinux
# x86_64 hedef için standart GDB
gdb vmlinux
# Yocto'da vmlinux genellikle şu konumdadır:
# tmp/work/MACHINE-poky-linux-gnueabi/linux-yocto/VERSION/
# linux-MACHINE-standard-build/vmlinux
Uzak Bağlantı Kurma
# GDB içinde seri bağlantıyı kur
(gdb) set remotebaud 115200
(gdb) target remote /dev/ttyUSB0
# Bağlantı başarılıysa mevcut durumu gösterir:
# Remote debugging using /dev/ttyUSB0
# 0xffffffc0100123b4 in default_idle () at arch/arm64/kernel/process.c:123
# 123 cpu_do_idle();
# (gdb)
# TCP üzerinden bağlantı (QEMU veya kgdboe için)
(gdb) target remote localhost:4321
GDB Uzak Bağlantı Parametreleri
İlk Bağlantıda Kullanışlı GDB Komutları
(gdb) info threads # Tüm CPU'lardaki thread'leri listele
(gdb) thread N # N numaralı thread'e geç (CPU'lar arası)
(gdb) bt # Mevcut stack trace (backtrace)
(gdb) frame N # N numaralı frame'e git
(gdb) info registers # Tüm register değerleri
(gdb) x/16xw ADRES # ADRES'ten 16 kelime hex dump
(gdb) p init_task # init_task yapısını yazdır
(gdb) p *current # Mevcut task_struct içeriği
(gdb) thread apply all bt # Tüm CPU'ların stack trace'i
Bağlantı Sorunlarını Giderme
# Sorun: "Remote connection closed" veya timeout
# Kontrol 1: Aynı TTY'yi başka bir program kullanıyor mu?
fuser /dev/ttyUSB0
# Kontrol 2: Baud hızları eşleşiyor mu?
# Hedef: cat /sys/module/kgdboc/parameters/kgdboc
# GDB: show remotebaud
# Kontrol 3: vmlinux doğru build'den mi?
# Hedef: uname -r
# Host: strings vmlinux | grep "Linux version"
# Kontrol 4: Debug sembolleri var mı?
nm vmlinux | wc -l # sıfırdan büyük olmalı
04 Kesme Noktaları ve İzleme Noktaları
KGDB, GDB'nin tüm kesme noktası ve izleme noktası mekanizmalarını kernel bağlamında destekler. Yazılım ve donanım kesme noktaları, bellek değişikliği izleme noktaları ve koşullu durmalar bunların başında gelir.
Yazılım Kesme Noktaları
Yazılım kesme noktaları hedef kodu geçici olarak INT3 (x86) veya BRK
(ARM64) talimatıyla değiştirir:
# Fonksiyon adıyla kesme noktası
(gdb) break sys_open
(gdb) break do_page_fault
# Kaynak dosya ve satır numarasıyla
(gdb) break kernel/sched/core.c:3142
# Koşullu kesme noktası — yalnızca büyük tahsisatlarda dur
(gdb) break kmalloc if size > 65536
# Mevcut kesme noktalarını listele
(gdb) info breakpoints
# Kesme noktasını sil
(gdb) delete 1 # numara ile
(gdb) clear sys_open # fonksiyon adıyla
Donanım Kesme Noktaları
Donanım kesme noktaları, CPU'nun debug register'larını kullanır (x86'da DR0–DR3, ARM64'te BVR/BCR). Salt okunur bellek bölgelerinde veya MMU olmayan alanlarda kullanılır:
# Donanım kesme noktası (hbreak)
(gdb) hbreak arch/arm64/mm/fault.c:250
# Belirli bir adrese donanım kesme noktası
(gdb) hbreak *0xffff800010001234
# ARM64'te genellikle 4-8 donanım kesme noktası mevcuttur
(gdb) info breakpoints
İzleme Noktaları (Watchpoints)
İzleme noktaları bir bellek konumu okunduğunda veya yazıldığında çekirdeği durdurur. Use-after-free ve bellek bozulması (memory corruption) hatalarını yakalamada son derece etkilidir:
# Değişken yazıldığında dur (write watchpoint)
(gdb) watch global_variable
# Belirli bir bellek adresini izle
(gdb) watch *((int *)0xffff800012345678)
# Okuma izleme noktası
(gdb) rwatch some_kernel_var
# Okuma veya yazma
(gdb) awatch some_kernel_var
# task_struct içindeki bir alanı izle
(gdb) watch -l current->mm
# İzleme noktalarını listele
(gdb) info watchpoints
Çalıştırma Kontrol Komutları
Pratik Senaryo: Bellek Bozulmasını Yakalama
# Senaryo: Bir sürücü başka bir modülün değişkenini bozuyor
# Adım 1: Bozulan değişkenin adresini bul
(gdb) p &target_module_global_var
# $1 = (int *) 0xffff800008abc123
# Adım 2: İzleme noktası koy
(gdb) watch *0xffff800008abc123
# Adım 3: Devam et — bozulma anında duracak
(gdb) continue
# Kernel durduğunda:
# Hardware watchpoint 1: *0xffff800008abc123
# Old value = 42
# New value = 0
# evil_driver_write () at drivers/evil/evil.c:88
# Adım 4: Stack izini al
(gdb) bt
# #0 evil_driver_write () at drivers/evil/evil.c:88
# #1 evil_irq_handler () at drivers/evil/evil.c:120
# #2 handle_irq_event () at kernel/irq/handle.c:167
05 Modül Hata Ayıklama
Yüklenebilir kernel modülleri (LKM) çalışma zamanında dinamik olarak yüklenir. Modül kodunun sembol adresleri önyükleme sırasında bilinmez; GDB'ye ayrıca bildirilmesi gerekir.
add-symbol-file Komutu
GDB'nin add-symbol-file komutu, modülün debug sembollerini içeren .ko
dosyasını belirtilen bellek adresine konumlandırır:
(gdb) add-symbol-file /path/to/mydriver.ko TEXT_ADDRESS \
-s .data DATA_ADDRESS \
-s .bss BSS_ADDRESS
Modül Bellek Adreslerini Okuma
Adresler hedef sistemdeki /sys/module/ sysfs arayüzünden okunur:
# Hedef sistemde (modül yüklüyken)
cat /sys/module/mydriver/sections/.text
# 0xffff800008abc000
cat /sys/module/mydriver/sections/.data
# 0xffff800008ac4000
cat /sys/module/mydriver/sections/.bss
# 0xffff800008ac6000
# Tüm section'ları tek seferde listele
for s in /sys/module/mydriver/sections/.*; do
printf "%s : %s\n" "$s" "$(cat $s 2>/dev/null)"
done
GDB'de Modülü Konumlandırma
# Host'ta GDB oturumunda sembol dosyasını ekle
(gdb) add-symbol-file mydriver.ko 0xffff800008abc000 \
-s .data 0xffff800008ac4000 \
-s .bss 0xffff800008ac6000
# Onay istenir:
# add symbol table from file "mydriver.ko" at
# .text_addr = 0xffff800008abc000
# (y or n) y
# Reading symbols from mydriver.ko...done.
# Artık modül içinde kesme noktası koyabilirsiniz
(gdb) break mydriver.c:probe_function
(gdb) break mydriver_read
Otomatik Sembol Yükleme (Python Yardımcı Script)
#!/usr/bin/env python3
# load_module_syms.py
# Kullanim: ssh root@hedef python3 - < load_module_syms.py mydriver
import sys, os
modname = sys.argv[1]
base = "/sys/module/" + modname + "/sections/"
def read_addr(section):
path = base + section
if os.path.exists(path):
return open(path).read().strip()
return None
text = read_addr(".text")
data = read_addr(".data")
bss = read_addr(".bss")
if not text:
print("# Modül bulunamadi:", modname)
sys.exit(1)
cmd = "add-symbol-file {}.ko {}".format(modname, text)
if data: cmd += " -s .data {}".format(data)
if bss: cmd += " -s .bss {}".format(bss)
print(cmd)
Modül Yükleme Anında Kesme
# Modülün yüklenme anında dur — do_init_module kesme noktası
(gdb) break do_init_module
(gdb) continue
# Modül yüklendiğinde kernel durur:
# Breakpoint 1, do_init_module (mod=0xffff800009abc000)
# at kernel/module.c:3482
# Modül adını kontrol et
(gdb) p mod->name
# $1 = "mydriver"
# Text adresini al ve sembol ekle
(gdb) p mod->core_layout.base
# $2 = (void *) 0xffff800008abc000
Modül Debug için Yocto Yapılandırması
06 Kernel Panic Analizi
Kernel panic ve oops mesajları, Linux'un kendi kendine ürettiği kritik hata bildirimleridir. KGDB ile bu anları dondurarak tam bir canlı veya post-mortem analiz yapmak mümkündür.
Kernel Oops Mesajı Anatomisi
Bir oops mesajı birkaç bölümden oluşur. Aşağıda NULL pointer dereference örneği:
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000010
Mem abort info:
ESR = 0x96000004
Exception class = DABT (current EL), IL = 32 bits
Data abort info:
ISV = 0, ISS = 0x00000004
CM = 0, WnR = 0
[0000000000000010] pgd=0000000000000000
Internal error: Oops: 96000004 [#1] PREEMPT SMP
Modules linked in: mydriver(O) e1000e i2c_core
CPU: 2 PID: 1234 Comm: myprocess Tainted: G O
pc : mydriver_read+0x48/0x120 [mydriver]
lr : vfs_read+0xbc/0x1a0
Call trace:
mydriver_read+0x48/0x120 [mydriver]
vfs_read+0xbc/0x1a0
ksys_read+0x68/0xf0
__arm64_sys_read+0x18/0x28
el0_svc+0x8/0x200
KGDB ile Panic Anında Canlı Analiz
# Panic sonrası KGDB otomatik devreye girer
# (CONFIG_KGDB_ON_PANIC etkinse — bazı dağıtımlarda)
# GDB'den bağlan:
(gdb) target remote /dev/ttyUSB0
# Panic anındaki stack izini al
(gdb) bt
# #0 die () at arch/arm64/kernel/traps.c:234
# #1 do_mem_abort ()
# #2 mydriver_read () at drivers/mydriver/mydriver.c:88
# Frame 2'ye git — hatanın gerçekleştiği yer
(gdb) frame 2
# O frame'deki lokal değişkenleri gör
(gdb) info locals
# ptr = 0x0 <-- NULL pointer!
# size = 4096
# Tam kaynak bağlamını gör
(gdb) list
# 85: int mydriver_read(struct file *file, char __user *buf, size_t count)
# 86: {
# 87: struct mydev *dev = file->private_data;
# 88: return copy_to_user(buf, dev->buffer, dev->size); <-- dev NULL!
Use-After-Free Tespiti
# Yöntem 1: KASAN ile otomatik tespit (önerilir)
# CONFIG_KASAN=y + CONFIG_KASAN_INLINE=y ile derleyin
# KASAN, UAF'ı stack trace ile birlikte otomatik raporlar
# Yöntem 2: İzleme noktası ile manuel tespit
# Nesnenin adresi biliniyorsa:
(gdb) watch -l *((struct mydev *)0xffff800009abc000)
# Yöntem 3: SLUB debug ile adres tespit
# Hedef: echo "mydev" > /sys/kernel/slab/mydev/trace
# Yöntem 4: Tipik use-after-free belirtisi
(gdb) x/32xb 0xdeadbeefdeadbeef
# KASAN poison değerleri: 0xCC (freed), 0xAA (uninitialized)
Oops Adresini Kaynak Satırına Çevirme
# GDB olmadan da oops adreslerini çözümleyebilirsiniz
# "pc : mydriver_read+0x48/0x120 [mydriver]" ifadesinden:
# Yöntem 1: addr2line ile (offset yeterli)
aarch64-linux-gnu-addr2line -e mydriver.ko 0x48
# /home/user/driver-src/mydriver.c:88
# Yöntem 2: faddr2line ile (fonksiyon+offset)
./scripts/faddr2line mydriver.ko mydriver_read+0x48
# mydriver_read at drivers/mydriver/mydriver.c:88
# Yöntem 3: decode_stacktrace.sh ile tam stack
./scripts/decode_stacktrace.sh vmlinux . < oops_log.txt
Post-Mortem: kdump + crash
# kdump kernel panic anında belleği diske yazar
# crash aracı bu dökümü analiz eder
# 1) Hedef sistemde kdump kurun
apt-get install kdump-tools
echo 'crashkernel=256M' >> /etc/default/grub
update-grub && reboot
# 2) Panic sonrası /var/crash/TARIH/vmcore oluşur
# 3) crash ile analiz (host veya hedef)
crash /usr/lib/debug/boot/vmlinux-$(uname -r) \
/var/crash/20260415/vmcore
# crash kabuğunda
crash> bt # backtrace
crash> log # dmesg ring buffer
crash> ps # process listesi
crash> mod # yüklü modüller
07 QEMU ile KGDB Geliştirme Ortamı
Gerçek donanım her zaman erişilebilir olmayabilir. QEMU, kernel geliştirme ve hata ayıklama için güçlü bir sanallaştırma ortamı sunar. KGDB, QEMU'nun sanal seri portu üzerinden sorunsuz çalışır.
QEMU TCP Seri Köprüsü ile KGDBOC
# ARM64 sanal makine — KGDB için TCP seri köprü
qemu-system-aarch64 \
-M virt \
-cpu cortex-a57 \
-m 1G \
-kernel Image \
-append "console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 nokaslr" \
-nographic \
-serial tcp::4321,server,nowait \
-drive file=rootfs.ext4,format=raw,if=virtio
# x86_64 sanal makine
qemu-system-x86_64 \
-kernel bzImage \
-append "console=ttyS0,115200 kgdboc=ttyS0,115200 nokaslr" \
-nographic \
-serial tcp::4321,server,nowait \
-initrd initrd.img
QEMU Yerleşik GDB Server (-s -S)
QEMU'nun kendi GDB server'ı (-s -S parametreleri), kernel çalışmadan önce makine
seviyesinde durur. KGDB'den farklıdır ancak kernel önyükleme sürecini debug etmek için kullanışlıdır:
# QEMU kendi GDB server'ı ile (makine seviyesi, KGDB değil)
qemu-system-aarch64 \
-M virt -cpu cortex-a57 -m 1G \
-kernel Image \
-s -S \ # -s: port 1234'te GDB server, -S: başlangıçta dur
-nographic
# Host'ta GDB:
aarch64-linux-gnu-gdb vmlinux
(gdb) target remote localhost:1234
(gdb) continue # Kernel önyüklemeye başlar
KGDB ile TCP Bağlantısı
# 1. QEMU başlatıldıktan ve kernel açıldıktan sonra
# QEMU guest'te KGDB'yi tetikle:
# QEMU monitor moduna geç: Ctrl+A, C
# monitor> sendkey alt-sysrq-g
# Veya guest terminal üzerinden:
# echo g > /proc/sysrq-trigger
# 2. Host'ta GDB bağlan
aarch64-linux-gnu-gdb vmlinux
(gdb) target remote localhost:4321
# TCP bağlantısında baud hızı ayarı gerekmez
QEMU + KGDB Geliştirme Döngüsü
1. Kernel veya modülü derle
|
v
2. QEMU başlat (rootfs'e modül kopyala)
|
v
3. Guest'te modülü yükle: insmod mydriver.ko
|
v
4. /sys/module/mydriver/sections/.text adresini oku
|
v
5. GDB: target remote localhost:4321
GDB: add-symbol-file mydriver.ko TEXT_ADRES
|
v
6. Kesme noktası koy; SysRq-g ile tetikle
|
v
7. Hata bul, düzelt -> 1'e don
QEMU Snapshot ile Tekrarlanabilir Test
# Belirli bir sistem durumunu snapshot olarak kaydet
# QEMU monitor modunda (Ctrl+A, C):
# monitor> savevm before-test
# Hata ayıkladıktan sonra başlangıç durumuna dön:
# monitor> loadvm before-test
# Bu özellik race condition araştırmasında son derece değerlidir:
# - Aynı sistem durumunu tekrar tekrar yeniden oluşturabilirsiniz
# - Modül yükleme öncesi temiz durum kolayca geri yüklenir
QEMU ile Kernel Modülü Geliştirme İpuçları
08 KDB: Klavye Hata Ayıklayıcı
KDB (Kernel Debugger), KGDB altyapısı üzerine inşa edilmiş ve GDB'ye ihtiyaç duymayan yerel bir hata ayıklama ön yüzüdür. Doğrudan hedef sistemin konsolundan etkileşimli olarak kullanılır. Uzak GDB bağlantısı mümkün olmadığında ya da üretim sisteminde acil inceleme gerektiğinde vazgeçilmezdir.
KDB'yi Etkinleştirme
# Kernel yapılandırmasında (derleme zamanı):
# CONFIG_KGDB_KDB=y
# CONFIG_KDB_DEFAULT_ENABLE=0x1
# Çalışma zamanında etkinleştirme:
echo 1 > /sys/module/kdb/parameters/kdb_enable
# KDB moduna giriş:
echo g > /proc/sysrq-trigger
KDB etkinleştirildiğinde ve SysRq-g tetiklendiğinde konsol şu görünümü alır:
Entering kdb (current=0xffff800009abc000, pid 1234) due to Keyboard Entry
[0]kdb>
Köşeli parantez içindeki sayı mevcut CPU numarasıdır.
Temel KDB Komutları
| Komut | Açıklama | Örnek |
|---|---|---|
help | Tüm komutları listeler | help |
go | Çalışmaya devam et | go |
bt | Mevcut stack trace | bt |
btp PID | Belirtilen PID'in stack trace'i | btp 1234 |
bta | Tüm süreçlerin stack trace'i | bta |
ps | Çalışan süreç listesi | ps |
md ADRES | Bellekten veri oku (hex dump) | md 0xffff800008abc000 |
mdr ADRES BOY | Belirtilen uzunlukta bellek oku | mdr 0xffff800008abc000 32 |
mm ADRES DEGER | Belleğe değer yaz | mm 0xffff000012345678 0x1 |
id ADRES | Adresi disassemble et | id mydriver_probe |
lsmod | Yüklü modülleri listele | lsmod |
rd | Register değerlerini göster | rd |
bp ADRES | Kesme noktası koy | bp do_sys_open |
bc NUM | Kesme noktasını sil | bc 1 |
sr SYSRQ | SysRq komutu çalıştır | sr t (thread dump) |
kgdb | KGDB protokolüne geç | kgdb |
KDB ile Acil Sistem Analizi
# Tüm CPU'lardaki stack trace'leri al
[0]kdb> bta
# Belirli bir task'ın stack'ını gör
[0]kdb> btp 1
# Tüm process'leri listele
[0]kdb> ps A
# CPU register durumunu gör
[0]kdb> rd
# Modül listesi — crash olan modülü tespit et
[0]kdb> lsmod
# Çalışmaya devam et
[0]kdb> go
KDB Bellek Komutları Kullanım Örnekleri
# Kernel sembol adresini doğrudan kullan
[0]kdb> md init_task
# 8 kelime oku
[0]kdb> md 0xffff800008abc000 8
# 16 bayt oku
[0]kdb> mdr 0xffff800008abc000 16
# Modül listesinden adres bul
[0]kdb> lsmod
# Module Address Size
# mydriver 0xffff800008abc000 16384
# Modül adresinden kodu disassemble et
[0]kdb> id 0xffff800008abc000
KGDB ile KDB Arasında Geçiş
# KDB modundayken KGDB'ye geç (uzak GDB bağlantısı için)
[0]kdb> kgdb
# Artık host'ta GDB ile bağlanabilirsiniz:
# aarch64-linux-gnu-gdb vmlinux
# (gdb) target remote /dev/ttyUSB0
# KGDB modundayken KDB'ye geç (GDB oturumundan):
(gdb) maintenance packet 3
Üretim Sisteminde Güvenli Kullanım
Üretim sistemlerinde KGDB/KDB kullanımı dikkatli değerlendirme gerektirir: