D言語の基本
DTraceで使用するスクリプト
DTraceを実行するコマンドはdtrace(1)です。使い方もawk(1)と似ています。引数に直接コードを書く場合には次のようにオプション-nにコードを指定します。
dtrace -n 'Dプログラム'
コードをファイルに書いてある場合には、
dtrace -s Dプログラムファイル.d
シバンにdtrace(1)を指定すればシェルスクリプトのようにDプログラムを実行させることができます。シバンにdtrace(1)を指定する場合、
#!/usr/sbin/dtrace -s
…略…
基本的にはこんな感じでコマンドを実行します。Dプログラムの中身ですが、
プローブ /プレディケート/ { アクション }
プローブ /プレディケート/ { アクション }
プローブ /プレディケート/ { アクション }
…
プローブというのはチェックする対象のようなものだと思ってください。その次のプレディケートというのは、
プローブは:で区切られた指定で、
dtrace(1)の簡単なサンプル
awk(1)には特別な条件として処理がはじまる前に一致するBEGINと処理が終わったあとに一致するENDという指定がありますが、
# dtrace -n 'BEGIN { trace("Hello World!"); }' dtrace: description 'BEGIN ' matched 1 probe CPU ID FUNCTION:NAME 0 1 :BEGIN Hello World! ^C #
trace()という処理がメッセージを出力する処理を行っています。この関数は指定されたデータの型に応じてそれぞれ適切な出力を行うというものです。ここでは指定した文字列がそのまま出力されている様子を確認できます。
trace()のほかに、
# dtrace -n 'BEGIN { printf("Hello World!"); }' dtrace: description 'BEGIN ' matched 1 probe CPU ID FUNCTION:NAME 0 1 :BEGIN Hello World! ^C #
dtrace(1)はawk(1)に着想を得て開発された言語と言われていますが、
次の例はopen(2)システムコールが呼ばれたタイミングで、
# dtrace -n 'syscall::open:entry { printf("%s %s", execname, copyinstr(arg0)); }' dtrace: description 'syscall::open:entry ' matched 2 probes CPU ID FUNCTION:NAME 0 58065 open:entry vmtoolsd /etc/resolv.conf 0 58065 open:entry date /etc/localtime 0 58065 open:entry date /usr/share/zoneinfo/posixrules 0 58065 open:entry cal /etc/localtime 0 58065 open:entry cal /usr/share/zoneinfo/posixrules 0 58065 open:entry cal /Users/daichi/.termcap.db 0 58065 open:entry cal /Users/daichi/.termcap 0 58065 open:entry cal /usr/share/misc/termcap.db 0 58065 open:entry vmtoolsd /etc/resolv.conf ^C root@virt:~ #
execnameは組み込み変数で、
copyinstr()は奇妙な指定のように思えると思いますが、
次のDプログラムはfork系のシステムコールが呼ばれたときと終了したときに一致し、
# dtrace -n 'syscall::*fork: { trace(pid); }' dtrace: description 'syscall::*fork: ' matched 16 probes CPU ID FUNCTION:NAME 0 58059 fork:entry 47996 0 58060 fork:return 47996 0 58187 vfork:entry 47996 0 58188 vfork:return 47996 0 58187 vfork:entry 47996 0 58188 vfork:return 47996 0 58059 fork:entry 47996 0 58060 fork:return 47996 0 58187 vfork:entry 47996 0 58188 vfork:return 47996 0 58187 vfork:entry 47996 0 58188 vfork:return 47996 ^C #
syscall::*fork:にはワイルドカードが使われています。*forkに一致するシステムコールがヒットするわけです。そしてこちらにはentryという指定がありません。このため、
次の例はexec系のシステムコールが呼ばれた場合に、
# dtrace -n 'syscall::exec*: { trace(execname); }' dtrace: description 'syscall::exec*: ' matched 2 probes CPU ID FUNCTION:NAME 0 58173 execve:entry fish 0 58174 execve:return date 0 58173 execve:entry fish 0 58174 execve:return hostname 0 58173 execve:entry fish 0 58174 execve:return tr 0 58173 execve:entry fish 0 58174 execve:return sed 0 58173 execve:entry fish 0 58174 execve:return awk ^C #
上記の例ですと、
プレディケートと、
# dtrace -n 'syscall:::entry /execname == "date"/ { @[probefunc] = count(); }' dtrace: description 'syscall:::entry ' matched 1082 probes ^C exit 3 ioctl 3 lseek 3 readlink 3 sysarch 3 write 3 __sysctl 6 access 6 open 6 issetugid 9 openat 9 read 12 close 15 fstat 18 lstat 18 munmap 18 mmap 33 sigprocmask 36 #
syscall:::entryというプローブですべてのシステムコールが呼ばれたタイミングに一致します。/execname == "date"/というプレディケートで、
@[probefunc] = count();というアクションがアグレゲーションというDTraceでもっとも特徴的な機能を使った処理になっています。呼び出された関数名
アグレゲーションは手続き型のプログラミング言語ではあまり見かけないものなので、
※ サンプルコマンドは"DTrace Dynamic Tracing In Oracle Solaris, Mac OS X & FreeBSD", by Brendan Gregg and Jim Mauro P.
勉強会
第60回 2017年2月23日(木)19:00~FreeBSD勉強会
発表内容検討中。発表ネタをお持ちの方、
参加申請はこちらから。
第62回 3月23日(木)19:00~FreeBSD勉強会:リキャップ・ザ・AsiaBSDCon 2017 ~日本語でふりかえるABC~
2017年3月9~12日まで、
3月のFreeBSD勉強会では、
FreeBSD勉強会 発表者募集
FreeBSD勉強会では発表者を募集しています。FreeBSDに関して発表を行いたい場合、