Have you ever needed to set a breakpoint on an entire module or memory region?
This is particularly useful if you want break on code execution in a module without specifying any function names directly. Let's say that between point A and point B, some code calls into module C, and corrupts its data.
In Visual Studio, you can set data breakpoints, which will break the debugger when a value changes. Very useful indeed, but you cannot break on a read access.
In the powerful Windbg, we are equipped with hardware breakpoints via the "ba" command (break on access), which works more or less the same as the page fault breakpoint I will explain. It has unfortunately a very strict limitation regarding the size. According to the documentation, the size can only be 1, 2 or 4 bytes, except when it concerns PAGE_EXECUTE, in that case the maximum size is 1 byte. This makes it harder to break over a large memory area.
In its strict sense, we are not going to set a breakpoint, but what we do can be used as a breakpoint, since we are making the debugger break on certain conditions which we can control.
What we will do is to change the access flag of memory pages, from PAGE_EXECUTE_* into PAGE_NOACCESS or PAGE_READONLY. When a function call is made into non-executable pages, it results in an access violation, which will break the debugger. At that point, you can inspect the callstack, variables, and memory regions. If you want to continue executing, you simply restore the access flag to its previous value, and tell the debugger to continue executing.
The same principle can be applied for data. Normally, memory pages where data is stored are marked PAGE_READWRITE. If you suspect memory corruption, you can simply mark the pages PAGE_READONLY, so whenever someone tries to modify the data, you will get an access violation.