Syscall adalah mekanisme di mana program pengguna berinteraksi dengan kernel Linux, dan strace adalah alat yang ampuh untuk melacaknya. Untuk lebih memahami cara kerja sistem operasi, akan sangat membantu untuk memahami cara kerjanya.
Sistem operasi dapat dibagi menjadi dua mode operasi:
- Mode kernel adalah mode hak istimewa yang digunakan oleh kernel sistem operasi.
- Mode pengguna adalah mode di mana sebagian besar aplikasi pengguna dijalankan.
Pengguna biasanya menggunakan utilitas baris perintah dan antarmuka grafis (GUI) untuk pekerjaan sehari-hari mereka. Pada saat yang sama, panggilan sistem bekerja secara tidak terlihat di latar belakang, mengacu pada kernel untuk melakukan pekerjaan tersebut.
Panggilan sistem sangat mirip dengan panggilan fungsi dalam arti bahwa panggilan tersebut diberikan argumen dan mengembalikan nilai. Satu-satunya perbedaan adalah bahwa panggilan sistem berfungsi di tingkat kernel, tetapi fungsi tidak. Beralih dari mode pengguna ke mode kernel dilakukan menggunakan mekanisme interupsi khusus .
Sebagian besar detail ini disembunyikan dari pengguna di pustaka sistem (glibc di sistem Linux). Panggilan sistem bersifat generik, tetapi meskipun demikian, mekanisme pelaksanaannya sebagian besar bergantung pada perangkat keras.
Artikel ini membahas beberapa contoh praktis penggunaan panggilan sistem parsing
strace. Contohnya menggunakan Red Hat Enterprise Linux, tetapi semua perintah seharusnya berfungsi pada distribusi Linux lain:
[root@sandbox ~]# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.7 (Maipo)
[root@sandbox ~]#
[root@sandbox ~]# uname -r
3.10.0-1062.el7.x86_64
[root@sandbox ~]#
Pertama, pastikan Anda memiliki alat yang diperlukan terinstal di sistem Anda. Anda
stracedapat memeriksa apakah sudah diinstal menggunakan perintah di bawah ini. Untuk melihat versi, stracejalankan dengan parameter -V:
[root@sandbox ~]# rpm -qa | grep -i strace
strace-4.12-9.el7.x86_64
[root@sandbox ~]#
[root@sandbox ~]# strace -V
strace -- version 4.12
[root@sandbox ~]#
Jika
stracetidak diinstal, instal dengan menjalankan:
yum install strace
Misalnya, buat direktori pengujian dalam
/tmpdan dua file menggunakan perintah touch:
[root@sandbox ~]# cd /tmp/
[root@sandbox tmp]#
[root@sandbox tmp]# mkdir testdir
[root@sandbox tmp]#
[root@sandbox tmp]# touch testdir/file1
[root@sandbox tmp]# touch testdir/file2
[root@sandbox tmp]#
(Saya
/tmphanya menggunakan direktori karena setiap orang memiliki akses ke sana, tetapi Anda dapat menggunakan direktori lain.)
Gunakan perintah untuk
lsmemeriksa bahwa testdirfile telah dibuat di direktori :
[root@sandbox tmp]# ls testdir/
file1 file2
[root@sandbox tmp]#
Anda mungkin menggunakan perintah
lssetiap hari tanpa menyadari bahwa panggilan sistem sedang berjalan di bawah tenda. Di sinilah abstraksi berperan. Beginilah cara kerja perintah ini:
-> (glibc) ->
Perintah tersebut
lsmemanggil fungsi dari pustaka sistem Linux (glibc). Perpustakaan ini, pada gilirannya, memanggil panggilan sistem, yang melakukan sebagian besar pekerjaan.
Jika Anda ingin mengetahui fungsi apa yang dipanggil dari pustaka glibc, gunakan perintah yang
ltracediikuti dengan perintah ls testdir/:
ltrace ls testdir/
Jika
ltracetidak diinstal, maka instal:
yum install ltrace
Akan ada banyak informasi di layar, tapi jangan khawatir - kita akan melihatnya nanti. Berikut beberapa fungsi pustaka penting dari keluarannya
ltrace:
opendir("testdir/") = { 3 }
readdir({ 3 }) = { 101879119, "." }
readdir({ 3 }) = { 134, ".." }
readdir({ 3 }) = { 101879120, "file1" }
strlen("file1") = 5
memcpy(0x1665be0, "file1\0", 6) = 0x1665be0
readdir({ 3 }) = { 101879122, "file2" }
strlen("file2") = 5
memcpy(0x166dcb0, "file2\0", 6) = 0x166dcb0
readdir({ 3 }) = nil
closedir({ 3 })
Dengan memeriksa keluaran ini, Anda mungkin dapat memahami apa yang sedang terjadi. Direktori bernama
testdirdibuka menggunakan fungsi perpustakaan opendir, diikuti dengan panggilan ke fungsi readdiryang membaca isi direktori. Akhirnya, sebuah fungsi dipanggil closediryang menutup direktori yang dibuka sebelumnya. Untuk saat ini, abaikan fungsi lain seperti strlendan memcpy.
Seperti yang Anda lihat, sangat mudah untuk melihat fungsi pustaka yang dipanggil, tetapi dalam artikel ini kita akan fokus pada panggilan sistem yang dipanggil oleh fungsi pustaka sistem.
Untuk melihat panggilan sistem gunakan
stracedengan perintah ls testdirseperti yang ditunjukkan di bawah ini. Dan sekali lagi Anda mendapatkan banyak informasi yang tidak koheren:
[root@sandbox tmp]# strace ls testdir/
execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
brk(NULL) = 0x1f12000
<<< truncated strace output >>>
write(1, "file1 file2\n", 13file1 file2
) = 13
close(1) = 0
munmap(0x7fd002c8d000, 4096) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++
[root@sandbox tmp]#
Sebagai hasil eksekusi,
straceAnda akan menerima daftar panggilan sistem yang dijalankan selama eksekusi perintah ls. Semua panggilan sistem dapat dibagi ke dalam kategori berikut:
- Manajemen proses
- Manajemen file
- Direktori dan manajemen sistem file
- Lainnya
Ada cara mudah untuk menganalisis informasi yang diterima - tulis output ke file menggunakan opsi
-o.
[root@sandbox tmp]# strace -o trace.log ls testdir/
file1 file2
[root@sandbox tmp]#
Kali ini, tidak akan ada data di layar - perintah akan
lsberfungsi seperti yang diharapkan, menampilkan daftar file dan menulis semua output straceke file trace.log. Untuk perintah sederhana, lsfile tersebut berisi hampir 100 baris:
[root@sandbox tmp]# ls -l trace.log
-rw-r--r--. 1 root root 7809 Oct 12 13:52 trace.log
[root@sandbox tmp]#
[root@sandbox tmp]# wc -l trace.log
114 trace.log
[root@sandbox tmp]#
Lihat baris pertama di file
trace.log:
execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
- Di awal baris adalah nama panggilan sistem yang sedang dijalankan - execve.
- Teks dalam tanda kurung adalah argumen yang diteruskan ke panggilan sistem.
- Angka setelah tanda = (dalam hal ini, 0) adalah nilai yang dikembalikan oleh pemanggilan sistem.
Sekarang hasilnya tidak terlalu menakutkan, bukan? Dan Anda juga dapat menerapkan logika yang sama untuk baris lain.
Perhatikan satu-satunya perintah yang Anda panggil -
ls testdir. Anda tahu nama direktori yang digunakan oleh perintah tersebut ls, jadi mengapa tidak menggunakan grepfor testdirdi dalam file trace.logdan melihat apa yang ditemukannya? Perhatikan baik-baik hasilnya:
[root@sandbox tmp]# grep testdir trace.log
execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
stat("testdir/", {st_mode=S_IFDIR|0755, st_size=32, ...}) = 0
openat(AT_FDCWD, "testdir/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
[root@sandbox tmp]#
Kembali ke analisis di atas
execve, dapatkah Anda mengetahui apa yang dilakukan oleh system call selanjutnya?
execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
Anda tidak perlu mengingat semua panggilan sistem dan apa yang dilakukannya: semuanya ada di dokumentasi. Halaman manual sedang terburu-buru untuk membantu! Pastikan paket diinstal sebelum menjalankan perintah man
man-pages:
[root@sandbox tmp]# rpm -qa | grep -i man-pages
man-pages-3.53-5.el7.noarch
[root@sandbox tmp]#
Ingatlah bahwa Anda perlu menambahkan "2" antara perintah
mandan nama syscall. Jika Anda membaca manabout man( man man), Anda akan melihat bahwa bagian 2 dicadangkan untuk panggilan sistem. Demikian juga, jika Anda memerlukan informasi tentang fungsi pustaka, Anda perlu menambahkan 3 antara mandan nama fungsi pustaka.
Di bawah ini adalah nomor bagian
man:
1. .
2. (, ).
3. ( ).
4. ( /dev).
Untuk melihat dokumentasi untuk panggilan sistem, jalankan man dengan nama panggilan sistem itu.
man 2 execve
Menurut dokumentasi, panggilan sistem
execvemenjalankan program yang diteruskan ke dalam parameter (dalam hal ini adalah ls). Parameter tambahan untuk ls juga diteruskan padanya. Dalam contoh ini, itu testdir. Oleh karena itu, panggilan sistem ini hanya berjalan lsdengan testdirsebagai parameter:
'execve - execute program'
'DESCRIPTION
execve() executes the program pointed to by filename'
Panggilan sistem berikutnya
statdiberikan parameter testdir:
stat("testdir/", {st_mode=S_IFDIR|0755, st_size=32, ...}) = 0
Untuk melihat penggunaan dokumentasi
man 2 stat. Panggilan sistem stat mengembalikan informasi tentang file yang ditentukan. Ingatlah bahwa semua yang ada di Linux adalah file, termasuk direktori.
Selanjutnya, panggilan sistem
openatterbuka testdir. Perhatikan bahwa nilai yang dikembalikan adalah 3. Ini adalah deskriptor file yang akan digunakan dalam panggilan sistem selanjutnya:
openat(AT_FDCWD, "testdir/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
Sekarang buka file tersebut
trace.logdan perhatikan baris yang mengikuti panggilan sistem openat. Anda akan melihat panggilan sistem getdentsyang melakukan sebagian besar pekerjaan yang diperlukan untuk menjalankan perintah ls testdir. Sekarang mari kita jalankan grep getdentsuntuk file tersebut trace.log:
[root@sandbox tmp]# grep getdents trace.log
getdents(3, /* 4 entries */, 32768) = 112
getdents(3, /* 0 entries */, 32768) = 0
[root@sandbox tmp]#
Documentation (
man getdents) mengatakan bahwa ia getdentsmembaca entri direktori , yang persis seperti yang kita butuhkan. Perhatikan bahwa argumen untuk getdent3 adalah deskriptor file yang diperoleh sebelumnya dari panggilan sistem openat.
Sekarang isi direktori telah diterima, kita memerlukan cara untuk menampilkan informasi di terminal. Jadi, kami lakukan
grepuntuk panggilan sistem lain write, yang digunakan untuk mengeluarkan ke terminal:
[root@sandbox tmp]# grep write trace.log
write(1, "file1 file2\n", 13) = 13
[root@sandbox tmp]#
Dalam argumen, Anda dapat melihat nama file yang akan di-output:
file1dan file2. Untuk argumen pertama (1), ingatlah bahwa di Linux, tiga deskriptor file dibuka secara default untuk proses apa pun:
- 0 - aliran input standar
- 1 - aliran keluaran standar
- 2 - aliran kesalahan standar
Jadi, panggilan sistem
writemengambil file1dan file2keluaran standar, yang merupakan terminal, menunjukkan angka 1.
Sekarang Anda tahu apa yang panggilan sistem lakukan sebagian besar pekerjaan untuk tim
ls testdir/. Tetapi bagaimana dengan 100+ panggilan sistem lainnya dalam file trace.log?
Sistem operasi melakukan banyak hal pendukung untuk memulai proses, sehingga banyak hal yang Anda lihat di file
trace.logadalah menginisialisasi dan membersihkan proses. Lihat file trace.log sepenuhnya dan coba pahami apa yang terjadi saat perintah dijalankan ls.
Sekarang Anda dapat menganalisis panggilan sistem untuk program apa pun. Utilitas strace juga menyediakan banyak opsi baris perintah yang berguna, beberapa di antaranya dijelaskan di bawah ini.
Secara default
strace, ini tidak menampilkan semua informasi tentang panggilan sistem. Namun, ini memiliki opsi -v verboseyang akan menampilkan informasi tambahan tentang setiap panggilan sistem:
strace -v ls testdir
Ini adalah praktik yang baik untuk menggunakan parameter
-funtuk melacak proses anak yang dibuat oleh proses yang sedang berjalan:
strace -f ls testdir
Tetapi bagaimana jika Anda hanya menginginkan nama panggilan sistem, berapa kali mereka dijalankan, dan persentase waktu yang dihabiskan untuk mengeksekusinya? Anda dapat menggunakan opsi
-cuntuk mendapatkan statistik ini:
strace -c ls testdir/
Jika Anda ingin melacak panggilan sistem tertentu, misalnya,
opendan mengabaikan yang lain, Anda dapat menggunakan opsi -edengan nama panggilan sistem:
[root@sandbox tmp]# strace -e open ls testdir
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libcap.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libacl.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libattr.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
file1 file2
+++ exited with 0 +++
[root@sandbox tmp]#
Bagaimana jika Anda perlu memfilter dengan beberapa panggilan sistem? Jangan khawatir, Anda dapat menggunakan opsi yang sama
-edan memisahkan panggilan sistem yang diperlukan dengan koma. Misalnya untuk writedan getdent:
[root@sandbox tmp]# strace -e write,getdents ls testdir
getdents(3, /* 4 entries */, 32768) = 112
getdents(3, /* 0 entries */, 32768) = 0
write(1, "file1 file2\n", 13file1 file2
) = 13
+++ exited with 0 +++
[root@sandbox tmp]#
Sejauh ini, kami hanya melacak perintah eksplisit yang dijalankan. Tapi bagaimana dengan perintah yang dijalankan sebelumnya? Bagaimana jika Anda ingin melacak setan? Untuk melakukan ini, Anda
stracememiliki opsi khusus di -pmana Anda dapat meneruskan ID proses.
Kami tidak akan memulai daemon, tetapi menggunakan perintah
catyang menampilkan konten file yang diteruskan sebagai argumen. Tetapi jika Anda tidak menentukan argumen, maka perintah cathanya akan menunggu masukan dari pengguna. Setelah memasukkan teks, itu akan menampilkan teks yang dimasukkan di layar. Begitu seterusnya hingga pengguna mengklik Ctrl+Cuntuk keluar.
Jalankan perintah
catdi satu terminal.
[root@sandbox tmp]# cat
Di terminal lain, temukan ID proses (PID) dengan perintah
ps:
[root@sandbox ~]# ps -ef | grep cat
root 22443 20164 0 14:19 pts/0 00:00:00 cat
root 22482 20300 0 14:20 pts/1 00:00:00 grep --color=auto cat
[root@sandbox ~]#
Sekarang mulailah
stracedengan opsi -pdan PID yang Anda temukan ps. Setelah memulai, itu straceakan menampilkan informasi tentang proses yang terhubung, serta PID-nya. Sekarang stracememantau panggilan sistem yang dilakukan oleh perintah cat. Panggilan sistem pertama yang akan Anda lihat dibaca, menunggu masukan dari utas 0, yaitu, dari input standar, yang sekarang menjadi terminal tempat perintah dijalankan cat:
[root@sandbox ~]# strace -p 22443
strace: Process 22443 attached
read(0,
Sekarang kembali ke terminal tempat Anda membiarkan perintah berjalan
catdan masukkan beberapa teks. Untuk demonstrasi, saya masuk x0x0. Harap dicatat bahwa saya cathanya mengulangi apa yang saya masukkan dan x0x0layar akan muncul dua kali.
[root@sandbox tmp]# cat
x0x0
x0x0
Kembali ke terminal tempat Anda
straceterhubung ke proses cat. Sekarang Anda melihat dua panggilan sistem baru: yang sebelumnya read, yang sekarang telah dibaca x0x0, dan satu lagi untuk menulis write, yang menulis x0x0kembali ke terminal, dan lagi yang baru read, yang menunggu pembacaan dari terminal. Perhatikan bahwa input standar (0) dan output standar (1) ada di terminal yang sama:
[root@sandbox ~]# strace -p 22443
strace: Process 22443 attached
read(0, "x0x0\n", 65536) = 5
write(1, "x0x0\n", 5) = 5
read(0,
Bayangkan manfaat peluncuran
stracedaemon: Anda dapat melihat semua yang terjadi di latar belakang. Selesaikan perintahnyacatdengan mengklik Ctrl+C... Ini juga akan menghentikan sesistracesejak proses yang dipantau telah dihentikan.
Untuk melihat stempel waktu panggilan sistem, gunakan opsi
-t:
[root@sandbox ~]#strace -t ls testdir/
14:24:47 execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
14:24:47 brk(NULL) = 0x1f07000
14:24:47 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2530bc8000
14:24:47 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
14:24:47 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
Bagaimana jika Anda ingin mengetahui waktu yang dihabiskan di antara panggilan sistem? Ada opsi praktis
-ryang menunjukkan waktu yang dibutuhkan untuk menjalankan setiap panggilan sistem. Cukup berguna, bukan?
[root@sandbox ~]#strace -r ls testdir/
0.000000 execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
0.000368 brk(NULL) = 0x1966000
0.000073 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6b1155000
0.000047 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
0.000119 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
Kesimpulan
Utilitas ini
stracesangat berguna untuk mempelajari panggilan sistem di Linux. Untuk opsi baris perintah lainnya, lihat manual dan dokumentasi online.
