实现一个lua 调试器

本文介绍了如何实现一个基于LUA调试库的调试器,支持包括继续运行、单步执行等功能。通过debug.sethook设置钩子函数,实现行级、函数调用和返回时的调试中断。在遇到效率问题时,通过修改LUA源代码添加获取调用栈深度的函数。文章还提供了C/C++层读取指定文件和行的函数,并给出了调试器的使用方法和debug.lua脚本示例。
摘要由CSDN通过智能技术生成

简介:
  LUA没有自带调试器,只提供了一套调试库,可以实现符合自己需要的调试器.晚上没事,改写了一下以前的一个GDB风格的LUA调试器,可嵌入到应用程序中,在需要的时候触发并调试,有需要的朋友可以参考下. 支持如下命令:
    h             帮助信息
    c             继续动行
    s             单步运行(不跳过函数调用)
    n             单步运行(跳过函数调用)
    p var         打印变量值
    b src:line    添加断点,注意src要写文件的绝对路径,例如 b script/main.lua:22
    d num         删除断点
    bl            列出所有断点
    be num        启用一个断点
    bd num        禁用一个断点
    bt            打印调用栈
   
实现:
    LUA支持用debug.sethook设置三种Hook:
    一,每行代码执行时调用Hook函数
    二,每个函数调用时执行Hook函数
    三,每个函数返回时调用Hook函数
    在Hook函数中,可以通过调用debug.getinfo得到当前LUA文件名,当前所执行代码的行号.所以,要实现针对行下断点,一个显尔易见的办法就是在每个HOOK中判断当前文件和当前行号是否是一个断点,是的话就中断下来(调用io.read()来等待输入).这样当然会比较慢,因为每行代码执行时都会去调用HOOK函数,但LUA一般是用来做逻辑而不是算术密集的操作,而且一般只是在开发期调试会使用hook,所以绝大部分情况下是足够用了.特殊情况下有效率要求时,可以使用下文介绍的另一种办法.
    但在实际开发中碰到了个问题:如何实现n命令(单步运行,跳过函数调用),LUA的HOOK是每行代码都会触发,可以取得当前函数,所以单步运行时很容易知道是不是进入了一个新函数,但是如何在进入这个函数时不中断,在调用完成时才中断?最直观的想法是在n命令碰到函数时,自动在函数调用的下一行加入断点并运行.但是实际情况要复杂得多,比如函数调用下一行是空行,函数调用当前行有return,比如:
    if ( foo() ) return end
    这样就要写很多代码分析的代码来保证正确性,逻辑就写复杂了,放弃这种做法.
    另一种想法是下函数执行hook和函数返回hook,执行hook触发时增量某个变量,返回hook扫许时减量某个变量,这样变量为0时就是返回到调用函数了(调用栈平衡),但是程序逻辑也变得复杂了,放弃这种做法.
    最直观的办法是检查调用栈深度,因为被调用函数返回时,调用栈深度总是不会变的.但是LUA debug库没有检查调用栈深度的函数,还好LUA是开源的,动手加一个即可.最后的代码见下面,如有更简单的办法请告之:
   
    在lua(5.1.4)源代码文件 ldblib.c中添加返回调用栈深度的函数:
  static int db_traceback_count (lua_State *L) {
    lua_Debug ar;
    int index = 1;
    while (lua_getstack(L, index, &ar))
          index++;
    lua_pushnumber( L, index - 1 );
    return 1;
  }
  在static const luaL_Reg dblib[] 数组中添加一行函数注册:
  {"traceback_count", db_traceback_count},
  
  重新编译LUA.
  为了像GDB一样在单步调试时能显示当前源代码,在C/C++层注册一个读取指定文件指定行的函数:
int get_file_line( lua_State *L )
{
        const char *file = luaL_checkstring( L, 1 );
        int line = lua_tonumber( L, 2 );
        if ( line < 1 ) line = 1;

        int n = 1;
        char src[2046];
        FILE *f = fopen( file, "r" );
        if ( f )
        {
                while ( fgets( src, 2046, f ) )
                {
                        if ( n == line )
                        {
                   

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值