lazily read/write context for all threads

This commit is contained in:
mrexodia 2017-02-24 18:13:36 +01:00
parent 732abb9ce9
commit 6c6e181ff5
No known key found for this signature in database
GPG Key ID: FC89E0AAA0C1AAD8
8 changed files with 119 additions and 28 deletions

View File

@ -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))

View File

@ -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;
}; };

View File

@ -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:

View File

@ -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;
}
}; };

View File

@ -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);
}; };
}; };

View File

@ -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);
{
this->registers.SetContext(this->mOldContext);
return true; 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()

View File

@ -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.

View File

@ -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)