Debugging 如何使用标准挂钩在Lua中实现断点?

Debugging 如何使用标准挂钩在Lua中实现断点?,debugging,lua,hook,breakpoints,Debugging,Lua,Hook,Breakpoints,这个问题的动机是第页练习25.7。264的Lua编程(第四版),更具体地说,是提示中提出的优化(我在下面的引文中强调了这一点): 练习25.7:编写断点库。它应该至少提供两个功能 setbreakpoint(函数,行)-->返回句柄 移除断点(句柄) 我们通过函数指定断点,并在该函数内指定一行。当程序遇到断点时,库应调用debug.debug。(提示:对于基本实现,请使用检查是否在断点中的行钩子;为了提高性能,使用调用钩子跟踪程序执行,并且仅在程序运行目标函数时启用行钩子) 我不知道如何实现提示

这个问题的动机是第页练习25.7。264的Lua编程(第四版),更具体地说,是提示中提出的优化(我在下面的引文中强调了这一点):

练习25.7:编写断点库。它应该至少提供两个功能

setbreakpoint(函数,行)-->返回句柄

移除断点(句柄)

我们通过函数指定断点,并在该函数内指定一行。当程序遇到断点时,库应调用
debug.debug
。(提示:对于基本实现,请使用检查是否在断点中的行钩子;为了提高性能,使用调用钩子跟踪程序执行,并且仅在程序运行目标函数时启用行钩子

我不知道如何实现提示中描述的优化

考虑以下代码(当然,这是一个仅为解决此问题而编造的人工示例):

函数
main
应该表示程序的入口点。函数
tweedledum
tweedledum
几乎彼此相同,只不过是重复调用彼此

假设我在tweedledum的赋值行上设置了一个断点。我可以实现一个调用钩子,它可以检查
tweedledum
是否已被调用,然后设置一个行钩子,该钩子将在调用所需的行时进行检查1

更有可能的是,
tweedledum
会在它脱离循环之前调用
tweedledee
。假设发生了这种情况。当前启用的线路挂钩可以检测到它不再位于tweedledum中,然后重新安装呼叫挂钩

此时,执行可以通过以下两种方式之一从
tweedledee
切换到
tweedledem

  • tweedledee
    可以调用
    tweedledum
    (再次)
  • tweedledee
    可以返回其调用程序,该调用程序恰好是
    tweedledem
  • 问题是:调用挂钩可以检测(1)中的事件,但无法检测(2)中的事件

    诚然,这个例子是非常人为的,但这是我能想出的最简单的方法来说明这个问题

    我能想到的最好的方法(它非常弱!)是在第一次调用
    tweedledum
    时跟踪堆栈深度
    N
    ,只有当堆栈深度下降到
    N
    以下时,才让行钩子重新安装调用钩子。因此,只要
    tweedledee
    在堆栈中,无论是否执行,行钩子都将有效

    是否可以仅使用Lua?2中可用的标准挂钩来实现提示中描述的优化


    1我的理解是,通过安装line钩子,调用钩子实际上是卸载自己。目前,每个协同程序只能有一个钩子处于活动状态如果我错了,请纠正我。

    2即:呼叫、连线、返回和计数挂钩

    问题是:调用挂钩可以检测(1)中的事件,但无法检测(2)中的事件

    这就是你错的地方:有三个可能的钩子事件:
    l
    表示行,
    c
    表示调用,
    r
    表示返回

    在钩子函数中,您可以将return和call事件视为几乎相同的事件,除非触发
    return
    事件时,您仍然在被调用函数中,因此目标函数在堆栈中的位置较高

    debug.sethook(函数(事件,行)
    如果事件==“调用”或事件==“返回”,则
    如果debug.getinfo(event='call'和2或3).func==target,则
    debug.sethook(debug.gethook(),'crl')
    其他的
    debug.sethook(debug.gethook(),'cr')
    结束
    elseif事件=='行',然后
    --检查行是否正确,并可能在此处调用debug.debug()
    结束
    (完"cr")
    
    一切都在……里



    注意,在设置钩子时,您可能需要检查当前是否在目标函数中;否则,除非在到达断点之前调用(并从中返回)另一个函数,否则您可能会跳过断点。

    谢谢。作为一个初学者,我发现这本手册几乎毫无用处:它是为那些已经理解它所描述的概念的人编写的,因此它可能是有用的参考,但不是学习这些东西的方法。无论如何,对我来说不是。我唯一能弄明白手册中所说的某些东西是什么意思的方法就是通过实验。而且很多。例如,我发现一次只能有一个钩子处于活动状态。你的帖子是我第一次看到可以将指标“l”、“c”和“r”组合在一起。同样,如果你已经知道,这一点很明显,但不是别的。”字符串掩码可能包含以下字符的任意组合,具有给定的含义“同样,所有内容都在手册中;)但是,是的,这是一个参考,不是一个指南。Lua编程正是第一次学习该语言的合适资源,但我强烈建议大家还是要习惯参考资料;这很完整,但你必须注意每一个字。是的,在我读了你的帖子后,我回去看了。我是第一次读到这本书的。原因如下:在PIL中的所有
    sethook
    示例中,作者从未对该参数使用过多个字符,这使人认为这是一个单字符参数。Q:如果将
    elseif事件=='line'
    替换为普通的
    else
    ,会发生什么,我只是认为它清楚地说明了“其他”是什么。此外,还可能发生“计数”事件,因此使用显式的
    elseif
    更能证明未来。顺便说一句,因为我看到你问了很多与Lua相关的问题
     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