このページの内容

4.7 – デバッグインターフェース

Luaには組み込みのデバッグ機能がありません。その代わり、関数とフックによる特別なインターフェースを提供します。このインターフェースを使うと、インタープリターの「内部情報」を必要とする各種デバッガー、プロファイラー、そのほかのツールを構築できます。


lua_Debug

typedef struct lua_Debug {
  int event;
  const char *name;           /* (n) */
  const char *namewhat;       /* (n) */
  const char *what;           /* (S) */
  const char *source;         /* (S) */
  size_t srclen;              /* (S) */
  int currentline;            /* (l) */
  int linedefined;            /* (S) */
  int lastlinedefined;        /* (S) */
  unsigned char nups;         /* (u) number of upvalues */
  unsigned char nparams;      /* (u) number of parameters */
  char isvararg;              /* (u) */
  unsigned char extraargs;    /* (t) number of extra arguments */
  char istailcall;            /* (t) */
  int ftransfer;              /* (r) index of first value transferred */
  int ntransfer;              /* (r) number of transferred values */
  char short_src[LUA_IDSIZE]; /* (S) */
  /* private part */
  other fields
} lua_Debug;

関数やアクティベーションレコードに関するさまざまな情報を運ぶ構造体です。lua_getstackは、後で利用するため、この構造体の非公開部分だけを設定します。lua_Debugのほかのフィールドへ有用な情報を設定するには、適切な引数を指定してlua_getinfoを呼び出す必要があります。具体的には、あるフィールドを取得するには、そのフィールドのコメント内で括弧に囲まれた文字をlua_getinfowhat引数へ追加します。

lua_Debugの各フィールドには、次の意味があります。

  • source: 関数を作成したチャンクのソースです。sourceが「@」で始まる場合、その関数は「@」に続く名前のファイルで定義されています。sourceが「=」で始まる場合、残りの内容が利用者定義の方法でソースを表します。それ以外の場合、関数は文字列内で定義されており、sourceがその文字列です。
  • srclen: 文字列sourceの長さです。
  • short_src: エラーメッセージで使う、sourceの「表示可能な」版です。
  • linedefined: 関数定義が始まる行番号です。
  • lastlinedefined: 関数定義が終わる行番号です。
  • what: Lua関数なら"Lua"、C関数なら"C"、チャンクの本体部分なら"main"となる文字列です。
  • currentline: 指定した関数が現在実行している行です。行情報がない場合、currentlineには-1が設定されます。
  • name: 指定した関数の妥当な名前です。Luaの関数は第一級の値なので、固定された名前を持ちません。複数のグローバル変数の値になる関数もあれば、テーブルのフィールドだけに格納される関数もあります。lua_getinfo関数は、その関数がどのように呼び出されたかを調べて適切な名前を見つけます。名前が見つからない場合、nameにはNULLが設定されます。
  • namewhat: nameフィールドについて説明します。関数の呼び出し方に応じて、namewhatの値は"global""local""upvalue""field"""(空文字列)、またはそのほかの選択肢になります。他の選択肢が適用できない場合、Luaは空文字列を使います。
  • istailcall: この関数呼び出しが末尾呼び出しによるものなら真です。この場合、このレベルの呼び出し元はスタック内にありません。
  • extraargs: __callメタメソッドを通して呼び出された関数への呼び出しによって追加された引数の数です。各__callメタ値は、呼び出されるオブジェクトという追加引数を1つ加えますが、__callメタ値が連鎖することもあります。
  • nups: 関数のアップバリュー数です。
  • nparams: 関数の引数数です。C関数では常に0です。
  • isvararg: 関数が可変長引数関数なら真です。C関数では常に真です。
  • ftransfer: 「転送」される最初の値、すなわち呼び出し時の引数またはreturn時の戻り値のスタック内インデックスです。そのほかの値は連続するインデックスにあります。このインデックスを使い、lua_getlocalおよびlua_setlocalを通して値へアクセスし、変更できます。このフィールドに意味があるのは、呼び出しフックでは最初の引数を、returnフックでは返される最初の値を示す場合だけです。呼び出しフックでは、この値は常に1です。
  • ntransfer: 転送される値の数です(前項を参照)。Lua関数の呼び出しでは、この値は常にnparamsと等しくなります。

lua_gethook

[-0, +0, –]

lua_Hook lua_gethook (lua_State *L);

現在のフック関数を返します。


lua_gethookcount

[-0, +0, –]

int lua_gethookcount (lua_State *L);

現在のフックカウントを返します。


lua_gethookmask

[-0, +0, –]

int lua_gethookmask (lua_State *L);

現在のフックマスクを返します。


lua_getinfo

[-(0|1), +(0|1|2), m]

int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);

特定の関数または関数呼び出しに関する情報を取得します。

関数呼び出しの情報を取得するには、ar引数が、以前のlua_getstack呼び出しで設定されたか、フックの引数として渡された有効なアクティベーションレコードでなければなりません(lua_Hookを参照)。

関数についての情報を得るには、関数をスタックへプッシュし、what文字列を文字「>」で始めます。この場合、lua_getinfoはスタック最上部から関数をポップします。たとえば、関数fが定義された行を知るには、次のコードを書けます。

     lua_Debug ar;
     lua_getglobal(L, "f");  /* get global 'f' */
     lua_getinfo(L, ">S", &ar);
     printf("%d\n", ar.linedefined);

文字列what内の各文字は、構造体arのどのフィールドを設定するか、またはどの値をスタックへプッシュするかを選択します。これらの文字は、構造体lua_Debugの宣言でも、各フィールドに続くコメント内の括弧で示されています。

  • f: 指定したレベルで実行中の関数をスタックへプッシュします。
  • l: currentlineフィールドを設定します。
  • n: nameおよびnamewhatフィールドを設定します。
  • r: ftransferおよびntransferフィールドを設定します。
  • S: sourcesrclenshort_srclinedefinedlastlinedefinedwhatフィールドを設定します。
  • t: istailcallおよびextraargsフィールドを設定します。
  • u: nupsnparamsisvarargフィールドを設定します。
  • L: 関連するコードがある関数内の行、つまりブレークポイントを置ける行をインデックスとするテーブルをスタックへプッシュします。コードがない行には空行やコメントが含まれます。この選択肢を「f」とともに指定した場合、テーブルは関数の後にプッシュされます。メモリエラーを発生させる可能性がある選択肢はこれだけです。

この関数は、what内の無効な選択肢を知らせるために0を返します。その場合でも、有効な選択肢は正しく処理されます。


lua_getlocal

[-0, +(0|1), –]

const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);

指定したアクティベーションレコードまたは関数のローカル変数や一時値に関する情報を取得します。

前者の場合、ar引数は以前のlua_getstack呼び出しで設定されたか、フックの引数として渡された有効なアクティベーションレコードでなければなりません(lua_Hookを参照)。インデックスnは調査するローカル変数を選択します。変数のインデックスと名前について詳しくはdebug.getlocalを参照してください。

lua_getlocalは変数の値をスタックへプッシュし、その名前を返します。

後者の場合、arNULLでなければならず、調査する関数がスタック最上部になければなりません。この場合、有効な変数に関する情報がないためLua関数の引数だけが見え、値はスタックへプッシュされません。

インデックスが有効なローカル変数の数を超える場合、NULLを返し、何もプッシュしません。


lua_getstack

[-0, +0, –]

int lua_getstack (lua_State *L, int level, lua_Debug *ar);

インタープリターの実行時スタックに関する情報を取得します。

この関数は、指定したレベルで実行中の関数のアクティベーションレコードを識別する情報をlua_Debug構造体の一部へ設定します。レベル0は現在実行中の関数で、レベルn+1はレベルnを呼び出した関数です。ただし、スタックで数えない末尾呼び出しは除きます。スタックの深さを超えるレベルで呼び出すと、lua_getstackは0を返し、それ以外では1を返します。


lua_getupvalue

[-0, +(0|1), –]

const char *lua_getupvalue (lua_State *L, int funcindex, int n);

インデックスfuncindexにあるクロージャのn番目のアップバリューについて情報を取得します。アップバリューの値をスタックへプッシュし、その名前を返します。インデックスnがアップバリュー数を超える場合はNULLを返し、何もプッシュしません。

アップバリューについて詳しくはdebug.getupvalueを参照してください。


lua_Hook

typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);

デバッグフック関数の型です。

フックが呼ばれるたびに、そのar引数のeventフィールドにはフックを発生させた特定のイベントが設定されます。Luaはこれらのイベントを、LUA_HOOKCALLLUA_HOOKRETLUA_HOOKTAILCALLLUA_HOOKLINELUA_HOOKCOUNTという定数で識別します。さらに、行イベントではcurrentlineフィールドも設定されます。arのほかのフィールドの値を取得するには、フックがlua_getinfoを呼び出す必要があります。

呼び出しイベントでは、eventは通常値のLUA_HOOKCALLか、末尾呼び出しの場合のLUA_HOOKTAILCALLになります。後者では対応するreturnイベントはありません。

Luaはフックの実行中、ほかのフック呼び出しを無効にします。そのため、フックからLuaを呼び戻して関数やチャンクを実行した場合、その実行中にはフックが呼ばれません。

フック関数は継続を持てません。すなわち、非NULLのkを指定してlua_yieldklua_pcallklua_callkを呼び出すことはできません。

フック関数は次の条件でyieldできます。yieldできるのはカウントイベントと行イベントだけです。yieldするには、フック関数がnresultsを0(値なし)にしてlua_yieldを呼び出し、実行を終えなければなりません。


lua_sethook

[-0, +0, –]

void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);

デバッグフック関数を設定します。

引数fはフック関数です。maskはフックを呼び出すイベントを指定し、定数LUA_MASKCALLLUA_MASKRETLUA_MASKLINELUA_MASKCOUNTのビット単位ORで構成します。count引数に意味があるのは、マスクにLUA_MASKCOUNTが含まれる場合だけです。各イベントでは、次のようにフックが呼ばれます。

  • 呼び出しフック: インタープリターが関数を呼び出したとき、Luaが新しい関数へ入った直後に呼ばれます。
  • returnフック: インタープリターが関数から戻るとき、Luaが関数を離れる直前に呼ばれます。
  • 行フック: インタープリターがコードの新しい行を実行し始める直前、またはコード内を後方へジャンプするとき(同じ行へのジャンプも含む)に呼ばれます。このイベントは、LuaがLua関数を実行している間だけ発生します。
  • カウントフック: インタープリターがcount個の命令を実行するたびに呼ばれます。このイベントは、LuaがLua関数を実行している間だけ発生します。

maskを0に設定するとフックは無効になります。


lua_setlocal

[-(0|1), +0, –]

const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);

指定したアクティベーションレコードのローカル変数へ値を設定します。スタック最上部の値を変数へ代入してその名前を返し、値をスタックからポップします。

インデックスが有効なローカル変数の数を超える場合、NULLを返し、何もポップしません。

引数arnは関数lua_getlocalと同じですが、lua_setlocalはアクティベーションレコードだけを操作するため、arNULLにはできません。


lua_setupvalue

[-(0|1), +0, –]

const char *lua_setupvalue (lua_State *L, int funcindex, int n);

クロージャのアップバリューへ値を設定します。スタック最上部の値をアップバリューへ代入してその名前を返し、値をスタックからポップします。

インデックスnがアップバリュー数を超える場合、NULLを返し、何もポップしません。

引数funcindexnは関数lua_getupvalueと同じです。


lua_upvalueid

[-0, +0, –]

void *lua_upvalueid (lua_State *L, int funcindex, int n);

インデックスfuncindexにあるクロージャの、番号nのアップバリューに対する一意な識別子を返します。

この一意な識別子により、異なるクロージャがアップバリューを共有しているか確認できます。1つのアップバリュー、すなわち同じ外側のローカル変数へアクセスするLuaクロージャは、そのアップバリューのインデックスに対して同一の識別子を返します。

引数funcindexnは関数lua_getupvalueと同じですが、nはアップバリュー数を超えられません。


lua_upvaluejoin

[-0, +0, –]

void lua_upvaluejoin (lua_State *L, int funcindex1, int n1,
                                    int funcindex2, int n2);

インデックスfuncindex1にあるLuaクロージャのn1番目のアップバリューが、インデックスfuncindex2にあるLuaクロージャのn2番目のアップバリューを参照するようにします。