• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

一个简陋的lua调试器

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

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")

 

 

 

 

 

 

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
OpenResty / Nginx模块,Lua库和相关资源的列表发布时间:2022-07-22
下一篇:
Lua - 使用cmd 控制台程序运行 lua脚本 步骤发布时间:2022-07-22
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap