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

ltrace —
library call tracer.

strace syscall'ları izlerken ltrace shared library çağrılarını yakalar. malloc/free takibi, C++ demangling, dinamik linker debug. Hangi kütüphane fonksiyonu yavaş çalışıyor?

00 ltrace vs strace — fark ve çalışma prensibi

strace kernel ile uygulama arasındaki syscall sınırını izlerken ltrace, shared library ile uygulama arasındaki PLT (Procedure Linkage Table) geçişlerini yakalar.

strace
Kernel system call'larını izler: open, read, write, ioctl, mmap... ptrace kullanır. Her dilde çalışır.
ltrace
Shared library fonksiyon çağrılarını izler: printf, malloc, strlen, fopen... PLT hook kullanır. Yalnızca dinamik olarak bağlı binary'lerde çalışır.

PLT mekanizması

Dinamik bağlamada her shared library çağrısı, PLT (Procedure Linkage Table) üzerinden geçer. ltrace bu tablodaki girişleri runtime'da değiştirerek her çağrıyı kendi kod parçasından geçirir, argümanları ve dönüş değerini kaydeder, ardından gerçek fonksiyona yönlendirir.

bash — kurulum
# Debian/Ubuntu
sudo apt install ltrace

# ARM embedded: Buildroot'ta
# BR2_PACKAGE_LTRACE=y

# Yocto:
# IMAGE_INSTALL:append = " ltrace"

# ltrace statik binary'lerde çalışmaz!
file myapp | grep -q "statically linked" && echo "ltrace çalışmaz"

01 Temel kullanım — shared lib çağrılarını izle

ltrace çıktısı, her kütüphane fonksiyon çağrısını argümanları ve dönüş değeriyle birlikte gösterir.

bash
# Temel kullanım
ltrace ./myapp

# Çalışan sürece bağlan
ltrace -p 1234

# Kısa çıktı (sadece kütüphane adlarını göster)
ltrace -l '*' ./myapp 2>&1 | head -30
ltrace çıktısı
__libc_start_main(0x10454, 1, 0xbefff6c4, 0x10580 <unfinished ...>
fopen("/etc/sensor.conf", "r")          = 0x20010
fgets(0xbefff540, 256, 0x20010)         = 0xbefff540
strcmp("port", "port")                  = 0
fgets(0xbefff540, 256, 0x20010)         = 0xbefff540
strcmp("baud", "baud")                  = 0
fclose(0x20010)                         = 0
malloc(48)                              = 0x200a0
memset(0x200a0, '\0', 48)               = 0x200a0
printf("Sensor initialized on %s\n", "/dev/ttyS0") = 30
sleep(1)                                = 0
...
+++ exited (status 0) +++

Format: fonksiyon_adı(argümanlar) = dönüş_değeri. String argümanlar otomatik olarak tırnak içinde gösterilir (ilk 32 karakter). <unfinished ...>, çok katmanlı çağrılarda görülür.

02 -e — çağrı filtreleme

ltrace çıktısı da strace gibi gürültülü olabilir. -e ile belirli fonksiyonları filtreleyin.

bash
# Sadece malloc ve free
ltrace -e malloc,free myapp

# Belirli kütüphaneyi filtrele
ltrace -l libpthread.so.0 myapp

# Birden fazla kütüphane
ltrace -l 'libpthread*' -l 'libssl*' myapp

# Joker karakter ile fonksiyon filtrele
ltrace -e 'str*' myapp
# strcmp, strlen, strncpy, strdup... — tüm str* fonksiyonları

# Belirli fonksiyonları hariç tut
ltrace -e '!memcpy,memset' myapp

# Özet istatistik (-c)
ltrace -c myapp
ltrace -c çıktısı
% time     seconds  usecs/call     calls      function
------ ----------- ----------- --------- --------------------
 45.23    0.023456        1234        19 read
 22.11    0.011478         574        20 fgets
 18.34    0.009512         475        20 strcmp
  8.12    0.004213         421        10 malloc
  4.20    0.002180         218        10 free
  1.00    0.000519         519         1 fopen
  0.62    0.000322          45         7 strlen
  0.38    0.000197         197         1 fclose
------ ----------- ----------- --------- --------------------
100.00    0.051877                    88 total

03 -C — C++ demangling

C++ uygulamalarında kütüphane çağrıları mangled isimlerle görünür. -C bayrağı bunları okunabilir hale getirir.

bash
# -C olmadan (C++ binary)
ltrace ./mycppapp 2>&1 | head -10
# _ZNSt8ios_base4InitC1Ev(0x404120, 1, 0x7ffc...) = 0
# _ZNSt6localeC1Ev(0x404130, ...)                  = 0x404130
# _ZN6SensorC1Eii(0x7ffd..., 1, 115200)            = 0x7ffd...

# -C ile demangled
ltrace -C ./mycppapp 2>&1 | head -10
# std::ios_base::Init::Init()(0x404120, ...) = 0
# std::locale::locale()(0x404130, ...)       = 0x404130
# Sensor::Sensor(int, int)(0x7ffd..., 1, 115200) = 0x7ffd...
İPUCU — STL container'ları

C++ STL container'ları (vector, map, string) sayısız iç fonksiyon çağrısı üretir. ltrace çıktısı çok gürültülü olabilir. ltrace -e malloc,free -C mycppapp kombinasyonu, yalnızca bellek işlemlerini görmek için çok kullanışlıdır.

04 -n — indent ile çağrı derinliği

-n N ile her iç içe çağrı N boşluk girintili gösterilir. Çağrı ağacını anlamayı kolaylaştırır.

bash
# -n 4: her seviye 4 boşluk girinti
ltrace -n 4 ./myapp 2>&1 | head -20
ltrace -n 4 çıktısı
__libc_start_main(...)
    sensor_init(...)                                <unfinished ...>
        fopen("/etc/sensor.conf", "r")              = 0x20010
        fgets(0xbefff540, 256, 0x20010)             = 0xbefff540
        atoi("115200")                              = 115200
        fclose(0x20010)                             = 0
        malloc(sizeof_SensorHandle)                 = 0x200a0
    <... sensor_init resumed>                       = 0x200a0
    sensor_read(0x200a0, ...)                       <unfinished ...>
        read(fd=5, buf, 128)  [system call]

05 malloc / free takibi — basit memory leak tespiti

ltrace ile malloc/free çağrılarını sayarak basit bellek sızıntısı tespiti yapılabilir. Valgrind kadar ayrıntılı değildir ama çok daha hızlıdır.

bash
# malloc ve free çağrılarını izle
ltrace -e malloc,free,calloc,realloc myapp 2>&1 | \
  grep -E "^(malloc|free|calloc|realloc)"
çıktı
malloc(48)   = 0x200a0
malloc(1024) = 0x20120
free(0x200a0)
malloc(72)   = 0x200a0
malloc(256)  = 0x20520
free(0x20120)
# malloc(256) = 0x20520 için free yok → potansiyel leak!
bash — basit leak sayacı scripti
# malloc ve free çağrılarını say
ltrace -e malloc,free,calloc myapp 2>&1 | \
  awk '
    /^malloc|^calloc/ { mallocs++ }
    /^free/           { frees++ }
    END {
      printf "malloc+calloc: %d\nfree: %d\n", mallocs, frees
      if (mallocs > frees)
          printf "UYARI: %d adet serbest bırakılmamış tahsis!\n", mallocs - frees
      else
          printf "OK: tahsis/serbest bırakma dengeli\n"
    }
  '
DİKKAT — ltrace vs Valgrind

ltrace ile malloc/free sayımı yüzeysel bir kontroldür: aynı sayıda malloc ve free olsa bile farklı pointer'larla çağrılmış olabilir (double-free veya yanlış pointer). Gerçek memory leak analizi için Valgrind Memcheck kullanın.

06 Dinamik linker debug — LD_PRELOAD ile fark

ltrace ve LD_PRELOAD farklı mekanizmalardır. ltrace non-intrusive izleme yaparken LD_PRELOAD gerçek bir fonksiyon değiştirir.

bash — LD_PRELOAD ile malloc intercept
# malloc_hook.c: tüm malloc çağrılarını logla
cat > /tmp/malloc_hook.c <<'EOF'
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

static void *(*real_malloc)(size_t) = NULL;

void *malloc(size_t size) {
    if (!real_malloc)
        real_malloc = dlsym(RTLD_NEXT, "malloc");
    void *ptr = real_malloc(size);
    fprintf(stderr, "[MALLOC] size=%zu ptr=%p\n", size, ptr);
    return ptr;
}
EOF

# Derle
gcc -shared -fPIC -o /tmp/malloc_hook.so /tmp/malloc_hook.c -ldl

# Çalıştır
LD_PRELOAD=/tmp/malloc_hook.so myapp 2>&1 | head -20
# [MALLOC] size=48  ptr=0x200a0
# [MALLOC] size=1024 ptr=0x20120

ltrace vs LD_PRELOAD karşılaştırması

ltrace
Binary'yi değiştirmez, PLT hook kullanır. Hızlı başlatma. Ayrıntılı argüman gösterimi. Tüm shared lib çağrılarına erişir.
LD_PRELOAD
Gerçek fonksiyon değiştirme — istediğiniz kodu çalıştırabilirsiniz. Heap profiling, logging, mock için ideal. Üretim ortamında da kullanılabilir.
bash — LD_DEBUG ile dinamik linker debug
# Hangi kütüphanelerin nasıl yüklendiğini göster
LD_DEBUG=libs myapp 2>&1 | head -20
#   1234: find library=libc.so.6 [0]: found at /lib/arm-linux-gnueabihf/libc.so.6
#   1234: find library=libsensor.so.1 [0]: trying /usr/local/lib...
#   1234: find library=libsensor.so.1 [0]: NOT FOUND

# LD_DEBUG seçenekleri
# LD_DEBUG=libs    : kütüphane arama
# LD_DEBUG=symbols : sembol çözümleme
# LD_DEBUG=bindings: bağlama bilgileri
# LD_DEBUG=all     : her şey (çok ayrıntılı)

07 Pratik: yavaş kütüphane fonksiyonu tespiti

Bir embedded uygulaması beklenenden yavaş çalışıyorsa, ltrace ile hangi kütüphane çağrısının zaman aldığı bulunabilir.

Senaryo: JSON parse kütüphanesi profilleme

bash
# -T: her çağrının süresini göster
ltrace -T -C myapp 2>&1 | grep -v "= 0 <0\." | head -30
# Sadece 0.0xx saniyeden uzun süren çağrıları göster
ltrace -T çıktısı
fopen("/var/lib/sensor/data.json", "r")   = 0x20010  <0.000234>
fread(0x20040, 1, 65536, 0x20010)         = 4096     <0.000089>
json_parse(0x20040, 4096)                 = 0x21000  <1.234567>
# json_parse 1.23 saniye sürdü! CPU-bound işlem
json_get(0x21000, "temperature")          = 0x21100  <0.000012>
json_free(0x21000)                        = NULL     <0.000345>
bash — istatistik ile yavaş fonksiyon bul
# ltrace -c ile toplam süre istatistikleri
ltrace -c myapp 2>&1
# % time     seconds  usecs/call   calls   function
# 94.23    1.234567      1234567       1   json_parse  <-- açık kazanan
#  3.11    0.040234         2012      20   fread
#  1.22    0.015998         1599      10   pthread_mutex_lock

# Çözüm: json_parse'ı daha hızlı kütüphane ile değiştir
# ya da sonucu önbelleğe al (dosya değişmemişse tekrar parse etme)

ARM embedded: ltrace sınırlamaları

bash
# ltrace bazı ARMv7 Thumb-2 binary'lerinde sorun çıkarabilir
# Alternatif: uftrace (daha modern, ARM desteği daha iyi)
uftrace record ./myapp
uftrace replay | head -30

# Ya da gprof ile profil (derleme zamanı enstrümantasyon)
arm-linux-gnueabihf-gcc -pg -o myapp_prof sensor.c main.c
./myapp_prof
arm-linux-gnueabihf-gprof myapp_prof gmon.out | head -30