一个简陋的lua调试器

摘要:
Lua没有提供特殊的调试器,但它提供了一些接口函数来实现您自己的调试器。下面基于命令行实现了一个简单的lua调试器,提供了一些最基本的调试功能。只有三个基本的lua调试函数,debug.sethook、debug.getlocal和debug.getinfo。有关具体用法和函数,请参阅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")

 

 

 

 

 

 

免责声明:文章转载自《一个简陋的lua调试器》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇利用netperf、iperf、mtr测试网络elementUI 表格 table 的表头错乱问题下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C#调试器导航

本快速入门演示如何在 Visual Studio 调试会话中导航,以及如何在会话中查看和更改程序状态。 本 快速入门适用于不熟悉用 Visual Studio 进行调试的开发人员,以及要详细了解在 Visual Studio 调试会话中导航的开发人员。但其中不传授调试本身的技艺。示例代码中的方法仅为演示本主题中所述的调试过程。这些方法并未采用应用程序或函...

使用Windbg解析dump文件

WinDbg OllyDbg SoftICE (已经停止更新) 虽说WinDbg在无源码调试方面确实比较困难,但在调试内核方面却真的有独到之处。 https://www.pediy.com/kssd/pediy10/94457.html 使用Windbg解析dump文件 1 常用的Windbg指令 ①!analyze -v ②kP...

网络报文抓取研究

1     引言 网络报文抓取是指通过对主机网络设备的探测,实现获取该网络当前传输的所有信息,并根据信息的源主机、目标主机、服务协议和端口等信息简单过滤掉不关心数据,然后提交给上层应用程序进行进一步处理。 2     网络数据包捕获原理 一个包捕获机制包含三个主要部分 1) 包捕获机制 不同的操作系统实现的底层包捕获机制可能是不一样的,但从形式上看大同小异...

PowerDesigner将PDM导出生成WORD文档

PowerDesigner将PDM导出生成WORD文档 环境 PowerDesigner15 1.点击Report Temlates 制作模板 2.如果没有模板,单击New图标创建。有直接双击进入。 3.在弹出的类型(Type)对话框中想选择PBM(Physical data Model),如果有中文汉化包则选择simolified Chinese(中...

十六进制字符串 char 数组 转换 c/c++/java

转载自:http://qing.blog.sina.com.cn/1820422183/6c81702733001qvk.html 1.c版 int hexcharToInt(char c) { if (c >= '0' && c <= '9') return (c - '0'); if (c >= 'A' &&...

VS2013创建Windows服务与调试服务

1、创建Windows服务 说明:     a)Description 服务描述,直接显示到Windows服务列表中的描述;   b)DisplayName 服务显示名称,直接显示到Windows服务列表中的名称;   c)ServiceName 服务进程名称,安装与卸载服务时的唯一标识。 单击“serviceProcessInstaller1”,...