如何设置dr7寄存器的值以便在x86-64上创建硬件断点? [英] How to set the value of dr7 register in order to create a hardware breakpoint on x86-64?

查看:72
本文介绍了如何设置dr7寄存器的值以便在x86-64上创建硬件断点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个允许在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

      LE和GE(本地和全局精确断点启用)标志(位8、9)—以后的P6系列处理器不支持此功能IA-32处理器和Intel 64处理器.[...],我们建议如果需要确切的断点,则将LE和GE标志设置为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):
        • 指令断点地址的长度必须为1字节( LENn字段设置为00 ).其他操作数大小的代码断点未定义

          Instruction breakpoint addresses must have a length specification of 1 byte (the LENn field is set to 00). Code breakpoints for other operand sizes are undefined

          因此,要在执行时设置断点:

          So, to set a breakpoint on execution:

          • 将保留位设置为正确的值
          • 将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.

              处理器仅在以下情况下识别指令断点地址:它指向指令的第一个字节.如果指令有前缀,则断点地址必须指向第一个前缀.

              The processor recognizes an instruction breakpoint address only when it points to the first byte of an instruction. If the instruction has prefixes, the breakpoint address must point to the first prefix.


              修改

              • 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上创建硬件断点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆