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






4.97/5 (38投票s)
引入硬件断点机制的简单代码。
引言
我决定写这篇关于硬件断点的文章,原因如下
- 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 位,定义何时触发断点
|
24-31 |
每个寄存器 2 位,定义断点的大小
|
我们使用 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 日 - 首次发布。