我是靠谱客的博主 开放画笔,最近开发中收集的这篇文章主要介绍linux调试器的实现---有关寄存器操作的实现,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在这里,依旧是我们的利器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;
}

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

最后

以上就是开放画笔为你收集整理的linux调试器的实现---有关寄存器操作的实现的全部内容,希望文章能够帮你解决linux调试器的实现---有关寄存器操作的实现所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(55)

评论列表共有 0 条评论

立即
投稿
返回
顶部