working single step with callbacks

This commit is contained in:
Mr. eXoDia 2015-04-05 05:11:51 +02:00
parent 25b4dd40de
commit 1a072a78c5
12 changed files with 100 additions and 40 deletions

View File

@ -36,8 +36,13 @@ namespace GleeBug
typedef std::map<DWORD, ThreadInfo> ThreadMap;
//callback function typedefs
typedef std::function<void(const Debugger &)> StepCallback;
typedef std::function<void()> StepCallback;
//vector typedefs
typedef std::vector<StepCallback> StepCallbackVector;
//macros
#define BIND(thisPtr, funcPtr) std::bind(&funcPtr, thisPtr)
};
#endif //_DEBUGGER_GLOBAL_H

View File

@ -7,12 +7,12 @@ namespace GleeBug
//DLL housekeeping
MODULEINFO modinfo;
memset(&modinfo, 0, sizeof(MODULEINFO));
GetModuleInformation(_curProcess->hProcess,
GetModuleInformation(_process->hProcess,
(HMODULE)loadDll.lpBaseOfDll,
&modinfo,
sizeof(MODULEINFO));
DllInfo dll(loadDll.lpBaseOfDll, modinfo.SizeOfImage, modinfo.EntryPoint);
_curProcess->dlls.insert({ Range(dll.lpBaseOfDll, dll.lpBaseOfDll + dll.sizeOfImage - 1), dll });
_process->dlls.insert({ Range(dll.lpBaseOfDll, dll.lpBaseOfDll + dll.sizeOfImage - 1), dll });
//call the debug event callback
cbLoadDllEvent(loadDll, dll);
@ -25,14 +25,14 @@ namespace GleeBug
{
//call the debug event callback
ULONG_PTR lpBaseOfDll = (ULONG_PTR)unloadDll.lpBaseOfDll;
auto dll = _curProcess->dlls.find(Range(lpBaseOfDll, lpBaseOfDll));
if (dll != _curProcess->dlls.end())
auto dll = _process->dlls.find(Range(lpBaseOfDll, lpBaseOfDll));
if (dll != _process->dlls.end())
cbUnloadDllEvent(unloadDll, dll->second);
else
cbUnloadDllEvent(unloadDll, DllInfo(unloadDll.lpBaseOfDll, 0, 0));
//DLL housekeeping
if (dll != _curProcess->dlls.end())
_curProcess->dlls.erase(dll);
if (dll != _process->dlls.end())
_process->dlls.erase(dll);
}
};

View File

@ -4,9 +4,9 @@ namespace GleeBug
{
void Debugger::exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
{
if (!_curProcess->systemBreakpoint) //handle system breakpoint
if (!_process->systemBreakpoint) //handle system breakpoint
{
_curProcess->systemBreakpoint = true;
_process->systemBreakpoint = true;
_continueStatus = DBG_CONTINUE;
//call the callback
@ -19,6 +19,21 @@ namespace GleeBug
void Debugger::exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
{
if (_thread->isSingleStepping) //handle single step
{
_thread->isSingleStepping = false;
_continueStatus = DBG_CONTINUE;
//call the callbacks
StepCallbackVector cbStepCopy = _thread->stepCallbacks;
_thread->stepCallbacks.clear();
for (auto cbStep : cbStepCopy)
cbStep();
cbStep();
}
else //handle other single step exceptions
{
}
}
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)

View File

@ -9,22 +9,22 @@ namespace GleeBug
createProcess.hProcess,
_debugEvent.dwThreadId);
_processes.insert({ process.dwProcessId, process });
_curProcess = &_processes.find(process.dwProcessId)->second;
_process = &_processes.find(process.dwProcessId)->second;
//thread housekeeping (main thread is created implicitly)
ThreadInfo thread(_debugEvent.dwThreadId,
createProcess.hThread,
createProcess.lpThreadLocalBase,
createProcess.lpStartAddress);
_curProcess->threads.insert({ thread.dwThreadId, thread });
_curProcess->curThread = &_curProcess->threads.find(thread.dwThreadId)->second;
_process->threads.insert({ thread.dwThreadId, thread });
_thread = _process->thread = &_process->threads.find(thread.dwThreadId)->second;
//read thread context from main thread
if (!_curProcess->curThread->RegReadContext())
if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!");
//call the debug event callback
cbCreateProcessEvent(createProcess, *_curProcess);
cbCreateProcessEvent(createProcess, *_process);
//close the file handle
CloseHandle(createProcess.hFile);
@ -37,12 +37,12 @@ namespace GleeBug
_breakDebugger = true;
//call the debug event callback
cbExitProcessEvent(exitProcess, *_curProcess);
cbExitProcessEvent(exitProcess, *_process);
//process housekeeping
_processes.erase(_debugEvent.dwProcessId);
//set the current process
_curProcess = nullptr;
_process = nullptr;
}
};

View File

@ -5,27 +5,27 @@ namespace GleeBug
void Debugger::createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread)
{
//thread housekeeping
_curProcess->threads.insert({ _debugEvent.dwThreadId,
_process->threads.insert({ _debugEvent.dwThreadId,
ThreadInfo(_debugEvent.dwThreadId, createThread.hThread, createThread.lpThreadLocalBase, createThread.lpStartAddress) });
//set the current thread
_curProcess->curThread = &_curProcess->threads.find(_debugEvent.dwThreadId)->second;
if (!_curProcess->curThread->RegReadContext())
_thread = _process->thread = &_process->threads.find(_debugEvent.dwThreadId)->second;
if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!");
//call the debug event callback
cbCreateThreadEvent(createThread, *_curProcess->curThread);
cbCreateThreadEvent(createThread, *_thread);
}
void Debugger::exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread)
{
//call the debug event callback
cbExitThreadEvent(exitThread, *_curProcess->curThread);
cbExitThreadEvent(exitThread, *_thread);
//thread housekeeping
_curProcess->threads.erase(_debugEvent.dwThreadId);
_process->threads.erase(_debugEvent.dwThreadId);
//set the current thread
_curProcess->curThread = nullptr;
_thread = _process->thread = nullptr;
}
};

View File

@ -21,18 +21,18 @@ namespace GleeBug
//set the current process and thread
if (_processes.count(_debugEvent.dwProcessId))
{
_curProcess = &_processes[_debugEvent.dwProcessId];
if (_curProcess->threads.count(_debugEvent.dwThreadId))
_process = &_processes[_debugEvent.dwProcessId];
if (_process->threads.count(_debugEvent.dwThreadId))
{
_curProcess->curThread = &_curProcess->threads[_debugEvent.dwThreadId];
if (!_curProcess->curThread->RegReadContext())
_thread = _process->thread = &_process->threads[_debugEvent.dwThreadId];
if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!");
}
else
_curProcess->curThread = nullptr;
_thread = _process->thread = nullptr;
}
else
_curProcess = nullptr;
_process = nullptr;
//dispatch the debug event
switch (_debugEvent.dwDebugEventCode)
@ -67,9 +67,9 @@ namespace GleeBug
}
//write the register context
if (_curProcess && _curProcess->curThread)
if (_thread)
{
if (!_curProcess->curThread->RegWriteContext())
if (!_thread->RegWriteContext())
cbInternalError("ThreadInfo::RegWriteContext() failed!");
}
@ -80,6 +80,6 @@ namespace GleeBug
//cleanup
_processes.clear();
_curProcess = nullptr;
_process = nullptr;
}
};

View File

@ -4,7 +4,7 @@ namespace GleeBug
{
ProcessInfo::ProcessInfo()
{
this->curThread = nullptr;
this->thread = nullptr;
this->systemBreakpoint = false;
this->hProcess = INVALID_HANDLE_VALUE;
}

View File

@ -17,7 +17,7 @@ namespace GleeBug
DWORD dwProcessId;
DWORD dwMainThreadId;
ThreadInfo* curThread;
ThreadInfo* thread;
bool systemBreakpoint;
ThreadMap threads;

View File

@ -41,4 +41,16 @@ namespace GleeBug
ResumeThread(this->hThread);
return bReturn;
}
void ThreadInfo::StepInto(StepCallback cbStep)
{
StepInto();
stepCallbacks.push_back(cbStep);
}
void ThreadInfo::StepInto()
{
registers.SetTrapFlag();
isSingleStepping = true;
}
};

View File

@ -16,7 +16,10 @@ namespace GleeBug
HANDLE hThread;
ULONG_PTR lpThreadLocalBase;
ULONG_PTR lpStartAddress;
RegistersInfo registers;
StepCallbackVector stepCallbacks;
bool isSingleStepping;
/**
\brief Default constructor.
@ -43,6 +46,10 @@ namespace GleeBug
*/
bool RegWriteContext();
void StepInto(StepCallback cbStep);
void StepInto();
private:
CONTEXT _oldContext;
};

View File

@ -101,6 +101,12 @@ namespace GleeBug
virtual void cbRipEvent(const RIP_INFO & rip) {};
protected: //other callbacks
/**
\brief Internal error callback. Provide an implementation to use this callback.
\param error The error message.
*/
virtual void cbInternalError(const std::string & error) {};
/**
\brief Unhandled exception callback. Provide an implementation to use this callback.
\param exceptionRecord The exception record.
@ -114,10 +120,9 @@ namespace GleeBug
virtual void cbSystemBreakpoint() {};
/**
\brief Internal error callback. Provide an implementation to use this callback.
\param error The error message.
\brief Step callback. Provide an implementation to use this callback.
*/
virtual void cbInternalError(const std::string & error) {};
virtual void cbStep() {};
protected: //core debug event handlers
/**
@ -195,8 +200,17 @@ namespace GleeBug
bool _breakDebugger;
DEBUG_EVENT _debugEvent;
ProcessMap _processes;
ProcessInfo* _curProcess;
bool _isRunning;
/**
\brief The current process (can be null in some cases).
*/
ProcessInfo* _process;
/**
\brief The current thread (can be null in some cases). Should be a copy of _process->thread.
*/
ThreadInfo* _thread;
};
};

View File

@ -69,10 +69,17 @@ protected:
rip.dwError);
};
void boobs()
{
printf("(.)Y(.) 0x%p\n",
_thread->registers.Rip);
}
virtual void cbSystemBreakpoint()
{
printf("System breakpoint reached, CIP: 0x%p\n",
_curProcess->curThread->registers.Rip);
_thread->registers.Rip);
_thread->StepInto(BIND(this, MyDebugger::boobs));
}
virtual void cbInternalError(const std::string & error)