K.Sasada's Home Page

こめんとのついか

こめんとこめんと!

message

please add long comment :).

_18(Tue)

Ruby VM アドベントカレンダーの 18 日目です.

今回は 2.0 から試験的に導入された Debug Inspector API のご紹介をしようと思います.なお,この機能も例によって実験中ですので,あとで変わるかもしれませんし,無くなるかもしれません.フィードバック,お待ちしております.

さて,Debug Inspector API とは何かというと,ずばりスタックフレームの情報を取り出すことです.っていうと,caller_locations でいいじゃん,という気がしますが,これはスタックフレームの任意のフレームの Binding オブジェクトが取り出せます.つまり,幻のメソッド Binding of caller って奴です.ただ,利用方法はちょっと複雑になっています.また,パフォーマンスが凄い遅いので,普通のプログラムの実行では使えないんじゃないかと思います.というか,使わないで下さい.あくまで,デバッガ用です.濫用厳禁.

Debug Inspector API と関係する宣言を include/ruby/debug.h から引用します.

/* debug inspector APIs */
typedef struct rb_debug_inspector_struct rb_debug_inspector_t;
typedef VALUE (*rb_debug_inspector_func_t)(const rb_debug_inspector_t *, void *);

VALUE rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data);
VALUE rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index);
VALUE rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index);
VALUE rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index);
VALUE rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index);
VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc);

まず,利用するときは rb_debug_inspector_open() を,関数ポインタ func と共に呼び出します.rb_debug_inspector_open() は,現在のコンテキストに対応した rb_debug_inspector_t オブジェクト(ここでは,デバッグコンテキストと呼びます)を作成し,func は生成されたデバッグコンテキストへのポインタと,rb_debug_inspector_open() の第二引数 data と共に呼ばれます.

だいたい,こんな感じになります.

VALUE
func(const rb_debug_inspector_t *dc, void *data)
{
  ...
}


  ... /* デバッグしたい箇所で */
  rb_debug_inspector_open(func, some_data_ptr);
  ...

デバッグコンテキストへのポインタ dc によって,現在のフレームの情報にアクセスできます.なお,dc は func が呼び出されている間のみ有効であり,func から返った後は dc は解放されていまいますのでご注意下さい.

まずは,caller_locations を取り出しましょう.rb_debug_inspector_backtrace_locations(dc) とすれば取り出せます.これを取り出すことで,スタックフレームの深さがわかります(今思えば,サイズを返す API を用意しておけばよかった.ごめん).これで,スタックの深さが `depth' であることがわかったとします.

n フレーム目(ただし,0 <= n < depth)のフレームの情報を取り出したいときは,rb_debug_inspector_frame_???_get(dc, n) として取り出します.??? に,取り出したい情報を書き込みます.これには次の種類があります.

ただし,binding や iseq は C メソッドなどで nil である可能性があります.class は TracePoint#defined_class で取り出すクラス(モジュール)と同様に特異メソッドの場合,特異クラスを返します.

さて,これがあると色々といやらしいことができる気がしませんか.でもあんまり濫用しないで下さいね.大事なことなので繰り返しておきますが,この機能も例によって実験中ですので,あとで変わるかもしれませんし,無くなるかもしれません.フィードバック,お待ちしております.

では,今日はこの辺で.


好きなだけ長いコメントをどうぞ。

お名前


back

tton 記述が使えます。YukiWikiな記述してりゃ問題ありません。

「行頭に#code」 と、「行頭に#end」 で挟むと、その間の行は pre で囲まれます。プログラムのソースを書くときに使ってください。

例:

#code

(なんかプログラム書く)

#end

リンクは

[[なまえ|http://www.example.org]]

とか

[[http://www.example.org]]

で貼れます。

$Date: 2003/04/28 10:27:51 $