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

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

//reg.h

#ifndef DEBUGGER_REG_H

#define DEBUGGER_REG_H

#include

#include

#include

#include

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::arrayg_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,®s);

//获取我们传进去的寄存器在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(®s)+(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,®s);//同样先将子进程的当前寄存器数据保存到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(®s)+(it-begin(g_register_descriptors)))=value;//给结构体中相应的寄存器赋值

ptrace(PTRACE_SETREGS,pid, nullptr,®s);//将修改后的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,®s);

return *(reinterpret_cast(®s)+(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;

}

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值