Jul*_*ien 2 c linux ptrace breakpoints x86-64
我正在开发一个允许ptrace()在OCaml语言中使用的“绑定”库,但我的问题仅涉及ptrace()。
因此,现在,我正在尝试编写一小段代码,以便通过使用ptrace()以下命令在Linux x86-64上创建一个简单的硬件断点:
#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;
}
Run Code Online (Sandbox Code Playgroud)
执行此代码时,我得到了一个Invalid argument。值dr7IS 0xc0001。为了找到有效值,我ptrace通过使用strace以下命令检查了GDB的使用方式:
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
Run Code Online (Sandbox Code Playgroud)
因此,GDB将dr7寄存器设置为value 0x101。我试过这个值,它的工作原理。因此,我想知道GDB使用的值的含义是什么?dr7_t我之前使用的位字段有效吗?
谢谢。
编辑:
感谢Neitsa,这是解决方案:
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;
}
Run Code Online (Sandbox Code Playgroud)
您的结构看起来不错(unsigned int尽管我会使用)。
几点评论(引号来自Intel Manual chap 17.2: Debug Registers):
memset整个结构为0)。其他领域:
LE和GE(本地和全局精确断点启用)标志(位8、9)— P6系列处理器,更高版本的IA-32处理器和Intel 64处理器不支持此功能。[...] 如果需要精确的断点,我们建议将LE和GE标志设置为1
指令断点地址的长度必须为1个字节(LENn字段设置为00)。其他操作数大小的代码断点未定义
因此,要在执行时设置断点:
处理器仅在指向指令的第一个字节时才识别指令断点地址。如果指令具有前缀,则断点地址必须指向第一个前缀。
编辑
从技术上讲,0x701应该正确: