00 strace nedir — ptrace mekanizması
strace, Linux'un ptrace(2) sistem çağrısı üzerine inşa edilmiş bir izleme aracıdır. Kaynak kodu olmayan ya da erişilemeyen binary'lerin davranışını anlamak için ideal yöntemdir.
Bir süreç her sistem çağrısı yapmak istediğinde kernel'a geçiş yapar. ptrace mekanizması bu geçişe "hook" eklemeye izin verir: strace, izlenen süreci her syscall girişinde ve çıkışında durdurur, argümanları ve dönüş değerini kaydeder, sonra süreci devam ettirir.
ptrace ek yükü
# strace ek yükünü ölç
time ls /
# real 0m0.004s
time strace ls / 2>/dev/null
# real 0m0.018s <-- ~4-5x yavaş
# Yüksek frekanslı uygulamalarda strace ciddi yavaşlamaya yol açar
# Sadece debug amacıyla kullanılmalı, üretimde asla
# Debian/Ubuntu
sudo apt install strace
# ARM embedded: Buildroot'ta CONFIG_STRACE=y
# Yocto: IMAGE_INSTALL += "strace"
# Sürümü kontrol et
strace --version
# strace -- version 5.16
01 Temel kullanım — yeni süreç ve -p PID attach
strace ya yeni bir süreci başlatır ya da çalışan bir sürece bağlanır. Çıktı varsayılan olarak stderr'e yazılır.
# Yeni süreç başlat ve izle
strace ls /tmp
# Çalışan sürece bağlan (root gerekebilir)
strace -p 1234
# İsimle bağlan (pidof ile)
strace -p $(pidof nginx)
# Birden fazla PID izle
strace -p 1234 -p 1235
execve("/bin/ls", ["ls", "/tmp"], 0x7ffe... /* 23 vars */) = 0
brk(NULL) = 0x55a8f2b00000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3a1c200000
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=87432, ...}) = 0
mmap(NULL, 87432, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f3a1c1ec000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
...
openat(AT_FDCWD, "/tmp", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
getdents64(3, /* 14 entries */, 32768) = 448
write(1, "core.myapp.1234 sensor.log ...", 34) = 34
close(3) = 0
exit_group(0) = ?
Her satır: syscall adı, argümanlar ve dönüş değeri (= 0 başarı, negatif değer hata). Hata durumlarında errno sembolik ismi de görünür: = -1 ENOENT (No such file or directory)
02 -e trace= — filtreleme
Filtresiz strace çıktısı çok gürültülüdür. -e trace= ile ilgilenilen syscall kategorilerini seçebilirsiniz.
# Sadece dosya işlemleri
strace -e trace=file myapp
# open, openat, read, write, close, stat, lstat, access, unlink...
# Sadece ağ işlemleri
strace -e trace=network myapp
# socket, connect, bind, listen, accept, send, recv, sendto...
# Sadece bellek işlemleri
strace -e trace=memory myapp
# mmap, munmap, mprotect, brk, madvise...
# Sadece sinyal işleme
strace -e trace=signal myapp
# Sadece süreç yönetimi
strace -e trace=process myapp
# execve, fork, clone, wait, exit...
# Belirli syscall'ları seç
strace -e trace=openat,read,write,close myapp
# Belirli syscall'ları hariç tut
strace -e trace='!mmap,mprotect,munmap' myapp
openat(AT_FDCWD, "/etc/sensor.conf", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/default/sensor.conf", O_RDONLY) = 3
read(3, "[sensor]\nport=/dev/ttyS0\nbaud=11", 4096) = 78
close(3) = 0
openat(AT_FDCWD, "/dev/ttyS0", O_RDWR|O_NOCTTY|O_NONBLOCK) = 4
# /etc/sensor.conf bulunamadı → fallback /etc/default/sensor.conf açıldı
03 -c — syscall istatistikleri
-c bayrağı, program sonunda hangi syscall'ın kaç kez çağrıldığını ve ne kadar süre harcadığını özetler. Performans darboğazlarını bulmak için hızlı bir yöntemdir.
# İstatistik modu (-c)
strace -c myapp
# İstatistik + belirli kategori
strace -c -e trace=file myapp
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
68.42 0.041234 1234 33 read
15.31 0.009234 89 104 12 openat
8.12 0.004899 122 40 write
4.22 0.002543 36 71 close
1.98 0.001193 23 52 fstat
0.87 0.000524 524 1 execve
0.62 0.000374 17 22 mmap
0.27 0.000163 20 8 mprotect
0.19 0.000117 117 1 munmap
------ ----------- ----------- --------- --------- ----------------
100.00 0.060281 332 12 total
# read: toplam sürenin %68'i → I/O darboğazı var!
04 -tt, -T — zaman damgası
Zaman damgaları, hangi syscall'ın ne kadar sürdüğünü ve olayların sırasını anlamak için kritiktir.
# -t: saniye cinsinden zaman damgası
strace -t myapp
# -tt: mikrosaniye hassasiyetinde
strace -tt myapp
# -ttt: Unix epoch (floating point)
strace -ttt myapp
# -T: her syscall'ın süresi (sonuna eklenir)
strace -T myapp
# Birlikte kullanım
strace -tt -T myapp
14:23:45.123456 openat(AT_FDCWD, "/dev/i2c-1", O_RDWR) = 5 <0.000234>
14:23:45.123721 ioctl(5, I2C_SLAVE, 0x48) = 0 <0.000089>
14:23:45.123834 write(5, "\x01\x00", 2) = 2 <0.000156>
14:23:45.270000 read(5, "\x0c\x80", 2) = 2 <0.146123>
# read süresi 0.146s → ADC conversion time (I2C sensör okuma)
14:23:45.270200 close(5) = 0 <0.000045>
05 -f — fork / exec izleme
Daemon'lar ve shell scriptleri genellikle alt süreçler oluşturur. -f bu alt süreçleri de izler.
# -f: fork/clone ile oluşturulan tüm çocuk süreçleri izle
strace -f myapp
# -ff: her süreci ayrı dosyaya yaz (PID ile)
strace -ff -o /tmp/trace myapp
# /tmp/trace.1234 (ana süreç)
# /tmp/trace.1235 (fork'lanan çocuk)
# /tmp/trace.1236 (exec ile başlatılan süreç)
# Sistem başlangıcı izleme (PID 1 — init/systemd)
strace -p 1 -f -e trace=process 2>&1 | head -50
1234 clone(child_stack=NULL, flags=CLONE_CHILD_...) = 1235
1235 execve("/usr/bin/sensor_helper", ...) = 0
1235 openat(AT_FDCWD, "/dev/i2c-1", O_RDWR) = 3
1234 wait4(1235, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 1235
# Her satır PID ile başlar
06 -o, -k — dosyaya yaz ve stack trace
Uzun süre çalışan süreçler için çıktıyı dosyaya yönlendirmek ve her syscall'da stack trace almak.
# -o: çıktıyı dosyaya yaz (stderr değil)
strace -o /tmp/myapp_trace.log myapp
# Hem ekranda görüntüle hem dosyaya yaz
strace myapp 2>&1 | tee /tmp/myapp_trace.log
# -k: her syscall için kullanıcı alanı stack trace ekle
# (strace 5.0+ gerekir, DWARF debug info yardımcı olur)
strace -k myapp 2>&1 | head -30
openat(AT_FDCWD, "/dev/i2c-1", O_RDWR) = 3
> /lib/arm-linux-gnueabihf/libc.so.6(open64+0x20) [0x76f3e200]
> myapp(i2c_open+0x18) [0x10498]
> myapp(sensor_init+0x34) [0x104e8]
> myapp(main+0x24) [0x10544]
# Hangi fonksiyon zincirinin bu syscall'ı tetiklediği görünür
07 Pratik: dosya erişimi ve network analizi
İki yaygın embedded senaryo: binary'nin hangi konfigürasyon dosyalarını aradığını bulmak ve ağ bağlantısını analiz etmek.
Senaryo 1: binary hangi dosyaları açıyor?
# Tüm dosya açma işlemlerini listele
strace -e trace=openat,open myapp 2>&1 | grep -v "= -1"
# Başarısız açmaları filtrele, sadece başarılı olanları göster
# Hangi dosyaları açmaya çalışıp bulamadı?
strace -e trace=openat myapp 2>&1 | grep ENOENT
# openat(..., "/etc/sensor.conf", ...) = -1 ENOENT
# openat(..., "/var/lib/sensor/config", ...) = -1 ENOENT
# Sıralı liste (unique dosyalar)
strace -e trace=openat myapp 2>&1 | \
grep -oP '"[^"]*"' | sort -u
Senaryo 2: ağ bağlantısı analizi
# Network syscall'larını izle
strace -e trace=network myapp 2>&1 | head -30
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 5
connect(5, {sa_family=AF_INET, sin_port=htons(1883),
sin_addr=inet_addr("192.168.1.10")}, 16) = -1 ECONNREFUSED
# MQTT broker 192.168.1.10:1883'e bağlanmaya çalışıyor ama reddedildi
socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) = 5
sendto(5, "...", 48, 0, {sa_family=AF_INET,
sin_port=htons(53), sin_addr=inet_addr("8.8.8.8")}, 16) = 48
# DNS sorgusu 8.8.8.8:53'e
08 Embedded: busybox strace + "permission denied" debug
Kaynak kısıtlı embedded sistemlerde busybox strace kullanılır. Permission denied hatalarını debug etmek için strace vazgeçilmezdir.
busybox strace
# busybox strace (tam strace'in alt kümesi)
busybox strace myapp
# Desteklenen bayraklar genellikle: -f, -e, -o, -p
busybox strace --help
# Buildroot'ta tam strace eklemek için:
# BR2_PACKAGE_STRACE=y
# Yocto'da:
# IMAGE_INSTALL:append = " strace"
# Statik strace indir ve SCP ile hedefe kopyala
# (eğer rootfs'e ekleyemiyorsan)
scp strace-arm-static root@192.168.1.100:/tmp/
/tmp/strace-arm-static myapp
Senaryo: "permission denied" debug
# Program "permission denied" veriyor ama nerede?
./sensor_daemon
# Error: Permission denied
# strace ile hangi işlemin hata verdiğini bul
strace -e trace=file ./sensor_daemon 2>&1 | grep EACCES
openat(AT_FDCWD, "/dev/i2c-1", O_RDWR) = -1 EACCES (Permission denied)
# /dev/i2c-1 açılamıyor!
# İzinleri kontrol et
ls -la /dev/i2c-1
# crw------- 1 root root 89, 1 /dev/i2c-1
# Sadece root erişebiliyor
# Çözüm 1: i2c grubuna ekle
sudo usermod -aG i2c $USER
sudo chown root:i2c /dev/i2c-1
sudo chmod g+rw /dev/i2c-1
# Çözüm 2: udev kuralı (kalıcı)
echo 'SUBSYSTEM=="i2c-dev", MODE="0660", GROUP="i2c"' \
> /etc/udev/rules.d/99-i2c.rules
udevadm control --reload-rules
Güvenli Linux yapılandırmalarında (Yama: Yama seccomp, SELinux veya AppArmor) ptrace varsayılan olarak kısıtlanmış olabilir. echo 0 > /proc/sys/kernel/yama/ptrace_scope komutu (root olarak) ptrace'i geçici olarak açar. Üretim sistemlerinde dikkatli olun.