Restore PAGE_GUARD memory breakpoints properly

This commit is contained in:
Duncan Ogilvie 2026-04-13 11:40:26 +02:00
parent 2cc003cdcf
commit e0a457965f
1 changed files with 25 additions and 46 deletions

View File

@ -260,16 +260,20 @@ namespace GleeBug
auto pageAddr = bpxPage->first;
auto pageProperties = bpxPage->second;
//TODO: If I only have a page with Read bp and the exception was not on read, I don't execute the callback. Because since this was implemented with PAGE_GUARD, writtes or executes still trigger
//This callback.
//FIX: If the memoryBreakpointPages for this page does not have a access flag and has a read flag, but the exception was not on read. Then we resume the debuggee.
if((exceptionRecord.ExceptionInformation[0] != 0))
{
//The bpx is solely on read.
if(((pageProperties.Type & 0x2) != 0) && ((pageProperties.Type & 0x1) == 0))
// PAGE_GUARD is shared by access/read/write/execute breakpoints, so the exception type in
// ExceptionInformation[0] decides whether this guard-page fault actually belongs to this breakpoint.
// Access breakpoints intentionally match every access type.
const auto accessType = exceptionRecord.ExceptionInformation[0];
const auto isAccessBreakpoint = (pageProperties.Type & 0x1) != 0;
const auto matchesRead = accessType == 0 && (((pageProperties.Type & 0x2) != 0) || isAccessBreakpoint);
const auto matchesWrite = accessType == 1 && (((pageProperties.Type & 0x4) != 0) || isAccessBreakpoint);
const auto matchesExecute = accessType == 8 && (((pageProperties.Type & 0x8) != 0) || isAccessBreakpoint);
if(!matchesRead && !matchesWrite && !matchesExecute)
{
mContinueStatus = DBG_CONTINUE;
//We restore the protection
// This page belongs to some memory breakpoint, but not one that should trigger on this access type.
// Restore the original protection, single-step the faulting instruction, then re-apply the guard/page
// permissions if the page is still tracked by any memory breakpoint.
if(!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
{
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
@ -278,39 +282,14 @@ namespace GleeBug
mProcess->StepInternal([this, pageAddr]()
{
//seek out the page address
auto found_page = mProcess->memoryBreakpointPages.find(pageAddr);
if(found_page == mProcess->memoryBreakpointPages.end())
{
//no page being used by bpx? Then just return
return;
}
mProcess->MemProtect(pageAddr, PAGE_SIZE, found_page->second.NewProtect);
return;
});
return;
}
else if(((pageProperties.Type & 0x1) != 0))
{
//We are fine if the breakpoint is on Access and somethine other than a read occurred.
}
else
{
//This exception handler was called within a page that had no breakpoints on read or access. Probably the program generated this exception! what a 0x1337 brat.
//In this situation we return control to debuggee.
return;
}
}
else
{
//The generated exception is on read.
//If the page doesn't have a breakpoint on read or on access then something else must have gone wrong - we pass execution to debuggee.
if((!(pageProperties.Type & 0x2)) && (!(pageProperties.Type & 0x1)))
{
return;
}
}
/*