为什么数据断点不能在未对齐的地址上工作
Why does data breakpoint not work on unaligned address
在Visual Studio中调试c++项目时,有些数据断点从未命中。
所以我写了一些测试代码:#include <iostream>
#include <stdint.h>
void test(uint32_t* p)
{
*p = 0;
// set a data breakpoint on p
*((char*)p + 2) = 0x1;
std::cout << *p << std::endl;
}
uint32_t* alloc(size_t offset)
{
char* p = new char[sizeof(uint32_t) + offset];
p = p + offset;
return (uint32_t*)p;
}
int main()
{
test(alloc(0)); // test #1
test(alloc(2)); // test #2
}
如你所见,在函数test中,*p的值将首先归零,然后它会隐式地改变,我有一个小端CPU,所以它必须是65536。
如果你在p(4字节)上设置了一个数据断点来检测变化,你会得到两种不同的结果:命中或未命中。这取决于p所指向的地址
在上面的测试代码中,测试#1会命中,而测试#2不会命中,#1和#2之间的区别是返回的地址Alloc(0)和Alloc (2).
如何:在MSDN上设置数据断点这篇文章没有讨论这个。
数据断点是在CPU的帮助下设置的,使用x86的调试寄存器;关于它们,Intel手册说(§17.2.5):
断点地址寄存器(调试寄存器
DR0
到DR3
)和LENn
字段为每个断点定义a数据或I/O断点的顺序字节地址范围。LENn
字段允许指定1-、2-、4-,或8字节范围,从相应的调试寄存器(DRn)中指定的线性地址开始。两字节范围必须与单词边界对齐;4字节范围必须在双字边界上对齐。 I/O地址是零扩展的(从16位到32位),以便与所选调试中的断点地址进行比较注册)。这些要求由处理器强制执行;它使用LENn字段位来掩盖较低的地址位在调试寄存器中。未对齐的数据或I/O断点地址不能产生有效的结果。
(重点)
所以,限制在硬件上
发生这种情况的详细解释:
数据断点使用CPU的调试寄存器。在x86上,这些调试寄存器通过屏蔽地址的低位来对齐它们的数据大小:
- 16位(2字节)断点获得其最低地址位清除
(addr & -2)
。 - 32位(4字节)断点得到它的2个最低地址位清除
(addr & -4)
。 - 64位(8字节)断点得到它的3个最低地址位清除
(addr & -8)
。
当x86 CPU访问内存时,它通过屏蔽与调试寄存器地址和相同的方式来比较地址,如果两者相等,则触发断点
这是一个简化调试断点比较器中的电子电路的技巧:只需要比较两个对齐的地址。
电子转换成伪代码:
if(!((address ^ debug_address) & debug_mask))
breakpoint();
代替:
if((address >= debug_address) & (address < debug_address_plus_length))
breakpoint();
在硅片上实现要复杂得多,并且会降低CPU的速度。
只要所有内存访问都对齐,地址屏蔽技巧就可以完美地工作。
所以我们说p指向地址0xF02,断点是32位(4字节),然后断点地址与((0xF02 & -4) == 0xF00)
对齐。
注释:-4是0xfffffffffc (32bits)或0xfffffffffffffffffffc (64bits)
然后访问地址(0xF02+2 == 0xF04)
CPU然后屏蔽0xF04 ((0xF04 & -4) == 0xF04)
,然后将其与调试断点地址(0xF00)进行比较。
它们不匹配,所以CPU不会触发断点
- 将数组的地址分配给变量并删除
- QSqlquery prepare()和bindvalue()不工作
- 空基优化子对象的地址
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- 导入库可以跨dll版本工作吗
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 如何在c++程序中找到函数的地址
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- 变量地址的运算符[]是如何工作的
- 在 Xcode 中工作的 CMake 中启用地址清理器的正确方法是什么
- C 在我的计算机上工作正常,但在Leetcode上获得地址消毒器堆越流行错误
- Outlook -从显示名称获取电子邮件地址.可以在Python中工作,而不是C
- 为什么数据断点不能在未对齐的地址上工作
- libmysql mysql_real_connect与IP地址失败,但与本地主机工作
- 如何工作与内存地址在C?它们是十六进数还是无符号整型
- 进程外内存堆围绕32位地址空间工作
- c++简单聊天不工作与我的IP地址
- CAtlHttpClient -导航到IP6地址似乎不工作