如何在Lua中使用标准钩子实现断点?
这个问题受到《Lua编程》(第四版)264页上练习25.7的启发,更具体地说,是提示中提出的优化(我在下面的引文中加重了它):
练习25.7:编写一个断点库。它应该提供至少两个函数
setbreakpoint(function, line) --> 返回句柄
removebreakpoint(handle)
我们用一个函数和一个该函数内的行来指定断点。当程序命中断点时,库应调用
debug.debug
。(提示:对于基本实现,使用一行钩子来检查是否在断点内;为了提高性能,使用调用钩子来跟踪程序执行,并仅在程序运行目标函数时打开行钩子。)
我无法弄清楚如何实现提示中描述的优化。
考虑以下代码(当然,这只是为了本问题而人为制造的人造例子):
function tweedledum ()
while true do
local ticket = math.random(1000)
if ticket % 5 == 0 then tweedledee() end
if ticket % 17 == 0 then break end
end
end
function tweedledee ()
while true do
local ticket = math.random(1000)
if ticket % 5 == 0 then tweedledum() end
if ticket % 17 == 0 then break end
end
end
function main ()
tweedledum()
end
函数main
应该代表程序的入口点。函数tweedledum
和tweedledee
几乎相同,并且几乎仅仅是反复调用彼此。
假设我在tweedledum
的赋值行上设置了断点。我可以实现一个调用钩子,可以检查是否已调用tweedledum
,然后设置一个行钩子,该行钩子将在调用所需行时检查1。
很可能tweedledum
在中断循环之前会调用tweedledee
。假设发生这种情况。当前启用的行钩子可以检测到不再在tweedledum
中,并重新安装调用钩子。
此时,执行可以以两种方式之一从tweedledee
切换到tweedledum
:
tweedledee
可以再次调用tweedledum
;tweedledee
可以_返回_其调用者,该调用者恰好是tweedledum
。
_问题在于:_调用钩子可以检测到事件(1)中的事件,但无法检测到事件(2)中的事件。
当然,这个例子非常人为,但它是我能想到的说明问题的最简单的方法。
我能想到的最好方法(非常弱!)是在第一次调用tweedledum
时跟踪堆栈深度N
,只有当堆栈深度下降到N
以下时,行钩子才重新安装调用钩子。因此,只要tweedledee
在堆栈中,无论它是否正在执行,行钩子都将生效。
是否有可能仅使用Lua中可用的标准钩子来实现提示中描述的优化2?
1 我的理解是,通过安装行钩子,调用钩子本质上卸载了它自己。AFAICT,每个协程只能有一个活动钩子。**如果我错了,请正确我。**
2 即:调用、行、返回和计数钩子。
原文链接 https://stackoverflow.com/questions/57289019
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
以下是翻译后的中文,保留了原本的 markdown 格式:
你的想法不对:其实有三种不同的钩子事件:
l
表示行,c
表示函数调用,r
表示函数返回。在钩子函数中,你可以把 return 和 call 事件看作几乎是一样的,唯一的不同就是当
return
事件触发时,你仍然在被调用的函数内部,这时目标函数在堆栈中会高出一层。debug.sethook(function(event, line) if event == "call" or event == "return" then if debug.getinfo(event=='call' and 2 or 3).func == target then debug.sethook(debug.gethook(), 'crl') else debug.sethook(debug.gethook(), 'cr') end elseif event == 'line' then -- 检查是否是正确的行,并在此处可能调用 debug.debug() end end, 'cr')
所有的细节都在手册中有说明 ;)
请注意,在设置钩子时,你可能需要检查当前是否在目标函数内部;否则你可能会错过一个断点,除非你在到达它之前调用(并返回)另一个函数。