簡単な使い方

Systemtapは、端的に言えばカーネルを対象とした(最新のものだとユーザプロセスも対象にできますが)プログラマブルなデバガです。基本はブレークポイントを埋め込んで、その箇所の情報(ローカル変数など)を取ってきてあれこれするのに使います。

例えば、以下のコマンドをrootユーザで実行すると、プロセスがどんなファイルをオープンしようとしているかが分かります。

# stap -e 'probe kernel.function("sys_open") {printf("%s open %s\n", execname(), user_string($filename))}'
...
hal-ipw-killswi open /usr/lib/libpcre.so.3
hal-ipw-killswi open /lib/libselinux.so.1
hal-ipw-killswi open /lib/tls/i686/cmov/libdl.so.2
hal-ipw-killswi open 
hal-ipw-killswi open /proc/mounts
dbus-daemon open /etc/passwd
dbus-daemon open /etc/group
...

(Ctrl-cで終了します)
この例では、stapコマンドに直接コマンドラインからスクリプトを与えています。もちろん、ファイル経由でも渡せますし、パイプ経由でも渡せます。

# cat > test.stp
probe kernel.function("sys_open")
{
  printf("%s open %s\n", execname(), user_string($filename))
}
# stap test.stp
(もしくは)
# cat test.stp | stap -

プログラムを見ていて分かったかもしれませんが、SystemtapスクリプトC言語awkに似ています。命令の終わりには";"がいりません(あってもいいのですが)。では、例から最低限の使い方を説明します。

probe
プローブの定義命令です。Systemtapカーネルの中にプローブポイント(デバガでいうブレークポイント)を設定し、そのプローブポイントが実行されるごとにプローブハンドラが呼ばれます。probeはこのプローブポイントとプローブハンドラの定義をするための命令です。Systemtapスクリプトは、必ず一つ以上のプローブを定義しておかねばなりません。基本は以下の文法になります。
probe プローブポイント {プローブハンドラの処理}
kernel.function("sys_open")
プローブポイントの定義です。Systemtapデバッグ情報を使うため、最小では行番号単位でプローブポイントを指示することができます。kernel.function("関数名")はもっともよく使うであろう関数の出入り口単位での指定です。この例では、sys_openという名前の関数を指定しています。詳しくは"man stapprobes"で解説が読めます。
{...}
プローブハンドラの本体の定義です。プローブハンドラは必ず{}でかこっておく必要があります。
printf("%s open $s\n", ...)
Cのprintfと同じフォーマットで引数を表示することができます。
execname()
Systemtapで用意している関数の一つです。プローブポイントを実行したプロセスの名前が表示されます。
$filename
$変数名 と書くと、指定した名前のローカル変数にアクセスできます。ただし、この場合変数自体は単なるポインタに過ぎないので、ここから文字列を引き出すには次の関数を使う必要があります。
user_string(...)
ユーザ空間から文字列を取り出します。sys_open関数のfilename引数は、以下のようにユーザ空間のデータとして定義されているので、この関数を使って取り出す必要があります。
asmlinkage long sys_open(const char __user *filename, int flags, int mode)

(fs/open.cより引用)


とりあえず、こんなもんでしょうか。唐突に始めすぎたのでよくわかりません>< 

一行スクリプトは普段から結構使います。長いスクリプトを書いているときに、これでいいんだっけ、と確認したいときなどに-eオプションで一行スクリプトで調べられると便利です。