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;
|
||||
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))
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
@ -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);
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue