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

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//为了方便获取寄存器的值,名字等后边的使用 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)的实现

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)));

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

复制代码
1
2
3
4
5
6
7
8
9
10
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结构体整个赋值给子进程当前的寄存器,这里我们只修改了我们传进去的寄存器的值 }

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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调试器内容请搜索靠谱客的其他文章。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部