本文介绍了如何设置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

      • 指令必须的指令断点的长度设置为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):
        • 因此,要在执行时设置断点:

          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.


              修改

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

06-27 05:15