65.9K
CodeProject 正在变化。 阅读更多。
Home

以编程方式切换硬件数据/读取/执行断点

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (38投票s)

2008年7月24日

CPOL

2分钟阅读

viewsIcon

189023

downloadIcon

4778

引入硬件断点机制的简单代码。

引言

我决定写这篇关于硬件断点的文章,原因如下

  • Visual C++ 仅支持写入式数据断点。 您可能希望在读取数据时也触发断点。
  • 您可能没有使用 Visual C++,因此您的调试器很可能使用一些基于软件的缓慢机制。
  • 您可能想要以编程方式设置/删除断点。
  • 您可能对底层 CPU 的东西感兴趣!

特点

  • 适用于 x86 和 x64。
  • 每个线程最多支持 4 个硬件断点。

调试寄存器

x86/x64 包含一组调试寄存器,命名为 DR0、DR1、DR2、DR3、DR6 和 DR7。 当处于 32 位模式时,这些寄存器是 32 位的,当处于长模式时,这些寄存器是 64 位的。 DR0、DR1、DR2 和 DR3 包含断点的线性地址,DR7 包含此处说明的位

含义
0-7 每个 4 个调试寄存器的标志(每个 2 个)。 第一个标志设置为指定本地断点(因此 CPU 在切换任务时重置该标志),第二个标志设置为指定全局断点。 显然,在 Windows 中,您只能使用第一个标志(虽然我没有尝试过第二个)。
16-23

每个寄存器 2 位,定义何时触发断点

  • 00b - 在执行代码时触发
  • 01b - 在写入数据时触发
  • 10b - 保留
  • 11b - 在读取或写入数据时触发
24-31

每个寄存器 2 位,定义断点的大小

  • 00b - 1 字节
  • 01b - 2 字节
  • 10b - 8 字节
  • 11b - 4 字节

我们使用 SetThreadContext 来设置线程的必要标志。 之后,当触发断点时,会引发值为 EXCEPTION_SINGLE_STEP 的异常。

设置断点

HANDLE SetHardwareBreakpoint(HANDLE hThread,HWBRK_TYPE Type,HWBRK_SIZE Size,void* s);
  • hThread - 要设置断点的线程的句柄。
  • Type - 断点的类型
    • HWBRK_TYPE_CODE
    • HWBRK_TYPE_READWRITE
    • HWBRK_TYPE_WRITE
  • Size - 断点的大小
    • HWBRK_SIZE_1
    • HWBRK_SIZE_2
    • HWBRK_SIZE_4
    • HWBRK_SIZE_8
  • addr - 断点的地址。

该函数返回断点的句柄,以便稍后在 RemoveHardwareBreakpoint 中使用。 如果发生以下情况,它可能会返回 0

  • 您无权访问该线程。
  • 您已为该线程设置了最大数量的断点 (4)。

移除断点

bool RemoveHardwareBreakpoint(HANDLE hBrk);

移除断点,成功时返回 true。

示例

int __stdcall WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
 char c1[100] = {0};
 lstrcpyA(c1,"Hello 1");
 HANDLE hX1 = 0;

 hX1 = SetHardwareBreakpoint(GetCurrentThread(), 
       HWBRK_TYPE_READWRITE,HWBRK_SIZE_4,c1);
 __try
 {
   volatile char a1 = c1[2];
   // To ensure that it won't be optimized out.
 }
 __except(GetExceptionCode() == STATUS_SINGLE_STEP)
 {
   MessageBoxA(0,"Breakpoint hit!",0,MB_OK);
 }
 RemoveHardwareBreakpoint(hX1);
 return 0; 
}

我等待您的评论和问题!

历史

  • 2008 年 7 月 24 日 - 首次发布。
© . All rights reserved.