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;
mRegisters = &mThread->registers;
if (!mThread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!");
}
else
{
@ -64,6 +62,10 @@ namespace GleeBug
}
}
//read register contexts
if(mProcess && !mProcess->RegReadContext())
cbInternalError("Process::RegReadContext() failed!");
//call the pre debug event callback
cbPreDebugEvent(mDebugEvent);
@ -120,12 +122,9 @@ namespace GleeBug
mThread->registers.TrapFlag = false;
}
//write the register context
if (mThread)
{
if (!mThread->RegWriteContext())
cbInternalError("ThreadInfo::RegWriteContext() failed!");
}
//write register contexts
if(mProcess && !mProcess->RegWriteContext())
cbInternalError("Process::RegWriteContext() failed!");
//continue the debug event
if (!ContinueDebugEvent(mDebugEvent.dwProcessId, mDebugEvent.dwThreadId, mContinueStatus))

View File

@ -394,6 +394,24 @@ namespace GleeBug
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:
Capstone mCapstone;
};

View File

@ -54,8 +54,10 @@
namespace GleeBug
{
ptr Registers::Get(R reg) const
ptr Registers::Get(R reg)
{
handleLazyContext();
switch (reg)
{
case R::DR0:
@ -244,6 +246,8 @@ namespace GleeBug
void Registers::Set(R reg, ptr value)
{
handleLazyContext();
switch (reg)
{
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);
}
void Registers::SetFlag(F flag, bool set)
{
handleLazyContext();
if (set)
mContext.EFlags |= ptr(flag);
else
mContext.EFlags &= ~ptr(flag);
}
void* Registers::getPtr(R reg) const
void* Registers::getPtr(R reg)
{
handleLazyContext();
switch (reg)
{
case R::DR0:

View File

@ -102,13 +102,45 @@ namespace GleeBug
memset(&this->mContext, 0, sizeof(CONTEXT));
}
const CONTEXT* Registers::GetContext() const
const CONTEXT* Registers::GetContext()
{
handleLazyContext();
return &mContext;
}
void Registers::SetContext(const CONTEXT & context)
{
handleLazyContext();
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
{
friend class Register;
friend class Thread;
public:
/**
@ -123,7 +124,7 @@ namespace GleeBug
\param reg The register to get.
\return The register value.
*/
ptr Get(R reg) const;
ptr Get(R reg);
/**
\brief Sets a given register.
@ -137,7 +138,7 @@ namespace GleeBug
\param flag The flag to get.
\return true if the flag is set, false otherwise.
*/
bool GetFlag(F flag) const;
bool GetFlag(F flag);
/**
\brief Sets a flag.
@ -149,7 +150,7 @@ namespace GleeBug
\brief Gets a pointer to the context object.
\return This function will never return a nullptr.
*/
const CONTEXT* GetContext() const;
const CONTEXT* GetContext();
/**
\brief Sets the CONTEXT.
@ -160,7 +161,24 @@ namespace GleeBug
private:
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));
this->mOldContext.ContextFlags = CONTEXT_ALL; //TODO: granular control over what's required
if (GetThreadContext(this->hThread, &this->mOldContext))
{
this->registers.SetContext(this->mOldContext);
return true;
}
return false;
this->registers.setContextLazy(&this->mOldContext, this->hThread);
return true;
}
bool Thread::RegWriteContext() const
bool Thread::RegWriteContext()
{
//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;
//update the context
return !!SetThreadContext(this->hThread, this->registers.GetContext());
return !!SetThreadContext(this->hThread, &this->registers.mContext);
}
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.
\return true if it succeeds, false if it fails.
*/
bool RegWriteContext() const;
bool RegWriteContext();
/**
\brief Step into.

View File

@ -235,6 +235,8 @@ public:
auto thread = threadFromHandle(hActiveThread);
if (!thread)
return 0;
if(mIsRunning)
thread->RegReadContext();
return thread->registers.Get(registerFromDword(IndexOfRegister));
}
@ -243,7 +245,11 @@ public:
auto thread = threadFromHandle(hActiveThread);
if (!thread)
return false;
if(mIsRunning)
thread->RegReadContext();
thread->registers.Set(registerFromDword(IndexOfRegister), NewRegisterValue);
if(mIsRunning)
thread->RegWriteContext();
return true;
}
@ -252,6 +258,8 @@ public:
auto thread = threadFromHandle(hActiveThread);
if (!thread || !titcontext)
return false;
if(mIsRunning)
thread->RegReadContext();
memset(titcontext, 0, sizeof(TITAN_ENGINE_CONTEXT_t));
auto context = thread->registers.GetContext();
titcontext->cax = thread->registers.Gax();
@ -294,6 +302,8 @@ public:
auto thread = threadFromHandle(hActiveThread);
if (!thread || !titcontext)
return false;
if(mIsRunning)
thread->RegReadContext();
thread->registers.Gax = titcontext->cax;
thread->registers.Gcx = titcontext->ccx;
thread->registers.Gdx = titcontext->cdx;
@ -328,6 +338,8 @@ public:
context.SegCs = titcontext->cs;
context.SegSs = titcontext->ss;
thread->registers.SetContext(context);
if(mIsRunning)
thread->RegWriteContext();
return true;
}
@ -449,11 +461,17 @@ public:
{
if (!mProcess)
return false;
return mProcess->SetHardwareBreakpoint(bpxAddress,
if(mIsRunning)
mProcess->RegReadContext();
if(!mProcess->SetHardwareBreakpoint(bpxAddress,
(HardwareSlot)IndexOfRegister, [bpxCallBack](const BreakpointInfo & info)
{
(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)