Eyes, JAPAN Blog > straceでプログラムを感じる

straceでプログラムを感じる

Takeyuki Sato

この記事は1年以上前に書かれたもので、内容が古い可能性がありますのでご注意ください。

感じるとは

プログラムは、ソースコードを読まないと挙動を把握できないかというとそうではありません。strace,dtrace,mtraceなどのtrace系コマンドを使って挙動を細部まで理解できなくとも大まかに把握することができます。そう、感じるのです(爆

さて、早速ですが「ls」コマンドを感じてみたいと思います。

「ls」を感じてみる

$ strace ls

そうすると標準出力にバーっと出ます。
以下、一部省略

execve("/bin/ls", ["ls"], [/* 51 vars */]) = 0
↑どのプログラムもまずは実態の呼び出し!引数なしの純粋さ!
brk(NULL) = 0x7a0000
↑動的に割り当てる領域の地面作ったる!
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
↑なんだかよくわからないけどファイルないみたいだから無視!
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fecaf534000
↑仮想メモリ 8192バイトもーらい!ここら変にこれから色々なプログラムロードしていくのか!?
...
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
↑printfとか入ってるツールボックス開けなきゃだ...ファイルディスクリプタ3!!!!
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\t\2\0\0\0\0\0"..., 832) = 832
↑ファイルディスクリプタ3よりバイナリで読みま〜す!
fstat(3, {st_mode=S_IFREG|0755, st_size=1864888, ...}) = 0
↑ファイルの状態取得してる!これでエラーが出るのはファイル名が長いとかのイチャモンで弾かれることあるけど今回はおっけーのreturn 0!
mprotect(0x7fecaeee5000, 2097152, PROT_NONE) = 0
↑指定のアドレス守ってあげる!
...
open("/lib/x86_64-linux-gnu/libpcre.so.3", O_RDONLY|O_CLOEXEC) = 3
↑正規表現ライブラリも欲しいのか!
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0000\25\0\0\0\0\0\0"..., 832) = 832
...
open("/proc/filesystems", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(3, "nodev\tsysfs\nnodev\trootfs\nnodev\tr"..., 1024) = 380
read(3, "", 1024) = 0
close(3) = 0
↑ファイルシステム一覧を取得したみたい...
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=4016704, ...}) = 0
mmap(NULL, 4016704, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fecae2c0000
close(3) = 0
↑文字コードについて取得したみたい...
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=48, ws_col=157, ws_xpixel=0, ws_ypixel=0}) = 0
open(".", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
↑ついに準備が整いカレントディレクトリーのファイルディスクリプタを取得!
fstat(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
getdents(3, /* 36 entries */, 32768) = 1240
getdents(3, /* 0 entries */, 32768) = 0
↑ファイルディスクリプタからディレクトリ構成もーらい!
close(3) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
write(1, "build Desktop\tDocuments Downlo"..., 95build Desktop Documents Downloads Music ns-3-allinone Pictures Public Templates Videos
) = 95
↑表示!
close(1) = 0
close(2) = 0

慣れると読まなくていいところや繰り返しの部分がわかり5秒くらい(盛ってます)で把握できます!

さて、今回はシステムコールをトレースするツールを使いましたが、共有ライブラリ関数をトレースするのもありさらにプログラムの内部が詳しくわかりますがそれはまた別の記事に書きたいと思います。

問題

最後に以下の内部動作を予想しながらトレースして、対象ホストに接続してるシステムコールを見つけてみてください!
pythonの処理とか色々ごちゃごちゃあって大変かもしれませんがシステムコールにあたりをつけてそのシステムコールだけを表示するオプションがありますので調べてみてください!

$ strace python -c 'import socket;socket.getaddrinfo("google.com","www")'

Comments are closed.