straceを使用したLinuxのシステム呼び出しの理解

この記事の翻訳は、特に基本コース上級コースの管理者Linuxの学生向けに作成されました。






syscallは、ユーザープログラムがLinuxカーネルと対話するメカニズムであり、straceはそれらを追跡するための強力なツールです。オペレーティングシステムがどのように機能するかをよりよく理解するには、それらがどのように機能するかを理解することが役立ちます。



オペレーティングシステムは、次の2つの動作モードに分けることができます。



  • カーネルモードは、オペレーティングシステムカーネルによって使用される特権モードです。
  • ユーザーモードは、ほとんどのユーザーアプリケーションが実行されるモードです。




ユーザーは通常、日常業務にコマンドラインユーティリティとグラフィカルインターフェイス(GUI)を使用します。同時に、システム呼び出しはバックグラウンドで目に見えない形で機能し、カーネルにアクセスして作業を行います。



システム呼び出しは、引数と戻り値が渡されるという意味で関数呼び出しと非常によく似ています。唯一の違いは、システム呼び出しはカーネルレベルで機能しますが、関数は機能しないことです。ユーザーモードからカーネルモードへの切り替えは、特別な割り込みメカニズムを使用して行われます



これらの詳細のほとんどは、システムライブラリ(Linuxシステムではglibc)でユーザーに表示されません。システム呼び出しは本質的に普遍的ですが、それにもかかわらず、それらの実行のメカニズムは主にハードウェアに依存しています。



この記事では、を使用してシステム呼び出しを解析するいくつかの実用的な例について説明しますstrace。例ではRedHat Enterprise Linuxを使用していますが、すべてのコマンドは他のLinuxディストリビューションで機能するはずです。



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




まず、システムに必要なツールがインストールされていることを確認します。strace以下のコマンドでインストールされているか確認できます。バージョンを表示straceするには、-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 ~]#




straceインストールされていない 場合は、以下を実行してインストールします。



yum install strace




たとえば/tmp、次のコマンドを使用して、と2つのファイルにテストディレクトリを作成します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]#




/tmp誰もがアクセスできるため、ディレクトリのみを使用しますが、他の任意のディレクトリを使用できます。)



コマンドを使用して、ファイルがlsディレクトリにtestdir作成さていること確認します。



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




lsシステム呼び出しが内部で実行されていることに気付かずに 、おそらく毎日コマンドを使用します。ここで抽象化が役立ちます。このコマンドの仕組みは次のとおりです。



   ->    (glibc) ->  




このコマンドlsは、Linuxシステムライブラリ(glibc)から関数を呼び出します。これらのライブラリは、システム呼び出しを呼び出し、ほとんどの作業を実行します。



glibcライブラリから呼び出された関数を知りたい場合は、次のコマンドを使用してから次ltraceのコマンドを実行しls testdir/ます。



ltrace ls testdir/




ltraceインストールされていない 場合は、以下をインストールします。



yum install ltrace




画面には多くの情報が表示されますが、心配しないでください。これについては後で説明します。出力からの重要なライブラリ関数のいくつかを次に示します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 })    




この出力を調べることで、おそらく何が起こっているのかを理解できます。指定されたディレクトリはtestdir、ライブラリ関数を使用して開かopendirれ、その後readdir、ディレクトリの内容を読み取る関数呼び出されます。最後に、closedir以前に開いたディレクトリを閉じる関数が呼び出されます。今のところ、strlenなどの他の関数は無視してくださいmemcpy



ご覧のとおり、呼び出されているライブラリ関数は簡単にわかりますが、この記事では、システムライブラリ関数によって呼び出されるシステム呼び出しに焦点を当てます。



システム呼び出しを表示するにstraceは、ls testdir以下に示すコマンドで使用ます。また、一貫性のない情報がたくさん表示されます。



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


実行の結果strace、コマンドの実行中に実行されたシステム呼び出しのリストを受け取りますlsすべてのシステム呼び出しは、次のカテゴリに分類できます。



  • プロセス管理
  • ファイル管理
  • ディレクトリとファイルシステムの管理
  • その他




受信した情報を分析する便利な方法があります-オプションを使用して出力をファイルに書き込みます-o



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




今回は、画面にデータが表示されません。コマンドはls期待どおりに機能straceし、ファイルのリストを表示して、すべての出力ファイルに書き込みますtrace.log単純なコマンドの場合、lsファイルにはほぼ100行が含まれてます。



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




ファイルの最初の行を見てくださいtrace.log



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




  • 行の先頭には、実行されているシステム呼び出しの名前—execveがあります。
  • 括弧内のテキストは、システム呼び出しに渡される引数です。
  • =記号の後の数字(この場合は0)は、システム呼び出しによって返される値です。




さて、結果はそれほど怖くないようですよね?また、他の行にも同じロジックを適用できます。



呼び出した唯一のコマンドに注意してください- ls testdirコマンドls使用されるディレクトリの名前を知っているので、ファイルでgrepfortestdir使用て、trace.log何が見つかるかを確認してみませんか?結果をよく見てください。



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




上記の分析に戻って、execve次のシステム呼び出しが何をしているのかわかりますか?



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




すべてのシステム呼び出しとその機能を覚えておく必要はありません。すべてがドキュメントに記載されています。マンページは急いで助けてくれます!manコマンドを実行する前に、パッケージがインストールされていることを確認してくださいman-pages



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




コマンドmanとsyscall名の間に「2」を追加する必要があることに注意してくださいmanについて読むと、セクション2がシステム呼び出し用に予約されていることがわかります。同様に、ライブラリ関数に関する情報が必要な場合は、とライブラリ関数の名前の間に3を追加する必要があります。 以下はセクション番号です:manman manman



man



1.       .
2.   (,  ).
3.   (  ).
4.   (    /dev).




システム呼び出しのドキュメントを表示するには、そのシステム呼び出しの名前でmanを実行します。



man 2 execve




ドキュメントによると、システム呼び出しexecveは、パラメーターで渡されるプログラムを実行します(この場合はls)。lsの追加パラメーターも渡されます。この例では、ですtestdirしたがって、このシステム呼び出しは、パラメータとしてで実行lstestdirれます。



'execve - execute program'

'DESCRIPTION
       execve()  executes  the  program  pointed to by filename'




次のシステム呼び出しにstatはパラメータが渡されますtestdir



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




ドキュメントを表示するには、を使用しますman 2 statstatシステム呼び出しは、指定されたファイルに関する情報を返します。Linuxのすべては、ディレクトリを含むファイルであることを忘れないでください。



次に、システム呼び出しopenatが開きますtestdir戻り値は3であることに注意してください。これは、後続のシステム呼び出しで使用されるファイル記述子です。



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




ファイルを開きます
trace.log
システム呼び出しに続く行に注意してくださいopenatgetdentsコマンドの実行に必要なほとんどの作業を実行するシステム呼び出しが表示されls testdirます。それではgrep getdents、ファイルに対して実行してみましょうtrace.log



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




ドキュメント(man getdents)には、getdents実際に必要なディレクトリエントリを読み取ると記載されています。getdent3の引数は、システム呼び出しから以前に取得したファイル記述子であることに注意してくださいopenat



ディレクトリの内容を受信したので、端末に情報を表示する方法が必要です。したがって、端末に出力するために使用されるgrep別のシステム呼び出しwriteに対して行います。



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




引数には、出力されるファイルの名前が表示されます:file1およびfile2最初の引数(1)については、Linuxでは、すべてのプロセスに対してデフォルトで3つのファイル記述子が開かれることに注意してください。



  • 0-標準入力ストリーム
  • 1-標準出力ストリーム
  • 2-標準エラーストリーム




このように、システムコールがwriteかかるfile1file2、端末で標準出力には、数1を表し、



今、あなたはシステムコールがチームのためにほとんどの作業を行って何を知っていますls testdir/。しかし、ファイル内の他の100以上のシステム呼び出しはtrace.logどうですか?



オペレーティングシステムは、プロセスを開始するために多くのサポートを行います。そのため、ファイルに表示される内容の多くはtrace.log、プロセスの初期化とクリーンアップです。 trace.logファイルをよく見て、コマンドの実行時に何が起こるかを理解してくださいls



これで、任意のプログラムのシステム呼び出しを分析できます。 straceユーティリティには、多くの便利なコマンドラインオプションも用意されています。その一部を以下に説明します。



デフォルトではstrace、システム呼び出しに関するすべての情報が表示されるわけではありません。ただし、-v verbose各システム呼び出しに関する追加情報を表示するオプションがあります



strace -v ls testdir




パラメータを使用-fして、実行中のプロセスによって作成された子プロセスを追跡することをお勧めします。



strace -f ls testdir




しかし、システム呼び出しの名前、それらが実行された回数、および実行に費やされた時間の割合だけが必要な場合はどうでしょうか。このオプション-c使用して、次の統計を取得できます



strace -c ls testdir/




たとえば、特定のシステムコールを追跡し、open他のコールを無視する場合-eは、システムコールの名前とともにオプション使用できます



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




複数のシステム呼び出しでフィルタリングする必要がある場合はどうなりますか?心配しないでください。同じオプション-e使用して、必要なシステム呼び出しをコンマで区切ることができます。たとえば、forwritegetdent



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




これまでのところ、明示的なコマンドの実行のみを追跡しました。しかし、以前に実行されたコマンドはどうですか?悪魔を追跡したい場合はどうなりますか?このために、プロセスIDを渡すことができるstrace特別なオプション-pがあります。



デーモンは起動しませんcatが、渡されたファイルの内容を引数として表示するコマンド使用します。ただし、引数を指定しない場合、コマンドcatはユーザーからの入力を待つだけです。テキストを入力すると、入力したテキストが画面に表示されます。ユーザーがクリックCtrl+Cして終了するまで、以下同様です。1つの端末で



コマンドcat実行します



[root@sandbox tmp]# cat




別の端末で、次のコマンドを使用してプロセスID(PID)を見つけます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 ~]#




次にstrace、で-p見つけたオプションとPIDから始めますps開始後、strace接続したプロセスに関する情報とPIDが表示されます。今、straceコマンドによって作られたシステムコールを監視しますcat最初に表示されるsyscallが読み取られ、スレッド0からの入力、つまり、コマンドが実行されている端末である標準入力からの入力を待機しますcat



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




コマンドを実行したままにしたターミナルに戻り、catテキストを入力します。デモンストレーションのために、私は入りましたx0x0cat入力しx0x0内容を繰り返すだけで、画面が2回表示されることに注意してください



[root@sandbox tmp]# cat
x0x0
x0x0




straceプロセスに接続 したターミナルに戻りますcatこれで、2つの新しいシステム呼び出しが表示されます。前の呼び出しreadは読み取り済みx0x0で、もう1つは書き込み用で、端末にwrite書きx0x0戻します。新しい呼び出しreadは、端末からの読み取りを待機しています。標準入力(0)と標準出力(1)が同じ端子上にあることに注意してください。



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




straceデーモン の起動の利点を想像してみてください。バックグラウンドで実行されるすべてを確認できます。コマンドを完了する
cat
クリックすることで
Ctrl+C
..。これにより、セッションも終了します
strace
監視対象のプロセスが終了したため。



システム呼び出しのタイムスタンプを表示するには、次のオプションを使用します-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




システム呼び出しの間に費やされた時間を知りたい場合はどうなりますか?-r各システム呼び出しを完了するのにかかる時間を示す便利なオプションがあります。かなり役に立ちましたね。



[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




結論



このユーティリティはstrace、Linuxでシステム呼び出しを学習するのに非常に便利です。その他のコマンドラインオプションについては、manおよびオンラインドキュメントを参照してください。






All Articles