Solaris モジューラデバッガ

walker の定義

int walk_init(mdb_walk_state_t *wsp);
int walk_step(mdb_walk_state_t *wsp);
void walk_fini(mdb_walk_state_t *wsp);

walker は initstep、および fini の 3 つの関数で構成されており、これらの関数は上記のプロトタイプの例に従って定義されています。walker は、mdb_walk() などのいずれかの walk 関数が呼び出されたとき、あるいはユーザーが ::walk 組み込み dcmd を実行したときに、デバッガによって起動されます。<sys/mdb_modapi.h> に定義されているように、walk が開始されると、MDB は walker の init 関数を呼び出し、新規 mdb_walk_state_t 構造体のアドレスをこの関数に渡します。

typedef struct mdb_walk_state {
			mdb_walk_cb_t walk_callback;    /* 実行のためのコールバック */
			void *walk_cbdata;              /* 専用データのコールバック */
			uintptr_t walk_addr;            /* 現在のアドレス */
			void *walk_data;                /* walk 専用データ */
			void *walk_arg;                 /* walk 専用引数 */
			void *walk_layer;               /* 配下の層からのデータ */
} mdb_walk_state_t;

walk ごとに個別に mdb_walk_state_t が作成されるため、同じ walker の複数のインスタンスを同時にアクティブにすることができます。たとえば mdb_walk() に指定されているように、state 構造体には、各ステップにおいて walker が呼び出すコールバック (walk_callback)、およびそのコールバックに対する専用データ (walk_cbdata) が含まれています。walk_cbdata ポインタは walker からは隠されているため、この値を変更したり、参照を解除したりすることはもちろん、有効なメモリーを指すポインタとみなすこともできません。

walk の開始アドレスは walk_addr に格納されています。このアドレスは mdb_walk() が呼び出された場合の NULL か、または mdb_pwalk() に指定されているアドレスパラメータのどちらかの値となります。::walk 組み込みコマンドが使用された場合、明示的なアドレスが ::walk の左側に指定されているときは、walk_addr は NULL 以外の値となります。開始アドレスが NULL の walk のことを大域 walk といいます。NULL 以外の明示的な開始アドレスを持つ walk のことを局所 walk といいます。

walker 専用の記憶領域として walk_data および walk_arg フィールドが用意されています。複雑な walker の場合、補助的な state 構造体を割り当てて、この構造体を指すように walk_data を設定する必要があります。walk が開始されるたびに、walk_arg は、対応する walker の mdb_walker_t 構造体の walk_init_arg メンバーが持つ値に初期設定されます。

場合によっては、複数の walker に同じ init、step、および fini ルーチンを共有させると便利です。たとえば、MDB genunix モジュールは、各カーネルのメモリーキャッシュに対する walker を提供しています。これらの walker は同じ init、step、および fini 関数を共有しているため、mdb_walker_twalk_init_arg メンバーを使用して、適切なキャッシュのアドレスを walk_arg として指定できます。

walker が mdb_layered_walk() を呼び出して配下の層をインスタンス化した場合、配下の層は walker の step 関数を呼び出す前に walk_addrwalk_layer をリセットします。配下の層は walk_addr を配下のオブジェクトのターゲットの仮想アドレスに設定し、walk_layer が配下のオブジェクトの walker の局所コピーをポイントするように設定します。階層化された walk については、以降の mdb_layered_walk() の説明を参照してください。

walker の init および step 関数は、次の状態値のどれかを返します。

WALK_NEXT

次のステップへ進みます。walk init 関数が WALK_NEXT を返すと、MDB は walk step 関数を呼び出します。walk step 関数から WALK_NEXT が返されたときは、MDB がもう一度 step 関数を呼び出す必要があることを示します。

WALK_DONE

walk が正常に完了しました。WALK_DONE は、walk が完了したことを示すために step 関数から返される場合と、与えられたデータ構造体が空である場合などに step が不要であることを示すために init 関数から返される場合があります。

WALK_ERR

walk がエラーのため終了しました。WALK_ERR が init 関数から返された場合、mdb_walk() (またはそれに相当するもの) は –1 を返して、walker が初期化に失敗したことを示します。WALK_ERR が step 関数から返された場合、walk は終了するが、mdb_walk() 関数からは成功が返されます。

walk_callback からも、上記のどれかの値が返されます。したがって walk step 関数は次のオブジェクトのアドレスを決定し、このオブジェクトの局所コピーを読み取って、walk_callback 関数を呼び出し、その状態を返します。walk が完了したか、またはエラーが発生した場合、step 関数もコールバックを呼び出さずに WALK_DONE または WALK_ERR を返すことがあります。

次に示すように、walker 自体は mdb_walker_t 構造体を使用して定義されます。

typedef struct mdb_walker {
        const char *walk_name;                 /* walk のタイプ名 */
        const char *walk_descr;                /* walk の記述 */
        int (*walk_init)(mdb_walk_state_t *);  /* walk コンストラクタ */
        int (*walk_step)(mdb_walk_state_t *);  /* walk 反復子 */
        void (*walk_fini)(mdb_walk_state_t *); /* walk デストラクタ */
        void *walk_init_arg;                   /* コンストラクタの引数 */
} mdb_walker_t;

walk_name および walk_descr フィールドは、それぞれ walker の名前と短い説明を含む文字列を指すように初期化されます。walker は NULL 以外の名前と説明を持つ必要があり、名前には MDB メタキャラクタを入れることはできません。説明の文字列は ::walkers および ::dmods 組み込み dcmd によって出力されます。

walk_initwalk_step、および walk_fini メンバーは、前述のように walk 関数自体を指しています。特別な初期化またはクリーンアップ措置が必要でないことを示すには、walk_init および walk_fini メンバーを NULL に設定します。walk_step メンバーは NULL には設定できません。前述のように、walk_init_arg メンバーは、指定された walker に対して新規に作成された mdb_walk_state_t ごとに walk_arg メンバーを初期化するのに使用されます。図 10–1 に、典型的な walker のアルゴリズムのフローチャートを示します。

図 10–1 walker の例

この図は walker の例を示しています。

walker はカーネル内の proc_t 構造体のリストに対して繰り返すように設計されています。リストの先頭は practive 大域変数に格納されており、各要素の p_next ポインタはリスト内の次の proc_t を指しています。リストの末尾は NULL ポインタになっています。walker の init ルーチンで、ステップ (1) として practive のシンボルが mdb_lookup_by_name() を使用して検出され、この値が wsp の指す mdb_walk_state_t にコピーされます。

walker の step 関数では、ステップ (2) としてリスト内の次の proc_t 構造体が mdb_vread() を使用してデバッガのアドレス空間にコピーされます。ステップ (3) でこの局所コピーを指すポインタによってコールバック関数が起動され、mdb_walk_state_t が次の繰り返しに対する proc_t 構造体のアドレスで更新されます。ステップ (4) では、この更新は、リスト内の次の要素を指す次のポインタに対応しています。

これらのステップは一般的な walker の構造を示しています。init ルーチンが特定のデータ構造体に関する大域的な情報を検出し、step 関数が次のデータ項目のコピーを読み取ってコールバック関数に渡し、次の要素のアドレスが読み取られます。最終的に walk が終了すると、fini 関数によってすべての専用記憶領域が解放されます。