linux调试器的实现---有关寄存器操作的实现

28 篇文章 0 订阅

在这里,依旧是我们的利器ptrace

//reg.h
#ifndef DEBUGGER_REG_H
#define DEBUGGER_REG_H

#include <string>
#include <boost/mpl/size_t.hpp>
#include <array>
#include <algorithm>
enum class reg 
{
    rax,rbx,rcx,rdx,
    rdi,rsi,rbp,rsp,
    r8,r9,r10,r11,
    r12,r13,r14,r15,
    rip,eflags,cs,orig_rax,
    fs_base,gs_base,fs,gs,ss,ds,es
};
static constexpr std::size_t n_registers=27;
struct reg_descriptor
{
    reg r;//rax---es寄存器
    int dwarf_r;
    std::string name;
};
//这里要看自己的平台下的reg.h或者user.h,我的是:
/usr/include/x86_64-linux-gnu/sys/reg.h,一定要对应起来,贴一个我的环境:ubuntu16.04下reg.h:
define R15 0
define R14 1
define R13 2
define R12 3
define RBP 4
define RBX 5
define R11 6
define R10 7
define R9 8
define R8 9
define RAX 10
define RCX 11
define RDX 12
define RSI 13
define RDI 14
define ORIG_RAX 15
define RIP 16
define CS 17
define EFLAGS 18
define RSP 19
define SS 20
define FS_BASE 21
define GS_BASE 22
define DS 23
define ES 24
define FS 25
define GS 26

//为了方便获取寄存器的值,名字等后边的使用
const 
std::array<reg_descriptor,n_registers>g_register_descriptors
{{
        {reg::r15,0,"r15"},
        {reg::r14,1,"r14"},
        {reg::r13,2,"r13"},
        {reg::r12,3,"r12"},
        {reg::rbp,4,"rbp"},
        {reg::rbx,5,"rbx"},
        {reg::r11,6,"r11"},
        {reg::r10,7,"r10"},
        {reg::r9,8,"r9"},
        {reg::r8,9,"r8"},
        {reg::rax,10,"rax"},
        {reg::rcx,11,"rcx"},
        {reg::rdx,12,"rdx"},
        {reg::rsi,13,"rsi"},
        {reg::rdi,14,"rdi"},
        {reg::orig_rax,15,"orig_rax"},
        {reg::rip,16,"rip"},
        {reg::cs,17,"cs"},
        {reg::eflags,18,"eflags"},
        {reg::rsp,19,"rsp"},
        {reg::ss,20,"ss"},
        {reg::fs_base,21,"fs_base"},
        {reg::gs_base,22,"gs_base"},
        {reg::ds,23,"ds"},
        {reg::es,24,"es"},
        {reg::fs,25,"fs"},
        {reg::gs,19,"26"},

}};
uint64_t get_register_value(pid_t pid,reg r);
void set_register_value(pid_t,reg r,uint64_t value);
uint64_t get_register_value_from_dwarf_register(pid_t pid, unsigned regnum);
std::string get_register_name(reg r);
reg get_register_from_name(const std::string& name);


#endif //DEBUGGER_REG_

我们先来看看get_register_value(pid_t pid,reg r)的实现

uint64_t get_register_value(pid_t pid,reg r)
{
    user_regs_struct regs;
    //这里父进程将子进程所有寄存器的值都放在了regs结构体里面
    ptrace(PTRACE_GETREGS,pid,nullptr,&regs);
    //获取我们传进去的寄存器在regs中的偏移
    auto it=std::find_if(begin(g_register_descriptors),end(g_register_descriptors),[r](reg_descriptor rd){
        return rd.r==r;
    });
    /**
     * 用存放了子进程reg结构体内容的regs获取我们制定的寄存器的值,下面这样代码首先将regs的地址强转成
     * 一个指向uint64_t的指针,这个指针加1,就相当于偏移了sizeof(uint64_t),这里偏移了it-begin(g_register_descriptors),
     * 也就是我们需要查看的寄存器
     */

    return *(reinterpret_cast<uint64_t*>(&regs)+(it-begin(g_register_descriptors)));

好像这个函数没啥说的,直接看注释就好。

void set_register_value(pid_t pid,reg r,uint64_t value)
{
    user_regs_struct regs;
    ptrace(PTRACE_GETREGS,pid, nullptr,&regs);//同样先将子进程的当前寄存器数据保存到regs这个结构体中
    auto it=std::find_if(begin(g_register_descriptors),end(g_register_descriptors),[r](reg_descriptor rd){
        return rd.r==r;//在reg_descriptor这个数组中先找到我们需要的寄存器在整个regs中的偏移
    });
    *(reinterpret_cast<uint64_t*>(&regs)+(it-begin(g_register_descriptors)))=value;//给结构体中相应的寄存器赋值
    ptrace(PTRACE_SETREGS,pid, nullptr,&regs);//将修改后的regs结构体整个赋值给子进程当前的寄存器,这里我们只修改了我们传进去的寄存器的值
}

上边两个函数理解了,下边这三个就不用详细解释了,直接看代码:

uint64_t get_register_value_from_dwarf_register(pid_t pid, unsigned regnum)
{
    user_regs_struct regs;
    auto it=std::find_if(begin(g_register_descriptors),end(g_register_descriptors),[regnum](reg_descriptor rd){
        return rd.dwarf_r==regnum;
    });
    if(it==end(g_register_descriptors))
    {
        throw std::out_of_range{"Unknow dwarf register"};
    }
    ptrace(PTRACE_GETREGS,pid, nullptr,&regs);
    return *(reinterpret_cast<uint64_t*>(&regs)+(it-begin(g_register_descriptors)));
}

std::string get_register_name(reg r)
{
    auto it=std::find_if(begin(g_register_descriptors),end(g_register_descriptors),[r](reg_descriptor rd){
       return rd.r==r;
    });
    return it->name;

}
reg get_register_from_name(const std::string&name)
{
    auto it=std::find_if(begin(g_register_descriptors),end(g_register_descriptors),[name](reg_descriptor rd){
        return rd.name==name;
    });
    return it->r;
}

到这里我们的有关寄存器操作的函数就实现了,下一篇我们将介绍断点的实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值