Perkakas analisis sebelumnya mengamati instruksi yang dijalankan prosesor, sedangkan strace mengamati batas antara program dan kernel. Topik ini membahas cara menggunakan strace untuk menelusuri setiap syscall yang dijalankan sebuah executable, mulai dari program assembly tanpa libc sampai program C biasa, beserta cara membaca argumen dan nilai balik yang dilaporkannya. Pembahasan juga mencakup opsi -o untuk menyimpan telusuran ke berkas, opsi -e trace= untuk menyaring jenis syscall tertentu, dan cara membaca kegagalan syscall pada kolom nilai balik.
Menelusuri program assembly sendiri#
strace menjalankan sebuah program sambil melaporkan setiap syscall yang dipanggilnya, lengkap dengan argumen pada kolom tengah dan nilai balik pada kolom kanan. Opsi -o menyalurkan laporan ke berkas alih-alih mencampurnya dengan keluaran program. Program berikut adalah program assembly tanpa libc yang hanya memanggil dua syscall, sehingga telusurannya pendek dan mudah dibaca.
; tulis.asm
; Menulis satu baris teks ke stdout melalui write, lalu mengakhiri proses.
default rel
section .rodata
pesan: db "Halo dari strace", 10
panjang equ $ - pesan
section .text
global _start
_start:
mov eax, 1 ; nomor syscall write
mov edi, 1 ; file descriptor 1, yaitu stdout
lea rsi, [pesan] ; alamat teks yang akan ditulis
mov edx, panjang ; jumlah byte yang akan ditulis
syscall
mov edi, eax ; jumlah byte yang ditulis menjadi kode keluar
mov eax, 60 ; nomor syscall exit
syscallPerintah berikut merakit program tersebut, menjalankannya dengan strace, lalu menampilkan baris-baris kunci dari berkas telusuran.
nasm -f elf64 tulis.asm -o tulis.o
ld tulis.o -o tulis
strace -o trace.log ./tulis
grep -E '^(write|exit|\+\+\+)' trace.logHalo dari strace
write(1, "Halo dari strace\n", 17) = 17
exit(17) = ?
+++ exited with 17 +++Baris pertama adalah keluaran program itu sendiri, sedangkan tiga baris berikutnya berasal dari strace. Baris write memuat empat bagian yang selalu sama bentuknya pada setiap telusuran, yaitu nama syscall, argumen dalam tanda kurung, tanda sama dengan, dan nilai balik di ujung kanan. Nilai balik write adalah 17 karena 17 byte berhasil ditulis, dan angka yang sama kemudian dibawa menjadi kode keluar proses. Baris exit(17) = ? menampilkan tanda tanya karena proses sudah berakhir pada syscall itu, sehingga tidak ada lagi proses yang menerima nilai baliknya. Baris +++ exited with 17 +++ adalah catatan penutup strace, bukan syscall.
Program C dan startup libc#
Program C yang mencetak satu baris memanggil syscall yang jauh lebih banyak sebelum mencapai fungsi main. Program berikut setara dengan program assembly sebelumnya dari sisi keluarannya, yaitu satu baris teks ke stdout.
#include <stdio.h>
int main(void) {
printf("hitung: %d\n", 6 * 7);
return 0;
}hitung: 42gcc cetak.c -o cetak
strace -o trace-c.log ./cetak
grep -E '^(write|exit|\+\+\+)' trace-c.loghitung: 42
write(1, "hitung: 42\n", 11) = 11
exit_group(0) = ?
+++ exited with 0 +++Berkas trace-c.log memuat sekitar lima puluh baris sebelum baris write di atas. Baris-baris awalnya adalah execve yang mengeksekusi program, deretan mmap yang memetakan libc ke memori, brk yang menyiapkan heap, set_tid_address yang mendaftarkan identitas thread utama, dan beberapa syscall lainnya. Seluruhnya adalah pekerjaan startup yang dilakukan libc sebelum baris pertama main dijalankan, sedangkan program assembly tanpa libc menyelesaikan tugas yang sama hanya dengan dua syscall, dan perbandingan ini memperlihatkan bahwa kedua program bertumpu pada antarmuka yang sama, yaitu nomor syscall pada register dan nilai balik pada kolom kanan, meskipun jumlah panggilannya berbeda jauh. Rangkaian startup tersebut bukan kode yang ditulis pemrogram, melainkan pekerjaan penaut dinamis yang menautkan libc ke proses sebelum main dijalankan. Karena itu, dua program C yang keluarannya sama persis dapat memiliki telusuran yang hampir seluruhnya terisi pekerjaan persiapan, dan pemahaman tentang bagian mana yang milik program sendiri baru diperoleh setelah telusuran dibaca sampai ke baris yang benar-benar memanggil write.
Memfilter telusuran dan membaca kegagalan#
Telusuran penuh yang memuat semua jenis syscall sering kali melebihi kebutuhan, sehingga strace menyediakan opsi -e trace=nama untuk membatasi laporan pada syscall yang disebut saja. Perintah berikut mengulangi telusuran program C dengan hanya melaporkan syscall write.
strace -e trace=write -o trace-write.log ./cetak
cat trace-write.loghitung: 42
write(1, "hitung: 42\n", 11) = 11
+++ exited with 0 +++Seluruh baris startup libc tidak muncul dalam laporan karena tidak termasuk dalam filter, sehingga tinggal satu syscall yang dipanggil program dan satu catatan penutup. Filter yang sama bekerja pada program mana pun, misalnya strace -e trace=openat cat berkas untuk mengamati pembukaan berkas oleh cat. Opsi lain yang berguna adalah -c, yang merangkum seluruh telusuran menjadi tabel jumlah panggilan per jenis syscall. Kolom jumlah dan nama syscall pada tabel itu stabil, sedangkan kolom waktunya berubah antar eksekusi dan sebaiknya tidak dijadikan acuan.
Kegagalan syscall juga terlihat pada kolom yang sama. Perintah berikut menjalankan cat pada sebuah berkas yang tidak ada, lalu menampilkan baris openat yang relevan.
strace -e trace=openat -o trace-open.log cat tidak-ada.txt
grep 'tidak-ada' trace-open.logcat: tidak-ada.txt: No such file or directory
openat(AT_FDCWD, "tidak-ada.txt", O_RDONLY) = -1 ENOENT (No such file or directory)Nilai baliknya adalah -1 ENOENT (No such file or directory), yang terdiri atas angka negatif penanda kegagalan, nama kegagalan kernel, dan deskripsi dalam tanda kurung. Kernel tidak pernah melempar pengecualian pada syscall, melainkan selalu melaporkan hasilnya melalui nilai balik di kolom kanan, dan strace memperlihatkan laporan itu apa adanya untuk setiap pemanggilan, baik yang berhasil maupun yang gagal.
Ringkasan#
- strace menjalankan program dan melaporkan setiap syscall berikut argumennya, dengan nilai balik selalu pada kolom kanan setelah tanda sama dengan.
- Opsi
-omenyimpan telusuran ke berkas, sedangkan-e trace=namamembatasi laporan hanya pada jenis syscall yang disebut. - Program C kecil memanggil puluhan syscall untuk startup libc sebelum
main, sedangkan program assembly tanpa libc cukup dua syscall untuk tugas yang sama. - Kegagalan syscall muncul sebagai nilai balik negatif beserta nama kegagalannya, misalnya
-1 ENOENTpada pembukaan berkas yang tidak ada.
Referensi#
- strace(1) — Linux man-pages
— Dokumentasi opsi strace, termasuk
-o,-e trace=, dan-cyang dipakai pada topik ini. - open(2) — Linux man-pages
— Penjelasan syscall pembukaan berkas dan arti nilai balik
-1beserta nama kegagalannya.