【问题标题】:Print stacktrace from C code with embedded lua使用嵌入式 lua 从 C 代码打印堆栈跟踪
【发布时间】:2012-08-28 16:45:28
【问题描述】:

如果我理解正确的话,Lua 默认会在出错时调用调试库“debug.traceback”。

但是,当将 Lua 嵌入到 C 代码中时,就像这里的示例中所做的那样: Simple Lua API Example

我们只有栈顶的错误信息。

if (status) {
    /* If something went wrong, error message is at the top of */
    /* the stack */
    fprintf(stderr, "Couldn't load file: %s\n", lua_tostring(L, -1));

    /* I want to print a stacktrace here. How do I do that? */
    exit(1);
}

在初始错误后如何从 C 打印堆栈跟踪?

【问题讨论】:

  • 在 Lua 5.2 中你可以使用 luaL_traceback。

标签: lua stack-trace traceback lua-api


【解决方案1】:

Lua默认会在出错时调用调试库“debug.traceback”。

不,不会。 Lua runtime (lua.exe) 会执行此操作,但 Lua 库不会自行执行此操作。如果你想要一个包含 Lua 错误的调用堆栈,那么你需要生成一个。

Lua 运行时通过使用lua_pcall's 错误函数来做到这一点。调用错误函数时堆栈尚未展开,因此您可以在那里获得堆栈跟踪。运行时使用的错误函数是这个:

static int traceback (lua_State *L) {
  if (!lua_isstring(L, 1))  /* 'message' not a string? */
    return 1;  /* keep it intact */
  lua_getfield(L, LUA_GLOBALSINDEX, "debug");
  if (!lua_istable(L, -1)) {
    lua_pop(L, 1);
    return 1;
  }
  lua_getfield(L, -1, "traceback");
  if (!lua_isfunction(L, -1)) {
    lua_pop(L, 2);
    return 1;
  }
  lua_pushvalue(L, 1);  /* pass error message */
  lua_pushinteger(L, 2);  /* skip this function and traceback */
  lua_call(L, 2, 1);  /* call debug.traceback */
  return 1;
}

【讨论】:

  • 谢谢,这不是一个完整的答案。但是我查阅了 lua.c,它给出了如何实际使用 traceback 函数的全貌。
  • 扩展它以遍历 C 堆栈需要很多特定于平台的细节,但肯定可以做到。如果符号可用于可执行文件,显然效果最好。 This question 提供了一堆做 C 端的方法。将结果字符串化并将其标记到 debug.traceback 的结果上是一个简单的问题。
【解决方案2】:

上面的 Nicol 回答是一个工作示例:

static int traceback(lua_State *L) {
    lua_getfield(L, LUA_GLOBALSINDEX, "debug");
    lua_getfield(L, -1, "traceback");
    lua_pushvalue(L, 1);
    lua_pushinteger(L, 2);
    lua_call(L, 2, 1);
    fprintf(stderr, "%s\n", lua_tostring(L, -1));
    return 1;
}

int main(int argc, char **argv) {
    lua_State *L = lua_open();
    luaL_openlibs(L);    
    lua_pushcfunction(L, traceback);
    int rv = luaL_loadfile(L, "src/main.lua");
    if (rv) {
        fprintf(stderr, "%s\n", lua_tostring(L, -1));
        return rv;
    } else {
        return lua_pcall(L, 0, 0, lua_gettop(L) - 1);
    }
}

【讨论】:

  • 好答案,注意较新的lua版本有lua_getglobal所以需要使用lua_getglobal(L, "debug");
  • 如果这个函数在后面打印我“null”,我做错了什么?
【解决方案3】:

mxcl的代码有问题:

static int traceback(lua_State *L) {
    lua_getfield(L, LUA_GLOBALSINDEX, "debug");
    lua_getfield(L, -1, "traceback");
    //---------------------------
    lua_pop(L,-2); //to popup the 'debug'
    //---------------------------
    lua_pushvalue(L, 1);
    lua_pushinteger(L, 2);
    lua_call(L, 2, 1);
    fprintf(stderr, "%s\n", lua_tostring(L, -1));
    return 1;
}

【讨论】:

  • 你还是错了,lua_pop 从堆栈中弹出 n 个元素。你应该使用lua_remove
【解决方案4】:

我和你一样遇到了一些问题,我发现这种方法可行:

luaL_traceback(L, L, NULL, 1);
printf("%s\n", lua_tostring(L, -1));

由于luaL_traceback正好是debug.traceback()用来打印堆栈,所以我认为这可能是一个正确的方法,你可以阅读关于luaL_traceback的API手册或者只是阅读Lua的源代码来弄清楚参数的含义。

【讨论】:

  • Lua 5.1好像没有这个功能,是我必须用的版本。太糟糕了。我也没有将调试库加载到在嵌入式设备上运行的 Lua 状态。
猜你喜欢
  • 2010-09-08
  • 2018-07-06
  • 1970-01-01
  • 1970-01-01
  • 2012-05-26
  • 2015-07-27
  • 2020-07-25
  • 2013-09-03
  • 1970-01-01
相关资源
最近更新 更多