mirror of https://github.com/x64dbg/GleeBug
Merge pull request #81 from mrexodia/breakpoint-lock
Fix race condition with breakpoint data structures
This commit is contained in:
commit
0ee4126a92
|
|
@ -5,6 +5,8 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
void Debugger::exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
|
void Debugger::exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
|
||||||
{
|
{
|
||||||
|
std::unique_lock<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
|
|
||||||
//check if the breakpoint exists
|
//check if the breakpoint exists
|
||||||
auto exceptionAddress = ptr(exceptionRecord.ExceptionAddress);
|
auto exceptionAddress = ptr(exceptionRecord.ExceptionAddress);
|
||||||
auto foundInfo = mProcess->breakpoints.find({ BreakpointType::Software, exceptionAddress });
|
auto foundInfo = mProcess->breakpoints.find({ BreakpointType::Software, exceptionAddress });
|
||||||
|
|
@ -17,6 +19,7 @@ namespace GleeBug
|
||||||
mContinueStatus = DBG_CONTINUE;
|
mContinueStatus = DBG_CONTINUE;
|
||||||
|
|
||||||
//call the callback
|
//call the callback
|
||||||
|
lock.unlock();
|
||||||
cbSystemBreakpoint();
|
cbSystemBreakpoint();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -50,6 +53,8 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
mProcess->StepInternal([this, info]()
|
mProcess->StepInternal([this, info]()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
|
|
||||||
//only restore the bytes if the breakpoint still exists
|
//only restore the bytes if the breakpoint still exists
|
||||||
auto foundBreakpoint = mProcess->breakpoints.find({ BreakpointType::Software, info.address });
|
auto foundBreakpoint = mProcess->breakpoints.find({ BreakpointType::Software, info.address });
|
||||||
if(foundBreakpoint != mProcess->breakpoints.end())
|
if(foundBreakpoint != mProcess->breakpoints.end())
|
||||||
|
|
@ -64,13 +69,18 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
BreakpointCallback breakpointCallback;
|
||||||
|
auto foundCallback = mProcess->breakpointCallbacks.find({ BreakpointType::Software, info.address });
|
||||||
|
if(foundCallback != mProcess->breakpointCallbacks.end())
|
||||||
|
breakpointCallback = foundCallback->second;
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
//call the generic callback
|
//call the generic callback
|
||||||
cbBreakpoint(info);
|
cbBreakpoint(info);
|
||||||
|
|
||||||
//call the user callback
|
//call the user callback
|
||||||
auto foundCallback = mProcess->breakpointCallbacks.find({ BreakpointType::Software, info.address });
|
if(breakpointCallback)
|
||||||
if(foundCallback != mProcess->breakpointCallbacks.end())
|
breakpointCallback(info);
|
||||||
foundCallback->second(info);
|
|
||||||
|
|
||||||
//delete the breakpoint if it is singleshoot
|
//delete the breakpoint if it is singleshoot
|
||||||
if(info.singleshoot)
|
if(info.singleshoot)
|
||||||
|
|
@ -85,9 +95,6 @@ namespace GleeBug
|
||||||
mThread->isInternalStepping = false;
|
mThread->isInternalStepping = false;
|
||||||
mContinueStatus = DBG_CONTINUE;
|
mContinueStatus = DBG_CONTINUE;
|
||||||
|
|
||||||
// Internal step callbacks can re-arm a memory-breakpoint page. Serialize
|
|
||||||
// that map access with concurrent set/delete transactions.
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(mProcess->memoryBreakpointMutex);
|
|
||||||
mThread->cbInternalStep();
|
mThread->cbInternalStep();
|
||||||
}
|
}
|
||||||
if(mThread->isSingleStepping) //handle single step
|
if(mThread->isSingleStepping) //handle single step
|
||||||
|
|
@ -142,6 +149,7 @@ namespace GleeBug
|
||||||
return; //not a hardware breakpoint
|
return; //not a hardware breakpoint
|
||||||
|
|
||||||
//find the breakpoint in the internal structures
|
//find the breakpoint in the internal structures
|
||||||
|
std::unique_lock<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
auto foundInfo = mProcess->breakpoints.find({ BreakpointType::Hardware, breakpointAddress });
|
auto foundInfo = mProcess->breakpoints.find({ BreakpointType::Hardware, breakpointAddress });
|
||||||
if(foundInfo == mProcess->breakpoints.end())
|
if(foundInfo == mProcess->breakpoints.end())
|
||||||
return; //not a valid hardware breakpoint
|
return; //not a valid hardware breakpoint
|
||||||
|
|
@ -156,21 +164,31 @@ namespace GleeBug
|
||||||
mThread->DeleteHardwareBreakpoint(breakpointSlot);
|
mThread->DeleteHardwareBreakpoint(breakpointSlot);
|
||||||
mProcess->StepInternal([this, info]()
|
mProcess->StepInternal([this, info]()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
|
|
||||||
//only restore if the breakpoint still exists
|
//only restore if the breakpoint still exists
|
||||||
if(mProcess->breakpoints.find({ BreakpointType::Hardware, info.address }) != mProcess->breakpoints.end())
|
if(mProcess->breakpoints.find({ BreakpointType::Hardware, info.address }) != mProcess->breakpoints.end())
|
||||||
mThread->SetHardwareBreakpoint(info.address, info.internal.hardware.slot, info.internal.hardware.type, info.internal.hardware.size);
|
mThread->SetHardwareBreakpoint(info.address, info.internal.hardware.slot, info.internal.hardware.type, info.internal.hardware.size);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
BreakpointCallback breakpointCallback;
|
||||||
|
auto foundCallback = mProcess->breakpointCallbacks.find({ BreakpointType::Hardware, info.address });
|
||||||
|
if(foundCallback != mProcess->breakpointCallbacks.end())
|
||||||
|
breakpointCallback = foundCallback->second;
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
//call the generic callback
|
//call the generic callback
|
||||||
cbBreakpoint(info);
|
cbBreakpoint(info);
|
||||||
|
|
||||||
//call the user callback
|
//call the user callback
|
||||||
auto foundCallback = mProcess->breakpointCallbacks.find({ BreakpointType::Hardware, info.address });
|
if(breakpointCallback)
|
||||||
if(foundCallback != mProcess->breakpointCallbacks.end())
|
breakpointCallback(info);
|
||||||
foundCallback->second(info);
|
|
||||||
|
|
||||||
//if the breakpoint was deleted during callback, clear internal stepping to prevent thread suspension
|
//if the breakpoint was deleted during callback, clear internal stepping to prevent thread suspension
|
||||||
if(mProcess->breakpoints.find({ BreakpointType::Hardware, info.address }) == mProcess->breakpoints.end())
|
lock.lock();
|
||||||
|
const bool breakpointDeleted = mProcess->breakpoints.find({ BreakpointType::Hardware, info.address }) == mProcess->breakpoints.end();
|
||||||
|
lock.unlock();
|
||||||
|
if(breakpointDeleted)
|
||||||
{
|
{
|
||||||
mThread->isInternalStepping = false;
|
mThread->isInternalStepping = false;
|
||||||
Registers(mThread->hThread, CONTEXT_CONTROL).TrapFlag = false;
|
Registers(mThread->hThread, CONTEXT_CONTROL).TrapFlag = false;
|
||||||
|
|
@ -185,13 +203,22 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
// Page protections are changed before set/delete publishes its metadata.
|
// Page protections are changed before set/delete publishes its metadata.
|
||||||
// Wait for the transaction before classifying this memory-breakpoint fault.
|
// Wait for the transaction before classifying this memory-breakpoint fault.
|
||||||
std::unique_lock<std::recursive_mutex> lock(mProcess->memoryBreakpointMutex);
|
std::unique_lock<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ASSUME:
|
ASSUME:
|
||||||
exceptionAddress may or may not have been generated by your breakpoints.
|
exceptionAddress may or may not have been generated by your breakpoints.
|
||||||
*/
|
*/
|
||||||
char error[128] = "";
|
char error[128] = "";
|
||||||
|
auto reportError = [&]()
|
||||||
|
{
|
||||||
|
const bool relock = lock.owns_lock();
|
||||||
|
if(relock)
|
||||||
|
lock.unlock();
|
||||||
|
cbInternalError(error);
|
||||||
|
if(relock)
|
||||||
|
lock.lock();
|
||||||
|
};
|
||||||
auto exceptionAddress = ptr(exceptionRecord.ExceptionInformation[1]);
|
auto exceptionAddress = ptr(exceptionRecord.ExceptionInformation[1]);
|
||||||
|
|
||||||
//check if the exception address is directly in the range of a memory breakpoint
|
//check if the exception address is directly in the range of a memory breakpoint
|
||||||
|
|
@ -212,7 +239,7 @@ namespace GleeBug
|
||||||
if(!mProcess->MemProtect(foundPage->first, PAGE_SIZE, foundPage->second.OldProtect))
|
if(!mProcess->MemProtect(foundPage->first, PAGE_SIZE, foundPage->second.OldProtect))
|
||||||
{
|
{
|
||||||
sprintf_s(error, "MemProtect failed on 0x%p", (void*)foundPage->first);
|
sprintf_s(error, "MemProtect failed on 0x%p", (void*)foundPage->first);
|
||||||
cbInternalError(error);
|
reportError();
|
||||||
}
|
}
|
||||||
|
|
||||||
//However the following situations may occur:
|
//However the following situations may occur:
|
||||||
|
|
@ -223,6 +250,8 @@ namespace GleeBug
|
||||||
// then we ought to restore the protection.
|
// then we ought to restore the protection.
|
||||||
mProcess->StepInternal([this, pBaseAddr]()
|
mProcess->StepInternal([this, pBaseAddr]()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
|
|
||||||
//seek out the page address
|
//seek out the page address
|
||||||
auto found_page = mProcess->memoryBreakpointPages.find(pBaseAddr);
|
auto found_page = mProcess->memoryBreakpointPages.find(pBaseAddr);
|
||||||
if(found_page == mProcess->memoryBreakpointPages.end())
|
if(found_page == mProcess->memoryBreakpointPages.end())
|
||||||
|
|
@ -245,7 +274,7 @@ namespace GleeBug
|
||||||
if(foundInfo == mProcess->breakpoints.end())
|
if(foundInfo == mProcess->breakpoints.end())
|
||||||
{
|
{
|
||||||
sprintf_s(error, "inconsistent memory breakpoint at 0x%p", (void*)exceptionAddress);
|
sprintf_s(error, "inconsistent memory breakpoint at 0x%p", (void*)exceptionAddress);
|
||||||
cbInternalError(error);
|
reportError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,7 +289,7 @@ namespace GleeBug
|
||||||
if(bpxPage == mProcess->memoryBreakpointPages.end())
|
if(bpxPage == mProcess->memoryBreakpointPages.end())
|
||||||
{
|
{
|
||||||
sprintf_s(error, "Process::memoryBreakPointPages data structure is incosistent, should dump page at 0x%p", (void*)(exceptionAddress & ~(PAGE_SIZE - 1)));
|
sprintf_s(error, "Process::memoryBreakPointPages data structure is incosistent, should dump page at 0x%p", (void*)(exceptionAddress & ~(PAGE_SIZE - 1)));
|
||||||
cbInternalError(error);
|
reportError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto pageAddr = bpxPage->first;
|
auto pageAddr = bpxPage->first;
|
||||||
|
|
@ -284,11 +313,13 @@ namespace GleeBug
|
||||||
if(!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
if(!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
||||||
{
|
{
|
||||||
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
|
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
|
||||||
cbInternalError(error);
|
reportError();
|
||||||
}
|
}
|
||||||
|
|
||||||
mProcess->StepInternal([this, pageAddr]()
|
mProcess->StepInternal([this, pageAddr]()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
|
|
||||||
auto found_page = mProcess->memoryBreakpointPages.find(pageAddr);
|
auto found_page = mProcess->memoryBreakpointPages.find(pageAddr);
|
||||||
if(found_page == mProcess->memoryBreakpointPages.end())
|
if(found_page == mProcess->memoryBreakpointPages.end())
|
||||||
return;
|
return;
|
||||||
|
|
@ -328,11 +359,13 @@ namespace GleeBug
|
||||||
if(!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
if(!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
||||||
{
|
{
|
||||||
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
|
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
|
||||||
cbInternalError(error);
|
reportError();
|
||||||
}
|
}
|
||||||
//Pass info as well
|
//Pass info as well
|
||||||
mProcess->StepInternal([this, pageAddr]()
|
mProcess->StepInternal([this, pageAddr]()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
|
|
||||||
//With page check this should work better: So when we reach this part of the code we are sure that:
|
//With page check this should work better: So when we reach this part of the code we are sure that:
|
||||||
//-The exception Address In deed corresponded to an existing (now possibly deleted) memory breakpoint range
|
//-The exception Address In deed corresponded to an existing (now possibly deleted) memory breakpoint range
|
||||||
//-memoryBreakpointPages was in deed consistent with this memory address that generated the exception (The data structure wasn't corrupted somehow)
|
//-memoryBreakpointPages was in deed consistent with this memory address that generated the exception (The data structure wasn't corrupted somehow)
|
||||||
|
|
@ -364,13 +397,22 @@ namespace GleeBug
|
||||||
|
|
||||||
void Debugger::exceptionAccessViolation(const EXCEPTION_RECORD & exceptionRecord, bool firstChance)
|
void Debugger::exceptionAccessViolation(const EXCEPTION_RECORD & exceptionRecord, bool firstChance)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::recursive_mutex> lock(mProcess->memoryBreakpointMutex);
|
std::unique_lock<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ASSUME:
|
ASSUME:
|
||||||
exceptionAddress may or may not have been generated by your breakpoints.
|
exceptionAddress may or may not have been generated by your breakpoints.
|
||||||
*/
|
*/
|
||||||
char error[128] = "";
|
char error[128] = "";
|
||||||
|
auto reportError = [&]()
|
||||||
|
{
|
||||||
|
const bool relock = lock.owns_lock();
|
||||||
|
if(relock)
|
||||||
|
lock.unlock();
|
||||||
|
cbInternalError(error);
|
||||||
|
if(relock)
|
||||||
|
lock.lock();
|
||||||
|
};
|
||||||
auto exceptionAddress = ptr(exceptionRecord.ExceptionInformation[1]);
|
auto exceptionAddress = ptr(exceptionRecord.ExceptionInformation[1]);
|
||||||
|
|
||||||
//check if the exception address is directly in the range of a memory breakpoint
|
//check if the exception address is directly in the range of a memory breakpoint
|
||||||
|
|
@ -391,7 +433,7 @@ namespace GleeBug
|
||||||
if(!mProcess->MemProtect(foundPage->first, PAGE_SIZE, foundPage->second.OldProtect))
|
if(!mProcess->MemProtect(foundPage->first, PAGE_SIZE, foundPage->second.OldProtect))
|
||||||
{
|
{
|
||||||
sprintf_s(error, "MemProtect failed on 0x%p", (void*)foundPage->first);
|
sprintf_s(error, "MemProtect failed on 0x%p", (void*)foundPage->first);
|
||||||
cbInternalError(error);
|
reportError();
|
||||||
}
|
}
|
||||||
|
|
||||||
//However the following situations may occur:
|
//However the following situations may occur:
|
||||||
|
|
@ -402,6 +444,8 @@ namespace GleeBug
|
||||||
// then we ought to restore the protection.
|
// then we ought to restore the protection.
|
||||||
mProcess->StepInternal([this, pBaseAddr]()
|
mProcess->StepInternal([this, pBaseAddr]()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
|
|
||||||
//seek out the page address
|
//seek out the page address
|
||||||
auto found_page = mProcess->memoryBreakpointPages.find(pBaseAddr);
|
auto found_page = mProcess->memoryBreakpointPages.find(pBaseAddr);
|
||||||
if(found_page == mProcess->memoryBreakpointPages.end())
|
if(found_page == mProcess->memoryBreakpointPages.end())
|
||||||
|
|
@ -424,7 +468,7 @@ namespace GleeBug
|
||||||
if(foundInfo == mProcess->breakpoints.end())
|
if(foundInfo == mProcess->breakpoints.end())
|
||||||
{
|
{
|
||||||
sprintf_s(error, "inconsistent memory breakpoint at 0x%p", (void*)exceptionAddress);
|
sprintf_s(error, "inconsistent memory breakpoint at 0x%p", (void*)exceptionAddress);
|
||||||
cbInternalError(error);
|
reportError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -439,7 +483,7 @@ namespace GleeBug
|
||||||
if(bpxPage == mProcess->memoryBreakpointPages.end())
|
if(bpxPage == mProcess->memoryBreakpointPages.end())
|
||||||
{
|
{
|
||||||
sprintf_s(error, "Process::memoryBreakPointPages data structure is incosistent, should dump page at 0x%p", (void*)(exceptionAddress & ~(PAGE_SIZE - 1)));
|
sprintf_s(error, "Process::memoryBreakPointPages data structure is incosistent, should dump page at 0x%p", (void*)(exceptionAddress & ~(PAGE_SIZE - 1)));
|
||||||
cbInternalError(error);
|
reportError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto pageAddr = bpxPage->first;
|
auto pageAddr = bpxPage->first;
|
||||||
|
|
@ -474,7 +518,7 @@ namespace GleeBug
|
||||||
if(!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
if(!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
||||||
{
|
{
|
||||||
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
|
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
|
||||||
cbInternalError(error);
|
reportError();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The page-wide protection belongs to another range. Execute this
|
// The page-wide protection belongs to another range. Execute this
|
||||||
|
|
@ -482,6 +526,8 @@ namespace GleeBug
|
||||||
// any memory breakpoint still owns it.
|
// any memory breakpoint still owns it.
|
||||||
mProcess->StepInternal([this, pageAddr]()
|
mProcess->StepInternal([this, pageAddr]()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
|
|
||||||
auto foundPage = mProcess->memoryBreakpointPages.find(pageAddr);
|
auto foundPage = mProcess->memoryBreakpointPages.find(pageAddr);
|
||||||
if(foundPage != mProcess->memoryBreakpointPages.end())
|
if(foundPage != mProcess->memoryBreakpointPages.end())
|
||||||
mProcess->MemProtect(pageAddr, PAGE_SIZE, foundPage->second.NewProtect);
|
mProcess->MemProtect(pageAddr, PAGE_SIZE, foundPage->second.NewProtect);
|
||||||
|
|
@ -513,11 +559,13 @@ namespace GleeBug
|
||||||
if(!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
if(!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
||||||
{
|
{
|
||||||
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
|
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
|
||||||
cbInternalError(error);
|
reportError();
|
||||||
}
|
}
|
||||||
//Pass info as well
|
//Pass info as well
|
||||||
mProcess->StepInternal([this, pageAddr]()
|
mProcess->StepInternal([this, pageAddr]()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
|
|
||||||
//With page check this should work better: So when we reach this part of the code we are sure that:
|
//With page check this should work better: So when we reach this part of the code we are sure that:
|
||||||
//-The exception Address In deed corresponded to an existing (now possibly deleted) memory breakpoint range
|
//-The exception Address In deed corresponded to an existing (now possibly deleted) memory breakpoint range
|
||||||
//-memoryBreakpointPages was in deed consistent with this memory address that generated the exception (The data structure wasn't corrupted somehow)
|
//-memoryBreakpointPages was in deed consistent with this memory address that generated the exception (The data structure wasn't corrupted somehow)
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,10 @@ namespace GleeBug
|
||||||
// single-step event arrives.
|
// single-step event arrives.
|
||||||
consecutiveTimeouts++;
|
consecutiveTimeouts++;
|
||||||
if(consecutiveTimeouts >= 2 && ThreadBeingProcessed == 0 && SuspendedThreads.empty() && DeferredExceptionThreads.empty() && mProcess)
|
if(consecutiveTimeouts >= 2 && ThreadBeingProcessed == 0 && SuspendedThreads.empty() && DeferredExceptionThreads.empty() && mProcess)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
mProcess->recentlyDeletedSwbp.clear();
|
mProcess->recentlyDeletedSwbp.clear();
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
bool Process::SetBreakpoint(ptr address, bool singleshoot, SoftwareType type)
|
bool Process::SetBreakpoint(ptr address, bool singleshoot, SoftwareType type)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(breakpointMutex);
|
||||||
|
|
||||||
//check the address
|
//check the address
|
||||||
if(!MemIsValidPtr(address) ||
|
if(!MemIsValidPtr(address) ||
|
||||||
breakpoints.find({ BreakpointType::Software, address }) != breakpoints.end())
|
breakpoints.find({ BreakpointType::Software, address }) != breakpoints.end())
|
||||||
|
|
@ -44,6 +46,8 @@ namespace GleeBug
|
||||||
|
|
||||||
bool Process::SetBreakpoint(ptr address, const BreakpointCallback & cbBreakpoint, bool singleshoot, SoftwareType type)
|
bool Process::SetBreakpoint(ptr address, const BreakpointCallback & cbBreakpoint, bool singleshoot, SoftwareType type)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(breakpointMutex);
|
||||||
|
|
||||||
//check if a callback on this address was already found
|
//check if a callback on this address was already found
|
||||||
if(breakpointCallbacks.find({ BreakpointType::Software, address }) != breakpointCallbacks.end())
|
if(breakpointCallbacks.find({ BreakpointType::Software, address }) != breakpointCallbacks.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -57,6 +61,8 @@ namespace GleeBug
|
||||||
|
|
||||||
bool Process::DeleteBreakpoint(ptr address)
|
bool Process::DeleteBreakpoint(ptr address)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(breakpointMutex);
|
||||||
|
|
||||||
//find the breakpoint
|
//find the breakpoint
|
||||||
auto found = breakpoints.find({ BreakpointType::Software, address });
|
auto found = breakpoints.find({ BreakpointType::Software, address });
|
||||||
if(found == breakpoints.end())
|
if(found == breakpoints.end())
|
||||||
|
|
@ -79,6 +85,8 @@ namespace GleeBug
|
||||||
|
|
||||||
bool Process::GetFreeHardwareBreakpointSlot(HardwareSlot & slot) const
|
bool Process::GetFreeHardwareBreakpointSlot(HardwareSlot & slot) const
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(breakpointMutex);
|
||||||
|
|
||||||
//find a free hardware breakpoint slot
|
//find a free hardware breakpoint slot
|
||||||
for(int i = 0; i < HWBP_COUNT; i++)
|
for(int i = 0; i < HWBP_COUNT; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -93,6 +101,8 @@ namespace GleeBug
|
||||||
|
|
||||||
bool Process::SetHardwareBreakpoint(ptr address, HardwareSlot slot, HardwareType type, HardwareSize size, bool singleshoot)
|
bool Process::SetHardwareBreakpoint(ptr address, HardwareSlot slot, HardwareType type, HardwareSize size, bool singleshoot)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(breakpointMutex);
|
||||||
|
|
||||||
//check the address
|
//check the address
|
||||||
if(!MemIsValidPtr(address) ||
|
if(!MemIsValidPtr(address) ||
|
||||||
breakpoints.find({ BreakpointType::Hardware, address }) != breakpoints.end())
|
breakpoints.find({ BreakpointType::Hardware, address }) != breakpoints.end())
|
||||||
|
|
@ -138,6 +148,8 @@ namespace GleeBug
|
||||||
|
|
||||||
bool Process::SetHardwareBreakpoint(ptr address, HardwareSlot slot, const BreakpointCallback & cbBreakpoint, HardwareType type, HardwareSize size, bool singleshoot)
|
bool Process::SetHardwareBreakpoint(ptr address, HardwareSlot slot, const BreakpointCallback & cbBreakpoint, HardwareType type, HardwareSize size, bool singleshoot)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(breakpointMutex);
|
||||||
|
|
||||||
//check if a callback on this address was already found
|
//check if a callback on this address was already found
|
||||||
if(breakpointCallbacks.find({ BreakpointType::Hardware, address }) != breakpointCallbacks.end())
|
if(breakpointCallbacks.find({ BreakpointType::Hardware, address }) != breakpointCallbacks.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -151,6 +163,8 @@ namespace GleeBug
|
||||||
|
|
||||||
bool Process::DeleteHardwareBreakpoint(ptr address)
|
bool Process::DeleteHardwareBreakpoint(ptr address)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(breakpointMutex);
|
||||||
|
|
||||||
//find the hardware breakpoint
|
//find the hardware breakpoint
|
||||||
auto found = breakpoints.find({ BreakpointType::Hardware, address });
|
auto found = breakpoints.find({ BreakpointType::Hardware, address });
|
||||||
if(found == breakpoints.end())
|
if(found == breakpoints.end())
|
||||||
|
|
@ -369,7 +383,7 @@ namespace GleeBug
|
||||||
|
|
||||||
bool Process::SetMemoryBreakpoint(ptr address, ptr size, MemoryType type, bool singleshoot)
|
bool Process::SetMemoryBreakpoint(ptr address, ptr size, MemoryType type, bool singleshoot)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(memoryBreakpointMutex);
|
std::lock_guard<std::recursive_mutex> lock(breakpointMutex);
|
||||||
DPRINTF();
|
DPRINTF();
|
||||||
|
|
||||||
// Basic checks, including the range-end overflow that would otherwise wrap
|
// Basic checks, including the range-end overflow that would otherwise wrap
|
||||||
|
|
@ -458,7 +472,7 @@ namespace GleeBug
|
||||||
|
|
||||||
bool Process::SetMemoryBreakpoint(ptr address, ptr size, const BreakpointCallback & cbBreakpoint, MemoryType type, bool singleshoot)
|
bool Process::SetMemoryBreakpoint(ptr address, ptr size, const BreakpointCallback & cbBreakpoint, MemoryType type, bool singleshoot)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(memoryBreakpointMutex);
|
std::lock_guard<std::recursive_mutex> lock(breakpointMutex);
|
||||||
|
|
||||||
//check if a callback on this address was already found
|
//check if a callback on this address was already found
|
||||||
if(breakpointCallbacks.find({ BreakpointType::Memory, address }) != breakpointCallbacks.end())
|
if(breakpointCallbacks.find({ BreakpointType::Memory, address }) != breakpointCallbacks.end())
|
||||||
|
|
@ -473,7 +487,7 @@ namespace GleeBug
|
||||||
|
|
||||||
bool Process::DeleteMemoryBreakpoint(ptr address)
|
bool Process::DeleteMemoryBreakpoint(ptr address)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(memoryBreakpointMutex);
|
std::lock_guard<std::recursive_mutex> lock(breakpointMutex);
|
||||||
|
|
||||||
// Find the byte range containing address, then find its breakpoint record.
|
// Find the byte range containing address, then find its breakpoint record.
|
||||||
const auto range = memoryBreakpointRanges.find(Range(address, address));
|
const auto range = memoryBreakpointRanges.find(Range(address, address));
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ namespace GleeBug
|
||||||
|
|
||||||
bool Process::MemReadSafe(ptr address, void* buffer, ptr size, ptr* bytesRead) const
|
bool Process::MemReadSafe(ptr address, void* buffer, ptr size, ptr* bytesRead) const
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(breakpointMutex);
|
||||||
|
|
||||||
if(!MemReadUnsafe(address, buffer, size, bytesRead))
|
if(!MemReadUnsafe(address, buffer, size, bytesRead))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -65,6 +67,8 @@ namespace GleeBug
|
||||||
|
|
||||||
bool Process::MemWriteSafe(ptr address, const void* buffer, ptr size, ptr* bytesWritten)
|
bool Process::MemWriteSafe(ptr address, const void* buffer, ptr size, ptr* bytesWritten)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(breakpointMutex);
|
||||||
|
|
||||||
if(size == 0)
|
if(size == 0)
|
||||||
{
|
{
|
||||||
if(bytesWritten)
|
if(bytesWritten)
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ namespace GleeBug
|
||||||
BreakpointInfo hardwareBreakpoints[4];
|
BreakpointInfo hardwareBreakpoints[4];
|
||||||
MemoryBreakpointSet memoryBreakpointRanges;
|
MemoryBreakpointSet memoryBreakpointRanges;
|
||||||
MemoryBreakpointMap memoryBreakpointPages;
|
MemoryBreakpointMap memoryBreakpointPages;
|
||||||
std::recursive_mutex memoryBreakpointMutex;
|
mutable std::recursive_mutex breakpointMutex;
|
||||||
|
|
||||||
std::unordered_set<ptr> recentlyDeletedSwbp;
|
std::unordered_set<ptr> recentlyDeletedSwbp;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,8 @@ retry_no_aslr:
|
||||||
|
|
||||||
if(mProcess)
|
if(mProcess)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
|
|
||||||
// 1. Restore all software (INT3) breakpoints, otherwise the debuggee
|
// 1. Restore all software (INT3) breakpoints, otherwise the debuggee
|
||||||
// faults on a leftover 0xCC once it is no longer being debugged.
|
// faults on a leftover 0xCC once it is no longer being debugged.
|
||||||
for(auto it = mProcess->breakpoints.begin(); it != mProcess->breakpoints.end(); )
|
for(auto it = mProcess->breakpoints.begin(); it != mProcess->breakpoints.end(); )
|
||||||
|
|
|
||||||
|
|
@ -793,6 +793,7 @@ public:
|
||||||
|
|
||||||
bool IsBPXEnabled(ULONG_PTR bpxAddress)
|
bool IsBPXEnabled(ULONG_PTR bpxAddress)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
return (mProcess->MemIsValidPtr(bpxAddress) &&
|
return (mProcess->MemIsValidPtr(bpxAddress) &&
|
||||||
mProcess->breakpoints.find({ BreakpointType::Software, bpxAddress }) != mProcess->breakpoints.end());
|
mProcess->breakpoints.find({ BreakpointType::Software, bpxAddress }) != mProcess->breakpoints.end());
|
||||||
}
|
}
|
||||||
|
|
@ -854,7 +855,11 @@ public:
|
||||||
auto slot = IndexOfRegister - UE_DR0;
|
auto slot = IndexOfRegister - UE_DR0;
|
||||||
if(!mProcess || slot > 3)
|
if(!mProcess || slot > 3)
|
||||||
return false;
|
return false;
|
||||||
auto address = mProcess->hardwareBreakpoints[slot].address;
|
ptr address;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mProcess->breakpointMutex);
|
||||||
|
address = mProcess->hardwareBreakpoints[slot].address;
|
||||||
|
}
|
||||||
return mProcess->DeleteHardwareBreakpoint(address);
|
return mProcess->DeleteHardwareBreakpoint(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -874,7 +879,11 @@ public:
|
||||||
{
|
{
|
||||||
for(auto & it : mProcesses)
|
for(auto & it : mProcesses)
|
||||||
{
|
{
|
||||||
auto breakpoints = it.second->breakpoints; //explicit copy
|
BreakpointMap breakpoints;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(it.second->breakpointMutex);
|
||||||
|
breakpoints = it.second->breakpoints;
|
||||||
|
}
|
||||||
for(const auto & jt : breakpoints)
|
for(const auto & jt : breakpoints)
|
||||||
it.second->DeleteGenericBreakpoint(jt.second);
|
it.second->DeleteGenericBreakpoint(jt.second);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue