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.

2199 lines
54 KiB

  1. /*++
  2. Copyright (c) 1999-2002 Microsoft Corporation
  3. Module Name:
  4. gen.c
  5. Abstract:
  6. Generic routins for minidump that work on both NT and Win9x.
  7. Author:
  8. Matthew D Hendel (math) 10-Sep-1999
  9. Revision History:
  10. --*/
  11. #include "pch.h"
  12. #include <limits.h>
  13. #include "nt4.h"
  14. #include "win.h"
  15. #include "ntx.h"
  16. #include "wce.h"
  17. #include "impl.h"
  18. #define REASONABLE_NB11_RECORD_SIZE (10 * KBYTE)
  19. #define REASONABLE_MISC_RECORD_SIZE (10 * KBYTE)
  20. ULONG g_MiniDumpStatus;
  21. #if defined (i386)
  22. //
  23. // For FPO frames on x86 we access bytes outside of the ESP - StackBase range.
  24. // This variable determines how many extra bytes we need to add for this
  25. // case.
  26. //
  27. #define X86_STACK_FRAME_EXTRA_FPO_BYTES 4
  28. #endif
  29. LPVOID
  30. AllocMemory(
  31. SIZE_T Size
  32. )
  33. {
  34. LPVOID Mem = HeapAlloc ( GetProcessHeap (), HEAP_ZERO_MEMORY, Size );
  35. if (!Mem) {
  36. // Handle marking the no-memory state for all allocations.
  37. GenAccumulateStatus(MDSTATUS_OUT_OF_MEMORY);
  38. }
  39. return Mem;
  40. }
  41. VOID
  42. FreeMemory(
  43. IN LPVOID Memory
  44. )
  45. {
  46. if ( Memory ) {
  47. HeapFree ( GetProcessHeap (), 0, Memory );
  48. }
  49. return;
  50. }
  51. PVOID
  52. ReAllocMemory(
  53. IN LPVOID Memory,
  54. IN SIZE_T Size
  55. )
  56. {
  57. LPVOID Mem = HeapReAlloc ( GetProcessHeap (), HEAP_ZERO_MEMORY, Memory, Size);
  58. if (!Mem) {
  59. // Handle marking the no-memory state for all allocations.
  60. GenAccumulateStatus(MDSTATUS_OUT_OF_MEMORY);
  61. }
  62. return Mem;
  63. }
  64. BOOL
  65. ProcessThread32Next(
  66. HANDLE hSnapshot,
  67. DWORD dwProcessID,
  68. THREADENTRY32 * ThreadInfo
  69. )
  70. {
  71. BOOL succ;
  72. //
  73. // NB: Toolhelp says nothing about the order of the threads will be
  74. // returned in (i.e., if they are grouped by process or not). If they
  75. // are groupled by process -- which they emperically seem to be -- there
  76. // is a more efficient algorithm than simple brute force.
  77. //
  78. do {
  79. ThreadInfo->dwSize = sizeof (*ThreadInfo);
  80. succ = Thread32Next (hSnapshot, ThreadInfo);
  81. } while (succ && ThreadInfo->th32OwnerProcessID != dwProcessID);
  82. return succ;
  83. }
  84. BOOL
  85. ProcessThread32First(
  86. HANDLE hSnapshot,
  87. DWORD dwProcessID,
  88. THREADENTRY32 * ThreadInfo
  89. )
  90. {
  91. BOOL succ;
  92. ThreadInfo->dwSize = sizeof (*ThreadInfo);
  93. succ = Thread32First (hSnapshot, ThreadInfo);
  94. if (succ && ThreadInfo->th32OwnerProcessID != dwProcessID) {
  95. succ = ProcessThread32Next (hSnapshot, dwProcessID, ThreadInfo);
  96. }
  97. return succ;
  98. }
  99. ULONG
  100. GenGetAccumulatedStatus(
  101. void
  102. )
  103. {
  104. return g_MiniDumpStatus;
  105. }
  106. void
  107. GenAccumulateStatus(
  108. IN ULONG Status
  109. )
  110. {
  111. g_MiniDumpStatus |= Status;
  112. }
  113. void
  114. GenClearAccumulatedStatus(
  115. void
  116. )
  117. {
  118. g_MiniDumpStatus = 0;
  119. }
  120. VOID
  121. GenGetDefaultWriteFlags(
  122. IN ULONG DumpType,
  123. OUT PULONG ModuleWriteFlags,
  124. OUT PULONG ThreadWriteFlags
  125. )
  126. {
  127. *ModuleWriteFlags = ModuleWriteModule | ModuleWriteMiscRecord |
  128. ModuleWriteCvRecord;
  129. if (DumpType & MiniDumpWithDataSegs) {
  130. *ModuleWriteFlags |= ModuleWriteDataSeg;
  131. }
  132. *ThreadWriteFlags = ThreadWriteThread | ThreadWriteContext;
  133. if (!(DumpType & MiniDumpWithFullMemory)) {
  134. *ThreadWriteFlags |= ThreadWriteStack | ThreadWriteInstructionWindow;
  135. #if defined (DUMP_BACKING_STORE)
  136. *ThreadWriteFlags |= ThreadWriteBackingStore;
  137. #endif
  138. }
  139. if (DumpType & MiniDumpWithProcessThreadData) {
  140. *ThreadWriteFlags |= ThreadWriteThreadData;
  141. }
  142. }
  143. BOOL
  144. GenExecuteIncludeThreadCallback(
  145. IN HANDLE hProcess,
  146. IN DWORD ProcessId,
  147. IN ULONG DumpType,
  148. IN ULONG ThreadId,
  149. IN MINIDUMP_CALLBACK_ROUTINE CallbackRoutine,
  150. IN PVOID CallbackParam,
  151. OUT PULONG WriteFlags
  152. )
  153. {
  154. BOOL Succ;
  155. MINIDUMP_CALLBACK_INPUT CallbackInput;
  156. MINIDUMP_CALLBACK_OUTPUT CallbackOutput;
  157. // Initialize the default write flags.
  158. GenGetDefaultWriteFlags(DumpType, &CallbackOutput.ModuleWriteFlags,
  159. WriteFlags);
  160. //
  161. // If there are no callbacks to call, then we are done.
  162. //
  163. if ( CallbackRoutine == NULL ) {
  164. return TRUE;
  165. }
  166. CallbackInput.ProcessHandle = hProcess;
  167. CallbackInput.ProcessId = ProcessId;
  168. CallbackInput.CallbackType = IncludeThreadCallback;
  169. CallbackInput.IncludeThread.ThreadId = ThreadId;
  170. CallbackOutput.ThreadWriteFlags = *WriteFlags;
  171. Succ = CallbackRoutine (CallbackParam,
  172. &CallbackInput,
  173. &CallbackOutput);
  174. //
  175. // If the callback returned FALSE, quit now.
  176. //
  177. if ( !Succ ) {
  178. return FALSE;
  179. }
  180. // Limit the flags that can be added.
  181. *WriteFlags &= CallbackOutput.ThreadWriteFlags;
  182. return TRUE;
  183. }
  184. BOOL
  185. GenExecuteIncludeModuleCallback(
  186. IN HANDLE hProcess,
  187. IN DWORD ProcessId,
  188. IN ULONG DumpType,
  189. IN ULONG64 BaseOfImage,
  190. IN MINIDUMP_CALLBACK_ROUTINE CallbackRoutine,
  191. IN PVOID CallbackParam,
  192. OUT PULONG WriteFlags
  193. )
  194. {
  195. BOOL Succ;
  196. MINIDUMP_CALLBACK_INPUT CallbackInput;
  197. MINIDUMP_CALLBACK_OUTPUT CallbackOutput;
  198. // Initialize the default write flags.
  199. GenGetDefaultWriteFlags(DumpType, WriteFlags,
  200. &CallbackOutput.ThreadWriteFlags);
  201. //
  202. // If there are no callbacks to call, then we are done.
  203. //
  204. if ( CallbackRoutine == NULL ) {
  205. return TRUE;
  206. }
  207. CallbackInput.ProcessHandle = hProcess;
  208. CallbackInput.ProcessId = ProcessId;
  209. CallbackInput.CallbackType = IncludeModuleCallback;
  210. CallbackInput.IncludeModule.BaseOfImage = BaseOfImage;
  211. CallbackOutput.ModuleWriteFlags = *WriteFlags;
  212. Succ = CallbackRoutine (CallbackParam,
  213. &CallbackInput,
  214. &CallbackOutput);
  215. //
  216. // If the callback returned FALSE, quit now.
  217. //
  218. if ( !Succ ) {
  219. return FALSE;
  220. }
  221. // Limit the flags that can be added.
  222. *WriteFlags = (*WriteFlags | ModuleReferencedByMemory) &
  223. CallbackOutput.ModuleWriteFlags;
  224. return TRUE;
  225. }
  226. BOOL
  227. GenGetVersionInfo(
  228. IN PWSTR FullPath,
  229. OUT VS_FIXEDFILEINFO * VersionInfo
  230. )
  231. /*++
  232. Routine Description:
  233. Get the VS_FIXEDFILEINFO for the module described by FullPath.
  234. Arguments:
  235. FullPath - FullPath to the module.
  236. VersionInfo - Buffer to copy the Version information.
  237. Return Values:
  238. TRUE - Success.
  239. FALSE - Failure.
  240. --*/
  241. {
  242. BOOL Succ;
  243. ULONG unused;
  244. ULONG Size;
  245. UINT VerSize;
  246. PVOID VersionBlock;
  247. PVOID VersionData;
  248. CHAR FullPathA [ MAX_PATH + 10 ];
  249. BOOL UseAnsi = FALSE;
  250. //
  251. // Get the version information.
  252. //
  253. Size = GetFileVersionInfoSizeW (FullPath, &unused);
  254. if (Size == 0 &&
  255. GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
  256. // We're on an OS that doesn't support Unicode
  257. // file operations. Convert to ANSI and see if
  258. // that helps.
  259. if (WideCharToMultiByte (CP_ACP,
  260. 0,
  261. FullPath,
  262. -1,
  263. FullPathA,
  264. sizeof (FullPathA),
  265. 0,
  266. 0
  267. ) > 0) {
  268. Size = GetFileVersionInfoSizeA(FullPathA, &unused);
  269. UseAnsi = TRUE;
  270. }
  271. }
  272. if (Size) {
  273. VersionBlock = AllocMemory (Size);
  274. if (VersionBlock) {
  275. if (UseAnsi) {
  276. Succ = GetFileVersionInfoA(FullPathA,
  277. 0,
  278. Size,
  279. VersionBlock);
  280. } else {
  281. Succ = GetFileVersionInfoW(FullPath,
  282. 0,
  283. Size,
  284. VersionBlock);
  285. }
  286. if (Succ)
  287. {
  288. //
  289. // Get the VS_FIXEDFILEINFO from the image.
  290. //
  291. VerSize = 0; // ?? sizeof (Module->VersionInfo);
  292. Succ = VerQueryValue(VersionBlock,
  293. "\\",
  294. &VersionData,
  295. &VerSize);
  296. if ( Succ && (VerSize == sizeof (VS_FIXEDFILEINFO)) ) {
  297. CopyMemory (VersionInfo, VersionData, sizeof (*VersionInfo));
  298. FreeMemory(VersionBlock);
  299. return TRUE;
  300. }
  301. }
  302. FreeMemory (VersionBlock);
  303. }
  304. }
  305. // Files don't have to have version information
  306. // so don't accumulate status for this failure.
  307. return FALSE;
  308. }
  309. BOOL
  310. GenGetDebugRecord(
  311. IN PVOID Base,
  312. IN ULONG MappedSize,
  313. IN PIMAGE_NT_HEADERS NtHeaders,
  314. IN ULONG DebugRecordType,
  315. IN ULONG DebugRecordMaxSize,
  316. OUT PVOID * DebugInfo,
  317. OUT ULONG * SizeOfDebugInfo
  318. )
  319. {
  320. ULONG i;
  321. ULONG Size;
  322. ULONG NumberOfDebugDirectories;
  323. IMAGE_DEBUG_DIRECTORY UNALIGNED* DebugDirectories;
  324. Size = 0;
  325. //
  326. // Find the debug directory and copy the memory into the.
  327. //
  328. DebugDirectories = (IMAGE_DEBUG_DIRECTORY UNALIGNED *)
  329. ImageDirectoryEntryToData (Base,
  330. FALSE,
  331. IMAGE_DIRECTORY_ENTRY_DEBUG,
  332. &Size);
  333. //
  334. // Check that we got a valid record.
  335. //
  336. if (DebugDirectories &&
  337. ((Size % sizeof (IMAGE_DEBUG_DIRECTORY)) == 0) &&
  338. (ULONG_PTR)DebugDirectories - (ULONG_PTR)Base + Size <= MappedSize)
  339. {
  340. NumberOfDebugDirectories = Size / sizeof (IMAGE_DEBUG_DIRECTORY);
  341. for (i = 0 ; i < NumberOfDebugDirectories; i++)
  342. {
  343. //
  344. // We should check if it's a NB10 or something record.
  345. //
  346. if ((DebugDirectories[ i ].Type == DebugRecordType) &&
  347. (DebugDirectories[ i ].SizeOfData < DebugRecordMaxSize))
  348. {
  349. if (DebugDirectories[i].PointerToRawData +
  350. DebugDirectories[i].SizeOfData > MappedSize)
  351. {
  352. break;
  353. }
  354. *SizeOfDebugInfo = DebugDirectories [ i ].SizeOfData;
  355. *DebugInfo = AllocMemory ( *SizeOfDebugInfo );
  356. if (!(*DebugInfo))
  357. {
  358. break;
  359. }
  360. CopyMemory(*DebugInfo,
  361. ((PBYTE) Base) +
  362. DebugDirectories [ i ].PointerToRawData,
  363. *SizeOfDebugInfo);
  364. return TRUE;
  365. }
  366. }
  367. }
  368. return FALSE;
  369. }
  370. PVOID
  371. GenOpenMapping(
  372. IN PCWSTR FilePath,
  373. OUT PULONG Size,
  374. OUT PWSTR LongPath,
  375. IN ULONG LongPathChars
  376. )
  377. {
  378. HANDLE hFile;
  379. HANDLE hMappedFile;
  380. PVOID MappedFile;
  381. DWORD Chars;
  382. //
  383. // The module may be loaded with a short name. Open
  384. // the mapping with the name given, but also determine
  385. // the long name if possible. This is done here as
  386. // the ANSI/Unicode issues are already being handled here.
  387. //
  388. hFile = CreateFileW(
  389. FilePath,
  390. GENERIC_READ,
  391. FILE_SHARE_READ | FILE_SHARE_WRITE,
  392. NULL,
  393. OPEN_EXISTING,
  394. 0,
  395. NULL
  396. );
  397. if ( hFile == NULL || hFile == INVALID_HANDLE_VALUE ) {
  398. if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
  399. // We're on an OS that doesn't support Unicode
  400. // file operations. Convert to ANSI and see if
  401. // that helps.
  402. CHAR FilePathA [ MAX_PATH + 10 ];
  403. if (WideCharToMultiByte (CP_ACP,
  404. 0,
  405. FilePath,
  406. -1,
  407. FilePathA,
  408. sizeof (FilePathA),
  409. 0,
  410. 0
  411. ) > 0) {
  412. hFile = CreateFileA(FilePathA,
  413. GENERIC_READ,
  414. FILE_SHARE_READ | FILE_SHARE_WRITE,
  415. NULL,
  416. OPEN_EXISTING,
  417. 0,
  418. NULL
  419. );
  420. if (hFile != INVALID_HANDLE_VALUE) {
  421. Chars = GetLongPathNameA(FilePathA, FilePathA,
  422. ARRAY_COUNT(FilePathA));
  423. if (Chars == 0 || Chars >= ARRAY_COUNT(FilePathA) ||
  424. MultiByteToWideChar(CP_ACP, 0, FilePathA, -1,
  425. LongPath, LongPathChars) == 0) {
  426. // Couldn't get the long path, just use the
  427. // given path.
  428. lstrcpynW(LongPath, FilePath, LongPathChars);
  429. }
  430. }
  431. }
  432. }
  433. if ( hFile == NULL || hFile == INVALID_HANDLE_VALUE ) {
  434. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  435. return NULL;
  436. }
  437. } else {
  438. Chars = GetLongPathNameW(FilePath, LongPath, LongPathChars);
  439. if (Chars == 0 || Chars >= LongPathChars) {
  440. // Couldn't get the long path, just use the given path.
  441. lstrcpynW(LongPath, FilePath, LongPathChars);
  442. }
  443. }
  444. *Size = GetFileSize(hFile, NULL);
  445. if (*Size == -1) {
  446. CloseHandle( hFile );
  447. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  448. return NULL;
  449. }
  450. hMappedFile = CreateFileMapping (
  451. hFile,
  452. NULL,
  453. PAGE_READONLY,
  454. 0,
  455. 0,
  456. NULL
  457. );
  458. if ( !hMappedFile ) {
  459. CloseHandle ( hFile );
  460. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  461. return NULL;
  462. }
  463. MappedFile = MapViewOfFile (
  464. hMappedFile,
  465. FILE_MAP_READ,
  466. 0,
  467. 0,
  468. 0
  469. );
  470. CloseHandle (hMappedFile);
  471. CloseHandle (hFile);
  472. if (!MappedFile) {
  473. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  474. }
  475. return MappedFile;
  476. }
  477. BOOL
  478. GenGetDataContributors(
  479. IN OUT PINTERNAL_PROCESS Process,
  480. IN PINTERNAL_MODULE Module
  481. )
  482. {
  483. ULONG i;
  484. PIMAGE_SECTION_HEADER NtSection;
  485. BOOL Succ = TRUE;
  486. PVOID MappedBase;
  487. PIMAGE_NT_HEADERS NtHeaders;
  488. ULONG MappedSize;
  489. BOOL AnsiApi;
  490. MappedBase = GenOpenMapping ( Module->FullPath, &MappedSize, NULL, 0 );
  491. if ( MappedBase == NULL ) {
  492. return FALSE;
  493. }
  494. NtHeaders = ImageNtHeader ( MappedBase );
  495. NtSection = IMAGE_FIRST_SECTION ( NtHeaders );
  496. for (i = 0; i < NtHeaders->FileHeader.NumberOfSections; i++) {
  497. if ( (NtSection[ i ].Characteristics & IMAGE_SCN_MEM_WRITE) &&
  498. (NtSection[ i ].Characteristics & IMAGE_SCN_MEM_READ) &&
  499. ( (NtSection[ i ].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) ||
  500. (NtSection[ i ].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) )
  501. ) {
  502. if (!GenAddMemoryBlock(Process, MEMBLOCK_DATA_SEG,
  503. SIGN_EXTEND (NtSection[i].VirtualAddress + Module->BaseOfImage),
  504. NtSection[i].Misc.VirtualSize)) {
  505. Succ = FALSE;
  506. } else {
  507. #if 0
  508. printf ("Section: %8.8s Addr: %08x Size: %08x Raw Size: %08x\n",
  509. NtSection[ i ].Name,
  510. (ULONG)(NtSection[ i ].VirtualAddress + Module->BaseOfImage),
  511. NtSection[ i ].Misc.VirtualSize,
  512. NtSection[ i ].SizeOfRawData
  513. );
  514. #endif
  515. }
  516. }
  517. }
  518. UnmapViewOfFile(MappedBase);
  519. return Succ;
  520. }
  521. HANDLE
  522. GenOpenThread(
  523. DWORD dwDesiredAccess,
  524. BOOL bInheritHandle,
  525. DWORD dwThreadId
  526. )
  527. {
  528. ULONG Type;
  529. ULONG Major;
  530. HANDLE hThread;
  531. //
  532. // First try the OpenThred call in the system, if one exists. This is
  533. // thunked to return NULL via the delay-load import mechanism if it
  534. // doesn't exist.
  535. //
  536. hThread = OpenThread (dwDesiredAccess,
  537. bInheritHandle,
  538. dwThreadId
  539. );
  540. if ( hThread != NULL ) {
  541. return hThread;
  542. }
  543. //
  544. // Did not succeed. Try alternate methods.
  545. //
  546. GenGetSystemType ( &Type, &Major, NULL, NULL, NULL );
  547. if ( Type == WinNt && Major == 4 ) {
  548. hThread = Nt4OpenThread (
  549. dwDesiredAccess,
  550. bInheritHandle,
  551. dwThreadId
  552. );
  553. } else if ( Type == Win9x ) {
  554. //
  555. // The Access and Inheritable parameters are ignored on Win9x.
  556. //
  557. hThread = WinOpenThread (
  558. dwDesiredAccess,
  559. bInheritHandle,
  560. dwThreadId
  561. );
  562. } else {
  563. hThread = NULL;
  564. }
  565. // Errors are sometimes expected due to
  566. // thread instability during initial suspension,
  567. // so do not accumulate status here.
  568. return hThread;
  569. }
  570. HRESULT
  571. GenAllocateThreadObject(
  572. IN struct _INTERNAL_PROCESS* Process,
  573. IN HANDLE ProcessHandle,
  574. IN ULONG ThreadId,
  575. IN ULONG DumpType,
  576. IN ULONG WriteFlags,
  577. PINTERNAL_THREAD* ThreadRet
  578. )
  579. /*++
  580. Routine Description:
  581. Allocate and initialize an INTERNAL_THREAD structure.
  582. Return Values:
  583. S_OK on success.
  584. S_FALSE if the thread can't be opened.
  585. Errors on failure.
  586. --*/
  587. {
  588. HRESULT Succ;
  589. PINTERNAL_THREAD Thread;
  590. ULONG64 StackEnd;
  591. ULONG64 StackLimit;
  592. ULONG64 StoreLimit;
  593. ASSERT ( ProcessHandle );
  594. Thread = (PINTERNAL_THREAD) AllocMemory ( sizeof (INTERNAL_THREAD) );
  595. if (Thread == NULL) {
  596. return E_OUTOFMEMORY;
  597. }
  598. *ThreadRet = Thread;
  599. Thread->ThreadId = ThreadId;
  600. Thread->ThreadHandle = GenOpenThread (
  601. THREAD_ALL_ACCESS,
  602. FALSE,
  603. Thread->ThreadId);
  604. if ( Thread->ThreadHandle == NULL ) {
  605. // The thread may have exited before we got around
  606. // to trying to open it. If the open fails with
  607. // a not-found code return an alternate success to
  608. // indicate that it's not a critical failure.
  609. Succ = HRESULT_FROM_WIN32(GetLastError());
  610. if (Succ == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) ||
  611. Succ == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) {
  612. Succ = S_FALSE;
  613. } else if (SUCCEEDED(Succ)) {
  614. Succ = E_FAIL;
  615. }
  616. if (FAILED(Succ)) {
  617. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  618. }
  619. goto Exit;
  620. }
  621. // If the current thread is dumping itself we can't
  622. // suspend. We can also assume the suspend count must
  623. // be zero since the thread is running.
  624. if (Thread->ThreadId == GetCurrentThreadId()) {
  625. Thread->SuspendCount = 0;
  626. } else {
  627. Thread->SuspendCount = SuspendThread ( Thread->ThreadHandle );
  628. }
  629. Thread->WriteFlags = WriteFlags;
  630. //
  631. // Add this if we ever need it
  632. //
  633. Thread->PriorityClass = 0;
  634. Thread->Priority = 0;
  635. //
  636. // Initialize the thread context.
  637. //
  638. Thread->Context.ContextFlags = ALL_REGISTERS;
  639. Succ = GetThreadContext (Thread->ThreadHandle,
  640. &Thread->Context) ? S_OK : E_FAIL;
  641. if ( Succ != S_OK ) {
  642. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  643. goto Exit;
  644. }
  645. Thread->SizeOfContext = sizeof (CONTEXT);
  646. Succ = GenGetThreadInfo(ProcessHandle,
  647. Thread->ThreadHandle,
  648. &Thread->Teb,
  649. &Thread->SizeOfTeb,
  650. &Thread->StackBase,
  651. &StackLimit,
  652. &Thread->BackingStoreBase,
  653. &StoreLimit);
  654. if (Succ != S_OK) {
  655. goto Exit;
  656. }
  657. //
  658. // If the stack pointer (SP) is within the range of the stack
  659. // region (as allocated by the OS), only take memory from
  660. // the stack region up to the SP. Otherwise, assume the program
  661. // has blown it's SP -- purposefully, or not -- and copy
  662. // the entire stack as known by the OS.
  663. //
  664. StackEnd = SIGN_EXTEND (STACK_POINTER (&Thread->Context));
  665. #if defined (i386)
  666. //
  667. // Note: for FPO frames on x86 we access bytes outside of the
  668. // ESP - StackBase range. Add a couple of bytes extra here so we
  669. // don't fail these cases.
  670. //
  671. StackEnd -= X86_STACK_FRAME_EXTRA_FPO_BYTES;
  672. #endif
  673. #ifdef DUMP_BACKING_STORE
  674. Thread->BackingStoreSize =
  675. (ULONG)(SIGN_EXTEND(BSTORE_POINTER(&Thread->Context)) -
  676. Thread->BackingStoreBase);
  677. #else
  678. Thread->BackingStoreSize = 0;
  679. #endif
  680. if (StackLimit <= StackEnd && StackEnd < Thread->StackBase) {
  681. Thread->StackEnd = StackEnd;
  682. } else {
  683. Thread->StackEnd = StackLimit;
  684. }
  685. if ((ULONG)(Thread->StackBase - Thread->StackEnd) >
  686. Process->MaxStackOrStoreSize) {
  687. Process->MaxStackOrStoreSize =
  688. (ULONG)(Thread->StackBase - Thread->StackEnd);
  689. }
  690. if (Thread->BackingStoreSize > Process->MaxStackOrStoreSize) {
  691. Process->MaxStackOrStoreSize = Thread->BackingStoreSize;
  692. }
  693. Exit:
  694. if ( Succ != S_OK ) {
  695. FreeMemory ( Thread );
  696. }
  697. return Succ;
  698. }
  699. VOID
  700. GenFreeThreadObject(
  701. IN PINTERNAL_THREAD Thread
  702. )
  703. {
  704. if (Thread->SuspendCount != -1 &&
  705. Thread->ThreadId != GetCurrentThreadId()) {
  706. ResumeThread (Thread->ThreadHandle);
  707. Thread->SuspendCount = -1;
  708. }
  709. CloseHandle (Thread->ThreadHandle);
  710. Thread->ThreadHandle = NULL;
  711. FreeMemory ( Thread );
  712. Thread = NULL;
  713. }
  714. BOOL
  715. GenGetThreadInstructionWindow(
  716. IN PINTERNAL_PROCESS Process,
  717. IN PINTERNAL_THREAD Thread
  718. )
  719. {
  720. PVOID MemBuf;
  721. PUCHAR InstrStart;
  722. ULONG InstrSize;
  723. SIZE_T BytesRead;
  724. BOOL Succ = FALSE;
  725. //
  726. // Store a window of the instruction stream around
  727. // the current program counter. This allows some
  728. // instruction context to be given even when images
  729. // can't be mapped. It also allows instruction
  730. // context to be given for generated code where
  731. // no image contains the necessary instructions.
  732. //
  733. InstrStart = (PUCHAR)PROGRAM_COUNTER(&Thread->Context) -
  734. INSTRUCTION_WINDOW_SIZE / 2;
  735. InstrSize = INSTRUCTION_WINDOW_SIZE;
  736. MemBuf = AllocMemory(InstrSize);
  737. if (!MemBuf) {
  738. return FALSE;
  739. }
  740. for (;;) {
  741. // If we can read the instructions through the
  742. // current program counter we'll say that's
  743. // good enough.
  744. if (ReadProcessMemory(Process->ProcessHandle,
  745. InstrStart,
  746. MemBuf,
  747. InstrSize,
  748. &BytesRead) &&
  749. InstrStart + BytesRead >
  750. (PUCHAR)PROGRAM_COUNTER(&Thread->Context)) {
  751. Succ = GenAddMemoryBlock(Process, MEMBLOCK_INSTR_WINDOW,
  752. SIGN_EXTEND(InstrStart),
  753. (ULONG)BytesRead) != NULL;
  754. break;
  755. }
  756. // We couldn't read up to the program counter.
  757. // If the start address is on the previous page
  758. // move it up to the same page.
  759. if (((ULONG_PTR)InstrStart & ~(PAGE_SIZE - 1)) !=
  760. (PROGRAM_COUNTER(&Thread->Context) & ~(PAGE_SIZE - 1))) {
  761. ULONG Fraction = PAGE_SIZE -
  762. (ULONG)(ULONG_PTR)InstrStart & (PAGE_SIZE - 1);
  763. InstrSize -= Fraction;
  764. InstrStart += Fraction;
  765. } else {
  766. // The start and PC were on the same page so
  767. // we just can't read memory. There may have been
  768. // a jump to a bad address or something, so this
  769. // doesn't constitute an unexpected failure.
  770. break;
  771. }
  772. }
  773. FreeMemory(MemBuf);
  774. return Succ;
  775. }
  776. PINTERNAL_MODULE
  777. GenAllocateModuleObject(
  778. IN PINTERNAL_PROCESS Process,
  779. IN PWSTR FullPathW,
  780. IN ULONG_PTR BaseOfModule,
  781. IN ULONG DumpType,
  782. IN ULONG WriteFlags
  783. )
  784. /*++
  785. Routine Description:
  786. Given the full-path to the module and the base of the module, create and
  787. initialize an INTERNAL_MODULE object, and return it.
  788. --*/
  789. {
  790. BOOL Succ;
  791. PVOID MappedBase;
  792. ULONG MappedSize;
  793. PIMAGE_NT_HEADERS NtHeaders;
  794. PINTERNAL_MODULE Module;
  795. ULONG Chars;
  796. BOOL AnsiApi;
  797. ASSERT (FullPathW);
  798. ASSERT (BaseOfModule);
  799. Module = (PINTERNAL_MODULE) AllocMemory ( sizeof (INTERNAL_MODULE) );
  800. if (Module == NULL) {
  801. return NULL;
  802. }
  803. MappedBase = GenOpenMapping ( FullPathW, &MappedSize,
  804. Module->FullPath,
  805. ARRAY_COUNT(Module->FullPath) );
  806. if ( MappedBase == NULL ) {
  807. FreeMemory(Module);
  808. return NULL;
  809. }
  810. if (IsFlagSet(DumpType, MiniDumpFilterModulePaths)) {
  811. Module->SavePath = Module->FullPath + lstrlenW(Module->FullPath);
  812. while (Module->SavePath > Module->FullPath) {
  813. Module->SavePath--;
  814. if (*Module->SavePath == '\\' ||
  815. *Module->SavePath == '/' ||
  816. *Module->SavePath == ':') {
  817. Module->SavePath++;
  818. break;
  819. }
  820. }
  821. } else {
  822. Module->SavePath = Module->FullPath;
  823. }
  824. //
  825. // Cull information from the image header.
  826. //
  827. NtHeaders = ImageNtHeader ( MappedBase );
  828. Module->BaseOfImage = SIGN_EXTEND (BaseOfModule);
  829. Module->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;
  830. Module->CheckSum = NtHeaders->OptionalHeader.CheckSum;
  831. Module->TimeDateStamp = NtHeaders->FileHeader.TimeDateStamp;
  832. Module->WriteFlags = WriteFlags;
  833. //
  834. // Get the version information for the module.
  835. //
  836. Succ = GenGetVersionInfo (
  837. FullPathW,
  838. &Module->VersionInfo
  839. );
  840. if ( !Succ ) {
  841. Module->VersionInfo.dwSignature = 0;
  842. }
  843. //
  844. // Get the CV record from the debug directory.
  845. //
  846. if (IsFlagSet(Module->WriteFlags, ModuleWriteCvRecord)) {
  847. Succ = GenGetDebugRecord(MappedBase,
  848. MappedSize,
  849. NtHeaders,
  850. IMAGE_DEBUG_TYPE_CODEVIEW,
  851. REASONABLE_NB11_RECORD_SIZE,
  852. &Module->CvRecord,
  853. &Module->SizeOfCvRecord);
  854. if ( !Succ ) {
  855. Module->CvRecord = NULL;
  856. Module->SizeOfCvRecord = 0;
  857. }
  858. }
  859. //
  860. // Get the MISC record from the debug directory.
  861. //
  862. if (IsFlagSet(Module->WriteFlags, ModuleWriteMiscRecord)) {
  863. Succ = GenGetDebugRecord(MappedBase,
  864. MappedSize,
  865. NtHeaders,
  866. IMAGE_DEBUG_TYPE_MISC,
  867. REASONABLE_MISC_RECORD_SIZE,
  868. &Module->MiscRecord,
  869. &Module->SizeOfMiscRecord);
  870. if ( !Succ ) {
  871. Module->MiscRecord = NULL;
  872. Module->SizeOfMiscRecord = 0;
  873. }
  874. }
  875. UnmapViewOfFile ( MappedBase );
  876. return Module;
  877. }
  878. VOID
  879. GenFreeModuleObject(
  880. IN PINTERNAL_MODULE Module
  881. )
  882. {
  883. FreeMemory ( Module->CvRecord );
  884. Module->CvRecord = NULL;
  885. FreeMemory ( Module->MiscRecord );
  886. Module->MiscRecord = NULL;
  887. FreeMemory ( Module );
  888. Module = NULL;
  889. }
  890. PINTERNAL_UNLOADED_MODULE
  891. GenAllocateUnloadedModuleObject(
  892. IN PWSTR Path,
  893. IN ULONG_PTR BaseOfModule,
  894. IN ULONG SizeOfModule,
  895. IN ULONG CheckSum,
  896. IN ULONG TimeDateStamp
  897. )
  898. {
  899. PINTERNAL_UNLOADED_MODULE Module;
  900. Module = (PINTERNAL_UNLOADED_MODULE)
  901. AllocMemory ( sizeof (*Module) );
  902. if (Module == NULL) {
  903. return NULL;
  904. }
  905. lstrcpynW (Module->Path, Path, ARRAY_COUNT(Module->Path));
  906. Module->BaseOfImage = SIGN_EXTEND (BaseOfModule);
  907. Module->SizeOfImage = SizeOfModule;
  908. Module->CheckSum = CheckSum;
  909. Module->TimeDateStamp = TimeDateStamp;
  910. return Module;
  911. }
  912. VOID
  913. GenFreeUnloadedModuleObject(
  914. IN PINTERNAL_UNLOADED_MODULE Module
  915. )
  916. {
  917. FreeMemory ( Module );
  918. Module = NULL;
  919. }
  920. typedef BOOL (WINAPI* FN_GetProcessTimes)(
  921. IN HANDLE hProcess,
  922. OUT LPFILETIME lpCreationTime,
  923. OUT LPFILETIME lpExitTime,
  924. OUT LPFILETIME lpKernelTime,
  925. OUT LPFILETIME lpUserTime
  926. );
  927. PINTERNAL_PROCESS
  928. GenAllocateProcessObject(
  929. IN HANDLE hProcess,
  930. IN ULONG ProcessId
  931. )
  932. {
  933. PINTERNAL_PROCESS Process;
  934. FN_GetProcessTimes GetProcTimes;
  935. LPVOID Peb;
  936. Process = (PINTERNAL_PROCESS) AllocMemory ( sizeof (INTERNAL_PROCESS) );
  937. if (!Process) {
  938. return NULL;
  939. }
  940. Process->ProcessId = ProcessId;
  941. Process->ProcessHandle = hProcess;
  942. Process->NumberOfThreads = 0;
  943. Process->NumberOfModules = 0;
  944. Process->NumberOfFunctionTables = 0;
  945. InitializeListHead (&Process->ThreadList);
  946. InitializeListHead (&Process->ModuleList);
  947. InitializeListHead (&Process->UnloadedModuleList);
  948. InitializeListHead (&Process->FunctionTableList);
  949. InitializeListHead (&Process->MemoryBlocks);
  950. GetProcTimes = (FN_GetProcessTimes)
  951. GetProcAddress(GetModuleHandle("kernel32.dll"),
  952. "GetProcessTimes");
  953. if (GetProcTimes) {
  954. FILETIME Create, Exit, User, Kernel;
  955. if (GetProcTimes(hProcess, &Create, &Exit, &User, &Kernel)) {
  956. Process->TimesValid = TRUE;
  957. Process->CreateTime = FileTimeToTimeDate(&Create);
  958. Process->UserTime = FileTimeToSeconds(&User);
  959. Process->KernelTime = FileTimeToSeconds(&Kernel);
  960. } else {
  961. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  962. }
  963. }
  964. Peb = GenGetPebAddress(hProcess, &Process->SizeOfPeb);
  965. Process->Peb = SIGN_EXTEND(Peb);
  966. return Process;
  967. }
  968. BOOL
  969. GenFreeProcessObject(
  970. IN PINTERNAL_PROCESS Process
  971. )
  972. {
  973. PINTERNAL_MODULE Module;
  974. PINTERNAL_UNLOADED_MODULE UnlModule;
  975. PINTERNAL_THREAD Thread;
  976. PINTERNAL_FUNCTION_TABLE Table;
  977. PVA_RANGE Range;
  978. PLIST_ENTRY Entry;
  979. Thread = NULL;
  980. Module = NULL;
  981. Entry = Process->ModuleList.Flink;
  982. while ( Entry != &Process->ModuleList ) {
  983. Module = CONTAINING_RECORD (Entry, INTERNAL_MODULE, ModulesLink);
  984. Entry = Entry->Flink;
  985. GenFreeModuleObject ( Module );
  986. Module = NULL;
  987. }
  988. Entry = Process->UnloadedModuleList.Flink;
  989. while ( Entry != &Process->UnloadedModuleList ) {
  990. UnlModule = CONTAINING_RECORD (Entry, INTERNAL_UNLOADED_MODULE,
  991. ModulesLink);
  992. Entry = Entry->Flink;
  993. GenFreeUnloadedModuleObject ( UnlModule );
  994. UnlModule = NULL;
  995. }
  996. Entry = Process->ThreadList.Flink;
  997. while ( Entry != &Process->ThreadList ) {
  998. Thread = CONTAINING_RECORD (Entry, INTERNAL_THREAD, ThreadsLink);
  999. Entry = Entry->Flink;
  1000. if (Thread->SuspendCount != -1) {
  1001. GenFreeThreadObject ( Thread );
  1002. Thread = NULL;
  1003. }
  1004. }
  1005. Entry = Process->FunctionTableList.Flink;
  1006. while ( Entry != &Process->FunctionTableList ) {
  1007. Table = CONTAINING_RECORD (Entry, INTERNAL_FUNCTION_TABLE, TableLink);
  1008. Entry = Entry->Flink;
  1009. GenFreeFunctionTableObject ( Table );
  1010. }
  1011. Entry = Process->MemoryBlocks.Flink;
  1012. while (Entry != &Process->MemoryBlocks) {
  1013. Range = CONTAINING_RECORD(Entry, VA_RANGE, NextLink);
  1014. Entry = Entry->Flink;
  1015. FreeMemory(Range);
  1016. }
  1017. FreeMemory ( Process );
  1018. Process = NULL;
  1019. return TRUE;
  1020. }
  1021. struct _INTERNAL_FUNCTION_TABLE*
  1022. GenAllocateFunctionTableObject(
  1023. IN ULONG64 MinAddress,
  1024. IN ULONG64 MaxAddress,
  1025. IN ULONG64 BaseAddress,
  1026. IN ULONG EntryCount,
  1027. IN PDYNAMIC_FUNCTION_TABLE RawTable
  1028. )
  1029. {
  1030. PINTERNAL_FUNCTION_TABLE Table;
  1031. Table = (PINTERNAL_FUNCTION_TABLE)
  1032. AllocMemory ( sizeof (INTERNAL_FUNCTION_TABLE) );
  1033. if (Table) {
  1034. Table->RawEntries = AllocMemory(sizeof(RUNTIME_FUNCTION) * EntryCount);
  1035. if (Table->RawEntries) {
  1036. Table->MinimumAddress = MinAddress;
  1037. Table->MaximumAddress = MaxAddress;
  1038. Table->BaseAddress = BaseAddress;
  1039. Table->EntryCount = EntryCount;
  1040. Table->RawTable = *RawTable;
  1041. // RawEntries will be filled out afterwards.
  1042. } else {
  1043. FreeMemory(Table);
  1044. Table = NULL;
  1045. }
  1046. }
  1047. return Table;
  1048. }
  1049. VOID
  1050. GenFreeFunctionTableObject(
  1051. IN struct _INTERNAL_FUNCTION_TABLE* Table
  1052. )
  1053. {
  1054. if (Table->RawEntries) {
  1055. FreeMemory(Table->RawEntries);
  1056. }
  1057. FreeMemory(Table);
  1058. }
  1059. BOOL
  1060. GenIncludeUnwindInfoMemory(
  1061. IN PINTERNAL_PROCESS Process,
  1062. IN ULONG DumpType,
  1063. IN struct _INTERNAL_FUNCTION_TABLE* Table
  1064. )
  1065. {
  1066. ULONG i;
  1067. PRUNTIME_FUNCTION FuncEnt;
  1068. if (DumpType & MiniDumpWithFullMemory) {
  1069. // Memory will be included by default.
  1070. return TRUE;
  1071. }
  1072. // This code only needs to scan IA64 and AMD64 tables.
  1073. #if !defined(_IA64_) && !defined(_AMD64_)
  1074. return TRUE;
  1075. #endif
  1076. FuncEnt = (PRUNTIME_FUNCTION)Table->RawEntries;
  1077. for (i = 0; i < Table->EntryCount; i++) {
  1078. #if defined(_IA64_) || defined(_AMD64_)
  1079. SIZE_T Done;
  1080. UNWIND_INFO Info;
  1081. ULONG64 Start;
  1082. ULONG Size;
  1083. #endif
  1084. #if defined(_IA64_)
  1085. Start = Table->BaseAddress + FuncEnt->UnwindInfoAddress;
  1086. if (!ReadProcessMemory(Process->ProcessHandle, (PVOID)Start,
  1087. &Info, sizeof(Info), &Done) ||
  1088. Done != sizeof(Info)) {
  1089. GenAccumulateStatus(MDSTATUS_UNABLE_TO_READ_MEMORY);
  1090. return FALSE;
  1091. }
  1092. Size = sizeof(Info) + Info.DataLength * sizeof(ULONG64);
  1093. #elif defined(_AMD64_)
  1094. Start = Table->BaseAddress + FuncEnt->UnwindData;
  1095. if (!ReadProcessMemory(Process->ProcessHandle, (PVOID)Start,
  1096. &Info, sizeof(Info), &Done) ||
  1097. Done != sizeof(Info)) {
  1098. GenAccumulateStatus(MDSTATUS_UNABLE_TO_READ_MEMORY);
  1099. return FALSE;
  1100. }
  1101. Size = sizeof(Info) +
  1102. (Info.CountOfCodes - 1) * sizeof(UNWIND_CODE);
  1103. // An extra alignment code and pointer may be added on to handle
  1104. // the chained info case where the chain pointer is just
  1105. // beyond the end of the normal code array.
  1106. if ((Info.Flags & UNW_FLAG_CHAININFO) != 0) {
  1107. if ((Info.CountOfCodes & 1) != 0) {
  1108. Size += sizeof(UNWIND_CODE);
  1109. }
  1110. Size += sizeof(ULONG64);
  1111. }
  1112. #endif
  1113. #if defined(_IA64_) || defined(_AMD64_)
  1114. if (!GenAddMemoryBlock(Process, MEMBLOCK_UNWIND_INFO, Start, Size)) {
  1115. return FALSE;
  1116. }
  1117. #endif
  1118. FuncEnt++;
  1119. }
  1120. return TRUE;
  1121. }
  1122. PVOID
  1123. GenGetTebAddress(
  1124. IN HANDLE Thread,
  1125. OUT PULONG SizeOfTeb
  1126. )
  1127. /*++
  1128. Routine Description:
  1129. Get the TIB (or TEB, if you prefer) address for the thread identified
  1130. by ThreadHandle.
  1131. Arguments:
  1132. Thread - A handle for a thread that has THRED_QUERY_CONTEXT and
  1133. THREAD_QUERY_INFORMATION privileges.
  1134. Return Values:
  1135. Linear address of the Tib (Teb) on success.
  1136. NULL on failure.
  1137. --*/
  1138. {
  1139. LPVOID TebAddress;
  1140. ULONG Type;
  1141. ULONG Major;
  1142. GenGetSystemType (&Type, &Major, NULL, NULL, NULL);
  1143. if ( Type == WinNt ) {
  1144. TebAddress = NtxGetTebAddress (Thread, SizeOfTeb);
  1145. } else if ( Type != Win9x ) {
  1146. // WinCE doesn't have a TIB.
  1147. TebAddress = NULL;
  1148. *SizeOfTeb = 0;
  1149. } else {
  1150. #ifdef _X86_
  1151. BOOL Succ;
  1152. ULONG Addr;
  1153. LDT_ENTRY Ldt;
  1154. CONTEXT Context;
  1155. Context.ContextFlags = CONTEXT_SEGMENTS;
  1156. Succ = GetThreadContext (Thread, &Context);
  1157. if ( !Succ ) {
  1158. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  1159. return NULL;
  1160. }
  1161. Succ = GetThreadSelectorEntry (Thread,
  1162. Context.SegFs,
  1163. &Ldt
  1164. );
  1165. if ( !Succ ) {
  1166. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  1167. return NULL;
  1168. }
  1169. Addr = (Ldt.HighWord.Bytes.BaseHi << 24) |
  1170. (Ldt.HighWord.Bytes.BaseMid << 16) |
  1171. (Ldt.BaseLow);
  1172. TebAddress = (LPVOID) Addr;
  1173. *SizeOfTeb = sizeof(NT_TIB);
  1174. #else
  1175. TebAddress = NULL;
  1176. *SizeOfTeb = 0;
  1177. #endif // _X86_
  1178. }
  1179. return TebAddress;
  1180. }
  1181. PVOID
  1182. GenGetPebAddress(
  1183. IN HANDLE Process,
  1184. OUT PULONG SizeOfPeb
  1185. )
  1186. {
  1187. LPVOID PebAddress;
  1188. ULONG Type;
  1189. ULONG Major;
  1190. GenGetSystemType (&Type, &Major, NULL, NULL, NULL);
  1191. if ( Type == WinNt ) {
  1192. PebAddress = NtxGetPebAddress (Process, SizeOfPeb);
  1193. } else if ( Type == WinCe ) {
  1194. PebAddress = WceGetPebAddress (Process, SizeOfPeb);
  1195. } else {
  1196. // No process data.
  1197. PebAddress = NULL;
  1198. *SizeOfPeb = 0;
  1199. }
  1200. return PebAddress;
  1201. }
  1202. HRESULT
  1203. GenGetThreadInfo(
  1204. IN HANDLE Process,
  1205. IN HANDLE Thread,
  1206. OUT PULONG64 Teb,
  1207. OUT PULONG SizeOfTeb,
  1208. OUT PULONG64 StackBase,
  1209. OUT PULONG64 StackLimit,
  1210. OUT PULONG64 StoreBase,
  1211. OUT PULONG64 StoreLimit
  1212. )
  1213. {
  1214. ULONG Type;
  1215. GenGetSystemType (&Type, NULL, NULL, NULL, NULL);
  1216. if ( Type == WinCe ) {
  1217. return WceGetThreadInfo(Process, Thread,
  1218. Teb, SizeOfTeb,
  1219. StackBase, StackLimit,
  1220. StoreBase, StoreLimit);
  1221. } else {
  1222. LPVOID TebAddress = GenGetTebAddress (Thread, SizeOfTeb);
  1223. if (!TebAddress) {
  1224. return E_FAIL;
  1225. }
  1226. *Teb = SIGN_EXTEND((LONG_PTR)TebAddress);
  1227. return TibGetThreadInfo(Process, TebAddress,
  1228. StackBase, StackLimit,
  1229. StoreBase, StoreLimit);
  1230. }
  1231. }
  1232. void
  1233. GenRemoveMemoryBlock(
  1234. IN PINTERNAL_PROCESS Process,
  1235. IN PVA_RANGE Block
  1236. )
  1237. {
  1238. RemoveEntryList(&Block->NextLink);
  1239. Process->NumberOfMemoryBlocks--;
  1240. Process->SizeOfMemoryBlocks -= Block->Size;
  1241. }
  1242. PVA_RANGE
  1243. GenAddMemoryBlock(
  1244. IN PINTERNAL_PROCESS Process,
  1245. IN MEMBLOCK_TYPE Type,
  1246. IN ULONG64 Start,
  1247. IN ULONG Size
  1248. )
  1249. {
  1250. ULONG64 End;
  1251. PLIST_ENTRY ScanEntry;
  1252. PVA_RANGE Scan;
  1253. ULONG64 ScanEnd;
  1254. PVA_RANGE New = NULL;
  1255. SIZE_T Done;
  1256. UCHAR Byte;
  1257. // Do not use Size after this to avoid ULONG overflows.
  1258. End = Start + Size;
  1259. if (End < Start) {
  1260. End = (ULONG64)-1;
  1261. }
  1262. if (Start == End) {
  1263. // Nothing to add.
  1264. return NULL;
  1265. }
  1266. if ((End - Start) > ULONG_MAX - Process->SizeOfMemoryBlocks) {
  1267. // Overflow.
  1268. GenAccumulateStatus(MDSTATUS_INTERNAL_ERROR);
  1269. return NULL;
  1270. }
  1271. //
  1272. // First trim the range down to memory that can actually
  1273. // be accessed.
  1274. //
  1275. while (Start < End) {
  1276. if (ReadProcessMemory(Process->ProcessHandle,
  1277. (PVOID)(ULONG_PTR)Start,
  1278. &Byte, sizeof(Byte), &Done) && Done) {
  1279. break;
  1280. }
  1281. // Move up to the next page.
  1282. Start = (Start + PAGE_SIZE) & ~(PAGE_SIZE - 1);
  1283. if (!Start) {
  1284. // Wrapped around.
  1285. return NULL;
  1286. }
  1287. }
  1288. if (Start >= End) {
  1289. // No valid memory.
  1290. return NULL;
  1291. }
  1292. ScanEnd = (Start + PAGE_SIZE) & ~(PAGE_SIZE - 1);
  1293. for (;;) {
  1294. if (ScanEnd >= End) {
  1295. break;
  1296. }
  1297. if (!ReadProcessMemory(Process->ProcessHandle,
  1298. (PVOID)(ULONG_PTR)ScanEnd,
  1299. &Byte, sizeof(Byte), &Done) || !Done) {
  1300. End = ScanEnd;
  1301. break;
  1302. }
  1303. // Move up to the next page.
  1304. ScanEnd = (ScanEnd + PAGE_SIZE) & ~(PAGE_SIZE - 1);
  1305. if (!ScanEnd) {
  1306. ScanEnd--;
  1307. break;
  1308. }
  1309. }
  1310. //
  1311. // When adding memory to the list of memory to be saved
  1312. // we want to avoid overlaps and also coalesce adjacent regions
  1313. // so that the list has the largest possible non-adjacent
  1314. // blocks. In order to accomplish this we make a pass over
  1315. // the list and merge all listed blocks that overlap or abut the
  1316. // incoming range with the incoming range, then remove the
  1317. // merged entries from the list. After this pass we have
  1318. // a region which is guaranteed not to overlap or abut anything in
  1319. // the list.
  1320. //
  1321. ScanEntry = Process->MemoryBlocks.Flink;
  1322. while (ScanEntry != &Process->MemoryBlocks) {
  1323. Scan = CONTAINING_RECORD(ScanEntry, VA_RANGE, NextLink);
  1324. ScanEnd = Scan->Start + Scan->Size;
  1325. ScanEntry = Scan->NextLink.Flink;
  1326. if (Scan->Start > End || ScanEnd < Start) {
  1327. // No overlap or adjacency.
  1328. continue;
  1329. }
  1330. //
  1331. // Compute the union of the incoming range and
  1332. // the scan block, then remove the scan block.
  1333. //
  1334. if (Scan->Start < Start) {
  1335. Start = Scan->Start;
  1336. }
  1337. if (ScanEnd > End) {
  1338. End = ScanEnd;
  1339. }
  1340. // We've lost the specific type. This is not a problem
  1341. // right now but if specific types must be preserved
  1342. // all the way through in the future it will be necessary
  1343. // to avoid merging.
  1344. Type = MEMBLOCK_MERGED;
  1345. GenRemoveMemoryBlock(Process, Scan);
  1346. if (!New) {
  1347. // Save memory for reuse.
  1348. New = Scan;
  1349. } else {
  1350. FreeMemory(Scan);
  1351. }
  1352. }
  1353. if (!New) {
  1354. New = (PVA_RANGE)AllocMemory(sizeof(*New));
  1355. if (!New) {
  1356. return NULL;
  1357. }
  1358. }
  1359. New->Start = Start;
  1360. // Overflow is extremely unlikely, so don't do anything
  1361. // fancy to handle it.
  1362. if (End - Start > ULONG_MAX) {
  1363. New->Size = ULONG_MAX;
  1364. } else {
  1365. New->Size = (ULONG)(End - Start);
  1366. }
  1367. New->Type = Type;
  1368. InsertTailList(&Process->MemoryBlocks, &New->NextLink);
  1369. Process->NumberOfMemoryBlocks++;
  1370. Process->SizeOfMemoryBlocks += New->Size;
  1371. return New;
  1372. }
  1373. void
  1374. GenRemoveMemoryRange(
  1375. IN PINTERNAL_PROCESS Process,
  1376. IN ULONG64 Start,
  1377. IN ULONG Size
  1378. )
  1379. {
  1380. ULONG64 End = Start + Size;
  1381. PLIST_ENTRY ScanEntry;
  1382. PVA_RANGE Scan;
  1383. ULONG64 ScanEnd;
  1384. Restart:
  1385. ScanEntry = Process->MemoryBlocks.Flink;
  1386. while (ScanEntry != &Process->MemoryBlocks) {
  1387. Scan = CONTAINING_RECORD(ScanEntry, VA_RANGE, NextLink);
  1388. ScanEnd = Scan->Start + Scan->Size;
  1389. ScanEntry = Scan->NextLink.Flink;
  1390. if (Scan->Start >= End || ScanEnd <= Start) {
  1391. // No overlap.
  1392. continue;
  1393. }
  1394. if (Scan->Start < Start) {
  1395. // Trim block to non-overlapping pre-Start section.
  1396. Scan->Size = (ULONG)(Start - Scan->Start);
  1397. if (ScanEnd > End) {
  1398. // There's also a non-overlapping section post-End.
  1399. // We need to add a new block.
  1400. GenAddMemoryBlock(Process, Scan->Type,
  1401. End, (ULONG)(ScanEnd - End));
  1402. // The list has changed so restart.
  1403. goto Restart;
  1404. }
  1405. } else if (ScanEnd > End) {
  1406. // Trim block to non-overlapping post-End section.
  1407. Scan->Start = End;
  1408. Scan->Size = (ULONG)(ScanEnd - End);
  1409. } else {
  1410. // Scan is completely contained.
  1411. GenRemoveMemoryBlock(Process, Scan);
  1412. FreeMemory(Scan);
  1413. }
  1414. }
  1415. }
  1416. VOID
  1417. WINAPI
  1418. GenGetSystemType(
  1419. OUT ULONG * Type, OPTIONAL
  1420. OUT ULONG * Major, OPTIONAL
  1421. OUT ULONG * Minor, OPTIONAL
  1422. OUT ULONG * ServicePack, OPTIONAL
  1423. OUT ULONG * BuildNumber OPTIONAL
  1424. )
  1425. {
  1426. OSVERSIONINFO Version;
  1427. Version.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  1428. GetVersionEx (&Version);
  1429. if (Type) {
  1430. if (Version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
  1431. *Type = Win9x;
  1432. } else if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  1433. *Type = WinNt;
  1434. } else if (Version.dwPlatformId == VER_PLATFORM_WIN32_CE) {
  1435. *Type = WinCe;
  1436. } else {
  1437. *Type = Unknown;
  1438. }
  1439. }
  1440. if (Major) {
  1441. if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT ||
  1442. Version.dwPlatformId == VER_PLATFORM_WIN32_CE) {
  1443. *Major = Version.dwMajorVersion;
  1444. } else {
  1445. if (Version.dwMinorVersion == 0) {
  1446. *Major = 95;
  1447. } else {
  1448. *Major = 98;
  1449. }
  1450. }
  1451. }
  1452. if (Minor) {
  1453. if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT ||
  1454. Version.dwPlatformId == VER_PLATFORM_WIN32_CE) {
  1455. *Minor = Version.dwMinorVersion;
  1456. } else {
  1457. *Minor = 0;
  1458. }
  1459. }
  1460. //
  1461. // TODO: Derive this from known build numbers only if it's necessary
  1462. // for external stuff.
  1463. //
  1464. if (ServicePack) {
  1465. *ServicePack = 0;
  1466. }
  1467. if (BuildNumber) {
  1468. *BuildNumber = Version.dwBuildNumber;
  1469. }
  1470. }
  1471. BOOL
  1472. GenScanAddressSpace(
  1473. IN PINTERNAL_PROCESS Process,
  1474. IN ULONG DumpType
  1475. )
  1476. {
  1477. ULONG ProtectMask = 0, TypeMask = 0;
  1478. BOOL Succ;
  1479. ULONG_PTR Offset;
  1480. MEMORY_BASIC_INFORMATION Info;
  1481. if (DumpType & MiniDumpWithPrivateReadWriteMemory) {
  1482. ProtectMask |= PAGE_READWRITE;
  1483. TypeMask |= MEM_PRIVATE;
  1484. }
  1485. if (!ProtectMask || !TypeMask) {
  1486. // Nothing to scan for.
  1487. return TRUE;
  1488. }
  1489. Succ = TRUE;
  1490. Offset = 0;
  1491. for (;;) {
  1492. if (!VirtualQueryEx(Process->ProcessHandle, (LPVOID)Offset,
  1493. &Info, sizeof(Info))) {
  1494. break;
  1495. }
  1496. Offset = (ULONG_PTR)Info.BaseAddress + Info.RegionSize;
  1497. if (Info.State == MEM_COMMIT &&
  1498. (Info.Protect & ProtectMask) &&
  1499. (Info.Type & TypeMask)) {
  1500. while (Info.RegionSize > 0) {
  1501. ULONG BlockSize;
  1502. if (Info.RegionSize > ULONG_MAX / 2) {
  1503. BlockSize = ULONG_MAX / 2;
  1504. } else {
  1505. BlockSize = (ULONG)Info.RegionSize;
  1506. }
  1507. if (!GenAddMemoryBlock(Process, MEMBLOCK_PRIVATE_RW,
  1508. SIGN_EXTEND(Info.BaseAddress),
  1509. BlockSize)) {
  1510. Succ = FALSE;
  1511. }
  1512. Info.BaseAddress = (PVOID)
  1513. ((ULONG_PTR)Info.BaseAddress + BlockSize);
  1514. Info.RegionSize -= BlockSize;
  1515. }
  1516. }
  1517. }
  1518. return Succ;
  1519. }
  1520. BOOL
  1521. GenGetProcessInfo(
  1522. IN HANDLE hProcess,
  1523. IN ULONG ProcessId,
  1524. IN ULONG DumpType,
  1525. IN MINIDUMP_CALLBACK_ROUTINE CallbackRoutine,
  1526. IN PVOID CallbackParam,
  1527. OUT PINTERNAL_PROCESS * ProcessRet
  1528. )
  1529. {
  1530. BOOL Succ;
  1531. ULONG Type;
  1532. ULONG Major;
  1533. GenGetSystemType (&Type, &Major, NULL, NULL, NULL);
  1534. if ( Type == WinNt && Major > 4 ) {
  1535. Succ = NtxGetProcessInfo (hProcess, ProcessId, DumpType,
  1536. CallbackRoutine, CallbackParam,
  1537. ProcessRet);
  1538. } else if ( Type == WinNt && Major == 4 ) {
  1539. Succ = Nt4GetProcessInfo (hProcess, ProcessId, DumpType,
  1540. CallbackRoutine, CallbackParam,
  1541. ProcessRet);
  1542. } else if ( Type == Win9x || Type == WinCe ) {
  1543. Succ = ThGetProcessInfo (hProcess, ProcessId, DumpType,
  1544. CallbackRoutine, CallbackParam,
  1545. ProcessRet);
  1546. } else {
  1547. Succ = FALSE;
  1548. }
  1549. if (Succ) {
  1550. // We don't consider a failure here to be a critical
  1551. // failure. The dump won't contain all of the
  1552. // requested information but it'll still have
  1553. // the basic thread information, which could be
  1554. // valuable on its own.
  1555. GenScanAddressSpace(*ProcessRet, DumpType);
  1556. }
  1557. return Succ;
  1558. }
  1559. BOOL
  1560. GenWriteHandleData(
  1561. IN HANDLE ProcessHandle,
  1562. IN HANDLE hFile,
  1563. IN struct _MINIDUMP_STREAM_INFO * StreamInfo
  1564. )
  1565. {
  1566. BOOL Succ;
  1567. ULONG Type;
  1568. ULONG Major;
  1569. GenGetSystemType(&Type, &Major, NULL, NULL, NULL);
  1570. if ( Type == WinNt ) {
  1571. Succ = NtxWriteHandleData(ProcessHandle, hFile, StreamInfo);
  1572. } else {
  1573. Succ = FALSE;
  1574. }
  1575. return Succ;
  1576. }
  1577. ULONG
  1578. CheckSum (
  1579. IN ULONG PartialSum,
  1580. IN PVOID SourceVa,
  1581. IN ULONG_PTR Length
  1582. )
  1583. /*++
  1584. Routine Description:
  1585. Computes a checksum for the supplied virtual address and length
  1586. This function comes from Dr. Dobbs Journal, May 1992
  1587. Arguments:
  1588. PartialSum - The previous partial checksum
  1589. SourceVa - Starting address
  1590. Length - Length, in bytes, of the range
  1591. Return Value:
  1592. The checksum value
  1593. --*/
  1594. {
  1595. PUSHORT Source;
  1596. Source = (PUSHORT) SourceVa;
  1597. Length = Length / 2;
  1598. while (Length--) {
  1599. PartialSum += *Source++;
  1600. PartialSum = (PartialSum >> 16) + (PartialSum & 0xFFFF);
  1601. }
  1602. return PartialSum;
  1603. }
  1604. BOOL
  1605. ThGetProcessInfo(
  1606. IN HANDLE hProcess,
  1607. IN ULONG ProcessId,
  1608. IN ULONG DumpType,
  1609. IN MINIDUMP_CALLBACK_ROUTINE CallbackRoutine,
  1610. IN PVOID CallbackParam,
  1611. OUT PINTERNAL_PROCESS * ProcessRet
  1612. )
  1613. /*++
  1614. Routine Description:
  1615. Using toolhelp, obtain the process information for this process.
  1616. As toolhelp provides an abstraction for retrieval, this
  1617. code is "generic" and can run on any platform supporting toolhelp.
  1618. Return Values:
  1619. TRUE - Success.
  1620. FALSE - Failure:
  1621. Environment:
  1622. Any platform that supports toolhelp.
  1623. --*/
  1624. {
  1625. BOOL Succ;
  1626. BOOL MoreThreads;
  1627. BOOL MoreModules;
  1628. HANDLE Snapshot;
  1629. MODULEENTRY32 ModuleInfo;
  1630. THREADENTRY32 ThreadInfo;
  1631. PINTERNAL_THREAD Thread;
  1632. PINTERNAL_PROCESS Process;
  1633. PINTERNAL_MODULE Module;
  1634. WCHAR UnicodePath [ MAX_PATH + 10 ];
  1635. ASSERT ( hProcess );
  1636. ASSERT ( ProcessId != 0 );
  1637. ASSERT ( ProcessRet );
  1638. Process = NULL;
  1639. Thread = NULL;
  1640. Module = NULL;
  1641. Snapshot = NULL;
  1642. ModuleInfo.dwSize = sizeof (MODULEENTRY32);
  1643. ThreadInfo.dwSize = sizeof (THREADENTRY32);
  1644. Process = GenAllocateProcessObject ( hProcess, ProcessId );
  1645. if ( Process == NULL ) {
  1646. return FALSE;
  1647. }
  1648. Snapshot = CreateToolhelp32Snapshot (
  1649. TH32CS_SNAPMODULE | TH32CS_SNAPTHREAD,
  1650. ProcessId
  1651. );
  1652. if ( Snapshot == (HANDLE) -1 ) {
  1653. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  1654. Succ = FALSE;
  1655. goto Exit;
  1656. }
  1657. //
  1658. // Walk thread list, suspending all threads and getting thread info.
  1659. //
  1660. for (MoreThreads = ProcessThread32First (Snapshot, ProcessId, &ThreadInfo );
  1661. MoreThreads;
  1662. MoreThreads = ProcessThread32Next ( Snapshot, ProcessId, &ThreadInfo ) ) {
  1663. HRESULT Status;
  1664. ULONG WriteFlags;
  1665. if (!GenExecuteIncludeThreadCallback(hProcess,
  1666. ProcessId,
  1667. DumpType,
  1668. ThreadInfo.th32ThreadID,
  1669. CallbackRoutine,
  1670. CallbackParam,
  1671. &WriteFlags) ||
  1672. IsFlagClear(WriteFlags, ThreadWriteThread)) {
  1673. continue;
  1674. }
  1675. Status = GenAllocateThreadObject (
  1676. Process,
  1677. hProcess,
  1678. ThreadInfo.th32ThreadID,
  1679. DumpType,
  1680. WriteFlags,
  1681. &Thread
  1682. );
  1683. if ( FAILED(Status) ) {
  1684. Succ = FALSE;
  1685. goto Exit;
  1686. }
  1687. // If Status is S_FALSE it means that the thread
  1688. // couldn't be opened and probably exited before
  1689. // we got to it. Just continue on.
  1690. if (Status == S_OK) {
  1691. Process->NumberOfThreads++;
  1692. InsertTailList (&Process->ThreadList, &Thread->ThreadsLink);
  1693. }
  1694. }
  1695. //
  1696. // Walk module list, getting module information.
  1697. //
  1698. for (MoreModules = Module32First ( Snapshot, &ModuleInfo );
  1699. MoreModules;
  1700. MoreModules = Module32Next ( Snapshot, &ModuleInfo ) ) {
  1701. ULONG WriteFlags;
  1702. ASSERT ( (ULONG_PTR)ModuleInfo.modBaseAddr == (ULONG_PTR)ModuleInfo.hModule );
  1703. if (!GenExecuteIncludeModuleCallback(hProcess,
  1704. ProcessId,
  1705. DumpType,
  1706. (LONG_PTR)ModuleInfo.modBaseAddr,
  1707. CallbackRoutine,
  1708. CallbackParam,
  1709. &WriteFlags) ||
  1710. IsFlagClear(WriteFlags, ModuleWriteModule)) {
  1711. continue;
  1712. }
  1713. MultiByteToWideChar (CP_ACP,
  1714. 0,
  1715. ModuleInfo.szExePath,
  1716. -1,
  1717. UnicodePath,
  1718. ARRAY_COUNT(UnicodePath)
  1719. );
  1720. Module = GenAllocateModuleObject (
  1721. Process,
  1722. UnicodePath,
  1723. (LONG_PTR) ModuleInfo.modBaseAddr,
  1724. DumpType,
  1725. WriteFlags
  1726. );
  1727. if ( Module == NULL ) {
  1728. Succ = FALSE;
  1729. goto Exit;
  1730. }
  1731. Process->NumberOfModules++;
  1732. InsertTailList (&Process->ModuleList, &Module->ModulesLink);
  1733. }
  1734. Succ = TRUE;
  1735. Exit:
  1736. if ( Snapshot ) {
  1737. CloseHandle ( Snapshot );
  1738. Snapshot = NULL;
  1739. }
  1740. if ( !Succ && Process != NULL ) {
  1741. GenFreeProcessObject ( Process );
  1742. Process = NULL;
  1743. }
  1744. *ProcessRet = Process;
  1745. return Succ;
  1746. }