詳解如何實(shí)現(xiàn)Lua調(diào)試器案例
如何實(shí)現(xiàn)Lua調(diào)試器案例是本文要介紹的內(nèi)容,主要是來(lái)學(xué)習(xí)lua調(diào)試器的實(shí)現(xiàn),具體內(nèi)容的實(shí)現(xiàn)來(lái)看本文詳解。
本文簡(jiǎn)單介紹了如何實(shí)現(xiàn)一個(gè)Lua調(diào)試器,實(shí)現(xiàn)Lua調(diào)試器的目的僅僅是寄希望借此熟悉Lua源代碼。所編寫的Lua調(diào)試器功能越強(qiáng),表明你對(duì)Lua源碼越了解。
先前用lua寫過(guò)一些應(yīng)用,感覺(jué)Lua是一個(gè)很小巧的語(yǔ)言,Lua源代碼無(wú)疑是研究語(yǔ)言相關(guān)的***。“Lua雖小,五臟俱全”!為了研究Lua源代碼,就打算著手寫一個(gè)簡(jiǎn)單的Lua調(diào)試器,發(fā)現(xiàn)其中還是有些收獲的,特記錄如下。
作為一個(gè)調(diào)試器,應(yīng)該支持一些最簡(jiǎn)單而又常用的功能,比如:?jiǎn)尾礁櫋⑤敵稣{(diào)試信息、設(shè)置斷點(diǎn)等。要探索如何實(shí)現(xiàn)Lua調(diào)試器,還是帶著這些問(wèn)題去找答案吧。本文使用的開(kāi)發(fā)環(huán)境為:win7,lua 5.1.4源代碼。
1、Lua虛擬機(jī)是如何暫停的?
Lua虛擬機(jī)和普通的CPU一樣,包含兩部分:數(shù)據(jù)存儲(chǔ)區(qū)和邏輯控制區(qū)。數(shù)據(jù)存儲(chǔ)區(qū)對(duì)應(yīng)著CPU的寄存器、狀態(tài)等,在Lua中實(shí)際上就是lua_State。邏輯控制區(qū)對(duì)應(yīng)著CPU的每條指令的具體實(shí)現(xiàn)。Lua虛擬機(jī)邏輯控制區(qū)的相關(guān)的源代碼位于lvm.c中。其中,執(zhí)行Lua指令的函數(shù)為luaV_execute。
為了方便調(diào)試,函數(shù)luaV_execute在執(zhí)行每條Lua指令之前,會(huì)去查找是否存在調(diào)試鉤子(hook):存在的話,去執(zhí)行鉤子。然后,判斷Lua虛擬機(jī)的狀態(tài)是否為暫停,若是的話就返回,而不執(zhí)行當(dāng)前Lua指令。若不存在調(diào)試鉤子,則正常執(zhí)行Lua指令。
- if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
- (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
- traceexec(L, pc); // 內(nèi)部會(huì)執(zhí)行相應(yīng)的鉤子函數(shù)
- if (L->status == LUA_YIELD) { // 鉤子函數(shù)是否將狀態(tài)轉(zhuǎn)為暫停?
- L->savedpc = pc - 1;
- return; // 此處離開(kāi)函數(shù)luaV_execute,導(dǎo)致虛擬機(jī)暫停執(zhí)行
- }
- base = L->base;
- }
由此想到一個(gè)辦法可以讓Lua虛擬機(jī)暫停:
首先,設(shè)置鉤子函數(shù),可以使用函數(shù)lua_sethook來(lái)實(shí)現(xiàn)。通常Lua調(diào)試器要支持單步跟蹤,可以使用LUA_MASKLINE類型的鉤子。但是要注意的是,這個(gè)鉤子函數(shù)會(huì)在執(zhí)行一條Lua指令之前觸發(fā)。
然后,鉤子函數(shù)中修改Lua虛擬機(jī)的狀態(tài)。可以使用Lua的C函數(shù)API lua_yield。該函數(shù)只是簡(jiǎn)單的Lua虛擬機(jī)的狀態(tài)設(shè)置為L(zhǎng)UA_YIELD,這樣可以保證在執(zhí)行指令之前退出。
2、Lua虛擬機(jī)是如何繼續(xù)執(zhí)行的?
了解了Lua虛擬機(jī)是如何暫停之后,就很容易看到,可以采用如下步驟:首先,將Lua虛擬機(jī)的狀態(tài)設(shè)置為0(正常狀態(tài)),然后執(zhí)行函數(shù)luaV_execute即可。這兩步操作可以采用Lua的C函數(shù)lua_resume即可。
3、Lua調(diào)試器的其它功能該如何實(shí)現(xiàn)?
其它的一些功能,比如:獲取Lua虛擬機(jī)中的一些信息,這些還是比較容易實(shí)現(xiàn)的。因?yàn)椋坏㎜ua虛擬機(jī)暫停后,可以通過(guò)查找lua_State中的信息來(lái)查詢,具體怎么查詢,那就取決于你對(duì)lua源代碼的熟悉程度了。反正都在lua_State里面,可以直接獲取的。
4、Lua調(diào)試器究竟該怎么實(shí)現(xiàn)?
考慮到,調(diào)試器可能是命令行版本的,也可能是包含界面的調(diào)試器。可以考慮將調(diào)試器作為一個(gè)庫(kù)來(lái)實(shí)現(xiàn),然后這個(gè)庫(kù)提供了一些接口,方便和前臺(tái)銜接。一下就是我封裝的一些接口,僅供參考:
- ECode luad_init(const char * filename);
- ECode luad_command_step(int * pErr);
- ECode luad_command_go(int * pErr);
- ECode luad_command_bk(int line);
- ECode luad_command_bkinfo(int ** ppBklines, int * pNum);
- int luad_currentline();
- Boolean luad_is_script_ended();
這個(gè)庫(kù)加上前段的命令輸入控制,就很容易做出一個(gè)命令行版的Lua調(diào)試器了。同理,做界面版的也很容易。下面是我寫的Lua調(diào)試器命令行版運(yùn)行截圖。
小結(jié):詳解如何實(shí)現(xiàn)Lua調(diào)試器案例的內(nèi)容介紹完了,希望通過(guò)本文的學(xué)習(xí)能對(duì)你有所幫助!
























