在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
Lua数据类型
CallInfo结构
Lua_State结构
C++中还原lua调用栈 Lua代码: 1 -- 2 -- This is a test lua 3 -- 4 function TestFunc(a) 5 return square(a); 6 end 7 8 TestFunc(5); C++代码:
当前c++调用栈:
lua调用栈解析:
使用c++函数来还原,实现如下: #include <cstring> #include <string> #include <vector> extern "C" { #include "lua.h" #include "lua.hpp" #include "lualib.h" #include "lauxlib.h" #include "luaconf.h" #include "lobject.h" #include "lstate.h" } const TValue luaO_nilobject_ = { NILCONSTANT }; /* corresponding test */ #define isvalid(o) ((o) != luaO_nilobject) /* value at a non-valid index */ #define NONVALIDVALUE cast(TValue *, luaO_nilobject) /* test for pseudo index */ #define ispseudo(i) ((i) <= LUA_REGISTRYINDEX) static TValue* index2addr(lua_State* L, int idx) { CallInfo* ci = L->ci; if (idx > 0) { TValue* o = ci->func + idx; api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index"); if (o >= L->top) return NONVALIDVALUE; else return o; } else if (!ispseudo(idx)) { /* negative index */ api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); return L->top + idx; } else if (idx == LUA_REGISTRYINDEX) return &G(L)->l_registry; else { /* upvalues */ idx = LUA_REGISTRYINDEX - idx; api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); if (ttislcf(ci->func)) /* light C function? */ return NONVALIDVALUE; /* it has no upvalues */ else { CClosure* func = clCvalue(ci->func); return (idx <= func->nupvalues) ? &func->upvalue[idx - 1] : NONVALIDVALUE; } } } void GetLuaTValue(lua_State* L, StkId o, int t, int ad, int count, char* szOutput) { int i = count + ad + 1; switch (t) { case LUA_TSTRING: sprintf_s(szOutput, 255, "%d[%d]: '%s'", i, ad, lua_tostring(L, i)); break; case LUA_TBOOLEAN: sprintf_s(szOutput, 255, "%d[%d]: %s", i, ad, lua_toboolean(L, i) ? "true" : "false"); break; case LUA_TNUMBER: if (ttisinteger(o)) sprintf_s(szOutput, 255, "%d[%d]: int %d", i, ad, (int)lua_tointeger(L, i)); else sprintf_s(szOutput, 255, "%d[%d]: double %lf", i, ad, lua_tonumber(L, i)); break; case LUA_TFUNCTION: if (ttislcf(o)) { sprintf_s(szOutput, 255, "%d[%d]: c 0x%p", i, ad, fvalue(o)); // lua_CFunction } else if (ttisCclosure(o)) { sprintf_s(szOutput, 255, "%d[%d]: c closure 0x%p FucAdr:0x%p", i, ad, clCvalue(o), clCvalue(o)->f); // CClosure } else if (ttisLclosure(o)) { Proto* pinfo = clLvalue(o)->p; sprintf_s(szOutput, 255, "%d[%d]: lua closure 0x%p %s[%d,%d]", i, ad, clLvalue(o), getstr(pinfo->source), pinfo->linedefined, pinfo->lastlinedefined); } break; case LUA_TTABLE: sprintf_s(szOutput, 255, "%d[%d]: table:0x%p", i, ad, hvalue(o)); break; case LUA_TLIGHTUSERDATA: sprintf_s(szOutput, 255, "%d[%d]: light userdata:0x%p", i, ad, pvalue(o)); break; case LUA_TUSERDATA: sprintf_s(szOutput, 255, "%d[%d]: full userdata:0x%p", i, ad, uvalue(o)); break; case LUA_TTHREAD: sprintf_s(szOutput, 255, "%d[%d]: thread:0x%p", i, ad, thvalue(o)); break; default: sprintf_s(szOutput, 255, "%d[%d]: %s", i, ad, lua_typename(L, t)); break; } } const char* VSDumpLuaStateTValue(lua_State* L, int n) { static char s_szBuffer[256] = { 0 }; memset(s_szBuffer, 0, 256); int ad = -1; int count = lua_gettop(L); int i = count; while (i) { if ((n < 0 ? ad : i) == n) { StkId o = index2addr(L, i); int t = (isvalid(o) ? ttnov(o) : LUA_TNONE); GetLuaTValue(L, o, t, ad, count, s_szBuffer); return s_szBuffer; } i--; ad--; } return "Lua Frame not found!"; } std::vector<std::string> VSDumpLuaState(lua_State* L) { std::vector<std::string> Msg; char szBuffer[256] = { 0 }; memset(szBuffer, 0, 256); int ad = -1; int count = lua_gettop(L); int i = count; sprintf_s(szBuffer, 255, "---------------- Lua State Dump ----------------"); Msg.push_back(szBuffer); while (i) { StkId o = index2addr(L, i); int t = (isvalid(o) ? ttnov(o) : LUA_TNONE); GetLuaTValue(L, o, t, ad, count, szBuffer); Msg.push_back(szBuffer); i--; ad--; } sprintf_s(szBuffer, 255, "---------------------------------------------"); Msg.push_back(szBuffer); return Msg; } std::vector<std::string> VSDumpLuaCallStack(lua_State* L) { std::vector<std::string> Msg; char szBuffer[256] = { 0 }; memset(szBuffer, 0, 256); sprintf_s(szBuffer, 255, "---------------- Lua Call Stack Dump ----------------"); Msg.push_back(szBuffer); CallInfo* curCi = L->ci; while (curCi != NULL) { StkId func = curCi->func; if (ttislcf(func)) { sprintf_s(szBuffer, 255, "++ CallStack: c 0x%p", fvalue(func)); // lua_CFunction } else if (ttisCclosure(func)) { sprintf_s(szBuffer, 255, "++ CallStack: c closure 0x%p FucAdr:0x%p", clCvalue(func), clCvalue(func)->f); // CClosure } else if (ttisLclosure(func)) { Proto* pinfo = clLvalue(func)->p; int linenum = pinfo->lineinfo[curCi->u.l.savedpc - pinfo->code]; sprintf_s(szBuffer, 255, "++ CallStack: lua closure 0x%p %s:%d", clLvalue(func), getstr(pinfo->source), linenum); } else { int funct = (isvalid(func) ? ttnov(func) : LUA_TNONE); sprintf_s(szBuffer, 255, "++ CallStack: %s", lua_typename(L, funct)); } Msg.push_back(szBuffer); StkId locals = ((L->top < curCi->top) ? L->top : curCi->top) - 1; int ad = -1; int count = (int)(locals - func); while (locals > func) { StkId o = locals; int t = (isvalid(o) ? ttnov(o) : LUA_TNONE); GetLuaTValue(L, o, t, ad, count, szBuffer); Msg.push_back(szBuffer); --locals; --ad; } if (curCi == &(L->base_ci)) { break; } curCi = curCi->previous; } sprintf_s(szBuffer, 255, "---------------------------------------------"); Msg.push_back(szBuffer); return Msg; }
在C++代码中(在业务逻辑或lua虚拟机里面)调用LuaCall(为以下4个函数),会导致luaD_call函数的调用,其参数StkId func为当前要执行的function(可能为LClosure、lua_CFunction或CClosure) 注:StkId即TValue*类型 例如:上面c++栈上的第4行luaD_call即为I:\\pubcode\\LuaTest\\LuaCode\\Test4.lua的LClosure(Lua闭包) /***************** lua.h *****************/ LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, lua_KContext ctx, lua_KFunction k); #define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, lua_KContext ctx, lua_KFunction k); #define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
调用关系如下: lua_pcall() / lua_pcallk() / lua_call() / lua_callk |- ... ... |-luaD_call(lua_State *L, StkId func, int nResults) |-if (!luaD_precall(L, func, nResults)) /* 返回0表示为LClosure */ 注:① 通过next_ci宏创建新的CallInfo栈帧 ② lua_CFunction或CClosure在该函数中直接执行 ③ LClosure会在该函数中参数不够时进行nil补全,为送入VM执行LClosure做好准备 |-- luaV_execute(L); /* 虚拟机执行LClosure */ |-... ... |-newframe: /* jump tag */ |-... ... |-for (;;) |-... ... |-vmcase(OP_CALL) /* call指令 */ |-if (luaD_precall(L, ra, nresults)) |---... ... |-else |---... ... |---goto newframe; |-vmcase(OP_TAILCALL) /* tailcall指令 */ |-if (luaD_precall(L, ra, nresults)) |---... ... |-else |---... ... |---goto newframe; |-... ...
Lua中还原lua调用栈 lua中的使用debug.traceback函数打印当前的lua调用栈 Lua代码: 1 -- 2 -- This is a test lua 3 -- 4 function TestFunc(a) 5 SubFunc(a); 6 end 7 8 function SubFunc(a) 9 local b = a + 100 10 print(debug.traceback()); 11 end 12 13 TestFunc(5); 输出结果如下: stack traceback: I:\pubcode\LuaTest\LuaCode/test4.lua:10: in function 'SubFunc' I:\pubcode\LuaTest\LuaCode/test4.lua:5: in function 'TestFunc' I:\pubcode\LuaTest\LuaCode/test4.lua:13: in main chunk [C]: in ?
它在c++中的绑定函数为db_traceback,db_traceback最后调用luaL_traceback函数来实现lua栈的打印 LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level) { lua_Debug ar; int top = lua_gettop(L); int last = lastlevel(L1); int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1; if (msg) lua_pushfstring(L, "%s\n", msg); luaL_checkstack(L, 10, NULL); lua_pushliteral(L, "stack traceback:"); while (lua_getstack(L1, level++, &ar)) { if (n1-- == 0) { /* too many levels? */ lua_pushliteral(L, "\n\t..."); /* add a '...' */ level = last - LEVELS2 + 1; /* and skip to last ones */ } else { lua_getinfo(L1, "Slnt", &ar); lua_pushfstring(L, "\n\t%s:", ar.short_src); if (ar.currentline > 0) lua_pushfstring(L, "%d:", ar.currentline); lua_pushliteral(L, " in "); pushfuncname(L, &ar); if (ar.istailcall) lua_pushliteral(L, "\n\t(...tail calls...)"); lua_concat(L, lua_gettop(L) - top); } } lua_concat(L, lua_gettop(L) - top); } 示例代码如下: int n = lua_gettop(L); luaL_traceback(L, L, "", 0); const char* luaCallStack = lua_tostring(L, -1); /* luaCallStack结果如下: stack traceback: [C]: in function 'square' I:\pubcode\LuaTest\LuaCode\test3.lua:18: in local 'LuaCall' I:\pubcode\LuaTest\LuaCode\test3.lua:21: in main chunk */ lua_settop(L, n); // 保持stack平衡
|
请发表评论