探究Lua Debug库实现简单的本地调试

简介

在网上有各种各样的调试库,比如MobDebug或者RemDebug等等,自己也想实现类似的功能,以便更好的自定义改造。

工具准备:

1、ZeroBraneSutdio

debug库介绍

这里将介绍常见的debug命令:

函数 简介
                  debug()                   进入一个用户交互模式,简单的来讲就是会等待用户的输入,lua程序处于阻塞状态,在这个时候可以执行一些lua的语法,比如调用方法,和运算等等,当输入"cont"后才会结束阻塞状态。
                 sethook ([thread,] hook, mask [, count])                  将一个函数作为钩子函数设入。 字符串 mask 以及数字 count 决定了钩子将在何时调用。 掩码是由下列字符组合成的字符串,每个字符有其含义:
'c': 每当 Lua 调用一个函数时,调用钩子;
'r': 每当 Lua 从一个函数内返回时,调用钩子;
'l': 每当 Lua 进入新的一行时,调用钩子。
                 getinfo ([thread,] f [, what])                   返回关于一个函数信息的表。 你可以直接提供该函数, 也可以用一个数字 f 表示该函数。 数字 f 表示运行在指定线程的调用栈对应层次上的函数: 0 层表示当前函数(getinfo 自身); 1 层表示调用 getinfo 的函数 (除非是尾调用,这种情况不计入栈);等等。 如果 f 是一个比活动函数数量还大的数字, getinfo 返回 nil。
getlocal ([thread,] f, local) 此函数返回在栈的 f 层处函数的索引为 local 的局部变量 的名字和值。 这个函数不仅用于访问显式定义的局部变量,也包括形参、临时变量等。

更多的命令详情可以查看菜鸟教程:https://www.runoob.com/lua/lua-debug.html

编码-API的使用

debug库的api使用

1. debug()
利用debug()函数可以实程序的阻塞

print("aaa")
debug.debug()  --进入用户交互状态,阻塞
print("bbb")

function add(a,b)
  return a+b
end

运行的结果:

> aaa
>

在交互模式下,可以执行lua语句,比如方法调用

> add(1,2)
> 3

使用"cont"命令,可以让程序继续往下运行

> cont
> bbb

2. sethook ([thread,] hook, mask [, count])
sethook函数可以实现程序运行的监听:
'c': 每当 Lua 调用一个函数时,调用钩子;
'r': 每当 Lua 从一个函数内返回时,调用钩子;
'l': 每当 Lua 进入新的一行时,调用钩子。

1 function hook(event,line)  
2  print(event,line)   --打印行号
3 end
4 debug.sethook(hook,"l")
5 local a = 10
6 local b = 20
7 print(a+b)

运行结果:hook函数打印了每个被执行代码的行号。"l"参数每运行一段新的代码时会被hook,从而调用hook函数

> line 5
> line 6
> line 7
> 30

其余的参数 "c"、"r"不再进行演示了,详细的介绍如上

3. getinfo ([thread,] f [, what])
这个函数用处很多,可以获取到一些信息,方法信息、文件信息等,这里较为复杂的可能是 f 这个参数了, 0 层表示当前函数(getinfo 自身); 1 层表示调用 getinfo 的函数 ,以此类推,具体效果可以写个demo进行试验

local table_info = debug.getinfo(1)
for k,v in pairs(table_info) do
  print(k,v)
end

输出结果:

linedefined 0  --函数定义的起始和结束行号
currentline 1  --上级(level - 1)函数被调用的行号
func    function: 0x00021cd0  --函数本身
isvararg    true  --参数是否有可变长参数
namewhat   --函数类型(field, upvalue, global)
lastlinedefined 5 --函数定义的起始和结束行号
source  @D:\Work_Home\ZB_Work\myTest.lua --指代函数定义的位置,如果函数是在文件中定义的,source就是这个文件路径前加"@"
nups    0  -- 函数的upvalue值的个数
what    main --函数类型(Lua, C, main)
nparams 0  --函数参数个数
short_src   --D:\Work_Home\ZB_Work\myTest.lua -- 是source的短版本,不超过60字符

4. getlocal ([thread,] f, local)
这个方法可以用于获取栈中变量的值, f 层处函数的索引为 local 的局部变量的名字和值

local a = 10
local b = 20

local i = 1
repeat
  local k,v = debug.getlocal(1,i)  --获取值
  print(k,v)
  i = i + 1
until not k

输出结果

> a   10
> b   20
> i   3
> nil   nil

编码-整合

使用上面介绍的api可以实现一个简单的单步调试功能的调试器

1   local model_step = 1
2   local model_over = 2
3   local model = model_step
4   local breakList={}
5  
6   local vkList={}
7  
8   function saveValues() --保存值
9   local i = 5
10  repeat
11    local k,v = debug.getlocal(3,i)
12    if k ~= "(*temporary)" and k~=nil then
13      vkList[k] = v
14    end
15    i = i+1
16  until not k
17  end
18
19  function watch(key)  --查看值
20    print(vkList[key])
21  end
22
23  function hook(event,line)
24    print("current at line:",line)
25    saveValues(line) --保存输出当前值
26    if(model == model_step) then
27      --单步
28      debug.debug() --实现单步调试效果,进入交互状态(阻塞)
29    else
30    --步过
31      if(breakList[line] ~= nil) then
32         debug.debug() --实现单步调试效果,进入交互状态(阻塞)
33      end
34    end
35  end
36
37  function addBreakpoint(line)  --添加断点
38    breakList[line] = line
39  end
40
41  function removeBreakpoint(line)  --移除断点
42    breakList[line] = nil
43  end
44
45  function step() --单步
46    model = model_step
47  end
48
49  function over() --步过
50  model = model_over
51  end
52  debug.sethook(hook,"l")
53
54  local a = 10  --被调试程序
55  local b = 20
56
57  function add(a,b) 
58  return a+b
59  end
60
61  local result = add(a,b)
62  print(result)

运行结果:

> current at line:  54
> lua_debug> addBreakpoint(58)  --58行添加断点
> lua_debug> cont  --结束debug()函数的阻塞
> current at line:  55
> lua_debug> watch("a")  --查看值
> 10
> lua_debug> over()  --进入步过模式
> lua_debug> cont  
> current at line:  59
> current at line:  57
> current at line:  61
> current at line:  58
> lua_debug> step()  --进入单步模式
> lua_debug> cont
> current at line:  62
> lua_debug> cont
> 30
> Program completed in 28.95 seconds (pid: 11404).

你可能感兴趣的:(探究Lua Debug库实现简单的本地调试)