MiniDumpDebugger.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. #include "MiniDumpDebugger.h"
  2. #include "DebugManager.h"
  3. #pragma warning(disable:4091)
  4. #include <DbgHelp.h>
  5. #include "BeefySysLib/util/AllocDebug.h"
  6. USING_NS_BF_DBG;
  7. USING_NS_BF;
  8. MiniDumpDebugger::MiniDumpDebugger(DebugManager* debugManager, DbgMiniDump* miniDump) : WinDebugger(debugManager)
  9. {
  10. mMiniDump = miniDump;
  11. mRunState = RunState_Paused;
  12. mExceptionThread = NULL;
  13. mExceptionContextRVA = 0;
  14. mDebugTarget = new DebugTarget(this);
  15. for (auto section : mMiniDump->mDirectory)
  16. {
  17. if (section.mStreamType == ThreadExListStream)
  18. {
  19. auto& threadEx = mMiniDump->GetStreamData<MINIDUMP_THREAD_EX_LIST>(section);
  20. /*WdThreadInfo* threadInfo = new WdThreadInfo();
  21. threadInfo->mThreadId = threadEx.ThreadId;
  22. mThreadList.Add(threadInfo);
  23. if (mActiveThread == NULL)
  24. {
  25. mActiveThread = threadInfo;
  26. mDebuggerWaitingThread = threadInfo;
  27. }
  28. mThreadMap[threadInfo->mThreadId] = threadInfo;*/
  29. }
  30. else if (section.mStreamType == ModuleListStream)
  31. {
  32. auto& moduleList = mMiniDump->GetStreamData<MINIDUMP_MODULE_LIST>(section);
  33. for (int moduleIdx = 0; moduleIdx < (int)moduleList.NumberOfModules; moduleIdx++)
  34. {
  35. auto& module = moduleList.Modules[moduleIdx];
  36. COFF* dbgModule = new COFF(mDebugTarget);
  37. if (mDebugTarget->mTargetBinary == NULL)
  38. {
  39. mDebugTarget->mLaunchBinary = dbgModule;
  40. mDebugTarget->mTargetBinary = dbgModule;
  41. }
  42. dbgModule->mImageBase = module.BaseOfImage;
  43. dbgModule->mImageSize = module.SizeOfImage;
  44. //TODO: 'get' the actual image
  45. dbgModule->mTimeStamp = module.TimeDateStamp;
  46. //dbgModule->mExpectedFileSize = module.;
  47. const wchar_t* moduleName = &mMiniDump->GetData<wchar_t>(module.ModuleNameRva + 4);
  48. dbgModule->mFilePath = UTF8Encode(moduleName);
  49. dbgModule->mDisplayName = GetFileName(dbgModule->mFilePath);
  50. struct _CodeViewEntry
  51. {
  52. public:
  53. int32 mSig;
  54. uint8 mGUID[16];
  55. int32 mAge;
  56. const char mPDBPath[1];
  57. };
  58. auto& codeViewEntry = mMiniDump->GetData<_CodeViewEntry>(module.CvRecord.Rva);
  59. if (codeViewEntry.mSig == 'SDSR')
  60. {
  61. // Do nothing, let the binay load the PDB itself
  62. //dbgModule->LoadPDB(codeViewEntry.mPDBPath, codeViewEntry.mGUID, codeViewEntry.mAge);
  63. }
  64. auto miscEntry = &mMiniDump->GetData<char>(module.MiscRecord.Rva);
  65. mDebugTarget->AddDbgModule(dbgModule);
  66. //TESTING
  67. /*{
  68. AutoCrit autoCrit(mDebugManager->mCritSect);
  69. mDebuggerThreadId = GetCurrentThreadId();
  70. dbgModule->RequestImage();
  71. dbgModule->RequestDebugInfo();
  72. mDebuggerThreadId = 0;
  73. }*/
  74. mPendingImageLoad.Add(dbgModule);
  75. // This is optional
  76. mPendingDebugInfoRequests.Add(dbgModule);
  77. }
  78. }
  79. else if (section.mStreamType == ThreadListStream)
  80. {
  81. auto& threadList = mMiniDump->GetStreamData<MINIDUMP_THREAD_LIST>(section);
  82. for (int threadIdx = 0; threadIdx < (int)threadList.NumberOfThreads; threadIdx++)
  83. {
  84. auto& thread = threadList.Threads[threadIdx];
  85. WdThreadInfo* threadInfo = new WdThreadInfo();
  86. threadInfo->mThreadId = thread.ThreadId;
  87. mThreadList.Add(threadInfo);
  88. if (mActiveThread == NULL)
  89. {
  90. mActiveThread = threadInfo;
  91. mDebuggerWaitingThread = threadInfo;
  92. }
  93. if ((thread.Stack.Memory.Rva != 0) && (thread.Stack.Memory.DataSize > 0))
  94. {
  95. void* stackMemory = &mMiniDump->GetData<uint8>(thread.Stack.Memory.Rva);
  96. MapMemory((addr_target)thread.Stack.StartOfMemoryRange, stackMemory, thread.Stack.Memory.DataSize);
  97. }
  98. mThreadMap[threadInfo->mThreadId] = threadInfo;
  99. }
  100. }
  101. else if (section.mStreamType == MemoryInfoListStream)
  102. {
  103. auto& memoryInfoList = mMiniDump->GetStreamData<MINIDUMP_MEMORY_INFO_LIST>(section);
  104. for (int memoryInfoIdx = 0; memoryInfoIdx < (int)memoryInfoList.NumberOfEntries; memoryInfoIdx++)
  105. {
  106. auto& memoryInfo = mMiniDump->GetData<MINIDUMP_MEMORY_INFO>(section.mDataRVA + memoryInfoList.SizeOfHeader + memoryInfoIdx*memoryInfoList.SizeOfEntry);
  107. }
  108. }
  109. else if (section.mStreamType == MemoryListStream)
  110. {
  111. auto& memoryList = mMiniDump->GetStreamData<MINIDUMP_MEMORY_LIST>(section);
  112. for (int memoryIdx = 0; memoryIdx < (int)memoryList.NumberOfMemoryRanges; memoryIdx++)
  113. {
  114. auto& memory = memoryList.MemoryRanges[memoryIdx];
  115. if (memory.Memory.Rva != 0)
  116. {
  117. void* memoryPtr = &mMiniDump->GetData<uint8>(memory.Memory.Rva);
  118. MapMemory((addr_target)memory.StartOfMemoryRange, memoryPtr, memory.Memory.DataSize);
  119. }
  120. }
  121. }
  122. else if (section.mStreamType == ExceptionStream)
  123. {
  124. auto& exceptionStream = mMiniDump->GetStreamData<MINIDUMP_EXCEPTION_STREAM>(section);
  125. //mCurException = exceptionStream.ExceptionRecord;
  126. mCurException.ExceptionCode = exceptionStream.ExceptionRecord.ExceptionCode;
  127. mCurException.ExceptionFlags = exceptionStream.ExceptionRecord.ExceptionFlags;
  128. mCurException.ExceptionAddress = (PVOID)exceptionStream.ExceptionRecord.ExceptionAddress;
  129. mCurException.NumberParameters = exceptionStream.ExceptionRecord.NumberParameters;
  130. for (int i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
  131. mCurException.ExceptionInformation[i] = exceptionStream.ExceptionRecord.ExceptionInformation[i];
  132. WdThreadInfo* threadInfo = NULL;
  133. if (mThreadMap.TryGetValue(exceptionStream.ThreadId, &threadInfo))
  134. {
  135. mActiveThread = threadInfo;
  136. mExplicitStopThread = mActiveThread;
  137. mRunState = RunState_Exception;
  138. /*mDebugPendingExpr->mException = StrFormat("Exception at 0x%@ in thread %d, exception code 0x%08X",
  139. mCurException.ExceptionAddress, mActiveThread->mThreadId, mCurException.ExceptionCode);*/
  140. mExceptionThread = mActiveThread;
  141. mExceptionContextRVA = exceptionStream.ThreadContext.Rva;
  142. }
  143. }
  144. else if (section.mStreamType == SystemInfoStream)
  145. {
  146. auto& systemInfo = mMiniDump->GetStreamData<MINIDUMP_SYSTEM_INFO>(section);
  147. }
  148. else if (section.mStreamType == MiscInfoStream)
  149. {
  150. auto& miscInfo = mMiniDump->GetStreamData<MINIDUMP_MISC_INFO>(section);
  151. }
  152. else if (section.mStreamType == 21/*SystemMemoryInfoStream*/)
  153. {
  154. auto data = ((uint8*)mMiniDump->mMF.mData + section.mDataRVA);
  155. }
  156. else if (section.mStreamType == 22/*ProcessVmCountersStream*/)
  157. {
  158. auto data = ((uint8*)mMiniDump->mMF.mData + section.mDataRVA);
  159. }
  160. else if (section.mStreamType == 24) // Thread names
  161. {
  162. auto data = ((uint8*)mMiniDump->mMF.mData + section.mDataRVA);
  163. int count = *(int32*)(data);
  164. for (int threadIdx = 0; threadIdx < count; threadIdx++)
  165. {
  166. struct ThreadNameInfo
  167. {
  168. int32 mThreadId;
  169. int32 mNameRVA;
  170. int32 mFlags; // Always zero
  171. };
  172. ThreadNameInfo* threadNameInfo = (ThreadNameInfo*)(data + 4 + threadIdx*12);
  173. int nameLen = *(int32*)((uint8*)mMiniDump->mMF.mData + threadNameInfo->mNameRVA);
  174. UTF16String name = UTF16String((wchar_t*)((uint8*)mMiniDump->mMF.mData + threadNameInfo->mNameRVA + 4), nameLen);
  175. WdThreadInfo* threadInfo = NULL;
  176. if (mThreadMap.TryGetValue(threadNameInfo->mThreadId, &threadInfo))
  177. {
  178. threadInfo->mName = UTF8Encode(name);
  179. }
  180. }
  181. }
  182. else if (section.mStreamType == 0x43500001) // kMinidumpStreamTypeCrashpadInfo
  183. {
  184. struct _MiniDumpCrashPadInfo
  185. {
  186. uint32 mVersion;
  187. GUID mReportID;
  188. GUID mClientID;
  189. };
  190. auto& crashPadInfo = mMiniDump->GetStreamData<_MiniDumpCrashPadInfo>(section);
  191. }
  192. else if (section.mStreamType == 0x4b6b0002) // Stability report
  193. {
  194. const char* report = &mMiniDump->GetStreamData<char>(section);
  195. }
  196. else if (section.mStreamType == 0x4b6b0002) // Stability report
  197. {
  198. const char* report = &mMiniDump->GetStreamData<char>(section);
  199. }
  200. else if (section.mStreamType == 0xBEEF00) // Error text
  201. {
  202. char* text = &mMiniDump->GetStreamData<char>(section);
  203. OutputMessage(String(text, section.mDataSize));
  204. }
  205. }
  206. Run();
  207. }
  208. MiniDumpDebugger::~MiniDumpDebugger()
  209. {
  210. delete mMiniDump;
  211. for (auto mappedFile : mMappedFiles)
  212. delete mappedFile;
  213. }
  214. void MiniDumpDebugger::MapMemory(addr_target addr, void* data, intptr_target size)
  215. {
  216. addr_target beginAddress = addr;
  217. addr_target endAddress = addr + size;
  218. int memSize = (int)(endAddress - beginAddress);
  219. for (int memOffset = 0; true; memOffset += DBG_MAX_LOOKBACK)
  220. {
  221. int curSize = memSize - memOffset;
  222. if (curSize <= 0)
  223. break;
  224. MiniDumpMemoryRegion* memRegion = mAlloc.Alloc<MiniDumpMemoryRegion>();
  225. memRegion->mAddress = beginAddress + memOffset;
  226. memRegion->mAddressLength = curSize;
  227. memRegion->mData = (uint8*)data + memOffset;
  228. memRegion->mNext = NULL;
  229. mMemMap.Insert(memRegion);
  230. }
  231. }
  232. MappedFile* MiniDumpDebugger::MapModule(COFF* dbgModule, const StringImpl& fileName)
  233. {
  234. auto mappedFile = new MappedFile();
  235. if (!mappedFile->Open(fileName))
  236. {
  237. delete mappedFile;
  238. return NULL;
  239. }
  240. mMappedFiles.Add(mappedFile);
  241. return mappedFile;
  242. }
  243. bool MiniDumpDebugger::PopulateRegisters(CPURegisters* registers)
  244. {
  245. if (mActiveThread == mExceptionThread)
  246. {
  247. auto& ctx = mMiniDump->GetData<BF_CONTEXT>(mExceptionContextRVA);
  248. return PopulateRegisters(registers, ctx);
  249. }
  250. for (auto section : mMiniDump->mDirectory)
  251. {
  252. if (section.mStreamType == ThreadExListStream)
  253. {
  254. }
  255. else if (section.mStreamType == ThreadListStream)
  256. {
  257. auto& threadList = mMiniDump->GetStreamData<MINIDUMP_THREAD_LIST>(section);
  258. for (int threadIdx = 0; threadIdx < (int)threadList.NumberOfThreads; threadIdx++)
  259. {
  260. auto& thread = threadList.Threads[threadIdx];
  261. if (thread.ThreadId == mActiveThread->mThreadId)
  262. {
  263. auto& ctx = mMiniDump->GetData<BF_CONTEXT>(thread.ThreadContext.Rva);
  264. return PopulateRegisters(registers, ctx);
  265. }
  266. }
  267. }
  268. }
  269. return false;
  270. }
  271. bool MiniDumpDebugger::ReadMemory(intptr address, uint64 length, void* dest, bool local)
  272. {
  273. if (local)
  274. {
  275. __try
  276. {
  277. memcpy(dest, (void*)address, length);
  278. return true;
  279. }
  280. __except (EXCEPTION_EXECUTE_HANDLER)
  281. {
  282. return false;
  283. }
  284. }
  285. uintptr useAddr = (uintptr)address;
  286. while (true)
  287. {
  288. MiniDumpMemoryRegion* memRegion = mMemMap.Get(useAddr, DBG_MAX_LOOKBACK);
  289. if (memRegion == NULL)
  290. return false;
  291. if ((uintptr)address < (uintptr)memRegion->mAddress)
  292. return false; // Out of bounds, done
  293. while (memRegion != NULL)
  294. {
  295. if (((uintptr)address >= (uintptr)memRegion->mAddress) && ((uintptr)address < memRegion->mAddress + memRegion->mAddressLength))
  296. {
  297. if ((uintptr)address + length <= (uintptr)(memRegion->mAddress + memRegion->mAddressLength))
  298. {
  299. // In bounds
  300. memcpy(dest, (uint8*)memRegion->mData + (address - memRegion->mAddress), length);
  301. }
  302. else
  303. {
  304. int headBytes = (int)(memRegion->mAddress + memRegion->mAddressLength - address);
  305. memcpy(dest, (uint8*)memRegion->mData + (address - memRegion->mAddress), headBytes);
  306. if (!ReadMemory(address + headBytes, length - headBytes, (uint8*)dest + headBytes, local))
  307. return false;
  308. }
  309. return true;
  310. }
  311. useAddr = BF_MIN(useAddr, memRegion->mAddress - 1);
  312. memRegion = memRegion->mNext;
  313. }
  314. //if (((uintptr)address < (uintptr)memRegion->mAddress) || ((uintptr)(address + length) > uintptr(memRegion->mAddress + memRegion->mAddressLength)))
  315. //return false; // Out of bounds
  316. }
  317. return false;
  318. }
  319. bool MiniDumpDebugger::WriteMemory(intptr address, void* src, uint64 length)
  320. {
  321. return false;
  322. }