Jump to contentJump to page navigation: previous page [access key p]/next page [access key n]
適用先 openSUSE Leap 15.7

4 SystemTap: システムデータのフィルタリングと分析 Edit source

SystemTap は、稼働中の Linux システムで動作状況を調査するためのコマンドラインインターフェイスとスクリプト言語を提供する仕組みです。特にカーネルの動作状況を詳細に収集することができます。 SystemTap のスクリプトは SystemTap スクリプト言語で記述され、これを C 言語のカーネルモジュールにコンパイルして、カーネル内に挿入します。スクリプトはデータを抽出するだけでなく、フィルタや要約を行うこともできるため、複雑な性能問題や機能面の問題を分析することができるようになっています。また、 SystemTap では netstat , ps , top , iostat などのツールの出力に似た情報を提供しますが、収集した情報に対してフィルタリングや分析などのオプションを適用することができます。

4.1 考え方の概要 Edit source

SystemTap スクリプトを動作させると、 SystemTap セッションが起動します。また、スクリプトが実行されるまでの間に、いくつかのパスが実行されます。その後、スクリプトはカーネルモジュールとしてコンパイルされ、読み込まれます。スクリプトを以前に実行していて、システムコンポーネント (コンパイラやカーネルのバージョン、ライブラリパスやスクリプトの内容) に変更がない場合、 SystemTap は再度スクリプトをコンパイルするようなことはありません。その代わり、 SystemTap のキャッシュ ( ~/.systemtap ) 内に保存されている *.c*.ko のデータを使用します。

タップの動作が完了すると、モジュールの読み込みも解除されます。たとえば 4.2項 「インストールと設定」 にあるテストスクリプトと、対応する説明をお読みください。

4.1.1 SystemTap スクリプト Edit source

SystemTap は SystemTap スクリプト ( *.stp ) を利用して行う仕組みです。スクリプト内では収集する情報の種類のほか、収集後に何をすべきかを指定しています。スクリプトは SystemTap スクリプト言語と呼ばれる、 AWK や C 言語に似た言語で作成します。言語の詳しい定義については https://sourceware.org/systemtap/langref.pdf (英語) をお読みください。また、スクリプト例については https://www.sourceware.org/systemtap/examples/ をご覧ください。

SystemTap スクリプトの考え方のベースとして、 イベント とそれに対応した ハンドラ があります。 SystemTap がスクリプトを実行すると、 SystemTap はまず特定のイベントを待機します。そのイベントが発生すると、 Linux カーネルはサブルーチンとして指定されたハンドラを実行し、元の処理に戻ります。このような仕組みであることから、イベントはスクリプトを実行する際のトリガー (起動条件) と考えることができます。また、ハンドラは指定したデータをそのまま記録することができるほか、特定の書式でそれを出力することもできます。

SystemTap 言語にはいくつかのデータ型 (整数, 文字列, およびそれらの連想配列) と、完全な制御構造 (ブロック, 条件分岐, ループ, 関数) が用意されています。また、文法は軽量な構造で、文末のセミコロンは省略することができますし、詳細なデータ型指定を行う必要もありません (データ型は自動的に推測およびチェックされます) 。

SystemTap スクリプトとその文法に関する詳細については、 4.3項 「スクリプトの文法」 のほか、 stapprobesstapfuncs の各マニュアルページをお読みください。マニュアルページは systemtap-docs パッケージ内に含まれています。

4.1.2 タップセット Edit source

タップセットは、あらかじめ記述されたプローブや関数を含むライブラリで、 SystemTap のスクリプト内から使用することができます。 SystemTap のスクリプトを実行すると、 SystemTap はスクリプト内のプローブイベントとハンドラが、タップセットライブラリ内に存在していないかどうかを確認します。 SystemTap はスクリプトを C 言語に翻訳する前に、対応するプローブや関数を読み込みます。 SystemTap スクリプト自身のように、タップセットにも同じファイル拡張子 *.stp が設定されています。

ただし、 SystemTap スクリプトとは異なり、タップセットは直接実行するためのものではありません。タップセットは他のスクリプトに定義を与える存在であり、タップセットライブラリはユーザに対して、イベントや関数の定義をやりやすくするために設計されているものです。タップセットは関数に対して別名を提供し、ユーザ側からイベントとして指定することができるようになります。そのため、カーネルのバージョンによって異なるようなカーネルの関数を、より簡単に指定することができるようになります。

4.1.3 コマンドと権限 Edit source

SystemTap に付属するメインのコマンドは、 stapstaprun の 2 種類です。これらを実行するには root の権限を使用するか、もしくは stapdev または stapusr のメンバーである必要があります。

stap

SystemTap のフロントエンドです。 SystemTap スクリプトのファイルを指定するか、もしくは標準入力から読み込むことで実行することができます。スクリプトは C 言語のコードに翻訳され、コンパイルされて動作中の Linux カーネル内でモジュールとして読み込みが行われます。これにより、必要なシステムトレースやプローブ関数を実行することができるようになります。

staprun

SystemTap のバックエンドです。 SystemTap のフロントエンドが作成したカーネルモジュールを、読み込んだり読み込みを解除したりすることができます。

それぞれのコマンドに対するオプションを知りたい場合は、 --help オプションを指定して実行してください。詳しくは stapstaprun の各マニュアルページをお読みください。

root の権限を与えずに一般ユーザの権限で SystemTap を実行させたい場合は、対象のユーザを下記の SystemTap グループのいずれかに所属するように設定してください。これらのグループは既定の openSUSE Leap では作成されていませんので、必要に応じて作成し、アクセス権を調整してください。また、お使いの環境でセキュリティへの影響に問題がなければ、 staprun コマンドのパーミッションを調整してもかまいません。

stapdev

このグループのメンバーであれば、 stap コマンドで SystemTap スクリプトを実行することができるほか、 staprun コマンドで計装モジュールを実行することもできます。なお、 stap コマンドの実行には、スクリプトをカーネルモジュールにコンパイルする処理と、コンパイルしたカーネルモジュールをカーネルに読み込む処理が含まれますので、実質的には root のアクセスと同等の権限を持つことになります。

stapusr

このグループのメンバーは、 staprun コマンドで計装モジュールを実行する権限のみを持ちます。これに加えて、 /lib/modules/カーネルバージョン/systemtap/ 内にあるモジュールのみを実行することができます。このディレクトリは root が所有しなければならず、かつ root ユーザのみが書き込むことができるようにしなければなりません。

4.1.4 主要なファイルとディレクトリ Edit source

下記では、 SystemTap で使用される主なファイルとディレクトリについて、概要を説明しています。

/lib/modules/カーネルバージョン/systemtap/

SystemTap の計装モジュールが含まれるディレクトリです。

/usr/share/systemtap/tapset/

タップセットの標準ライブラリが含まれるディレクトリです。

/usr/share/doc/packages/systemtap/examples

様々な用途に対応した SystemTap スクリプトの例を配置しているディレクトリです。なお、このディレクトリは systemtap-docs パッケージをインストールした場合にのみ作成されます。

~/.systemtap/cache

キャッシュされた SystemTap ファイルを含むデータディレクトリです。

/tmp/stap*

SystemTap ファイルの一時ディレクトリです。 C 言語に変換されたコードのほか、カーネルオブジェクトなどが含まれます。

4.2 インストールと設定 Edit source

SystemTap を動作させるにはカーネルに関する情報が必要となることから、カーネル関連の追加パッケージをインストールしなければなりません。また、 SystemTap でプローブを設定したいカーネルごとに、それぞれ下記のパッケージをインストールする必要があります。さらに、下記のパッケージをインストールする場合は、プローブを設定したいカーネルのフレーバー (下記では * と記してあります) とバージョンが厳密に一致したパッケージをインストールする必要があります。

重要
重要: デバッグ情報 (debuginfo) パッケージのリポジトリについて

お使いのシステムでオンライン更新を有効にしていれば、 openSUSE Leap 15.7 に対応する *-Debuginfo-Updates という名前のオンラインリポジトリ内に、 debuginfo パッケージが存在しています。このリポジトリを有効にするには、 YaST をお使いください。

従来型の SystemTap 設定を行う場合は、下記のパッケージをインストールしてください (YaST もしくは zypper を利用してインストールします。

  • systemtap

  • systemtap-server

  • systemtap-docs (任意)

  • kernel-*-base

  • kernel-*-debuginfo

  • kernel-*-devel

  • kernel-source-*

  • gcc

マニュアルページや SystemTap のスクリプト例など、様々な目的でのヘルプ情報を必要とする場合は、これらに加えて systemtap-docs パッケージもインストールしてください。

マシン内に必要なパッケージを全てインストールできていて、 SystemTap を使用するための準備が整っているかどうかを確認するには、下記のコマンドを root で実行します:

# stap -v -e 'probe vfs.read {printf("read performed
"); exit()}'

上記のコマンドを実行すると、スクリプトを実行して現在動作しているカーネルに対してプローブを設定し、出力を返します。出力が下記のような内容になっていれば、 SystemTap は問題なく配置できたことになります:

Pass 1: parsed user script and 59 library script(s) in 80usr/0sys/214real ms.
Pass 2: analyzed script: 1 probe(s), 11 function(s), 2 embed(s), 1 global(s) in
 140usr/20sys/412real ms.
Pass 3: translated to C into
 "/tmp/stapDwEk76/stap_1856e21ea1c246da85ad8c66b4338349_4970.c" in 160usr/0sys/408real ms.
Pass 4: compiled C into "stap_1856e21ea1c246da85ad8c66b4338349_4970.ko" in
 2030usr/360sys/10182real ms.
Pass 5: starting run.
 read performed
Pass 5: run completed in 10usr/20sys/257real ms.

1

スクリプトと /usr/share/systemtap/tapset/ 内にある既存のタップセットライブラリをチェックしています。タップセットとはあらかじめ作成されたプローブや関数を集めたライブラリで、 SystemTap スクリプト内から使用できる仕組みです。

2

スクリプトのコンポーネントを調べています。

3

スクリプトを C 言語に変換しています。その後、作成された C 言語のソースコードを C コンパイラに通して、カーネルモジュールを作成しています。変換後の C 言語ソースコード ( *.c ) とカーネルモジュール ( *.ko ) が、 ~/.systemtap にある SystemTap キャッシュ内に保管されます。

4

モジュールを読み込んだあと、スクリプト内に指定されている全てのプローブ (イベントおよびハンドラ) をカーネル内のフックとして設置し、有効化しています。この例で使用しているプローブは、仮想ファイルシステム (Virtual File System; VFS) の読み込み処理になります。任意のプロセッサ内で対象のイベントが発生すると、対応するハンドラが実行 (この例では、 read performed と表示しています) され、エラー無しに終了しています。

5

SystemTap のセッションが終了すると、プローブは無効化され、カーネルモジュールの読み込みも解除されます。

テスト時に何らかのエラーメッセージが表示された場合、まずは出力された内容をご確認ください。出力された内容に必要なパッケージに関する情報が書かれている場合は、まず必要なパッケージが正しくインストールされていることを確認してください。また、カーネルをインストールした場合は、システムを再起動して新しいカーネルを読み込む必要があります。

4.3 スクリプトの文法 Edit source

SystemTap のスクリプトは、下記に示す 2 つのコンポーネントから構成されています:

SystemTap イベント (プローブポイント)

カーネル内のどのイベントでスクリプトを実行するのかを表している箇所です。特定の関数内に入ったタイミングや特定の関数を出たタイミング、もしくはタイマーの経過後やセッションの開始および停止などに設定することができます。

SystemTap ハンドラ (プローブボディ)

特定のイベントが発生した際に実行すべきスクリプトを表している箇所です。これは通常、イベント内の情報を抽出したり、それらを内部の変数に格納したり、結果を出力したりする処理を行います。

イベントとそれに対応するハンドラをまとめて、 プローブ と呼びます。 SystemTap のイベントは プローブポイント 、対応するハンドラは プローブボディ とも呼びます。

コメントは SystemTap スクリプト内の任意の箇所に配置することができます。コメントの書式は、 #, /* */ , // のいずれかです。

4.3.1 プローブの書式 Edit source

SystemTap のスクリプトには複数のプローブを設定することができます。プローブは下記の書式で作成します:

probe イベント名 {ステートメント}

それぞれのプローブには対応するステートメントブロックを設定します。ステートメントブロックは { } で括らなければならず、かつイベントごとに実行すべきステートメントを含むものとします。

例 4.1: シンプルな SystemTap スクリプト

下記はシンプルな SystemTap スクリプトの例です。

probe1 begin2
{3
   printf4 ("hello world
")5
   exit ()6
}7

1

プローブの開始位置です。

2

イベント begin (SystemTap セッションの開始) の指定です。

3

{ で示されているとおり、ハンドラ定義の開始位置です。

4

ハンドラ内での最初の関数です。この例では printf 関数を使用しています。

5

printf 関数で出力すべき文字列を指定しています。末尾には改行 ( /n ) が書かれています。

6

ハンドラ内での 2 つめの関数です。この例では exit() 関数を使用しています。なお、 SystemTap スクリプトは exit() 関数を実行するまでは、動作し続けることに注意してください。この関数を実行する前にスクリプトの実行を停止したい場合は、 CtrlC を押します。

7

} で示されているとおり、ハンドラ定義の終了位置です。

イベント begin 2 (SystemTap セッションの開始) が発生すると、 { } で括られたハンドラを実行します。ここでは、 printf 関数 4 になります。この場合、 hello world という文字列に加えて改行 5 を出力しています。出力が終わると、スクリプトは終了します。

ステートメント内に複数の記述が存在する場合、 SystemTap ではそれらを順次実行します。言い換えると、複数のステートメントを記述するにあたって、特殊な区切り文字や終端などを入れる必要はありません。 SystemTap 内では一般に、ステートメントブロックは C プログラミング言語と同じ書式になっています。

4.3.2 SystemTap イベント (プローブポイント) Edit source

SystemTap にはいくつかの内蔵イベントが用意されています。

一般的なイベント名はドットで区切った DNS のような命名体系になっています。この仕組みにより、名前をツリー構造で管理できるようになっています。また、ドット区切り内の各コンポーネントには、文字列や数値によるパラメータを設定できるようになっていて、見た目では関数のような表現になっています。また、コンポーネントに * を指定した場合、複数のプローブポイントにマッチするようなイベント名にすることができます。また、プローブポイントの後には ? が付けられることもあります。この場合、それが任意指定のものであることを示し、展開に失敗した場合もエラーが無視されるようになります。 また、プローブポイントの後ろに ! を付けた場合、任意指定でかつ十分な存在であることを示します。

SystemTap では 1 つのプローブに対して複数のイベントを設定することができます。複数のイベントを指定する場合、イベント間は ( , ) で区切ります。また、 1 つのプローブに対して複数のイベントが指定された場合、 SystemTap はいずれかのイベントが発生した場合に、指定のハンドラを実行することになります。

イベントは下記のような分類に分けることができます:

  • 同期型イベント: 任意のプロセスが、カーネルコード内の特定の箇所に達した場合に発生するイベントです。これは他のイベントに対して参照ポイント (インストラクションアドレス) を与え、ここから多くのコンテキスト情報を取得できるようになります。

    同期型イベントの例として、 vfs.ファイル操作 があります。これは仮想ファイルシステム (Virtual File System; VFS) 内の ファイル操作 イベントを表すもので、たとえば 4.2項 「インストールと設定」 では、 readファイル操作 の箇所にあたります。

  • 非同期型イベント: 特定のインストラクションやカーネルコード内の位置に結びつかないイベントです。このようなプローブポイントとしては、カウンターやタイマーなどの構造があります。

    非同期型イベントの例としては、 begin (SystemTap セッションの開始) や end (SystemTap セッションの終了) のほか、タイマーイベントがあります。タイマーイベントは定期的に実行すべきハンドラを指定するためのもので、たとえば example timer.s()timer.ms(ミリ秒) のように指定します。

    タイマーイベントは、他のプローブと併用することで、定期的なデータ更新を行うことができるようになるほか、時間が経過するたびに変化していくような情報を追跡することができるようになります。

例 4.2: タイマーイベントのプローブ

たとえば下記のようなプローブを設定すると、 hello world を 4 秒間隔で出力します:

probe timer.s(4)
{
   printf("hello world
")
}

対応するイベントの詳細について、詳しくは stapprobes のマニュアルページをお読みください。マニュアルページ内の See Also セクションには、特定のサブシステムやコンポーネントに対するイベントを含む、他のマニュアルページへのリンクが書かれています。

4.3.3 SystemTap ハンドラ (プローブボディ) Edit source

SystemTap イベントには対応するハンドラが指定されます。ハンドラ内では、ステートメントブロックから構成される処理を記述します。

4.3.3.1 関数 Edit source

複数のプローブ内で同じステートメントを実行する必要がある場合は、それらの共通部分を関数として取り出して、再利用しやすくすることをお勧めします。関数はキーワード function に続いて関数名を指定することで、定義を行うことができます。また、任意の数の文字列や数値 (いずれも値渡し) をパラメータとして取ることができ、返り値は単一の文字列もしくは数値を設定することができます。

function 関数名(パラメータ) {ステートメント}
probe イベント {関数名(パラメータ)}

上記の例では、 イベント のハンドラが実行されると、 関数名 の関数が実行されます。 パラメータ は任意指定のもので、関数に渡すパラメータを指定します。

関数はスクリプト内の任意の場所に記述することができます。

よく使用する関数の例として、既に 例4.1「シンプルな SystemTap スクリプト」 で紹介を行っている printf 関数があります。この関数は書式を指定してデータを出力するための関数で、書式ではどれだけの数のパラメータを出力するのか、およびどのように整形して出力するのかを指定します。書式文字列は二重引用符で括り、書式指定は % 文字で書き始めます。

どのような書式指定文字列を使用するのかは、そのパラメータに依存して決まります。書式指定文字列は複数個指定することができ、その際にはパラメータをカンマ区切りで指定します。

例 4.3: 書式指定を伴う printf 関数
printf ("1%s2(%d3) open
4", execname(), pid())

1

" で示されているとおり、書式指定文字列の開始位置です。

2

文字列の書式指定です。

3

整数の書式指定です。

4

" で示されているとおり、書式指定文字列の終了位置です。

上記の例では、実行ファイル名 ( execname() ) を文字列で、プロセス ID ( pid() ) を括弧内に整数で、それぞれ出力する指定になっています。その後ろは固定でスペースを入れ、 open と出力して改行を行います:

[...]
vmware-guestd(2206) open
held(2360) open
[...]

例4.3「書式指定を伴う printf 関数」 で使用している execname()pid() のほかにも、 printf のパラメータとしては様々な関数を指定することができます。

SystemTap で最もよく使用される関数は下記のとおりです:

tid()

現在のスレッドの ID を返します。

pid()

現在のスレッドのプロセス ID を返します。

uid()

現在のユーザのユーザ ID を返します。

cpu()

現在の CPU 番号を返します。

execname()

現在のプロセスの名前を返します。

gettimeofday_s()

Unix エポック (1970 年 1 月 1 日) からの経過秒数を返します。

ctime()

時刻を文字列に変換します。

pp()

現在処理しているプローブポイントの文字列表現を返します。

thread_indent()

出力結果を読みやすくするための便利な関数です。これは各スレッド ( tid() ) に対して (内部的な) インデントカウンタを保存するものです。この関数には 1 つだけパラメータを指定しますが、このパラメータはインデント差 (スレッドのインデントカウンタの増減値) を指定します。返り値は一般的なトレースデータと、インデントカウンタの値に対応した数のスペースを含む文字列になります。一般的なトレースデータには、タイムスタンプ (スレッドの初期インデントからの経過マイクロ秒) のほか、プロセス名とスレッド ID それ自身が含まれます。これにより、どの関数を誰が呼び出したのか、およびそれにどれだけの時間を要したのかがわかるようになっています。

システムコールの開始と終了は、見た目ではわかりにくくなってしまうことがあります。たとえば一方のシステムコールが他方のシステムコールを呼び出していて、そのいずれにもプローブを設定しているような場合、開始と終了が入れ子になってしまい、出力がわかりにくくなってしまいます。このインデントカウンタの仕組みを使用することで、入れ子の形で呼び出されているシステムコールの出力を字下げ (インデント) して、読みやすくする効果を生み出します。

提供されている SystemTap 関数に関する詳細な情報については、 stapfuncs のマニュアルページをお読みください。

4.3.3.2 その他の基本構造 Edit source

関数のほかに、 SystemTap ハンドラ内ではその他の一般的な構造を作成することができます。具体的には変数や条件分岐 (if / else) 、 while ループや for ループ、そして配列やコマンドラインパラメータなどがあります。

4.3.3.2.1 変数 Edit source

変数はスクリプト内の任意の場所に定義することができます。変数を定義したい場合は、単純に名前を選んで関数や表現を代入するだけです:

foo = gettimeofday( )

代入した後は、任意の箇所で変数を使用するだけです。 SystemTap では、変数の代入元のデータ型 (文字列もしくは数値) に従って、変数のデータ型を自動継承します。何らかの矛盾が発生した場合、それらはエラーとして報告されます。上記の例では、 foo は代入元に従って数値型として設定され、 printf() 関数の整数書式指定子 ( %d ) で出力できる変数になります。

ただし、既定では変数は全てプローブ内ローカルになります。プローブ内ローカルであることから、変数はハンドラの実行のたびに初期化され、使用され、廃棄されることになります。プローブ間で変数を共有したい場合は、グローバル変数としてスクリプト内に定義してください。グローバル変数を定義するには、プローブの外で global キーワードを指定して宣言します:

例 4.4: グローバル変数の使用
global count_jiffies, count_ms
probe timer.jiffies(100) { count_jiffies ++ }
probe timer.ms(100) { count_ms ++ }
probe timer.ms(12345)
{
  hz=(1000*count_jiffies) / count_ms
  printf ("jiffies:ms ratio %d:%d => CONFIG_HZ=%d
",
    count_jiffies, count_ms, hz)
  exit ()
  }

上記の例では、 jiffies とミリ秒によるタイマーを利用して、カーネルの CONFIG_HZ の設定を計算しています。 jiffy/jiffies はシステムのタイマー割り込みの回数を数えるもので、プロセッサのクロック周波数によって間隔が変化するものであることから、これを実時間で割ることで、クロック周波数を計算しています。ここでの global 定義は count_jiffiescount_ms ですが、これらはそれぞれのタイマー値を保存しておくためのものです。また、 ++ という演算子は、変数の値を 1 だけ足す意味です。

4.3.3.2.2 条件分岐 Edit source

SystemTap スクリプト内で使用できる条件分岐には、いくつかのものがあります。最もよく使用されるものを下記に示します:

If/Else ステートメント

下記のように記述します:

if (条件)1ステートメント_12
else3ステートメント_24

if ステートメントは、整数表現がゼロであるかどうかを調べます。 1 の結果がゼロ以外であった場合、最初のステートメント 2 が実行されます。逆に、ゼロであった場合は、 2 番目のステートメント 4 が実行されます。 else 句 ( 3 および 4 ) は任意指定で、指定しても指定しなくてもかまいません。また、 24 には、ステートメントブロックを指定することもできます。

While ループ

下記のように記述します:

while (条件)1ステートメント2

条件 がゼロ以外であった場合、 2 を実行します。 2 はステートメントブロックでもかまいません。最終的に 条件 がゼロになるまで、繰り返し実行します。

For ループ

while ループのショートカットとして規定されているもので、下記のように記述します:

for (初期化1; 条件2; 増加処理3) ステートメント

1 に記述したステートメントはカウンタの初期化用に使用すべき箇所で、ループの開始前に実行されます。ループは 2 のステートメントの結果が false になるまで繰り返されます (判断処理はループの処理前に行われます) 。また、 3 はループカウンタの増加処理で使用すべき箇所です。こちらはループ処理後に実行されます。

比較演算子

条件の指定では、下記の演算子を使用することができます:

==: 等しいかどうか

!=: 等しくないかどうか

>=: 前のほうが後より大きいかどうか、もしくは等しいかどうか

<=: 前のほうが後より小さいかどうか、もしくは等しいかどうか

4.4 スクリプト例 Edit source

systemtap-docs パッケージをインストールしていれば、 /usr/share/doc/packages/systemtap/examples 内に SystemTap のスクリプト例がいくつか用意されています。

本章では、 /usr/share/doc/packages/systemtap/examples/network/tcp_connections.stp にあるシンプルなスクリプト例を詳しく説明します:

例 4.5: tcp_connections.stp での着信 TCP 接続の監視
#! /usr/bin/env stap

probe begin {
  printf("%6s %16s %6s %6s %16s
",
         "UID", "CMD", "PID", "PORT", "IP_SOURCE")
}

probe kernel.function("tcp_accept").return?,
      kernel.function("inet_csk_accept").return? {
  sock = $return
  if (sock != 0)
    printf("%6d %16s %6d %6d %16s
", uid(), execname(), pid(),
           inet_get_local_port(sock), inet_get_ip_source(sock))
}

この SystemTap スクリプトは着信側の TCP 接続を監視して、リアルタイムに望まない接続を識別する仕組みを提供するものです。それぞれコンピュータが受け入れた着信側 TCP 接続に対して、下記のような情報を表示します:

  • ユーザ ID ( UID )

  • 接続を受け付けたコマンド ( CMD )

  • コマンドのプロセス ID ( PID )

  • 接続に使用しているポート ( PORT )

  • TCP 接続の発信元 ( IP_SOURCE )

スクリプトを実行するには、下記のように入力して実行します:

stap /usr/share/doc/packages/systemtap/examples/network/tcp_connections.stp

すると、画面内に出力が表示されるようになります。スクリプトを手作業で停止するには、 CtrlC を押します。

4.5 ユーザスペースプローブ Edit source

DTrace のようにユーザスペースで動作するアプリケーションをデバッグする目的で、 openSUSE Leap 15.7 では、 SystemTap でユーザスペースのプローブを行うことができます。ユーザスペースのプローブでは、アプリケーション内の任意の場所にプローブポイントを設置することができます。これにより、 SystemTap はカーネルスペースとユーザスペースの両方を調査できることになり、結果としてシステム全体を調査できるようになっています。

ユーザスペースのプローブを設置する際に必要となる utrace インフラストラクチャと uprobe カーネルモジュールを取得するには、 4.2項 「インストールと設定」 に示されているパッケージに加え、 kernel-trace パッケージをインストールする必要があります。

utrace はユーザスペースの処理を制御するためのフレームワークを実装するものです。様々なトレーシング エンジン で使用することのできるインターフェイスを提供し、これ自身は読み込み可能なカーネルモジュールとして提供されます。エンジンは特定のイベントに対してコールバック関数を登録し、トレース対象のスレッドに結びつけられます。コールバックはカーネル内の 安全な 場所から行われるため、関数が実行できる処理の種類に大きな余裕ができることになります。 utrace では、たとえばシステムコールの開始と終了、 fork() やタスクに送信されるシグナルなど、様々なイベントを監視することができます。 utrace のインフラストラクチャについて、詳しくは https://sourceware.org/systemtap/wiki/utrace (英語) をお読みください。

SystemTap では、ユーザスペースプロセス内での関数の開始および終了のプローブに対応しているほか、コード内にマーカーを設定してプローブしたり、特定のプロセス内イベントを監視したりすることもできます。

現在実行しているカーネルが utrace に対応しているかどうかを調べるには、下記のコマンドを実行します:

> sudo grep CONFIG_UTRACE /boot/config-`uname -r`

ユーザスペースのプローブについて、詳しくは https://sourceware.org/systemtap/SystemTap_Beginners_Guide/userspace-probing.html (英語) をお読みください。

4.6 さらなる情報 Edit source

本章では、 SystemTap の概要部までしか言及できていません。 SystemTap に関する詳細な情報を得たい場合は、それぞれ下記を参照してください (英語のみの提供である場合もあります):

https://sourceware.org/systemtap/

SystemTap プロジェクトの Web ページです。

https://sourceware.org/systemtap/wiki/

SystemTap に関する便利な情報を数多く集めているサイトです。ユーザに対する詳しい説明から開発者向けの資料のほか、他のツールとの比較やレビュー、よくある質問とその回答 (FAQ) やヒントなどが書かれています。また、 SystemTap スクリプトの例もあり、使用例や SystemTap に関する直近の対話、ペーパーなども用意されています。

https://sourceware.org/systemtap/documentation.html

PDF および HTML 形式で、 SystemTap Tutorial (SystemTap チュートリアル), SystemTap Beginner's Guide (SystemTap 初心者ガイド), Tapset Developer's Guide (タップセット開発者ガイド), SystemTap Language Reference (SystemTap 言語リファレンス) などが用意されています。

なお、 SystemTap の言語リファレンスとチュートリアルについては、 /usr/share/doc/packages/systemtap ディレクトリ内にも用意されています。また、スクリプトの例については、上記の example サブディレクトリをご覧ください。

このページを印刷