Lua - 调试接口

  Lua - 调试接口

4 - 调试接口 The Debug Interface

Lua 没有内置的调试设施。它使用一种特殊的接口,这种接口依赖函数和 钩子(hooks)。该接口允许构造不同种类的调试器,分析器以及其他工具用以从解释器得到所需的信息。

4.1 - 堆栈及函数信息 Stack and Function Information

得到解释程序运行时堆栈信息的主要函数是:

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

这个函数用一个指定等级的函数的 activation record 的标示符填充一个 lua_Debug 结构,等级 0 是当前运行函数,然而等级 n+1 是在等级 n 上调用的函数。当没有错误发生时,lua_getstack 返回 1;当在比栈更深的等级上调用的时候,它返回 0;

lua_Debug 结构被用来携带一个处于活动状态的函数的各种信息:

      typedef struct lua_Debug {
        int event;
        const char *name;      /* (n) */
        const char *namewhat;  /* (n) `global', `local', `field', `method' */
        const char *what;      /* (S) `Lua' function, `C' function, Lua `main' */
        const char *source;    /* (S) */
        int currentline;       /* (l) */
        int nups;              /* (u) number of upvalues */
        int linedefined;       /* (S) */
        char short_src[LUA_IDSIZE]; /* (S) */

        /* private part */
        ...
      } lua_Debug;

lua_getstack 只填充结构的私有部分以备之后使用。要填充 lua_Debug 其他有用信息,调用

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

这个函数发生错误是返回 0 (举个例子,一个无效的 what 选项)。what 字符串中的每个字符选择填充一些 ar 结构的字段,把上面在 lua_Debug 定义中用圆括号括起来的字母作为指示: `S´ 填充在 source, linedefinedwhat 字段中;`l´ 填充在 currentline 字段中,等等...。而且,`f´ 将正在运?性谒燃渡系暮谷攵颜弧?

想要从一个不处于活动状态的函数那得到信息(就是不在栈上的函数),你需要将其压入栈并且用 >´ 作为 what 字符串的开始。举个例子,要知道函数 f 定义在第几行,你需要这样写

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

lua_Debug 的字段有如下的含义:

  • source 如果函数在一个字符串中定义,那么 source 就是那个字符串。如果函数定义在一个文件中,source 开始于一个 `@´ 后面跟随文件名。
  • short_src 一个可打印版的 source,用于错误信息。
  • linedefined 函数定义起始的行号。
  • what 如果这是一个Lua函数,显示 "Lua" 字符串, "C" 为C 函数,"main" 如果这是一个语句段的main部分,"tail" 如果这是一个做了尾部调用的函数。在后面的情况里,Lua 没有其他关于这个函部的信息。
  • currentline 代表当前函数执行到的行数。如果没有行信息可用,currentline 被设置为 -1
  • name 一个所给函数合理的函数名。因为函数在Lua中属于第一类值,它们没有固定的名字:一些函数可能是多个全局变量的值,其他的可能只储存在一个表字段里。lua_getinfo 函数检测函数如何被调用或者是否为一个全局变量的值以寻找一个合适的名字。如果找不到合适的名字,name 被设置为 NULL
  • namewhat name 字段的解释。根据函数如何被调用,namewhat 的值可以是 "global", "local", "method", "field" 或者 "" (空字符串)。(当没有其他可选项的时候Lua使用空字符串代替)
  • nups 函数上值的数量。

4.2 - 操作局部变量和上值 Manipulating Local Variables and Upvalues

为了更多的操作局部变量和上值,调试接口使用索引:第一个参数或者局部变量索引为 1,以此类推,直到最后一个活动的局部变量。整个函数中的活动的上值没有特定的顺序。

下面的函数允许操作一个所给激活记录的局部变量:

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

参数 ar 必须是一个被前一个 lua_getstack 调用填充的有效的激活记录或者作为一个钩子函数的参数(见 4.3)。lua_getlocal 获得一个局部变量的索引 n,将变量的值压入栈,并且返回变量名。lua_setlocal 从栈顶分配一个值给变量并且返回变量名。当索引超过活动的局部变量的数量时,两个函数都返回 NULL

以下的函部可以操作所给函数的上值(不像局部变量,函数的上值即使在函数不处于活动状态的时候都可以被访问):

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

这些函数可以作为Lua 函数使用也可以作为C 函数使用。(作为Lua 函数,上值是函数外部使用的局部变量,因此它被包含在函数闭包中。)funcindex 指向栈中的一个函数。lua_getupvalue 得到一个上值的索引 n,将上值的值压入栈,并返回其变量名。lua_setupvalue 从栈顶分配一个值给上值并返回变量名。当索引大于上值数量时,两个函数都返回 NULL。对于C 函数来说,这些函数使用空字符串作为所有上值的变量名。

作为一个例子,下面的函数列举了所给等级的栈中的函数的所有局部变量名和上值变量名:

       int listvars (lua_State *L, int level) {
         lua_Debug ar;
         int i;
         const char *name;
         if (lua_getstack(L, level, &ar) == 0)
           return 0;  /* failure: no such level in the stack */
         i = 1;
         while ((name = lua_getlocal(L, &ar, i++)) != NULL) {
           printf("local %d %s/n", i-1, name);
           lua_pop(L, 1);  /* remove variable value */
         }
         lua_getinfo(L, "f", &ar);  /* retrieves function */
         i = 1;
         while ((name = lua_getupvalue(L, -1, i++)) != NULL) {
           printf("upvalue %d %s/n", i-1, name);
           lua_pop(L, 1);  /* remove upvalue value */
         }
         return 1;
       }

4.3 - 钩子 Hooks

Lua offers a mechanism of hooks, which are user-defined C functions that are called during the program execution. A hook may be called in four different events: a call event, when Lua calls a function; a return event, when Lua returns from a function; a line event, when Lua starts executing a new line of code; and a count event, which happens every "count" instructions. Lua identifies these events with the following constants: LUA_HOOKCALL, LUA_HOOKRET (or LUA_HOOKTAILRET, see below), LUA_HOOKLINE, and LUA_HOOKCOUNT.

A hook has type lua_Hook, defined as follows:

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

You can set the hook with the following function:

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

func is the hook. mask specifies on which events the hook will be called: It is formed by a disjunction of the constants LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE, and LUA_MASKCOUNT. The count argument is only meaningful when the mask includes LUA_MASKCOUNT. For each event, the hook is called as explained below:

  • The call hook is called when the interpreter calls a function. The hook is called just after Lua enters the new function.
  • The return hook is called when the interpreter returns from a function. The hook is called just before Lua leaves the function.
  • The line hook is called when the interpreter is about to start the execution of a new line of code, or when it jumps back in the code (even to the same line). (This event only happens while Lua is executing a Lua function.)
  • The count hook is called after the interpreter executes every count instructions. (This event only happens while Lua is executing a Lua function.)

A hook is disabled by setting mask to zero.

You can get the current hook, the current mask, and the current count with the following functions:

       lua_Hook lua_gethook      (lua_State *L);
       int      lua_gethookmask  (lua_State *L);
       int      lua_gethookcount (lua_State *L);

Whenever a hook is called, its ar argument has its field event set to the specific event that triggered the hook. Moreover, for line events, the field currentline is also set. To get the value of any other field in ar, the hook must call lua_getinfo. For return events, event may be LUA_HOOKRET, the normal value, or LUA_HOOKTAILRET. In the latter case, Lua is simulating a return from a function that did a tail call; in this case, it is useless to call lua_getinfo.

While Lua is running a hook, it disables other calls to hooks. Therefore, if a hook calls back Lua to execute a function or a chunk, that execution occurs without any calls to hooks.

你可能感兴趣的:(lua,function,string,table,hook,character)