mirror of https://github.com/x64dbg/GleeBug
remove lazy context
This commit is contained in:
parent
22c5c2189c
commit
0b18c04e1e
|
|
@ -2,6 +2,7 @@
|
|||
#define DEBUGGER_GLOBAL_H
|
||||
|
||||
#include "GleeBug.h"
|
||||
#include <memory>
|
||||
|
||||
//defines
|
||||
#define GLEEBUG_HWBP_COUNT 4
|
||||
|
|
@ -30,9 +31,9 @@ namespace GleeBug
|
|||
typedef std::function<void(const BreakpointInfo & info)> BreakpointCallback;
|
||||
|
||||
//map typedefs
|
||||
typedef std::map<uint32, Process> ProcessMap;
|
||||
typedef std::map<uint32, std::unique_ptr<Process>> ProcessMap;
|
||||
typedef std::map<Range, Dll, RangeCompare> DllMap;
|
||||
typedef std::map<uint32, Thread> ThreadMap;
|
||||
typedef std::map<uint32, std::unique_ptr<Thread>> ThreadMap;
|
||||
typedef std::map<BreakpointKey, BreakpointInfo> BreakpointMap;
|
||||
typedef std::map<BreakpointKey, BreakpointCallback> BreakpointCallbackMap;
|
||||
typedef std::unordered_map<ptr, BreakpointMap::iterator> SoftwareBreakpointMap;
|
||||
|
|
|
|||
|
|
@ -16,19 +16,19 @@ namespace GleeBug
|
|||
|
||||
//process housekeeping
|
||||
mProcesses.insert({ mDebugEvent.dwProcessId,
|
||||
Process(createProcess.hProcess,
|
||||
std::make_unique<Process>(createProcess.hProcess,
|
||||
mDebugEvent.dwProcessId,
|
||||
mDebugEvent.dwThreadId,
|
||||
createProcess) });
|
||||
mProcess = &mProcesses.find(mDebugEvent.dwProcessId)->second;
|
||||
mProcess = mProcesses.find(mDebugEvent.dwProcessId)->second.get();
|
||||
|
||||
//thread housekeeping (main thread is created implicitly)
|
||||
mProcess->threads.insert({ mDebugEvent.dwThreadId,
|
||||
Thread(createProcess.hThread,
|
||||
std::make_unique<Thread>(createProcess.hThread,
|
||||
mDebugEvent.dwThreadId,
|
||||
createProcess.lpThreadLocalBase,
|
||||
createProcess.lpStartAddress) });
|
||||
mThread = mProcess->thread = &mProcess->threads.find(mDebugEvent.dwThreadId)->second;
|
||||
mThread = mProcess->thread = mProcess->threads.find(mDebugEvent.dwThreadId)->second.get();
|
||||
mRegisters = &mThread->registers;
|
||||
|
||||
//read thread context from main thread
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@ namespace GleeBug
|
|||
{
|
||||
//thread housekeeping
|
||||
mProcess->threads.insert({ mDebugEvent.dwThreadId,
|
||||
Thread(createThread.hThread,
|
||||
std::make_unique<Thread>(createThread.hThread,
|
||||
mDebugEvent.dwThreadId,
|
||||
createThread.lpThreadLocalBase,
|
||||
createThread.lpStartAddress) });
|
||||
|
||||
//set the current thread
|
||||
mThread = mProcess->thread = &mProcess->threads.find(mDebugEvent.dwThreadId)->second;
|
||||
mThread = mProcess->thread = mProcess->threads.find(mDebugEvent.dwThreadId)->second.get();
|
||||
mRegisters = &mThread->registers;
|
||||
if (!mThread->RegReadContext())
|
||||
cbInternalError("Thread::RegReadContext() failed!");
|
||||
|
|
|
|||
|
|
@ -38,11 +38,11 @@ namespace GleeBug
|
|||
auto processFound = mProcesses.find(mDebugEvent.dwProcessId);
|
||||
if (processFound != mProcesses.end())
|
||||
{
|
||||
mProcess = &processFound->second;
|
||||
mProcess = processFound->second.get();
|
||||
auto threadFound = mProcess->threads.find(mDebugEvent.dwThreadId);
|
||||
if (threadFound != mProcess->threads.end())
|
||||
{
|
||||
mThread = mProcess->thread = &threadFound->second;
|
||||
mThread = mProcess->thread = threadFound->second.get();
|
||||
mRegisters = &mThread->registers;
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ namespace GleeBug
|
|||
bool success = true;
|
||||
for (auto & thread : threads)
|
||||
{
|
||||
if (!thread.second.SetHardwareBreakpoint(address, slot, type, size))
|
||||
if (!thread.second->SetHardwareBreakpoint(address, slot, type, size))
|
||||
{
|
||||
success = false;
|
||||
break;
|
||||
|
|
@ -111,7 +111,7 @@ namespace GleeBug
|
|||
if (!success)
|
||||
{
|
||||
for (auto & thread : threads)
|
||||
thread.second.DeleteHardwareBreakpoint(slot);
|
||||
thread.second->DeleteHardwareBreakpoint(slot);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -161,7 +161,7 @@ namespace GleeBug
|
|||
bool success = true;
|
||||
for (auto & thread : threads)
|
||||
{
|
||||
if (!thread.second.DeleteHardwareBreakpoint(info.internal.hardware.slot))
|
||||
if (!thread.second->DeleteHardwareBreakpoint(info.internal.hardware.slot))
|
||||
success = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace GleeBug
|
|||
bool systemBreakpoint;
|
||||
bool permanentDep;
|
||||
|
||||
ThreadMap threads; //DO NOT COPY THESE OBJECTS!
|
||||
ThreadMap threads;
|
||||
DllMap dlls;
|
||||
BreakpointMap breakpoints;
|
||||
SoftwareBreakpointMap softwareBreakpointReferences;
|
||||
|
|
@ -42,6 +42,11 @@ namespace GleeBug
|
|||
*/
|
||||
explicit Process(HANDLE hProcess, uint32 dwProcessId, uint32 dwMainThreadId, const CREATE_PROCESS_DEBUG_INFO & createProcessInfo);
|
||||
|
||||
/**
|
||||
\brief Copy constructor.
|
||||
*/
|
||||
Process(const Process &) = delete;
|
||||
|
||||
/**
|
||||
\brief Read memory from the process.
|
||||
\param address The virtual address to read from.
|
||||
|
|
@ -397,7 +402,7 @@ namespace GleeBug
|
|||
{
|
||||
auto result = true;
|
||||
for(auto & thread : this->threads)
|
||||
if(!thread.second.RegReadContext())
|
||||
if(!thread.second->RegReadContext())
|
||||
result = false;
|
||||
return result;
|
||||
}
|
||||
|
|
@ -406,7 +411,7 @@ namespace GleeBug
|
|||
{
|
||||
auto result = true;
|
||||
for(auto & thread : this->threads)
|
||||
if(!thread.second.RegWriteContext())
|
||||
if(!thread.second->RegWriteContext())
|
||||
result = false;
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@ namespace GleeBug
|
|||
*/
|
||||
Registers();
|
||||
|
||||
/**
|
||||
\brief Copy constructor.
|
||||
*/
|
||||
Registers(const Registers &) = delete;
|
||||
|
||||
#include "Debugger.Thread.Registers.Register.h"
|
||||
|
||||
Register<R::DR0, ptr> Dr0;
|
||||
|
|
|
|||
|
|
@ -13,40 +13,18 @@ namespace GleeBug
|
|||
{
|
||||
}
|
||||
|
||||
Thread::Thread(const Thread & other) :
|
||||
hThread(other.hThread),
|
||||
dwThreadId(other.dwThreadId),
|
||||
lpThreadLocalBase(other.lpThreadLocalBase),
|
||||
lpStartAddress(other.lpStartAddress),
|
||||
registers(), //create new registers
|
||||
stepCallbacks(other.stepCallbacks),
|
||||
isSingleStepping(other.isSingleStepping),
|
||||
isInternalStepping(other.isInternalStepping),
|
||||
cbInternalStep(other.cbInternalStep)
|
||||
{
|
||||
}
|
||||
|
||||
Thread & Thread::operator=(const Thread& other)
|
||||
{
|
||||
hThread = other.hThread;
|
||||
dwThreadId = other.dwThreadId;
|
||||
lpThreadLocalBase = other.lpThreadLocalBase;
|
||||
lpStartAddress = other.lpStartAddress;
|
||||
registers = Registers(); //create new registers
|
||||
stepCallbacks = other.stepCallbacks;
|
||||
isSingleStepping = other.isSingleStepping;
|
||||
isInternalStepping = other.isInternalStepping;
|
||||
cbInternalStep = other.cbInternalStep;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Thread::RegReadContext()
|
||||
{
|
||||
memset(&this->mOldContext, 0, sizeof(CONTEXT));
|
||||
this->mOldContext.ContextFlags = CONTEXT_ALL; //TODO: granular control over what's required
|
||||
this->registers.setContextLazy(&this->mOldContext, this->hThread);
|
||||
if(GetThreadContext(this->hThread, &this->mOldContext))
|
||||
{
|
||||
this->registers.SetContext(this->mOldContext);
|
||||
return true;
|
||||
}
|
||||
__debugbreak();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Thread::RegWriteContext()
|
||||
{
|
||||
|
|
@ -54,7 +32,10 @@ namespace GleeBug
|
|||
if (memcmp(&this->mOldContext, &this->registers.mContext, sizeof(CONTEXT)) == 0)
|
||||
return true;
|
||||
//update the context
|
||||
return !!SetThreadContext(this->hThread, &this->registers.mContext);
|
||||
if(SetThreadContext(this->hThread, &this->registers.mContext))
|
||||
return true;
|
||||
__debugbreak();
|
||||
return false;
|
||||
}
|
||||
|
||||
void Thread::StepInto()
|
||||
|
|
@ -85,4 +66,14 @@ namespace GleeBug
|
|||
isInternalStepping = true;
|
||||
cbInternalStep = cbStep;
|
||||
}
|
||||
|
||||
bool Thread::Suspend()
|
||||
{
|
||||
return SuspendThread(hThread) != -1;
|
||||
}
|
||||
|
||||
bool Thread::Resume()
|
||||
{
|
||||
return ResumeThread(hThread) != -1;
|
||||
}
|
||||
};
|
||||
|
|
@ -36,14 +36,7 @@ namespace GleeBug
|
|||
/**
|
||||
\brief Copy constructor.
|
||||
*/
|
||||
Thread(const Thread & other);
|
||||
|
||||
/**
|
||||
\brief Assignment operator.
|
||||
\param other The other object.
|
||||
\return A shallow copy of this object.
|
||||
*/
|
||||
Thread & operator=(const Thread & other);
|
||||
Thread(const Thread & other) = delete;
|
||||
|
||||
/**
|
||||
\brief Read the register context from the thread. This fills the RegistersInfo member.
|
||||
|
|
@ -117,6 +110,18 @@ namespace GleeBug
|
|||
*/
|
||||
bool DeleteHardwareBreakpoint(HardwareSlot slot);
|
||||
|
||||
/**
|
||||
\brief Suspends this thread.
|
||||
\return true if it succeeds, false if it fails.
|
||||
*/
|
||||
bool Suspend();
|
||||
|
||||
/**
|
||||
\brief Resumes this thread.
|
||||
\return true if it succeeds, false if it fails.
|
||||
*/
|
||||
bool Resume();
|
||||
|
||||
private:
|
||||
CONTEXT mOldContext;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,6 +18,11 @@ namespace GleeBug
|
|||
*/
|
||||
Debugger();
|
||||
|
||||
/**
|
||||
\brief Copy constructor.
|
||||
*/
|
||||
Debugger(const Debugger &) = delete;
|
||||
|
||||
/**
|
||||
\brief Destructs the Debugger instance.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -240,6 +240,32 @@ public:
|
|||
mThread->StepInto(STEPCALLBACK(CallBack));
|
||||
}
|
||||
|
||||
struct ThreadSuspender
|
||||
{
|
||||
ThreadSuspender(Thread* thread, bool running, bool writeRegs)
|
||||
: thread(running ? thread : nullptr), writeRegs(writeRegs)
|
||||
{
|
||||
if(this->thread)
|
||||
{
|
||||
this->thread->Suspend();
|
||||
this->thread->RegReadContext();
|
||||
}
|
||||
}
|
||||
|
||||
~ThreadSuspender()
|
||||
{
|
||||
if(this->thread)
|
||||
{
|
||||
if(this->writeRegs)
|
||||
this->thread->RegWriteContext();
|
||||
this->thread->Resume();
|
||||
}
|
||||
}
|
||||
|
||||
Thread* thread;
|
||||
bool writeRegs;
|
||||
};
|
||||
|
||||
//Registers
|
||||
ULONG_PTR GetContextDataEx(HANDLE hActiveThread, DWORD IndexOfRegister)
|
||||
{
|
||||
|
|
@ -248,8 +274,7 @@ public:
|
|||
auto thread = threadFromHandle(hActiveThread);
|
||||
if(!thread)
|
||||
return 0;
|
||||
if(mIsRunning)
|
||||
thread->RegReadContext();
|
||||
ThreadSuspender suspender(thread, mIsRunning, false);
|
||||
return thread->registers.Get(registerFromDword(IndexOfRegister));
|
||||
}
|
||||
|
||||
|
|
@ -258,11 +283,8 @@ public:
|
|||
auto thread = threadFromHandle(hActiveThread);
|
||||
if (!thread)
|
||||
return false;
|
||||
if(mIsRunning)
|
||||
thread->RegReadContext();
|
||||
ThreadSuspender suspender(thread, mIsRunning, true);
|
||||
thread->registers.Set(registerFromDword(IndexOfRegister), NewRegisterValue);
|
||||
if(mIsRunning)
|
||||
thread->RegWriteContext();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -273,8 +295,7 @@ public:
|
|||
auto thread = threadFromHandle(hActiveThread);
|
||||
if (!thread || !titcontext)
|
||||
return false;
|
||||
if(mIsRunning)
|
||||
thread->RegReadContext();
|
||||
ThreadSuspender suspender(thread, mIsRunning, false);
|
||||
memset(titcontext, 0, sizeof(TITAN_ENGINE_CONTEXT_t));
|
||||
auto context = thread->registers.GetContext();
|
||||
titcontext->cax = thread->registers.Gax();
|
||||
|
|
@ -317,8 +338,7 @@ public:
|
|||
auto thread = threadFromHandle(hActiveThread);
|
||||
if (!thread || !titcontext)
|
||||
return false;
|
||||
if(mIsRunning)
|
||||
thread->RegReadContext();
|
||||
ThreadSuspender suspender(thread, mIsRunning, true);
|
||||
thread->registers.Gax = titcontext->cax;
|
||||
thread->registers.Gcx = titcontext->ccx;
|
||||
thread->registers.Gdx = titcontext->cdx;
|
||||
|
|
@ -353,8 +373,6 @@ public:
|
|||
context.SegCs = titcontext->cs;
|
||||
context.SegSs = titcontext->ss;
|
||||
thread->registers.SetContext(context);
|
||||
if(mIsRunning)
|
||||
thread->RegWriteContext();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -572,16 +590,25 @@ public:
|
|||
{
|
||||
if (!mProcess)
|
||||
return false;
|
||||
if(mIsRunning)
|
||||
auto running = mIsRunning;
|
||||
if(running)
|
||||
{
|
||||
for(auto & thread : mProcess->threads)
|
||||
thread.second->Suspend();
|
||||
mProcess->RegReadContext();
|
||||
}
|
||||
if(!mProcess->SetHardwareBreakpoint(bpxAddress,
|
||||
(HardwareSlot)IndexOfRegister, [bpxCallBack](const BreakpointInfo & info)
|
||||
{
|
||||
(HWBPCALLBACK(bpxCallBack))((const void*)info.address);
|
||||
}, hwtypeFromTitan(bpxType), hwsizeFromTitan(bpxSize)))
|
||||
return false;
|
||||
if(mIsRunning)
|
||||
if(running)
|
||||
{
|
||||
mProcess->RegWriteContext();
|
||||
for(auto & thread : mProcess->threads)
|
||||
thread.second->Resume();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -622,9 +649,9 @@ public:
|
|||
{
|
||||
for(auto & it : mProcesses)
|
||||
{
|
||||
auto breakpoints = it.second.breakpoints; //explicit copy
|
||||
auto breakpoints = it.second->breakpoints; //explicit copy
|
||||
for(const auto & jt : breakpoints)
|
||||
it.second.DeleteGenericBreakpoint(jt.second);
|
||||
it.second->DeleteGenericBreakpoint(jt.second);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -756,10 +783,10 @@ private: //functions
|
|||
auto foundP = mProcesses.find(uint32(tbi.ClientId.UniqueProcess));
|
||||
if(foundP == mProcesses.end())
|
||||
return nullptr;
|
||||
auto foundT = foundP->second.threads.find(uint32(tbi.ClientId.UniqueThread));
|
||||
if(foundT == foundP->second.threads.end())
|
||||
auto foundT = foundP->second->threads.find(uint32(tbi.ClientId.UniqueThread));
|
||||
if(foundT == foundP->second->threads.end())
|
||||
return nullptr;
|
||||
return &foundT->second;
|
||||
return foundT->second.get();
|
||||
}
|
||||
|
||||
Process* processFromHandle(HANDLE hProcess)
|
||||
|
|
@ -767,7 +794,7 @@ private: //functions
|
|||
auto foundP = mProcesses.find(GetProcessId(hProcess));
|
||||
if(foundP == mProcesses.end())
|
||||
return nullptr;
|
||||
return &foundP->second;
|
||||
return foundP->second.get();
|
||||
}
|
||||
|
||||
static HardwareType hwtypeFromTitan(DWORD type)
|
||||
|
|
|
|||
Loading…
Reference in New Issue