MiniDumpDebugger.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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->mDbgModules.Add(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. }
  197. Run();
  198. }
  199. MiniDumpDebugger::~MiniDumpDebugger()
  200. {
  201. delete mMiniDump;
  202. for (auto mappedFile : mMappedFiles)
  203. delete mappedFile;
  204. }
  205. void MiniDumpDebugger::MapMemory(addr_target addr, void* data, intptr_target size)
  206. {
  207. addr_target beginAddress = addr;
  208. addr_target endAddress = addr + size;
  209. int memSize = (int)(endAddress - beginAddress);
  210. for (int memOffset = 0; true; memOffset += DBG_MAX_LOOKBACK)
  211. {
  212. int curSize = memSize - memOffset;
  213. if (curSize <= 0)
  214. break;
  215. MiniDumpMemoryRegion* memRegion = mAlloc.Alloc<MiniDumpMemoryRegion>();
  216. memRegion->mAddress = beginAddress + memOffset;
  217. memRegion->mAddressLength = curSize;
  218. memRegion->mData = (uint8*)data + memOffset;
  219. memRegion->mNext = NULL;
  220. mMemMap.Insert(memRegion);
  221. }
  222. }
  223. MappedFile* MiniDumpDebugger::MapModule(COFF* dbgModule, const StringImpl& fileName)
  224. {
  225. auto mappedFile = new MappedFile();
  226. if (!mappedFile->Open(fileName))
  227. {
  228. delete mappedFile;
  229. return NULL;
  230. }
  231. mMappedFiles.Add(mappedFile);
  232. return mappedFile;
  233. }
  234. bool MiniDumpDebugger::PopulateRegisters(CPURegisters* registers)
  235. {
  236. if (mActiveThread == mExceptionThread)
  237. {
  238. auto& ctx = mMiniDump->GetData<BF_CONTEXT>(mExceptionContextRVA);
  239. return PopulateRegisters(registers, ctx);
  240. }
  241. for (auto section : mMiniDump->mDirectory)
  242. {
  243. if (section.mStreamType == ThreadExListStream)
  244. {
  245. }
  246. else if (section.mStreamType == ThreadListStream)
  247. {
  248. auto& threadList = mMiniDump->GetStreamData<MINIDUMP_THREAD_LIST>(section);
  249. for (int threadIdx = 0; threadIdx < (int)threadList.NumberOfThreads; threadIdx++)
  250. {
  251. auto& thread = threadList.Threads[threadIdx];
  252. if (thread.ThreadId == mActiveThread->mThreadId)
  253. {
  254. auto& ctx = mMiniDump->GetData<BF_CONTEXT>(thread.ThreadContext.Rva);
  255. return PopulateRegisters(registers, ctx);
  256. }
  257. }
  258. }
  259. }
  260. return false;
  261. }
  262. bool MiniDumpDebugger::ReadMemory(intptr address, uint64 length, void* dest, bool local)
  263. {
  264. if (local)
  265. {
  266. __try
  267. {
  268. memcpy(dest, (void*)address, length);
  269. return true;
  270. }
  271. __except (EXCEPTION_EXECUTE_HANDLER)
  272. {
  273. return false;
  274. }
  275. }
  276. uintptr useAddr = (uintptr)address;
  277. while (true)
  278. {
  279. MiniDumpMemoryRegion* memRegion = mMemMap.Get(useAddr, DBG_MAX_LOOKBACK);
  280. if (memRegion == NULL)
  281. return false;
  282. if ((uintptr)address < (uintptr)memRegion->mAddress)
  283. return false; // Out of bounds, done
  284. while (memRegion != NULL)
  285. {
  286. if (((uintptr)address >= (uintptr)memRegion->mAddress) && ((uintptr)address < memRegion->mAddress + memRegion->mAddressLength))
  287. {
  288. if ((uintptr)address + length <= (uintptr)(memRegion->mAddress + memRegion->mAddressLength))
  289. {
  290. // In bounds
  291. memcpy(dest, (uint8*)memRegion->mData + (address - memRegion->mAddress), length);
  292. }
  293. else
  294. {
  295. int headBytes = (int)(memRegion->mAddress + memRegion->mAddressLength - address);
  296. memcpy(dest, (uint8*)memRegion->mData + (address - memRegion->mAddress), headBytes);
  297. if (!ReadMemory(address + headBytes, length - headBytes, (uint8*)dest + headBytes, local))
  298. return false;
  299. }
  300. return true;
  301. }
  302. useAddr = BF_MIN(useAddr, memRegion->mAddress - 1);
  303. memRegion = memRegion->mNext;
  304. }
  305. //if (((uintptr)address < (uintptr)memRegion->mAddress) || ((uintptr)(address + length) > uintptr(memRegion->mAddress + memRegion->mAddressLength)))
  306. //return false; // Out of bounds
  307. }
  308. return false;
  309. }
  310. bool MiniDumpDebugger::WriteMemory(intptr address, void* src, uint64 length)
  311. {
  312. return false;
  313. }