Tüm eğitimler
TEKNİK REHBERGÖMÜLÜ LİNUXHATA AYIKLAMA2026

KGDB
Çekirdek Seviyesi GDB ile Hata Ayıklama

KGDB ve KGDBOC ile çalışan Linux kernel'da kesme noktası koyma, bellek inceleme, modül hata ayıklama ve gömülü UART tabanlı uzak hata ayıklama.

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:

Zamanlama bağımlı hatalarprintk eklemek çalışma zamanı zamanlamasını değiştirir ve yarış koşullarını (race condition) gizler.
Önyükleme erken aşamasıKonsol sürücüsü hazır olmadan önceki paniklerde log tamponu boşaltılamaz.
Dinamik modül durumuHangi değişkenin ne zaman bozulduğunu bulmak için binlerce satır log yazılması gerekebilir.
Canlı bellek incelemeÇalışan bir çekirdeğin veri yapılarına (task_struct, inode, sk_buff) anlık olarak bakmak mümkün olmaz.

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ı

ÖzellikKGDBJTAG
Ek donanımYok — seri port yeterliJTAG probe (20–500 USD)
Kurulum süresiKernel config + birkaç komutOpenOCD/J-Link kurulumu + pinout
Erişim seviyesiKernel sembolleri üzerindenRegister ve bellek tam erişim
Bootloader debugHayır (kernel sonrası)Evet, reset vektöründen itibaren
SMP desteğiEvet — tüm CPU'lar durdurulurEvet
Ü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ğiMenü YoluAçıklama
CONFIG_KGDBKernel hacking → KGDBKGDB temel desteği — zorunlu
CONFIG_KGDB_SERIAL_CONSOLEKernel hacking → KGDB → use kgdb over the serial consoleUART üzerinden KGDBOC desteği
CONFIG_KGDB_KDBKernel hacking → KGDB → include kdb frontendKlavye hata ayıklayıcı arabirimi
CONFIG_FRAME_POINTERKernel hacking → Compile with frame pointersGDB'nin yığın çerçevelerini doğru görmesi için zorunlu
CONFIG_DEBUG_INFOKernel hacking → Compile the kernel with debug infoDWARF hata ayıklama sembolleri kernel'a gömülür
CONFIG_DEBUG_INFO_DWARF4Kernel hacking → Debug information → DWARF4GDB uyumluluğu için önerilir
CONFIG_MAGIC_SYSRQKernel hacking → Magic SysRq keySysRq-g ile KGDB tetiklemek için gerekli
CONFIG_RANDOMIZE_BASESecurity → 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

Baud hızı eşleşmesiHost GDB bağlantısı ile hedef kgdboc parametresi aynı baud hızını kullanmalıdır. 115200 standart ve önerilen değerdir.
Konsol paylaşımıKGDBOC, konsol TTY'sini KGDB modu aktifken geçici olarak devralır. Normal log akışı bu sürede duraklar.
Akış kontrolüHardware flow control (RTS/CTS) devre dışı bırakın. Çoğu USB-UART dongle'da sorun çıkarır.
kgdbwait uyarısıkgdbwait parametresiyle çekirdek, GDB bağlanana kadar önyüklemede tamamen bloke olur. Watchdog'u tetikleyebilir.

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

set remotebaud BAUDSeri port baud hızını ayarlar. kgdboc parametresiyle eşleşmelidir (115200).
set remote hardware-breakpoint-limit NARM gibi mimarilerde donanım kesme noktası sayısını sınırlar (genellikle 4–8).
set remote hardware-watchpoint-limit NDonanım izleme noktası sayısını sınırlar.
set serial baud BAUDAlternatif baud ayar komutu; GDB sürümüne göre farklılık gösterebilir.

İ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ı

continue (c)Çekirdeği çalıştırmaya devam ettirir; bir sonraki kesme noktasına kadar sürer.
step (s)Bir kaynak satırı ilerler; fonksiyon çağrılarının içine girer.
next (n)Bir kaynak satırı ilerler; fonksiyon çağrılarının üzerinden atlar.
stepi (si)Bir makine komutu ilerler; assembly seviyesi analiz için kullanılır.
finishMevcut fonksiyonun sonuna kadar çalışır ve döner.
until SATIRBelirtilen satıra kadar çalışır; döngüleri atlamak için kullanışlıdır.

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ı

INHIBIT_PACKAGE_STRIP = "1".ko dosyasının debug sembollerinin paketleme sırasında soyulmasını engeller.
INHIBIT_PACKAGE_DEBUG_SPLIT = "1"Debug sembollerinin ayrı bir paket olarak bölünmesini engeller; semboller ana .ko içinde kalır.
CONFIG_DEBUG_INFO=y (fragment).ko dosyasının DWARF debug bilgisi içermesi için kernel config fragment'ine eklenmeli.

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ı

9P/VirtFS paylaşımlı dizinQEMU 9P protokolü ile host dizinini guest'e monte edin; derlenen .ko dosyasını kopyalamadan kullanın.
-kernel ile hızlı döngüYeni kernel imajı denemek için QEMU'yu -kernel ile yeniden başlatın; disk imajını yeniden oluşturmanız gerekmez.
nokaslr zorunluQEMU boot parametrelerine nokaslr eklemeden GDB sembol adresleri tutarsız olacaktır.

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ı

KomutAçıklamaÖrnek
helpTüm komutları listelerhelp
goÇalışmaya devam etgo
btMevcut stack tracebt
btp PIDBelirtilen PID'in stack trace'ibtp 1234
btaTüm süreçlerin stack trace'ibta
psÇalışan süreç listesips
md ADRESBellekten veri oku (hex dump)md 0xffff800008abc000
mdr ADRES BOYBelirtilen uzunlukta bellek okumdr 0xffff800008abc000 32
mm ADRES DEGERBelleğe değer yazmm 0xffff000012345678 0x1
id ADRESAdresi disassemble etid mydriver_probe
lsmodYüklü modülleri listelelsmod
rdRegister değerlerini gösterrd
bp ADRESKesme noktası koybp do_sys_open
bc NUMKesme noktasını silbc 1
sr SYSRQSysRq komutu çalıştırsr t (thread dump)
kgdbKGDB 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:

Fiziksel erişim kontrolüKDB, UART portuna fiziksel erişimi olan herkese kernel seviyesi kontrol verir. Debug portunu yetkisiz erişime karşı koruyun.
SysRq kısıtlama/proc/sys/kernel/sysrq değerini 0 yaparak üretimde SysRq'yu tamamen devre dışı bırakın; ihtiyaç duyulduğunda 1 yapın.
Ayrı debug buildKGDB/KDB içeren kernel sürümlerini yalnızca geliştirme ve test ortamlarında kullanın; üretim imajlarına dahil etmeyin.
CONFIG_KGDB_KDB=n üretimdeÜretim çekirdeklerinde KDB desteğini derleme zamanında devre dışı bırakmak en güvenli yaklaşımdır.