Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2465 lines
69 KiB

  1. /*++
  2. Copyright (c) 1999-2002 Microsoft Corporation
  3. Module Name:
  4. gen.c
  5. Abstract:
  6. Generic routines for minidump that work on both NT and Win9x.
  7. Author:
  8. Matthew D Hendel (math) 10-Sep-1999
  9. Revision History:
  10. --*/
  11. #include "pch.cpp"
  12. #include <limits.h>
  13. //
  14. // For FPO frames on x86 we access bytes outside of the ESP - StackBase range.
  15. // This variable determines how many extra bytes we need to add for this
  16. // case.
  17. //
  18. #define X86_STACK_FRAME_EXTRA_FPO_BYTES 4
  19. #define REASONABLE_NB11_RECORD_SIZE (10 * KBYTE)
  20. #define REASONABLE_MISC_RECORD_SIZE (10 * KBYTE)
  21. class GenMiniDumpProviderCallbacks : public MiniDumpProviderCallbacks
  22. {
  23. public:
  24. GenMiniDumpProviderCallbacks(
  25. IN PMINIDUMP_STATE Dump,
  26. IN PINTERNAL_PROCESS Process
  27. )
  28. {
  29. m_Dump = Dump;
  30. m_Process = Process;
  31. m_MemType = MEMBLOCK_OTHER;
  32. m_SaveMemType = MEMBLOCK_OTHER;
  33. }
  34. virtual HRESULT EnumMemory(ULONG64 Offset, ULONG Size)
  35. {
  36. return GenAddMemoryBlock(m_Dump, m_Process, m_MemType, Offset, Size);
  37. }
  38. void PushMemType(MEMBLOCK_TYPE Type)
  39. {
  40. m_SaveMemType = m_MemType;
  41. m_MemType = Type;
  42. }
  43. void PopMemType(void)
  44. {
  45. m_MemType = m_SaveMemType;
  46. }
  47. PMINIDUMP_STATE m_Dump;
  48. PINTERNAL_PROCESS m_Process;
  49. MEMBLOCK_TYPE m_MemType, m_SaveMemType;
  50. };
  51. LPVOID
  52. AllocMemory(
  53. IN PMINIDUMP_STATE Dump,
  54. IN ULONG Size
  55. )
  56. {
  57. LPVOID Mem = Dump->AllocProv->Alloc(Size);
  58. if (!Mem) {
  59. // Handle marking the no-memory state for all allocations.
  60. GenAccumulateStatus(Dump, MDSTATUS_OUT_OF_MEMORY);
  61. }
  62. return Mem;
  63. }
  64. VOID
  65. FreeMemory(
  66. IN PMINIDUMP_STATE Dump,
  67. IN LPVOID Memory
  68. )
  69. {
  70. Dump->AllocProv->Free(Memory);
  71. }
  72. PVOID
  73. ReAllocMemory(
  74. IN PMINIDUMP_STATE Dump,
  75. IN LPVOID Memory,
  76. IN ULONG Size
  77. )
  78. {
  79. LPVOID Mem = Dump->AllocProv->Realloc(Memory, Size);
  80. if (!Mem) {
  81. // Handle marking the no-memory state for all allocations.
  82. GenAccumulateStatus(Dump, MDSTATUS_OUT_OF_MEMORY);
  83. }
  84. return Mem;
  85. }
  86. void
  87. GenAccumulateStatus(
  88. IN PMINIDUMP_STATE Dump,
  89. IN ULONG Status
  90. )
  91. {
  92. // This is a function to make it easy to debug failures
  93. // by setting a breakpoint here.
  94. Dump->AccumStatus |= Status;
  95. }
  96. VOID
  97. GenGetDefaultWriteFlags(
  98. IN PMINIDUMP_STATE Dump,
  99. OUT PULONG ModuleWriteFlags,
  100. OUT PULONG ThreadWriteFlags
  101. )
  102. {
  103. *ModuleWriteFlags = ModuleWriteModule | ModuleWriteMiscRecord |
  104. ModuleWriteCvRecord;
  105. if (Dump->DumpType & MiniDumpWithDataSegs) {
  106. *ModuleWriteFlags |= ModuleWriteDataSeg;
  107. }
  108. *ThreadWriteFlags = ThreadWriteThread | ThreadWriteContext;
  109. if (!(Dump->DumpType & MiniDumpWithFullMemory)) {
  110. *ThreadWriteFlags |= ThreadWriteStack | ThreadWriteInstructionWindow;
  111. if (Dump->BackingStore) {
  112. *ThreadWriteFlags |= ThreadWriteBackingStore;
  113. }
  114. }
  115. if (Dump->DumpType & MiniDumpWithProcessThreadData) {
  116. *ThreadWriteFlags |= ThreadWriteThreadData;
  117. }
  118. }
  119. BOOL
  120. GenExecuteIncludeThreadCallback(
  121. IN PMINIDUMP_STATE Dump,
  122. IN ULONG ThreadId,
  123. OUT PULONG WriteFlags
  124. )
  125. {
  126. BOOL Succ;
  127. MINIDUMP_CALLBACK_INPUT CallbackInput;
  128. MINIDUMP_CALLBACK_OUTPUT CallbackOutput;
  129. // Initialize the default write flags.
  130. GenGetDefaultWriteFlags(Dump, &CallbackOutput.ModuleWriteFlags,
  131. WriteFlags);
  132. //
  133. // If there are no callbacks to call, then we are done.
  134. //
  135. if ( Dump->CallbackRoutine == NULL ) {
  136. return TRUE;
  137. }
  138. CallbackInput.ProcessHandle = Dump->ProcessHandle;
  139. CallbackInput.ProcessId = Dump->ProcessId;
  140. CallbackInput.CallbackType = IncludeThreadCallback;
  141. CallbackInput.IncludeThread.ThreadId = ThreadId;
  142. CallbackOutput.ThreadWriteFlags = *WriteFlags;
  143. Succ = Dump->CallbackRoutine (Dump->CallbackParam,
  144. &CallbackInput,
  145. &CallbackOutput);
  146. //
  147. // If the callback returned FALSE, quit now.
  148. //
  149. if ( !Succ ) {
  150. return FALSE;
  151. }
  152. // Limit the flags that can be added.
  153. *WriteFlags &= CallbackOutput.ThreadWriteFlags;
  154. return TRUE;
  155. }
  156. BOOL
  157. GenExecuteIncludeModuleCallback(
  158. IN PMINIDUMP_STATE Dump,
  159. IN ULONG64 BaseOfImage,
  160. OUT PULONG WriteFlags
  161. )
  162. {
  163. BOOL Succ;
  164. MINIDUMP_CALLBACK_INPUT CallbackInput;
  165. MINIDUMP_CALLBACK_OUTPUT CallbackOutput;
  166. // Initialize the default write flags.
  167. GenGetDefaultWriteFlags(Dump, WriteFlags,
  168. &CallbackOutput.ThreadWriteFlags);
  169. //
  170. // If there are no callbacks to call, then we are done.
  171. //
  172. if ( Dump->CallbackRoutine == NULL ) {
  173. return TRUE;
  174. }
  175. CallbackInput.ProcessHandle = Dump->ProcessHandle;
  176. CallbackInput.ProcessId = Dump->ProcessId;
  177. CallbackInput.CallbackType = IncludeModuleCallback;
  178. CallbackInput.IncludeModule.BaseOfImage = BaseOfImage;
  179. CallbackOutput.ModuleWriteFlags = *WriteFlags;
  180. Succ = Dump->CallbackRoutine (Dump->CallbackParam,
  181. &CallbackInput,
  182. &CallbackOutput);
  183. //
  184. // If the callback returned FALSE, quit now.
  185. //
  186. if ( !Succ ) {
  187. return FALSE;
  188. }
  189. // Limit the flags that can be added.
  190. *WriteFlags = (*WriteFlags | ModuleReferencedByMemory) &
  191. CallbackOutput.ModuleWriteFlags;
  192. return TRUE;
  193. }
  194. HRESULT
  195. GenGetDebugRecord(
  196. IN PMINIDUMP_STATE Dump,
  197. IN PVOID Base,
  198. IN ULONG MappedSize,
  199. IN ULONG DebugRecordType,
  200. IN ULONG DebugRecordMaxSize,
  201. OUT PVOID * DebugInfo,
  202. OUT ULONG * SizeOfDebugInfo
  203. )
  204. {
  205. ULONG i;
  206. ULONG Size;
  207. ULONG NumberOfDebugDirectories;
  208. IMAGE_DEBUG_DIRECTORY UNALIGNED* DebugDirectories;
  209. Size = 0;
  210. //
  211. // Find the debug directory and copy the memory into the buffer.
  212. // Assumes the call to this function is wrapped in a try/except.
  213. //
  214. DebugDirectories = (IMAGE_DEBUG_DIRECTORY UNALIGNED *)
  215. GenImageDirectoryEntryToData (Base,
  216. FALSE,
  217. IMAGE_DIRECTORY_ENTRY_DEBUG,
  218. &Size);
  219. //
  220. // Check that we got a valid record.
  221. //
  222. if (DebugDirectories &&
  223. ((Size % sizeof (IMAGE_DEBUG_DIRECTORY)) == 0) &&
  224. (ULONG_PTR)DebugDirectories - (ULONG_PTR)Base + Size <= MappedSize)
  225. {
  226. NumberOfDebugDirectories = Size / sizeof (IMAGE_DEBUG_DIRECTORY);
  227. for (i = 0 ; i < NumberOfDebugDirectories; i++)
  228. {
  229. //
  230. // We should check if it's a NB10 or something record.
  231. //
  232. if ((DebugDirectories[ i ].Type == DebugRecordType) &&
  233. (DebugDirectories[ i ].SizeOfData < DebugRecordMaxSize))
  234. {
  235. if (DebugDirectories[i].PointerToRawData +
  236. DebugDirectories[i].SizeOfData > MappedSize)
  237. {
  238. return E_INVALIDARG;
  239. }
  240. Size = DebugDirectories [ i ].SizeOfData;
  241. PVOID NewInfo = AllocMemory(Dump, Size);
  242. if (!NewInfo)
  243. {
  244. return E_OUTOFMEMORY;
  245. }
  246. CopyMemory(NewInfo,
  247. ((PBYTE) Base) +
  248. DebugDirectories [ i ].PointerToRawData,
  249. Size);
  250. *DebugInfo = NewInfo;
  251. *SizeOfDebugInfo = Size;
  252. return S_OK;
  253. }
  254. }
  255. }
  256. return E_INVALIDARG;
  257. }
  258. HRESULT
  259. GenAddDataSection(IN PMINIDUMP_STATE Dump,
  260. IN PINTERNAL_PROCESS Process,
  261. IN PINTERNAL_MODULE Module,
  262. IN PIMAGE_SECTION_HEADER Section)
  263. {
  264. HRESULT Status = S_OK;
  265. if ( (Section->Characteristics & IMAGE_SCN_MEM_WRITE) &&
  266. (Section->Characteristics & IMAGE_SCN_MEM_READ) &&
  267. ( (Section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) ||
  268. (Section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) )) {
  269. Status = GenAddMemoryBlock(Dump, Process, MEMBLOCK_DATA_SEG,
  270. Section->VirtualAddress +
  271. Module->BaseOfImage,
  272. Section->Misc.VirtualSize);
  273. #if 0
  274. if (Status == S_OK) {
  275. printf ("Section: %8.8s Addr: %0I64x Size: %08x Raw Size: %08x\n",
  276. Section->Name,
  277. Section->VirtualAddress + Module->BaseOfImage,
  278. Section->Misc.VirtualSize,
  279. Section->SizeOfRawData);
  280. }
  281. #endif
  282. }
  283. return Status;
  284. }
  285. HRESULT
  286. GenGetDataContributors(
  287. IN PMINIDUMP_STATE Dump,
  288. IN OUT PINTERNAL_PROCESS Process,
  289. IN PINTERNAL_MODULE Module
  290. )
  291. {
  292. ULONG i;
  293. PIMAGE_SECTION_HEADER NtSection;
  294. HRESULT Status;
  295. PVOID MappedBase;
  296. PIMAGE_NT_HEADERS NtHeaders;
  297. ULONG MappedSize;
  298. UCHAR HeaderBuffer[512];
  299. PVOID HeaderBase;
  300. GenMiniDumpProviderCallbacks Callbacks(Dump, Process);
  301. // See if the provider wants to handle this.
  302. Callbacks.PushMemType(MEMBLOCK_DATA_SEG);
  303. if (Dump->SysProv->
  304. EnumImageDataSections(Process->ProcessHandle, Module->FullPath,
  305. Module->BaseOfImage, &Callbacks) == S_OK) {
  306. // Provider did everything.
  307. return S_OK;
  308. }
  309. if ((Status = Dump->SysProv->
  310. OpenMapping(Module->FullPath, &MappedSize, NULL, 0,
  311. &MappedBase)) != S_OK) {
  312. MappedBase = NULL;
  313. // If we can't map the file try and read the image
  314. // data from the process.
  315. if ((Status = Dump->SysProv->
  316. ReadAllVirtual(Dump->ProcessHandle,
  317. Module->BaseOfImage,
  318. HeaderBuffer,
  319. sizeof(HeaderBuffer))) != S_OK) {
  320. GenAccumulateStatus(Dump, MDSTATUS_UNABLE_TO_READ_MEMORY);
  321. return Status;
  322. }
  323. HeaderBase = HeaderBuffer;
  324. } else {
  325. HeaderBase = MappedBase;
  326. }
  327. NtHeaders = GenImageNtHeader(HeaderBase, NULL);
  328. if (!NtHeaders) {
  329. Status = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
  330. } else {
  331. HRESULT OneStatus;
  332. Status = S_OK;
  333. NtSection = IMAGE_FIRST_SECTION ( NtHeaders );
  334. if (MappedBase) {
  335. __try {
  336. for (i = 0; i < NtHeaders->FileHeader.NumberOfSections; i++) {
  337. if ((OneStatus =
  338. GenAddDataSection(Dump, Process, Module,
  339. &NtSection[i])) != S_OK) {
  340. Status = OneStatus;
  341. }
  342. }
  343. } __except(EXCEPTION_EXECUTE_HANDLER) {
  344. Status = HRESULT_FROM_NT(GetExceptionCode());
  345. }
  346. } else {
  347. ULONG64 SectionOffs;
  348. IMAGE_SECTION_HEADER SectionBuffer;
  349. SectionOffs = Module->BaseOfImage +
  350. ((ULONG_PTR)NtSection - (ULONG_PTR)HeaderBase);
  351. for (i = 0; i < NtHeaders->FileHeader.NumberOfSections; i++) {
  352. if ((OneStatus = Dump->SysProv->
  353. ReadAllVirtual(Dump->ProcessHandle,
  354. SectionOffs,
  355. &SectionBuffer,
  356. sizeof(SectionBuffer))) != S_OK) {
  357. Status = OneStatus;
  358. } else if ((OneStatus =
  359. GenAddDataSection(Dump, Process, Module,
  360. &SectionBuffer)) != S_OK) {
  361. Status = OneStatus;
  362. }
  363. SectionOffs += sizeof(SectionBuffer);
  364. }
  365. }
  366. }
  367. if (MappedBase) {
  368. Dump->SysProv->CloseMapping(MappedBase);
  369. }
  370. return Status;
  371. }
  372. HRESULT
  373. GenAllocateThreadObject(
  374. IN PMINIDUMP_STATE Dump,
  375. IN struct _INTERNAL_PROCESS* Process,
  376. IN ULONG ThreadId,
  377. IN ULONG WriteFlags,
  378. PINTERNAL_THREAD* ThreadRet
  379. )
  380. /*++
  381. Routine Description:
  382. Allocate and initialize an INTERNAL_THREAD structure.
  383. Return Values:
  384. S_OK on success.
  385. S_FALSE if the thread can't be opened.
  386. Errors on failure.
  387. --*/
  388. {
  389. HRESULT Status;
  390. PINTERNAL_THREAD Thread;
  391. ULONG64 StackEnd;
  392. ULONG64 StackLimit;
  393. ULONG64 StoreLimit;
  394. ULONG64 StoreCurrent;
  395. Thread = (PINTERNAL_THREAD)
  396. AllocMemory ( Dump, sizeof (INTERNAL_THREAD) + Dump->ContextSize );
  397. if (Thread == NULL) {
  398. return E_OUTOFMEMORY;
  399. }
  400. *ThreadRet = Thread;
  401. Thread->ThreadId = ThreadId;
  402. Status = Dump->SysProv->
  403. OpenThread(THREAD_ALL_ACCESS,
  404. FALSE,
  405. Thread->ThreadId,
  406. &Thread->ThreadHandle);
  407. if (Status != S_OK) {
  408. // The thread may have exited before we got around
  409. // to trying to open it. If the open fails with
  410. // a not-found code return an alternate success to
  411. // indicate that it's not a critical failure.
  412. if (Status == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) ||
  413. Status == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
  414. Status == HRESULT_FROM_NT(STATUS_INVALID_CID)) {
  415. Status = S_FALSE;
  416. } else if (SUCCEEDED(Status)) {
  417. Status = E_FAIL;
  418. }
  419. if (FAILED(Status)) {
  420. GenAccumulateStatus(Dump, MDSTATUS_CALL_FAILED);
  421. }
  422. goto Exit;
  423. }
  424. // If the current thread is dumping itself we can't
  425. // suspend. We can also assume the suspend count must
  426. // be zero since the thread is running.
  427. if (Thread->ThreadId == Dump->SysProv->GetCurrentThreadId()) {
  428. Thread->SuspendCount = 0;
  429. } else {
  430. Thread->SuspendCount = Dump->SysProv->
  431. SuspendThread ( Thread->ThreadHandle );
  432. }
  433. Thread->WriteFlags = WriteFlags;
  434. //
  435. // Add this if we ever need it
  436. //
  437. Thread->PriorityClass = 0;
  438. Thread->Priority = 0;
  439. //
  440. // Initialize the thread context.
  441. //
  442. Thread->ContextBuffer = Thread + 1;
  443. Status = Dump->SysProv->
  444. GetThreadContext (Thread->ThreadHandle,
  445. Thread->ContextBuffer,
  446. Dump->ContextSize,
  447. &Thread->CurrentPc,
  448. &StackEnd,
  449. &StoreCurrent);
  450. if ( Status != S_OK ) {
  451. GenAccumulateStatus(Dump, MDSTATUS_CALL_FAILED);
  452. goto Exit;
  453. }
  454. if (Dump->CpuType == IMAGE_FILE_MACHINE_I386) {
  455. //
  456. // Note: for FPO frames on x86 we access bytes outside of the
  457. // ESP - StackBase range. Add a couple of bytes extra here so we
  458. // don't fail these cases.
  459. //
  460. StackEnd -= X86_STACK_FRAME_EXTRA_FPO_BYTES;
  461. }
  462. if ((Status = Dump->SysProv->
  463. GetThreadInfo(Dump->ProcessHandle,
  464. Thread->ThreadHandle,
  465. &Thread->Teb,
  466. &Thread->SizeOfTeb,
  467. &Thread->StackBase,
  468. &StackLimit,
  469. &Thread->BackingStoreBase,
  470. &StoreLimit)) != S_OK) {
  471. goto Exit;
  472. }
  473. //
  474. // If the stack pointer (SP) is within the range of the stack
  475. // region (as allocated by the OS), only take memory from
  476. // the stack region up to the SP. Otherwise, assume the program
  477. // has blown it's SP -- purposefully, or not -- and copy
  478. // the entire stack as known by the OS.
  479. //
  480. if (Dump->BackingStore) {
  481. Thread->BackingStoreSize =
  482. (ULONG)(StoreCurrent - Thread->BackingStoreBase);
  483. } else {
  484. Thread->BackingStoreSize = 0;
  485. }
  486. if (StackLimit <= StackEnd && StackEnd < Thread->StackBase) {
  487. Thread->StackEnd = StackEnd;
  488. } else {
  489. Thread->StackEnd = StackLimit;
  490. }
  491. if ((ULONG)(Thread->StackBase - Thread->StackEnd) >
  492. Process->MaxStackOrStoreSize) {
  493. Process->MaxStackOrStoreSize =
  494. (ULONG)(Thread->StackBase - Thread->StackEnd);
  495. }
  496. if (Thread->BackingStoreSize > Process->MaxStackOrStoreSize) {
  497. Process->MaxStackOrStoreSize = Thread->BackingStoreSize;
  498. }
  499. Exit:
  500. if ( Status != S_OK ) {
  501. FreeMemory ( Dump, Thread );
  502. }
  503. return Status;
  504. }
  505. VOID
  506. GenFreeThreadObject(
  507. IN PMINIDUMP_STATE Dump,
  508. IN PINTERNAL_THREAD Thread
  509. )
  510. {
  511. if (Thread->SuspendCount != -1 &&
  512. Thread->ThreadId != Dump->SysProv->GetCurrentThreadId()) {
  513. Dump->SysProv->ResumeThread (Thread->ThreadHandle);
  514. Thread->SuspendCount = -1;
  515. }
  516. Dump->SysProv->CloseThread(Thread->ThreadHandle);
  517. Thread->ThreadHandle = NULL;
  518. FreeMemory ( Dump, Thread );
  519. Thread = NULL;
  520. }
  521. HRESULT
  522. GenGetThreadInstructionWindow(
  523. IN PMINIDUMP_STATE Dump,
  524. IN PINTERNAL_PROCESS Process,
  525. IN PINTERNAL_THREAD Thread
  526. )
  527. {
  528. PVOID MemBuf;
  529. ULONG64 InstrStart;
  530. ULONG InstrSize;
  531. ULONG BytesRead;
  532. HRESULT Status = E_FAIL;
  533. if (!Dump->InstructionWindowSize) {
  534. return S_OK;
  535. }
  536. //
  537. // Store a window of the instruction stream around
  538. // the current program counter. This allows some
  539. // instruction context to be given even when images
  540. // can't be mapped. It also allows instruction
  541. // context to be given for generated code where
  542. // no image contains the necessary instructions.
  543. //
  544. InstrStart = Thread->CurrentPc - Dump->InstructionWindowSize / 2;
  545. InstrSize = Dump->InstructionWindowSize;
  546. MemBuf = AllocMemory(Dump, InstrSize);
  547. if (!MemBuf) {
  548. return E_OUTOFMEMORY;
  549. }
  550. for (;;) {
  551. // If we can read the instructions through the
  552. // current program counter we'll say that's
  553. // good enough.
  554. if (Dump->SysProv->
  555. ReadVirtual(Dump->ProcessHandle,
  556. InstrStart,
  557. MemBuf,
  558. InstrSize,
  559. &BytesRead) == S_OK &&
  560. InstrStart + BytesRead >
  561. Thread->CurrentPc) {
  562. Status = GenAddMemoryBlock(Dump, Process, MEMBLOCK_INSTR_WINDOW,
  563. InstrStart, BytesRead);
  564. break;
  565. }
  566. // We couldn't read up to the program counter.
  567. // If the start address is on the previous page
  568. // move it up to the same page.
  569. if ((InstrStart & ~((ULONG64)Dump->PageSize - 1)) !=
  570. (Thread->CurrentPc & ~((ULONG64)Dump->PageSize - 1))) {
  571. ULONG Fraction = Dump->PageSize -
  572. (ULONG)InstrStart & (Dump->PageSize - 1);
  573. InstrSize -= Fraction;
  574. InstrStart += Fraction;
  575. } else {
  576. // The start and PC were on the same page so
  577. // we just can't read memory. There may have been
  578. // a jump to a bad address or something, so this
  579. // doesn't constitute an unexpected failure.
  580. break;
  581. }
  582. }
  583. FreeMemory(Dump, MemBuf);
  584. return Status;
  585. }
  586. PWSTR
  587. GenGetPathTail(
  588. IN PWSTR Path
  589. )
  590. {
  591. PWSTR Scan = Path + GenStrLengthW(Path);
  592. while (Scan > Path) {
  593. Scan--;
  594. if (*Scan == '\\' ||
  595. *Scan == '/' ||
  596. *Scan == ':') {
  597. return Scan + 1;
  598. }
  599. }
  600. return Path;
  601. }
  602. HRESULT
  603. GenAllocateModuleObject(
  604. IN PMINIDUMP_STATE Dump,
  605. IN PINTERNAL_PROCESS Process,
  606. IN PWSTR FullPathW,
  607. IN ULONG64 BaseOfModule,
  608. IN ULONG WriteFlags,
  609. OUT PINTERNAL_MODULE* ModuleRet
  610. )
  611. /*++
  612. Routine Description:
  613. Given the full-path to the module and the base of the module, create and
  614. initialize an INTERNAL_MODULE object, and return it.
  615. --*/
  616. {
  617. HRESULT Status;
  618. PVOID MappedBase;
  619. ULONG MappedSize;
  620. PIMAGE_NT_HEADERS NtHeaders;
  621. PINTERNAL_MODULE Module;
  622. ULONG Chars;
  623. ASSERT (FullPathW);
  624. ASSERT (BaseOfModule);
  625. Module = (PINTERNAL_MODULE)
  626. AllocMemory ( Dump, sizeof (INTERNAL_MODULE) );
  627. if (Module == NULL) {
  628. return E_OUTOFMEMORY;
  629. }
  630. //
  631. // Get the version information for the module.
  632. //
  633. if ((Status = Dump->SysProv->
  634. GetImageVersionInfo(Dump->ProcessHandle, FullPathW, BaseOfModule,
  635. &Module->VersionInfo)) != S_OK) {
  636. ZeroMemory(&Module->VersionInfo, sizeof(Module->VersionInfo));
  637. }
  638. if ((Status = Dump->SysProv->
  639. OpenMapping(FullPathW, &MappedSize,
  640. Module->FullPath, ARRAY_COUNT(Module->FullPath),
  641. &MappedBase)) != S_OK) {
  642. MappedBase = NULL;
  643. // Some providers can't map but still have image
  644. // information. Try that.
  645. if ((Status = Dump->SysProv->
  646. GetImageHeaderInfo(Dump->ProcessHandle,
  647. FullPathW,
  648. BaseOfModule,
  649. &Module->SizeOfImage,
  650. &Module->CheckSum,
  651. &Module->TimeDateStamp)) != S_OK) {
  652. GenAccumulateStatus(Dump, MDSTATUS_CALL_FAILED);
  653. FreeMemory(Dump, Module);
  654. return Status;
  655. }
  656. // No long path name is available so just use
  657. // the incoming path.
  658. GenStrCopyNW(Module->FullPath, FullPathW,
  659. ARRAY_COUNT(Module->FullPath));
  660. }
  661. if (IsFlagSet(Dump->DumpType, MiniDumpFilterModulePaths)) {
  662. Module->SavePath = GenGetPathTail(Module->FullPath);
  663. } else {
  664. Module->SavePath = Module->FullPath;
  665. }
  666. Module->BaseOfImage = BaseOfModule;
  667. Module->WriteFlags = WriteFlags;
  668. Module->CvRecord = NULL;
  669. Module->SizeOfCvRecord = 0;
  670. Module->MiscRecord = NULL;
  671. Module->SizeOfMiscRecord = 0;
  672. if (MappedBase) {
  673. IMAGE_NT_HEADERS64 Hdr64;
  674. NtHeaders = GenImageNtHeader ( MappedBase, &Hdr64 );
  675. if (!NtHeaders) {
  676. GenAccumulateStatus(Dump, MDSTATUS_CALL_FAILED);
  677. FreeMemory(Dump, Module);
  678. return HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
  679. }
  680. __try {
  681. //
  682. // Cull information from the image header.
  683. //
  684. Module->SizeOfImage = Hdr64.OptionalHeader.SizeOfImage;
  685. Module->CheckSum = Hdr64.OptionalHeader.CheckSum;
  686. Module->TimeDateStamp = Hdr64.FileHeader.TimeDateStamp;
  687. //
  688. // Get the CV record from the debug directory.
  689. //
  690. if (IsFlagSet(Module->WriteFlags, ModuleWriteCvRecord)) {
  691. GenGetDebugRecord(Dump,
  692. MappedBase,
  693. MappedSize,
  694. IMAGE_DEBUG_TYPE_CODEVIEW,
  695. REASONABLE_NB11_RECORD_SIZE,
  696. &Module->CvRecord,
  697. &Module->SizeOfCvRecord);
  698. }
  699. //
  700. // Get the MISC record from the debug directory.
  701. //
  702. if (IsFlagSet(Module->WriteFlags, ModuleWriteMiscRecord)) {
  703. GenGetDebugRecord(Dump,
  704. MappedBase,
  705. MappedSize,
  706. IMAGE_DEBUG_TYPE_MISC,
  707. REASONABLE_MISC_RECORD_SIZE,
  708. &Module->MiscRecord,
  709. &Module->SizeOfMiscRecord);
  710. }
  711. Status = S_OK;
  712. } __except(EXCEPTION_EXECUTE_HANDLER) {
  713. Status = HRESULT_FROM_NT(GetExceptionCode());
  714. }
  715. Dump->SysProv->CloseMapping(MappedBase);
  716. if (Status != S_OK) {
  717. GenAccumulateStatus(Dump, MDSTATUS_CALL_FAILED);
  718. FreeMemory(Dump, Module);
  719. return Status;
  720. }
  721. } else {
  722. ULONG RecordLen;
  723. //
  724. // See if the provider can retrieve debug records.
  725. //
  726. RecordLen = 0;
  727. if (IsFlagSet(Module->WriteFlags, ModuleWriteCvRecord) &&
  728. Dump->SysProv->
  729. GetImageDebugRecord(Process->ProcessHandle,
  730. Module->FullPath,
  731. Module->BaseOfImage,
  732. IMAGE_DEBUG_TYPE_CODEVIEW,
  733. NULL,
  734. &RecordLen) == S_OK &&
  735. RecordLen <= REASONABLE_NB11_RECORD_SIZE &&
  736. (Module->CvRecord = AllocMemory(Dump, RecordLen))) {
  737. Module->SizeOfCvRecord = RecordLen;
  738. if (Dump->SysProv->
  739. GetImageDebugRecord(Process->ProcessHandle,
  740. Module->FullPath,
  741. Module->BaseOfImage,
  742. IMAGE_DEBUG_TYPE_CODEVIEW,
  743. Module->CvRecord,
  744. &Module->SizeOfCvRecord) != S_OK) {
  745. FreeMemory(Dump, Module->CvRecord);
  746. Module->CvRecord = NULL;
  747. Module->SizeOfCvRecord = 0;
  748. }
  749. }
  750. RecordLen = 0;
  751. if (IsFlagSet(Module->WriteFlags, ModuleWriteMiscRecord) &&
  752. Dump->SysProv->
  753. GetImageDebugRecord(Process->ProcessHandle,
  754. Module->FullPath,
  755. Module->BaseOfImage,
  756. IMAGE_DEBUG_TYPE_CODEVIEW,
  757. NULL,
  758. &RecordLen) == S_OK &&
  759. RecordLen <= REASONABLE_MISC_RECORD_SIZE &&
  760. (Module->MiscRecord = AllocMemory(Dump, RecordLen))) {
  761. Module->SizeOfMiscRecord = RecordLen;
  762. if (Dump->SysProv->
  763. GetImageDebugRecord(Process->ProcessHandle,
  764. Module->FullPath,
  765. Module->BaseOfImage,
  766. IMAGE_DEBUG_TYPE_MISC,
  767. Module->MiscRecord,
  768. &Module->SizeOfMiscRecord) != S_OK) {
  769. FreeMemory(Dump, Module->MiscRecord);
  770. Module->MiscRecord = NULL;
  771. Module->SizeOfMiscRecord = 0;
  772. }
  773. }
  774. }
  775. *ModuleRet = Module;
  776. return S_OK;
  777. }
  778. VOID
  779. GenFreeModuleObject(
  780. IN PMINIDUMP_STATE Dump,
  781. IN PINTERNAL_MODULE Module
  782. )
  783. {
  784. FreeMemory ( Dump, Module->CvRecord );
  785. Module->CvRecord = NULL;
  786. FreeMemory ( Dump, Module->MiscRecord );
  787. Module->MiscRecord = NULL;
  788. FreeMemory ( Dump, Module );
  789. Module = NULL;
  790. }
  791. HRESULT
  792. GenAllocateUnloadedModuleObject(
  793. IN PMINIDUMP_STATE Dump,
  794. IN PWSTR Path,
  795. IN ULONG64 BaseOfModule,
  796. IN ULONG SizeOfModule,
  797. IN ULONG CheckSum,
  798. IN ULONG TimeDateStamp,
  799. OUT PINTERNAL_UNLOADED_MODULE* ModuleRet
  800. )
  801. {
  802. PINTERNAL_UNLOADED_MODULE Module;
  803. Module = (PINTERNAL_UNLOADED_MODULE)
  804. AllocMemory ( Dump, sizeof (*Module) );
  805. if (Module == NULL) {
  806. return E_OUTOFMEMORY;
  807. }
  808. GenStrCopyNW(Module->Path, Path, ARRAY_COUNT(Module->Path));
  809. Module->BaseOfImage = BaseOfModule;
  810. Module->SizeOfImage = SizeOfModule;
  811. Module->CheckSum = CheckSum;
  812. Module->TimeDateStamp = TimeDateStamp;
  813. *ModuleRet = Module;
  814. return S_OK;
  815. }
  816. VOID
  817. GenFreeUnloadedModuleObject(
  818. IN PMINIDUMP_STATE Dump,
  819. IN PINTERNAL_UNLOADED_MODULE Module
  820. )
  821. {
  822. FreeMemory ( Dump, Module );
  823. Module = NULL;
  824. }
  825. HRESULT
  826. GenAllocateFunctionTableObject(
  827. IN PMINIDUMP_STATE Dump,
  828. IN ULONG64 MinAddress,
  829. IN ULONG64 MaxAddress,
  830. IN ULONG64 BaseAddress,
  831. IN ULONG EntryCount,
  832. IN PVOID RawTable,
  833. OUT PINTERNAL_FUNCTION_TABLE* TableRet
  834. )
  835. {
  836. PINTERNAL_FUNCTION_TABLE Table;
  837. Table = (PINTERNAL_FUNCTION_TABLE)
  838. AllocMemory(Dump, sizeof(INTERNAL_FUNCTION_TABLE) +
  839. Dump->FuncTableSize);
  840. if (!Table) {
  841. return E_OUTOFMEMORY;
  842. }
  843. Table->RawEntries =
  844. AllocMemory(Dump, Dump->FuncTableEntrySize * EntryCount);
  845. if (!Table->RawEntries) {
  846. FreeMemory(Dump, Table);
  847. return E_OUTOFMEMORY;
  848. }
  849. Table->MinimumAddress = MinAddress;
  850. Table->MaximumAddress = MaxAddress;
  851. Table->BaseAddress = BaseAddress;
  852. Table->EntryCount = EntryCount;
  853. Table->RawTable = (Table + 1);
  854. memcpy(Table->RawTable, RawTable, Dump->FuncTableSize);
  855. *TableRet = Table;
  856. return S_OK;
  857. }
  858. VOID
  859. GenFreeFunctionTableObject(
  860. IN PMINIDUMP_STATE Dump,
  861. IN struct _INTERNAL_FUNCTION_TABLE* Table
  862. )
  863. {
  864. if (Table->RawEntries) {
  865. FreeMemory(Dump, Table->RawEntries);
  866. }
  867. FreeMemory(Dump, Table);
  868. }
  869. HRESULT
  870. GenAllocateProcessObject(
  871. IN PMINIDUMP_STATE Dump,
  872. OUT PINTERNAL_PROCESS* ProcessRet
  873. )
  874. {
  875. HRESULT Status;
  876. PINTERNAL_PROCESS Process;
  877. FILETIME Create, Exit, User, Kernel;
  878. Process = (PINTERNAL_PROCESS)
  879. AllocMemory ( Dump, sizeof (INTERNAL_PROCESS) );
  880. if (!Process) {
  881. return E_OUTOFMEMORY;
  882. }
  883. Process->ProcessId = Dump->ProcessId;
  884. Process->ProcessHandle = Dump->ProcessHandle;
  885. Process->NumberOfThreads = 0;
  886. Process->NumberOfModules = 0;
  887. Process->NumberOfFunctionTables = 0;
  888. InitializeListHead (&Process->ThreadList);
  889. InitializeListHead (&Process->ModuleList);
  890. InitializeListHead (&Process->UnloadedModuleList);
  891. InitializeListHead (&Process->FunctionTableList);
  892. InitializeListHead (&Process->MemoryBlocks);
  893. if ((Status = Dump->SysProv->
  894. GetPeb(Dump->ProcessHandle,
  895. &Process->Peb, &Process->SizeOfPeb)) != S_OK) {
  896. // Failure is only critical if the dump needs
  897. // to include PEB memory.
  898. if (Dump->DumpType & MiniDumpWithProcessThreadData) {
  899. FreeMemory(Dump, Process);
  900. return Status;
  901. } else {
  902. Process->Peb = 0;
  903. Process->SizeOfPeb = 0;
  904. }
  905. }
  906. // Win9x doesn't support GetProcessTimes so failures
  907. // here are possible.
  908. if (Dump->SysProv->
  909. GetProcessTimes(Dump->ProcessHandle,
  910. &Create, &User, &Kernel) == S_OK) {
  911. Process->TimesValid = TRUE;
  912. Process->CreateTime = FileTimeToTimeDate(&Create);
  913. Process->UserTime = FileTimeToSeconds(&User);
  914. Process->KernelTime = FileTimeToSeconds(&Kernel);
  915. }
  916. *ProcessRet = Process;
  917. return S_OK;
  918. }
  919. VOID
  920. GenFreeProcessObject(
  921. IN PMINIDUMP_STATE Dump,
  922. IN PINTERNAL_PROCESS Process
  923. )
  924. {
  925. PINTERNAL_MODULE Module;
  926. PINTERNAL_UNLOADED_MODULE UnlModule;
  927. PINTERNAL_THREAD Thread;
  928. PINTERNAL_FUNCTION_TABLE Table;
  929. PVA_RANGE Range;
  930. PLIST_ENTRY Entry;
  931. Thread = NULL;
  932. Module = NULL;
  933. Entry = Process->ModuleList.Flink;
  934. while ( Entry != &Process->ModuleList ) {
  935. Module = CONTAINING_RECORD (Entry, INTERNAL_MODULE, ModulesLink);
  936. Entry = Entry->Flink;
  937. GenFreeModuleObject ( Dump, Module );
  938. }
  939. Entry = Process->UnloadedModuleList.Flink;
  940. while ( Entry != &Process->UnloadedModuleList ) {
  941. UnlModule = CONTAINING_RECORD (Entry, INTERNAL_UNLOADED_MODULE,
  942. ModulesLink);
  943. Entry = Entry->Flink;
  944. GenFreeUnloadedModuleObject ( Dump, UnlModule );
  945. }
  946. Entry = Process->ThreadList.Flink;
  947. while ( Entry != &Process->ThreadList ) {
  948. Thread = CONTAINING_RECORD (Entry, INTERNAL_THREAD, ThreadsLink);
  949. Entry = Entry->Flink;
  950. GenFreeThreadObject ( Dump, Thread );
  951. }
  952. Entry = Process->FunctionTableList.Flink;
  953. while ( Entry != &Process->FunctionTableList ) {
  954. Table = CONTAINING_RECORD (Entry, INTERNAL_FUNCTION_TABLE, TableLink);
  955. Entry = Entry->Flink;
  956. GenFreeFunctionTableObject ( Dump, Table );
  957. }
  958. Entry = Process->MemoryBlocks.Flink;
  959. while (Entry != &Process->MemoryBlocks) {
  960. Range = CONTAINING_RECORD(Entry, VA_RANGE, NextLink);
  961. Entry = Entry->Flink;
  962. FreeMemory(Dump, Range);
  963. }
  964. FreeMemory ( Dump, Process );
  965. Process = NULL;
  966. }
  967. HRESULT
  968. GenIncludeUnwindInfoMemory(
  969. IN PMINIDUMP_STATE Dump,
  970. IN PINTERNAL_PROCESS Process,
  971. IN PINTERNAL_FUNCTION_TABLE Table
  972. )
  973. {
  974. HRESULT Status;
  975. ULONG i;
  976. if (Dump->DumpType & MiniDumpWithFullMemory) {
  977. // Memory will be included by default.
  978. return S_OK;
  979. }
  980. for (i = 0; i < Table->EntryCount; i++) {
  981. ULONG64 Start;
  982. ULONG Size;
  983. if ((Status = Dump->SysProv->
  984. EnumFunctionTableEntryMemory(Table->BaseAddress,
  985. Table->RawEntries,
  986. i,
  987. &Start,
  988. &Size)) != S_OK) {
  989. return Status;
  990. }
  991. if ((Status = GenAddMemoryBlock(Dump, Process, MEMBLOCK_UNWIND_INFO,
  992. Start, Size)) != S_OK) {
  993. return Status;
  994. }
  995. }
  996. return S_OK;
  997. }
  998. void
  999. GenRemoveMemoryBlock(
  1000. IN PINTERNAL_PROCESS Process,
  1001. IN PVA_RANGE Block
  1002. )
  1003. {
  1004. RemoveEntryList(&Block->NextLink);
  1005. Process->NumberOfMemoryBlocks--;
  1006. Process->SizeOfMemoryBlocks -= Block->Size;
  1007. }
  1008. HRESULT
  1009. GenAddMemoryBlock(
  1010. IN PMINIDUMP_STATE Dump,
  1011. IN PINTERNAL_PROCESS Process,
  1012. IN MEMBLOCK_TYPE Type,
  1013. IN ULONG64 Start,
  1014. IN ULONG Size
  1015. )
  1016. {
  1017. ULONG64 End;
  1018. PLIST_ENTRY ScanEntry;
  1019. PVA_RANGE Scan;
  1020. ULONG64 ScanEnd;
  1021. PVA_RANGE New = NULL;
  1022. SIZE_T Done;
  1023. UCHAR Byte;
  1024. // Do not use Size after this to avoid ULONG overflows.
  1025. End = Start + Size;
  1026. if (End < Start) {
  1027. End = (ULONG64)-1;
  1028. }
  1029. if (Start == End) {
  1030. // Nothing to add.
  1031. return S_OK;
  1032. }
  1033. if ((End - Start) > ULONG_MAX - Process->SizeOfMemoryBlocks) {
  1034. // Overflow.
  1035. GenAccumulateStatus(Dump, MDSTATUS_INTERNAL_ERROR);
  1036. return E_INVALIDARG;
  1037. }
  1038. //
  1039. // First trim the range down to memory that can actually
  1040. // be accessed.
  1041. //
  1042. while (Start < End) {
  1043. if (Dump->SysProv->
  1044. ReadAllVirtual(Dump->ProcessHandle,
  1045. Start, &Byte, sizeof(Byte)) == S_OK) {
  1046. break;
  1047. }
  1048. // Move up to the next page.
  1049. Start = (Start + Dump->PageSize) & ~((ULONG64)Dump->PageSize - 1);
  1050. if (!Start) {
  1051. // Wrapped around.
  1052. return S_OK;
  1053. }
  1054. }
  1055. if (Start >= End) {
  1056. // No valid memory.
  1057. return S_OK;
  1058. }
  1059. ScanEnd = (Start + Dump->PageSize) & ~((ULONG64)Dump->PageSize - 1);
  1060. for (;;) {
  1061. if (ScanEnd >= End) {
  1062. break;
  1063. }
  1064. if (Dump->SysProv->
  1065. ReadAllVirtual(Dump->ProcessHandle,
  1066. ScanEnd, &Byte, sizeof(Byte)) != S_OK) {
  1067. End = ScanEnd;
  1068. break;
  1069. }
  1070. // Move up to the next page.
  1071. ScanEnd = (ScanEnd + Dump->PageSize) & ~((ULONG64)Dump->PageSize - 1);
  1072. if (!ScanEnd) {
  1073. ScanEnd--;
  1074. break;
  1075. }
  1076. }
  1077. //
  1078. // When adding memory to the list of memory to be saved
  1079. // we want to avoid overlaps and also coalesce adjacent regions
  1080. // so that the list has the largest possible non-adjacent
  1081. // blocks. In order to accomplish this we make a pass over
  1082. // the list and merge all listed blocks that overlap or abut the
  1083. // incoming range with the incoming range, then remove the
  1084. // merged entries from the list. After this pass we have
  1085. // a region which is guaranteed not to overlap or abut anything in
  1086. // the list.
  1087. //
  1088. ScanEntry = Process->MemoryBlocks.Flink;
  1089. while (ScanEntry != &Process->MemoryBlocks) {
  1090. Scan = CONTAINING_RECORD(ScanEntry, VA_RANGE, NextLink);
  1091. ScanEnd = Scan->Start + Scan->Size;
  1092. ScanEntry = Scan->NextLink.Flink;
  1093. if (Scan->Start > End || ScanEnd < Start) {
  1094. // No overlap or adjacency.
  1095. continue;
  1096. }
  1097. //
  1098. // Compute the union of the incoming range and
  1099. // the scan block, then remove the scan block.
  1100. //
  1101. if (Scan->Start < Start) {
  1102. Start = Scan->Start;
  1103. }
  1104. if (ScanEnd > End) {
  1105. End = ScanEnd;
  1106. }
  1107. // We've lost the specific type. This is not a problem
  1108. // right now but if specific types must be preserved
  1109. // all the way through in the future it will be necessary
  1110. // to avoid merging.
  1111. Type = MEMBLOCK_MERGED;
  1112. GenRemoveMemoryBlock(Process, Scan);
  1113. if (!New) {
  1114. // Save memory for reuse.
  1115. New = Scan;
  1116. } else {
  1117. FreeMemory(Dump, Scan);
  1118. }
  1119. }
  1120. if (!New) {
  1121. New = (PVA_RANGE)AllocMemory(Dump, sizeof(*New));
  1122. if (!New) {
  1123. return E_OUTOFMEMORY;
  1124. }
  1125. }
  1126. New->Start = Start;
  1127. // Overflow is extremely unlikely, so don't do anything
  1128. // fancy to handle it.
  1129. if (End - Start > ULONG_MAX) {
  1130. New->Size = ULONG_MAX;
  1131. } else {
  1132. New->Size = (ULONG)(End - Start);
  1133. }
  1134. New->Type = Type;
  1135. InsertTailList(&Process->MemoryBlocks, &New->NextLink);
  1136. Process->NumberOfMemoryBlocks++;
  1137. Process->SizeOfMemoryBlocks += New->Size;
  1138. return S_OK;
  1139. }
  1140. void
  1141. GenRemoveMemoryRange(
  1142. IN PMINIDUMP_STATE Dump,
  1143. IN PINTERNAL_PROCESS Process,
  1144. IN ULONG64 Start,
  1145. IN ULONG Size
  1146. )
  1147. {
  1148. ULONG64 End = Start + Size;
  1149. PLIST_ENTRY ScanEntry;
  1150. PVA_RANGE Scan;
  1151. ULONG64 ScanEnd;
  1152. Restart:
  1153. ScanEntry = Process->MemoryBlocks.Flink;
  1154. while (ScanEntry != &Process->MemoryBlocks) {
  1155. Scan = CONTAINING_RECORD(ScanEntry, VA_RANGE, NextLink);
  1156. ScanEnd = Scan->Start + Scan->Size;
  1157. ScanEntry = Scan->NextLink.Flink;
  1158. if (Scan->Start >= End || ScanEnd <= Start) {
  1159. // No overlap.
  1160. continue;
  1161. }
  1162. if (Scan->Start < Start) {
  1163. // Trim block to non-overlapping pre-Start section.
  1164. Scan->Size = (ULONG)(Start - Scan->Start);
  1165. if (ScanEnd > End) {
  1166. // There's also a non-overlapping section post-End.
  1167. // We need to add a new block.
  1168. GenAddMemoryBlock(Dump, Process, Scan->Type,
  1169. End, (ULONG)(ScanEnd - End));
  1170. // The list has changed so restart.
  1171. goto Restart;
  1172. }
  1173. } else if (ScanEnd > End) {
  1174. // Trim block to non-overlapping post-End section.
  1175. Scan->Start = End;
  1176. Scan->Size = (ULONG)(ScanEnd - End);
  1177. } else {
  1178. // Scan is completely contained.
  1179. GenRemoveMemoryBlock(Process, Scan);
  1180. FreeMemory(Dump, Scan);
  1181. }
  1182. }
  1183. }
  1184. HRESULT
  1185. GenAddPebMemory(
  1186. IN PMINIDUMP_STATE Dump,
  1187. IN PINTERNAL_PROCESS Process
  1188. )
  1189. {
  1190. HRESULT Status = S_OK, Check;
  1191. GenMiniDumpProviderCallbacks Callbacks(Dump, Process);
  1192. Callbacks.PushMemType(MEMBLOCK_PEB);
  1193. // Accumulate error status but do not stop processing
  1194. // for errors.
  1195. if ((Check = GenAddMemoryBlock(Dump, Process, MEMBLOCK_PEB,
  1196. Process->Peb,
  1197. Process->SizeOfPeb)) != S_OK) {
  1198. Status = Check;
  1199. }
  1200. if (!(Dump->DumpType & MiniDumpWithoutOptionalData) &&
  1201. (Check = Dump->SysProv->
  1202. EnumPebMemory(Process->ProcessHandle,
  1203. Process->Peb, Process->SizeOfPeb,
  1204. &Callbacks)) != S_OK) {
  1205. Status = Check;
  1206. }
  1207. Callbacks.PopMemType();
  1208. return Status;
  1209. }
  1210. HRESULT
  1211. GenAddTebMemory(
  1212. IN PMINIDUMP_STATE Dump,
  1213. IN PINTERNAL_PROCESS Process,
  1214. IN PINTERNAL_THREAD Thread
  1215. )
  1216. {
  1217. HRESULT Status = S_OK, Check;
  1218. GenMiniDumpProviderCallbacks Callbacks(Dump, Process);
  1219. Callbacks.PushMemType(MEMBLOCK_TEB);
  1220. // Accumulate error status but do not stop processing
  1221. // for errors.
  1222. if ((Check = GenAddMemoryBlock(Dump, Process, MEMBLOCK_TEB,
  1223. Thread->Teb, Thread->SizeOfTeb)) != S_OK) {
  1224. Status = Check;
  1225. }
  1226. if (!(Dump->DumpType & MiniDumpWithoutOptionalData) &&
  1227. (Check = Dump->SysProv->
  1228. EnumTebMemory(Process->ProcessHandle, Thread->ThreadHandle,
  1229. Thread->Teb, Thread->SizeOfTeb,
  1230. &Callbacks)) != S_OK) {
  1231. Status = Check;
  1232. }
  1233. Callbacks.PopMemType();
  1234. return Status;
  1235. }
  1236. HRESULT
  1237. GenScanAddressSpace(
  1238. IN PMINIDUMP_STATE Dump,
  1239. IN PINTERNAL_PROCESS Process
  1240. )
  1241. {
  1242. HRESULT Status;
  1243. ULONG ProtectMask = 0, TypeMask = 0;
  1244. ULONG64 Offset, Size;
  1245. ULONG Protect, State, Type;
  1246. if (Dump->DumpType & MiniDumpWithPrivateReadWriteMemory) {
  1247. ProtectMask |= PAGE_READWRITE;
  1248. TypeMask |= MEM_PRIVATE;
  1249. }
  1250. if (!ProtectMask || !TypeMask) {
  1251. // Nothing to scan for.
  1252. return S_OK;
  1253. }
  1254. Status = S_OK;
  1255. Offset = 0;
  1256. for (;;) {
  1257. if (Dump->SysProv->
  1258. QueryVirtual(Dump->ProcessHandle, Offset, &Offset, &Size,
  1259. &Protect, &State, &Type) != S_OK) {
  1260. break;
  1261. }
  1262. ULONG64 ScanOffset = Offset;
  1263. Offset += Size;
  1264. if (State == MEM_COMMIT &&
  1265. (Protect & ProtectMask) &&
  1266. (Type & TypeMask)) {
  1267. while (Size > 0) {
  1268. ULONG BlockSize;
  1269. HRESULT OneStatus;
  1270. if (Size > ULONG_MAX / 2) {
  1271. BlockSize = ULONG_MAX / 2;
  1272. } else {
  1273. BlockSize = (ULONG)Size;
  1274. }
  1275. if ((OneStatus =
  1276. GenAddMemoryBlock(Dump,
  1277. Process,
  1278. MEMBLOCK_PRIVATE_RW,
  1279. ScanOffset,
  1280. BlockSize)) != S_OK) {
  1281. Status = OneStatus;
  1282. }
  1283. ScanOffset += BlockSize;
  1284. Size -= BlockSize;
  1285. }
  1286. }
  1287. }
  1288. return Status;
  1289. }
  1290. BOOL
  1291. GenAppendStrW(
  1292. IN OUT PWSTR* Str,
  1293. IN OUT PULONG Chars,
  1294. IN PCWSTR Append
  1295. )
  1296. {
  1297. if (!Append) {
  1298. return FALSE;
  1299. }
  1300. while (*Chars > 1 && *Append) {
  1301. **Str = *Append++;
  1302. (*Str)++;
  1303. (*Chars)--;
  1304. }
  1305. if (!*Chars) {
  1306. return FALSE;
  1307. }
  1308. **Str = 0;
  1309. return TRUE;
  1310. }
  1311. PWSTR
  1312. GenIToAW(
  1313. IN ULONG Val,
  1314. IN ULONG FieldChars,
  1315. IN WCHAR FillChar,
  1316. IN PWSTR Buf,
  1317. IN ULONG BufChars
  1318. )
  1319. {
  1320. PWSTR Store = Buf + (BufChars - 1);
  1321. *Store-- = 0;
  1322. if (Val == 0) {
  1323. *Store-- = L'0';
  1324. } else {
  1325. while (Val) {
  1326. if (Store < Buf) {
  1327. return NULL;
  1328. }
  1329. *Store-- = (WCHAR)(Val % 10) + L'0';
  1330. Val /= 10;
  1331. }
  1332. }
  1333. PWSTR FieldStart = Buf + (BufChars - 1) - FieldChars;
  1334. while (Store >= FieldStart) {
  1335. *Store-- = FillChar;
  1336. }
  1337. return Store + 1;
  1338. }
  1339. class GenCorDataAccessServices : public ICorDataAccessServices
  1340. {
  1341. public:
  1342. GenCorDataAccessServices(IN PMINIDUMP_STATE Dump,
  1343. IN PINTERNAL_PROCESS Process)
  1344. {
  1345. m_Dump = Dump;
  1346. m_Process = Process;
  1347. }
  1348. // IUnknown.
  1349. STDMETHOD(QueryInterface)(
  1350. THIS_
  1351. IN REFIID InterfaceId,
  1352. OUT PVOID* Interface
  1353. )
  1354. {
  1355. *Interface = NULL;
  1356. return E_NOINTERFACE;
  1357. }
  1358. STDMETHOD_(ULONG, AddRef)(
  1359. THIS
  1360. )
  1361. {
  1362. return 1;
  1363. }
  1364. STDMETHOD_(ULONG, Release)(
  1365. THIS
  1366. )
  1367. {
  1368. return 0;
  1369. }
  1370. // ICorDataAccessServices.
  1371. virtual HRESULT STDMETHODCALLTYPE GetMachineType(
  1372. /* [out] */ ULONG32 *machine);
  1373. virtual HRESULT STDMETHODCALLTYPE GetPointerSize(
  1374. /* [out] */ ULONG32 *size);
  1375. virtual HRESULT STDMETHODCALLTYPE GetImageBase(
  1376. /* [string][in] */ LPCWSTR name,
  1377. /* [out] */ CORDATA_ADDRESS *base);
  1378. virtual HRESULT STDMETHODCALLTYPE ReadVirtual(
  1379. /* [in] */ CORDATA_ADDRESS address,
  1380. /* [length_is][size_is][out] */ PBYTE buffer,
  1381. /* [in] */ ULONG32 request,
  1382. /* [optional][out] */ ULONG32 *done);
  1383. virtual HRESULT STDMETHODCALLTYPE WriteVirtual(
  1384. /* [in] */ CORDATA_ADDRESS address,
  1385. /* [size_is][in] */ PBYTE buffer,
  1386. /* [in] */ ULONG32 request,
  1387. /* [optional][out] */ ULONG32 *done);
  1388. virtual HRESULT STDMETHODCALLTYPE GetTlsValue(
  1389. /* [in] */ ULONG32 index,
  1390. /* [out] */ CORDATA_ADDRESS* value);
  1391. virtual HRESULT STDMETHODCALLTYPE SetTlsValue(
  1392. /* [in] */ ULONG32 index,
  1393. /* [in] */ CORDATA_ADDRESS value);
  1394. virtual HRESULT STDMETHODCALLTYPE GetCurrentThreadId(
  1395. /* [out] */ ULONG32* threadId);
  1396. virtual HRESULT STDMETHODCALLTYPE GetThreadContext(
  1397. /* [in] */ ULONG32 threadId,
  1398. /* [in] */ ULONG32 contextFlags,
  1399. /* [in] */ ULONG32 contextSize,
  1400. /* [out, size_is(contextSize)] */ PBYTE context);
  1401. virtual HRESULT STDMETHODCALLTYPE SetThreadContext(
  1402. /* [in] */ ULONG32 threadId,
  1403. /* [in] */ ULONG32 contextSize,
  1404. /* [in, size_is(contextSize)] */ PBYTE context);
  1405. PMINIDUMP_STATE m_Dump;
  1406. PINTERNAL_PROCESS m_Process;
  1407. };
  1408. HRESULT STDMETHODCALLTYPE
  1409. GenCorDataAccessServices::GetMachineType(
  1410. /* [out] */ ULONG32 *machine
  1411. )
  1412. {
  1413. *machine = m_Dump->CpuType;
  1414. return S_OK;
  1415. }
  1416. HRESULT STDMETHODCALLTYPE
  1417. GenCorDataAccessServices::GetPointerSize(
  1418. /* [out] */ ULONG32 *size
  1419. )
  1420. {
  1421. *size = m_Dump->PtrSize;
  1422. return S_OK;
  1423. }
  1424. HRESULT STDMETHODCALLTYPE
  1425. GenCorDataAccessServices::GetImageBase(
  1426. /* [string][in] */ LPCWSTR name,
  1427. /* [out] */ CORDATA_ADDRESS *base
  1428. )
  1429. {
  1430. if ((!GenStrCompareW(name, L"mscoree.dll") &&
  1431. !GenStrCompareW(m_Process->CorDllType, L"ee")) ||
  1432. (!GenStrCompareW(name, L"mscorwks.dll") &&
  1433. !GenStrCompareW(m_Process->CorDllType, L"wks")) ||
  1434. (!GenStrCompareW(name, L"mscorsvr.dll") &&
  1435. !GenStrCompareW(m_Process->CorDllType, L"svr"))) {
  1436. *base = m_Process->CorDllBase;
  1437. return S_OK;
  1438. }
  1439. return E_NOINTERFACE;
  1440. }
  1441. HRESULT STDMETHODCALLTYPE
  1442. GenCorDataAccessServices::ReadVirtual(
  1443. /* [in] */ CORDATA_ADDRESS address,
  1444. /* [length_is][size_is][out] */ PBYTE buffer,
  1445. /* [in] */ ULONG32 request,
  1446. /* [optional][out] */ ULONG32 *done
  1447. )
  1448. {
  1449. return m_Dump->SysProv->
  1450. ReadVirtual(m_Process->ProcessHandle,
  1451. address, buffer, request, (PULONG)done);
  1452. }
  1453. HRESULT STDMETHODCALLTYPE
  1454. GenCorDataAccessServices::WriteVirtual(
  1455. /* [in] */ CORDATA_ADDRESS address,
  1456. /* [size_is][in] */ PBYTE buffer,
  1457. /* [in] */ ULONG32 request,
  1458. /* [optional][out] */ ULONG32 *done)
  1459. {
  1460. // No modification supported.
  1461. return E_UNEXPECTED;
  1462. }
  1463. HRESULT STDMETHODCALLTYPE
  1464. GenCorDataAccessServices::GetTlsValue(
  1465. /* [in] */ ULONG32 index,
  1466. /* [out] */ CORDATA_ADDRESS* value
  1467. )
  1468. {
  1469. // Not needed for minidump.
  1470. return E_NOTIMPL;
  1471. }
  1472. HRESULT STDMETHODCALLTYPE
  1473. GenCorDataAccessServices::SetTlsValue(
  1474. /* [in] */ ULONG32 index,
  1475. /* [in] */ CORDATA_ADDRESS value)
  1476. {
  1477. // No modification supported.
  1478. return E_UNEXPECTED;
  1479. }
  1480. HRESULT STDMETHODCALLTYPE
  1481. GenCorDataAccessServices::GetCurrentThreadId(
  1482. /* [out] */ ULONG32* threadId)
  1483. {
  1484. // Not needed for minidump.
  1485. return E_NOTIMPL;
  1486. }
  1487. HRESULT STDMETHODCALLTYPE
  1488. GenCorDataAccessServices::GetThreadContext(
  1489. /* [in] */ ULONG32 threadId,
  1490. /* [in] */ ULONG32 contextFlags,
  1491. /* [in] */ ULONG32 contextSize,
  1492. /* [out, size_is(contextSize)] */ PBYTE context
  1493. )
  1494. {
  1495. PINTERNAL_THREAD Thread;
  1496. PLIST_ENTRY Entry;
  1497. Entry = m_Process->ThreadList.Flink;
  1498. while (Entry != &m_Process->ThreadList) {
  1499. Thread = CONTAINING_RECORD(Entry,
  1500. INTERNAL_THREAD,
  1501. ThreadsLink);
  1502. Entry = Entry->Flink;
  1503. if (Thread->ThreadId == threadId) {
  1504. ULONG64 Ignored;
  1505. return m_Dump->SysProv->
  1506. GetThreadContext(Thread->ThreadHandle,
  1507. context, contextSize,
  1508. &Ignored, &Ignored, &Ignored);
  1509. }
  1510. }
  1511. return E_NOINTERFACE;
  1512. }
  1513. HRESULT STDMETHODCALLTYPE
  1514. GenCorDataAccessServices::SetThreadContext(
  1515. /* [in] */ ULONG32 threadId,
  1516. /* [in] */ ULONG32 contextSize,
  1517. /* [in, size_is(contextSize)] */ PBYTE context)
  1518. {
  1519. // No modification supported.
  1520. return E_UNEXPECTED;
  1521. }
  1522. class GenCorDataEnumMemoryRegions : public ICorDataEnumMemoryRegions
  1523. {
  1524. public:
  1525. GenCorDataEnumMemoryRegions(IN PMINIDUMP_STATE Dump,
  1526. IN PINTERNAL_PROCESS Process)
  1527. {
  1528. m_Dump = Dump;
  1529. m_Process = Process;
  1530. }
  1531. // IUnknown.
  1532. STDMETHOD(QueryInterface)(
  1533. THIS_
  1534. IN REFIID InterfaceId,
  1535. OUT PVOID* Interface
  1536. )
  1537. {
  1538. *Interface = NULL;
  1539. return E_NOINTERFACE;
  1540. }
  1541. STDMETHOD_(ULONG, AddRef)(
  1542. THIS
  1543. )
  1544. {
  1545. return 1;
  1546. }
  1547. STDMETHOD_(ULONG, Release)(
  1548. THIS
  1549. )
  1550. {
  1551. return 0;
  1552. }
  1553. // ICorDataEnumMemoryRegions.
  1554. HRESULT STDMETHODCALLTYPE EnumMemoryRegion(
  1555. /* [in] */ CORDATA_ADDRESS address,
  1556. /* [in] */ ULONG32 size
  1557. )
  1558. {
  1559. return GenAddMemoryBlock(m_Dump, m_Process, MEMBLOCK_COR,
  1560. address, size);
  1561. }
  1562. private:
  1563. PMINIDUMP_STATE m_Dump;
  1564. PINTERNAL_PROCESS m_Process;
  1565. };
  1566. HRESULT
  1567. GenTryGetCorMemory(
  1568. IN PMINIDUMP_STATE Dump,
  1569. IN PINTERNAL_PROCESS Process,
  1570. IN PWSTR CorDebugDllPath,
  1571. OUT PBOOL Loaded
  1572. )
  1573. {
  1574. HRESULT Status;
  1575. GenCorDataAccessServices Services(Dump, Process);
  1576. GenCorDataEnumMemoryRegions EnumMem(Dump, Process);
  1577. ICorDataAccess* Access;
  1578. *Loaded = FALSE;
  1579. if ((Status = Dump->SysProv->
  1580. GetCorDataAccess(CorDebugDllPath, &Services, &Access)) != S_OK) {
  1581. return Status;
  1582. }
  1583. *Loaded = TRUE;
  1584. Status = Access->EnumMemoryRegions(&EnumMem, DAC_ENUM_MEM_DEFAULT);
  1585. Dump->SysProv->ReleaseCorDataAccess(Access);
  1586. return Status;
  1587. }
  1588. HRESULT
  1589. GenGetCorMemory(
  1590. IN PMINIDUMP_STATE Dump,
  1591. IN PINTERNAL_PROCESS Process
  1592. )
  1593. {
  1594. HRESULT Status;
  1595. // Do not enable COR memory gathering for .NET Server
  1596. // as it's not stable yet.
  1597. #ifdef GET_COR_MEMORY
  1598. if (!Process->CorDllType) {
  1599. // COR is not loaded.
  1600. return S_OK;
  1601. }
  1602. if (Dump->DumpType & (MiniDumpWithFullMemory |
  1603. MiniDumpWithPrivateReadWriteMemory)) {
  1604. // All COR memory should already be included.
  1605. return S_OK;
  1606. }
  1607. WCHAR CorDebugDllPath[MAX_PATH + 1];
  1608. WCHAR NumStr[16];
  1609. PWSTR DllPathEnd, End;
  1610. ULONG Chars;
  1611. BOOL Loaded;
  1612. GenStrCopyNW(CorDebugDllPath, Process->CorDllPath,
  1613. ARRAY_COUNT(CorDebugDllPath));
  1614. DllPathEnd = GenGetPathTail(CorDebugDllPath);
  1615. //
  1616. // First try to load with the basic name.
  1617. //
  1618. End = DllPathEnd;
  1619. *End = 0;
  1620. Chars = (ULONG)(ARRAY_COUNT(CorDebugDllPath) - (End - CorDebugDllPath));
  1621. if (!GenAppendStrW(&End, &Chars, L"mscordacwks.dll")) {
  1622. return E_INVALIDARG;
  1623. }
  1624. if ((Status = GenTryGetCorMemory(Dump, Process, CorDebugDllPath,
  1625. &Loaded)) == S_OK ||
  1626. Loaded)
  1627. {
  1628. return Status;
  1629. }
  1630. //
  1631. // That didn't work, so try with the full name.
  1632. //
  1633. #if defined(_X86_)
  1634. PWSTR HostCpu = L"x86";
  1635. #elif defined(_IA64_)
  1636. PWSTR HostCpu = L"IA64";
  1637. #elif defined(_AMD64_)
  1638. PWSTR HostCpu = L"AMD64";
  1639. #elif defined(_ARM_)
  1640. PWSTR HostCpu = L"ARM";
  1641. #else
  1642. #error Unknown processor.
  1643. #endif
  1644. if (!GenAppendStrW(&End, &Chars, L"mscordac") ||
  1645. !GenAppendStrW(&End, &Chars, Process->CorDllType) ||
  1646. !GenAppendStrW(&End, &Chars, L"_") ||
  1647. !GenAppendStrW(&End, &Chars, HostCpu) ||
  1648. !GenAppendStrW(&End, &Chars, L"_") ||
  1649. !GenAppendStrW(&End, &Chars, Dump->CpuTypeName) ||
  1650. !GenAppendStrW(&End, &Chars, L"_") ||
  1651. !GenAppendStrW(&End, &Chars,
  1652. GenIToAW(Process->CorDllVer.dwFileVersionMS >> 16,
  1653. 0, 0, NumStr, ARRAY_COUNT(NumStr))) ||
  1654. !GenAppendStrW(&End, &Chars, L".") ||
  1655. !GenAppendStrW(&End, &Chars,
  1656. GenIToAW(Process->CorDllVer.dwFileVersionMS & 0xffff,
  1657. 0, 0, NumStr, ARRAY_COUNT(NumStr))) ||
  1658. !GenAppendStrW(&End, &Chars, L".") ||
  1659. !GenAppendStrW(&End, &Chars,
  1660. GenIToAW(Process->CorDllVer.dwFileVersionLS >> 16,
  1661. 0, 0, NumStr, ARRAY_COUNT(NumStr))) ||
  1662. !GenAppendStrW(&End, &Chars, L".") ||
  1663. !GenAppendStrW(&End, &Chars,
  1664. GenIToAW(Process->CorDllVer.dwFileVersionLS & 0xffff,
  1665. 2, L'0', NumStr, ARRAY_COUNT(NumStr))) ||
  1666. ((Process->CorDllVer.dwFileFlags & VS_FF_DEBUG) &&
  1667. !GenAppendStrW(&End, &Chars,
  1668. (Process->CorDllVer.dwFileFlags & VS_FF_SPECIALBUILD) ?
  1669. L".dbg" : L".chk")) ||
  1670. !GenAppendStrW(&End, &Chars, L".dll")) {
  1671. return E_INVALIDARG;
  1672. }
  1673. return GenTryGetCorMemory(Dump, Process, CorDebugDllPath, &Loaded);
  1674. #else
  1675. return S_OK;
  1676. #endif
  1677. }
  1678. HRESULT
  1679. GenGetProcessInfo(
  1680. IN PMINIDUMP_STATE Dump,
  1681. OUT PINTERNAL_PROCESS * ProcessRet
  1682. )
  1683. {
  1684. HRESULT Status;
  1685. BOOL EnumStarted = FALSE;
  1686. PINTERNAL_PROCESS Process;
  1687. WCHAR UnicodePath[MAX_PATH + 10];
  1688. if ((Status = GenAllocateProcessObject(Dump, &Process)) != S_OK) {
  1689. return Status;
  1690. }
  1691. if ((Status = Dump->SysProv->StartProcessEnum(Dump->ProcessHandle,
  1692. Dump->ProcessId)) != S_OK) {
  1693. goto Exit;
  1694. }
  1695. EnumStarted = TRUE;
  1696. //
  1697. // Walk thread list, suspending all threads and getting thread info.
  1698. //
  1699. for (;;) {
  1700. PINTERNAL_THREAD Thread;
  1701. ULONG ThreadId;
  1702. Status = Dump->SysProv->EnumThreads(&ThreadId);
  1703. if (Status == S_FALSE) {
  1704. break;
  1705. } else if (Status != S_OK) {
  1706. goto Exit;
  1707. }
  1708. ULONG WriteFlags;
  1709. if (!GenExecuteIncludeThreadCallback(Dump,
  1710. ThreadId,
  1711. &WriteFlags) ||
  1712. IsFlagClear(WriteFlags, ThreadWriteThread)) {
  1713. continue;
  1714. }
  1715. Status = GenAllocateThreadObject(Dump,
  1716. Process,
  1717. ThreadId,
  1718. WriteFlags,
  1719. &Thread);
  1720. if (FAILED(Status)) {
  1721. goto Exit;
  1722. }
  1723. // If Status is S_FALSE it means that the thread
  1724. // couldn't be opened and probably exited before
  1725. // we got to it. Just continue on.
  1726. if (Status == S_OK) {
  1727. Process->NumberOfThreads++;
  1728. InsertTailList(&Process->ThreadList, &Thread->ThreadsLink);
  1729. }
  1730. }
  1731. //
  1732. // Walk module list, getting module information.
  1733. //
  1734. for (;;) {
  1735. PINTERNAL_MODULE Module;
  1736. ULONG64 ModuleBase;
  1737. Status = Dump->SysProv->EnumModules(&ModuleBase,
  1738. UnicodePath,
  1739. ARRAY_COUNT(UnicodePath));
  1740. if (Status == S_FALSE) {
  1741. break;
  1742. } else if (Status != S_OK) {
  1743. goto Exit;
  1744. }
  1745. PWSTR ModPathTail;
  1746. BOOL IsCor = FALSE;
  1747. ModPathTail = GenGetPathTail(UnicodePath);
  1748. if (!GenStrCompareW(ModPathTail, L"mscoree.dll") &&
  1749. !Process->CorDllType) {
  1750. IsCor = TRUE;
  1751. Process->CorDllType = L"ee";
  1752. } else if (!GenStrCompareW(ModPathTail, L"mscorwks.dll")) {
  1753. IsCor = TRUE;
  1754. Process->CorDllType = L"wks";
  1755. } else if (!GenStrCompareW(ModPathTail, L"mscorsvr.dll")) {
  1756. IsCor = TRUE;
  1757. Process->CorDllType = L"svr";
  1758. }
  1759. if (IsCor) {
  1760. Process->CorDllBase = ModuleBase;
  1761. GenStrCopyNW(Process->CorDllPath, UnicodePath,
  1762. ARRAY_COUNT(Process->CorDllPath));
  1763. }
  1764. ULONG WriteFlags;
  1765. if (!GenExecuteIncludeModuleCallback(Dump,
  1766. ModuleBase,
  1767. &WriteFlags) ||
  1768. IsFlagClear(WriteFlags, ModuleWriteModule)) {
  1769. // If this is the COR DLL module we need to get
  1770. // its version information for later use. The
  1771. // callback has dropped it from the enumeration
  1772. // so do it right now before the module is forgotten.
  1773. if (IsCor &&
  1774. (Status = Dump->SysProv->
  1775. GetImageVersionInfo(Dump->ProcessHandle,
  1776. UnicodePath,
  1777. ModuleBase,
  1778. &Process->CorDllVer)) != S_OK) {
  1779. // If we can't get the version just forget
  1780. // that this process has the COR loaded.
  1781. // The dump will probably be useless but
  1782. // there's a tiny chance it won't.
  1783. Process->CorDllType = NULL;
  1784. }
  1785. continue;
  1786. }
  1787. if ((Status =
  1788. GenAllocateModuleObject(Dump,
  1789. Process,
  1790. UnicodePath,
  1791. ModuleBase,
  1792. WriteFlags,
  1793. &Module)) != S_OK) {
  1794. goto Exit;
  1795. }
  1796. if (IsCor) {
  1797. Process->CorDllVer = Module->VersionInfo;
  1798. }
  1799. Process->NumberOfModules++;
  1800. InsertTailList (&Process->ModuleList, &Module->ModulesLink);
  1801. }
  1802. //
  1803. // Walk function table list. The function table list
  1804. // is important but not absolutely critical so failures
  1805. // here are not fatal.
  1806. //
  1807. for (;;) {
  1808. PINTERNAL_FUNCTION_TABLE Table;
  1809. ULONG64 MinAddr, MaxAddr, BaseAddr;
  1810. ULONG EntryCount;
  1811. ULONG64 RawTable[(MAX_DYNAMIC_FUNCTION_TABLE + sizeof(ULONG64) - 1) /
  1812. sizeof(ULONG64)];
  1813. PVOID RawEntryHandle;
  1814. Status = Dump->SysProv->
  1815. EnumFunctionTables(&MinAddr,
  1816. &MaxAddr,
  1817. &BaseAddr,
  1818. &EntryCount,
  1819. RawTable,
  1820. Dump->FuncTableSize,
  1821. &RawEntryHandle);
  1822. if (Status != S_OK) {
  1823. break;
  1824. }
  1825. if (GenAllocateFunctionTableObject(Dump,
  1826. MinAddr,
  1827. MaxAddr,
  1828. BaseAddr,
  1829. EntryCount,
  1830. RawTable,
  1831. &Table) == S_OK) {
  1832. if (Dump->SysProv->
  1833. EnumFunctionTableEntries(RawTable,
  1834. Dump->FuncTableSize,
  1835. RawEntryHandle,
  1836. Table->RawEntries,
  1837. EntryCount *
  1838. Dump->FuncTableEntrySize) != S_OK) {
  1839. GenFreeFunctionTableObject(Dump, Table);
  1840. } else {
  1841. GenIncludeUnwindInfoMemory(Dump, Process, Table);
  1842. Process->NumberOfFunctionTables++;
  1843. InsertTailList(&Process->FunctionTableList,
  1844. &Table->TableLink);
  1845. }
  1846. }
  1847. }
  1848. //
  1849. // Walk unloaded module list. The unloaded module
  1850. // list is not critical information so failures here
  1851. // are not fatal.
  1852. //
  1853. if (Dump->DumpType & MiniDumpWithUnloadedModules) {
  1854. PINTERNAL_UNLOADED_MODULE UnlModule;
  1855. ULONG64 ModuleBase;
  1856. ULONG Size;
  1857. ULONG CheckSum;
  1858. ULONG TimeDateStamp;
  1859. while (Dump->SysProv->
  1860. EnumUnloadedModules(UnicodePath,
  1861. ARRAY_COUNT(UnicodePath),
  1862. &ModuleBase,
  1863. &Size,
  1864. &CheckSum,
  1865. &TimeDateStamp) == S_OK) {
  1866. if (GenAllocateUnloadedModuleObject(Dump,
  1867. UnicodePath,
  1868. ModuleBase,
  1869. Size,
  1870. CheckSum,
  1871. TimeDateStamp,
  1872. &UnlModule) == S_OK) {
  1873. Process->NumberOfUnloadedModules++;
  1874. InsertHeadList(&Process->UnloadedModuleList,
  1875. &UnlModule->ModulesLink);
  1876. } else {
  1877. break;
  1878. }
  1879. }
  1880. }
  1881. Status = S_OK;
  1882. Exit:
  1883. if (EnumStarted) {
  1884. Dump->SysProv->FinishProcessEnum();
  1885. }
  1886. if (Status == S_OK) {
  1887. // We don't consider a failure here to be a critical
  1888. // failure. The dump won't contain all of the
  1889. // requested information but it'll still have
  1890. // the basic thread information, which could be
  1891. // valuable on its own.
  1892. GenScanAddressSpace(Dump, Process);
  1893. GenGetCorMemory(Dump, Process);
  1894. } else {
  1895. GenFreeProcessObject(Dump, Process);
  1896. Process = NULL;
  1897. }
  1898. *ProcessRet = Process;
  1899. return Status;
  1900. }
  1901. HRESULT
  1902. GenWriteHandleData(
  1903. IN PMINIDUMP_STATE Dump,
  1904. IN PMINIDUMP_STREAM_INFO StreamInfo
  1905. )
  1906. {
  1907. HRESULT Status;
  1908. ULONG HandleCount;
  1909. ULONG Hits;
  1910. WCHAR TypeName[64];
  1911. WCHAR ObjectName[MAX_PATH];
  1912. PMINIDUMP_HANDLE_DESCRIPTOR Descs, Desc;
  1913. ULONG32 Len;
  1914. MINIDUMP_HANDLE_DATA_STREAM DataStream;
  1915. RVA Rva = StreamInfo->RvaOfHandleData;
  1916. if ((Status = Dump->SysProv->
  1917. StartHandleEnum(Dump->ProcessHandle,
  1918. Dump->ProcessId,
  1919. &HandleCount)) != S_OK) {
  1920. return Status;
  1921. }
  1922. if (!HandleCount) {
  1923. Dump->SysProv->FinishHandleEnum();
  1924. return S_OK;
  1925. }
  1926. Descs = (PMINIDUMP_HANDLE_DESCRIPTOR)
  1927. AllocMemory(Dump, HandleCount * sizeof(*Desc));
  1928. if (Descs == NULL) {
  1929. Dump->SysProv->FinishHandleEnum();
  1930. return E_OUTOFMEMORY;
  1931. }
  1932. Hits = 0;
  1933. Desc = Descs;
  1934. while (Hits < HandleCount &&
  1935. Dump->SysProv->
  1936. EnumHandles(&Desc->Handle,
  1937. (PULONG)&Desc->Attributes,
  1938. (PULONG)&Desc->GrantedAccess,
  1939. (PULONG)&Desc->HandleCount,
  1940. (PULONG)&Desc->PointerCount,
  1941. TypeName,
  1942. ARRAY_COUNT(TypeName),
  1943. ObjectName,
  1944. ARRAY_COUNT(ObjectName)) == S_OK) {
  1945. // Successfully got a handle, so consider this a hit.
  1946. Hits++;
  1947. Desc->TypeNameRva = Rva;
  1948. Len = GenStrLengthW(TypeName) * sizeof(WCHAR);
  1949. if ((Status = Dump->OutProv->
  1950. WriteAll(&Len, sizeof(Len))) != S_OK) {
  1951. goto Exit;
  1952. }
  1953. Len += sizeof(WCHAR);
  1954. if ((Status = Dump->OutProv->
  1955. WriteAll(TypeName, Len)) != S_OK) {
  1956. goto Exit;
  1957. }
  1958. Rva += Len + sizeof(Len);
  1959. if (ObjectName[0]) {
  1960. Desc->ObjectNameRva = Rva;
  1961. Len = GenStrLengthW(ObjectName) * sizeof(WCHAR);
  1962. if ((Status = Dump->OutProv->
  1963. WriteAll(&Len, sizeof(Len))) != S_OK) {
  1964. goto Exit;
  1965. }
  1966. Len += sizeof(WCHAR);
  1967. if ((Status = Dump->OutProv->
  1968. WriteAll(ObjectName, Len)) != S_OK) {
  1969. goto Exit;
  1970. }
  1971. Rva += Len + sizeof(Len);
  1972. } else {
  1973. Desc->ObjectNameRva = 0;
  1974. }
  1975. Desc++;
  1976. }
  1977. DataStream.SizeOfHeader = sizeof(DataStream);
  1978. DataStream.SizeOfDescriptor = sizeof(*Descs);
  1979. DataStream.NumberOfDescriptors = (ULONG)(Desc - Descs);
  1980. DataStream.Reserved = 0;
  1981. StreamInfo->RvaOfHandleData = Rva;
  1982. StreamInfo->SizeOfHandleData = sizeof(DataStream) +
  1983. DataStream.NumberOfDescriptors * sizeof(*Descs);
  1984. if ((Status = Dump->OutProv->
  1985. WriteAll(&DataStream, sizeof(DataStream))) == S_OK) {
  1986. Status = Dump->OutProv->
  1987. WriteAll(Descs, DataStream.NumberOfDescriptors * sizeof(*Descs));
  1988. }
  1989. Exit:
  1990. FreeMemory(Dump, Descs);
  1991. Dump->SysProv->FinishHandleEnum();
  1992. return Status;
  1993. }
  1994. ULONG
  1995. GenProcArchToImageMachine(ULONG ProcArch)
  1996. {
  1997. switch(ProcArch) {
  1998. case PROCESSOR_ARCHITECTURE_INTEL:
  1999. return IMAGE_FILE_MACHINE_I386;
  2000. case PROCESSOR_ARCHITECTURE_IA64:
  2001. return IMAGE_FILE_MACHINE_IA64;
  2002. case PROCESSOR_ARCHITECTURE_AMD64:
  2003. return IMAGE_FILE_MACHINE_AMD64;
  2004. case PROCESSOR_ARCHITECTURE_ARM:
  2005. return IMAGE_FILE_MACHINE_ARM;
  2006. case PROCESSOR_ARCHITECTURE_ALPHA:
  2007. return IMAGE_FILE_MACHINE_ALPHA;
  2008. case PROCESSOR_ARCHITECTURE_ALPHA64:
  2009. return IMAGE_FILE_MACHINE_AXP64;
  2010. default:
  2011. return IMAGE_FILE_MACHINE_UNKNOWN;
  2012. }
  2013. }
  2014. LPWSTR
  2015. GenStrCopyNW(
  2016. OUT LPWSTR lpString1,
  2017. IN LPCWSTR lpString2,
  2018. IN int iMaxLength
  2019. )
  2020. {
  2021. wchar_t * cp = lpString1;
  2022. if (iMaxLength > 0)
  2023. {
  2024. while( iMaxLength > 1 && (*cp++ = *lpString2++) )
  2025. iMaxLength--; /* Copy src over dst */
  2026. if (cp > lpString1 && cp[-1]) {
  2027. *cp = 0;
  2028. }
  2029. }
  2030. return( lpString1 );
  2031. }
  2032. size_t
  2033. GenStrLengthW(
  2034. const wchar_t * wcs
  2035. )
  2036. {
  2037. const wchar_t *eos = wcs;
  2038. while( *eos++ )
  2039. ;
  2040. return( (size_t)(eos - wcs - 1) );
  2041. }
  2042. int
  2043. GenStrCompareW(
  2044. IN LPCWSTR String1,
  2045. IN LPCWSTR String2
  2046. )
  2047. {
  2048. while (*String1) {
  2049. if (*String1 < *String2) {
  2050. return -1;
  2051. } else if (*String1 > *String2) {
  2052. return 1;
  2053. }
  2054. String1++;
  2055. String2++;
  2056. }
  2057. return *String2 ? 1 : 0;
  2058. }
  2059. C_ASSERT(sizeof(EXCEPTION_RECORD64) == sizeof(MINIDUMP_EXCEPTION));
  2060. void
  2061. GenExRecord32ToMd(PEXCEPTION_RECORD32 Rec32,
  2062. PMINIDUMP_EXCEPTION RecMd)
  2063. {
  2064. ULONG i;
  2065. RecMd->ExceptionCode = Rec32->ExceptionCode;
  2066. RecMd->ExceptionFlags = Rec32->ExceptionFlags;
  2067. RecMd->ExceptionRecord = (LONG)Rec32->ExceptionRecord;
  2068. RecMd->ExceptionAddress = (LONG)Rec32->ExceptionAddress;
  2069. RecMd->NumberParameters = Rec32->NumberParameters;
  2070. for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
  2071. {
  2072. RecMd->ExceptionInformation[i] =
  2073. (LONG)Rec32->ExceptionInformation[i];
  2074. }
  2075. }