mirror of https://github.com/x64dbg/TitanEngine
parent
ec7a8b9352
commit
e80b959150
|
|
@ -29,9 +29,7 @@ DWORD ProcessExitCode = 0;
|
|||
HANDLE DBGFileHandle;
|
||||
std::vector<ULONG_PTR> tlsCallBackList;
|
||||
std::vector<PROCESS_ITEM_DATA> hListProcess;
|
||||
DWORD engineStepCount = 0;
|
||||
LPVOID engineStepCallBack = NULL;
|
||||
bool engineStepActive = false;
|
||||
std::unordered_map<DWORD, EngineStepThreadState> engineStepThreads;
|
||||
bool engineProcessIsNowDetached = false;
|
||||
DWORD DBGCode = DBG_CONTINUE;
|
||||
bool engineFileIsBeingDebugged = false;
|
||||
|
|
@ -90,6 +88,7 @@ void DebuggerReset()
|
|||
std::vector<BreakPointDetail>().swap(BreakPointBuffer);
|
||||
std::unordered_map<ULONG_PTR, MemoryBreakpointPageDetail>().swap(MemoryBreakpointPages);
|
||||
recentlyDeletedBpx.clear();
|
||||
engineStepThreads.clear();
|
||||
}
|
||||
|
||||
void ClearProcessList()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define _GLOBAL_DEBUGGER_H
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <Windows.h>
|
||||
|
||||
extern HARDWARE_DATA DebugRegister[4];
|
||||
|
|
@ -29,9 +30,18 @@ extern DWORD ProcessExitCode;
|
|||
extern HANDLE DBGFileHandle;
|
||||
extern std::vector<ULONG_PTR> tlsCallBackList;
|
||||
extern std::vector<PROCESS_ITEM_DATA> hListProcess;
|
||||
extern DWORD engineStepCount;
|
||||
extern LPVOID engineStepCallBack;
|
||||
extern bool engineStepActive;
|
||||
// Per-thread pending single-step state. A single-step (user step or the internal
|
||||
// step-over of a breakpoint) is always armed on a specific thread by setting that
|
||||
// thread's trap flag, but the resulting STATUS_SINGLE_STEP event can be delivered
|
||||
// interleaved with other threads' events. Keying the step state by thread id makes
|
||||
// each thread consume only its own step, and allows several threads to be stepped
|
||||
// independently (matching GleeBug).
|
||||
struct EngineStepThreadState
|
||||
{
|
||||
LPVOID callback; // step callback to fire when the step completes
|
||||
DWORD count; // remaining repeats (0 = fire the callback on the next step)
|
||||
};
|
||||
extern std::unordered_map<DWORD, EngineStepThreadState> engineStepThreads;
|
||||
extern bool engineProcessIsNowDetached;
|
||||
extern DWORD DBGCode;
|
||||
extern bool engineFileIsBeingDebugged;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ __declspec(dllexport) void TITCALL ForceClose()
|
|||
__declspec(dllexport) void TITCALL StepInto(LPVOID StepCallBack)
|
||||
{
|
||||
EnterCriticalSection(&engineStepActiveCr);
|
||||
if(!engineStepActive)
|
||||
// Arm a single-step for the current event thread only. State is per-thread, so a
|
||||
// step already pending on another thread does not block this one.
|
||||
if(engineStepThreads.find(DBGEvent.dwThreadId) == engineStepThreads.end())
|
||||
{
|
||||
ULONG_PTR ueCurrentPosition = GetContextData(UE_CIP);
|
||||
unsigned char instr[16];
|
||||
|
|
@ -60,9 +62,7 @@ __declspec(dllexport) void TITCALL StepInto(LPVOID StepCallBack)
|
|||
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
||||
SetThreadContext(hActiveThread, &myDBGContext);
|
||||
EngineCloseHandle(hActiveThread);
|
||||
engineStepActive = true;
|
||||
engineStepCallBack = StepCallBack;
|
||||
engineStepCount = 0;
|
||||
engineStepThreads[DBGEvent.dwThreadId] = { StepCallBack, 0 };
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&engineStepActiveCr);
|
||||
|
|
@ -93,7 +93,11 @@ __declspec(dllexport) void TITCALL StepOut(LPVOID StepOut, bool StepFinal)
|
|||
__declspec(dllexport) void TITCALL SingleStep(DWORD StepCount, LPVOID StepCallBack)
|
||||
{
|
||||
StepInto(StepCallBack);
|
||||
engineStepCount = StepCount - 1; //We already stepped once
|
||||
EnterCriticalSection(&engineStepActiveCr);
|
||||
auto it = engineStepThreads.find(DBGEvent.dwThreadId);
|
||||
if(it != engineStepThreads.end())
|
||||
it->second.count = StepCount - 1; //We already stepped once
|
||||
LeaveCriticalSection(&engineStepActiveCr);
|
||||
}
|
||||
|
||||
__declspec(dllexport) void TITCALL SetNextDbgContinueStatus(DWORD SetDbgCode)
|
||||
|
|
|
|||
|
|
@ -16,22 +16,28 @@
|
|||
static void engineStep()
|
||||
{
|
||||
EnterCriticalSection(&engineStepActiveCr);
|
||||
if(engineStepActive)
|
||||
// Only deliver the pending single-step to the thread it was armed for. State is
|
||||
// per-thread, so an automatic breakpoint step-over on a different thread cannot
|
||||
// consume this thread's step or fire its callback on the wrong thread.
|
||||
auto it = engineStepThreads.find(DBGEvent.dwThreadId);
|
||||
if(it != engineStepThreads.end())
|
||||
{
|
||||
DBGCode = DBG_CONTINUE;
|
||||
if(engineStepCount == 0)
|
||||
if(it->second.count == 0)
|
||||
{
|
||||
typedef void(TITCALL * fCustomBreakPoint)(void);
|
||||
auto cbStep = fCustomBreakPoint(engineStepCallBack);
|
||||
engineStepActive = false;
|
||||
engineStepCallBack = NULL;
|
||||
auto cbStep = fCustomBreakPoint(it->second.callback);
|
||||
engineStepThreads.erase(it);
|
||||
LeaveCriticalSection(&engineStepActiveCr);
|
||||
cbStep();
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleStep(engineStepCount, engineStepCallBack);
|
||||
auto count = it->second.count;
|
||||
auto callback = it->second.callback;
|
||||
engineStepThreads.erase(it); // SingleStep re-arms this thread's entry
|
||||
LeaveCriticalSection(&engineStepActiveCr);
|
||||
SingleStep(count, callback);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1288,7 +1294,11 @@ __declspec(dllexport) void TITCALL DebugLoop()
|
|||
//general unhandled exception callback
|
||||
if(DBGCode == DBG_EXCEPTION_NOT_HANDLED)
|
||||
{
|
||||
engineStepActive = false;
|
||||
// The current thread's pending single-step (if any) did not complete
|
||||
// normally; cancel it. Other threads' steps are unaffected.
|
||||
EnterCriticalSection(&engineStepActiveCr);
|
||||
engineStepThreads.erase(DBGEvent.dwThreadId);
|
||||
LeaveCriticalSection(&engineStepActiveCr);
|
||||
|
||||
if(DBGCustomHandler->chUnhandledException != NULL)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue