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.

3288 lines
92 KiB

  1. /*++
  2. Copyright(c) 1999-2002 Microsoft Corporation
  3. Module Name:
  4. minidump.c
  5. Abstract:
  6. Minidump user-mode crashdump support.
  7. Author:
  8. Matthew D Hendel (math) 20-Aug-1999
  9. --*/
  10. #include "pch.cpp"
  11. #include <limits.h>
  12. #include <dbgver.h>
  13. PINTERNAL_MODULE
  14. ModuleContainingAddress(
  15. IN PINTERNAL_PROCESS Process,
  16. IN ULONG64 Address
  17. )
  18. {
  19. PINTERNAL_MODULE Module;
  20. PLIST_ENTRY ModuleEntry;
  21. ModuleEntry = Process->ModuleList.Flink;
  22. while ( ModuleEntry != &Process->ModuleList ) {
  23. Module = CONTAINING_RECORD (ModuleEntry, INTERNAL_MODULE,
  24. ModulesLink);
  25. ModuleEntry = ModuleEntry->Flink;
  26. if (Address >= Module->BaseOfImage &&
  27. Address < Module->BaseOfImage + Module->SizeOfImage) {
  28. return Module;
  29. }
  30. }
  31. return NULL;
  32. }
  33. VOID
  34. ScanMemoryForModuleRefs(
  35. IN PMINIDUMP_STATE Dump,
  36. IN PINTERNAL_PROCESS Process,
  37. IN BOOL DoRead,
  38. IN ULONG64 Base,
  39. IN ULONG Size,
  40. IN PVOID MemBuffer,
  41. IN MEMBLOCK_TYPE TypeOfMemory,
  42. IN BOOL FilterContent
  43. )
  44. {
  45. PVOID CurMem;
  46. ULONG64 CurPtr;
  47. ULONG Done;
  48. // We only want to scan certain kinds of memory.
  49. if (TypeOfMemory != MEMBLOCK_STACK &&
  50. TypeOfMemory != MEMBLOCK_STORE &&
  51. TypeOfMemory != MEMBLOCK_DATA_SEG &&
  52. TypeOfMemory != MEMBLOCK_INDIRECT)
  53. {
  54. return;
  55. }
  56. // If the base address is not pointer-size aligned
  57. // we can't easily assume that this is a meaningful
  58. // area of memory to scan for references. Normal
  59. // stack and store addresses will always be pointer
  60. // size aligned so this should only reject invalid
  61. // addresses.
  62. if (!Base || !Size || (Base & (Dump->PtrSize - 1))) {
  63. return;
  64. }
  65. if (DoRead) {
  66. if (Dump->SysProv->
  67. ReadVirtual(Dump->ProcessHandle,
  68. Base, MemBuffer, Size, &Done) != S_OK) {
  69. return;
  70. }
  71. } else {
  72. Done = Size;
  73. }
  74. CurMem = MemBuffer;
  75. Done /= Dump->PtrSize;
  76. while (Done-- > 0) {
  77. PINTERNAL_MODULE Module;
  78. BOOL InAny;
  79. CurPtr = GenGetPointer(Dump, CurMem);
  80. // An IA64 backing store can contain PFS values
  81. // that must be preserved in order to allow stack walking.
  82. // The high two bits of PFS are the privilege level, which
  83. // should always be 0y11 for user-mode code so we use this
  84. // as a marker to look for PFS entries.
  85. // There is also a NAT collection flush at every 0x1F8
  86. // offset. These values cannot be filtered.
  87. if (Dump->CpuType == IMAGE_FILE_MACHINE_IA64 &&
  88. TypeOfMemory == MEMBLOCK_STORE) {
  89. if ((Base & 0x1f8) == 0x1f8 ||
  90. (CurPtr & 0xc000000000000000UI64) == 0xc000000000000000UI64) {
  91. goto Next;
  92. }
  93. }
  94. InAny = FALSE;
  95. if (Module = ModuleContainingAddress(Process, CurPtr)) {
  96. Module->WriteFlags |= ModuleReferencedByMemory;
  97. InAny = TRUE;
  98. }
  99. // If the current pointer is not a module reference
  100. // or an internal reference for a thread stack or store,
  101. // filter it.
  102. if (FilterContent && !InAny) {
  103. PINTERNAL_THREAD Thread;
  104. PLIST_ENTRY ThreadEntry;
  105. ThreadEntry = Process->ThreadList.Flink;
  106. while ( ThreadEntry != &Process->ThreadList ) {
  107. Thread = CONTAINING_RECORD (ThreadEntry, INTERNAL_THREAD,
  108. ThreadsLink);
  109. ThreadEntry = ThreadEntry->Flink;
  110. if ((CurPtr >= Thread->StackEnd &&
  111. CurPtr < Thread->StackBase) ||
  112. (CurPtr >= Thread->BackingStoreBase &&
  113. CurPtr < Thread->BackingStoreBase +
  114. Thread->BackingStoreSize)) {
  115. InAny = TRUE;
  116. break;
  117. }
  118. }
  119. if (!InAny) {
  120. GenSetPointer(Dump, CurMem, 0);
  121. }
  122. }
  123. Next:
  124. CurMem = (PUCHAR)CurMem + Dump->PtrSize;
  125. Base += Dump->PtrSize;
  126. }
  127. }
  128. HRESULT
  129. WriteAtOffset(
  130. IN PMINIDUMP_STATE Dump,
  131. ULONG Offset,
  132. PVOID Buffer,
  133. ULONG BufferSize
  134. )
  135. {
  136. HRESULT Status;
  137. if ((Status = Dump->OutProv->
  138. Seek(FILE_BEGIN, Offset, NULL)) == S_OK) {
  139. Status = Dump->OutProv->
  140. WriteAll(Buffer, BufferSize);
  141. }
  142. return Status;
  143. }
  144. HRESULT
  145. WriteOther(
  146. IN PMINIDUMP_STATE Dump,
  147. IN PMINIDUMP_STREAM_INFO StreamInfo,
  148. IN PVOID Buffer,
  149. IN ULONG SizeOfBuffer,
  150. OUT ULONG * BufferRva
  151. )
  152. {
  153. HRESULT Status;
  154. ULONG Rva;
  155. ASSERT (Buffer != NULL);
  156. ASSERT (SizeOfBuffer != 0);
  157. //
  158. // If it's larger than we've allocated space for, fail.
  159. //
  160. Rva = StreamInfo->RvaForCurOther;
  161. if (Rva + SizeOfBuffer >
  162. StreamInfo->RvaOfOther + StreamInfo->SizeOfOther) {
  163. return E_INVALIDARG;
  164. }
  165. //
  166. // Set location to point at which we want to write and write.
  167. //
  168. if ((Status = Dump->OutProv->
  169. Seek(FILE_BEGIN, Rva, NULL)) == S_OK) {
  170. if ((Status = Dump->OutProv->
  171. WriteAll(Buffer, SizeOfBuffer)) == S_OK) {
  172. if (BufferRva) {
  173. *BufferRva = Rva;
  174. }
  175. StreamInfo->RvaForCurOther += SizeOfBuffer;
  176. }
  177. }
  178. return Status;
  179. }
  180. HRESULT
  181. WriteMemory(
  182. IN PMINIDUMP_STATE Dump,
  183. IN PMINIDUMP_STREAM_INFO StreamInfo,
  184. IN PVOID Buffer,
  185. IN ULONG64 StartOfRegion,
  186. IN ULONG SizeOfRegion,
  187. OUT ULONG * MemoryDataRva OPTIONAL
  188. )
  189. {
  190. HRESULT Status;
  191. ULONG DataRva;
  192. ULONG ListRva;
  193. ULONG SizeOfMemoryDescriptor;
  194. MINIDUMP_MEMORY_DESCRIPTOR Descriptor;
  195. ASSERT ( StreamInfo != NULL );
  196. ASSERT ( Buffer != NULL );
  197. ASSERT ( StartOfRegion != 0 );
  198. ASSERT ( SizeOfRegion != 0 );
  199. //
  200. // Writing a memory entry is a little different. When a memory entry
  201. // is written we need a descriptor in the memory list describing the
  202. // memory written AND a variable-sized entry in the MEMORY_DATA region
  203. // with the actual data.
  204. //
  205. ListRva = StreamInfo->RvaForCurMemoryDescriptor;
  206. DataRva = StreamInfo->RvaForCurMemoryData;
  207. SizeOfMemoryDescriptor = sizeof (MINIDUMP_MEMORY_DESCRIPTOR);
  208. //
  209. // If we overflowed either the memory list or the memory data
  210. // regions, fail.
  211. //
  212. if ( ( ListRva + SizeOfMemoryDescriptor >
  213. StreamInfo->RvaOfMemoryDescriptors + StreamInfo->SizeOfMemoryDescriptors) ||
  214. ( DataRva + SizeOfRegion >
  215. StreamInfo->RvaOfMemoryData + StreamInfo->SizeOfMemoryData ) ) {
  216. return E_INVALIDARG;
  217. }
  218. //
  219. // First, write the data to the MEMORY_DATA region.
  220. //
  221. if ((Status = Dump->OutProv->
  222. Seek(FILE_BEGIN, DataRva, NULL)) != S_OK ||
  223. (Status = Dump->OutProv->
  224. WriteAll(Buffer, SizeOfRegion)) != S_OK) {
  225. return Status;
  226. }
  227. //
  228. // Then update the memory descriptor in the MEMORY_LIST region.
  229. //
  230. Descriptor.StartOfMemoryRange = StartOfRegion;
  231. Descriptor.Memory.DataSize = SizeOfRegion;
  232. Descriptor.Memory.Rva = DataRva;
  233. if ((Status = Dump->OutProv->
  234. Seek(FILE_BEGIN, ListRva, NULL)) != S_OK ||
  235. (Status = Dump->OutProv->
  236. WriteAll(&Descriptor, SizeOfMemoryDescriptor)) != S_OK) {
  237. return Status;
  238. }
  239. //
  240. // Update both the List Rva and the Data Rva and return the
  241. // the Data Rva.
  242. //
  243. StreamInfo->RvaForCurMemoryDescriptor += SizeOfMemoryDescriptor;
  244. StreamInfo->RvaForCurMemoryData += SizeOfRegion;
  245. if ( MemoryDataRva ) {
  246. *MemoryDataRva = DataRva;
  247. }
  248. return S_OK;
  249. }
  250. HRESULT
  251. WriteMemoryFromProcess(
  252. IN PMINIDUMP_STATE Dump,
  253. IN PMINIDUMP_STREAM_INFO StreamInfo,
  254. IN PINTERNAL_PROCESS Process,
  255. IN ULONG64 BaseOfRegion,
  256. IN ULONG SizeOfRegion,
  257. IN BOOL FilterContent,
  258. IN MEMBLOCK_TYPE TypeOfMemory,
  259. OUT ULONG * MemoryDataRva OPTIONAL
  260. )
  261. {
  262. HRESULT Status;
  263. PVOID Buffer;
  264. Buffer = AllocMemory ( Dump, SizeOfRegion );
  265. if (!Buffer) {
  266. return E_OUTOFMEMORY;
  267. }
  268. if ((Status = Dump->SysProv->
  269. ReadAllVirtual(Dump->ProcessHandle, BaseOfRegion, Buffer,
  270. SizeOfRegion)) == S_OK) {
  271. if (FilterContent) {
  272. ScanMemoryForModuleRefs(Dump, Process, FALSE, BaseOfRegion,
  273. SizeOfRegion, Buffer, TypeOfMemory,
  274. TRUE);
  275. }
  276. Status = WriteMemory (Dump,
  277. StreamInfo,
  278. Buffer,
  279. BaseOfRegion,
  280. SizeOfRegion,
  281. MemoryDataRva);
  282. }
  283. FreeMemory(Dump, Buffer);
  284. return Status;
  285. }
  286. HRESULT
  287. WriteThread(
  288. IN PMINIDUMP_STATE Dump,
  289. IN PMINIDUMP_STREAM_INFO StreamInfo,
  290. IN LPVOID ThreadData,
  291. IN ULONG SizeOfThreadData,
  292. OUT ULONG * ThreadDataRva OPTIONAL
  293. )
  294. {
  295. HRESULT Status;
  296. ULONG Rva;
  297. ASSERT (StreamInfo);
  298. ASSERT (ThreadData);
  299. Rva = StreamInfo->RvaForCurThread;
  300. if ( Rva + SizeOfThreadData >
  301. StreamInfo->RvaOfThreadList + StreamInfo->SizeOfThreadList ) {
  302. return E_INVALIDARG;
  303. }
  304. if ((Status = Dump->OutProv->
  305. Seek(FILE_BEGIN, Rva, NULL)) != S_OK ||
  306. (Status = Dump->OutProv->
  307. WriteAll(ThreadData, SizeOfThreadData)) != S_OK) {
  308. return Status;
  309. }
  310. if ( ThreadDataRva ) {
  311. *ThreadDataRva = Rva;
  312. }
  313. StreamInfo->RvaForCurThread += SizeOfThreadData;
  314. return S_OK;
  315. }
  316. HRESULT
  317. WriteStringToPool(
  318. IN PMINIDUMP_STATE Dump,
  319. IN PMINIDUMP_STREAM_INFO StreamInfo,
  320. IN PWSTR String,
  321. OUT ULONG * StringRva
  322. )
  323. {
  324. HRESULT Status;
  325. ULONG32 StringLen;
  326. ULONG SizeOfString;
  327. ULONG Rva;
  328. ASSERT (String);
  329. ASSERT (sizeof (ULONG32) == sizeof (MINIDUMP_STRING));
  330. StringLen = GenStrLengthW(String) * sizeof (WCHAR);
  331. SizeOfString = sizeof (MINIDUMP_STRING) + StringLen + sizeof (WCHAR);
  332. Rva = StreamInfo->RvaForCurString;
  333. if ( Rva + SizeOfString >
  334. StreamInfo->RvaOfStringPool + StreamInfo->SizeOfStringPool ) {
  335. return E_INVALIDARG;
  336. }
  337. if ((Status = Dump->OutProv->
  338. Seek(FILE_BEGIN, Rva, NULL)) != S_OK ||
  339. (Status = Dump->OutProv->
  340. WriteAll(&StringLen, sizeof(StringLen))) != S_OK) {
  341. return Status;
  342. }
  343. //
  344. // Include the trailing '\000'.
  345. //
  346. StringLen += sizeof (WCHAR);
  347. if ((Status = Dump->OutProv->
  348. WriteAll(String, StringLen)) != S_OK) {
  349. return Status;
  350. }
  351. if ( StringRva ) {
  352. *StringRva = Rva;
  353. }
  354. StreamInfo->RvaForCurString += SizeOfString;
  355. return S_OK;
  356. }
  357. HRESULT
  358. WriteModule (
  359. IN PMINIDUMP_STATE Dump,
  360. IN PMINIDUMP_STREAM_INFO StreamInfo,
  361. IN PMINIDUMP_MODULE Module,
  362. OUT ULONG * ModuleRva
  363. )
  364. {
  365. HRESULT Status;
  366. ULONG Rva;
  367. ULONG SizeOfModule;
  368. ASSERT (StreamInfo);
  369. ASSERT (Module);
  370. SizeOfModule = sizeof (MINIDUMP_MODULE);
  371. Rva = StreamInfo->RvaForCurModule;
  372. if ( Rva + SizeOfModule >
  373. StreamInfo->RvaOfModuleList + StreamInfo->SizeOfModuleList ) {
  374. return E_INVALIDARG;
  375. }
  376. if ((Status = Dump->OutProv->
  377. Seek(FILE_BEGIN, Rva, NULL)) != S_OK ||
  378. (Status = Dump->OutProv->
  379. WriteAll(Module, SizeOfModule)) != S_OK) {
  380. return Status;
  381. }
  382. if ( ModuleRva ) {
  383. *ModuleRva = Rva;
  384. }
  385. StreamInfo->RvaForCurModule += SizeOfModule;
  386. return S_OK;
  387. }
  388. HRESULT
  389. WriteUnloadedModule (
  390. IN PMINIDUMP_STATE Dump,
  391. IN PMINIDUMP_STREAM_INFO StreamInfo,
  392. IN PMINIDUMP_UNLOADED_MODULE Module,
  393. OUT ULONG * ModuleRva
  394. )
  395. {
  396. HRESULT Status;
  397. ULONG Rva;
  398. ULONG SizeOfModule;
  399. ASSERT (StreamInfo);
  400. ASSERT (Module);
  401. SizeOfModule = sizeof (*Module);
  402. Rva = StreamInfo->RvaForCurUnloadedModule;
  403. if ( Rva + SizeOfModule >
  404. StreamInfo->RvaOfUnloadedModuleList +
  405. StreamInfo->SizeOfUnloadedModuleList ) {
  406. return E_INVALIDARG;
  407. }
  408. if ((Status = Dump->OutProv->
  409. Seek(FILE_BEGIN, Rva, NULL)) != S_OK ||
  410. (Status = Dump->OutProv->
  411. WriteAll(Module, SizeOfModule)) != S_OK) {
  412. return Status;
  413. }
  414. if ( ModuleRva ) {
  415. *ModuleRva = Rva;
  416. }
  417. StreamInfo->RvaForCurUnloadedModule += SizeOfModule;
  418. return S_OK;
  419. }
  420. HRESULT
  421. WriteThreadList(
  422. IN PMINIDUMP_STATE Dump,
  423. IN PMINIDUMP_STREAM_INFO StreamInfo,
  424. IN PINTERNAL_PROCESS Process
  425. )
  426. {
  427. HRESULT Status;
  428. ULONG StackMemoryRva;
  429. ULONG StoreMemoryRva;
  430. ULONG ContextRva;
  431. MINIDUMP_THREAD_EX DumpThread;
  432. PINTERNAL_THREAD Thread;
  433. ULONG NumberOfThreads;
  434. PLIST_ENTRY Entry;
  435. ASSERT (Process);
  436. ASSERT (StreamInfo);
  437. //
  438. // Write the thread count.
  439. //
  440. NumberOfThreads = Process->NumberOfThreadsToWrite;
  441. if ((Status = Dump->OutProv->
  442. Seek(FILE_BEGIN, StreamInfo->RvaOfThreadList, NULL)) != S_OK ||
  443. (Status = Dump->OutProv->
  444. WriteAll(&NumberOfThreads, sizeof(NumberOfThreads))) != S_OK) {
  445. return Status;
  446. }
  447. StreamInfo->RvaForCurThread += sizeof(NumberOfThreads);
  448. //
  449. // Iterate over the thread list writing the description,
  450. // context and memory for each thread.
  451. //
  452. Entry = Process->ThreadList.Flink;
  453. while ( Entry != &Process->ThreadList ) {
  454. Thread = CONTAINING_RECORD (Entry,
  455. INTERNAL_THREAD,
  456. ThreadsLink);
  457. Entry = Entry->Flink;
  458. //
  459. // Only write the threads that have been flagged to be written.
  460. //
  461. if (IsFlagClear (Thread->WriteFlags, ThreadWriteThread)) {
  462. continue;
  463. }
  464. //
  465. // Write the context if it was flagged to be written.
  466. //
  467. if (IsFlagSet (Thread->WriteFlags, ThreadWriteContext)) {
  468. //
  469. // Write the thread context to the OTHER stream.
  470. //
  471. if ((Status = WriteOther (Dump,
  472. StreamInfo,
  473. Thread->ContextBuffer,
  474. Dump->ContextSize,
  475. &ContextRva)) != S_OK) {
  476. return Status;
  477. }
  478. } else {
  479. ContextRva = 0;
  480. }
  481. //
  482. // Write the stack if it was flagged to be written.
  483. //
  484. if (IsFlagSet (Thread->WriteFlags, ThreadWriteStack)) {
  485. //
  486. // Write the stack memory data; write it directly from the image.
  487. //
  488. if ((Status =
  489. WriteMemoryFromProcess(Dump,
  490. StreamInfo,
  491. Process,
  492. Thread->StackEnd,
  493. (ULONG) (Thread->StackBase -
  494. Thread->StackEnd),
  495. IsFlagSet(Dump->DumpType,
  496. MiniDumpFilterMemory),
  497. MEMBLOCK_STACK,
  498. &StackMemoryRva)) != S_OK) {
  499. return Status;
  500. }
  501. } else {
  502. StackMemoryRva = 0;
  503. }
  504. //
  505. // Write the backing store if it was flagged to be written.
  506. // A newly created thread's backing store may be empty
  507. // so handle the case of zero size.
  508. //
  509. if (IsFlagSet (Thread->WriteFlags, ThreadWriteBackingStore) &&
  510. Thread->BackingStoreSize) {
  511. //
  512. // Write the store memory data; write it directly from the image.
  513. //
  514. if ((Status =
  515. WriteMemoryFromProcess(Dump,
  516. StreamInfo,
  517. Process,
  518. Thread->BackingStoreBase,
  519. Thread->BackingStoreSize,
  520. IsFlagSet(Dump->DumpType,
  521. MiniDumpFilterMemory),
  522. MEMBLOCK_STORE,
  523. &StoreMemoryRva
  524. )) != S_OK) {
  525. return Status;
  526. }
  527. } else {
  528. StoreMemoryRva = 0;
  529. }
  530. //
  531. // Build the dump thread.
  532. //
  533. DumpThread.ThreadId = Thread->ThreadId;
  534. DumpThread.SuspendCount = Thread->SuspendCount;
  535. DumpThread.PriorityClass = Thread->PriorityClass;
  536. DumpThread.Priority = Thread->Priority;
  537. DumpThread.Teb = Thread->Teb;
  538. //
  539. // Stack offset and size.
  540. //
  541. DumpThread.Stack.StartOfMemoryRange = Thread->StackEnd;
  542. DumpThread.Stack.Memory.DataSize =
  543. (ULONG) ( Thread->StackBase - Thread->StackEnd );
  544. DumpThread.Stack.Memory.Rva = StackMemoryRva;
  545. //
  546. // Backing store offset and size.
  547. //
  548. DumpThread.BackingStore.StartOfMemoryRange = Thread->BackingStoreBase;
  549. DumpThread.BackingStore.Memory.DataSize = Thread->BackingStoreSize;
  550. DumpThread.BackingStore.Memory.Rva = StoreMemoryRva;
  551. //
  552. // Context offset and size.
  553. //
  554. DumpThread.ThreadContext.DataSize = Dump->ContextSize;
  555. DumpThread.ThreadContext.Rva = ContextRva;
  556. //
  557. // Write the dump thread to the threads region.
  558. //
  559. if ((Status = WriteThread (Dump,
  560. StreamInfo,
  561. &DumpThread,
  562. StreamInfo->ThreadStructSize,
  563. NULL)) != S_OK) {
  564. return Status;
  565. }
  566. }
  567. return S_OK;
  568. }
  569. HRESULT
  570. WriteModuleList(
  571. IN PMINIDUMP_STATE Dump,
  572. IN PMINIDUMP_STREAM_INFO StreamInfo,
  573. IN PINTERNAL_PROCESS Process
  574. )
  575. {
  576. HRESULT Status;
  577. MINIDUMP_MODULE DumpModule;
  578. ULONG StringRva;
  579. ULONG CvRecordRva;
  580. ULONG MiscRecordRva;
  581. PLIST_ENTRY Entry;
  582. PINTERNAL_MODULE Module;
  583. ULONG32 NumberOfModules;
  584. ASSERT (Process);
  585. ASSERT (StreamInfo);
  586. NumberOfModules = Process->NumberOfModulesToWrite;
  587. if ((Status = Dump->OutProv->
  588. Seek(FILE_BEGIN, StreamInfo->RvaForCurModule, NULL)) != S_OK ||
  589. (Status = Dump->OutProv->
  590. WriteAll(&NumberOfModules, sizeof(NumberOfModules))) != S_OK) {
  591. return Status;
  592. }
  593. StreamInfo->RvaForCurModule += sizeof (NumberOfModules);
  594. //
  595. // Iterate through the module list writing the module name, module entry
  596. // and module debug info to the dump file.
  597. //
  598. Entry = Process->ModuleList.Flink;
  599. while ( Entry != &Process->ModuleList ) {
  600. Module = CONTAINING_RECORD (Entry,
  601. INTERNAL_MODULE,
  602. ModulesLink);
  603. Entry = Entry->Flink;
  604. //
  605. // If we are not to write information for this module, just continue.
  606. //
  607. if (IsFlagClear (Module->WriteFlags, ModuleWriteModule)) {
  608. continue;
  609. }
  610. //
  611. // Write module name.
  612. //
  613. if ((Status = WriteStringToPool (Dump,
  614. StreamInfo,
  615. Module->SavePath,
  616. &StringRva)) != S_OK) {
  617. return Status;
  618. }
  619. //
  620. // Write CvRecord for a module into the OTHER region.
  621. //
  622. if ( IsFlagSet (Module->WriteFlags, ModuleWriteCvRecord) &&
  623. Module->CvRecord != NULL && Module->SizeOfCvRecord != 0 ) {
  624. if ((Status = WriteOther (Dump,
  625. StreamInfo,
  626. Module->CvRecord,
  627. Module->SizeOfCvRecord,
  628. &CvRecordRva)) != S_OK) {
  629. return Status;
  630. }
  631. } else {
  632. CvRecordRva = 0;
  633. }
  634. if ( IsFlagSet (Module->WriteFlags, ModuleWriteMiscRecord) &&
  635. Module->MiscRecord != NULL && Module->SizeOfMiscRecord != 0 ) {
  636. if ((Status = WriteOther (Dump,
  637. StreamInfo,
  638. Module->MiscRecord,
  639. Module->SizeOfMiscRecord,
  640. &MiscRecordRva)) != S_OK) {
  641. return Status;
  642. }
  643. } else {
  644. MiscRecordRva = 0;
  645. }
  646. DumpModule.BaseOfImage = Module->BaseOfImage;
  647. DumpModule.SizeOfImage = Module->SizeOfImage;
  648. DumpModule.CheckSum = Module->CheckSum;
  649. DumpModule.TimeDateStamp = Module->TimeDateStamp;
  650. DumpModule.VersionInfo = Module->VersionInfo;
  651. DumpModule.CvRecord.Rva = CvRecordRva;
  652. DumpModule.CvRecord.DataSize = Module->SizeOfCvRecord;
  653. DumpModule.MiscRecord.Rva = MiscRecordRva;
  654. DumpModule.MiscRecord.DataSize = Module->SizeOfMiscRecord;
  655. DumpModule.ModuleNameRva = StringRva;
  656. DumpModule.Reserved0 = 0;
  657. DumpModule.Reserved1 = 0;
  658. //
  659. // Write the module entry itself.
  660. //
  661. if ((Status = WriteModule (Dump,
  662. StreamInfo,
  663. &DumpModule,
  664. NULL)) != S_OK) {
  665. return Status;
  666. }
  667. }
  668. return S_OK;
  669. }
  670. HRESULT
  671. WriteUnloadedModuleList(
  672. IN PMINIDUMP_STATE Dump,
  673. IN PMINIDUMP_STREAM_INFO StreamInfo,
  674. IN PINTERNAL_PROCESS Process
  675. )
  676. {
  677. HRESULT Status;
  678. MINIDUMP_UNLOADED_MODULE_LIST DumpModuleList;
  679. MINIDUMP_UNLOADED_MODULE DumpModule;
  680. ULONG StringRva;
  681. PLIST_ENTRY Entry;
  682. PINTERNAL_UNLOADED_MODULE Module;
  683. ULONG32 NumberOfModules;
  684. ASSERT (Process);
  685. ASSERT (StreamInfo);
  686. if (IsListEmpty(&Process->UnloadedModuleList)) {
  687. // Nothing to write.
  688. return S_OK;
  689. }
  690. NumberOfModules = Process->NumberOfUnloadedModules;
  691. if ((Status = Dump->OutProv->
  692. Seek(FILE_BEGIN, StreamInfo->RvaForCurUnloadedModule,
  693. NULL)) != S_OK) {
  694. return Status;
  695. }
  696. DumpModuleList.SizeOfHeader = sizeof(DumpModuleList);
  697. DumpModuleList.SizeOfEntry = sizeof(DumpModule);
  698. DumpModuleList.NumberOfEntries = NumberOfModules;
  699. if ((Status = Dump->OutProv->
  700. WriteAll(&DumpModuleList, sizeof(DumpModuleList))) != S_OK) {
  701. return Status;
  702. }
  703. StreamInfo->RvaForCurUnloadedModule += sizeof (DumpModuleList);
  704. //
  705. // Iterate through the module list writing the module name, module entry
  706. // and module debug info to the dump file.
  707. //
  708. Entry = Process->UnloadedModuleList.Flink;
  709. while ( Entry != &Process->UnloadedModuleList ) {
  710. Module = CONTAINING_RECORD (Entry,
  711. INTERNAL_UNLOADED_MODULE,
  712. ModulesLink);
  713. Entry = Entry->Flink;
  714. //
  715. // Write module name.
  716. //
  717. if ((Status = WriteStringToPool (Dump,
  718. StreamInfo,
  719. Module->Path,
  720. &StringRva)) != S_OK) {
  721. return Status;
  722. }
  723. DumpModule.BaseOfImage = Module->BaseOfImage;
  724. DumpModule.SizeOfImage = Module->SizeOfImage;
  725. DumpModule.CheckSum = Module->CheckSum;
  726. DumpModule.TimeDateStamp = Module->TimeDateStamp;
  727. DumpModule.ModuleNameRva = StringRva;
  728. //
  729. // Write the module entry itself.
  730. //
  731. if ((Status = WriteUnloadedModule(Dump,
  732. StreamInfo,
  733. &DumpModule,
  734. NULL)) != S_OK) {
  735. return Status;
  736. }
  737. }
  738. return S_OK;
  739. }
  740. #define FUNCTION_TABLE_ALIGNMENT 8
  741. HRESULT
  742. WriteFunctionTableList(
  743. IN PMINIDUMP_STATE Dump,
  744. IN PMINIDUMP_STREAM_INFO StreamInfo,
  745. IN PINTERNAL_PROCESS Process
  746. )
  747. {
  748. HRESULT Status;
  749. MINIDUMP_FUNCTION_TABLE_STREAM TableStream;
  750. MINIDUMP_FUNCTION_TABLE_DESCRIPTOR DumpTable;
  751. PLIST_ENTRY Entry;
  752. PINTERNAL_FUNCTION_TABLE Table;
  753. RVA PrevRva, Rva;
  754. ASSERT (Process);
  755. ASSERT (StreamInfo);
  756. if (IsListEmpty(&Process->FunctionTableList)) {
  757. // Nothing to write.
  758. return S_OK;
  759. }
  760. Rva = StreamInfo->RvaOfFunctionTableList;
  761. if ((Status = Dump->OutProv->
  762. Seek(FILE_BEGIN, Rva, NULL)) != S_OK) {
  763. return Status;
  764. }
  765. TableStream.SizeOfHeader = sizeof(TableStream);
  766. TableStream.SizeOfDescriptor = sizeof(DumpTable);
  767. TableStream.SizeOfNativeDescriptor = Dump->FuncTableSize;
  768. TableStream.SizeOfFunctionEntry = Dump->FuncTableEntrySize;
  769. TableStream.NumberOfDescriptors = Process->NumberOfFunctionTables;
  770. // Ensure that the actual descriptors are 8-byte aligned in
  771. // the overall file.
  772. Rva += sizeof(TableStream);
  773. PrevRva = Rva;
  774. Rva = (Rva + FUNCTION_TABLE_ALIGNMENT - 1) &
  775. ~(FUNCTION_TABLE_ALIGNMENT - 1);
  776. TableStream.SizeOfAlignPad = Rva - PrevRva;
  777. if ((Status = Dump->OutProv->
  778. WriteAll(&TableStream, sizeof(TableStream))) != S_OK) {
  779. return Status;
  780. }
  781. //
  782. // Iterate through the function table list
  783. // and write out the table data.
  784. //
  785. Entry = Process->FunctionTableList.Flink;
  786. while ( Entry != &Process->FunctionTableList ) {
  787. Table = CONTAINING_RECORD (Entry,
  788. INTERNAL_FUNCTION_TABLE,
  789. TableLink);
  790. Entry = Entry->Flink;
  791. // Move to aligned RVA.
  792. if ((Status = Dump->OutProv->
  793. Seek(FILE_BEGIN, Rva, NULL)) != S_OK) {
  794. return Status;
  795. }
  796. DumpTable.MinimumAddress = Table->MinimumAddress;
  797. DumpTable.MaximumAddress = Table->MaximumAddress;
  798. DumpTable.BaseAddress = Table->BaseAddress;
  799. DumpTable.EntryCount = Table->EntryCount;
  800. Rva += sizeof(DumpTable) + Dump->FuncTableSize +
  801. Dump->FuncTableEntrySize * Table->EntryCount;
  802. PrevRva = Rva;
  803. Rva = (Rva + FUNCTION_TABLE_ALIGNMENT - 1) &
  804. ~(FUNCTION_TABLE_ALIGNMENT - 1);
  805. DumpTable.SizeOfAlignPad = Rva - PrevRva;
  806. if ((Status = Dump->OutProv->
  807. WriteAll(&DumpTable, sizeof(DumpTable))) != S_OK ||
  808. (Status = Dump->OutProv->
  809. WriteAll(Table->RawTable, Dump->FuncTableSize)) != S_OK ||
  810. (Status = Dump->OutProv->
  811. WriteAll(Table->RawEntries,
  812. Dump->FuncTableEntrySize * Table->EntryCount)) != S_OK) {
  813. return Status;
  814. }
  815. }
  816. return S_OK;
  817. }
  818. HRESULT
  819. WriteMemoryBlocks(
  820. IN PMINIDUMP_STATE Dump,
  821. IN PMINIDUMP_STREAM_INFO StreamInfo,
  822. IN PINTERNAL_PROCESS Process
  823. )
  824. {
  825. HRESULT Status;
  826. PLIST_ENTRY ScanEntry;
  827. PVA_RANGE Scan;
  828. ScanEntry = Process->MemoryBlocks.Flink;
  829. while (ScanEntry != &Process->MemoryBlocks) {
  830. Scan = CONTAINING_RECORD(ScanEntry, VA_RANGE, NextLink);
  831. ScanEntry = Scan->NextLink.Flink;
  832. if ((Status =
  833. WriteMemoryFromProcess(Dump,
  834. StreamInfo,
  835. Process,
  836. Scan->Start,
  837. Scan->Size,
  838. FALSE,
  839. Scan->Type,
  840. NULL)) != S_OK) {
  841. return Status;
  842. }
  843. }
  844. return S_OK;
  845. }
  846. HRESULT
  847. CalculateSizeForThreads(
  848. IN PMINIDUMP_STATE Dump,
  849. IN PINTERNAL_PROCESS Process,
  850. IN OUT MINIDUMP_STREAM_INFO * StreamInfo
  851. )
  852. {
  853. ULONG SizeOfContexts;
  854. ULONG SizeOfMemRegions;
  855. ULONG SizeOfThreads;
  856. ULONG SizeOfMemoryDescriptors;
  857. ULONG NumberOfThreads;
  858. ULONG NumberOfMemRegions;
  859. PINTERNAL_THREAD Thread;
  860. PLIST_ENTRY Entry;
  861. ASSERT (Process);
  862. ASSERT (StreamInfo);
  863. NumberOfThreads = 0;
  864. NumberOfMemRegions = 0;
  865. SizeOfContexts = 0;
  866. SizeOfMemRegions = 0;
  867. // If no backing store information is written a normal
  868. // MINIDUMP_THREAD can be used, otherwise a MINIDUMP_THREAD_EX
  869. // is required.
  870. StreamInfo->ThreadStructSize = sizeof(MINIDUMP_THREAD);
  871. Entry = Process->ThreadList.Flink;
  872. while ( Entry != &Process->ThreadList ) {
  873. Thread = CONTAINING_RECORD (Entry,
  874. INTERNAL_THREAD,
  875. ThreadsLink);
  876. Entry = Entry->Flink;
  877. //
  878. // Do we need to write any information for this thread at all?
  879. //
  880. if (IsFlagClear (Thread->WriteFlags, ThreadWriteThread)) {
  881. continue;
  882. }
  883. NumberOfThreads++;
  884. //
  885. // Write a context for this thread?
  886. //
  887. if (IsFlagSet (Thread->WriteFlags, ThreadWriteContext)) {
  888. SizeOfContexts += Dump->ContextSize;
  889. }
  890. //
  891. // Write a stack for this thread?
  892. //
  893. if (IsFlagSet (Thread->WriteFlags, ThreadWriteStack)) {
  894. NumberOfMemRegions++;
  895. SizeOfMemRegions += (ULONG) (Thread->StackBase - Thread->StackEnd);
  896. }
  897. //
  898. // Write the backing store for this thread?
  899. //
  900. if (IsFlagSet (Thread->WriteFlags, ThreadWriteBackingStore)) {
  901. // A newly created thread's backing store may be empty
  902. // so handle the case of zero size.
  903. if (Thread->BackingStoreSize) {
  904. NumberOfMemRegions++;
  905. SizeOfMemRegions += Thread->BackingStoreSize;
  906. }
  907. // We still need a THREAD_EX as this is a platform
  908. // which supports backing store.
  909. StreamInfo->ThreadStructSize = sizeof(MINIDUMP_THREAD_EX);
  910. }
  911. // Write an instruction window for this thread?
  912. if (IsFlagSet (Thread->WriteFlags, ThreadWriteInstructionWindow)) {
  913. GenGetThreadInstructionWindow(Dump, Process, Thread);
  914. }
  915. // Write thread data for this thread?
  916. if (IsFlagSet (Thread->WriteFlags, ThreadWriteThreadData) &&
  917. Thread->SizeOfTeb) {
  918. GenAddTebMemory(Dump, Process, Thread);
  919. }
  920. }
  921. Process->NumberOfThreadsToWrite = NumberOfThreads;
  922. //
  923. // Nobody should have allocated memory from the thread list region yet.
  924. //
  925. ASSERT (StreamInfo->SizeOfThreadList == 0);
  926. SizeOfThreads = NumberOfThreads * StreamInfo->ThreadStructSize;
  927. SizeOfMemoryDescriptors = NumberOfMemRegions *
  928. sizeof (MINIDUMP_MEMORY_DESCRIPTOR);
  929. StreamInfo->SizeOfThreadList += sizeof (ULONG32);
  930. StreamInfo->SizeOfThreadList += SizeOfThreads;
  931. StreamInfo->SizeOfOther += SizeOfContexts;
  932. StreamInfo->SizeOfMemoryData += SizeOfMemRegions;
  933. StreamInfo->SizeOfMemoryDescriptors += SizeOfMemoryDescriptors;
  934. return S_OK;
  935. }
  936. HRESULT
  937. CalculateSizeForModules(
  938. IN PMINIDUMP_STATE Dump,
  939. IN PINTERNAL_PROCESS Process,
  940. IN OUT MINIDUMP_STREAM_INFO * StreamInfo
  941. )
  942. /*++
  943. Routine Description:
  944. Calculate amount of space needed in the string pool, the memory table and
  945. the module list table for module information.
  946. Arguments:
  947. Process - Minidump process information.
  948. StreamInfo - The stream size information for this dump.
  949. --*/
  950. {
  951. ULONG NumberOfModules;
  952. ULONG SizeOfDebugInfo;
  953. ULONG SizeOfStringData;
  954. PINTERNAL_MODULE Module;
  955. PLIST_ENTRY Entry;
  956. ASSERT (Process);
  957. ASSERT (StreamInfo);
  958. NumberOfModules = 0;
  959. SizeOfDebugInfo = 0;
  960. SizeOfStringData = 0;
  961. Entry = Process->ModuleList.Flink;
  962. while ( Entry != &Process->ModuleList ) {
  963. Module = CONTAINING_RECORD (Entry, INTERNAL_MODULE, ModulesLink);
  964. Entry = Entry->Flink;
  965. if (IsFlagClear (Module->WriteFlags, ModuleWriteModule)) {
  966. continue;
  967. }
  968. NumberOfModules++;
  969. SizeOfStringData += (GenStrLengthW(Module->SavePath) + 1) * sizeof(WCHAR);
  970. SizeOfStringData += sizeof ( MINIDUMP_STRING );
  971. //
  972. // Add in the sizes of both the CV and MISC records.
  973. //
  974. if (IsFlagSet (Module->WriteFlags, ModuleWriteCvRecord)) {
  975. SizeOfDebugInfo += Module->SizeOfCvRecord;
  976. }
  977. if (IsFlagSet (Module->WriteFlags, ModuleWriteMiscRecord)) {
  978. SizeOfDebugInfo += Module->SizeOfMiscRecord;
  979. }
  980. //
  981. // Add the module data sections if requested.
  982. //
  983. if (IsFlagSet (Module->WriteFlags, ModuleWriteDataSeg)) {
  984. GenGetDataContributors(Dump, Process, Module);
  985. }
  986. }
  987. Process->NumberOfModulesToWrite = NumberOfModules;
  988. ASSERT (StreamInfo->SizeOfModuleList == 0);
  989. StreamInfo->SizeOfModuleList += sizeof (MINIDUMP_MODULE_LIST);
  990. StreamInfo->SizeOfModuleList += (NumberOfModules * sizeof (MINIDUMP_MODULE));
  991. StreamInfo->SizeOfStringPool += SizeOfStringData;
  992. StreamInfo->SizeOfOther += SizeOfDebugInfo;
  993. return S_OK;
  994. }
  995. HRESULT
  996. CalculateSizeForUnloadedModules(
  997. IN PINTERNAL_PROCESS Process,
  998. IN OUT MINIDUMP_STREAM_INFO * StreamInfo
  999. )
  1000. {
  1001. ULONG SizeOfStringData;
  1002. PINTERNAL_UNLOADED_MODULE Module;
  1003. PLIST_ENTRY Entry;
  1004. ASSERT (Process);
  1005. ASSERT (StreamInfo);
  1006. SizeOfStringData = 0;
  1007. Entry = Process->UnloadedModuleList.Flink;
  1008. while ( Entry != &Process->UnloadedModuleList ) {
  1009. Module = CONTAINING_RECORD (Entry, INTERNAL_UNLOADED_MODULE,
  1010. ModulesLink);
  1011. Entry = Entry->Flink;
  1012. SizeOfStringData += (GenStrLengthW(Module->Path) + 1) * sizeof(WCHAR);
  1013. SizeOfStringData += sizeof ( MINIDUMP_STRING );
  1014. }
  1015. ASSERT (StreamInfo->SizeOfUnloadedModuleList == 0);
  1016. StreamInfo->SizeOfUnloadedModuleList +=
  1017. sizeof (MINIDUMP_UNLOADED_MODULE_LIST);
  1018. StreamInfo->SizeOfUnloadedModuleList +=
  1019. (Process->NumberOfUnloadedModules * sizeof (MINIDUMP_UNLOADED_MODULE));
  1020. StreamInfo->SizeOfStringPool += SizeOfStringData;
  1021. return S_OK;
  1022. }
  1023. HRESULT
  1024. CalculateSizeForFunctionTables(
  1025. IN PMINIDUMP_STATE Dump,
  1026. IN PINTERNAL_PROCESS Process,
  1027. IN OUT MINIDUMP_STREAM_INFO * StreamInfo
  1028. )
  1029. {
  1030. ULONG SizeOfTableData;
  1031. PINTERNAL_FUNCTION_TABLE Table;
  1032. PLIST_ENTRY Entry;
  1033. ASSERT (Process);
  1034. ASSERT (StreamInfo);
  1035. SizeOfTableData = 0;
  1036. Entry = Process->FunctionTableList.Flink;
  1037. while ( Entry != &Process->FunctionTableList ) {
  1038. Table = CONTAINING_RECORD (Entry, INTERNAL_FUNCTION_TABLE, TableLink);
  1039. Entry = Entry->Flink;
  1040. // Alignment space is required as the structures
  1041. // in the stream must be properly aligned.
  1042. SizeOfTableData += FUNCTION_TABLE_ALIGNMENT +
  1043. sizeof(MINIDUMP_FUNCTION_TABLE_DESCRIPTOR) +
  1044. Dump->FuncTableSize +
  1045. Table->EntryCount * Dump->FuncTableEntrySize;
  1046. }
  1047. ASSERT (StreamInfo->SizeOfFunctionTableList == 0);
  1048. StreamInfo->SizeOfFunctionTableList +=
  1049. sizeof (MINIDUMP_FUNCTION_TABLE_STREAM) + SizeOfTableData;
  1050. return S_OK;
  1051. }
  1052. HRESULT
  1053. WriteDirectoryEntry(
  1054. IN PMINIDUMP_STATE Dump,
  1055. IN ULONG StreamType,
  1056. IN ULONG RvaOfDir,
  1057. IN SIZE_T SizeOfDir
  1058. )
  1059. {
  1060. MINIDUMP_DIRECTORY Dir;
  1061. //
  1062. // Do not write empty streams.
  1063. //
  1064. if (SizeOfDir == 0) {
  1065. return S_OK;
  1066. }
  1067. //
  1068. // The maximum size of a directory is a ULONG.
  1069. //
  1070. if (SizeOfDir > _UI32_MAX) {
  1071. return E_INVALIDARG;
  1072. }
  1073. Dir.StreamType = StreamType;
  1074. Dir.Location.Rva = RvaOfDir;
  1075. Dir.Location.DataSize = (ULONG) SizeOfDir;
  1076. return Dump->OutProv->
  1077. WriteAll(&Dir, sizeof(Dir));
  1078. }
  1079. VOID
  1080. ScanContextForModuleRefs(
  1081. IN PMINIDUMP_STATE Dump,
  1082. IN PINTERNAL_PROCESS Process,
  1083. IN PINTERNAL_THREAD Thread
  1084. )
  1085. {
  1086. ULONG NumReg;
  1087. PUCHAR Reg;
  1088. PINTERNAL_MODULE Module;
  1089. Reg = (PUCHAR)Thread->ContextBuffer + Dump->RegScanOffset;
  1090. NumReg = Dump->RegScanCount;
  1091. while (NumReg-- > 0) {
  1092. ULONG64 CurPtr;
  1093. CurPtr = GenGetPointer(Dump, Reg);
  1094. Reg += Dump->PtrSize;
  1095. if (Module = ModuleContainingAddress(Process, CurPtr)) {
  1096. Module->WriteFlags |= ModuleReferencedByMemory;
  1097. }
  1098. }
  1099. }
  1100. HRESULT
  1101. FilterOrScanMemory(
  1102. IN PMINIDUMP_STATE Dump,
  1103. IN PINTERNAL_PROCESS Process,
  1104. IN PVOID MemBuffer
  1105. )
  1106. {
  1107. PINTERNAL_THREAD Thread;
  1108. PLIST_ENTRY ThreadEntry;
  1109. //
  1110. // Scan the stack and backing store
  1111. // memory for every thread.
  1112. //
  1113. ThreadEntry = Process->ThreadList.Flink;
  1114. while ( ThreadEntry != &Process->ThreadList ) {
  1115. Thread = CONTAINING_RECORD (ThreadEntry, INTERNAL_THREAD, ThreadsLink);
  1116. ThreadEntry = ThreadEntry->Flink;
  1117. ScanContextForModuleRefs(Dump, Process, Thread);
  1118. ScanMemoryForModuleRefs(Dump, Process, TRUE,
  1119. Thread->StackEnd,
  1120. (ULONG)(Thread->StackBase - Thread->StackEnd),
  1121. MemBuffer, MEMBLOCK_STACK, FALSE);
  1122. ScanMemoryForModuleRefs(Dump, Process, TRUE,
  1123. Thread->BackingStoreBase,
  1124. Thread->BackingStoreSize,
  1125. MemBuffer, MEMBLOCK_STORE, FALSE);
  1126. }
  1127. return S_OK;
  1128. }
  1129. #define IND_CAPTURE_SIZE (Dump->PageSize / 4)
  1130. #define PRE_IND_CAPTURE_SIZE (IND_CAPTURE_SIZE / 4)
  1131. HRESULT
  1132. AddIndirectMemory(
  1133. IN PMINIDUMP_STATE Dump,
  1134. IN PINTERNAL_PROCESS Process,
  1135. IN ULONG64 Base,
  1136. IN ULONG Size,
  1137. IN PVOID MemBuffer
  1138. )
  1139. {
  1140. HRESULT Status = S_OK;
  1141. PVOID CurMem;
  1142. ULONG Done;
  1143. // If the base address is not pointer-size aligned
  1144. // we can't easily assume that this is a meaningful
  1145. // area of memory to scan for references. Normal
  1146. // stack and store addresses will always be pointer
  1147. // size aligned so this should only reject invalid
  1148. // addresses.
  1149. if (!Base || !Size || (Base & (Dump->PtrSize - 1))) {
  1150. return S_OK;
  1151. }
  1152. if ((Status = Dump->SysProv->
  1153. ReadVirtual(Dump->ProcessHandle,
  1154. Base, MemBuffer, Size, &Done)) != S_OK) {
  1155. return Status;
  1156. }
  1157. CurMem = MemBuffer;
  1158. Done /= Dump->PtrSize;
  1159. while (Done-- > 0) {
  1160. ULONG64 Start;
  1161. HRESULT OneStatus;
  1162. //
  1163. // How much memory to save behind the pointer is an
  1164. // interesting question. The reference could be to
  1165. // an arbitrary amount of data, so we want to save
  1166. // a good chunk, but we don't want to end up saving
  1167. // full memory.
  1168. // Instead, pick an arbitrary size -- 1/4 of a page --
  1169. // and save some before and after the pointer.
  1170. //
  1171. Start = GenGetPointer(Dump, CurMem);
  1172. // If it's a pointer into an image assume doesn't
  1173. // need to be stored via this mechanism as it's either
  1174. // code, which will be mapped later; or data, which can
  1175. // be saved with MiniDumpWithDataSegs.
  1176. if (!ModuleContainingAddress(Process, Start)) {
  1177. if (Start < PRE_IND_CAPTURE_SIZE) {
  1178. Start = 0;
  1179. } else {
  1180. Start -= PRE_IND_CAPTURE_SIZE;
  1181. }
  1182. if ((OneStatus =
  1183. GenAddMemoryBlock(Dump, Process, MEMBLOCK_INDIRECT,
  1184. Start, IND_CAPTURE_SIZE)) != S_OK) {
  1185. Status = OneStatus;
  1186. }
  1187. }
  1188. CurMem = (PUCHAR)CurMem + Dump->PtrSize;
  1189. }
  1190. return Status;
  1191. }
  1192. HRESULT
  1193. AddIndirectlyReferencedMemory(
  1194. IN PMINIDUMP_STATE Dump,
  1195. IN PINTERNAL_PROCESS Process,
  1196. IN PVOID MemBuffer
  1197. )
  1198. {
  1199. HRESULT Status;
  1200. PINTERNAL_THREAD Thread;
  1201. PLIST_ENTRY ThreadEntry;
  1202. //
  1203. // Scan the stack and backing store
  1204. // memory for every thread.
  1205. //
  1206. ThreadEntry = Process->ThreadList.Flink;
  1207. while ( ThreadEntry != &Process->ThreadList ) {
  1208. Thread = CONTAINING_RECORD (ThreadEntry, INTERNAL_THREAD, ThreadsLink);
  1209. ThreadEntry = ThreadEntry->Flink;
  1210. if ((Status =
  1211. AddIndirectMemory(Dump,
  1212. Process,
  1213. Thread->StackEnd,
  1214. (ULONG)(Thread->StackBase - Thread->StackEnd),
  1215. MemBuffer)) != S_OK) {
  1216. return Status;
  1217. }
  1218. if ((Status =
  1219. AddIndirectMemory(Dump,
  1220. Process,
  1221. Thread->BackingStoreBase,
  1222. Thread->BackingStoreSize,
  1223. MemBuffer)) != S_OK) {
  1224. return Status;
  1225. }
  1226. }
  1227. return S_OK;
  1228. }
  1229. HRESULT
  1230. PostProcessInfo(
  1231. IN PMINIDUMP_STATE Dump,
  1232. IN PINTERNAL_PROCESS Process
  1233. )
  1234. {
  1235. PVOID MemBuffer;
  1236. HRESULT Status = S_OK;
  1237. MemBuffer = AllocMemory(Dump, Process->MaxStackOrStoreSize);
  1238. if (!MemBuffer) {
  1239. return E_OUTOFMEMORY;
  1240. }
  1241. if (Dump->DumpType & (MiniDumpFilterMemory | MiniDumpScanMemory)) {
  1242. Status = FilterOrScanMemory(Dump, Process, MemBuffer);
  1243. }
  1244. if (Status == S_OK &&
  1245. (Dump->DumpType & MiniDumpWithIndirectlyReferencedMemory)) {
  1246. // Indirect memory is not crucial to the dump so
  1247. // ignore any failures.
  1248. AddIndirectlyReferencedMemory(Dump, Process, MemBuffer);
  1249. }
  1250. FreeMemory(Dump, MemBuffer);
  1251. return Status;
  1252. }
  1253. HRESULT
  1254. ExecuteCallbacks(
  1255. IN PMINIDUMP_STATE Dump,
  1256. IN PINTERNAL_PROCESS Process
  1257. )
  1258. {
  1259. PINTERNAL_MODULE Module;
  1260. PINTERNAL_THREAD Thread;
  1261. PLIST_ENTRY Entry;
  1262. MINIDUMP_CALLBACK_INPUT CallbackInput;
  1263. MINIDUMP_CALLBACK_OUTPUT CallbackOutput;
  1264. ASSERT ( Process != NULL );
  1265. Thread = NULL;
  1266. Module = NULL;
  1267. //
  1268. // If there are no callbacks to call, then we are done.
  1269. //
  1270. if ( Dump->CallbackRoutine == NULL ) {
  1271. return S_OK;
  1272. }
  1273. CallbackInput.ProcessHandle = Dump->ProcessHandle;
  1274. CallbackInput.ProcessId = Dump->ProcessId;
  1275. //
  1276. // Call callbacks for each module.
  1277. //
  1278. CallbackInput.CallbackType = ModuleCallback;
  1279. Entry = Process->ModuleList.Flink;
  1280. while ( Entry != &Process->ModuleList ) {
  1281. Module = CONTAINING_RECORD (Entry, INTERNAL_MODULE, ModulesLink);
  1282. Entry = Entry->Flink;
  1283. CallbackInput.Module.FullPath = Module->FullPath;
  1284. CallbackInput.Module.BaseOfImage = Module->BaseOfImage;
  1285. CallbackInput.Module.SizeOfImage = Module->SizeOfImage;
  1286. CallbackInput.Module.CheckSum = Module->CheckSum;
  1287. CallbackInput.Module.TimeDateStamp = Module->TimeDateStamp;
  1288. CopyMemory (&CallbackInput.Module.VersionInfo,
  1289. &Module->VersionInfo,
  1290. sizeof (CallbackInput.Module.VersionInfo)
  1291. );
  1292. CallbackInput.Module.CvRecord = Module->CvRecord;
  1293. CallbackInput.Module.SizeOfCvRecord = Module->SizeOfCvRecord;
  1294. CallbackInput.Module.MiscRecord = Module->MiscRecord;
  1295. CallbackInput.Module.SizeOfMiscRecord = Module->SizeOfMiscRecord;
  1296. CallbackOutput.ModuleWriteFlags = Module->WriteFlags;
  1297. if (!Dump->CallbackRoutine (Dump->CallbackParam,
  1298. &CallbackInput,
  1299. &CallbackOutput)) {
  1300. // If the callback returned FALSE, quit now.
  1301. return E_ABORT;
  1302. }
  1303. // Don't turn on any flags that weren't originally set.
  1304. Module->WriteFlags &= CallbackOutput.ModuleWriteFlags;
  1305. }
  1306. Module = NULL;
  1307. //
  1308. // Call callbacks for each thread.
  1309. //
  1310. if (Dump->BackingStore) {
  1311. CallbackInput.CallbackType = ThreadExCallback;
  1312. } else {
  1313. CallbackInput.CallbackType = ThreadCallback;
  1314. }
  1315. Entry = Process->ThreadList.Flink;
  1316. while ( Entry != &Process->ThreadList ) {
  1317. Thread = CONTAINING_RECORD (Entry, INTERNAL_THREAD, ThreadsLink);
  1318. Entry = Entry->Flink;
  1319. CallbackInput.ThreadEx.ThreadId = Thread->ThreadId;
  1320. CallbackInput.ThreadEx.ThreadHandle = Thread->ThreadHandle;
  1321. CallbackInput.ThreadEx.Context = *(PCONTEXT)Thread->ContextBuffer;
  1322. CallbackInput.ThreadEx.SizeOfContext = Dump->ContextSize;
  1323. CallbackInput.ThreadEx.StackBase = Thread->StackBase;
  1324. CallbackInput.ThreadEx.StackEnd = Thread->StackEnd;
  1325. CallbackInput.ThreadEx.BackingStoreBase = Thread->BackingStoreBase;
  1326. CallbackInput.ThreadEx.BackingStoreEnd =
  1327. Thread->BackingStoreBase + Thread->BackingStoreSize;
  1328. CallbackOutput.ThreadWriteFlags = Thread->WriteFlags;
  1329. if (!Dump->CallbackRoutine (Dump->CallbackParam,
  1330. &CallbackInput,
  1331. &CallbackOutput)) {
  1332. // If the callback returned FALSE, quit now.
  1333. return E_ABORT;
  1334. }
  1335. // Don't turn on any flags that weren't originally set.
  1336. Thread->WriteFlags &= CallbackOutput.ThreadWriteFlags;
  1337. }
  1338. Thread = NULL;
  1339. //
  1340. // Call callbacks to include memory.
  1341. //
  1342. CallbackInput.CallbackType = MemoryCallback;
  1343. for (;;) {
  1344. CallbackOutput.MemoryBase = 0;
  1345. CallbackOutput.MemorySize = 0;
  1346. if (!Dump->CallbackRoutine (Dump->CallbackParam,
  1347. &CallbackInput,
  1348. &CallbackOutput) ||
  1349. !CallbackOutput.MemorySize) {
  1350. // If the callback returned FALSE there is no more memory.
  1351. break;
  1352. }
  1353. GenAddMemoryBlock(Dump, Process, MEMBLOCK_MEM_CALLBACK,
  1354. CallbackOutput.MemoryBase,
  1355. CallbackOutput.MemorySize);
  1356. }
  1357. return S_OK;
  1358. }
  1359. HRESULT
  1360. WriteSystemInfo(
  1361. IN PMINIDUMP_STATE Dump,
  1362. IN PMINIDUMP_STREAM_INFO StreamInfo
  1363. )
  1364. {
  1365. HRESULT Status;
  1366. MINIDUMP_SYSTEM_INFO SystemInfo;
  1367. WCHAR CSDVersionW [128];
  1368. RVA StringRva;
  1369. ULONG Length;
  1370. StringRva = 0;
  1371. //
  1372. // First, get the CPU information.
  1373. //
  1374. if ((Status = Dump->SysProv->
  1375. GetCpuInfo(&SystemInfo.ProcessorArchitecture,
  1376. &SystemInfo.ProcessorLevel,
  1377. &SystemInfo.ProcessorRevision,
  1378. &SystemInfo.NumberOfProcessors,
  1379. &SystemInfo.Cpu)) != S_OK) {
  1380. return Status;
  1381. }
  1382. //
  1383. // Next get OS Information.
  1384. //
  1385. SystemInfo.ProductType = (UCHAR)Dump->OsProductType;
  1386. SystemInfo.MajorVersion = Dump->OsMajor;
  1387. SystemInfo.MinorVersion = Dump->OsMinor;
  1388. SystemInfo.BuildNumber = Dump->OsBuildNumber;
  1389. SystemInfo.PlatformId = Dump->OsPlatformId;
  1390. SystemInfo.SuiteMask = Dump->OsSuiteMask;
  1391. SystemInfo.Reserved2 = 0;
  1392. if ((Status = Dump->SysProv->
  1393. GetOsCsdString(CSDVersionW, ARRAY_COUNT(CSDVersionW))) != S_OK) {
  1394. return Status;
  1395. }
  1396. Length = (GenStrLengthW(CSDVersionW) + 1) * sizeof(WCHAR);
  1397. if ( Length != StreamInfo->VersionStringLength ) {
  1398. //
  1399. // If this fails it means that since the OS lied to us about the
  1400. // size of the string. Very bad, we should investigate.
  1401. //
  1402. ASSERT ( FALSE );
  1403. return E_INVALIDARG;
  1404. }
  1405. if ((Status = WriteStringToPool (Dump,
  1406. StreamInfo,
  1407. CSDVersionW,
  1408. &StringRva)) != S_OK) {
  1409. return Status;
  1410. }
  1411. SystemInfo.CSDVersionRva = StringRva;
  1412. ASSERT ( sizeof (SystemInfo) == StreamInfo->SizeOfSystemInfo );
  1413. return WriteAtOffset (Dump,
  1414. StreamInfo->RvaOfSystemInfo,
  1415. &SystemInfo,
  1416. sizeof (SystemInfo));
  1417. }
  1418. HRESULT
  1419. CalculateSizeForSystemInfo(
  1420. IN PMINIDUMP_STATE Dump,
  1421. IN OUT MINIDUMP_STREAM_INFO * StreamInfo
  1422. )
  1423. {
  1424. HRESULT Status;
  1425. WCHAR CSDVersionW [128];
  1426. ULONG Length;
  1427. if ((Status = Dump->SysProv->
  1428. GetOsCsdString(CSDVersionW, ARRAY_COUNT(CSDVersionW))) != S_OK) {
  1429. return Status;
  1430. }
  1431. Length = (GenStrLengthW(CSDVersionW) + 1) * sizeof(WCHAR);
  1432. StreamInfo->SizeOfSystemInfo = sizeof (MINIDUMP_SYSTEM_INFO);
  1433. StreamInfo->SizeOfStringPool += Length;
  1434. StreamInfo->SizeOfStringPool += sizeof (MINIDUMP_STRING);
  1435. StreamInfo->VersionStringLength = Length;
  1436. return S_OK;
  1437. }
  1438. HRESULT
  1439. WriteMiscInfo(
  1440. IN PMINIDUMP_STATE Dump,
  1441. IN PMINIDUMP_STREAM_INFO StreamInfo,
  1442. IN PINTERNAL_PROCESS Process
  1443. )
  1444. {
  1445. MINIDUMP_MISC_INFO MiscInfo;
  1446. ZeroMemory(&MiscInfo, sizeof(MiscInfo));
  1447. MiscInfo.SizeOfInfo = sizeof(MiscInfo);
  1448. MiscInfo.Flags1 |= MINIDUMP_MISC1_PROCESS_ID;
  1449. MiscInfo.ProcessId = Process->ProcessId;
  1450. if (Process->TimesValid) {
  1451. MiscInfo.Flags1 |= MINIDUMP_MISC1_PROCESS_TIMES;
  1452. MiscInfo.ProcessCreateTime = Process->CreateTime;
  1453. MiscInfo.ProcessUserTime = Process->UserTime;
  1454. MiscInfo.ProcessKernelTime = Process->KernelTime;
  1455. }
  1456. return WriteAtOffset(Dump,
  1457. StreamInfo->RvaOfMiscInfo,
  1458. &MiscInfo,
  1459. sizeof(MiscInfo));
  1460. }
  1461. void
  1462. PostProcessMemoryBlocks(
  1463. IN PMINIDUMP_STATE Dump,
  1464. IN PINTERNAL_PROCESS Process
  1465. )
  1466. {
  1467. PINTERNAL_THREAD Thread;
  1468. PLIST_ENTRY ThreadEntry;
  1469. //
  1470. // Remove any overlap with thread stacks and backing stores.
  1471. //
  1472. ThreadEntry = Process->ThreadList.Flink;
  1473. while ( ThreadEntry != &Process->ThreadList ) {
  1474. Thread = CONTAINING_RECORD (ThreadEntry, INTERNAL_THREAD, ThreadsLink);
  1475. ThreadEntry = ThreadEntry->Flink;
  1476. GenRemoveMemoryRange(Dump, Process,
  1477. Thread->StackEnd,
  1478. (ULONG)(Thread->StackBase - Thread->StackEnd));
  1479. GenRemoveMemoryRange(Dump, Process,
  1480. Thread->BackingStoreBase,
  1481. Thread->BackingStoreSize);
  1482. }
  1483. }
  1484. HRESULT
  1485. CalculateStreamInfo(
  1486. IN PMINIDUMP_STATE Dump,
  1487. IN PINTERNAL_PROCESS Process,
  1488. OUT PMINIDUMP_STREAM_INFO StreamInfo,
  1489. IN BOOL ExceptionPresent,
  1490. IN PMINIDUMP_USER_STREAM UserStreamArray,
  1491. IN ULONG UserStreamCount
  1492. )
  1493. {
  1494. ULONG i;
  1495. HRESULT Status;
  1496. ULONG NumberOfStreams;
  1497. ULONG SizeOfDirectory;
  1498. ULONG SizeOfUserStreams;
  1499. ASSERT ( Process != NULL );
  1500. ASSERT ( StreamInfo != NULL );
  1501. ZeroMemory (StreamInfo, sizeof (*StreamInfo));
  1502. if ( ExceptionPresent ) {
  1503. NumberOfStreams = NUMBER_OF_STREAMS + UserStreamCount;
  1504. } else {
  1505. NumberOfStreams = NUMBER_OF_STREAMS + UserStreamCount - 1;
  1506. }
  1507. if (Dump->DumpType & MiniDumpWithHandleData) {
  1508. NumberOfStreams++;
  1509. }
  1510. if (!IsListEmpty(&Process->UnloadedModuleList)) {
  1511. NumberOfStreams++;
  1512. }
  1513. // Add a stream for dynamic function tables if some were found.
  1514. if (!IsListEmpty(&Process->FunctionTableList)) {
  1515. NumberOfStreams++;
  1516. }
  1517. SizeOfDirectory = sizeof (MINIDUMP_DIRECTORY) * NumberOfStreams;
  1518. StreamInfo->NumberOfStreams = NumberOfStreams;
  1519. StreamInfo->RvaOfHeader = 0;
  1520. StreamInfo->SizeOfHeader = sizeof (MINIDUMP_HEADER);
  1521. StreamInfo->RvaOfDirectory =
  1522. StreamInfo->RvaOfHeader + StreamInfo->SizeOfHeader;
  1523. StreamInfo->SizeOfDirectory = SizeOfDirectory;
  1524. StreamInfo->RvaOfSystemInfo =
  1525. StreamInfo->RvaOfDirectory + StreamInfo->SizeOfDirectory;
  1526. if ((Status =
  1527. CalculateSizeForSystemInfo(Dump, StreamInfo)) != S_OK) {
  1528. return Status;
  1529. }
  1530. StreamInfo->RvaOfMiscInfo =
  1531. StreamInfo->RvaOfSystemInfo + StreamInfo->SizeOfSystemInfo;
  1532. StreamInfo->RvaOfException =
  1533. StreamInfo->RvaOfMiscInfo + sizeof(MINIDUMP_MISC_INFO);
  1534. //
  1535. // If an exception is present, reserve enough space for the exception
  1536. // and for the excepting thread's context in the Other stream.
  1537. //
  1538. if ( ExceptionPresent ) {
  1539. StreamInfo->SizeOfException = sizeof (MINIDUMP_EXCEPTION_STREAM);
  1540. StreamInfo->SizeOfOther += Dump->ContextSize;
  1541. }
  1542. StreamInfo->RvaOfThreadList =
  1543. StreamInfo->RvaOfException + StreamInfo->SizeOfException;
  1544. StreamInfo->RvaForCurThread = StreamInfo->RvaOfThreadList;
  1545. if ((Status =
  1546. CalculateSizeForThreads(Dump, Process, StreamInfo)) != S_OK) {
  1547. return Status;
  1548. }
  1549. if ((Status =
  1550. CalculateSizeForModules(Dump, Process, StreamInfo)) != S_OK) {
  1551. return Status;
  1552. }
  1553. if (!IsListEmpty(&Process->UnloadedModuleList)) {
  1554. if ((Status =
  1555. CalculateSizeForUnloadedModules(Process, StreamInfo)) != S_OK) {
  1556. return Status;
  1557. }
  1558. }
  1559. if (!IsListEmpty(&Process->FunctionTableList)) {
  1560. if ((Status = CalculateSizeForFunctionTables(Dump, Process,
  1561. StreamInfo)) != S_OK) {
  1562. return Status;
  1563. }
  1564. }
  1565. if ((Dump->DumpType & MiniDumpWithProcessThreadData) &&
  1566. Process->SizeOfPeb) {
  1567. GenAddPebMemory(Dump, Process);
  1568. }
  1569. PostProcessMemoryBlocks(Dump, Process);
  1570. // Add in any extra memory blocks.
  1571. StreamInfo->SizeOfMemoryData += Process->SizeOfMemoryBlocks;
  1572. StreamInfo->SizeOfMemoryDescriptors += Process->NumberOfMemoryBlocks *
  1573. sizeof(MINIDUMP_MEMORY_DESCRIPTOR);
  1574. StreamInfo->RvaOfModuleList =
  1575. StreamInfo->RvaOfThreadList + StreamInfo->SizeOfThreadList;
  1576. StreamInfo->RvaForCurModule = StreamInfo->RvaOfModuleList;
  1577. StreamInfo->RvaOfUnloadedModuleList =
  1578. StreamInfo->RvaOfModuleList + StreamInfo->SizeOfModuleList;
  1579. StreamInfo->RvaForCurUnloadedModule = StreamInfo->RvaOfUnloadedModuleList;
  1580. // If there aren't any function tables the size will be zero
  1581. // and the RVA will just end up being the RVA after
  1582. // the module list.
  1583. StreamInfo->RvaOfFunctionTableList =
  1584. StreamInfo->RvaOfUnloadedModuleList +
  1585. StreamInfo->SizeOfUnloadedModuleList;
  1586. StreamInfo->RvaOfStringPool =
  1587. StreamInfo->RvaOfFunctionTableList +
  1588. StreamInfo->SizeOfFunctionTableList;
  1589. StreamInfo->RvaForCurString = StreamInfo->RvaOfStringPool;
  1590. StreamInfo->RvaOfOther =
  1591. StreamInfo->RvaOfStringPool + StreamInfo->SizeOfStringPool;
  1592. StreamInfo->RvaForCurOther = StreamInfo->RvaOfOther;
  1593. SizeOfUserStreams = 0;
  1594. for (i = 0; i < UserStreamCount; i++) {
  1595. SizeOfUserStreams += (ULONG) UserStreamArray[i].BufferSize;
  1596. }
  1597. StreamInfo->RvaOfUserStreams =
  1598. StreamInfo->RvaOfOther + StreamInfo->SizeOfOther;
  1599. StreamInfo->SizeOfUserStreams = SizeOfUserStreams;
  1600. //
  1601. // Minidumps with full memory must put the raw memory
  1602. // data at the end of the dump so that it's easy to
  1603. // avoid mapping it when the dump is mapped. There's
  1604. // no problem with putting the memory data at the end
  1605. // of the dump in all the other cases so just always
  1606. // put the memory data at the end of the dump.
  1607. //
  1608. // One other benefit of having the raw data at the end
  1609. // is that we can safely assume that everything except
  1610. // the raw memory data will fit in the first 4GB of
  1611. // the file so we don't need to use 64-bit file offsets
  1612. // for everything.
  1613. //
  1614. // In the full memory case no other memory should have
  1615. // been saved so far as stacks, data segs and so on
  1616. // will automatically be included in the full memory
  1617. // information. If something was saved it'll throw off
  1618. // the dump writing as full memory descriptors are generated
  1619. // on the fly at write time rather than being precached.
  1620. // If other descriptors and memory blocks have been written
  1621. // out everything will be wrong.
  1622. // Full-memory descriptors are also 64-bit and do not
  1623. // match the 32-bit descriptors written elsewhere.
  1624. //
  1625. if ((Dump->DumpType & MiniDumpWithFullMemory) &&
  1626. (StreamInfo->SizeOfMemoryDescriptors > 0 ||
  1627. StreamInfo->SizeOfMemoryData > 0)) {
  1628. return E_INVALIDARG;
  1629. }
  1630. StreamInfo->SizeOfMemoryDescriptors +=
  1631. (Dump->DumpType & MiniDumpWithFullMemory) ?
  1632. sizeof (MINIDUMP_MEMORY64_LIST) : sizeof (MINIDUMP_MEMORY_LIST);
  1633. StreamInfo->RvaOfMemoryDescriptors =
  1634. StreamInfo->RvaOfUserStreams + StreamInfo->SizeOfUserStreams;
  1635. StreamInfo->RvaForCurMemoryDescriptor =
  1636. StreamInfo->RvaOfMemoryDescriptors;
  1637. StreamInfo->RvaOfMemoryData =
  1638. StreamInfo->RvaOfMemoryDescriptors +
  1639. StreamInfo->SizeOfMemoryDescriptors;
  1640. StreamInfo->RvaForCurMemoryData = StreamInfo->RvaOfMemoryData;
  1641. //
  1642. // Handle data cannot easily be sized beforehand so it's
  1643. // also streamed in at write time. In a partial dump
  1644. // it'll come after the memory data. In a full dump
  1645. // it'll come before it.
  1646. //
  1647. StreamInfo->RvaOfHandleData = StreamInfo->RvaOfMemoryData +
  1648. StreamInfo->SizeOfMemoryData;
  1649. return S_OK;
  1650. }
  1651. HRESULT
  1652. WriteHeader(
  1653. IN PMINIDUMP_STATE Dump,
  1654. IN PMINIDUMP_STREAM_INFO StreamInfo
  1655. )
  1656. {
  1657. HRESULT Status;
  1658. MINIDUMP_HEADER Header;
  1659. Header.Signature = MINIDUMP_SIGNATURE;
  1660. // Encode an implementation-specific version into the high word
  1661. // of the version to make it clear what version of the code
  1662. // was used to generate a dump.
  1663. Header.Version =
  1664. (MINIDUMP_VERSION & 0xffff) |
  1665. ((VER_PRODUCTMAJORVERSION & 0xf) << 28) |
  1666. ((VER_PRODUCTMINORVERSION & 0xf) << 24) |
  1667. ((VER_PRODUCTBUILD & 0xff) << 16);
  1668. Header.NumberOfStreams = StreamInfo->NumberOfStreams;
  1669. Header.StreamDirectoryRva = StreamInfo->RvaOfDirectory;
  1670. // If there were any partial failures during the
  1671. // dump generation set the checksum to indicate that.
  1672. // The checksum field was never used before so
  1673. // we're stealing it for a somewhat related purpose.
  1674. Header.CheckSum = Dump->AccumStatus;
  1675. Header.Flags = Dump->DumpType;
  1676. //
  1677. // Store the time of dump generation.
  1678. //
  1679. if ((Status = Dump->SysProv->
  1680. GetCurrentTimeDate((PULONG)&Header.TimeDateStamp)) != S_OK) {
  1681. return Status;
  1682. }
  1683. ASSERT (sizeof (Header) == StreamInfo->SizeOfHeader);
  1684. return WriteAtOffset (Dump,
  1685. StreamInfo->RvaOfHeader,
  1686. &Header,
  1687. sizeof (Header));
  1688. }
  1689. HRESULT
  1690. WriteDirectoryTable(
  1691. IN PMINIDUMP_STATE Dump,
  1692. IN PMINIDUMP_STREAM_INFO StreamInfo,
  1693. IN PINTERNAL_PROCESS Process,
  1694. IN PMINIDUMP_USER_STREAM UserStreamArray,
  1695. IN ULONG UserStreamCount
  1696. )
  1697. {
  1698. HRESULT Status;
  1699. ULONG i;
  1700. ULONG Offset;
  1701. if ((Status =
  1702. WriteDirectoryEntry (Dump,
  1703. StreamInfo->ThreadStructSize ==
  1704. sizeof(MINIDUMP_THREAD_EX) ?
  1705. ThreadExListStream : ThreadListStream,
  1706. StreamInfo->RvaOfThreadList,
  1707. StreamInfo->SizeOfThreadList)) != S_OK) {
  1708. return Status;
  1709. }
  1710. if ((Status =
  1711. WriteDirectoryEntry (Dump,
  1712. ModuleListStream,
  1713. StreamInfo->RvaOfModuleList,
  1714. StreamInfo->SizeOfModuleList)) != S_OK) {
  1715. return Status;
  1716. }
  1717. if (!IsListEmpty(&Process->UnloadedModuleList)) {
  1718. if ((Status =
  1719. WriteDirectoryEntry (Dump,
  1720. UnloadedModuleListStream,
  1721. StreamInfo->RvaOfUnloadedModuleList,
  1722. StreamInfo->SizeOfUnloadedModuleList)) != S_OK) {
  1723. return Status;
  1724. }
  1725. }
  1726. if (!IsListEmpty(&Process->FunctionTableList)) {
  1727. if ((Status =
  1728. WriteDirectoryEntry (Dump,
  1729. FunctionTableStream,
  1730. StreamInfo->RvaOfFunctionTableList,
  1731. StreamInfo->SizeOfFunctionTableList)) != S_OK) {
  1732. return Status;
  1733. }
  1734. }
  1735. if ((Status =
  1736. WriteDirectoryEntry (Dump,
  1737. (Dump->DumpType & MiniDumpWithFullMemory) ?
  1738. Memory64ListStream : MemoryListStream,
  1739. StreamInfo->RvaOfMemoryDescriptors,
  1740. StreamInfo->SizeOfMemoryDescriptors)) != S_OK) {
  1741. return Status;
  1742. }
  1743. //
  1744. // Write exception directory entry.
  1745. //
  1746. if ((Status =
  1747. WriteDirectoryEntry (Dump,
  1748. ExceptionStream,
  1749. StreamInfo->RvaOfException,
  1750. StreamInfo->SizeOfException)) != S_OK) {
  1751. return Status;
  1752. }
  1753. //
  1754. // Write system info entry.
  1755. //
  1756. if ((Status =
  1757. WriteDirectoryEntry (Dump,
  1758. SystemInfoStream,
  1759. StreamInfo->RvaOfSystemInfo,
  1760. StreamInfo->SizeOfSystemInfo)) != S_OK) {
  1761. return Status;
  1762. }
  1763. //
  1764. // Write misc info entry.
  1765. //
  1766. if ((Status =
  1767. WriteDirectoryEntry(Dump,
  1768. MiscInfoStream,
  1769. StreamInfo->RvaOfMiscInfo,
  1770. sizeof(MINIDUMP_MISC_INFO))) != S_OK) {
  1771. return Status;
  1772. }
  1773. if ((Dump->DumpType & MiniDumpWithHandleData) &&
  1774. StreamInfo->SizeOfHandleData) {
  1775. //
  1776. // Write handle data entry. If no handle data
  1777. // was recovered we don't write an entry and
  1778. // just let another unused stream get auto-created.
  1779. //
  1780. if ((Status =
  1781. WriteDirectoryEntry (Dump,
  1782. HandleDataStream,
  1783. StreamInfo->RvaOfHandleData,
  1784. StreamInfo->SizeOfHandleData)) != S_OK) {
  1785. return Status;
  1786. }
  1787. }
  1788. Offset = StreamInfo->RvaOfUserStreams;
  1789. for (i = 0; i < UserStreamCount; i++) {
  1790. if ((Status =
  1791. WriteDirectoryEntry (Dump,
  1792. UserStreamArray[i].Type,
  1793. Offset,
  1794. UserStreamArray [i].BufferSize)) != S_OK) {
  1795. return Status;
  1796. }
  1797. Offset += UserStreamArray[i].BufferSize;
  1798. }
  1799. return S_OK;
  1800. }
  1801. HRESULT
  1802. WriteException(
  1803. IN PMINIDUMP_STATE Dump,
  1804. IN PMINIDUMP_STREAM_INFO StreamInfo,
  1805. IN CONST PEXCEPTION_INFO ExceptionInfo
  1806. )
  1807. {
  1808. HRESULT Status;
  1809. ULONG i;
  1810. ULONG ContextRva;
  1811. MINIDUMP_EXCEPTION_STREAM ExceptionStream;
  1812. if (ExceptionInfo == NULL ) {
  1813. return S_OK;
  1814. }
  1815. if ((Status = WriteOther (Dump,
  1816. StreamInfo,
  1817. ExceptionInfo->ContextRecord,
  1818. Dump->ContextSize,
  1819. &ContextRva)) != S_OK) {
  1820. return Status;
  1821. }
  1822. ZeroMemory (&ExceptionStream, sizeof (ExceptionStream));
  1823. ExceptionStream.ThreadId = ExceptionInfo->ThreadId;
  1824. ExceptionStream.ExceptionRecord = ExceptionInfo->ExceptionRecord;
  1825. ExceptionStream.ThreadContext.DataSize = Dump->ContextSize;
  1826. ExceptionStream.ThreadContext.Rva = ContextRva;
  1827. return WriteAtOffset(Dump,
  1828. StreamInfo->RvaOfException,
  1829. &ExceptionStream,
  1830. StreamInfo->SizeOfException);
  1831. }
  1832. HRESULT
  1833. WriteUserStreams(
  1834. IN PMINIDUMP_STATE Dump,
  1835. IN PMINIDUMP_STREAM_INFO StreamInfo,
  1836. IN PMINIDUMP_USER_STREAM UserStreamArray,
  1837. IN ULONG UserStreamCount
  1838. )
  1839. {
  1840. HRESULT Status;
  1841. ULONG i;
  1842. ULONG Offset;
  1843. Offset = StreamInfo->RvaOfUserStreams;
  1844. for (i = 0; i < UserStreamCount; i++) {
  1845. if ((Status = WriteAtOffset(Dump,
  1846. Offset,
  1847. UserStreamArray[i].Buffer,
  1848. UserStreamArray[i].BufferSize)) != S_OK) {
  1849. return Status;
  1850. }
  1851. Offset += UserStreamArray[ i ].BufferSize;
  1852. }
  1853. return S_OK;
  1854. }
  1855. HRESULT
  1856. WriteMemoryListHeader(
  1857. IN PMINIDUMP_STATE Dump,
  1858. IN PMINIDUMP_STREAM_INFO StreamInfo
  1859. )
  1860. {
  1861. HRESULT Status;
  1862. ULONG Size;
  1863. ULONG Count;
  1864. MINIDUMP_MEMORY_LIST MemoryList;
  1865. ASSERT ( StreamInfo->RvaOfMemoryDescriptors ==
  1866. StreamInfo->RvaForCurMemoryDescriptor );
  1867. Size = StreamInfo->SizeOfMemoryDescriptors;
  1868. Size -= sizeof (MINIDUMP_MEMORY_LIST);
  1869. ASSERT ( (Size % sizeof (MINIDUMP_MEMORY_DESCRIPTOR)) == 0);
  1870. Count = Size / sizeof (MINIDUMP_MEMORY_DESCRIPTOR);
  1871. MemoryList.NumberOfMemoryRanges = Count;
  1872. if ((Status = WriteAtOffset (Dump,
  1873. StreamInfo->RvaOfMemoryDescriptors,
  1874. &MemoryList,
  1875. sizeof (MemoryList))) != S_OK) {
  1876. return Status;
  1877. }
  1878. StreamInfo->RvaForCurMemoryDescriptor += sizeof (MemoryList);
  1879. return S_OK;
  1880. }
  1881. #define FULL_MEMORY_BUFFER 65536
  1882. HRESULT
  1883. WriteFullMemory(
  1884. IN PMINIDUMP_STATE Dump,
  1885. IN PMINIDUMP_STREAM_INFO StreamInfo
  1886. )
  1887. {
  1888. PVOID Buffer;
  1889. HRESULT Status;
  1890. ULONG64 Offset;
  1891. ULONG64 Size;
  1892. ULONG Protect, State, Type;
  1893. MINIDUMP_MEMORY64_LIST List;
  1894. MINIDUMP_MEMORY_DESCRIPTOR64 Desc;
  1895. ULONG64 SeekOffset;
  1896. //
  1897. // Pick up the current offset for the RVA as
  1898. // variable data may have been written in previously.
  1899. //
  1900. if ((Status = Dump->OutProv->
  1901. Seek(FILE_CURRENT, 0, &SeekOffset)) != S_OK) {
  1902. return Status;
  1903. }
  1904. StreamInfo->RvaOfMemoryDescriptors = (ULONG)SeekOffset;
  1905. Buffer = AllocMemory(Dump, FULL_MEMORY_BUFFER);
  1906. if (Buffer == NULL) {
  1907. return E_OUTOFMEMORY;
  1908. }
  1909. //
  1910. // First pass: count and write descriptors.
  1911. // Only accessible, available memory is saved.
  1912. //
  1913. // Write placeholder list header.
  1914. ZeroMemory(&List, sizeof(List));
  1915. if ((Status = Dump->OutProv->
  1916. WriteAll(&List, sizeof(List))) != S_OK) {
  1917. goto Exit;
  1918. }
  1919. Offset = 0;
  1920. for (;;) {
  1921. if (Dump->SysProv->
  1922. QueryVirtual(Dump->ProcessHandle, Offset, &Offset, &Size,
  1923. &Protect, &State, &Type) != S_OK) {
  1924. break;
  1925. }
  1926. if (((Protect & PAGE_GUARD) ||
  1927. (Protect & PAGE_NOACCESS) ||
  1928. (State & MEM_FREE) ||
  1929. (State & MEM_RESERVE))) {
  1930. Offset += Size;
  1931. continue;
  1932. }
  1933. // The size of a stream is a ULONG32 so we can't store
  1934. // any more than that.
  1935. if (List.NumberOfMemoryRanges ==
  1936. (_UI32_MAX - sizeof(MINIDUMP_MEMORY64_LIST)) / sizeof(Desc)) {
  1937. goto Exit;
  1938. }
  1939. List.NumberOfMemoryRanges++;
  1940. Desc.StartOfMemoryRange = Offset;
  1941. Desc.DataSize = Size;
  1942. if ((Status = Dump->OutProv->
  1943. WriteAll(&Desc, sizeof(Desc))) != S_OK) {
  1944. goto Exit;
  1945. }
  1946. Offset += Size;
  1947. }
  1948. StreamInfo->SizeOfMemoryDescriptors +=
  1949. (ULONG)List.NumberOfMemoryRanges * sizeof(Desc);
  1950. List.BaseRva = (RVA64)StreamInfo->RvaOfMemoryDescriptors +
  1951. StreamInfo->SizeOfMemoryDescriptors;
  1952. //
  1953. // Second pass: write memory contents.
  1954. //
  1955. Offset = 0;
  1956. for (;;) {
  1957. ULONG64 ChunkOffset;
  1958. ULONG ChunkSize;
  1959. if (Dump->SysProv->
  1960. QueryVirtual(Dump->ProcessHandle, Offset, &Offset, &Size,
  1961. &Protect, &State, &Type) != S_OK) {
  1962. break;
  1963. }
  1964. if (((Protect & PAGE_GUARD) ||
  1965. (Protect & PAGE_NOACCESS) ||
  1966. (State & MEM_FREE) ||
  1967. (State & MEM_RESERVE))) {
  1968. Offset += Size;
  1969. continue;
  1970. }
  1971. ChunkOffset = Offset;
  1972. Offset += Size;
  1973. while (Size > 0) {
  1974. if (Size > FULL_MEMORY_BUFFER) {
  1975. ChunkSize = FULL_MEMORY_BUFFER;
  1976. } else {
  1977. ChunkSize = (ULONG)Size;
  1978. }
  1979. if ((Status = Dump->SysProv->
  1980. ReadAllVirtual(Dump->ProcessHandle,
  1981. ChunkOffset, Buffer, ChunkSize)) != S_OK) {
  1982. goto Exit;
  1983. }
  1984. if ((Status = Dump->OutProv->
  1985. WriteAll(Buffer, ChunkSize)) != S_OK) {
  1986. goto Exit;
  1987. }
  1988. ChunkOffset += ChunkSize;
  1989. Size -= ChunkSize;
  1990. }
  1991. }
  1992. // Write correct list header.
  1993. Status = WriteAtOffset(Dump, StreamInfo->RvaOfMemoryDescriptors,
  1994. &List, sizeof(List));
  1995. Exit:
  1996. FreeMemory(Dump, Buffer);
  1997. return Status;
  1998. }
  1999. HRESULT
  2000. WriteDumpData(
  2001. IN PMINIDUMP_STATE Dump,
  2002. IN PMINIDUMP_STREAM_INFO StreamInfo,
  2003. IN PINTERNAL_PROCESS Process,
  2004. IN CONST PEXCEPTION_INFO ExceptionInfo,
  2005. IN CONST PMINIDUMP_USER_STREAM UserStreamArray,
  2006. IN ULONG UserStreamCount
  2007. )
  2008. {
  2009. HRESULT Status;
  2010. if ((Status = WriteHeader ( Dump, StreamInfo )) != S_OK) {
  2011. return Status;
  2012. }
  2013. if ((Status = WriteSystemInfo ( Dump, StreamInfo )) != S_OK) {
  2014. return Status;
  2015. }
  2016. if ((Status = WriteMiscInfo(Dump, StreamInfo, Process)) != S_OK) {
  2017. return Status;
  2018. }
  2019. //
  2020. // Optionally, write the exception to the file.
  2021. //
  2022. if ((Status = WriteException ( Dump, StreamInfo, ExceptionInfo )) != S_OK) {
  2023. return Status;
  2024. }
  2025. if (!(Dump->DumpType & MiniDumpWithFullMemory)) {
  2026. //
  2027. // WriteMemoryList initializes the memory list header (count).
  2028. // The actual writing of the entries is done by WriteThreadList
  2029. // and WriteModuleList.
  2030. //
  2031. if ((Status = WriteMemoryListHeader ( Dump, StreamInfo )) != S_OK) {
  2032. return Status;
  2033. }
  2034. if ((Status = WriteMemoryBlocks(Dump, StreamInfo, Process)) != S_OK) {
  2035. return Status;
  2036. }
  2037. }
  2038. //
  2039. // Write the threads list. This will also write the contexts, and
  2040. // stacks for each thread.
  2041. //
  2042. if ((Status = WriteThreadList ( Dump, StreamInfo, Process )) != S_OK) {
  2043. return Status;
  2044. }
  2045. //
  2046. // Write the module list. This will also write the debug information and
  2047. // module name to the file.
  2048. //
  2049. if ((Status = WriteModuleList ( Dump, StreamInfo, Process )) != S_OK) {
  2050. return Status;
  2051. }
  2052. //
  2053. // Write the unloaded module list.
  2054. //
  2055. if ((Status = WriteUnloadedModuleList ( Dump, StreamInfo, Process )) != S_OK) {
  2056. return Status;
  2057. }
  2058. //
  2059. // Write the function table list.
  2060. //
  2061. if ((Status = WriteFunctionTableList ( Dump, StreamInfo, Process )) != S_OK) {
  2062. return Status;
  2063. }
  2064. if ((Status = WriteUserStreams ( Dump,
  2065. StreamInfo,
  2066. UserStreamArray,
  2067. UserStreamCount)) != S_OK) {
  2068. return Status;
  2069. }
  2070. // Put the file pointer at the end of the dump so
  2071. // we can accumulate write-streamed data.
  2072. if ((Status = Dump->OutProv->
  2073. Seek(FILE_BEGIN, StreamInfo->RvaOfHandleData, NULL)) != S_OK) {
  2074. return Status;
  2075. }
  2076. if (Dump->DumpType & MiniDumpWithHandleData) {
  2077. if ((Status =
  2078. GenWriteHandleData(Dump, StreamInfo)) != S_OK) {
  2079. return Status;
  2080. }
  2081. }
  2082. if (Dump->DumpType & MiniDumpWithFullMemory) {
  2083. if ((Status = WriteFullMemory(Dump, StreamInfo)) != S_OK) {
  2084. return Status;
  2085. }
  2086. }
  2087. if ((Status = Dump->OutProv->
  2088. Seek(FILE_BEGIN, StreamInfo->RvaOfDirectory, NULL)) != S_OK) {
  2089. return Status;
  2090. }
  2091. return WriteDirectoryTable ( Dump,
  2092. StreamInfo,
  2093. Process,
  2094. UserStreamArray,
  2095. UserStreamCount);
  2096. }
  2097. HRESULT
  2098. MarshalExceptionPointers(
  2099. IN PMINIDUMP_STATE Dump,
  2100. IN CONST _MINIDUMP_EXCEPTION_INFORMATION64* ExceptionParam,
  2101. IN OUT PEXCEPTION_INFO ExceptionInfo
  2102. )
  2103. {
  2104. HRESULT Status;
  2105. if (Dump->ExRecordSize == sizeof(EXCEPTION_RECORD32)) {
  2106. EXCEPTION_RECORD32 Record;
  2107. if ((Status = Dump->SysProv->
  2108. ReadAllVirtual(Dump->ProcessHandle,
  2109. ExceptionParam->ExceptionRecord,
  2110. &Record,
  2111. sizeof(Record))) != S_OK) {
  2112. return Status;
  2113. }
  2114. GenExRecord32ToMd(&Record, &ExceptionInfo->ExceptionRecord);
  2115. } else {
  2116. EXCEPTION_RECORD64 Record;
  2117. if ((Status = Dump->SysProv->
  2118. ReadAllVirtual(Dump->ProcessHandle,
  2119. ExceptionParam->ExceptionRecord,
  2120. &Record,
  2121. sizeof(Record))) != S_OK) {
  2122. return Status;
  2123. }
  2124. GenExRecord64ToMd(&Record, &ExceptionInfo->ExceptionRecord);
  2125. }
  2126. if ((Status = Dump->SysProv->
  2127. ReadAllVirtual(Dump->ProcessHandle,
  2128. ExceptionParam->ContextRecord,
  2129. ExceptionInfo->ContextRecord,
  2130. Dump->ContextSize)) != S_OK) {
  2131. return Status;
  2132. }
  2133. return S_OK;
  2134. }
  2135. HRESULT
  2136. GetExceptionInfo(
  2137. IN PMINIDUMP_STATE Dump,
  2138. IN CONST struct _MINIDUMP_EXCEPTION_INFORMATION64* ExceptionParam,
  2139. OUT PEXCEPTION_INFO * ExceptionInfoBuffer
  2140. )
  2141. {
  2142. HRESULT Status;
  2143. PEXCEPTION_INFO ExceptionInfo;
  2144. ULONG Size;
  2145. if ( ExceptionParam == NULL ) {
  2146. *ExceptionInfoBuffer = NULL;
  2147. return S_OK;
  2148. }
  2149. if (Dump->ExRecordSize != sizeof(EXCEPTION_RECORD32) &&
  2150. Dump->ExRecordSize != sizeof(EXCEPTION_RECORD64)) {
  2151. return E_INVALIDARG;
  2152. }
  2153. Size = sizeof(*ExceptionInfo);
  2154. if (ExceptionParam->ClientPointers) {
  2155. Size += Dump->ContextSize;
  2156. }
  2157. ExceptionInfo = (PEXCEPTION_INFO)AllocMemory(Dump, Size);
  2158. if ( ExceptionInfo == NULL ) {
  2159. return E_OUTOFMEMORY;
  2160. }
  2161. if ( !ExceptionParam->ClientPointers ) {
  2162. if (Dump->ExRecordSize == sizeof(EXCEPTION_RECORD32)) {
  2163. GenExRecord32ToMd((PEXCEPTION_RECORD32)
  2164. ExceptionParam->ExceptionRecord,
  2165. &ExceptionInfo->ExceptionRecord);
  2166. } else {
  2167. GenExRecord64ToMd((PEXCEPTION_RECORD64)
  2168. ExceptionParam->ExceptionRecord,
  2169. &ExceptionInfo->ExceptionRecord);
  2170. }
  2171. ExceptionInfo->ContextRecord =
  2172. (PVOID)ExceptionParam->ContextRecord;
  2173. Status = S_OK;
  2174. } else {
  2175. ExceptionInfo->ContextRecord = (PVOID)(ExceptionInfo + 1);
  2176. Status = MarshalExceptionPointers(Dump,
  2177. ExceptionParam,
  2178. ExceptionInfo);
  2179. }
  2180. ExceptionInfo->ThreadId = ExceptionParam->ThreadId;
  2181. if ( Status != S_OK ) {
  2182. FreeMemory(Dump, ExceptionInfo);
  2183. } else {
  2184. //
  2185. // We've seen some cases where the exception record has
  2186. // a bogus number of parameters, causing stack corruption here.
  2187. // We could fail such cases but in the spirit of try to
  2188. // allow dumps to generated as often as possible we just
  2189. // limit the number to the maximum.
  2190. //
  2191. if (ExceptionInfo->ExceptionRecord.NumberParameters >
  2192. EXCEPTION_MAXIMUM_PARAMETERS) {
  2193. ExceptionInfo->ExceptionRecord.NumberParameters =
  2194. EXCEPTION_MAXIMUM_PARAMETERS;
  2195. }
  2196. *ExceptionInfoBuffer = ExceptionInfo;
  2197. }
  2198. return Status;
  2199. }
  2200. VOID
  2201. FreeExceptionInfo(
  2202. IN PMINIDUMP_STATE Dump,
  2203. IN PEXCEPTION_INFO ExceptionInfo
  2204. )
  2205. {
  2206. if ( ExceptionInfo ) {
  2207. FreeMemory(Dump, ExceptionInfo);
  2208. }
  2209. }
  2210. HRESULT
  2211. GetSystemType(
  2212. IN OUT PMINIDUMP_STATE Dump
  2213. )
  2214. {
  2215. HRESULT Status;
  2216. if ((Status = Dump->SysProv->
  2217. GetCpuType(&Dump->CpuType,
  2218. &Dump->BackingStore)) != S_OK) {
  2219. return Status;
  2220. }
  2221. switch(Dump->CpuType) {
  2222. case IMAGE_FILE_MACHINE_I386:
  2223. Dump->CpuTypeName = L"x86";
  2224. break;
  2225. case IMAGE_FILE_MACHINE_IA64:
  2226. Dump->CpuTypeName = L"IA64";
  2227. break;
  2228. case IMAGE_FILE_MACHINE_AMD64:
  2229. Dump->CpuTypeName = L"AMD64";
  2230. break;
  2231. case IMAGE_FILE_MACHINE_ARM:
  2232. Dump->CpuTypeName = L"ARM";
  2233. break;
  2234. default:
  2235. return E_INVALIDARG;
  2236. }
  2237. if ((Status = Dump->SysProv->
  2238. GetOsInfo(&Dump->OsPlatformId,
  2239. &Dump->OsMajor,
  2240. &Dump->OsMinor,
  2241. &Dump->OsBuildNumber,
  2242. &Dump->OsProductType,
  2243. &Dump->OsSuiteMask)) != S_OK) {
  2244. return Status;
  2245. }
  2246. Dump->SysProv->
  2247. GetContextSizes(&Dump->ContextSize,
  2248. &Dump->RegScanOffset,
  2249. &Dump->RegScanCount);
  2250. Dump->SysProv->
  2251. GetPointerSize(&Dump->PtrSize);
  2252. Dump->SysProv->
  2253. GetPageSize(&Dump->PageSize);
  2254. Dump->SysProv->
  2255. GetFunctionTableSizes(&Dump->FuncTableSize,
  2256. &Dump->FuncTableEntrySize);
  2257. Dump->SysProv->
  2258. GetInstructionWindowSize(&Dump->InstructionWindowSize);
  2259. if (Dump->FuncTableSize > MAX_DYNAMIC_FUNCTION_TABLE) {
  2260. return E_INVALIDARG;
  2261. }
  2262. Dump->ExRecordSize = Dump->PtrSize == 8 ?
  2263. sizeof(EXCEPTION_RECORD64) : sizeof(EXCEPTION_RECORD32);
  2264. if (Dump->RegScanCount == -1) {
  2265. // Default reg scan.
  2266. switch(Dump->CpuType) {
  2267. case IMAGE_FILE_MACHINE_I386:
  2268. Dump->RegScanOffset = 0x9c;
  2269. Dump->RegScanCount = 11;
  2270. break;
  2271. case IMAGE_FILE_MACHINE_IA64:
  2272. Dump->RegScanOffset = 0x878;
  2273. Dump->RegScanCount = 41;
  2274. break;
  2275. case IMAGE_FILE_MACHINE_AMD64:
  2276. Dump->RegScanOffset = 0x78;
  2277. Dump->RegScanCount = 17;
  2278. break;
  2279. case IMAGE_FILE_MACHINE_ARM:
  2280. Dump->RegScanOffset = 4;
  2281. Dump->RegScanCount = 16;
  2282. break;
  2283. default:
  2284. return E_INVALIDARG;
  2285. }
  2286. }
  2287. if (Dump->InstructionWindowSize == -1) {
  2288. // Default window.
  2289. switch(Dump->CpuType) {
  2290. case IMAGE_FILE_MACHINE_I386:
  2291. Dump->InstructionWindowSize = 256;
  2292. break;
  2293. case IMAGE_FILE_MACHINE_IA64:
  2294. Dump->InstructionWindowSize = 768;
  2295. break;
  2296. case IMAGE_FILE_MACHINE_AMD64:
  2297. Dump->InstructionWindowSize = 256;
  2298. break;
  2299. case IMAGE_FILE_MACHINE_ARM:
  2300. Dump->InstructionWindowSize = 512;
  2301. break;
  2302. default:
  2303. return E_INVALIDARG;
  2304. }
  2305. }
  2306. return S_OK;
  2307. }
  2308. HRESULT
  2309. WINAPI
  2310. MiniDumpProvideDump(
  2311. IN HANDLE hProcess,
  2312. IN DWORD ProcessId,
  2313. IN MiniDumpSystemProvider* SysProv,
  2314. IN MiniDumpOutputProvider* OutProv,
  2315. IN MiniDumpAllocationProvider* AllocProv,
  2316. IN ULONG DumpType,
  2317. IN CONST struct _MINIDUMP_EXCEPTION_INFORMATION64* ExceptionParam, OPTIONAL
  2318. IN CONST struct _MINIDUMP_USER_STREAM_INFORMATION* UserStreamParam, OPTIONAL
  2319. IN CONST struct _MINIDUMP_CALLBACK_INFORMATION* CallbackParam OPTIONAL
  2320. )
  2321. {
  2322. HRESULT Status;
  2323. PINTERNAL_PROCESS Process;
  2324. MINIDUMP_STREAM_INFO StreamInfo;
  2325. PEXCEPTION_INFO ExceptionInfo;
  2326. PMINIDUMP_USER_STREAM UserStreamArray;
  2327. ULONG UserStreamCount;
  2328. MINIDUMP_STATE Dump;
  2329. if ((DumpType & ~(MiniDumpNormal |
  2330. MiniDumpWithDataSegs |
  2331. MiniDumpWithFullMemory |
  2332. MiniDumpWithHandleData |
  2333. MiniDumpFilterMemory |
  2334. MiniDumpScanMemory |
  2335. MiniDumpWithUnloadedModules |
  2336. MiniDumpWithIndirectlyReferencedMemory |
  2337. MiniDumpFilterModulePaths |
  2338. MiniDumpWithProcessThreadData |
  2339. MiniDumpWithPrivateReadWriteMemory |
  2340. MiniDumpWithoutOptionalData))) {
  2341. return E_INVALIDARG;
  2342. }
  2343. // Modify flags that are affected by dropping optional data.
  2344. if (DumpType & MiniDumpWithoutOptionalData) {
  2345. DumpType &= ~(MiniDumpWithFullMemory |
  2346. MiniDumpWithIndirectlyReferencedMemory |
  2347. MiniDumpWithPrivateReadWriteMemory);
  2348. }
  2349. // Full memory by definition includes data segments,
  2350. // so turn off data segments if full memory is requested.
  2351. if (DumpType & MiniDumpWithFullMemory) {
  2352. DumpType &= ~(MiniDumpWithDataSegs |
  2353. MiniDumpFilterMemory |
  2354. MiniDumpScanMemory |
  2355. MiniDumpWithIndirectlyReferencedMemory |
  2356. MiniDumpWithProcessThreadData |
  2357. MiniDumpWithPrivateReadWriteMemory);
  2358. }
  2359. // Fail immediately if stream-oriented data is requested but the
  2360. // output provider can't handle streamed output.
  2361. if ((DumpType & (MiniDumpWithHandleData |
  2362. MiniDumpWithFullMemory)) &&
  2363. OutProv->SupportsStreaming() != S_OK) {
  2364. return E_INVALIDARG;
  2365. }
  2366. //
  2367. // Initialization
  2368. //
  2369. Process = NULL;
  2370. UserStreamArray = NULL;
  2371. UserStreamCount = 0;
  2372. Dump.ProcessHandle = hProcess;
  2373. Dump.ProcessId = ProcessId;
  2374. Dump.SysProv = SysProv;
  2375. Dump.OutProv = OutProv;
  2376. Dump.AllocProv = AllocProv;
  2377. Dump.DumpType = DumpType,
  2378. Dump.AccumStatus = 0;
  2379. if ( CallbackParam ) {
  2380. Dump.CallbackRoutine = CallbackParam->CallbackRoutine;
  2381. Dump.CallbackParam = CallbackParam->CallbackParam;
  2382. } else {
  2383. Dump.CallbackRoutine = NULL;
  2384. Dump.CallbackParam = NULL;
  2385. }
  2386. if ((Status = GetSystemType(&Dump)) != S_OK) {
  2387. return Status;
  2388. }
  2389. //
  2390. // Marshal exception pointers into our process space if necessary.
  2391. //
  2392. if ((Status = GetExceptionInfo(&Dump,
  2393. ExceptionParam,
  2394. &ExceptionInfo)) != S_OK) {
  2395. goto Exit;
  2396. }
  2397. if ( UserStreamParam ) {
  2398. UserStreamArray = UserStreamParam->UserStreamArray;
  2399. UserStreamCount = UserStreamParam->UserStreamCount;
  2400. }
  2401. //
  2402. // Gather information about the process we are dumping.
  2403. //
  2404. if ((Status = GenGetProcessInfo(&Dump, &Process)) != S_OK) {
  2405. goto Exit;
  2406. }
  2407. //
  2408. // Process gathered information.
  2409. //
  2410. if ((Status = PostProcessInfo(&Dump, Process)) != S_OK) {
  2411. goto Exit;
  2412. }
  2413. //
  2414. // Execute user callbacks to filter out unwanted data.
  2415. //
  2416. if ((Status = ExecuteCallbacks(&Dump, Process)) != S_OK) {
  2417. goto Exit;
  2418. }
  2419. //
  2420. // Pass 1: Fill in the StreamInfo structure.
  2421. //
  2422. if ((Status =
  2423. CalculateStreamInfo(&Dump,
  2424. Process,
  2425. &StreamInfo,
  2426. ( ExceptionInfo != NULL ) ? TRUE : FALSE,
  2427. UserStreamArray,
  2428. UserStreamCount)) != S_OK) {
  2429. goto Exit;
  2430. }
  2431. //
  2432. // Pass 2: Write the minidump data to disk.
  2433. //
  2434. if (DumpType & (MiniDumpWithHandleData |
  2435. MiniDumpWithFullMemory)) {
  2436. // We don't know how big the output will be.
  2437. if ((Status = OutProv->Start(0)) != S_OK) {
  2438. goto Exit;
  2439. }
  2440. } else {
  2441. // Pass in the size of the dump.
  2442. if ((Status = OutProv->Start(StreamInfo.RvaOfHandleData)) != S_OK) {
  2443. goto Exit;
  2444. }
  2445. }
  2446. Status = WriteDumpData(&Dump,
  2447. &StreamInfo,
  2448. Process,
  2449. ExceptionInfo,
  2450. UserStreamArray,
  2451. UserStreamCount);
  2452. OutProv->Finish();
  2453. Exit:
  2454. //
  2455. // Free up any memory marshalled for the exception pointers.
  2456. //
  2457. FreeExceptionInfo ( &Dump, ExceptionInfo );
  2458. //
  2459. // Free the process objects.
  2460. //
  2461. if ( Process ) {
  2462. GenFreeProcessObject ( &Dump, Process );
  2463. }
  2464. return Status;
  2465. }
  2466. BOOL
  2467. UseDbgHelp(void)
  2468. {
  2469. #if !defined (_DBGHELP_SOURCE_)
  2470. OSVERSIONINFO OsVer;
  2471. //
  2472. // Bind to dbghelp imports.
  2473. //
  2474. // We can only use the dbghelp imports if the dbghelp on
  2475. // the system is of recent vintage and therefore has a good
  2476. // chance of including all the latest minidump code. Currently
  2477. // Windows Server (5.01 >= build 3620) has the latest minidump
  2478. // code so its dbghelp can be used. If minidump.lib has major
  2479. // feature additions this check will need to be revised.
  2480. //
  2481. OsVer.dwOSVersionInfoSize = sizeof(OsVer);
  2482. if (GetVersionEx(&OsVer) &&
  2483. OsVer.dwPlatformId == VER_PLATFORM_WIN32_NT &&
  2484. (OsVer.dwMajorVersion > 5 ||
  2485. (OsVer.dwMajorVersion == 5 &&
  2486. OsVer.dwMinorVersion >= 2)) &&
  2487. OsVer.dwBuildNumber >= 3620) {
  2488. return TRUE;
  2489. }
  2490. #endif
  2491. return FALSE;
  2492. }
  2493. BOOL
  2494. WINAPI
  2495. MiniDumpWriteDump(
  2496. IN HANDLE hProcess,
  2497. IN DWORD ProcessId,
  2498. IN HANDLE hFile,
  2499. IN MINIDUMP_TYPE DumpType,
  2500. IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
  2501. IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL
  2502. IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL
  2503. )
  2504. {
  2505. HRESULT Status;
  2506. MiniDumpSystemProvider* SysProv = NULL;
  2507. MiniDumpOutputProvider* OutProv = NULL;
  2508. MiniDumpAllocationProvider* AllocProv = NULL;
  2509. MINIDUMP_EXCEPTION_INFORMATION64 ExInfoBuffer;
  2510. PMINIDUMP_EXCEPTION_INFORMATION64 ExInfo;
  2511. // Attempt to use the system's copy of the code in
  2512. // dbghelp. If any of this process fails just continue
  2513. // on with the local code.
  2514. if (UseDbgHelp()) {
  2515. HINSTANCE Dll = LoadLibrary("dbghelp.dll");
  2516. if (Dll) {
  2517. MINI_DUMP_WRITE_DUMP Fn = (MINI_DUMP_WRITE_DUMP)
  2518. GetProcAddress(Dll, "MiniDumpWriteDump");
  2519. if (Fn) {
  2520. BOOL Succ = Fn(hProcess, ProcessId, hFile, DumpType,
  2521. ExceptionParam, UserStreamParam, CallbackParam);
  2522. FreeLibrary(Dll);
  2523. return Succ;
  2524. }
  2525. FreeLibrary(Dll);
  2526. }
  2527. }
  2528. if ((Status =
  2529. MiniDumpCreateLiveSystemProvider(&SysProv)) != S_OK ||
  2530. (Status =
  2531. MiniDumpCreateFileOutputProvider(hFile, &OutProv)) != S_OK ||
  2532. (Status =
  2533. MiniDumpCreateLiveAllocationProvider(&AllocProv)) != S_OK) {
  2534. goto Exit;
  2535. }
  2536. if (ExceptionParam) {
  2537. ExInfo = &ExInfoBuffer;
  2538. ExInfo->ThreadId = ExceptionParam->ThreadId;
  2539. ExInfo->ClientPointers = ExceptionParam->ClientPointers;
  2540. if (ExInfo->ClientPointers) {
  2541. EXCEPTION_POINTERS ClientPointers;
  2542. if ((Status = SysProv->
  2543. ReadAllVirtual(hProcess,
  2544. (LONG_PTR)ExceptionParam->ExceptionPointers,
  2545. &ClientPointers,
  2546. sizeof(ClientPointers))) != S_OK) {
  2547. goto Exit;
  2548. }
  2549. ExInfo->ExceptionRecord =
  2550. (LONG_PTR)ClientPointers.ExceptionRecord;
  2551. ExInfo->ContextRecord =
  2552. (LONG_PTR)ClientPointers.ContextRecord;
  2553. } else {
  2554. ExInfo->ExceptionRecord =
  2555. (LONG_PTR)ExceptionParam->ExceptionPointers->ExceptionRecord;
  2556. ExInfo->ContextRecord =
  2557. (LONG_PTR)ExceptionParam->ExceptionPointers->ContextRecord;
  2558. }
  2559. } else {
  2560. ExInfo = NULL;
  2561. }
  2562. Status = MiniDumpProvideDump(hProcess, ProcessId,
  2563. SysProv, OutProv, AllocProv,
  2564. DumpType, ExInfo,
  2565. UserStreamParam, CallbackParam);
  2566. Exit:
  2567. if (SysProv) {
  2568. SysProv->Release();
  2569. }
  2570. if (OutProv) {
  2571. OutProv->Release();
  2572. }
  2573. if (AllocProv) {
  2574. AllocProv->Release();
  2575. }
  2576. if (Status == S_OK) {
  2577. return TRUE;
  2578. } else {
  2579. SetLastError(Status);
  2580. return FALSE;
  2581. }
  2582. }
  2583. BOOL
  2584. WINAPI
  2585. MiniDumpReadDumpStream(
  2586. IN PVOID Base,
  2587. ULONG StreamNumber,
  2588. OUT PMINIDUMP_DIRECTORY * Dir, OPTIONAL
  2589. OUT PVOID * Stream, OPTIONAL
  2590. OUT ULONG * StreamSize OPTIONAL
  2591. )
  2592. {
  2593. ULONG i;
  2594. BOOL Found;
  2595. PMINIDUMP_DIRECTORY Dirs;
  2596. PMINIDUMP_HEADER Header;
  2597. // Attempt to use the system's copy of the code in
  2598. // dbghelp. If any of this process fails just continue
  2599. // on with the local code.
  2600. if (UseDbgHelp()) {
  2601. HINSTANCE Dll = LoadLibrary("dbghelp.dll");
  2602. if (Dll) {
  2603. MINI_DUMP_READ_DUMP_STREAM Fn = (MINI_DUMP_READ_DUMP_STREAM)
  2604. GetProcAddress(Dll, "MiniDumpReadDumpStream");
  2605. if (Fn) {
  2606. BOOL Succ = Fn(Base, StreamNumber,
  2607. Dir, Stream, StreamSize);
  2608. FreeLibrary(Dll);
  2609. return Succ;
  2610. }
  2611. FreeLibrary(Dll);
  2612. }
  2613. }
  2614. //
  2615. // Initialization
  2616. //
  2617. Found = FALSE;
  2618. Header = (PMINIDUMP_HEADER) Base;
  2619. if ( Header->Signature != MINIDUMP_SIGNATURE ||
  2620. (Header->Version & 0xffff) != MINIDUMP_VERSION ) {
  2621. //
  2622. // Invalid Minidump file.
  2623. //
  2624. return FALSE;
  2625. }
  2626. Dirs = (PMINIDUMP_DIRECTORY) RVA_TO_ADDR (Header, Header->StreamDirectoryRva);
  2627. for (i = 0; i < Header->NumberOfStreams; i++) {
  2628. if (Dirs [i].StreamType == StreamNumber) {
  2629. Found = TRUE;
  2630. break;
  2631. }
  2632. }
  2633. if ( !Found ) {
  2634. return FALSE;
  2635. }
  2636. if ( Dir ) {
  2637. *Dir = &Dirs [i];
  2638. }
  2639. if ( Stream ) {
  2640. *Stream = RVA_TO_ADDR (Base, Dirs [i].Location.Rva);
  2641. }
  2642. if ( StreamSize ) {
  2643. *StreamSize = Dirs[i].Location.DataSize;
  2644. }
  2645. return TRUE;
  2646. }