Geliştirici Araçları
TEKNİK REHBER GELİŞTİRİCİ ARAÇLARI BİNUTILS 2026

addr2line —
crash decoder.

Seri porttan gelen hex adresi kaynak dosya ve satır numarasına çevir. Core dump backtrace, kernel oops, gdbserver crash decode. PIE/ASLR ile adres düzeltme.

00 addr2line nedir — DWARF mekanizması

addr2line, bir bellek adresini kaynak kodu konumuna çeviren bir araçtır. Embedded geliştirmede en pratik crash analizi yöntemidir: hedefte gelen adres, geliştirici makinasında kaynak satırına dönüşür.

addr2line, ELF dosyasındaki DWARF debug bilgisini okur. DWARF, her assembly talimatını bir kaynak dosyası ve satır numarasıyla ilişkilendiren .debug_line section'ını içerir. Bu section, -g bayrağıyla derleme yapıldığında oluşturulur.

bash — kurulum ve temel kullanım
# binutils paketinin bir parçası — ayrı kurulum gerekmez
which addr2line
# /usr/bin/addr2line

# ARM cross:
arm-linux-gnueabihf-addr2line --version
# GNU addr2line (GNU Binutils for Debian) 2.38

# Temel kullanım
addr2line -e myapp 0x104b2
# /home/user/project/sensor.c:42

01 -e, -f, -i bayrakları

addr2line'ın üç temel bayrağı: ikili dosya belirtme, fonksiyon adı gösterme ve inline fonksiyon zincirini açma.

bash
# -e: hangi ELF dosyası kullanılacak
addr2line -e myapp 0x104b2
# /home/user/project/sensor.c:42

# -f: fonksiyon adını da göster
addr2line -e myapp -f 0x104b2
# read_temperature
# /home/user/project/sensor.c:42

# -i: inline fonksiyon zincirini göster
# Derleyici inline ettiğinde gerçek kaynak farklı dosyada olabilir
addr2line -e myapp -f -i 0x104b2
# convert_adc_to_celsius    <-- inline edilmiş iç fonksiyon
# /home/user/project/adc.h:15
# read_temperature          <-- asıl çağıran
# /home/user/project/sensor.c:42

# -p: insan dostu çıktı formatı (pretty-print)
addr2line -e myapp -f -p 0x104b2
# read_temperature at /home/user/project/sensor.c:42
-e binary
DWARF bilgisini içeren ELF dosyasını belirt. Hedef binary'yi değil, debug simbolleri olan binary'yi işaret etmeli.
-f / --functions
Kaynak satırının yanı sıra fonksiyon adını da göster.
-i / --inlines
Inline expansion zincirini göster — optimize kodda kritik.
-p / --pretty-print
Her adres için tek satır okunabilir çıktı.
-a / --addresses
Çıktının başında adresi tekrar yaz — birden fazla adres işlenirken faydalı.

02 Crash log adresini kaynak satırına çevirme

ARM tabanlı embedded sistemlerde seri konsoldan gelen tipik bir crash mesajı: "Segmentation fault (core dumped)" yerine doğrudan register dump gelir.

ARM sistem panic çıktısı

seri konsol — crash çıktısı
Unhandled fault: page fault (0x82f) at 0x00000000
pgd = dc3a4000
[00000000] *pgd=9c3a8031, *pte=00000000, *ppte=00000000
Internal error: Oops: 82f [#1] SMP ARM
Modules linked in: sensor_drv
CPU: 0 PID: 134 Comm: sensor_daemon Not tainted 5.15.0
Hardware name: Generic DT based system
PC is at read_temperature+0x22/0x60
LR is at sensor_loop+0x4e/0xa0
pc : [<00010494>]    lr : [<000104de>]
sp : dea8bd80  ip : 00000000  fp : dea8bda4
bash — adres decode
# PC (program counter) adresini decode et
arm-linux-gnueabihf-addr2line -e myapp -f -i 0x00010494
# read_temperature
# /home/user/project/sensor.c:38

# LR (link register) adresini decode et — çağıran yer
arm-linux-gnueabihf-addr2line -e myapp -f -i 0x000104de
# sensor_loop
# /home/user/project/main.c:92

# Stack backtrace'i toplu decode et
arm-linux-gnueabihf-addr2line -e myapp -f -i \
  0x00010494 0x000104de 0x00010600 0x00010700

Crash log'dan adresleri otomatik çıkarma

bash
# Crash log'dan hex adresleri çıkar ve decode et
grep -oE '\[<[0-9a-f]+>\]' crash.log | \
  grep -oE '[0-9a-f]+' | \
  while read addr; do
    echo "=== 0x$addr ==="
    arm-linux-gnueabihf-addr2line -e myapp -f -p "0x$addr"
  done

03 Core dump + backtrace analizi

Core dump, bir süreç çöktüğünde bellek görüntüsünü kaydeder. gdb ile backtrace alınır, addr2line ile kaynak satırları decode edilir.

bash — core dump ile çalışma
# Core dump'ı etkinleştir (hedef sistemde)
ulimit -c unlimited
echo "/tmp/core.%e.%p" > /proc/sys/kernel/core_pattern

# Programı çalıştır, crash bekle
./myapp
# Segmentation fault (core dumped)

# gdb ile backtrace al
arm-linux-gnueabihf-gdb myapp /tmp/core.myapp.1234 \
  -batch -ex "bt" -ex "quit"
gdb backtrace çıktısı
#0  0x00010494 in read_temperature ()
#1  0x000104de in sensor_loop ()
#2  0x00010600 in main ()
#3  0x76f4e3c4 in __libc_start_main () from /lib/libc.so.6
bash — backtrace → kaynak satırı
# gdb backtrace'indeki adresleri addr2line ile decode et
for addr in 0x00010494 0x000104de 0x00010600; do
    echo -n "#? $addr: "
    arm-linux-gnueabihf-addr2line -e myapp -f -p "$addr"
done

# Çıktı:
# #? 0x00010494: read_temperature at sensor.c:38
# #? 0x000104de: sensor_loop at main.c:92
# #? 0x00010600: main at main.c:15

04 DWARF debug info gereksinimi

addr2line çalışabilmek için DWARF debug bilgisine ihtiyaç duyar. Üretim binary'leri genellikle strip edilmiş olduğundan bu bilgi ayrı tutulmalıdır.

bash — debug bilgisi yönetimi
# -g ile derle: DWARF bilgisi ELF içine gömülür
arm-linux-gnueabihf-gcc -g -O2 -o myapp sensor.c main.c

# Üretim: debug bilgisini ayrı .debug dosyasına çıkar
arm-linux-gnueabihf-objcopy --only-keep-debug myapp myapp.debug
arm-linux-gnueabihf-strip --strip-debug myapp

# Debug link ekle (gdb ve addr2line .debug dosyasını bulur)
arm-linux-gnueabihf-objcopy \
  --add-gnu-debuglink=myapp.debug myapp

# Debug dosyası ile addr2line kullan
arm-linux-gnueabihf-addr2line -e myapp.debug -f 0x10494

# DWARF var mı kontrol et
readelf -S myapp | grep debug
# [18] .debug_info   PROGBITS  ... (DWARF mevcut)
# Çıktı yoksa: strip edilmiş, .debug dosyasını kullan
İPUCU — Yocto debug paketleri

Yocto'da IMAGE_FEATURES += "dbg-pkgs" veya -dbg paketleri kurulunca debug sembolleri /usr/lib/debug/ altına yerleştirilir. addr2line bu dizini otomatik arar. Cross geliştirmede: addr2line -e deploy/images/.../myapp.debug

05 PIE / -fpie ile adres düzeltme

PIE (Position Independent Executable) ve ASLR (Address Space Layout Randomization) ile derlenen programlarda crash adresleri her çalıştırmada farklı olur. Ham adresi kullanmak yerine base address ile offset hesabı yapılır.

bash
# PIE binary mi kontrol et
readelf -h myapp | grep Type
# Type: DYN (Position-Independent Executable)  <-- PIE
# Type: EXEC (Executable file)                  <-- non-PIE

# PIE binary'de crash: /proc/PID/maps ile base address bul
# Crash çıktısından:
# PC: 0x5648a3b2  (runtime adresi)

# /proc/maps'ten base address bul (programı çalıştır, PID not al)
cat /proc/1234/maps | head -3
# 56489000-5648f000 r-xp 00000000 08:01 ... myapp  <-- base: 0x56489000

# Offset hesapla: runtime_addr - base_addr
# 0x5648a3b2 - 0x56489000 = 0x13b2

# addr2line'a offset ver
addr2line -e myapp -f 0x13b2
# read_temperature
# /home/user/project/sensor.c:38

Embedded: ASLR genellikle kapalıdır

bash
# Embedded Linux'ta ASLR durumu
cat /proc/sys/kernel/randomize_va_space
# 0 = ASLR kapalı (pek çok embedded sistemde varsayılan)
# 1 = stack/mmap randomize
# 2 = tam ASLR

# ASLR kapalıysa non-PIE binary'de adresler sabittir
# → addr2line'a doğrudan ham adresi ver

# Test sırasında ASLR geçici kapatma
echo 0 > /proc/sys/kernel/randomize_va_space

06 Kernel oops adresi decode

Kernel modülü çöktüğünde dmesg'de görünen oops mesajı, modül base address ve offset bilgisi içerir. addr2line ile modül kaynak kodu bulunabilir.

dmesg — kernel oops örneği
[  234.567890] BUG: unable to handle kernel NULL pointer dereference at 00000000
[  234.567891] IP: [<bf001234>] sensor_drv_read+0x34/0x80 [sensor_drv]
[  234.567892] *pde = 00000000
[  234.567893] Oops: 0002 [#1] SMP
[  234.567894] CPU: 0 PID: 152 Comm: cat Tainted: G    O  5.15.0
[  234.567895] Call Trace:
[  234.567896] [<bf001290>] sensor_drv_ioctl+0x50/0xc0 [sensor_drv]
[  234.567897] [<c012abc0>] vfs_ioctl+0x30/0x60
bash — kernel modülü decode
# Kernel modülü için: .ko dosyasının debug versiyonu gerekir
# IP: sensor_drv_read+0x34 → fonksiyon + offset

# addr2line ile .ko debug dosyasından decode
addr2line -e sensor_drv.ko.debug -f 0x34
# sensor_drv_read
# /home/user/kernel/drivers/sensor/sensor_drv.c:87

# Alternatif: scripts/faddr2line (kernel kaynak ağacında)
./scripts/faddr2line sensor_drv.ko sensor_drv_read+0x34
# sensor_drv_read+0x34/0x80:
# sensor_drv.c:87
İPUCU — kernel DWARF

Kernel modüllerini debug sembollerle derlemek için CONFIG_DEBUG_INFO=y gerekir. Yocto'da: KERNEL_EXTRA_FEATURES += "debug". Üretim kerneli genellikle strip edilmiştir; geliştirme amacıyla build sunucusundaki vmlinux dosyasını saklayın.

07 Pratik: gdbserver crash decode + otomatik script

gdbserver üzerinden uzaktan hata ayıklama ve otomatik crash decode scripti.

gdbserver ile uzaktan crash decode

bash — hedef sistemde (ARM board)
# gdbserver başlat
gdbserver :2345 ./myapp

# ya da çalışan bir sürece bağlan
gdbserver --attach :2345 1234
bash — geliştirici makinasında
# arm-linux-gnueabihf-gdb ile uzaktan bağlan
arm-linux-gnueabihf-gdb myapp_debug

# gdb içinde:
(gdb) target remote 192.168.1.100:2345
(gdb) set sysroot /opt/sysroot
(gdb) break main
(gdb) continue
# ... crash gerçekleşir ...
(gdb) bt
# #0  0x00010494 in read_temperature (ch=0) at sensor.c:38
# #1  0x000104de in sensor_loop () at main.c:92

# gdb çıktısından adresleri al, addr2line ile çapraz doğrula
(gdb) info frame
(gdb) quit

Otomatik crash decode scripti

bash — auto_decode.sh
#!/bin/bash
# Kullanım: ./auto_decode.sh <binary> <crash_log>
# Örnek:   ./auto_decode.sh myapp.debug /tmp/crash.log

BINARY=${1:?"İkili dosya belirtin"}
LOGFILE=${2:-/dev/stdin}
TOOLPREFIX=${TOOLPREFIX:-arm-linux-gnueabihf-}
ADDR2LINE="${TOOLPREFIX}addr2line"

echo "=== CRASH DECODE: $BINARY ==="
echo

# Hex adreslerini çıkar (0x ile başlayan ya da köşeli parantezli)
grep -oE '(0x[0-9a-fA-F]+|\[<[0-9a-fA-F]+>\])' "$LOGFILE" | \
  grep -oE '[0-9a-fA-F]{6,}' | \
  sort -u | \
  while read addr; do
    result=$("$ADDR2LINE" -e "$BINARY" -f -p "0x$addr" 2>/dev/null)
    if [ -n "$result" ] && ! echo "$result" | grep -q "?"; then
        echo "0x$addr → $result"
    fi
  done

echo
echo "=== BİTTİ ==="
kullanım
chmod +x auto_decode.sh
./auto_decode.sh myapp.debug crash.log

# Çıktı:
# === CRASH DECODE: myapp.debug ===
#
# 0x00010494 → read_temperature at sensor.c:38
# 0x000104de → sensor_loop at main.c:92
# 0x00010600 → main at main.c:15
#
# === BİTTİ ===