• 一个简陋的lua调试器


    lua没有提供专门的调试器,但却提供了一些接口函数,用以实现你自己的调试器。

    下面实现了一个简单的基于命令行的lua调试器,提供一些最最基本的调试功能。

    这里面只用到了3个基本的lua调试函数,debug.sethook,debug.getlocal,debug.getinfo.

    函数的具体用法和功能可以参照lua手册。

    下面是简单的实现代码:

    Command.h

    #ifndef _COMMAND_H
    #define _COMMAND_H
    /*命令定义说明
    命令 参数
    start   filename         :启动执行一个lua文件
    list/l  filename         :显示文件内容
    break/b filename:lineno  :在filename的lineno设置断点
    step/s                   :单步执行
    continue/c               :继续运行
    exit/e                   :退出调试器
    stop                     :停止调试
    print/p variable         :打印变量值
    */
    
    class CommandLine;
    //命令基类
    class Command
    {
    public:
        Command(){}
        virtual bool Execute(bool callfromlua) = 0;//执行命令
    };
    
    class CommandStart : public Command
    {
    public:
        CommandStart(char *para):para(para){}
        bool Execute(bool callfromlua);
    private:
        char *para;//命令的参数
    };
    class CommandExit : public Command
    {
    public:
        CommandExit(){}
        bool Execute(bool callfromlua);
    };
    class CommandBreak : public Command
    {
    public:
        CommandBreak(char *para):para(para){}
        bool Execute(bool callfromlua);
    private:
        char *para;//命令的参数
    };
    
    class CommandStep : public Command
    {
    public:
        CommandStep(){}
        bool Execute(bool callfromlua);
    };
    
    class CommandContinue : public Command
    {
    public:
        CommandContinue(){}
        bool Execute(bool callfromlua);
    };
    class CommandPrint : public Command
    {
    public:
        CommandPrint(char *valname):valname(valname){}
        bool Execute(bool callfromlua);
    private:
        char *valname;
    };
    
    class CommandFactory
    {
    public:
        static Command *CreateCommand(char *commandline);
    };
    
    #endif

    command.cpp

    #include "stdafx.h"
    #include "command.h"
    #include "commandline.h"
    
    extern lua_State *L;
    bool CommandStart::Execute(bool callfromlua)
    {
        if(CommandLine::isrunning)
        {
            printf("程序已经在运行/n");
            return true;
        }
        
        CommandLine::isrunning = true;
        //执行lua文件
        if (luaL_dofile(L, para)) {
            const char * error = lua_tostring(L, -1);
            lua_pop(L,1);
        }
        CommandLine::isrunning = false;
        printf("程序终止/n");
        return true;
    }
    
    bool CommandBreak::Execute(bool callfromlua)
    {
        const char *filename = strtok(para,":");
        const char *line = strtok(NULL,":");
        if(!filename || !line)
        {
            printf("断点输入不正确/n");
            return true;
        }
        int lineno = atol(line);
        CommandLine::InsertBreakPoint(filename,lineno);
        return true;
    }
    
    bool CommandStep::Execute(bool callfromlua)
    {
        if(!CommandLine::isrunning)
        {
            printf("请先运行程序/n");
            return true;
        }
        CommandLine::setpState = true;
        return false;
    }
    bool CommandContinue::Execute(bool callfromlua)
    {
        CommandLine::setpState = false;
        if(callfromlua)
            return false;
        return true;
    }
    
    bool CommandExit::Execute(bool callfromlua)
    {
        printf("你确定要退出调试器吗?(y:是,n:否)");
        int c = getchar();
        if( c == 'y' || c == 'Y')
            exit(0);
        return false;
    }
    bool CommandPrint::Execute(bool callfromlua)
    {
        lua_getglobal(L,"printlocal");
        lua_pushstring(L,valname);
        if(lua_pcall(L, 1, 0, 0) != 0)
        {
            const char *error = lua_tostring(L,-1);
            printf("%s/n",error);
            lua_pop(L,1);
        }
        return true;
    }
    
    Command *CommandFactory::CreateCommand(char *commandline)
    {
        char *cmd = strtok(commandline," ");
        if(!cmd || strcmp("",cmd) == 0)
            return NULL;
        if(strcmp("start",cmd) == 0)
        {
            char *para = strtok(NULL," ");
            return new CommandStart(para);
        }
        else if(strcmp("exit",cmd) == 0 || strcmp("e",cmd) == 0)
        {
            return new CommandExit();
        }
        else if(strcmp("break",cmd) == 0 || strcmp("b",cmd) == 0)
        {
            char *para = strtok(NULL," ");
            return new CommandBreak(para);
        }
        else if(strcmp("step",cmd) == 0 || strcmp("s",cmd) == 0)
        {
            return new CommandStep();
        }
        else if(strcmp("continue",cmd) == 0 || strcmp("c",cmd) == 0)
        {
            return new CommandContinue();
        }
        else if(strcmp("print",cmd) == 0 || strcmp("p",cmd) == 0)
        {
            char *para = strtok(NULL," ");
            return new CommandPrint(para);
        }
        return NULL;
    }

    Commandline.h

    //命令行处理
    #ifndef _COMMANDLINE_H
    #define _COMMANDLINE_H
    extern "C"
    {
        #include "lua.h"
        #include "lauxlib.h"
        #include "lualib.h"
    }
    #include <string>
    #include <map>
    #include <list>
    
    class CommandLine
    {
    public:
        static void Init();
        //等待用户的命令输入
        static void Wait4Command(bool fromlua = false);
        static char *GetInput();
        //列出所有断点
        static std::list<std::pair<std::string,std::pair<int,bool> > > ListBreakPoint();
        //是否命中断点 
        static bool HitBreakPoint(std::string filename,int lineno)
        {    
            std::map<std::string,std::map<int,bool> >::iterator it = breakpoints.find(filename);
            if( it != breakpoints.end())
            {
                std::map<int,bool>::iterator it2 = it->second.find(lineno);
                if(it2 != it->second.end())
                {
                    return it2->second;
                }
            }
            return false;
        }
        
        //添加一个断点
        static void InsertBreakPoint(std::string filename,int lineno)
        {
            std::map<std::string,std::map<int,bool> >::iterator it = breakpoints.find(filename);
            if( it != breakpoints.end())
            {
                it->second.insert(std::make_pair(lineno,true));
            }
            else
            {
                std::map<int,bool> tmp;
                tmp.insert(std::make_pair(lineno,true));
                breakpoints.insert(std::make_pair(filename,tmp));
            }
        }
        static bool setpState;//是否单步执行
        static bool isrunning;//调试的程序正在运行
    private:
        static std::map<std::string,std::map<int,bool> > breakpoints;//断点记录
    };
    
    
    #endif

    Commandline.cpp

    #include "stdafx.h"
    #include "commandline.h"
    #include <iostream>
    #include <string.h>
    #include "command.h"
    lua_State *L;
    bool CommandLine::setpState;//是否单步执行
    bool CommandLine::isrunning;//调试的程序正在运行
    std::map<std::string,std::map<int,bool> > CommandLine::breakpoints;//断点记录
    static int  readline(FILE * f, char *vptr, unsigned int maxlen)
    {
            unsigned int n, rc;
            char    c, *ptr;
            ptr = (char*)vptr;
            for (n = 1; n < maxlen; n++) {
        
                if ( (rc = (unsigned int)fread(&c,1,1,f)) == 1) {
                    
                    if (c == '/n')
                    {
                        *ptr='/0';
                        break;
                    }
                    else
                        *ptr++ = c;
                } else if (rc == 0) {
                    *ptr = 0;
                    return (n - 1);     
                } else {
                    printf("读取文件出错/n");
                    return (-1);       
                }
            }
            *ptr = 0;                  
            return (n);
    }
    static int luaHook(lua_State *L)
    {
        const char *filename = lua_tostring(L,1);
        int lineno = lua_tonumber(L,2);
        if(CommandLine::HitBreakPoint(filename,lineno) || CommandLine::setpState)
        {
            //读取文件的lineno行,并打印
            char buf[1024];
            FILE *f = fopen(filename,"r");
            if(f)
            {
                for(int i = 1; i <= lineno; ++i)
                    readline(f,buf,1024);
                printf("%s/n",buf);
            }
            CommandLine::Wait4Command(true);
        }
        
        return 0;
    }
    
    void CommandLine::Init()
    {
        L = lua_open();
        luaL_openlibs(L);
        lua_register(L, "CHook", luaHook);
        //注册钩子
        if (luaL_dofile(L, "./hook.lua")) {
            const char * error = lua_tostring(L, -1);
            lua_pop(L,1);
        }
        setpState = false;
        isrunning = false;
    }
    char* CommandLine::GetInput()
    {
        static char cmd[1024];
        int i = 0;
        for(; i < 1023; ++i)
        {
            cmd[i] = (char)getchar();
            if(cmd[i] == '/n')
                break;
        }
        cmd[i] = '/0';
        return cmd;
    }
    void CommandLine::Wait4Command(bool fromlua)
    {
        for( ; ;)
        {
            char *input = GetInput();
            //分析并处理命令行
            Command *cmd = CommandFactory::CreateCommand(input);
            if(!cmd)
            {    
                continue;
            }
            
            if(!cmd->Execute(fromlua))
                break;
        }
    }

    luaDebuger.cpp

    // luaDebuger.cpp : 定义控制台应用程序的入口点。
    //
    #include "stdafx.h"
    #include "Commandline.h"
    int _tmain(int argc, _TCHAR* argv[])
    {
        CommandLine::Init();
        CommandLine::Wait4Command(false);
        return 0;
    }

    hook.lua

    function hookfunc(event,line)
        local s = debug.getinfo(2).short_src
        CHook(s,line)
    end
    function printlocal(valname)
        
        --lua中没法根据变量名获得变量的信息,所以下面只能取得栈中所有本地变量的信息,
        --然后一一比对,看看是否是要查看的变量
        local i = 1
        repeat
            local name,value = debug.getlocal(4,i) --第1层是当前函数,第2层是c++中的CHook,第3层是hookfunc,第4层才是我们要跟踪的函数栈
            if name == nil then
                print("变量不存在")
                return
            end
            if name == valname then
                print(name .. ":" .. value)
                return
            end
            i = i + 1    
        until false
    end
    debug.sethook(hookfunc,"l")

     

     

     

     

     

     

  • 相关阅读:
    性能测试术语讲解
    Silverlight 部署
    C#数据库SQLServer查询、修改数据
    有一点点背
    Ajax与XMLHttpRequest对象
    ServletListener 之 监听HTTP会话
    JAVA中几种常见集合的使用实例
    [转]全面接触Java集合框架(二)
    自定义标签之 SimpleTag的开发
    jsp常用内置对象
  • 原文地址:https://www.cnblogs.com/sniperHW/p/2460677.html
Copyright © 2020-2023  润新知