mirror of https://github.com/x64dbg/GleeBug
lazily read/write context for all threads
This commit is contained in:
parent
732abb9ce9
commit
6c6e181ff5
|
|
@ -44,8 +44,6 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
mThread = mProcess->thread = &threadFound->second;
|
mThread = mProcess->thread = &threadFound->second;
|
||||||
mRegisters = &mThread->registers;
|
mRegisters = &mThread->registers;
|
||||||
if (!mThread->RegReadContext())
|
|
||||||
cbInternalError("ThreadInfo::RegReadContext() failed!");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -64,6 +62,10 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//read register contexts
|
||||||
|
if(mProcess && !mProcess->RegReadContext())
|
||||||
|
cbInternalError("Process::RegReadContext() failed!");
|
||||||
|
|
||||||
//call the pre debug event callback
|
//call the pre debug event callback
|
||||||
cbPreDebugEvent(mDebugEvent);
|
cbPreDebugEvent(mDebugEvent);
|
||||||
|
|
||||||
|
|
@ -120,12 +122,9 @@ namespace GleeBug
|
||||||
mThread->registers.TrapFlag = false;
|
mThread->registers.TrapFlag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//write the register context
|
//write register contexts
|
||||||
if (mThread)
|
if(mProcess && !mProcess->RegWriteContext())
|
||||||
{
|
cbInternalError("Process::RegWriteContext() failed!");
|
||||||
if (!mThread->RegWriteContext())
|
|
||||||
cbInternalError("ThreadInfo::RegWriteContext() failed!");
|
|
||||||
}
|
|
||||||
|
|
||||||
//continue the debug event
|
//continue the debug event
|
||||||
if (!ContinueDebugEvent(mDebugEvent.dwProcessId, mDebugEvent.dwThreadId, mContinueStatus))
|
if (!ContinueDebugEvent(mDebugEvent.dwProcessId, mDebugEvent.dwThreadId, mContinueStatus))
|
||||||
|
|
|
||||||
|
|
@ -394,6 +394,24 @@ namespace GleeBug
|
||||||
StepOver(std::bind(callback, debugger));
|
StepOver(std::bind(callback, debugger));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RegReadContext()
|
||||||
|
{
|
||||||
|
auto result = true;
|
||||||
|
for(auto & thread : this->threads)
|
||||||
|
if(!thread.second.RegReadContext())
|
||||||
|
result = false;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RegWriteContext()
|
||||||
|
{
|
||||||
|
auto result = true;
|
||||||
|
for(auto & thread : this->threads)
|
||||||
|
if(!thread.second.RegWriteContext())
|
||||||
|
result = false;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Capstone mCapstone;
|
Capstone mCapstone;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,10 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
ptr Registers::Get(R reg) const
|
ptr Registers::Get(R reg)
|
||||||
{
|
{
|
||||||
|
handleLazyContext();
|
||||||
|
|
||||||
switch (reg)
|
switch (reg)
|
||||||
{
|
{
|
||||||
case R::DR0:
|
case R::DR0:
|
||||||
|
|
@ -244,6 +246,8 @@ namespace GleeBug
|
||||||
|
|
||||||
void Registers::Set(R reg, ptr value)
|
void Registers::Set(R reg, ptr value)
|
||||||
{
|
{
|
||||||
|
handleLazyContext();
|
||||||
|
|
||||||
switch (reg)
|
switch (reg)
|
||||||
{
|
{
|
||||||
case R::DR0:
|
case R::DR0:
|
||||||
|
|
@ -513,21 +517,27 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Registers::GetFlag(F flag) const
|
bool Registers::GetFlag(F flag)
|
||||||
{
|
{
|
||||||
|
handleLazyContext();
|
||||||
|
|
||||||
return (mContext.EFlags & ptr(flag)) == ptr(flag);
|
return (mContext.EFlags & ptr(flag)) == ptr(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Registers::SetFlag(F flag, bool set)
|
void Registers::SetFlag(F flag, bool set)
|
||||||
{
|
{
|
||||||
|
handleLazyContext();
|
||||||
|
|
||||||
if (set)
|
if (set)
|
||||||
mContext.EFlags |= ptr(flag);
|
mContext.EFlags |= ptr(flag);
|
||||||
else
|
else
|
||||||
mContext.EFlags &= ~ptr(flag);
|
mContext.EFlags &= ~ptr(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Registers::getPtr(R reg) const
|
void* Registers::getPtr(R reg)
|
||||||
{
|
{
|
||||||
|
handleLazyContext();
|
||||||
|
|
||||||
switch (reg)
|
switch (reg)
|
||||||
{
|
{
|
||||||
case R::DR0:
|
case R::DR0:
|
||||||
|
|
|
||||||
|
|
@ -102,13 +102,45 @@ namespace GleeBug
|
||||||
memset(&this->mContext, 0, sizeof(CONTEXT));
|
memset(&this->mContext, 0, sizeof(CONTEXT));
|
||||||
}
|
}
|
||||||
|
|
||||||
const CONTEXT* Registers::GetContext() const
|
const CONTEXT* Registers::GetContext()
|
||||||
{
|
{
|
||||||
|
handleLazyContext();
|
||||||
return &mContext;
|
return &mContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Registers::SetContext(const CONTEXT & context)
|
void Registers::SetContext(const CONTEXT & context)
|
||||||
{
|
{
|
||||||
|
handleLazyContext();
|
||||||
this->mContext = context;
|
this->mContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Registers::setContextLazy(CONTEXT* oldContext, HANDLE hThread)
|
||||||
|
{
|
||||||
|
this->mLazyOldContext = oldContext;
|
||||||
|
this->mLazyThread = hThread;
|
||||||
|
this->mLazySet = true;
|
||||||
|
this->mContext = *this->mLazyOldContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Registers::handleLazyContext()
|
||||||
|
{
|
||||||
|
if(!this->mLazySet)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(!this->mLazyOldContext || !this->mLazyThread) //assert
|
||||||
|
__debugbreak();
|
||||||
|
|
||||||
|
//TODO: handle failure of GetThreadContext
|
||||||
|
auto result = false;
|
||||||
|
if(GetThreadContext(this->mLazyThread, this->mLazyOldContext))
|
||||||
|
{
|
||||||
|
this->mContext = *this->mLazyOldContext;
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->mLazyOldContext = nullptr;
|
||||||
|
this->mLazyThread = nullptr;
|
||||||
|
this->mLazySet = false;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -11,6 +11,7 @@ namespace GleeBug
|
||||||
class Registers
|
class Registers
|
||||||
{
|
{
|
||||||
friend class Register;
|
friend class Register;
|
||||||
|
friend class Thread;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
|
@ -123,7 +124,7 @@ namespace GleeBug
|
||||||
\param reg The register to get.
|
\param reg The register to get.
|
||||||
\return The register value.
|
\return The register value.
|
||||||
*/
|
*/
|
||||||
ptr Get(R reg) const;
|
ptr Get(R reg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Sets a given register.
|
\brief Sets a given register.
|
||||||
|
|
@ -137,7 +138,7 @@ namespace GleeBug
|
||||||
\param flag The flag to get.
|
\param flag The flag to get.
|
||||||
\return true if the flag is set, false otherwise.
|
\return true if the flag is set, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool GetFlag(F flag) const;
|
bool GetFlag(F flag);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Sets a flag.
|
\brief Sets a flag.
|
||||||
|
|
@ -149,7 +150,7 @@ namespace GleeBug
|
||||||
\brief Gets a pointer to the context object.
|
\brief Gets a pointer to the context object.
|
||||||
\return This function will never return a nullptr.
|
\return This function will never return a nullptr.
|
||||||
*/
|
*/
|
||||||
const CONTEXT* GetContext() const;
|
const CONTEXT* GetContext();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Sets the CONTEXT.
|
\brief Sets the CONTEXT.
|
||||||
|
|
@ -160,7 +161,24 @@ namespace GleeBug
|
||||||
private:
|
private:
|
||||||
CONTEXT mContext;
|
CONTEXT mContext;
|
||||||
|
|
||||||
void* getPtr(R reg) const;
|
CONTEXT* mLazyOldContext = nullptr;
|
||||||
|
HANDLE mLazyThread = nullptr;
|
||||||
|
bool mLazySet = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Lazily set CONTEXT. This will only actually retrieve the context if a function in this thread is called.
|
||||||
|
\param oldContext Pointer to the old context, used to determine if updates are required.
|
||||||
|
\param hThread Handle of the thread to get the context from if required.
|
||||||
|
*/
|
||||||
|
void setContextLazy(CONTEXT* oldContext, HANDLE hThread);
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Retrieve the actual context if setContextLazy has been called.
|
||||||
|
\return Whether retrieving the actual context was successful.
|
||||||
|
*/
|
||||||
|
bool handleLazyContext();
|
||||||
|
|
||||||
|
void* getPtr(R reg);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,21 +44,17 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
memset(&this->mOldContext, 0, sizeof(CONTEXT));
|
memset(&this->mOldContext, 0, sizeof(CONTEXT));
|
||||||
this->mOldContext.ContextFlags = CONTEXT_ALL; //TODO: granular control over what's required
|
this->mOldContext.ContextFlags = CONTEXT_ALL; //TODO: granular control over what's required
|
||||||
if (GetThreadContext(this->hThread, &this->mOldContext))
|
this->registers.setContextLazy(&this->mOldContext, this->hThread);
|
||||||
{
|
return true;
|
||||||
this->registers.SetContext(this->mOldContext);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::RegWriteContext() const
|
bool Thread::RegWriteContext()
|
||||||
{
|
{
|
||||||
//check if something actually changed
|
//check if something actually changed
|
||||||
if (memcmp(&this->mOldContext, this->registers.GetContext(), sizeof(CONTEXT)) == 0)
|
if (memcmp(&this->mOldContext, &this->registers.mContext, sizeof(CONTEXT)) == 0)
|
||||||
return true;
|
return true;
|
||||||
//update the context
|
//update the context
|
||||||
return !!SetThreadContext(this->hThread, this->registers.GetContext());
|
return !!SetThreadContext(this->hThread, &this->registers.mContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::StepInto()
|
void Thread::StepInto()
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ namespace GleeBug
|
||||||
\brief Write the register context to the thread. This does nothing if the registers did not change.
|
\brief Write the register context to the thread. This does nothing if the registers did not change.
|
||||||
\return true if it succeeds, false if it fails.
|
\return true if it succeeds, false if it fails.
|
||||||
*/
|
*/
|
||||||
bool RegWriteContext() const;
|
bool RegWriteContext();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Step into.
|
\brief Step into.
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,8 @@ public:
|
||||||
auto thread = threadFromHandle(hActiveThread);
|
auto thread = threadFromHandle(hActiveThread);
|
||||||
if (!thread)
|
if (!thread)
|
||||||
return 0;
|
return 0;
|
||||||
|
if(mIsRunning)
|
||||||
|
thread->RegReadContext();
|
||||||
return thread->registers.Get(registerFromDword(IndexOfRegister));
|
return thread->registers.Get(registerFromDword(IndexOfRegister));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -243,7 +245,11 @@ public:
|
||||||
auto thread = threadFromHandle(hActiveThread);
|
auto thread = threadFromHandle(hActiveThread);
|
||||||
if (!thread)
|
if (!thread)
|
||||||
return false;
|
return false;
|
||||||
|
if(mIsRunning)
|
||||||
|
thread->RegReadContext();
|
||||||
thread->registers.Set(registerFromDword(IndexOfRegister), NewRegisterValue);
|
thread->registers.Set(registerFromDword(IndexOfRegister), NewRegisterValue);
|
||||||
|
if(mIsRunning)
|
||||||
|
thread->RegWriteContext();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -252,6 +258,8 @@ public:
|
||||||
auto thread = threadFromHandle(hActiveThread);
|
auto thread = threadFromHandle(hActiveThread);
|
||||||
if (!thread || !titcontext)
|
if (!thread || !titcontext)
|
||||||
return false;
|
return false;
|
||||||
|
if(mIsRunning)
|
||||||
|
thread->RegReadContext();
|
||||||
memset(titcontext, 0, sizeof(TITAN_ENGINE_CONTEXT_t));
|
memset(titcontext, 0, sizeof(TITAN_ENGINE_CONTEXT_t));
|
||||||
auto context = thread->registers.GetContext();
|
auto context = thread->registers.GetContext();
|
||||||
titcontext->cax = thread->registers.Gax();
|
titcontext->cax = thread->registers.Gax();
|
||||||
|
|
@ -294,6 +302,8 @@ public:
|
||||||
auto thread = threadFromHandle(hActiveThread);
|
auto thread = threadFromHandle(hActiveThread);
|
||||||
if (!thread || !titcontext)
|
if (!thread || !titcontext)
|
||||||
return false;
|
return false;
|
||||||
|
if(mIsRunning)
|
||||||
|
thread->RegReadContext();
|
||||||
thread->registers.Gax = titcontext->cax;
|
thread->registers.Gax = titcontext->cax;
|
||||||
thread->registers.Gcx = titcontext->ccx;
|
thread->registers.Gcx = titcontext->ccx;
|
||||||
thread->registers.Gdx = titcontext->cdx;
|
thread->registers.Gdx = titcontext->cdx;
|
||||||
|
|
@ -328,6 +338,8 @@ public:
|
||||||
context.SegCs = titcontext->cs;
|
context.SegCs = titcontext->cs;
|
||||||
context.SegSs = titcontext->ss;
|
context.SegSs = titcontext->ss;
|
||||||
thread->registers.SetContext(context);
|
thread->registers.SetContext(context);
|
||||||
|
if(mIsRunning)
|
||||||
|
thread->RegWriteContext();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -449,11 +461,17 @@ public:
|
||||||
{
|
{
|
||||||
if (!mProcess)
|
if (!mProcess)
|
||||||
return false;
|
return false;
|
||||||
return mProcess->SetHardwareBreakpoint(bpxAddress,
|
if(mIsRunning)
|
||||||
|
mProcess->RegReadContext();
|
||||||
|
if(!mProcess->SetHardwareBreakpoint(bpxAddress,
|
||||||
(HardwareSlot)IndexOfRegister, [bpxCallBack](const BreakpointInfo & info)
|
(HardwareSlot)IndexOfRegister, [bpxCallBack](const BreakpointInfo & info)
|
||||||
{
|
{
|
||||||
(HWBPCALLBACK(bpxCallBack))((const void*)info.address);
|
(HWBPCALLBACK(bpxCallBack))((const void*)info.address);
|
||||||
}, hwtypeFromTitan(bpxType), hwsizeFromTitan(bpxSize));
|
}, hwtypeFromTitan(bpxType), hwsizeFromTitan(bpxSize)))
|
||||||
|
return false;
|
||||||
|
if(mIsRunning)
|
||||||
|
mProcess->RegWriteContext();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeleteHardwareBreakPoint(DWORD IndexOfRegister)
|
bool DeleteHardwareBreakPoint(DWORD IndexOfRegister)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue