Source code of Windows XP (NT5)
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.

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