Linux ですべてのデバッグに失敗した場合の最後のオプションは、 straceを使用することだと同僚が言ったことがあります。
私はこの奇妙なツールの背後にある科学を学ぼうとしましたが、私はシステム管理の第一人者ではなく、実際には結果が得られませんでした.
そう、
- それは正確には何ですか、それは何をしますか?
- どのような場合に、どのように使用する必要がありますか?
- 出力をどのように理解し、処理する必要がありますか?
簡単に言えば、これはどのように機能するのでしょうか?
Linux ですべてのデバッグに失敗した場合の最後のオプションは、 straceを使用することだと同僚が言ったことがあります。
私はこの奇妙なツールの背後にある科学を学ぼうとしましたが、私はシステム管理の第一人者ではなく、実際には結果が得られませんでした.
そう、
簡単に言えば、これはどのように機能するのでしょうか?
Strace の概要
strace は、軽量のデバッガーと見なすことができます。これにより、プログラマー/ユーザーは、プログラムが OS とどのように対話しているかをすばやく知ることができます。これは、システム コールとシグナルを監視することによって行われます。
ソースコードを持っていない場合や、わざわざ実際に調べたくない場合に、Good を使用します。
また、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 を実行し、出力をファイルにリダイレクトしてから、そのファイルで path/file/env 文字列を grep すると、プログラムが実際に何をしようとしているのかを確認するのに役立つ場合があります。あなたが期待したものとは異なります。
Strace は、これらのプログラムをデバッガーで実行する余裕がない実稼働システムを調査するためのツールとして際立っています。特に、次の 2 つの状況で strace を使用しました。
strace を使用した分析の例については、この質問に対する私の回答を参照してください。
アクセス許可の問題をデバッグするために、常に strace を使用しています。テクニックは次のようになります。
$ strace -e trace=open,stat,read,write gnome-calculator
gnome-calculator
実行するコマンドはどこにありますか。
Strace can be used as a debugging tool, or as a primitive profiler.
As a debugger, you can see how given system calls were called, executed and what they return. This is very important, as it allows you to see not only that a program failed, but WHY a program failed. Usually it's just a result of lousy coding not catching all the possible outcomes of a program. Other times it's just hardcoded paths to files. Without strace you get to guess what went wrong where and how. With strace you get a breakdown of a syscall, usually just looking at a return value tells you a lot.
Profiling is another use. You can use it to time execution of each syscalls individually, or as an aggregate. While this might not be enough to fix your problems, it will at least greatly narrow down the list of potential suspects. If you see a lot of fopen/close pairs on a single file, you probably unnecessairly open and close files every execution of a loop, instead of opening and closing it outside of a loop.
Ltrace is strace's close cousin, also very useful. You must learn to differenciate where your bottleneck is. If a total execution is 8 seconds, and you spend only 0.05secs on system calls, then stracing the program is not going to do you much good, the problem is in your code, which is usually a logic problem, or the program actually needs to take that long to run.
The biggest problem with strace/ltrace is reading their output. If you don't know how the calls are made, or at least the names of syscalls/functions, it's going to be difficult to decipher the meaning. Knowing what the functions return can also be very beneficial, especially for different error codes. While it's a pain to decipher, they sometimes really return a pearl of knowledge; once I saw a situation where I ran out of inodes, but not out of free space, thus all the usual utilities didn't give me any warning, I just couldn't make a new file. Reading the error code from strace's output pointed me in the right direction.
strace -tfp PID は PID プロセスのシステム コールを監視するため、プロセス/プログラムのステータスをデバッグ/監視できます。
最小限の実行可能な例
概念が明確でない場合は、それを説明する、まだ見たことのない簡単な例があります。
この場合、その例は Linux x86_64 アセンブリ フリースタンディング (libc なし) の hello world です。
こんにちは。
.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 $0, %rdi /* syscall number */
syscall
msg:
.ascii "hello\n"
len = . - msg
組み立てて実行します。
as -o hello.o hello.S
ld -o hello.out hello.o
./hello.out
期待される出力:
hello
それでは、その例で strace を使用しましょう。
env -i ASDF=qwer strace -o strace.log -s999 -v ./hello.out arg0 arg1
cat strace.log
を使用しております:
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
現在含まれているもの:
execve("./hello.out", ["./hello.out", "arg0", "arg1"], ["ASDF=qwer"]) = 0
write(1, "hello\n", 6) = 6
exit(0) = ?
+++ exited with 0 +++
このような最小限の例では、出力のすべての文字が自明です。
execve
行:で文書化されている CLI 引数と環境を含む、strace
実行方法を示しますhello.out
man execve
write
行: 作成した書き込みシステム コールを示します。6
文字列の長さです"hello\n"
。
= 6
は、システム コールの戻り値であり、 に記載されているように、man 2 write
書き込まれたバイト数です。
exit
行: 作成した exit システム コールを示します。プログラムが終了したため、戻り値はありません。
より複雑な例
もちろん、strace の適用は、複雑なプログラムが実際に実行しているシステム コールを確認して、プログラムのデバッグ/最適化を支援することです。
特に、Linux で遭遇する可能性が高いほとんどのシステム コールには glibc ラッパーがあり、その多くは POSIX からのものです。
内部的には、glibc ラッパーは多かれ少なかれ次のようにインライン アセンブリを使用します:インライン アセンブリで sysenter を介してシステム コールを呼び出すには?
次に学習する必要がある例は、POSIX のwrite
hello world です。
main.c
#define _XOPEN_SOURCE 700
#include <unistd.h>
int main(void) {
char *msg = "hello\n";
write(1, msg, 6);
return 0;
}
コンパイルして実行します。
gcc -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out
今回は、main
main 用の適切な環境をセットアップする前に、glibc によって一連のシステム コールが行われていることがわかります。
これは、現在、フリースタンディング プログラムではなく、libc 機能を可能にするより一般的な glibc プログラムを使用しているためです。
次に、最後に次のものstrace.log
が含まれます。
write(1, "hello\n", 6) = 6
exit_group(0) = ?
+++ exited with 0 +++
write
したがって、 POSIX 関数は、驚いたことに、Linuxwrite
システム コールを使用していると結論付けます。
また、 が の代わりに呼び出しにreturn 0
つながることもわかります。はー、これは知りませんでした!これがとてもクールな理由です。次に説明します。exit_group
exit
strace
man exit_group
このシステム コールは、呼び出しスレッドだけでなく、呼び出しプロセスのスレッド グループ内のすべてのスレッドを終了することを除いて、exit(2) と同等です。
dlopen
そして、これは私がどのシステムコールが使用するかを調べた別の例です:
Ubuntu 16.04、GCC 6.4.0、Linux カーネル 4.4.0 でテスト済み。
Strace は、アプリケーションがオペレーティング システムとどのように対話するかを示すツールです。
これは、アプリケーションが使用する OS システム呼び出しと、それらを呼び出すパラメーターを通知することによって行われます。
たとえば、プログラムが開こうとしているファイルを確認し、呼び出しが成功するかどうかを確認します。
このツールを使用すると、あらゆる種類の問題をデバッグできます。たとえば、アプリケーションが、インストールしたことがわかっているライブラリが見つからないと言った場合、 strace は、アプリケーションがそのファイルを探している場所を教えてくれます。
そして、それは氷山の一角にすぎません。
strace は、プログラムがさまざまなシステム コール (カーネルへの要求) を行う方法を学習するための優れたツールであり、失敗したものとその失敗に関連するエラー値も報告します。すべての失敗がバグというわけではありません。たとえば、ファイルを検索しようとしているコードで ENOENT (No such file or directory) エラーが発生する場合がありますが、コードのロジックでは許容されるシナリオである可能性があります。
strace の適切な使用例の 1 つは、一時ファイルの作成中に競合状態をデバッグすることです。たとえば、あらかじめ決められた文字列にプロセス ID (PID) を追加してファイルを作成するプログラムは、マルチスレッド シナリオで問題に直面する可能性があります。[PID+TID (プロセス ID + スレッド ID) または mkstemp などのより適切なシステム コールがこれを修正します]。
クラッシュのデバッグにも適しています。strace とクラッシュのデバッグに関するこの (私の) 記事が役に立つかもしれません。
strace を使用して Web サイトを掘り下げる方法の例をいくつか示します。これが役に立てば幸いです。
次のように最初のバイトまでの時間を確認します。
time php index.php > timeTrace.txt
アクションの何パーセントが何をしているかを確認します。多くのlstat
とfstat
は、キャッシュをクリアする時期であることを示している可能性があります。
strace -s 200 -c php index.php > traceLstat.txt
trace.txt
どのような呼び出しが行われているかを正確に確認できるように、を出力します。
strace -Tt -o Fulltrace.txt php index.php
.1
これを使用して、読み込みにから.9
秒の間かかったかどうかを確認します。
cat Fulltrace.txt | grep "[<]0.[1-9]" > traceSlowest.txt
に引っかかった行方不明のファイルまたはディレクトリを確認しますstrace
。これにより、システムに関連する多くの情報が出力されます。関連するビットのみが顧客のファイルに関連しています。
strace -vv php index.php 2>&1 | sed -n '/= -1/p' > traceFailures.txt