straceでシステムコールをトレース

2012-05-17

straceとは

straceはシステムコールの呼び出しをトレースするコマンドです。

特にソースコードを変更せずに、コマンドで指定するだけなので気軽に使えます。

今回はstraceを使ってシステムコールの呼び出しをトレースする方法を紹介します。

下ごしらえ

まずはトレース対象となる実行形式を作ります。

main.cとして以下のコードを保存します。

#include <stdio.h>

int main(int argc, char *argv[])
{
  printf("printf called!\n");
  return 0;
}

コンパイルします。

$ gcc main.c

コンパイルが完了したので実行してみましょう。

$ ./a.out
printf called!

無事に実行されました。

straceを使う

それでは準備ができましたので本題のstraceを使ってみましょう。

straceの引数として実行形式を指定します。

$ strace ./a.out > /dev/null
execve("./a.out", ["./a.out"], [/* 40 vars */]) = 0
brk(0)                                  = 0xa83000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f53eac43000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=45084, ...}) = 0
mmap(NULL, 45084, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f53eac37000
close(3)                                = 0
open("/lib64/libc.so.6", O_RDONLY)      = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360\355\1\275:\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1908792, ...}) = 0
mmap(0x3abd000000, 3733672, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x3abd000000
mprotect(0x3abd186000, 2097152, PROT_NONE) = 0
mmap(0x3abd386000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x186000) = 0x3abd386000
mmap(0x3abd38b000, 18600, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x3abd38b000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f53eac36000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f53eac35000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f53eac34000
arch_prctl(ARCH_SET_FS, 0x7f53eac35700) = 0
mprotect(0x3abd386000, 16384, PROT_READ) = 0
mprotect(0x3abca1f000, 4096, PROT_READ) = 0
munmap(0x7f53eac37000, 45084)           = 0
fstat(1, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff04334260) = -1 ENOTTY (Inappropriate ioctl for device)
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f53eac42000
write(1, "printf called!\n", 15)        = 15
exit_group(0)                           = ?

単にprintfを呼び出しただけなのにこんなにも出力されました。

単にprintfを呼び出すのにこれだけのシステムコールが呼ばれているわけです。

printfの内部でよばれているシステムコールはwriteなので、wtiteだけ抜き出したい場合には 次のように-eオプションでwriteを指定します。

$ strace -e write  ./a.out > /dev/null
write(1, "printf called!\n", 15)        = 15

writeだけが表示されていますね。

まとめ

今回はstraceを使って関数の呼び出しをトレースする方法を紹介しました。

どんなシステムコールが呼び出されているかを簡単に確認できます。

呼び出されるシステムコールがわかると内部でどんな動作をしているのかを探る 重要な手がかりとなります。

ご質問等、何かありましたらこちらへ。