2012-09-04 62 views
16

如果我正確理解這一點,那麼當發生錯誤時,Lua默認會調用調試庫「debug.traceback」。從嵌入lua的C代碼打印堆棧跟蹤

然而,嵌入的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堆棧跟蹤初始誤差後?

+2

在Lua 5.2中,你可以使用luaL_traceback。 – lhf

回答

14

當出現錯誤時,Lua默認會調用調試庫「debug.traceback」。

不,它不會。 Lua 運行時(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; 
} 
+2

謝謝,不是一個完整的答案。但是我擡頭看了lua.c,並且給出瞭如何實際使用追蹤功能的全貌。 – Matt

+0

爲了擴展C棧,需要大量特定於平臺的細節,但當然可以完成。如果符號可用於可執行文件,它顯然會工作得最好。 [這個問題](http://stackoverflow.com/questions/105659/how-can-one-grab-a-stack-trace-in-c)提供了一堆方法來做C端。將結果字符串化並將其標記爲'debug.traceback'的結果是一個直接的問題。 – RBerteig

9

工作過尼科爾的回答上面這裏是一個工作示例:

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); 
    } 
} 
+1

好的答案,**注意**新的lua版本有'lua_getglobal'因此需要使用'lua_getglobal(L,「debug」);' –

+0

如果這個函數在後面打印出「null」,我做錯了什麼? – PaulD

2

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; 
} 
+1

你還是錯了,[lua_pop](http://www.lua.org/manual/5.1/manual.html#lua_pop)從堆棧中彈出n個元素。你應該使用[lua_remove](http://www.lua.org/manual/5.1/manual.html#lua_remove) – xpol

5

我遇見有些問題和我一樣,我發現這種方式工作:

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

因爲luaL_traceback正好是debug.traceback()用於打印堆棧,所以我認爲這可能是一個合適的方法,你可以閱讀關於luaL_traceback的API手冊,或者閱讀Lua的源代碼來弄清楚params的含義。

+0

似乎這個函數在Lua 5.1中不存在,這是我必須使用的版本。太糟糕了。我也沒有將調試庫加載到在嵌入式設備上運行的Lua狀態。 – Marko