In Visual Studio while debugging a C++ project, some data breakpoints never hit.
So I wrote some code for testing:
#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
}
As you see, in function test, the value of *p will be zeroed first, then it will be changed implicitly, I got a litte-endian CPU so it must be 65536.
If you set a data breakpoint on p (4 bytes) to detect the changing, you'll get two different results: hit or not. It depends on the address of that p pointed at.
In my testing code above, test #1 will hit and test #2 will not, the difference between #1 and #2 are the addresses returned by alloc(0) and alloc(2).
This article How to: Set a Data Breakpoint on MSDN does not talk about this.
Does data breakpoint not work on an unaligned address ?
If a source file has changed and the source no longer matches the code you're debugging, the debugger won't set breakpoints in the code by default. Normally, this problem happens when a source file is changed, but the source code wasn't rebuilt. To fix this issue, rebuild the project.
You set breakpoints wherever you want to pause debugger execution. For example, you may want to see the state of code variables or look at the call stack at a certain breakpoint. If you are trying to resolve a warning or issue while using breakpoints, see Troubleshoot breakpoints in the Visual Studio debugger.
solution -> Properties -> Startup Project -> startup projects -> Start action , Debug/General settings -> uncheck Just My Code , quit VC++, reload, restart PC.
The data breakpoints are set with the assistance of the CPU, using the debug registers on x86; about them, the Intel manual says (§17.2.5):
Breakpoint address registers (debug registers
DR0
throughDR3
) and theLENn
fields for each breakpoint define a range of sequential byte addresses for a data or I/O breakpoint. TheLENn
fields permit specification of a 1-, 2-, 4- , or 8-byte range, beginning at the linear address specified in the corresponding debug register (DRn). Two-byte ranges must be aligned on word boundaries; 4-byte ranges must be aligned on doubleword boundaries. I/O addresses are zero-extended (from 16 to 32 bits, for comparison with the breakpoint address in the selected debug register). These requirements are enforced by the processor; it uses LENn field bits to mask the lower address bits in the debug registers. Unaligned data or I/O breakpoint addresses do not yield valid results.
(emphasis added)
So, the limitation is in hardware.
Detailed explanation of why this happens:
Data breakpoints use the CPU's debug registers. On x86 these debug registers get aligned to their data size by masking the address' lower bits:
(addr & -2)
.(addr & -4)
.(addr & -8)
.When the x86 CPU access memory it compares the address by masking it in the same way to the debug register address and if the two are equal it triggers a breakpoint.
This is a trick to simplify the electronic circuit in the debug breakpoint comparator: Only the two aligned addresses need to be compared.
Electronically it translates to the pseudo-code:
if(!((address ^ debug_address) & debug_mask))
breakpoint();
Instead of:
if((address >= debug_address) & (address < debug_address_plus_length))
breakpoint();
Which would be much more complex to implement in silicon and slow down the CPU. Even in software the first one would run faster.
The address-masking trick works perfectly as long as all memory accesses are aligned.
So let's say p points to address 0xF02 and the breakpoint is 32bits (4 bytes), then the breakpoint address gets aligned to ((0xF02 & -4) == 0xF00)
.
note: -4 is 0xFFFFFFFC (32bits) or 0xFFFFFFFFFFFFFFFC (64bits)
You then access the address (0xF02+2 == 0xF04)
The CPU then masks 0xF04 ((0xF04 & -4) == 0xF04)
before comparing it to the debug breakpoint address (0xF00).
They don't match so the CPU does not trigger the breakpoint.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With