mirror of
https://github.com/reactos/reactos.git
synced 2024-08-26 13:18:51 +00:00
![William Kent](/assets/img/avatar_default.png)
* Convert to wWinMain() * Add a resource file * Use a slightly friendlier application name * Add code to load the output path from the Registry * Add localized string resources
159 lines
4.4 KiB
C++
159 lines
4.4 KiB
C++
/*
|
|
* PROJECT: Dr. Watson crash reporter
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: Debug loop
|
|
* COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#include <psapi.h>
|
|
|
|
#define MS_VC_EXCEPTION_THREAD_NAME 0x406d1388
|
|
|
|
ModuleData::ModuleData(void* addr)
|
|
{
|
|
BaseAddress = addr;
|
|
Size = 0;
|
|
Unloaded = false;
|
|
}
|
|
|
|
void ModuleData::Update(HANDLE hProcess)
|
|
{
|
|
MODULEINFO mi = {0};
|
|
GetModuleInformation(hProcess, (HMODULE)BaseAddress, &mi, sizeof(mi));
|
|
assert(BaseAddress == mi.lpBaseOfDll);
|
|
Size = mi.SizeOfImage;
|
|
|
|
ModuleName.resize(MAX_PATH);
|
|
DWORD dwLen = GetModuleFileNameExA(hProcess, (HMODULE)BaseAddress, &ModuleName[0], ModuleName.size());
|
|
ModuleName.resize(dwLen);
|
|
}
|
|
|
|
|
|
ThreadData::ThreadData(HANDLE handle)
|
|
: Handle(handle)
|
|
{
|
|
memset(&Context, 0, sizeof(Context));
|
|
}
|
|
|
|
void ThreadData::Update()
|
|
{
|
|
Context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_DEBUG_REGISTERS;
|
|
GetThreadContext(Handle, &Context);
|
|
}
|
|
|
|
DumpData::DumpData()
|
|
:ProcessID(0)
|
|
,ThreadID(0)
|
|
,ProcessHandle(NULL)
|
|
,Event(NULL)
|
|
,FirstBPHit(false)
|
|
{
|
|
memset(&ExceptionInfo, 0, sizeof(ExceptionInfo));
|
|
}
|
|
|
|
|
|
bool UpdateFromEvent(DEBUG_EVENT& evt, DumpData& data)
|
|
{
|
|
switch(evt.dwDebugEventCode)
|
|
{
|
|
case CREATE_PROCESS_DEBUG_EVENT:
|
|
{
|
|
data.ProcessPath.resize(MAX_PATH*2);
|
|
DWORD len = GetModuleFileNameExW(evt.u.CreateProcessInfo.hProcess, NULL, &data.ProcessPath[0], data.ProcessPath.size());
|
|
if (len)
|
|
{
|
|
data.ProcessPath.resize(len);
|
|
std::string::size_type pos = data.ProcessPath.find_last_of(L"\\/");
|
|
if (pos != std::string::npos)
|
|
data.ProcessName = data.ProcessPath.substr(pos+1);
|
|
}
|
|
else
|
|
{
|
|
data.ProcessPath = L"??";
|
|
}
|
|
if (data.ProcessName.empty())
|
|
data.ProcessName = data.ProcessPath;
|
|
|
|
CloseHandle(evt.u.CreateProcessInfo.hFile);
|
|
data.ProcessID = evt.dwProcessId;
|
|
data.ProcessHandle = evt.u.CreateProcessInfo.hProcess;
|
|
data.Threads[evt.dwThreadId] = ThreadData(evt.u.CreateProcessInfo.hThread);
|
|
}
|
|
break;
|
|
case CREATE_THREAD_DEBUG_EVENT:
|
|
data.Threads[evt.dwThreadId] = ThreadData(evt.u.CreateThread.hThread);
|
|
break;
|
|
case EXIT_THREAD_DEBUG_EVENT:
|
|
{
|
|
ThreadMap::iterator it = data.Threads.find(evt.dwThreadId);
|
|
if (it != data.Threads.end())
|
|
{
|
|
data.Threads.erase(it);
|
|
}
|
|
}
|
|
break;
|
|
case LOAD_DLL_DEBUG_EVENT:
|
|
CloseHandle(evt.u.LoadDll.hFile);
|
|
for (size_t n = 0; n < data.Modules.size(); ++n)
|
|
{
|
|
if (data.Modules[n].BaseAddress == evt.u.LoadDll.lpBaseOfDll)
|
|
{
|
|
data.Modules[n].Unloaded = false;
|
|
return true;
|
|
}
|
|
}
|
|
data.Modules.push_back(ModuleData(evt.u.LoadDll.lpBaseOfDll));
|
|
break;
|
|
case UNLOAD_DLL_DEBUG_EVENT:
|
|
for (size_t n = 0; n < data.Modules.size(); ++n)
|
|
{
|
|
if (data.Modules[n].BaseAddress == evt.u.UnloadDll.lpBaseOfDll)
|
|
data.Modules[n].Unloaded = true;
|
|
}
|
|
break;
|
|
case OUTPUT_DEBUG_STRING_EVENT: // ignore
|
|
break;
|
|
case EXCEPTION_DEBUG_EVENT:
|
|
if (evt.u.Exception.dwFirstChance)
|
|
{
|
|
switch(evt.u.Exception.ExceptionRecord.ExceptionCode)
|
|
{
|
|
case EXCEPTION_BREAKPOINT:
|
|
if (!data.FirstBPHit)
|
|
{
|
|
data.FirstBPHit = true;
|
|
|
|
if (data.Event)
|
|
{
|
|
SetEvent(data.Event);
|
|
CloseHandle(data.Event);
|
|
data.Event = NULL;
|
|
}
|
|
return true;
|
|
}
|
|
break;
|
|
case MS_VC_EXCEPTION_THREAD_NAME:
|
|
/* Thread name */
|
|
return true;
|
|
case DBG_CONTROL_C:
|
|
case DBG_CONTROL_BREAK:
|
|
return true;
|
|
}
|
|
}
|
|
data.ExceptionInfo = evt.u.Exception;
|
|
data.ThreadID = evt.dwThreadId;
|
|
return false;
|
|
case EXIT_PROCESS_DEBUG_EVENT:
|
|
//assert(FALSE);
|
|
return false;
|
|
case RIP_EVENT:
|
|
//assert(FALSE);
|
|
return false;
|
|
default:
|
|
assert(false);
|
|
}
|
|
return true;
|
|
}
|
|
|