问题描述
我正在开发一个允许在OCaml语言中使用 ptrace()
的绑定"库,但是我的问题仅与 ptrace()
有关.
I'm working on a "binding" library that allows to use ptrace()
in the OCaml language but my question only relates to ptrace()
.
所以,现在,我正在尝试编写一小段代码,以便使用 ptrace()
在上在Linux x86-64上创建一个简单的硬件断点:
So, right now, I'm trying to write a small piece of code in order to create a simple hardware breakpoint on Linux x86-64 by using ptrace()
:
#define DR_OFFSET(x) (((struct user *)0)->u_debugreg + x)
typedef struct {
int dr0_local: 1;
int dr0_global: 1;
int dr1_local: 1;
int dr1_global: 1;
int dr2_local: 1;
int dr2_global: 1;
int dr3_local: 1;
int dr3_global: 1;
int reserverd: 8;
break_flag_t dr0_break: 2;
data_length_t dr0_len: 2;
break_flag_t dr1_break: 2;
data_length_t dr1_len: 2;
break_flag_t dr2_break: 2;
data_length_t dr2_len: 2;
break_flag_t dr3_break: 2;
data_length_t dr3_len: 2;
} dr7_t;
CAMLprim value ptrace_breakpoint(value ml_pid, value ml_addr)
{
CAMLparam2(ml_pid, ml_addr);
dr7_t dr7 = {0};
dr7.dr0_local = 1;
dr7.dr0_break = 0; /* break on execution */
dr7.dr0_len = 0x03; /* len 4 */
ptrace(PTRACE_POKEUSER, Int_val(ml_pid), DR_OFFSET(0), (void*)Int64_val(ml_addr));
ptrace(PTRACE_POKEUSER, Int_val(ml_pid), DR_OFFSET(7), (void*)dr7));
ptrace(PTRACE_POKEUSER, Int_val(ml_pid), DR_OFFSET(6), (void*)0);
CAMLreturn0;
}
执行此代码时,出现一个无效参数
. dr7
的值为 0xc0001
.为了找到有效值,我通过使用 strace
:
When I execute this code, I got an Invalid argument
. The value of dr7
is 0xc0001
. In order to find a valid value, I inspected how GDB use ptrace
by using strace
:
ptrace(PTRACE_POKEUSER, 6459, offsetof(struct user, u_debugreg), 0x400519) = 0
ptrace(PTRACE_POKEUSER, 6459, offsetof(struct user, u_debugreg) + 56, 0x101) = 0
ptrace(PTRACE_POKEUSER, 6459, offsetof(struct user, u_debugreg) + 48, 0) = 0
因此,GDB将dr7寄存器设置为值 0x101
.我试过这个值,它起作用.因此,我想知道GDB使用的值的含义是什么?我之前使用的 dr7_t
位字段有效吗?
So, GDB set the dr7 register to the value 0x101
. I tried this value and it works. Thus, I'm wondering what is the meaning of the value used by GDB? Is the dr7_t
bit fields that I used before valid?
谢谢.
感谢Neitsa,这是解决方案:
Thanks to Neitsa, here is the solution:
typedef struct {
unsigned int dr0_local: 1;
unsigned int dr0_global: 1;
unsigned int dr1_local: 1;
unsigned int dr1_global: 1;
unsigned int dr2_local: 1;
unsigned int dr2_global: 1;
unsigned int dr3_local: 1;
unsigned int dr3_global: 1;
unsigned int le: 1;
unsigned int ge: 1;
unsigned int reserved_10: 1;
unsigned int rtm: 1;
unsigned int reserved_12: 1;
unsigned int gd: 1;
unsigned int reserved_14_15: 2;
break_flag_t dr0_break: 2;
data_length_t dr0_len: 2;
break_flag_t dr1_break: 2;
data_length_t dr1_len: 2;
break_flag_t dr2_break: 2;
data_length_t dr2_len: 2;
break_flag_t dr3_break: 2;
data_length_t dr3_len: 2;
} dr7_t;
CAMLprim value ptrace_breakpoint(value ml_pid, value ml_addr)
{
CAMLparam2(ml_pid, ml_addr);
dr7_t dr7 = {0};
dr7.dr0_local = 1;
dr7.le = 1;
dr7.ge = 1;
dr7.reserved_10 = 1;
my_ptrace(PTRACE_POKEUSER, Int_val(ml_pid), DR_OFFSET(0), (void*)Int64_val(ml_addr));
my_ptrace(PTRACE_POKEUSER, Int_val(ml_pid), DR_OFFSET(7), (void*)dr7));
my_ptrace(PTRACE_POKEUSER, Int_val(ml_pid), DR_OFFSET(6), (void*)0);
CAMLreturn0;
}
推荐答案
您的结构看起来不错(尽管我会使用 unsigned int
).
Your structure looks good (I would have used unsigned int
though).
一些说明(引自 Intel手册第17.2章:调试寄存器
):
- 保留位(必须根据文档相应地设置 ):
- 第10位保留,但设置为1.
- 第12、14和15位保留,必须设置为0(整个结构预先设置为0).
- Reserved bits (must be set accordingly to the documentation):
- Bit 10 is reserved but set to 1.
- Bits 12, 14 and 15 are reserved and must be set to 0 (
memset
the whole structure to 0 beforehand).
其他字段:
- 您应该还实现第8位和第9位并将其设置为1
- You should also implement bit 8 and bit 9 and set them to 1
- 指令必须的指令断点的长度设置为1个字节(这意味着相应的
LENn
字段必须设置为0): - Instruction breakpoint for instructions must have length set to 1 byte (which implies that the corresponding
LENn
field must be set to 0): - 将保留位设置为正确的值
- 将DR7.LE和DR7.GE设置为1
- 将DR7.L0(L1,L2,L3)设置为 1 [本地断点]
- 确保DR7.RW/0(RW/1、RW/2、RW/3)为 0 [在执行指令时中断]
- 确保DR7.LEN0(LEN1,LEN2,LEN3)为 0 [1字节长度]
- 将DR0(1、2、3)设置为指令线性地址
- 断点[DR0至DR3]的线性地址必须落在指令的第一个字节上.
- Set the reserved bits to their right values
- Set DR7.LE and DR7.GE to 1
- Set DR7.L0 (L1, L2, L3) to 1 [local breakpoint]
- Make sure DR7.RW/0 (RW/1, RW/2, RW/3) is 0 [break on instruction exec]
- Make sure DR7.LEN0 (LEN1, LEN2, LEN3) is 0 [1 byte length]
- Set DR0 (1, 2, 3) to the instruction linear address
- The linear address of the breakpoint [DR0 to DR3] must fall on the first byte of the instruction.
修改
- 0x101:
- bin(0x101)='0b100000001'
- DR7.L0&DR7.LE设置为1
从技术上讲,0x701应该正确:
Technically, 0x701 should be correct:
- 0x701:
- bin(0x701)='0b11100000001'
- DR7.L0&DR7.LE&DR7.GE和DR7.bit10设置为1
这篇关于如何设置dr7寄存器的值以便在x86-64上创建硬件断点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
因此,要在执行时设置断点:
So, to set a breakpoint on execution: