linux调试器的实现---主要框架

准备知识

主要用的知识点:ptrace,关于ptrace不太了解的同学可以先看看这两篇文章:
玩转ptrace1:https://www.cnblogs.com/catch/p/3476280.html
玩转ptrace2:http://blog.csdn.net/code09/article/details/6093363

首先运行我们的调试器,调试器作为父进程,fork一个子进程,在子进程中先trace_me,然后调用exec函数去执行被调试的进程。在父进程中运行一个大循环,去监听我们输入的调试指令。
我们来看看main函数

//main.cpp
#include <iostream>
#include <zconf.h>
#include<sys/ptrace.h>
#include "debugger.h"

int main(int argc,char *argv[]){
    using namespace std;
    if(argc<2)
    {
        cerr<<"Program name not specified"<<endl;
    }

    auto prog=argv[1];//要调试的程序的名字
    pid_t pid=fork();
    if(pid==0)
    {
        cout<<"子进程中"<<endl;
        ptrace(PTRACE_TRACEME,0, nullptr, nullptr);
        execl(prog,prog, nullptr);//执行要调试的程序,程序启动完毕会给父进程发送一个sigtrap信号
    }else if(pid>=1)
    {
        cout<<"父进程中"<<endl;
        debugger dbg{prog,pid};
        dbg.run();//在这里我们一直运行我们的调试器,去监听子进程的状态的改变
    }
}

当子进程的状态改变的时候,父进程就能收到这种信号。
我们继续看父进程中的run函数:

void debugger::run()
{

    int wait_status;
    auto options=0;
    waitpid(m_pid,&wait_status,options);//父进程阻塞在这里等待子进程启动完毕
    char* line= nullptr;
    while((line=linenoise("minidbg>"))!= nullptr)//调试器在这里输入
    {
        handle_command(line);//主要对命令处理函数
        linenoiseHistoryAdd(line);
        linenoiseFree(line);
    }
}

我们继续看handle_command函数:

void debugger::handle_command(const  std::string&line)
{
    auto args=split(line,' ');
    auto command=args[0];
    if(is_prefix(command,"continue"))
    {
        continue_execution();
    }else if(is_prefix(command,"break"))
    {
        std::string addr{args[1],2};//从0x以后开始初始地址,认为用户已经加上了0x
        set_breakpoint_at_address(std::stol(addr,0,16));//设置断点
    }else if(is_prefix(command,"register"))
    {
        if(is_prefix(args[1],"dump"))
        {
            dump_register();
        }else if(is_prefix(args[1],"read"))
        {
            std::cout<<get_register_value(m_pid,get_register_from_name(args[2]))<<std::endl;

        }else if(is_prefix(args[1],"write"))
        {
            std::string val{args[3],2};
            set_register_value(m_pid,get_register_from_name(args[2]),std::stol(val,0,16));
        }
    }else if(is_prefix(command,"memory"))
    {
        std::string addr{args[2],2};
        if(is_prefix(args[1],"read"))
        {
            std::cout<<std::hex<<read_memory(std::stol(addr,0,16))<<std::endl;
        }
        if(is_prefix(args[1],"write"))
        {
            std::string val{args[3],2};
            write_memory(std::stol(addr,0,16),std::stol(val,0,16));
        }
    }
    else
    {
        std::cerr<<"Unknow command\n";
    }
}

这里我们先实现了几个常用的命令,后边还会对这些命令有扩充。
接下来的几篇,我们将会分析每个命令的实现。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值