GNU/Linux >> Belajar Linux >  >> Linux

Memahami panggilan sistem di Linux dengan strace

Panggilan sistem adalah cara terprogram suatu program meminta layanan dari kernel, dan strace adalah alat yang ampuh yang memungkinkan Anda untuk melacak lapisan tipis antara proses pengguna dan kernel Linux.

Untuk memahami cara kerja sistem operasi, Anda harus terlebih dahulu memahami cara kerja panggilan sistem. Salah satu fungsi utama sistem operasi adalah menyediakan abstraksi untuk program pengguna.

Sistem operasi secara kasar dapat dibagi menjadi dua mode:

  • Mode kernel: Mode istimewa dan kuat yang digunakan oleh kernel sistem operasi
  • Mode pengguna: Tempat sebagian besar aplikasi pengguna berjalan

Sebagian besar pengguna bekerja dengan utilitas baris perintah dan antarmuka pengguna grafis (GUI) untuk melakukan tugas sehari-hari. Panggilan sistem bekerja tanpa suara di latar belakang, berinteraksi dengan kernel untuk menyelesaikan pekerjaan.

Lebih banyak sumber daya Linux

  • Lembar contekan perintah Linux
  • Lembar contekan perintah Linux tingkat lanjut
  • Kursus online gratis:Ikhtisar Teknis RHEL
  • Lembar contekan jaringan Linux
  • Lembar contekan SELinux
  • Lembar contekan perintah umum Linux
  • Apa itu container Linux?
  • Artikel Linux terbaru kami

Panggilan sistem sangat mirip dengan panggilan fungsi, yang berarti mereka menerima dan mengerjakan argumen dan mengembalikan nilai. Satu-satunya perbedaan adalah bahwa panggilan sistem masuk ke kernel, sedangkan panggilan fungsi tidak. Beralih dari ruang pengguna ke ruang kernel dilakukan dengan menggunakan mekanisme perangkap khusus.

Sebagian besar disembunyikan dari pengguna dengan menggunakan pustaka sistem (alias glibc pada sistem Linux). Meskipun panggilan sistem bersifat generik, mekanisme mengeluarkan panggilan sistem sangat bergantung pada mesin.

Artikel ini membahas beberapa contoh praktis dengan menggunakan beberapa perintah umum dan menganalisis panggilan sistem yang dibuat oleh setiap perintah menggunakan strace . Contoh-contoh ini menggunakan Red Hat Enterprise Linux, tetapi perintahnya harus bekerja sama di distro Linux lainnya:

[root@sandbox ~]# cat /etc/redhat-release 
Red Hat Enterprise Linux Server rilis 7.7 (Maipo)
[root@sandbox ~]#
[root@sandbox ~]# uname -r
3.10.0-1062.el7.x86_64
[root@sandbox ~]#

Pertama, pastikan bahwa alat yang diperlukan telah diinstal pada sistem Anda. Anda dapat memverifikasi apakah strace diinstal menggunakan perintah RPM di bawah ini; jika ya, Anda dapat memeriksa strace nomor versi utilitas menggunakan -V pilihan:

[root@sandbox ~]# rpm -qa | grep -i strace
strace-4.12-9.el7.x86_64
[root@sandbox ~]#
[root@sandbox ~]# strace -V
strace -- versi 4.12
[root@sandbox ~]#

Jika tidak berhasil, instal strace dengan menjalankan:

yum install strace 

Untuk tujuan contoh ini, buat direktori pengujian dalam /tmp dan buat dua file menggunakan sentuh perintah menggunakan:

[root@sandbox ~]# cd /tmp/
[root@sandbox tmp]#
[root@sandbox tmp]# mkdir testdir
[root@sandbox tmp]#
[root@sandbox tmp]# sentuh testdir/file1
[root@sandbox tmp]# sentuh testdir/file2
[root@sandbox tmp]#

(Saya menggunakan /tmp direktori karena setiap orang memiliki akses ke sana, tetapi Anda dapat memilih direktori lain jika Anda mau.)

Verifikasi bahwa file dibuat menggunakan ls perintah pada testdir direktori:

[root@sandbox tmp]# ls testdir/
file1  file2
[root@sandbox tmp]#

Anda mungkin menggunakan ls perintah setiap hari tanpa menyadari panggilan sistem sedang bekerja di bawahnya. Ada abstraksi yang bermain di sini; berikut cara kerja perintah ini:

Command-line utility -> Invokes functions from system libraries (glibc) -> Invokes system calls 

ls perintah secara internal memanggil fungsi dari pustaka sistem (alias glibc ) di Linux. Pustaka ini memanggil panggilan sistem yang melakukan sebagian besar pekerjaan.

Jika Anda ingin mengetahui fungsi mana yang dipanggil dari glibc perpustakaan, gunakan ltrace perintah diikuti oleh ls testdir/ biasa perintah:

ltrace ls testdir/ 

Jika lacak belum terpasang, instal dengan memasukkan:

yum install ltrace 

Sekelompok output akan dibuang ke layar; jangan khawatir tentang itu—ikuti saja. Beberapa fungsi perpustakaan penting dari output ltrace perintah yang relevan dengan contoh ini meliputi:

opendir("testdir/")                                  ={ 3 }
readdir({ 3 })                               =." }
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 })                              }      }      }

Dengan melihat output di atas, Anda mungkin dapat memahami apa yang terjadi. Direktori bernama testdir sedang dibuka oleh opendir fungsi library, diikuti dengan panggilan ke readdir fungsi, yaitu membaca isi direktori. Pada akhirnya, ada panggilan ke closedir fungsi, yang menutup direktori yang dibuka sebelumnya. Abaikan strlen lainnya dan memcpy berfungsi untuk saat ini.

Anda dapat melihat fungsi pustaka mana yang dipanggil, tetapi artikel ini akan fokus pada panggilan sistem yang dipanggil oleh fungsi pustaka sistem.

Mirip dengan di atas, untuk memahami panggilan sistem apa yang dipanggil, cukup masukkan strace sebelum ls testdir perintah, seperti yang ditunjukkan di bawah ini. Sekali lagi, sekelompok omong kosong akan dibuang ke layar Anda, yang dapat Anda ikuti di sini:

[root@sandbox tmp]# strace ls testdir/
execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) =0
brk(NULL)                               =0x1f12000
<<>>
write(1, "file1  file2\n", 13file1  file2
)     =13 /> Tutup (1) =0
MUNMAP (0x7FD002C8D000, 4096) =0
tutup (2) =0
exit_group (0) =?
++ keluar dengan 0 +++
[root@sandbox tmp]#

Keluaran di layar setelah menjalankan strace perintah hanyalah panggilan sistem yang dibuat untuk menjalankan ls memerintah. Setiap panggilan sistem memiliki tujuan khusus untuk sistem operasi, dan panggilan tersebut dapat dikategorikan secara luas ke dalam bagian berikut:

  • Panggilan sistem manajemen proses
  • Panggilan sistem manajemen file
  • Panggilan sistem manajemen direktori dan sistem file
  • Panggilan sistem lainnya

Cara yang lebih mudah untuk menganalisis informasi yang dibuang ke layar Anda adalah dengan mencatat output ke file menggunakan strace berguna -o bendera. Tambahkan nama file yang sesuai setelah -o tandai dan jalankan perintah lagi:

[root@sandbox tmp]# strace -o trace.log ls testdir/
file1  file2
[root@sandbox tmp]#

Kali ini, tidak ada keluaran yang dibuang ke layar—ls perintah bekerja seperti yang diharapkan dengan menunjukkan nama file dan mencatat semua output ke file trace.log . File memiliki hampir 100 baris konten hanya untuk ls simple sederhana perintah:

[root@sandbox tmp]# ls -l trace.log 
-rw-r--r--. 1 root root 7809 12 Okt 13:52 trace.log
[root@sandbox tmp]#
[root@sandbox tmp]# wc -l trace.log
114 trace.log
[root@sandbox tmp]#

Lihatlah baris pertama dalam contoh trace.log:

execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0 
  • Kata pertama dari baris, eksekusi , adalah nama panggilan sistem yang sedang dieksekusi.
  • Teks di dalam tanda kurung adalah argumen yang diberikan ke panggilan sistem.
  • Angka setelah = tanda (yaitu 0 dalam hal ini) adalah nilai yang dikembalikan oleh execve panggilan sistem.

Outputnya sepertinya tidak terlalu mengintimidasi sekarang, bukan? Dan Anda dapat menerapkan logika yang sama untuk memahami baris lain.

Sekarang, persempit fokus Anda ke satu perintah yang Anda panggil, yaitu ls testdir . Anda tahu nama direktori yang digunakan oleh perintah ls , jadi mengapa tidak grep untuk testdir dalam trace.log . Anda file dan lihat apa yang Anda dapatkan? Lihat setiap baris hasil secara detail:

[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]#

Memikirkan kembali analisis eksekutif di atas, dapatkah Anda memberi tahu apa fungsi panggilan sistem ini?

execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0 

Anda tidak perlu mengingat semua panggilan sistem atau apa yang mereka lakukan, karena Anda dapat merujuk ke dokumentasi saat Anda membutuhkannya. Halaman manual untuk menyelamatkan! Pastikan paket berikut diinstal sebelum menjalankan man perintah:

[root@sandbox tmp]# rpm -qa | grep -i halaman manual
halaman manual-3.53-5.el7.noarch
[root@sandbox tmp]#

Ingatlah bahwa Anda perlu menambahkan 2 antara pria perintah dan nama panggilan sistem. Jika Anda membaca pria halaman manual menggunakan man man , Anda dapat melihat bahwa bagian 2 dicadangkan untuk panggilan sistem. Demikian pula, jika Anda memerlukan informasi tentang fungsi perpustakaan, Anda perlu menambahkan 3 antara pria dan nama fungsi perpustakaan.

Berikut ini adalah nomor bagian manual dan jenis halaman yang dikandungnya:

1. Program yang dapat dieksekusi atau perintah shell
2. Panggilan sistem (fungsi yang disediakan oleh kernel)
3. Panggilan perpustakaan (fungsi dalam perpustakaan program)
4. File khusus (biasanya ditemukan di /dev)

Jalankan pria berikut ini perintah dengan nama panggilan sistem untuk melihat dokumentasi panggilan sistem tersebut:

man 2 execve 

Sesuai dengan eksekutif halaman manual, ini mengeksekusi program yang diteruskan dalam argumen (dalam hal ini, yaitu ls ). Ada argumen tambahan yang dapat diberikan kepada ls , seperti testdir dalam contoh ini. Oleh karena itu, panggilan sistem ini hanya menjalankan ls dengan testdir sebagai argumen:

'execve - execute program'

'DESCRIPTION
       execve()  mengeksekusi  program  yang ditunjukkan oleh nama file'

Panggilan sistem berikutnya, bernama stat , menggunakan testdir argumen:

stat("testdir/", {st_mode=S_IFDIR|0755, st_size=32, ...}) = 0 

Gunakan stat man 2 untuk mengakses dokumentasi. status adalah panggilan sistem yang mendapatkan status file—ingat bahwa semua yang ada di Linux adalah file, termasuk direktori.

Selanjutnya, buka panggilan sistem membuka testdir. Perhatikan 3 yang dikembalikan. Ini adalah deskripsi file, yang akan digunakan oleh panggilan sistem selanjutnya:

openat(AT_FDCWD, "testdir/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3 

Sejauh ini baik. Sekarang, buka trace.log file dan pergi ke baris berikut openat panggilan sistem. Anda akan melihat getdents panggilan sistem dipanggil, yang melakukan sebagian besar dari apa yang diperlukan untuk menjalankan ls testdir memerintah. Sekarang, grep getdents dari trace.log berkas:

[root@sandbox tmp]# grep getdents trace.log 
getdents(3, /* 4 entries */, 32768)     =112
getdents(3, /* 0 entries */, 32768 )     =0
[root@sandbox tmp]#

getdents halaman manual menggambarkannya sebagai mendapatkan entri direktori , yang ingin Anda lakukan. Perhatikan bahwa argumen untuk getdents adalah 3 , yang merupakan deskriptor file dari openat panggilan sistem di atas.

Sekarang setelah Anda memiliki daftar direktori, Anda memerlukan cara untuk menampilkannya di terminal Anda. Jadi, terima untuk panggilan sistem lain, tulis , yang digunakan untuk menulis ke terminal, dalam log:

[root@sandbox tmp]# grep write trace.log
write(1, "file1  file2\n", 13)          =13
[root@sandbox tmp]#

Dalam argumen ini, Anda dapat melihat nama file yang akan ditampilkan:file1 dan file2 . Mengenai argumen pertama (1 ), ingat di Linux bahwa, ketika proses apa pun dijalankan, tiga deskriptor file dibuka untuknya secara default. Berikut ini adalah deskriptor file default:

  • 0 - Masukan standar
  • 1 - Standar
  • 2 - Kesalahan standar

Jadi, tulis panggilan sistem menampilkan file1 dan file2 pada tampilan standar, yang merupakan terminal, diidentifikasi dengan 1 .

Sekarang Anda tahu panggilan sistem mana yang paling berhasil untuk ls testdir/ memerintah. Namun bagaimana dengan 100+ panggilan sistem lainnya di trace.log mengajukan? Sistem operasi harus melakukan banyak pembersihan untuk menjalankan suatu proses, jadi banyak hal yang Anda lihat di file log adalah inisialisasi dan pembersihan proses. Baca seluruh trace.log file dan coba pahami apa yang terjadi untuk membuat ls perintah kerja.

Sekarang setelah Anda mengetahui cara menganalisis panggilan sistem untuk perintah yang diberikan, Anda dapat menggunakan pengetahuan ini untuk perintah lain guna memahami panggilan sistem apa yang sedang dijalankan. strate menyediakan banyak tanda baris perintah yang berguna untuk memudahkan Anda, dan beberapa di antaranya dijelaskan di bawah ini.

Secara default, strace tidak mencakup semua informasi panggilan sistem. Namun, ia memiliki -v verbose . yang praktis opsi yang dapat memberikan informasi tambahan pada setiap panggilan sistem:

strace -v ls testdir 

Ini adalah praktik yang baik untuk selalu menggunakan -f opsi saat menjalankan strace memerintah. Ini memungkinkan strace untuk melacak setiap proses anak yang dibuat oleh proses yang sedang dilacak:

strace -f ls testdir 

Katakanlah Anda hanya ingin nama panggilan sistem, berapa kali panggilan itu berjalan, dan persentase waktu yang dihabiskan di setiap panggilan sistem. Anda dapat menggunakan -c tandai untuk mendapatkan statistik tersebut:

strace -c ls testdir/ 

Misalkan Anda ingin berkonsentrasi pada panggilan sistem tertentu, seperti berfokus pada terbuka panggilan sistem dan mengabaikan sisanya. Anda dapat menggunakan -e tandai diikuti dengan 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
buka("/lib64/libcap.so.2", O_RDONLY|O_CLOEXEC) =3
buka("/lib64/libacl.so.1 ", O_RDONLY|O_CLOEXEC) =3
buka("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) =3
buka("/lib64/libpcre.so.1", O_RDONLY| O_CLOEXEC) =3
buka("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) =3
buka("/lib64/libattr.so.1", O_RDONLY|O_CLOEXEC) =3
buka("/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) =3
buka("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) =3
file1  file2
+++ keluar dengan 0 +++
[root@sandbox tmp]#

Bagaimana jika Anda ingin berkonsentrasi pada lebih dari satu panggilan sistem? Jangan khawatir, Anda dapat menggunakan -e yang sama bendera baris perintah dengan koma di antara dua panggilan sistem. Misalnya, untuk melihat tulis dan getdents panggilan sistem:

[root@sandbox tmp]# strace -e write,getdents ls testdir
getdents(3, /* 4 entries */, 32768)     =112
getdents(3, /* 0 entries * /, 32768)     =0
tulis(1, "file1  file2\n", 13file1  file2
)          =13
+++ keluar dengan 0 +++
[root@ kotak pasir tmp]#

Contoh-contoh sejauh ini telah melacak perintah yang dijalankan secara eksplisit. Tapi bagaimana dengan perintah yang sudah dijalankan dan sedang dieksekusi? Bagaimana, misalnya, jika Anda ingin melacak daemon yang hanya merupakan proses yang berjalan lama? Untuk ini, strace menyediakan -p . khusus tandai yang dapat Anda berikan ID prosesnya.

Alih-alih menjalankan strace pada daemon, ambil contoh kucing perintah, yang biasanya menampilkan isi file jika Anda memberikan nama file sebagai argumen. Jika tidak ada argumen yang diberikan, kucing perintah hanya menunggu di terminal bagi pengguna untuk memasukkan teks. Setelah teks dimasukkan, ia mengulangi teks yang diberikan sampai pengguna menekan Ctrl+C untuk keluar.

Jalankan kucing perintah dari satu terminal; itu akan menampilkan prompt dan cukup tunggu di sana (ingat kucing masih berjalan dan belum keluar):

[root@sandbox tmp]# cat 

Dari terminal lain, temukan pengidentifikasi proses (PID) menggunakan ps perintah:

[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, jalankan strace pada proses yang sedang berjalan dengan -p bendera dan PID (yang Anda temukan di atas menggunakan ps ). Setelah menjalankan strace , output menyatakan proses yang dilampirkan bersama dengan nomor PID. Sekarang, strace sedang melacak panggilan sistem yang dilakukan oleh kucing memerintah. Panggilan sistem pertama yang Anda lihat adalah baca , yang menunggu input dari 0, atau input standar, yang merupakan terminal tempat cat perintah dijalankan:

[root@sandbox ~]# strace -p 22443
strace:Proses 22443 terpasang
read(0,

Sekarang, kembali ke terminal tempat Anda meninggalkan kucing perintah berjalan dan masukkan beberapa teks. Saya memasukkan x0x0 untuk tujuan demo. Perhatikan bagaimana kucing hanya mengulangi apa yang saya masukkan; karenanya, x0x0 muncul dua kali. Saya memasukkan yang pertama, dan yang kedua adalah keluaran yang diulang oleh kucing perintah:

[root@sandbox tmp]# cat
x0x0
x0x0

Kembali ke terminal tempat strace melekat pada kucing proses. Sekarang Anda melihat dua panggilan sistem tambahan:baca sebelumnya panggilan sistem, yang sekarang terbaca x0x0 di terminal, dan satu lagi untuk tulis , yang menulis x0x0 kembali ke terminal, dan lagi baca . yang baru , yang menunggu untuk dibaca dari terminal. Perhatikan bahwa masukan Standar (0 ) dan Keluar standar (1 ) keduanya berada di terminal yang sama:

[root@sandbox ~]# strace -p 22443
strace:Proses 22443 terpasang
read(0, "x0x0\n", 65536)                =5
write(1, " x0x0\n", 5)                   =5
read(0,

Bayangkan betapa membantunya ini saat menjalankan strace terhadap daemon untuk melihat semua yang dilakukannya di latar belakang. Bunuh kucing perintah dengan menekan Ctrl+C; ini juga membunuh jejak your Anda sesi karena proses tidak lagi berjalan.

Jika Anda ingin melihat stempel waktu terhadap semua panggilan sistem Anda, cukup gunakan -t opsi dengan strace :

[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_ANONYMOUS, MAP_ANONYMO -1, 0) =0x7f2530bc8000
14:24:47 access("/etc/ld.so.preload", R_OK) =-1 ENOENT (Tidak ada file atau direktori seperti itu)
14:24:47 buka("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) =3

Bagaimana jika Anda ingin mengetahui waktu yang dihabiskan di antara panggilan sistem? strate memiliki -r . yang praktis perintah yang menunjukkan waktu yang dihabiskan untuk mengeksekusi 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) =01150.0005000fb />b1150.000
access("/etc/ld.so.preload", R_OK) =-1 ENOENT (Tidak ada file atau direktori seperti itu)
0,000119 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) =3

Kesimpulan

strate utilitas ini sangat berguna untuk memahami panggilan sistem di Linux. Untuk mempelajari tentang flag baris perintah lainnya, silakan merujuk ke halaman manual dan dokumentasi online.


Linux
  1. Tingkatkan kinerja sistem Linux dengan noatime

  2. Perintah Shutdown Linux (dengan Contoh)

  3. Menjadwalkan tugas sistem dengan Cron di Linux

  1. Pantau sistem Linux Anda di terminal Anda dengan procps-ng

  2. Menyeimbangkan keamanan Linux dengan kegunaan

  3. Howto:Pemrograman C dengan Direktori di Linux

  1. Coba Linux di sistem operasi apa pun dengan VirtualBox

  2. Pengujian pena dengan alat keamanan Linux

  3. Mengapa fungsi kucing saya dengan panggilan sistem lebih lambat dibandingkan dengan kucing Linux?