我正致力于"绑定"允许在OCaml语言中使用ptrace()
的库,但我的问题仅与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;
}
当我执行此代码时,我得到了Invalid argument
。 dr7
的值为0xc0001
。为了找到有效值,我使用ptrace
检查了GDB如何使用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
位字段是否有效?
谢谢。
修改
感谢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;
}
答案 0 :(得分:4)
你的结构看起来不错(我会使用unsigned int
)。
一些评论(引用来自Intel Manual chap 17.2: Debug Registers
):
memset
整个结构为0)。其他领域:
LE和GE(本地和全局精确断点启用)标志(位8,9) - 稍后,P6系列处理器不支持此功能 IA-32处理器和Intel 64处理器。 [...],我们建议 如果需要确切的断点,则LE和GE标志设置为1
指令断点地址的长度规范必须为1 byte( LENn字段设置为00 )。其他操作数大小的代码断点未定义
因此,要在执行时设置断点:
处理器仅在识别时识别指令断点地址 它指向指令的第一个字节。如果指令有 前缀,断点地址必须指向第一个前缀。
修改强>
从技术上讲,0x701应该是正确的: