strace はどのように使用すればよいでしょうか?
質問
Linux でデバッグにすべてが失敗した場合の最後の選択肢は、ある同僚が私にかつて言ったことです。 跡.
この奇妙なツールの背後にある科学を学ぼうとしましたが、私はシステム管理の専門家ではないため、あまり結果は得られませんでした。
それで、
- それは正確には何ですか?そしてそれは何をするのですか?
- どのような場合にどのように使用する必要がありますか?
- 出力はどのように理解され、処理されるべきでしょうか?
簡単に言うと、 簡単な言葉で言うと, 、これはどのように機能するのでしょうか?
解決
Straceの概要
straceは、軽量のデバッガーと見なすことができます。プログラマー/ユーザーは、プログラムがOSとどのように対話しているかをすばやく見つけることができます。システムコールとシグナルを監視することでこれを行います。
使用
あなたがソースコードを持っていないときや、本当にそれを経験することに煩わされたくないときに適しています。
また、GDBを開くつもりはないが、外部の相互作用を理解したいだけの場合は、独自のコードに役立ちます。
良い紹介
先日straceを使用するためにこのイントロに遭遇しました: strace hello world
他のヒント
簡単に言えば、straceは、プログラムによって発行されたすべてのシステムコールとそのリターンコードをトレースします。ファイル/ソケット操作など、もっとわかりにくい操作を考えてください。
システムコールは標準Cライブラリコールをより正確に表すため、Cの実用的な知識がある場合に最も役立ちます。
プログラムが/ usr / local / bin / coughだとしましょう。単に使用します:
strace /usr/local/bin/cough <any required argument for cough here>
または
strace -o <out_file> /usr/local/bin/cough <any required argument for cough here>
「out_file」に書き込む。
すべてのstrace出力はstderrに送られます(注意してください、その膨大な量はしばしばファイルへのリダイレクトを要求します)。最も単純なケースでは、プログラムはエラーで異常終了し、strace出力でOSとの最後の対話がどこで行われているのかを確認できます。
次の情報を入手できます。
man strace
straceは、適用されたプロセスによって行われたすべてのシステムコールをリストします。システムコールが何を意味するのかわからない場合、そこから多くのマイレージを取得することはできません。
それにもかかわらず、問題がファイルまたはパスまたは環境値に関連する場合、問題のあるプログラムでstraceを実行し、出力をファイルにリダイレクトしてから、そのファイルをパス/ファイル/環境文字列にgrepすることで、プログラムが何であるかを確認できる場合があります実際に、あなたが期待していたこととは異なり、やろうとしている。
Straceは、これらのプログラムをデバッガーで実行する余裕がない本番システムを調査するためのツールとして際立っています。特に、次の2つの状況でstraceを使用しました。
- プログラムfooはデッドロック状態にあるようで、応答しなくなりました。これはgdbのターゲットになる可能性があります。ただし、ソースコードを常に持っているわけではなく、デバッガーで実行するのが簡単ではないスクリプト言語を扱っていることもありました。この場合、すでに実行中のプログラムでstraceを実行すると、システムコールのリストが取得されます。これは、クライアント/サーバーアプリケーションまたはデータベースと対話するアプリケーションを調査している場合に特に便利です
- プログラムが遅い理由の調査。特に、新しい分散ファイルシステムに移行したばかりで、システムの新しいスループットは非常に低速でした。 '-T'オプションを使用してstraceを指定すると、各システムコールに費やされた時間を確認できます。これは、ファイルシステムが原因で速度が低下する原因を特定するのに役立ちました。
straceを使用した分析の例については、この質問に対する私の答えをご覧ください。 。
許可の問題をデバッグするために、常にstraceを使用しています。テクニックは次のようになります。
$ strace -e trace=open,stat,read,write gnome-calculator
gnome-calculator
は、実行するコマンドです。
strace -tfp PIDはPIDプロセスのシステムコールを監視するため、プロセス/プログラムのステータスをデバッグ/監視できます。
Strace は、デバッグ ツールまたはプリミティブ プロファイラーとして使用できます。
デバッガとして、特定のシステム コールがどのように呼び出され、実行され、何を返したかを確認できます。これは、プログラムが失敗したことだけでなく、なぜプログラムが失敗したかを確認できるため、非常に重要です。通常、これは、プログラムの考えられるすべての結果を捉えていない、お粗末なコーディングの結果にすぎません。ファイルへのパスがハードコーディングされているだけの場合もあります。痕跡がなければ、何がどこでどのように間違っていたのかを推測することになります。strace を使用すると、システムコールの内訳がわかります。通常は戻り値を見るだけで多くのことがわかります。
プロファイリングは別の用途です。これを使用して、各 Syscall の実行時間を個別に、または集計として計ることができます。これは問題を解決するには十分ではないかもしれませんが、少なくとも潜在的な容疑者のリストを大幅に絞り込むことができます。1 つのファイルに fopen/close ペアが多数ある場合は、ループの外でファイルを開いたり閉じたりするのではなく、ループの実行ごとに不必要にファイルを開いたり閉じたりしている可能性があります。
Ltrace は strace に近いもので、これも非常に便利です。ボトルネックがどこにあるのかを見分ける方法を学ばなければなりません。合計実行時間が 8 秒で、システム コールに 0.05 秒しか費やしていない場合、プログラムのストレーシングはあまり役に立ちません。問題はコード内にあり、通常はロジックの問題であるか、プログラムが実際に必要とするものです。走るのにそんなに時間がかかるとは。
strace/ltrace の最大の問題は、出力の読み取りです。呼び出しがどのように行われるか、または少なくともシステムコール/関数の名前がわからない場合、意味を解読するのは困難になります。関数が何を返すかを知ることは、特にさまざまなエラー コードの場合に非常に有益です。解読するのは骨が折れますが、時には本当に知識の真珠が戻ってきます。一度、inode が不足しているが、空き領域が不足しているという状況を見たことがあります。そのため、通常のユーティリティはすべて警告を表示せず、新しいファイルを作成できませんでした。strace の出力からエラー コードを読み取ると、正しい方向が示されました。
Straceは、アプリケーションがオペレーティングシステムと対話する方法を示すツールです。
これは、アプリケーションが使用するOSシステム呼び出しと、それらが呼び出すパラメーターを指定することでこれを行います。
たとえば、プログラムがどのファイルを開こうとしているかを確認し、呼び出しが成功したかどうかを確認します。
このツールを使用して、あらゆる種類の問題をデバッグできます。たとえば、インストール済みのライブラリが見つからないとアプリケーションが言った場合、straceはアプリケーションがそのファイルを探している場所を教えてくれます。
それは氷山の一角にすぎません。
straceは、プログラムがさまざまなシステムコール(カーネルへの要求)を行う方法を学習するための優れたツールであり、失敗に関連するエラー値とともに失敗したものも報告します。すべての失敗がバグではありません。たとえば、ファイルを検索しようとしているコードはENOENT(No such file or directory)エラーを受け取ることがありますが、コードのロジックでは許容できるシナリオです。
straceを使用する1つの良い使用例は、一時ファイルの作成中に競合状態をデバッグすることです。たとえば、プロセスID(PID)を事前に決定された文字列に追加してファイルを作成するプログラムは、マルチスレッドシナリオで問題に直面する可能性があります。 [PID + TID(プロセスID +スレッドID)またはmkstempなどのより優れたシステムコールがこれを修正します。]
また、クラッシュのデバッグにも適しています。 straceとデバッグクラッシュに関するこの(私の)記事をご覧ください。便利です。
オペレーティングシステムとの対話方法をチェックする strace
を読む回答のいくつかが気に入りました。
これはまさに私たちが見ることができるものです。システムが呼び出します。 strace
と ltrace
を比較すると、違いはより明白です。
<*>gt;ltrace -c cd
Desktop Documents Downloads examples.desktop Music Pictures Public Templates Videos
% time seconds usecs/call calls function
------ ----------- ----------- --------- --------------------
15.52 0.004946 329 15 memcpy
13.34 0.004249 94 45 __ctype_get_mb_cur_max
12.87 0.004099 2049 2 fclose
12.12 0.003861 83 46 strlen
10.96 0.003491 109 32 __errno_location
10.37 0.003303 117 28 readdir
8.41 0.002679 133 20 strcoll
5.62 0.001791 111 16 __overflow
3.24 0.001032 114 9 fwrite_unlocked
1.26 0.000400 100 4 __freading
1.17 0.000372 41 9 getenv
0.70 0.000222 111 2 fflush
0.67 0.000214 107 2 __fpending
0.64 0.000203 101 2 fileno
0.62 0.000196 196 1 closedir
0.43 0.000138 138 1 setlocale
0.36 0.000114 114 1 _setjmp
0.31 0.000098 98 1 realloc
0.25 0.000080 80 1 bindtextdomain
0.21 0.000068 68 1 opendir
0.19 0.000062 62 1 strrchr
0.18 0.000056 56 1 isatty
0.16 0.000051 51 1 ioctl
0.15 0.000047 47 1 getopt_long
0.14 0.000045 45 1 textdomain
0.13 0.000042 42 1 __cxa_atexit
------ ----------- ----------- --------- --------------------
100.00 0.031859 244 total
gt;strace -c cd
Desktop Documents Downloads examples.desktop Music Pictures Public Templates Videos
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
0.00 0.000000 0 7 read
0.00 0.000000 0 1 write
0.00 0.000000 0 11 close
0.00 0.000000 0 10 fstat
0.00 0.000000 0 17 mmap
0.00 0.000000 0 12 mprotect
0.00 0.000000 0 1 munmap
0.00 0.000000 0 3 brk
0.00 0.000000 0 2 rt_sigaction
0.00 0.000000 0 1 rt_sigprocmask
0.00 0.000000 0 2 ioctl
0.00 0.000000 0 8 8 access
0.00 0.000000 0 1 execve
0.00 0.000000 0 2 getdents
0.00 0.000000 0 2 2 statfs
0.00 0.000000 0 1 arch_prctl
0.00 0.000000 0 1 set_tid_address
0.00 0.000000 0 9 openat
0.00 0.000000 0 1 set_robust_list
0.00 0.000000 0 1 prlimit64
------ ----------- ----------- --------- --------- ----------------
100.00 0.000000 93 10 total
一方、機能をトレースする ltrace
があります。
マニュアルを何度かチェックしましたが、 strace
という名前の由来は見つかりませんでしたが、システムコールトレースである可能性が高いのは明らかです。
strace
について3つの大きなメモがあります。
注1:これらの関数 strace
と ltrace
は両方とも、システムコール ptrace
。したがって、 ptrace
システムコールは、 strace
の効果的な方法です。
ptrace()システムコールは、1つのプロセス( &quot; tracer&quot;)は、別のプロセスの実行を監視および制御できます (&quot; tracee&quot;)、トレースのメモリを調べて変更し、 レジスタ。主にブレークポイントのデバッグを実装するために使用されます およびシステムコールのトレース。
注2: strace
は非常に冗長になる可能性があるため、 strace
で使用できるさまざまなパラメーターがあります。物事の要約のような -c
を試すのが好きです。 -c
に基づいて、 -e trace = open
のような1つのシステムコールを選択できます。この場合、そのコールのみが表示されます。これは、トレースしているコマンドの実行中にどのファイルが開かれるかを調べている場合に興味深い場合があります。
そしてもちろん、同じ目的で grep
を使用できますが、このようにリダイレクトする必要があることに注意してください 2&gt;&amp; 1 | grepなど
を使用して、コマンドの発行時に構成ファイルが参照されることを理解します。
注3:この非常に重要な注を見つけました。特定のアーキテクチャに限定されません。 strace
は、さまざまなアーキテクチャのバイナリをトレースできるため、気が遠くなります。
最小限の実行可能な例
概念が明確でない場合は、それを説明する、見たことのない単純な例があります。
この場合、その例は、Linux x86_64アセンブリ自立(libcなし)hello worldです:
hello.S
.text
.global _start
_start:
/* write */
mov $1, %rax /* syscall number */
mov $1, %rdi /* stdout */
mov $msg, %rsi /* buffer */
mov $len, %rdx /* buffer len */
syscall
/* exit */
mov $60, %rax /* exit status */
mov as -o hello.o hello.S
ld -o hello.out hello.o
./hello.out
, %rdi /* syscall number */
syscall
msg:
.ascii "hello\n"
len = . - msg
アセンブルして実行:
hello
期待される出力:
env -i ASDF=qwer strace -o strace.log -s999 -v ./hello.out arg0 arg1
cat strace.log
今、その例でstraceを使用しましょう。
execve("./hello.out", ["./hello.out", "arg0", "arg1"], ["ASDF=qwer"]) = 0
write(1, "hello\n", 6) = 6
exit(0) = ?
+++ exited with 0 +++
使用:
-
環境変数を制御する
-
env -i ASDF = qwer
: https://unix.stackexchange.com/questions/48994/how-to-run-a-program-in-a-clean-environment-in-bash -
-s999 -v
を使用して、ログに関する詳細情報を表示します
strace.log
に次が含まれるようになりました:
#define _XOPEN_SOURCE 700
#include <unistd.h>
int main(void) {
char *msg = "hello\n";
write(1, msg, 6);
return 0;
}
このような最小限の例では、出力のすべての文字が自明です:
-
execve
行:manで文書化されているCLI引数と環境を含む
strace
がhello.out
を実行した方法を示しますexecve -
write
行:作成した書き込みシステムコールを示します。6
は、文字列&quot; hello \ n&quot;
の長さです。= 6
はシステムコールの戻り値で、man 2 write
に記載されているように、書き込まれたバイト数です。 -
exit
行:行ったexitシステムコールを示します。プログラムが終了したため、戻り値はありません!
より複雑な例
もちろん、straceの適用は、プログラムのデバッグ/最適化を支援するために、複雑なプログラムが実際に実行しているシステムコールを確認することです。
特に、Linuxで遭遇する可能性のあるほとんどのシステムコールには、glibcラッパー POSIXからのそれらの多く。
内部では、glibcラッパーは次のようにインラインアセンブリを多かれ少なかれ使用しています。インラインアセンブリのsysenter経由でシステムコールを呼び出す方法
次に学習すべき例は、POSIX write
hello worldです:
main.c
gcc -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out
コンパイルして実行:
write(1, "hello\n", 6) = 6
exit_group(0) = ?
+++ exited with 0 +++
今回は、 main
の前にglibcによって一連のシステムコールが行われ、mainの環境を整えていることがわかります。
これは、独立したプログラムではなく、libc機能を可能にするより一般的なglibcプログラムを使用しているためです。
その後、すべての終わりに、 strace.log
には以下が含まれます。
したがって、 write
POSIX関数は、Linuxの write
システムコールを使用していると思います。
また、 return 0
は exit
ではなく exit_group
の呼び出しにつながることも確認しています。ハ、私はこれについて知りませんでした!これが strace
がとてもクールな理由です。 man exit_group
が説明します:
このシステムコールは、呼び出しスレッドだけでなく、呼び出しプロセスのスレッドグループ内のすべてのスレッドを終了することを除いて、exit(2)と同等です。
また、 dlopen
がどのシステムコールを使用するかを調査した別の例を次に示します。 https://unix.stackexchange.com/questions/226524/what-system-call-is-used-to-load-libraries-in- linux / 462710#462710
Ubuntu 16.04、GCC 6.4.0、Linuxカーネルでテスト済み