hitzhangjie / tinydbg

This repo teaches you how to build a golang debugger in golang. This repo is forked from go-delve/delve and simplified for linux/amd64.
MIT License
3 stars 0 forks source link

解释型语言的调试器只需要在解释器基础上包装下就行了 #25

Open hitzhangjie opened 2 years ago

hitzhangjie commented 2 years ago

解释型语言的调试器只需要在解释器基础上包装下就行了,实现比较简单。

因为解释器本身就是自带控制程序执行、查看进程状态的能力,不需要像编译型语言那样还要再通过调试信息标准来描述程序数据结构长啥样、应该通过哪些系统调用来读写、调用栈、行号表信息怎么获取等等,编译型语言调试器实现非常复杂。

hitzhangjie commented 2 years ago

比如python,可以sys.settrace(traceit),解释器没执行一次就触发一次traceit这个函数,只需要在函数里面处理关心的事件就可以了。

def traceit(frame: FrameType, event: str, arg: Any) -> Optional[Callable]:

Here, event is a string telling what has happened in the program – for instance,

'line' – a new line is executed
'call' – a function just has been called
'return' – a function returns
The frame argument holds the current execution frame – that is, the function and its local variables:

frame.f_lineno – the current line
frame.f_locals – the current variables (as a Python dictionary)
frame.f_code – the current code (as a Code object), with attributes such as
frame.f_code.co_name – the name of the current function

see: https://www.debuggingbook.org/beta/html/Tracer.html#:~:text=Tracing%20Python%20Programs,access%20program%20state.

hitzhangjie commented 2 years ago

这里还显示了另一种通过“代码织入” code instrucmentation 的方法来实现tracer的思路,比较适合解释型语言这种。

大致就是通过AST分析、AST重写在函数定义的Node里面塞入一个print("xxxx")之类的语句Node

hitzhangjie commented 2 years ago

对于其他的step、next、print、bt、until等功能,实际上都可以基于trace功能来实现,而这些功能解释器一般都有提供了。实现起来真的简单多了。

see:https://www.debuggingbook.org/beta/html/Debugger.html#:~:text=Help-,How%20Debuggers%20Work,learn%20how%20such%20debuggers%20work%20%E2%80%93%20by%20building%20your%20own%20debugger.,-from%20bookutils%20import

文末最后提到了time travel debugger的实现,最差的就是记录每一行语句或者分支执行时全部变量的变化,但是这种耗内存多,可以只记录变化。这里只是个简单的练习,要想真的做到这种程度,还是参考下mozilla rr的记录方案,那才叫一个全面。