1 /* 2 * PROJECT: Dr. Watson crash reporter 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Debug loop 5 * COPYRIGHT: Copyright 2017 Mark Jansen <mark.jansen@reactos.org> 6 */ 7 8 #include "precomp.h" 9 #include <psapi.h> 10 11 #define MS_VC_EXCEPTION_THREAD_NAME 0x406d1388 12 13 ModuleData::ModuleData(void* addr) 14 { 15 BaseAddress = addr; 16 Size = 0; 17 Unloaded = false; 18 } 19 20 void ModuleData::Update(HANDLE hProcess) 21 { 22 MODULEINFO mi = {0}; 23 GetModuleInformation(hProcess, (HMODULE)BaseAddress, &mi, sizeof(mi)); 24 assert(BaseAddress == mi.lpBaseOfDll); 25 Size = mi.SizeOfImage; 26 27 ModuleName.resize(MAX_PATH); 28 DWORD dwLen = GetModuleFileNameExA(hProcess, (HMODULE)BaseAddress, &ModuleName[0], ModuleName.size()); 29 ModuleName.resize(dwLen); 30 } 31 32 33 ThreadData::ThreadData(HANDLE handle) 34 : Handle(handle) 35 { 36 memset(&Context, 0, sizeof(Context)); 37 } 38 39 void ThreadData::Update() 40 { 41 Context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_DEBUG_REGISTERS; 42 GetThreadContext(Handle, &Context); 43 } 44 45 DumpData::DumpData() 46 :ProcessID(0) 47 ,ThreadID(0) 48 ,ProcessHandle(NULL) 49 ,Event(NULL) 50 ,FirstBPHit(false) 51 { 52 memset(&ExceptionInfo, 0, sizeof(ExceptionInfo)); 53 } 54 55 56 bool UpdateFromEvent(DEBUG_EVENT& evt, DumpData& data) 57 { 58 switch(evt.dwDebugEventCode) 59 { 60 case CREATE_PROCESS_DEBUG_EVENT: 61 { 62 data.ProcessPath.resize(MAX_PATH*2); 63 DWORD len = GetModuleFileNameExW(evt.u.CreateProcessInfo.hProcess, NULL, &data.ProcessPath[0], data.ProcessPath.size()); 64 if (len) 65 { 66 data.ProcessPath.resize(len); 67 std::string::size_type pos = data.ProcessPath.find_last_of(L"\\/"); 68 if (pos != std::string::npos) 69 data.ProcessName = data.ProcessPath.substr(pos+1); 70 } 71 else 72 { 73 data.ProcessPath = L"??"; 74 } 75 if (data.ProcessName.empty()) 76 data.ProcessName = data.ProcessPath; 77 78 CloseHandle(evt.u.CreateProcessInfo.hFile); 79 data.ProcessID = evt.dwProcessId; 80 data.ProcessHandle = evt.u.CreateProcessInfo.hProcess; 81 data.Threads[evt.dwThreadId] = ThreadData(evt.u.CreateProcessInfo.hThread); 82 } 83 break; 84 case CREATE_THREAD_DEBUG_EVENT: 85 data.Threads[evt.dwThreadId] = ThreadData(evt.u.CreateThread.hThread); 86 break; 87 case EXIT_THREAD_DEBUG_EVENT: 88 { 89 ThreadMap::iterator it = data.Threads.find(evt.dwThreadId); 90 if (it != data.Threads.end()) 91 { 92 data.Threads.erase(it); 93 } 94 } 95 break; 96 case LOAD_DLL_DEBUG_EVENT: 97 CloseHandle(evt.u.LoadDll.hFile); 98 for (size_t n = 0; n < data.Modules.size(); ++n) 99 { 100 if (data.Modules[n].BaseAddress == evt.u.LoadDll.lpBaseOfDll) 101 { 102 data.Modules[n].Unloaded = false; 103 return true; 104 } 105 } 106 data.Modules.push_back(ModuleData(evt.u.LoadDll.lpBaseOfDll)); 107 break; 108 case UNLOAD_DLL_DEBUG_EVENT: 109 for (size_t n = 0; n < data.Modules.size(); ++n) 110 { 111 if (data.Modules[n].BaseAddress == evt.u.UnloadDll.lpBaseOfDll) 112 data.Modules[n].Unloaded = true; 113 } 114 break; 115 case OUTPUT_DEBUG_STRING_EVENT: // ignore 116 break; 117 case EXCEPTION_DEBUG_EVENT: 118 if (evt.u.Exception.dwFirstChance) 119 { 120 switch(evt.u.Exception.ExceptionRecord.ExceptionCode) 121 { 122 case EXCEPTION_BREAKPOINT: 123 if (!data.FirstBPHit) 124 { 125 data.FirstBPHit = true; 126 127 if (data.Event) 128 { 129 SetEvent(data.Event); 130 CloseHandle(data.Event); 131 data.Event = NULL; 132 } 133 return true; 134 } 135 break; 136 case MS_VC_EXCEPTION_THREAD_NAME: 137 /* Thread name */ 138 return true; 139 case DBG_CONTROL_C: 140 case DBG_CONTROL_BREAK: 141 return true; 142 } 143 } 144 data.ExceptionInfo = evt.u.Exception; 145 data.ThreadID = evt.dwThreadId; 146 return false; 147 case EXIT_PROCESS_DEBUG_EVENT: 148 //assert(FALSE); 149 return false; 150 case RIP_EVENT: 151 //assert(FALSE); 152 return false; 153 default: 154 assert(false); 155 } 156 return true; 157 } 158 159