remove lazy context

This commit is contained in:
mrexodia 2017-06-04 18:26:42 +02:00
parent 22c5c2189c
commit 0b18c04e1e
No known key found for this signature in database
GPG Key ID: FC89E0AAA0C1AAD8
11 changed files with 113 additions and 74 deletions

View File

@ -2,6 +2,7 @@
#define DEBUGGER_GLOBAL_H #define DEBUGGER_GLOBAL_H
#include "GleeBug.h" #include "GleeBug.h"
#include <memory>
//defines //defines
#define GLEEBUG_HWBP_COUNT 4 #define GLEEBUG_HWBP_COUNT 4
@ -30,9 +31,9 @@ namespace GleeBug
typedef std::function<void(const BreakpointInfo & info)> BreakpointCallback; typedef std::function<void(const BreakpointInfo & info)> BreakpointCallback;
//map typedefs //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<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, BreakpointInfo> BreakpointMap;
typedef std::map<BreakpointKey, BreakpointCallback> BreakpointCallbackMap; typedef std::map<BreakpointKey, BreakpointCallback> BreakpointCallbackMap;
typedef std::unordered_map<ptr, BreakpointMap::iterator> SoftwareBreakpointMap; typedef std::unordered_map<ptr, BreakpointMap::iterator> SoftwareBreakpointMap;

View File

@ -16,19 +16,19 @@ namespace GleeBug
//process housekeeping //process housekeeping
mProcesses.insert({ mDebugEvent.dwProcessId, mProcesses.insert({ mDebugEvent.dwProcessId,
Process(createProcess.hProcess, std::make_unique<Process>(createProcess.hProcess,
mDebugEvent.dwProcessId, mDebugEvent.dwProcessId,
mDebugEvent.dwThreadId, mDebugEvent.dwThreadId,
createProcess) }); createProcess) });
mProcess = &mProcesses.find(mDebugEvent.dwProcessId)->second; mProcess = mProcesses.find(mDebugEvent.dwProcessId)->second.get();
//thread housekeeping (main thread is created implicitly) //thread housekeeping (main thread is created implicitly)
mProcess->threads.insert({ mDebugEvent.dwThreadId, mProcess->threads.insert({ mDebugEvent.dwThreadId,
Thread(createProcess.hThread, std::make_unique<Thread>(createProcess.hThread,
mDebugEvent.dwThreadId, mDebugEvent.dwThreadId,
createProcess.lpThreadLocalBase, createProcess.lpThreadLocalBase,
createProcess.lpStartAddress) }); createProcess.lpStartAddress) });
mThread = mProcess->thread = &mProcess->threads.find(mDebugEvent.dwThreadId)->second; mThread = mProcess->thread = mProcess->threads.find(mDebugEvent.dwThreadId)->second.get();
mRegisters = &mThread->registers; mRegisters = &mThread->registers;
//read thread context from main thread //read thread context from main thread

View File

@ -6,13 +6,13 @@ namespace GleeBug
{ {
//thread housekeeping //thread housekeeping
mProcess->threads.insert({ mDebugEvent.dwThreadId, mProcess->threads.insert({ mDebugEvent.dwThreadId,
Thread(createThread.hThread, std::make_unique<Thread>(createThread.hThread,
mDebugEvent.dwThreadId, mDebugEvent.dwThreadId,
createThread.lpThreadLocalBase, createThread.lpThreadLocalBase,
createThread.lpStartAddress) }); createThread.lpStartAddress) });
//set the current thread //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; mRegisters = &mThread->registers;
if (!mThread->RegReadContext()) if (!mThread->RegReadContext())
cbInternalError("Thread::RegReadContext() failed!"); cbInternalError("Thread::RegReadContext() failed!");

View File

@ -38,11 +38,11 @@ namespace GleeBug
auto processFound = mProcesses.find(mDebugEvent.dwProcessId); auto processFound = mProcesses.find(mDebugEvent.dwProcessId);
if (processFound != mProcesses.end()) if (processFound != mProcesses.end())
{ {
mProcess = &processFound->second; mProcess = processFound->second.get();
auto threadFound = mProcess->threads.find(mDebugEvent.dwThreadId); auto threadFound = mProcess->threads.find(mDebugEvent.dwThreadId);
if (threadFound != mProcess->threads.end()) if (threadFound != mProcess->threads.end())
{ {
mThread = mProcess->thread = &threadFound->second; mThread = mProcess->thread = threadFound->second.get();
mRegisters = &mThread->registers; mRegisters = &mThread->registers;
} }
else else

View File

@ -100,7 +100,7 @@ namespace GleeBug
bool success = true; bool success = true;
for (auto & thread : threads) for (auto & thread : threads)
{ {
if (!thread.second.SetHardwareBreakpoint(address, slot, type, size)) if (!thread.second->SetHardwareBreakpoint(address, slot, type, size))
{ {
success = false; success = false;
break; break;
@ -111,7 +111,7 @@ namespace GleeBug
if (!success) if (!success)
{ {
for (auto & thread : threads) for (auto & thread : threads)
thread.second.DeleteHardwareBreakpoint(slot); thread.second->DeleteHardwareBreakpoint(slot);
return false; return false;
} }
@ -161,7 +161,7 @@ namespace GleeBug
bool success = true; bool success = true;
for (auto & thread : threads) for (auto & thread : threads)
{ {
if (!thread.second.DeleteHardwareBreakpoint(info.internal.hardware.slot)) if (!thread.second->DeleteHardwareBreakpoint(info.internal.hardware.slot))
success = false; success = false;
} }

View File

@ -24,7 +24,7 @@ namespace GleeBug
bool systemBreakpoint; bool systemBreakpoint;
bool permanentDep; bool permanentDep;
ThreadMap threads; //DO NOT COPY THESE OBJECTS! ThreadMap threads;
DllMap dlls; DllMap dlls;
BreakpointMap breakpoints; BreakpointMap breakpoints;
SoftwareBreakpointMap softwareBreakpointReferences; SoftwareBreakpointMap softwareBreakpointReferences;
@ -42,6 +42,11 @@ namespace GleeBug
*/ */
explicit Process(HANDLE hProcess, uint32 dwProcessId, uint32 dwMainThreadId, const CREATE_PROCESS_DEBUG_INFO & createProcessInfo); 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. \brief Read memory from the process.
\param address The virtual address to read from. \param address The virtual address to read from.
@ -397,7 +402,7 @@ namespace GleeBug
{ {
auto result = true; auto result = true;
for(auto & thread : this->threads) for(auto & thread : this->threads)
if(!thread.second.RegReadContext()) if(!thread.second->RegReadContext())
result = false; result = false;
return result; return result;
} }
@ -406,7 +411,7 @@ namespace GleeBug
{ {
auto result = true; auto result = true;
for(auto & thread : this->threads) for(auto & thread : this->threads)
if(!thread.second.RegWriteContext()) if(!thread.second->RegWriteContext())
result = false; result = false;
return result; return result;
} }

View File

@ -19,6 +19,11 @@ namespace GleeBug
*/ */
Registers(); Registers();
/**
\brief Copy constructor.
*/
Registers(const Registers &) = delete;
#include "Debugger.Thread.Registers.Register.h" #include "Debugger.Thread.Registers.Register.h"
Register<R::DR0, ptr> Dr0; Register<R::DR0, ptr> Dr0;

View File

@ -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() bool Thread::RegReadContext()
{ {
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
this->registers.setContextLazy(&this->mOldContext, this->hThread); if(GetThreadContext(this->hThread, &this->mOldContext))
{
this->registers.SetContext(this->mOldContext);
return true; return true;
} }
__debugbreak();
return false;
}
bool Thread::RegWriteContext() bool Thread::RegWriteContext()
{ {
@ -54,7 +32,10 @@ namespace GleeBug
if (memcmp(&this->mOldContext, &this->registers.mContext, 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.mContext); if(SetThreadContext(this->hThread, &this->registers.mContext))
return true;
__debugbreak();
return false;
} }
void Thread::StepInto() void Thread::StepInto()
@ -85,4 +66,14 @@ namespace GleeBug
isInternalStepping = true; isInternalStepping = true;
cbInternalStep = cbStep; cbInternalStep = cbStep;
} }
bool Thread::Suspend()
{
return SuspendThread(hThread) != -1;
}
bool Thread::Resume()
{
return ResumeThread(hThread) != -1;
}
}; };

View File

@ -36,14 +36,7 @@ namespace GleeBug
/** /**
\brief Copy constructor. \brief Copy constructor.
*/ */
Thread(const Thread & other); Thread(const Thread & other) = delete;
/**
\brief Assignment operator.
\param other The other object.
\return A shallow copy of this object.
*/
Thread & operator=(const Thread & other);
/** /**
\brief Read the register context from the thread. This fills the RegistersInfo member. \brief Read the register context from the thread. This fills the RegistersInfo member.
@ -117,6 +110,18 @@ namespace GleeBug
*/ */
bool DeleteHardwareBreakpoint(HardwareSlot slot); 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: private:
CONTEXT mOldContext; CONTEXT mOldContext;
}; };

View File

@ -18,6 +18,11 @@ namespace GleeBug
*/ */
Debugger(); Debugger();
/**
\brief Copy constructor.
*/
Debugger(const Debugger &) = delete;
/** /**
\brief Destructs the Debugger instance. \brief Destructs the Debugger instance.
*/ */

View File

@ -240,6 +240,32 @@ public:
mThread->StepInto(STEPCALLBACK(CallBack)); 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 //Registers
ULONG_PTR GetContextDataEx(HANDLE hActiveThread, DWORD IndexOfRegister) ULONG_PTR GetContextDataEx(HANDLE hActiveThread, DWORD IndexOfRegister)
{ {
@ -248,8 +274,7 @@ public:
auto thread = threadFromHandle(hActiveThread); auto thread = threadFromHandle(hActiveThread);
if(!thread) if(!thread)
return 0; return 0;
if(mIsRunning) ThreadSuspender suspender(thread, mIsRunning, false);
thread->RegReadContext();
return thread->registers.Get(registerFromDword(IndexOfRegister)); return thread->registers.Get(registerFromDword(IndexOfRegister));
} }
@ -258,11 +283,8 @@ public:
auto thread = threadFromHandle(hActiveThread); auto thread = threadFromHandle(hActiveThread);
if (!thread) if (!thread)
return false; return false;
if(mIsRunning) ThreadSuspender suspender(thread, mIsRunning, true);
thread->RegReadContext();
thread->registers.Set(registerFromDword(IndexOfRegister), NewRegisterValue); thread->registers.Set(registerFromDword(IndexOfRegister), NewRegisterValue);
if(mIsRunning)
thread->RegWriteContext();
return true; return true;
} }
@ -273,8 +295,7 @@ public:
auto thread = threadFromHandle(hActiveThread); auto thread = threadFromHandle(hActiveThread);
if (!thread || !titcontext) if (!thread || !titcontext)
return false; return false;
if(mIsRunning) ThreadSuspender suspender(thread, mIsRunning, false);
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();
@ -317,8 +338,7 @@ public:
auto thread = threadFromHandle(hActiveThread); auto thread = threadFromHandle(hActiveThread);
if (!thread || !titcontext) if (!thread || !titcontext)
return false; return false;
if(mIsRunning) ThreadSuspender suspender(thread, mIsRunning, true);
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;
@ -353,8 +373,6 @@ 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;
} }
@ -572,16 +590,25 @@ public:
{ {
if (!mProcess) if (!mProcess)
return false; return false;
if(mIsRunning) auto running = mIsRunning;
if(running)
{
for(auto & thread : mProcess->threads)
thread.second->Suspend();
mProcess->RegReadContext(); mProcess->RegReadContext();
}
if(!mProcess->SetHardwareBreakpoint(bpxAddress, 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; return false;
if(mIsRunning) if(running)
{
mProcess->RegWriteContext(); mProcess->RegWriteContext();
for(auto & thread : mProcess->threads)
thread.second->Resume();
}
return true; return true;
} }
@ -622,9 +649,9 @@ public:
{ {
for(auto & it : mProcesses) for(auto & it : mProcesses)
{ {
auto breakpoints = it.second.breakpoints; //explicit copy auto breakpoints = it.second->breakpoints; //explicit copy
for(const auto & jt : breakpoints) for(const auto & jt : breakpoints)
it.second.DeleteGenericBreakpoint(jt.second); it.second->DeleteGenericBreakpoint(jt.second);
} }
return false; return false;
} }
@ -756,10 +783,10 @@ private: //functions
auto foundP = mProcesses.find(uint32(tbi.ClientId.UniqueProcess)); auto foundP = mProcesses.find(uint32(tbi.ClientId.UniqueProcess));
if(foundP == mProcesses.end()) if(foundP == mProcesses.end())
return nullptr; return nullptr;
auto foundT = foundP->second.threads.find(uint32(tbi.ClientId.UniqueThread)); auto foundT = foundP->second->threads.find(uint32(tbi.ClientId.UniqueThread));
if(foundT == foundP->second.threads.end()) if(foundT == foundP->second->threads.end())
return nullptr; return nullptr;
return &foundT->second; return foundT->second.get();
} }
Process* processFromHandle(HANDLE hProcess) Process* processFromHandle(HANDLE hProcess)
@ -767,7 +794,7 @@ private: //functions
auto foundP = mProcesses.find(GetProcessId(hProcess)); auto foundP = mProcesses.find(GetProcessId(hProcess));
if(foundP == mProcesses.end()) if(foundP == mProcesses.end())
return nullptr; return nullptr;
return &foundP->second; return foundP->second.get();
} }
static HardwareType hwtypeFromTitan(DWORD type) static HardwareType hwtypeFromTitan(DWORD type)