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

4986 lines
155 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Dump file writing.
  4. //
  5. // Copyright (C) Microsoft Corporation, 2001-2002.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. #include <uminiprov.hpp>
  10. #include <dbgver.h>
  11. #include <bugcodes.h>
  12. #define GENERIC_FORMATS \
  13. (DEBUG_FORMAT_WRITE_CAB | \
  14. DEBUG_FORMAT_CAB_SECONDARY_FILES | \
  15. DEBUG_FORMAT_NO_OVERWRITE)
  16. #define UMINI_FORMATS \
  17. (DEBUG_FORMAT_USER_SMALL_FULL_MEMORY | \
  18. DEBUG_FORMAT_USER_SMALL_HANDLE_DATA | \
  19. DEBUG_FORMAT_USER_SMALL_UNLOADED_MODULES | \
  20. DEBUG_FORMAT_USER_SMALL_INDIRECT_MEMORY | \
  21. DEBUG_FORMAT_USER_SMALL_DATA_SEGMENTS | \
  22. DEBUG_FORMAT_USER_SMALL_FILTER_MEMORY | \
  23. DEBUG_FORMAT_USER_SMALL_FILTER_PATHS | \
  24. DEBUG_FORMAT_USER_SMALL_PROCESS_THREAD_DATA | \
  25. DEBUG_FORMAT_USER_SMALL_PRIVATE_READ_WRITE_MEMORY)
  26. // Internal format flag for testing of microdumps. This
  27. // will not be made into a public flag and must not conflict
  28. // with them.
  29. #define FORMAT_USER_MICRO 0x01000000
  30. //----------------------------------------------------------------------------
  31. //
  32. // UserFullDumpTargetInfo::Write.
  33. //
  34. //----------------------------------------------------------------------------
  35. #define USER_DUMP_MEMORY_BUFFER 65536
  36. struct CREATE_USER_DUMP_STATE
  37. {
  38. ThreadInfo* Thread;
  39. ImageInfo* Image;
  40. ULONG64 MemHandle;
  41. HANDLE DumpFileHandle;
  42. MEMORY_BASIC_INFORMATION64 MemInfo;
  43. MEMORY_BASIC_INFORMATION32 MemInfo32;
  44. ULONG64 MemBufDone;
  45. ULONG64 TotalMemQueried;
  46. ULONG64 TotalMemData;
  47. CROSS_PLATFORM_CONTEXT TargetContext;
  48. DEBUG_EVENT Event;
  49. CRASH_THREAD CrashThread;
  50. ULONG64 MemBuf[USER_DUMP_MEMORY_BUFFER / sizeof(ULONG64)];
  51. };
  52. BOOL WINAPI
  53. CreateUserDumpCallback(
  54. ULONG DataType,
  55. PVOID* Data,
  56. PULONG DataLength,
  57. PVOID UserData
  58. )
  59. {
  60. CREATE_USER_DUMP_STATE* State = (CREATE_USER_DUMP_STATE*)UserData;
  61. ThreadInfo* Thread;
  62. switch(DataType)
  63. {
  64. case DMP_DUMP_FILE_HANDLE:
  65. *Data = State->DumpFileHandle;
  66. *DataLength = sizeof(HANDLE);
  67. break;
  68. case DMP_DEBUG_EVENT:
  69. ADDR PcAddr;
  70. //
  71. // Fake up an exception event for the current thread.
  72. //
  73. ZeroMemory(&State->Event, sizeof(State->Event));
  74. g_Machine->GetPC(&PcAddr);
  75. State->Event.dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
  76. State->Event.dwProcessId = g_Process->m_SystemId;
  77. State->Event.dwThreadId = g_Thread->m_SystemId;
  78. if (g_LastEventType == DEBUG_EVENT_EXCEPTION)
  79. {
  80. // Use the exception record from the last exception.
  81. ExceptionRecord64To(&g_LastEventInfo.Exception.ExceptionRecord,
  82. &State->Event.u.Exception.ExceptionRecord);
  83. State->Event.u.Exception.dwFirstChance =
  84. g_LastEventInfo.Exception.FirstChance;
  85. }
  86. else
  87. {
  88. // Fake a breakpoint exception.
  89. State->Event.u.Exception.ExceptionRecord.ExceptionCode =
  90. STATUS_BREAKPOINT;
  91. State->Event.u.Exception.ExceptionRecord.ExceptionAddress =
  92. (PVOID)(ULONG_PTR)Flat(PcAddr);
  93. State->Event.u.Exception.dwFirstChance = TRUE;
  94. }
  95. *Data = &State->Event;
  96. *DataLength = sizeof(State->Event);
  97. break;
  98. case DMP_THREAD_STATE:
  99. ULONG64 Teb64;
  100. if (State->Thread == NULL)
  101. {
  102. Thread = g_Process->m_ThreadHead;
  103. }
  104. else
  105. {
  106. Thread = State->Thread->m_Next;
  107. }
  108. State->Thread = Thread;
  109. if (Thread == NULL)
  110. {
  111. return FALSE;
  112. }
  113. ZeroMemory(&State->CrashThread, sizeof(State->CrashThread));
  114. State->CrashThread.ThreadId = Thread->m_SystemId;
  115. State->CrashThread.SuspendCount = Thread->m_SuspendCount;
  116. if (IS_LIVE_USER_TARGET(g_Target))
  117. {
  118. if (g_Target->m_ClassQualifier ==
  119. DEBUG_USER_WINDOWS_PROCESS_SERVER)
  120. {
  121. // The priority information isn't important
  122. // enough to warrant remoting.
  123. State->CrashThread.PriorityClass = NORMAL_PRIORITY_CLASS;
  124. State->CrashThread.Priority = THREAD_PRIORITY_NORMAL;
  125. }
  126. else
  127. {
  128. State->CrashThread.PriorityClass =
  129. GetPriorityClass(OS_HANDLE(g_Process->m_SysHandle));
  130. State->CrashThread.Priority =
  131. GetThreadPriority(OS_HANDLE(Thread->m_Handle));
  132. }
  133. }
  134. else
  135. {
  136. State->CrashThread.PriorityClass = NORMAL_PRIORITY_CLASS;
  137. State->CrashThread.Priority = THREAD_PRIORITY_NORMAL;
  138. }
  139. if (g_Target->GetThreadInfoDataOffset(Thread, NULL, &Teb64) != S_OK)
  140. {
  141. Teb64 = 0;
  142. }
  143. State->CrashThread.Teb = (DWORD_PTR)Teb64;
  144. *Data = &State->CrashThread;
  145. *DataLength = sizeof(State->CrashThread);
  146. break;
  147. case DMP_MEMORY_BASIC_INFORMATION:
  148. if (g_Target->QueryMemoryRegion(g_Process,
  149. &State->MemHandle, FALSE,
  150. &State->MemInfo) != S_OK)
  151. {
  152. State->MemHandle = 0;
  153. State->MemInfo.RegionSize = 0;
  154. return FALSE;
  155. }
  156. State->TotalMemQueried += State->MemInfo.RegionSize;
  157. #ifdef _WIN64
  158. *Data = &State->MemInfo;
  159. *DataLength = sizeof(State->MemInfo);
  160. #else
  161. State->MemInfo32.BaseAddress = (ULONG)State->MemInfo.BaseAddress;
  162. State->MemInfo32.AllocationBase = (ULONG)State->MemInfo.AllocationBase;
  163. State->MemInfo32.AllocationProtect = State->MemInfo.AllocationProtect;
  164. State->MemInfo32.RegionSize = (ULONG)State->MemInfo.RegionSize;
  165. State->MemInfo32.State = State->MemInfo.State;
  166. State->MemInfo32.Protect = State->MemInfo.Protect;
  167. State->MemInfo32.Type = State->MemInfo.Type;
  168. *Data = &State->MemInfo32;
  169. *DataLength = sizeof(State->MemInfo32);
  170. #endif
  171. break;
  172. case DMP_THREAD_CONTEXT:
  173. if (State->Thread == NULL)
  174. {
  175. Thread = g_Process->m_ThreadHead;
  176. }
  177. else
  178. {
  179. Thread = State->Thread->m_Next;
  180. }
  181. State->Thread = Thread;
  182. if (Thread == NULL)
  183. {
  184. g_Target->ChangeRegContext(g_Thread);
  185. return FALSE;
  186. }
  187. g_Target->ChangeRegContext(Thread);
  188. if (g_Machine->GetContextState(MCTX_CONTEXT) != S_OK ||
  189. g_Machine->ConvertContextTo(&g_Machine->m_Context,
  190. g_Target->m_SystemVersion,
  191. g_Target->m_TypeInfo.SizeTargetContext,
  192. &State->TargetContext) != S_OK)
  193. {
  194. ErrOut("Unable to retrieve context for thread %d. "
  195. "Dump may be corrupt.", Thread->m_UserId);
  196. return FALSE;
  197. }
  198. *Data = &State->TargetContext;
  199. *DataLength = g_Target->m_TypeInfo.SizeTargetContext;
  200. break;
  201. case DMP_MODULE:
  202. ImageInfo* Image;
  203. PCRASH_MODULE Module;
  204. if (State->Image == NULL)
  205. {
  206. Image = g_Process->m_ImageHead;
  207. }
  208. else
  209. {
  210. Image = State->Image->m_Next;
  211. }
  212. State->Image = Image;
  213. if (Image == NULL)
  214. {
  215. return FALSE;
  216. }
  217. Module = (PCRASH_MODULE)State->MemBuf;
  218. Module->BaseOfImage = (DWORD_PTR)Image->m_BaseOfImage;
  219. Module->SizeOfImage = Image->m_SizeOfImage;
  220. Module->ImageNameLength = strlen(Image->m_ImagePath) + 1;
  221. CopyString(Module->ImageName, Image->m_ImagePath,
  222. USER_DUMP_MEMORY_BUFFER - sizeof(*Module));
  223. *Data = Module;
  224. *DataLength = sizeof(*Module) + Module->ImageNameLength;
  225. break;
  226. case DMP_MEMORY_DATA:
  227. ULONG64 Left;
  228. Left = State->MemInfo.RegionSize - State->MemBufDone;
  229. if (Left == 0)
  230. {
  231. State->MemBufDone = 0;
  232. if (g_Target->QueryMemoryRegion(g_Process,
  233. &State->MemHandle, FALSE,
  234. &State->MemInfo) != S_OK)
  235. {
  236. State->MemHandle = 0;
  237. State->MemInfo.RegionSize = 0;
  238. // Sanity check that we wrote out as much data
  239. // as we stored in the MEMORY_BASIC phase.
  240. if (State->TotalMemQueried != State->TotalMemData)
  241. {
  242. ErrOut("Queried %s bytes of memory but wrote %s "
  243. "bytes of memory data.\nDump may be corrupt.\n",
  244. FormatDisp64(State->TotalMemQueried),
  245. FormatDisp64(State->TotalMemData));
  246. }
  247. return FALSE;
  248. }
  249. Left = State->MemInfo.RegionSize;
  250. State->TotalMemData += State->MemInfo.RegionSize;
  251. }
  252. if (Left > USER_DUMP_MEMORY_BUFFER)
  253. {
  254. Left = USER_DUMP_MEMORY_BUFFER;
  255. }
  256. if (CurReadAllVirtual(State->MemInfo.BaseAddress +
  257. State->MemBufDone, State->MemBuf,
  258. (ULONG)Left) != S_OK)
  259. {
  260. ErrOut("ReadVirtual at %s failed. Dump may be corrupt.\n",
  261. FormatAddr64(State->MemInfo.BaseAddress +
  262. State->MemBufDone));
  263. return FALSE;
  264. }
  265. State->MemBufDone += Left;
  266. *Data = State->MemBuf;
  267. *DataLength = (ULONG)Left;
  268. break;
  269. }
  270. return TRUE;
  271. }
  272. HRESULT
  273. UserFullDumpTargetInfo::Write(HANDLE hFile, ULONG FormatFlags,
  274. PCSTR CommentA, PCWSTR CommentW)
  275. {
  276. dprintf("user full dump\n");
  277. FlushCallbacks();
  278. if (!IS_LIVE_USER_TARGET(g_Target))
  279. {
  280. ErrOut("User full dumps can only be written in "
  281. "live user-mode sessions\n");
  282. return E_UNEXPECTED;
  283. }
  284. if (CommentA != NULL || CommentW != NULL)
  285. {
  286. ErrOut("User full dumps do not support comments\n");
  287. return E_INVALIDARG;
  288. }
  289. CREATE_USER_DUMP_STATE* State;
  290. State = (CREATE_USER_DUMP_STATE*)calloc(1, sizeof(*State));
  291. if (State == NULL)
  292. {
  293. ErrOut("Unable to allocate memory for dump state\n");
  294. return E_OUTOFMEMORY;
  295. }
  296. State->DumpFileHandle = hFile;
  297. HRESULT Status;
  298. if (!DbgHelpCreateUserDump(NULL, CreateUserDumpCallback, State))
  299. {
  300. Status = WIN32_LAST_STATUS();
  301. ErrOut("Dump creation failed, %s\n \"%s\"\n",
  302. FormatStatusCode(Status), FormatStatus(Status));
  303. }
  304. else
  305. {
  306. Status = S_OK;
  307. }
  308. free(State);
  309. return Status;
  310. }
  311. //----------------------------------------------------------------------------
  312. //
  313. // UserMiniDumpTargetInfo::Write.
  314. //
  315. //----------------------------------------------------------------------------
  316. class DbgSystemProvider : public MiniDumpSystemProvider
  317. {
  318. public:
  319. DbgSystemProvider(void);
  320. ~DbgSystemProvider(void);
  321. virtual void Release(void);
  322. virtual HRESULT GetCurrentTimeDate(OUT PULONG TimeDate);
  323. virtual HRESULT GetCpuType(OUT PULONG Type,
  324. OUT PBOOL BackingStore);
  325. virtual HRESULT GetCpuInfo(OUT PUSHORT Architecture,
  326. OUT PUSHORT Level,
  327. OUT PUSHORT Revision,
  328. OUT PUCHAR NumberOfProcessors,
  329. OUT PCPU_INFORMATION Info);
  330. virtual void GetContextSizes(OUT PULONG Size,
  331. OUT PULONG RegScanStart,
  332. OUT PULONG RegScanCount);
  333. virtual void GetPointerSize(OUT PULONG Size);
  334. virtual void GetPageSize(OUT PULONG Size);
  335. virtual void GetFunctionTableSizes(OUT PULONG TableSize,
  336. OUT PULONG EntrySize);
  337. virtual void GetInstructionWindowSize(OUT PULONG Size);
  338. virtual HRESULT GetOsInfo(OUT PULONG PlatformId,
  339. OUT PULONG Major,
  340. OUT PULONG Minor,
  341. OUT PULONG BuildNumber,
  342. OUT PUSHORT ProductType,
  343. OUT PUSHORT SuiteMask);
  344. virtual HRESULT GetOsCsdString(OUT PWSTR Buffer,
  345. IN ULONG BufferChars);
  346. virtual HRESULT OpenMapping(IN PCWSTR FilePath,
  347. OUT PULONG Size,
  348. OUT PWSTR LongPath,
  349. IN ULONG LongPathChars,
  350. OUT PVOID* Mapping);
  351. virtual void CloseMapping(PVOID Mapping);
  352. virtual HRESULT GetImageHeaderInfo(IN HANDLE Process,
  353. IN PCWSTR FilePath,
  354. IN ULONG64 ImageBase,
  355. OUT PULONG Size,
  356. OUT PULONG CheckSum,
  357. OUT PULONG TimeDateStamp);
  358. virtual HRESULT GetImageVersionInfo(IN HANDLE Process,
  359. IN PCWSTR FilePath,
  360. IN ULONG64 ImageBase,
  361. OUT VS_FIXEDFILEINFO* Info);
  362. virtual HRESULT GetImageDebugRecord(IN HANDLE Process,
  363. IN PCWSTR FilePath,
  364. IN ULONG64 ImageBase,
  365. IN ULONG RecordType,
  366. OUT OPTIONAL PVOID Data,
  367. IN OUT PULONG DataLen);
  368. virtual HRESULT EnumImageDataSections(IN HANDLE Process,
  369. IN PCWSTR FilePath,
  370. IN ULONG64 ImageBase,
  371. IN MiniDumpProviderCallbacks*
  372. Callback);
  373. virtual HRESULT OpenThread(IN ULONG DesiredAccess,
  374. IN BOOL InheritHandle,
  375. IN ULONG ThreadId,
  376. OUT PHANDLE Handle);
  377. virtual void CloseThread(IN HANDLE Handle);
  378. virtual ULONG GetCurrentThreadId(void);
  379. virtual ULONG SuspendThread(IN HANDLE Thread);
  380. virtual ULONG ResumeThread(IN HANDLE Thread);
  381. virtual HRESULT GetThreadContext(IN HANDLE Thread,
  382. OUT PVOID Context,
  383. IN ULONG ContextSize,
  384. OUT PULONG64 CurrentPc,
  385. OUT PULONG64 CurrentStack,
  386. OUT PULONG64 CurrentStore);
  387. virtual HRESULT GetTeb(IN HANDLE Thread,
  388. OUT PULONG64 Offset,
  389. OUT PULONG Size);
  390. virtual HRESULT GetThreadInfo(IN HANDLE Process,
  391. IN HANDLE Thread,
  392. OUT PULONG64 Teb,
  393. OUT PULONG SizeOfTeb,
  394. OUT PULONG64 StackBase,
  395. OUT PULONG64 StackLimit,
  396. OUT PULONG64 StoreBase,
  397. OUT PULONG64 StoreLimit);
  398. virtual HRESULT GetPeb(IN HANDLE Process,
  399. OUT PULONG64 Offset,
  400. OUT PULONG Size);
  401. virtual HRESULT GetProcessTimes(IN HANDLE Process,
  402. OUT LPFILETIME Create,
  403. OUT LPFILETIME User,
  404. OUT LPFILETIME Kernel);
  405. virtual HRESULT ReadVirtual(IN HANDLE Process,
  406. IN ULONG64 Offset,
  407. OUT PVOID Buffer,
  408. IN ULONG Request,
  409. OUT PULONG Done);
  410. virtual HRESULT ReadAllVirtual(IN HANDLE Process,
  411. IN ULONG64 Offset,
  412. OUT PVOID Buffer,
  413. IN ULONG Request);
  414. virtual HRESULT QueryVirtual(IN HANDLE Process,
  415. IN ULONG64 Offset,
  416. OUT PULONG64 Base,
  417. OUT PULONG64 Size,
  418. OUT PULONG Protect,
  419. OUT PULONG State,
  420. OUT PULONG Type);
  421. virtual HRESULT StartProcessEnum(IN HANDLE Process,
  422. IN ULONG ProcessId);
  423. virtual HRESULT EnumThreads(OUT PULONG ThreadId);
  424. virtual HRESULT EnumModules(OUT PULONG64 Base,
  425. OUT PWSTR Path,
  426. IN ULONG PathChars);
  427. virtual HRESULT EnumFunctionTables(OUT PULONG64 MinAddress,
  428. OUT PULONG64 MaxAddress,
  429. OUT PULONG64 BaseAddress,
  430. OUT PULONG EntryCount,
  431. OUT PVOID RawTable,
  432. IN ULONG RawTableSize,
  433. OUT PVOID* RawEntryHandle);
  434. virtual HRESULT EnumFunctionTableEntries(IN PVOID RawTable,
  435. IN ULONG RawTableSize,
  436. IN PVOID RawEntryHandle,
  437. OUT PVOID RawEntries,
  438. IN ULONG RawEntriesSize);
  439. virtual HRESULT EnumFunctionTableEntryMemory(IN ULONG64 TableBase,
  440. IN PVOID RawEntries,
  441. IN ULONG Index,
  442. OUT PULONG64 Start,
  443. OUT PULONG Size);
  444. virtual HRESULT EnumUnloadedModules(OUT PWSTR Path,
  445. IN ULONG PathChars,
  446. OUT PULONG64 BaseOfModule,
  447. OUT PULONG SizeOfModule,
  448. OUT PULONG CheckSum,
  449. OUT PULONG TimeDateStamp);
  450. virtual void FinishProcessEnum(void);
  451. virtual HRESULT StartHandleEnum(IN HANDLE Process,
  452. IN ULONG ProcessId,
  453. OUT PULONG Count);
  454. virtual HRESULT EnumHandles(OUT PULONG64 Handle,
  455. OUT PULONG Attributes,
  456. OUT PULONG GrantedAccess,
  457. OUT PULONG HandleCount,
  458. OUT PULONG PointerCount,
  459. OUT PWSTR TypeName,
  460. IN ULONG TypeNameChars,
  461. OUT PWSTR ObjectName,
  462. IN ULONG ObjectNameChars);
  463. virtual void FinishHandleEnum(void);
  464. virtual HRESULT EnumPebMemory(IN HANDLE Process,
  465. IN ULONG64 PebOffset,
  466. IN ULONG PebSize,
  467. IN MiniDumpProviderCallbacks* Callback);
  468. virtual HRESULT EnumTebMemory(IN HANDLE Process,
  469. IN HANDLE Thread,
  470. IN ULONG64 TebOffset,
  471. IN ULONG TebSize,
  472. IN MiniDumpProviderCallbacks* Callback);
  473. virtual HRESULT GetCorDataAccess(IN PWSTR AccessDllName,
  474. IN struct ICorDataAccessServices*
  475. Services,
  476. OUT struct ICorDataAccess**
  477. Access);
  478. virtual void ReleaseCorDataAccess(IN struct ICorDataAccess*
  479. Access);
  480. protected:
  481. ThreadInfo* m_Thread;
  482. ImageInfo* m_Image;
  483. UnloadedModuleInfo* m_UnlEnum;
  484. ULONG m_Handle;
  485. ULONG64 m_FuncTableStart;
  486. ULONG64 m_FuncTableHandle;
  487. };
  488. DbgSystemProvider::DbgSystemProvider(void)
  489. {
  490. }
  491. DbgSystemProvider::~DbgSystemProvider(void)
  492. {
  493. }
  494. void
  495. DbgSystemProvider::Release(void)
  496. {
  497. delete this;
  498. }
  499. HRESULT
  500. DbgSystemProvider::GetCurrentTimeDate(OUT PULONG TimeDate)
  501. {
  502. *TimeDate = FileTimeToTimeDateStamp(g_Target->GetCurrentTimeDateN());
  503. return S_OK;
  504. }
  505. HRESULT
  506. DbgSystemProvider::GetCpuType(OUT PULONG Type,
  507. OUT PBOOL BackingStore)
  508. {
  509. *Type = g_Target->m_MachineType;
  510. *BackingStore = *Type == IMAGE_FILE_MACHINE_IA64;
  511. return S_OK;
  512. }
  513. HRESULT
  514. DbgSystemProvider::GetCpuInfo(OUT PUSHORT Architecture,
  515. OUT PUSHORT Level,
  516. OUT PUSHORT Revision,
  517. OUT PUCHAR NumberOfProcessors,
  518. OUT PCPU_INFORMATION Info)
  519. {
  520. DEBUG_PROCESSOR_IDENTIFICATION_ALL ProcId;
  521. ULONG64 ProcFeatures[4];
  522. ULONG NumVals;
  523. *Architecture = (USHORT)ImageMachineToProcArch(g_Target->m_MachineType);
  524. *NumberOfProcessors = (UCHAR)g_Target->m_NumProcessors;
  525. //
  526. // We've set the basic processor type so that the dump
  527. // can be interpreted correctly. Any other failures should
  528. // not be considered fatal.
  529. //
  530. *Level = 0;
  531. *Revision = 0;
  532. ZeroMemory(Info, sizeof(*Info));
  533. if (g_Target->GetProcessorId(0, &ProcId) != S_OK)
  534. {
  535. return S_OK;
  536. }
  537. switch(g_Target->m_MachineType)
  538. {
  539. case IMAGE_FILE_MACHINE_I386:
  540. *Level = (USHORT)ProcId.X86.Family;
  541. *Revision = ((USHORT)ProcId.X86.Model << 8) |
  542. (USHORT)ProcId.X86.Stepping;
  543. memcpy(Info->X86CpuInfo.VendorId, ProcId.X86.VendorString,
  544. sizeof(Info->X86CpuInfo.VendorId));
  545. if (SUCCEEDED(g_Target->
  546. GetSpecificProcessorFeatures(0,
  547. ProcFeatures,
  548. DIMA(ProcFeatures),
  549. &NumVals)) &&
  550. NumVals >= 2)
  551. {
  552. Info->X86CpuInfo.VersionInformation =
  553. (ULONG32)ProcFeatures[0];
  554. Info->X86CpuInfo.FeatureInformation =
  555. (ULONG32)ProcFeatures[1];
  556. if (NumVals >= 3)
  557. {
  558. Info->X86CpuInfo.AMDExtendedCpuFeatures =
  559. (ULONG32)ProcFeatures[2];
  560. }
  561. }
  562. break;
  563. case IMAGE_FILE_MACHINE_IA64:
  564. *Level = (USHORT)ProcId.Ia64.Model;
  565. *Revision = (USHORT)ProcId.Ia64.Revision;
  566. break;
  567. case IMAGE_FILE_MACHINE_AMD64:
  568. *Level = (USHORT)ProcId.Amd64.Family;
  569. *Revision = ((USHORT)ProcId.Amd64.Model << 8) |
  570. (USHORT)ProcId.Amd64.Stepping;
  571. break;
  572. }
  573. if (g_Target->m_MachineType != IMAGE_FILE_MACHINE_I386 &&
  574. SUCCEEDED(g_Target->
  575. GetGenericProcessorFeatures(0,
  576. ProcFeatures,
  577. DIMA(ProcFeatures),
  578. &NumVals)))
  579. {
  580. C_ASSERT(sizeof(Info->OtherCpuInfo.ProcessorFeatures) <=
  581. sizeof(ProcFeatures));
  582. if (NumVals < DIMA(ProcFeatures))
  583. {
  584. ZeroMemory(ProcFeatures + NumVals,
  585. (DIMA(ProcFeatures) - NumVals) *
  586. sizeof(ProcFeatures[0]));
  587. }
  588. memcpy(Info->OtherCpuInfo.ProcessorFeatures, ProcFeatures,
  589. sizeof(Info->OtherCpuInfo.ProcessorFeatures));
  590. }
  591. return S_OK;
  592. }
  593. void
  594. DbgSystemProvider::GetContextSizes(OUT PULONG Size,
  595. OUT PULONG RegScanOffset,
  596. OUT PULONG RegScanCount)
  597. {
  598. *Size = g_Target->m_TypeInfo.SizeTargetContext;
  599. // Default reg scan.
  600. *RegScanOffset = -1;
  601. *RegScanCount = -1;
  602. }
  603. void
  604. DbgSystemProvider::GetPointerSize(OUT PULONG Size)
  605. {
  606. *Size = g_Machine->m_Ptr64 ? 8 : 4;
  607. }
  608. void
  609. DbgSystemProvider::GetPageSize(OUT PULONG Size)
  610. {
  611. *Size = g_Machine->m_PageSize;
  612. }
  613. void
  614. DbgSystemProvider::GetFunctionTableSizes(OUT PULONG TableSize,
  615. OUT PULONG EntrySize)
  616. {
  617. *TableSize = g_Target->m_TypeInfo.SizeDynamicFunctionTable;
  618. *EntrySize = g_Target->m_TypeInfo.SizeRuntimeFunction;
  619. }
  620. void
  621. DbgSystemProvider::GetInstructionWindowSize(OUT PULONG Size)
  622. {
  623. // Default window.
  624. *Size = -1;
  625. }
  626. HRESULT
  627. DbgSystemProvider::GetOsInfo(OUT PULONG PlatformId,
  628. OUT PULONG Major,
  629. OUT PULONG Minor,
  630. OUT PULONG BuildNumber,
  631. OUT PUSHORT ProductType,
  632. OUT PUSHORT SuiteMask)
  633. {
  634. *PlatformId = g_Target->m_PlatformId;
  635. *Major = g_Target->m_KdVersion.MajorVersion;
  636. *Minor = g_Target->m_KdVersion.MinorVersion;
  637. *BuildNumber = g_Target->m_BuildNumber;
  638. *ProductType = (USHORT)g_Target->m_ProductType;
  639. *SuiteMask = (USHORT)g_Target->m_SuiteMask;
  640. return S_OK;
  641. }
  642. HRESULT
  643. DbgSystemProvider::GetOsCsdString(OUT PWSTR Buffer,
  644. IN ULONG BufferChars)
  645. {
  646. if (!MultiByteToWideChar(CP_ACP, 0,
  647. g_Target->m_ServicePackString, -1,
  648. Buffer, BufferChars))
  649. {
  650. return WIN32_LAST_STATUS();
  651. }
  652. return S_OK;
  653. }
  654. HRESULT
  655. DbgSystemProvider::OpenMapping(IN PCWSTR FilePath,
  656. OUT PULONG Size,
  657. OUT PWSTR LongPath,
  658. IN ULONG LongPathChars,
  659. OUT PVOID* ViewRet)
  660. {
  661. // We could potentially support this via image file
  662. // location but the minidump code is deliberately
  663. // written to not rely to mappings.
  664. return E_NOTIMPL;
  665. }
  666. void
  667. DbgSystemProvider::CloseMapping(PVOID Mapping)
  668. {
  669. // No mapping support.
  670. DBG_ASSERT(!Mapping);
  671. }
  672. HRESULT
  673. DbgSystemProvider::GetImageHeaderInfo(IN HANDLE Process,
  674. IN PCWSTR FilePath,
  675. IN ULONG64 ImageBase,
  676. OUT PULONG Size,
  677. OUT PULONG CheckSum,
  678. OUT PULONG TimeDateStamp)
  679. {
  680. ImageInfo* Image = ((ProcessInfo*)Process)->
  681. FindImageByOffset(ImageBase, FALSE);
  682. if (!Image)
  683. {
  684. return E_NOINTERFACE;
  685. }
  686. *Size = Image->m_SizeOfImage;
  687. *CheckSum = Image->m_CheckSum;
  688. *TimeDateStamp = Image->m_TimeDateStamp;
  689. return S_OK;
  690. }
  691. HRESULT
  692. DbgSystemProvider::GetImageVersionInfo(IN HANDLE Process,
  693. IN PCWSTR FilePath,
  694. IN ULONG64 ImageBase,
  695. OUT VS_FIXEDFILEINFO* Info)
  696. {
  697. HRESULT Status;
  698. PSTR Ansi;
  699. if ((Status = WideToAnsi(FilePath, &Ansi)) != S_OK)
  700. {
  701. return Status;
  702. }
  703. Status = g_Target->
  704. GetImageVersionInformation((ProcessInfo*)Process,
  705. Ansi, ImageBase, "\\",
  706. Info, sizeof(*Info), NULL);
  707. FreeAnsi(Ansi);
  708. return Status;
  709. }
  710. HRESULT
  711. DbgSystemProvider::GetImageDebugRecord(IN HANDLE Process,
  712. IN PCWSTR FilePath,
  713. IN ULONG64 ImageBase,
  714. IN ULONG RecordType,
  715. IN OUT OPTIONAL PVOID Data,
  716. OUT PULONG DataLen)
  717. {
  718. // We can rely on the default processing.
  719. return E_NOINTERFACE;
  720. }
  721. HRESULT
  722. DbgSystemProvider::EnumImageDataSections(IN HANDLE Process,
  723. IN PCWSTR FilePath,
  724. IN ULONG64 ImageBase,
  725. IN MiniDumpProviderCallbacks*
  726. Callback)
  727. {
  728. // We can rely on the default processing.
  729. return E_NOINTERFACE;
  730. }
  731. HRESULT
  732. DbgSystemProvider::OpenThread(IN ULONG DesiredAccess,
  733. IN BOOL InheritHandle,
  734. IN ULONG ThreadId,
  735. OUT PHANDLE Handle)
  736. {
  737. // Just use the thread pointer as the "handle".
  738. *Handle = g_Process->FindThreadBySystemId(ThreadId);
  739. return *Handle ? S_OK : E_NOINTERFACE;
  740. }
  741. void
  742. DbgSystemProvider::CloseThread(IN HANDLE Handle)
  743. {
  744. // "Handle" is just a pointer so nothing to do.
  745. }
  746. ULONG
  747. DbgSystemProvider::GetCurrentThreadId(void)
  748. {
  749. // The minidump code uses the current thread ID
  750. // to avoid suspending the thread running the dump
  751. // code. That's not a problem for the debugger,
  752. // so return an ID that will never match.
  753. // SuspendThread will always be called so all
  754. // suspend counts will be set properly.
  755. return 0;
  756. }
  757. ULONG
  758. DbgSystemProvider::SuspendThread(IN HANDLE Thread)
  759. {
  760. return ((ThreadInfo*)Thread)->m_SuspendCount;
  761. }
  762. ULONG
  763. DbgSystemProvider::ResumeThread(IN HANDLE Thread)
  764. {
  765. return ((ThreadInfo*)Thread)->m_SuspendCount;
  766. }
  767. HRESULT
  768. DbgSystemProvider::GetThreadContext(IN HANDLE Thread,
  769. OUT PVOID Context,
  770. IN ULONG ContextSize,
  771. OUT PULONG64 CurrentPc,
  772. OUT PULONG64 CurrentStack,
  773. OUT PULONG64 CurrentStore)
  774. {
  775. HRESULT Status;
  776. ADDR Addr;
  777. g_Target->ChangeRegContext((ThreadInfo*)Thread);
  778. if ((Status = g_Machine->
  779. GetContextState(MCTX_CONTEXT)) != S_OK ||
  780. (Status = g_Machine->
  781. ConvertContextTo(&g_Machine->m_Context,
  782. g_Target->m_SystemVersion,
  783. g_Target->m_TypeInfo.SizeTargetContext,
  784. Context)) != S_OK)
  785. {
  786. return Status;
  787. }
  788. g_Machine->GetPC(&Addr);
  789. *CurrentPc = Flat(Addr);
  790. g_Machine->GetSP(&Addr);
  791. *CurrentStack = Flat(Addr);
  792. if (g_Target->m_MachineType == IMAGE_FILE_MACHINE_IA64)
  793. {
  794. *CurrentStore = g_Machine->m_Context.IA64Context.RsBSP;
  795. }
  796. else
  797. {
  798. *CurrentStore = 0;
  799. }
  800. return S_OK;
  801. }
  802. HRESULT
  803. DbgSystemProvider::GetTeb(IN HANDLE Thread,
  804. OUT PULONG64 Offset,
  805. OUT PULONG Size)
  806. {
  807. // Always save a whole page for the TEB.
  808. *Size = g_Machine->m_PageSize;
  809. return g_Target->
  810. GetThreadInfoTeb((ThreadInfo*)Thread, 0, 0, Offset);
  811. }
  812. HRESULT
  813. DbgSystemProvider::GetThreadInfo(IN HANDLE Process,
  814. IN HANDLE Thread,
  815. OUT PULONG64 Teb,
  816. OUT PULONG SizeOfTeb,
  817. OUT PULONG64 StackBase,
  818. OUT PULONG64 StackLimit,
  819. OUT PULONG64 StoreBase,
  820. OUT PULONG64 StoreLimit)
  821. {
  822. HRESULT Status;
  823. MEMORY_BASIC_INFORMATION64 MemInfo;
  824. ULONG64 MemHandle;
  825. if ((Status = g_Target->
  826. GetThreadInfoTeb((ThreadInfo*)Thread, 0, 0, Teb)) != S_OK)
  827. {
  828. return Status;
  829. }
  830. //
  831. // Try and save a whole page for the TEB. If that's
  832. // not possible, save as much as is there.
  833. //
  834. MemHandle = *Teb;
  835. if ((Status = g_Target->
  836. QueryMemoryRegion((ProcessInfo*)Process, &MemHandle,
  837. TRUE, &MemInfo)) != S_OK)
  838. {
  839. return Status;
  840. }
  841. *SizeOfTeb = g_Machine->m_PageSize;
  842. if (*Teb + *SizeOfTeb > MemInfo.BaseAddress + MemInfo.RegionSize)
  843. {
  844. *SizeOfTeb = (ULONG)
  845. ((MemInfo.BaseAddress + MemInfo.RegionSize) - *Teb);
  846. }
  847. //
  848. // Read the TIB for stack and store limit information.
  849. //
  850. ULONG PtrSize = g_Machine->m_Ptr64 ? 8 : 4;
  851. if ((Status = g_Target->
  852. ReadPointer((ProcessInfo*)Process, g_Machine, *Teb + PtrSize,
  853. StackBase)) != S_OK ||
  854. (Status = g_Target->
  855. ReadPointer((ProcessInfo*)Process, g_Machine, *Teb + 2 * PtrSize,
  856. StackLimit)) != S_OK)
  857. {
  858. return Status;
  859. }
  860. *StoreBase = 0;
  861. *StoreLimit = 0;
  862. switch(g_Target->m_PlatformId)
  863. {
  864. case VER_PLATFORM_WIN32_WINDOWS:
  865. // Can't have a backing store.
  866. break;
  867. case VER_PLATFORM_WIN32_NT:
  868. if (g_Target->m_MachineType == IMAGE_FILE_MACHINE_IA64)
  869. {
  870. #if 1
  871. // XXX drewb - The TEB bstore values don't seem to point to
  872. // the actual base of the backing store. Just
  873. // assume it's contiguous with the stack.
  874. *StoreBase = *StackBase;
  875. #else
  876. if ((Status = g_Target->
  877. ReadPointer((ProcessInfo*)Process, g_Machine,
  878. *Teb + IA64_TEB_BSTORE_BASE,
  879. StoreBase)) != S_OK)
  880. {
  881. return Status;
  882. }
  883. #endif
  884. if ((Status = g_Target->
  885. ReadPointer((ProcessInfo*)Process, g_Machine,
  886. *Teb + IA64_TEB_BSTORE_BASE + PtrSize,
  887. StoreLimit)) != S_OK)
  888. {
  889. return Status;
  890. }
  891. }
  892. break;
  893. default:
  894. return E_INVALIDARG;
  895. }
  896. return S_OK;
  897. }
  898. HRESULT
  899. DbgSystemProvider::GetPeb(IN HANDLE Process,
  900. OUT PULONG64 Offset,
  901. OUT PULONG Size)
  902. {
  903. HRESULT Status;
  904. MEMORY_BASIC_INFORMATION64 MemInfo;
  905. ULONG64 MemHandle;
  906. // The passed in process isn't very useful but we know
  907. // that we're dumping the current state so always
  908. // retrieve the PEB for the current thread.
  909. if ((Status = g_Target->
  910. GetProcessInfoPeb(g_Thread, 0, 0, Offset)) != S_OK)
  911. {
  912. return Status;
  913. }
  914. //
  915. // Try and save a whole page for the PEB. If that's
  916. // not possible, save as much as is there.
  917. //
  918. MemHandle = *Offset;
  919. if ((Status = g_Target->
  920. QueryMemoryRegion((ProcessInfo*)Process, &MemHandle,
  921. TRUE, &MemInfo)) != S_OK)
  922. {
  923. return Status;
  924. }
  925. *Size = g_Machine->m_PageSize;
  926. if (*Offset + *Size > MemInfo.BaseAddress + MemInfo.RegionSize)
  927. {
  928. *Size = (ULONG)
  929. ((MemInfo.BaseAddress + MemInfo.RegionSize) - *Offset);
  930. }
  931. return S_OK;
  932. }
  933. HRESULT
  934. DbgSystemProvider::GetProcessTimes(IN HANDLE Process,
  935. OUT LPFILETIME Create,
  936. OUT LPFILETIME User,
  937. OUT LPFILETIME Kernel)
  938. {
  939. HRESULT Status;
  940. ULONG64 Create64, Exit64, User64, Kernel64;
  941. if ((Status = g_Target->GetProcessTimes((ProcessInfo*)Process,
  942. &Create64, &Exit64,
  943. &Kernel64, &User64)) != S_OK)
  944. {
  945. return Status;
  946. }
  947. Create->dwHighDateTime = (ULONG)(Create64 >> 32);
  948. Create->dwLowDateTime = (ULONG)Create64;
  949. User->dwHighDateTime = (ULONG)(User64 >> 32);
  950. User->dwLowDateTime = (ULONG)User64;
  951. Kernel->dwHighDateTime = (ULONG)(Kernel64 >> 32);
  952. Kernel->dwLowDateTime = (ULONG)Kernel64;
  953. return S_OK;
  954. }
  955. HRESULT
  956. DbgSystemProvider::ReadVirtual(IN HANDLE Process,
  957. IN ULONG64 Offset,
  958. OUT PVOID Buffer,
  959. IN ULONG Request,
  960. OUT PULONG Done)
  961. {
  962. return g_Target->ReadVirtual((ProcessInfo*)Process, Offset,
  963. Buffer, Request, Done);
  964. }
  965. HRESULT
  966. DbgSystemProvider::ReadAllVirtual(IN HANDLE Process,
  967. IN ULONG64 Offset,
  968. OUT PVOID Buffer,
  969. IN ULONG Request)
  970. {
  971. return g_Target->ReadAllVirtual((ProcessInfo*)Process, Offset,
  972. Buffer, Request);
  973. }
  974. HRESULT
  975. DbgSystemProvider::QueryVirtual(IN HANDLE Process,
  976. IN ULONG64 Offset,
  977. OUT PULONG64 Base,
  978. OUT PULONG64 Size,
  979. OUT PULONG Protect,
  980. OUT PULONG State,
  981. OUT PULONG Type)
  982. {
  983. HRESULT Status;
  984. MEMORY_BASIC_INFORMATION64 Info;
  985. if ((Status = g_Target->
  986. QueryMemoryRegion((ProcessInfo*)Process, &Offset, TRUE,
  987. &Info)) != S_OK)
  988. {
  989. return Status;
  990. }
  991. *Base = Info.BaseAddress;
  992. *Size = Info.RegionSize;
  993. *Protect = Info.Protect;
  994. *State = Info.State;
  995. *Type = Info.Type;
  996. return S_OK;
  997. }
  998. HRESULT
  999. DbgSystemProvider::StartProcessEnum(IN HANDLE Process,
  1000. IN ULONG ProcessId)
  1001. {
  1002. m_Thread = ((ProcessInfo*)Process)->m_ThreadHead;
  1003. m_Image = ((ProcessInfo*)Process)->m_ImageHead;
  1004. // Unloaded modules aren't critical, so just
  1005. // ignore them if the enumerator fails.
  1006. m_UnlEnum = ((ProcessInfo*)Process)->m_Target->
  1007. GetUnloadedModuleInfo();
  1008. if (m_UnlEnum && m_UnlEnum->Initialize(g_Thread) != S_OK)
  1009. {
  1010. m_UnlEnum = NULL;
  1011. }
  1012. m_FuncTableStart = 0;
  1013. m_FuncTableHandle = 0;
  1014. return S_OK;
  1015. }
  1016. HRESULT
  1017. DbgSystemProvider::EnumThreads(OUT PULONG ThreadId)
  1018. {
  1019. if (!m_Thread)
  1020. {
  1021. return S_FALSE;
  1022. }
  1023. *ThreadId = m_Thread->m_SystemId;
  1024. m_Thread = m_Thread->m_Next;
  1025. return S_OK;
  1026. }
  1027. HRESULT
  1028. DbgSystemProvider::EnumModules(OUT PULONG64 Base,
  1029. OUT PWSTR Path,
  1030. IN ULONG PathChars)
  1031. {
  1032. if (!m_Image)
  1033. {
  1034. return S_FALSE;
  1035. }
  1036. *Base = m_Image->m_BaseOfImage;
  1037. if (!MultiByteToWideChar(CP_ACP, 0,
  1038. m_Image->m_ImagePath, -1,
  1039. Path, PathChars))
  1040. {
  1041. return WIN32_LAST_STATUS();
  1042. }
  1043. m_Image = m_Image->m_Next;
  1044. return S_OK;
  1045. }
  1046. HRESULT
  1047. DbgSystemProvider::EnumFunctionTables(OUT PULONG64 MinAddress,
  1048. OUT PULONG64 MaxAddress,
  1049. OUT PULONG64 BaseAddress,
  1050. OUT PULONG EntryCount,
  1051. OUT PVOID RawTable,
  1052. IN ULONG RawTableSize,
  1053. OUT PVOID* RawEntryHandle)
  1054. {
  1055. HRESULT Status;
  1056. CROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE CpTable;
  1057. if ((Status = g_Target->
  1058. EnumFunctionTables(g_Process,
  1059. &m_FuncTableStart,
  1060. &m_FuncTableHandle,
  1061. MinAddress,
  1062. MaxAddress,
  1063. BaseAddress,
  1064. EntryCount,
  1065. &CpTable,
  1066. RawEntryHandle)) != S_OK)
  1067. {
  1068. return Status;
  1069. }
  1070. memcpy(RawTable, &CpTable, RawTableSize);
  1071. return S_OK;
  1072. }
  1073. HRESULT
  1074. DbgSystemProvider::EnumFunctionTableEntries(IN PVOID RawTable,
  1075. IN ULONG RawTableSize,
  1076. IN PVOID RawEntryHandle,
  1077. OUT PVOID RawEntries,
  1078. IN ULONG RawEntriesSize)
  1079. {
  1080. memcpy(RawEntries, RawEntryHandle, RawEntriesSize);
  1081. free(RawEntryHandle);
  1082. return S_OK;
  1083. }
  1084. HRESULT
  1085. DbgSystemProvider::EnumFunctionTableEntryMemory(IN ULONG64 TableBase,
  1086. IN PVOID RawEntries,
  1087. IN ULONG Index,
  1088. OUT PULONG64 Start,
  1089. OUT PULONG Size)
  1090. {
  1091. return g_Machine->GetUnwindInfoBounds(g_Process,
  1092. TableBase,
  1093. RawEntries,
  1094. Index,
  1095. Start,
  1096. Size);
  1097. }
  1098. HRESULT
  1099. DbgSystemProvider::EnumUnloadedModules(OUT PWSTR Path,
  1100. IN ULONG PathChars,
  1101. OUT PULONG64 BaseOfModule,
  1102. OUT PULONG SizeOfModule,
  1103. OUT PULONG CheckSum,
  1104. OUT PULONG TimeDateStamp)
  1105. {
  1106. char UnlName[MAX_INFO_UNLOADED_NAME];
  1107. DEBUG_MODULE_PARAMETERS Params;
  1108. if (!m_UnlEnum ||
  1109. m_UnlEnum->GetEntry(UnlName, &Params) != S_OK)
  1110. {
  1111. return S_FALSE;
  1112. }
  1113. if (!MultiByteToWideChar(CP_ACP, 0,
  1114. UnlName, -1,
  1115. Path, PathChars))
  1116. {
  1117. return WIN32_LAST_STATUS();
  1118. }
  1119. *BaseOfModule = Params.Base;
  1120. *SizeOfModule = Params.Size;
  1121. *CheckSum = Params.Checksum;
  1122. *TimeDateStamp = Params.TimeDateStamp;
  1123. return S_OK;
  1124. }
  1125. void
  1126. DbgSystemProvider::FinishProcessEnum(void)
  1127. {
  1128. // Nothing to do.
  1129. }
  1130. HRESULT
  1131. DbgSystemProvider::StartHandleEnum(IN HANDLE Process,
  1132. IN ULONG ProcessId,
  1133. OUT PULONG Count)
  1134. {
  1135. m_Handle = 4;
  1136. // If the target doesn't have handle data don't make
  1137. // it a fatal error, just don't enumerate anything.
  1138. if (g_Target->
  1139. ReadHandleData((ProcessInfo*)Process, 0,
  1140. DEBUG_HANDLE_DATA_TYPE_HANDLE_COUNT,
  1141. Count, sizeof(*Count), NULL) != S_OK)
  1142. {
  1143. *Count = 0;
  1144. }
  1145. return S_OK;
  1146. }
  1147. HRESULT
  1148. DbgSystemProvider::EnumHandles(OUT PULONG64 Handle,
  1149. OUT PULONG Attributes,
  1150. OUT PULONG GrantedAccess,
  1151. OUT PULONG HandleCount,
  1152. OUT PULONG PointerCount,
  1153. OUT PWSTR TypeName,
  1154. IN ULONG TypeNameChars,
  1155. OUT PWSTR ObjectName,
  1156. IN ULONG ObjectNameChars)
  1157. {
  1158. DEBUG_HANDLE_DATA_BASIC BasicInfo;
  1159. for (;;)
  1160. {
  1161. if (m_Handle >= (1 << 24))
  1162. {
  1163. return S_FALSE;
  1164. }
  1165. // If we can't get the basic info and type there isn't much
  1166. // point in writing anything out so skip the handle.
  1167. if (g_Target->
  1168. ReadHandleData(g_Process, m_Handle,
  1169. DEBUG_HANDLE_DATA_TYPE_BASIC,
  1170. &BasicInfo, sizeof(BasicInfo), NULL) == S_OK &&
  1171. SUCCEEDED(g_Target->
  1172. ReadHandleData(g_Process, m_Handle,
  1173. DEBUG_HANDLE_DATA_TYPE_TYPE_NAME_WIDE,
  1174. TypeName,
  1175. TypeNameChars * sizeof(*TypeName),
  1176. NULL)))
  1177. {
  1178. break;
  1179. }
  1180. m_Handle += 4;
  1181. }
  1182. // Try and get the object name.
  1183. if (FAILED(g_Target->
  1184. ReadHandleData(g_Process, m_Handle,
  1185. DEBUG_HANDLE_DATA_TYPE_OBJECT_NAME_WIDE,
  1186. ObjectName,
  1187. ObjectNameChars * sizeof(*ObjectName),
  1188. NULL)))
  1189. {
  1190. *ObjectName = 0;
  1191. }
  1192. *Handle = m_Handle;
  1193. *Attributes = BasicInfo.Attributes;
  1194. *GrantedAccess = BasicInfo.GrantedAccess;
  1195. *HandleCount = BasicInfo.HandleCount;
  1196. *PointerCount = BasicInfo.PointerCount;
  1197. m_Handle += 4;
  1198. return S_OK;
  1199. }
  1200. void
  1201. DbgSystemProvider::FinishHandleEnum(void)
  1202. {
  1203. // Nothing to do.
  1204. }
  1205. HRESULT
  1206. DbgSystemProvider::EnumPebMemory(IN HANDLE Process,
  1207. IN ULONG64 PebOffset,
  1208. IN ULONG PebSize,
  1209. IN MiniDumpProviderCallbacks* Callback)
  1210. {
  1211. if (g_Target->m_SystemVersion <= NT_SVER_START ||
  1212. g_Target->m_SystemVersion >= NT_SVER_END)
  1213. {
  1214. // Basic Win32 doesn't have a defined PEB.
  1215. return S_OK;
  1216. }
  1217. // XXX drewb - This requires a whole set of constants
  1218. // to abstract data structure locations. Leave it
  1219. // for when we really need it.
  1220. return S_OK;
  1221. }
  1222. HRESULT
  1223. DbgSystemProvider::EnumTebMemory(IN HANDLE Process,
  1224. IN HANDLE Thread,
  1225. IN ULONG64 TebOffset,
  1226. IN ULONG TebSize,
  1227. IN MiniDumpProviderCallbacks* Callback)
  1228. {
  1229. if (g_Target->m_SystemVersion <= NT_SVER_START ||
  1230. g_Target->m_SystemVersion >= NT_SVER_END)
  1231. {
  1232. // Basic Win32 doesn't have a defined TEB beyond
  1233. // the TIB. The TIB can reference fiber data but
  1234. // that's NT-specific.
  1235. return S_OK;
  1236. }
  1237. // XXX drewb - This requires a whole set of constants
  1238. // to abstract data structure locations. Leave it
  1239. // for when we really need it.
  1240. return S_OK;
  1241. }
  1242. HRESULT
  1243. DbgSystemProvider::GetCorDataAccess(IN PWSTR AccessDllName,
  1244. IN struct ICorDataAccessServices*
  1245. Services,
  1246. OUT struct ICorDataAccess**
  1247. Access)
  1248. {
  1249. HRESULT Status;
  1250. // We're providing all of the system services to
  1251. // the minidump code so we know that its state
  1252. // matches what's available directly from the debugger's
  1253. // state. Just ignore the given DLL name and
  1254. // service interface in favor of the one the
  1255. // debugger already has.
  1256. if ((Status = g_Process->LoadCorDebugDll()) != S_OK)
  1257. {
  1258. return Status;
  1259. }
  1260. *Access = g_Process->m_CorAccess;
  1261. return S_OK;
  1262. }
  1263. void
  1264. DbgSystemProvider::ReleaseCorDataAccess(IN struct ICorDataAccess*
  1265. Access)
  1266. {
  1267. // No work necessary.
  1268. }
  1269. PMINIDUMP_EXCEPTION_INFORMATION64
  1270. CreateMiniExceptionInformation(PMINIDUMP_EXCEPTION_INFORMATION64 ExInfo,
  1271. PEXCEPTION_RECORD ExRecord,
  1272. PCROSS_PLATFORM_CONTEXT Context)
  1273. {
  1274. // If the last event was an exception put together
  1275. // exception information in minidump format.
  1276. if (g_LastEventType != DEBUG_EVENT_EXCEPTION ||
  1277. g_Process != g_EventProcess)
  1278. {
  1279. return NULL;
  1280. }
  1281. // Get the full context for the event thread.
  1282. g_Target->ChangeRegContext(g_EventThread);
  1283. if (g_Machine->GetContextState(MCTX_CONTEXT) != S_OK)
  1284. {
  1285. return NULL;
  1286. }
  1287. *Context = g_Machine->m_Context;
  1288. ExInfo->ThreadId = g_EventThreadSysId;
  1289. ExInfo->ClientPointers = FALSE;
  1290. ExInfo->ExceptionRecord = (LONG_PTR)ExRecord;
  1291. ExceptionRecord64To(&g_LastEventInfo.Exception.ExceptionRecord, ExRecord);
  1292. ExInfo->ContextRecord = (LONG_PTR)Context;
  1293. return ExInfo;
  1294. }
  1295. BOOL WINAPI
  1296. MicroDumpCallback(
  1297. IN PVOID CallbackParam,
  1298. IN CONST PMINIDUMP_CALLBACK_INPUT CallbackInput,
  1299. IN OUT PMINIDUMP_CALLBACK_OUTPUT CallbackOutput
  1300. )
  1301. {
  1302. switch(CallbackInput->CallbackType)
  1303. {
  1304. case IncludeModuleCallback:
  1305. // Mask off all flags other than the basic write flag.
  1306. CallbackOutput->ModuleWriteFlags &= ModuleWriteModule;
  1307. break;
  1308. case ModuleCallback:
  1309. // Eliminate all unreferenced modules.
  1310. if (!(CallbackOutput->ModuleWriteFlags & ModuleReferencedByMemory))
  1311. {
  1312. CallbackOutput->ModuleWriteFlags = 0;
  1313. }
  1314. break;
  1315. case IncludeThreadCallback:
  1316. if (CallbackInput->IncludeThread.ThreadId != g_EventThreadSysId)
  1317. {
  1318. return FALSE;
  1319. }
  1320. // Reduce write to the minimum of information
  1321. // necessary for a stack walk.
  1322. CallbackOutput->ThreadWriteFlags &= ~ThreadWriteInstructionWindow;
  1323. break;
  1324. }
  1325. return TRUE;
  1326. }
  1327. HRESULT
  1328. UserMiniDumpTargetInfo::Write(HANDLE hFile, ULONG FormatFlags,
  1329. PCSTR CommentA, PCWSTR CommentW)
  1330. {
  1331. if (!IS_USER_TARGET(g_Target))
  1332. {
  1333. ErrOut("User minidumps can only be written in user-mode sessions\n");
  1334. return E_UNEXPECTED;
  1335. }
  1336. dprintf("mini user dump\n");
  1337. FlushCallbacks();
  1338. HRESULT Status;
  1339. MINIDUMP_EXCEPTION_INFORMATION64 ExInfoBuf, *ExInfo;
  1340. EXCEPTION_RECORD ExRecord;
  1341. CROSS_PLATFORM_CONTEXT Context;
  1342. ULONG MiniType;
  1343. MINIDUMP_USER_STREAM UserStreams[2];
  1344. MINIDUMP_USER_STREAM_INFORMATION UserStreamInfo;
  1345. MINIDUMP_CALLBACK_INFORMATION CallbackBuffer;
  1346. PMINIDUMP_CALLBACK_INFORMATION Callback;
  1347. MiniType = MiniDumpNormal;
  1348. if (FormatFlags & DEBUG_FORMAT_USER_SMALL_FULL_MEMORY)
  1349. {
  1350. MiniType |= MiniDumpWithFullMemory;
  1351. }
  1352. if (FormatFlags & DEBUG_FORMAT_USER_SMALL_HANDLE_DATA)
  1353. {
  1354. MiniType |= MiniDumpWithHandleData;
  1355. }
  1356. if (FormatFlags & DEBUG_FORMAT_USER_SMALL_UNLOADED_MODULES)
  1357. {
  1358. MiniType |= MiniDumpWithUnloadedModules;
  1359. }
  1360. if (FormatFlags & DEBUG_FORMAT_USER_SMALL_INDIRECT_MEMORY)
  1361. {
  1362. MiniType |= MiniDumpWithIndirectlyReferencedMemory;
  1363. }
  1364. if (FormatFlags & DEBUG_FORMAT_USER_SMALL_DATA_SEGMENTS)
  1365. {
  1366. MiniType |= MiniDumpWithDataSegs;
  1367. }
  1368. if (FormatFlags & DEBUG_FORMAT_USER_SMALL_FILTER_MEMORY)
  1369. {
  1370. MiniType |= MiniDumpFilterMemory;
  1371. }
  1372. if (FormatFlags & DEBUG_FORMAT_USER_SMALL_FILTER_PATHS)
  1373. {
  1374. MiniType |= MiniDumpFilterModulePaths;
  1375. }
  1376. if (FormatFlags & DEBUG_FORMAT_USER_SMALL_PROCESS_THREAD_DATA)
  1377. {
  1378. MiniType |= MiniDumpWithProcessThreadData;
  1379. }
  1380. if (FormatFlags & DEBUG_FORMAT_USER_SMALL_PRIVATE_READ_WRITE_MEMORY)
  1381. {
  1382. MiniType |= MiniDumpWithPrivateReadWriteMemory;
  1383. }
  1384. UserStreamInfo.UserStreamCount = 0;
  1385. UserStreamInfo.UserStreamArray = UserStreams;
  1386. if (CommentA != NULL)
  1387. {
  1388. UserStreams[UserStreamInfo.UserStreamCount].Type =
  1389. CommentStreamA;
  1390. UserStreams[UserStreamInfo.UserStreamCount].BufferSize =
  1391. strlen(CommentA) + 1;
  1392. UserStreams[UserStreamInfo.UserStreamCount].Buffer =
  1393. (PVOID)CommentA;
  1394. UserStreamInfo.UserStreamCount++;
  1395. }
  1396. if (CommentW != NULL)
  1397. {
  1398. UserStreams[UserStreamInfo.UserStreamCount].Type =
  1399. CommentStreamW;
  1400. UserStreams[UserStreamInfo.UserStreamCount].BufferSize =
  1401. (wcslen(CommentW) + 1) * sizeof(WCHAR);
  1402. UserStreams[UserStreamInfo.UserStreamCount].Buffer =
  1403. (PVOID)CommentW;
  1404. UserStreamInfo.UserStreamCount++;
  1405. }
  1406. ExInfo = CreateMiniExceptionInformation(&ExInfoBuf, &ExRecord, &Context);
  1407. if (FormatFlags & FORMAT_USER_MICRO)
  1408. {
  1409. // This case isn't expected to be used by users,
  1410. // it's for testing of the microdump support.
  1411. Callback = &CallbackBuffer;
  1412. Callback->CallbackRoutine = MicroDumpCallback;
  1413. Callback->CallbackParam = NULL;
  1414. ExInfo = NULL;
  1415. MiniType |= MiniDumpScanMemory;
  1416. }
  1417. else
  1418. {
  1419. Callback = NULL;
  1420. }
  1421. HANDLE ProcHandle;
  1422. MiniDumpSystemProvider* SysProv = NULL;
  1423. MiniDumpOutputProvider* OutProv = NULL;
  1424. MiniDumpAllocationProvider* AllocProv = NULL;
  1425. if ((Status =
  1426. MiniDumpCreateFileOutputProvider(hFile, &OutProv)) != S_OK ||
  1427. (Status =
  1428. MiniDumpCreateLiveAllocationProvider(&AllocProv)) != S_OK)
  1429. {
  1430. goto Exit;
  1431. }
  1432. //
  1433. // If we're live we can let the official minidump
  1434. // code do all the work. If not, hook up a provider
  1435. // that uses debugger information. This provider
  1436. // could always be used but the default live-system
  1437. // provider offers slightly more information so
  1438. // check and use that if possible.
  1439. //
  1440. if (IS_LIVE_USER_TARGET(g_Target) &&
  1441. ((LiveUserTargetInfo*)g_Target)->m_Local)
  1442. {
  1443. if ((Status =
  1444. MiniDumpCreateLiveSystemProvider(&SysProv)) != S_OK)
  1445. {
  1446. goto Exit;
  1447. }
  1448. ProcHandle = OS_HANDLE(g_Process->m_SysHandle);
  1449. }
  1450. else
  1451. {
  1452. DbgSystemProvider* DbgSysProv = new DbgSystemProvider;
  1453. if (!DbgSysProv)
  1454. {
  1455. Status = E_OUTOFMEMORY;
  1456. goto Exit;
  1457. }
  1458. SysProv = DbgSysProv;
  1459. ProcHandle = (HANDLE)g_Process;
  1460. }
  1461. Status = MiniDumpProvideDump(ProcHandle, g_Process->m_SystemId,
  1462. SysProv, OutProv, AllocProv,
  1463. MiniType, ExInfo,
  1464. &UserStreamInfo, Callback);
  1465. Exit:
  1466. if (Status != S_OK)
  1467. {
  1468. ErrOut("Dump creation failed, %s\n \"%s\"\n",
  1469. FormatStatusCode(Status), FormatStatus(Status));
  1470. }
  1471. if (SysProv)
  1472. {
  1473. SysProv->Release();
  1474. }
  1475. if (OutProv)
  1476. {
  1477. OutProv->Release();
  1478. }
  1479. if (AllocProv)
  1480. {
  1481. AllocProv->Release();
  1482. }
  1483. // Reset the current register context in case
  1484. // it was changed at some point.
  1485. g_Target->ChangeRegContext(g_Thread);
  1486. return Status;
  1487. }
  1488. //-------------------------------------------------------------------
  1489. // initialize the dump headers
  1490. //
  1491. #define MINIDUMP_BUGCHECK 0x10000000
  1492. void
  1493. KernelDumpTargetInfo::InitDumpHeader32(
  1494. PDUMP_HEADER32 pdh,
  1495. PCSTR CommentA,
  1496. PCWSTR CommentW,
  1497. ULONG BugCheckCodeModifier
  1498. )
  1499. {
  1500. ULONG64 Data[4];
  1501. PULONG FillPtr = (PULONG)pdh;
  1502. while (FillPtr < (PULONG)(pdh + 1))
  1503. {
  1504. *FillPtr++ = DUMP_SIGNATURE32;
  1505. }
  1506. pdh->Signature = DUMP_SIGNATURE32;
  1507. pdh->ValidDump = DUMP_VALID_DUMP32;
  1508. pdh->MajorVersion = g_Target->m_KdVersion.MajorVersion;
  1509. pdh->MinorVersion = g_Target->m_KdVersion.MinorVersion;
  1510. g_Target->ReadDirectoryTableBase(Data);
  1511. pdh->DirectoryTableBase = (ULONG)Data[0];
  1512. pdh->PfnDataBase =
  1513. (ULONG)g_Target->m_KdDebuggerData.MmPfnDatabase;
  1514. pdh->PsLoadedModuleList =
  1515. (ULONG)g_Target->m_KdDebuggerData.PsLoadedModuleList;
  1516. pdh->PsActiveProcessHead =
  1517. (ULONG)g_Target->m_KdDebuggerData.PsActiveProcessHead;
  1518. pdh->MachineImageType = g_Target->m_KdVersion.MachineType;
  1519. pdh->NumberProcessors = g_Target->m_NumProcessors;
  1520. g_Target->ReadBugCheckData(&(pdh->BugCheckCode), Data);
  1521. pdh->BugCheckCode |= BugCheckCodeModifier;
  1522. pdh->BugCheckParameter1 = (ULONG)Data[0];
  1523. pdh->BugCheckParameter2 = (ULONG)Data[1];
  1524. pdh->BugCheckParameter3 = (ULONG)Data[2];
  1525. pdh->BugCheckParameter4 = (ULONG)Data[3];
  1526. //pdh->VersionUser = 0;
  1527. pdh->PaeEnabled = g_Target->m_KdDebuggerData.PaeEnabled;
  1528. pdh->KdDebuggerDataBlock = (ULONG)g_Target->m_KdDebuggerDataOffset;
  1529. // pdh->PhysicalMemoryBlock =;
  1530. g_Machine->GetContextState(MCTX_CONTEXT);
  1531. g_Machine->ConvertContextTo(&g_Machine->m_Context,
  1532. g_Target->m_SystemVersion,
  1533. sizeof(pdh->ContextRecord),
  1534. pdh->ContextRecord);
  1535. if (g_LastEventType == DEBUG_EVENT_EXCEPTION)
  1536. {
  1537. // Use the exception record from the last event.
  1538. ExceptionRecord64To32(&g_LastEventInfo.Exception.ExceptionRecord,
  1539. &pdh->Exception);
  1540. }
  1541. else
  1542. {
  1543. ADDR PcAddr;
  1544. // Fake a breakpoint exception.
  1545. ZeroMemory(&pdh->Exception, sizeof(pdh->Exception));
  1546. pdh->Exception.ExceptionCode = STATUS_BREAKPOINT;
  1547. g_Machine->GetPC(&PcAddr);
  1548. pdh->Exception.ExceptionAddress = (ULONG)Flat(PcAddr);
  1549. }
  1550. pdh->RequiredDumpSpace.QuadPart = TRIAGE_DUMP_SIZE32;
  1551. pdh->SystemTime.QuadPart = g_Target->GetCurrentTimeDateN();
  1552. pdh->SystemUpTime.QuadPart = g_Target->GetCurrentSystemUpTimeN();
  1553. if (g_Target->m_ProductType != INVALID_PRODUCT_TYPE)
  1554. {
  1555. pdh->ProductType = g_Target->m_ProductType;
  1556. pdh->SuiteMask = g_Target->m_SuiteMask;
  1557. }
  1558. PSTR ConvComment = NULL;
  1559. if (!CommentA && CommentW)
  1560. {
  1561. if (WideToAnsi(CommentW, &ConvComment) != S_OK)
  1562. {
  1563. ConvComment = NULL;
  1564. }
  1565. else
  1566. {
  1567. CommentA = ConvComment;
  1568. }
  1569. }
  1570. if (CommentA != NULL && CommentA[0])
  1571. {
  1572. CopyString(pdh->Comment, CommentA, DIMA(pdh->Comment));
  1573. }
  1574. FreeAnsi(ConvComment);
  1575. }
  1576. void
  1577. KernelDumpTargetInfo::InitDumpHeader64(
  1578. PDUMP_HEADER64 pdh,
  1579. PCSTR CommentA,
  1580. PCWSTR CommentW,
  1581. ULONG BugCheckCodeModifier
  1582. )
  1583. {
  1584. ULONG64 Data[4];
  1585. PULONG FillPtr = (PULONG)pdh;
  1586. while (FillPtr < (PULONG)(pdh + 1))
  1587. {
  1588. *FillPtr++ = DUMP_SIGNATURE32;
  1589. }
  1590. pdh->Signature = DUMP_SIGNATURE64;
  1591. pdh->ValidDump = DUMP_VALID_DUMP64;
  1592. pdh->MajorVersion = g_Target->m_KdVersion.MajorVersion;
  1593. pdh->MinorVersion = g_Target->m_KdVersion.MinorVersion;
  1594. // IA64 has several page directories. The defined
  1595. // behavior is to put the kernel page directory
  1596. // in the dump header as that's the one that can
  1597. // be most useful when first initializing the dump.
  1598. if (g_Target->m_EffMachineType == IMAGE_FILE_MACHINE_IA64)
  1599. {
  1600. ULONG Next;
  1601. if (g_Machine->
  1602. SetPageDirectory(g_Thread, PAGE_DIR_KERNEL, 0, &Next) != S_OK)
  1603. {
  1604. ErrOut("Unable to update the kernel dirbase\n");
  1605. Data[0] = 0;
  1606. }
  1607. else
  1608. {
  1609. Data[0] = g_Machine->m_PageDirectories[PAGE_DIR_KERNEL];
  1610. }
  1611. }
  1612. else
  1613. {
  1614. g_Target->ReadDirectoryTableBase(Data);
  1615. }
  1616. pdh->DirectoryTableBase = Data[0];
  1617. pdh->PfnDataBase =
  1618. g_Target->m_KdDebuggerData.MmPfnDatabase;
  1619. pdh->PsLoadedModuleList =
  1620. g_Target->m_KdDebuggerData.PsLoadedModuleList;
  1621. pdh->PsActiveProcessHead =
  1622. g_Target->m_KdDebuggerData.PsActiveProcessHead;
  1623. pdh->MachineImageType = g_Target->m_KdVersion.MachineType;
  1624. pdh->NumberProcessors = g_Target->m_NumProcessors;
  1625. g_Target->ReadBugCheckData(&(pdh->BugCheckCode), Data);
  1626. pdh->BugCheckCode |= BugCheckCodeModifier;
  1627. pdh->BugCheckParameter1 = Data[0];
  1628. pdh->BugCheckParameter2 = Data[1];
  1629. pdh->BugCheckParameter3 = Data[2];
  1630. pdh->BugCheckParameter4 = Data[3];
  1631. //pdh->VersionUser = 0;
  1632. pdh->KdDebuggerDataBlock = g_Target->m_KdDebuggerDataOffset;
  1633. // pdh->PhysicalMemoryBlock =;
  1634. g_Machine->GetContextState(MCTX_CONTEXT);
  1635. g_Machine->ConvertContextTo(&g_Machine->m_Context,
  1636. g_Target->m_SystemVersion,
  1637. sizeof(pdh->ContextRecord),
  1638. pdh->ContextRecord);
  1639. if (g_LastEventType == DEBUG_EVENT_EXCEPTION)
  1640. {
  1641. // Use the exception record from the last event.
  1642. pdh->Exception = g_LastEventInfo.Exception.ExceptionRecord;
  1643. }
  1644. else
  1645. {
  1646. ADDR PcAddr;
  1647. // Fake a breakpoint exception.
  1648. ZeroMemory(&pdh->Exception, sizeof(pdh->Exception));
  1649. pdh->Exception.ExceptionCode = STATUS_BREAKPOINT;
  1650. g_Machine->GetPC(&PcAddr);
  1651. pdh->Exception.ExceptionAddress = Flat(PcAddr);
  1652. }
  1653. pdh->RequiredDumpSpace.QuadPart = TRIAGE_DUMP_SIZE64;
  1654. pdh->SystemTime.QuadPart = g_Target->GetCurrentTimeDateN();
  1655. pdh->SystemUpTime.QuadPart = g_Target->GetCurrentSystemUpTimeN();
  1656. if (g_Target->m_ProductType != INVALID_PRODUCT_TYPE)
  1657. {
  1658. pdh->ProductType = g_Target->m_ProductType;
  1659. pdh->SuiteMask = g_Target->m_SuiteMask;
  1660. }
  1661. PSTR ConvComment = NULL;
  1662. if (!CommentA && CommentW)
  1663. {
  1664. if (WideToAnsi(CommentW, &ConvComment) != S_OK)
  1665. {
  1666. ConvComment = NULL;
  1667. }
  1668. else
  1669. {
  1670. CommentA = ConvComment;
  1671. }
  1672. }
  1673. if (CommentA != NULL && CommentA[0])
  1674. {
  1675. CopyString(pdh->Comment, CommentA, DIMA(pdh->Comment));
  1676. }
  1677. FreeAnsi(ConvComment);
  1678. }
  1679. //----------------------------------------------------------------------------
  1680. //
  1681. // KernelFull64DumpTargetInfo::Write.
  1682. //
  1683. //----------------------------------------------------------------------------
  1684. HRESULT
  1685. KernelFull64DumpTargetInfo::Write(HANDLE File, ULONG FormatFlags,
  1686. PCSTR CommentA, PCWSTR CommentW)
  1687. {
  1688. PDUMP_HEADER64 DumpHeader64;
  1689. HRESULT Status;
  1690. ULONG64 Offset;
  1691. PPHYSICAL_MEMORY_DESCRIPTOR64 PhysMem = NULL;
  1692. DWORD i, j;
  1693. PUCHAR PageBuffer = NULL;
  1694. DWORD BytesRead;
  1695. DWORD BytesWritten;
  1696. DWORD Percent;
  1697. ULONG64 CurrentPagesWritten;
  1698. DbgKdTransport* KdTrans;
  1699. DumpHeader64 = (PDUMP_HEADER64) LocalAlloc(LPTR, sizeof(DUMP_HEADER64));
  1700. if (DumpHeader64 == NULL)
  1701. {
  1702. ErrOut("Failed to allocate dump header buffer\n");
  1703. return E_OUTOFMEMORY;
  1704. }
  1705. if (!IS_REMOTE_KERNEL_TARGET(g_Target) && !IS_KERNEL_FULL_DUMP(g_Target))
  1706. {
  1707. ErrOut("\nKernel full dumps can only be written when all of physical "
  1708. "memory is accessible - aborting now\n");
  1709. return E_INVALIDARG;
  1710. }
  1711. if (IS_CONN_KERNEL_TARGET(g_Target))
  1712. {
  1713. KdTrans = ((ConnLiveKernelTargetInfo*)g_Target)->m_Transport;
  1714. }
  1715. else
  1716. {
  1717. KdTrans = NULL;
  1718. }
  1719. dprintf("Full kernel dump\n");
  1720. FlushCallbacks();
  1721. KernelDumpTargetInfo::InitDumpHeader64(DumpHeader64,
  1722. CommentA, CommentW, 0);
  1723. DumpHeader64->DumpType = DUMP_TYPE_FULL;
  1724. DumpHeader64->WriterStatus = DUMP_DBGENG_SUCCESS;
  1725. //
  1726. // now copy the memory descriptor list to our header..
  1727. // first get the pointer va
  1728. //
  1729. Status = g_Target->ReadPointer(g_Process, g_Target->m_Machine,
  1730. g_Target->m_KdDebuggerData.
  1731. MmPhysicalMemoryBlock,
  1732. &Offset);
  1733. if (Status != S_OK || (Offset == 0))
  1734. {
  1735. ErrOut("Unable to read MmPhysicalMemoryBlock\n");
  1736. Status = Status != S_OK ? Status : E_INVALIDARG;
  1737. }
  1738. else
  1739. {
  1740. //
  1741. // first read the memory descriptor size...
  1742. //
  1743. PhysMem = &DumpHeader64->PhysicalMemoryBlock;
  1744. Status = g_Target->
  1745. ReadVirtual(g_Process, Offset,
  1746. PhysMem, DMP_PHYSICAL_MEMORY_BLOCK_SIZE_64,
  1747. &BytesRead);
  1748. if (Status != S_OK ||
  1749. BytesRead < sizeof(*PhysMem) +
  1750. (sizeof(PhysMem->Run[0]) * (PhysMem->NumberOfRuns - 1)))
  1751. {
  1752. ErrOut("Unable to read MmPhysicalMemoryBlock\n");
  1753. Status = Status != S_OK ? Status : E_INVALIDARG;
  1754. }
  1755. else
  1756. {
  1757. //
  1758. // calculate total dump file size
  1759. //
  1760. DumpHeader64->RequiredDumpSpace.QuadPart =
  1761. DumpHeader64->PhysicalMemoryBlock.NumberOfPages *
  1762. g_Machine->m_PageSize;
  1763. //
  1764. // write dump header to crash dump file
  1765. //
  1766. if (!WriteFile(File,
  1767. DumpHeader64,
  1768. sizeof(DUMP_HEADER64),
  1769. &BytesWritten,
  1770. NULL))
  1771. {
  1772. Status = WIN32_LAST_STATUS();
  1773. ErrOut("Failed writing to crashdump file - %s\n \"%s\"\n",
  1774. FormatStatusCode(Status),
  1775. FormatStatusArgs(Status, NULL));
  1776. }
  1777. }
  1778. }
  1779. if (Status == S_OK)
  1780. {
  1781. PageBuffer = (PUCHAR) LocalAlloc(LPTR, g_Machine->m_PageSize);
  1782. if (PageBuffer == NULL)
  1783. {
  1784. ErrOut("Failed to allocate double buffer\n");
  1785. }
  1786. else
  1787. {
  1788. //
  1789. // now write the physical memory out to disk.
  1790. // we use the dump header to retrieve the physical memory base and
  1791. // run count then ask the transport to gecth these pages form the
  1792. // target. On 1394, the virtual debugger driver will do physical
  1793. // address reads on the remote host since there is a onoe-to-one
  1794. // relationships between physical 1394 and physical mem addresses.
  1795. //
  1796. CurrentPagesWritten = 0;
  1797. Percent = 0;
  1798. for (i = 0; i < PhysMem->NumberOfRuns; i++)
  1799. {
  1800. Offset = 0;
  1801. Offset = PhysMem->Run[i].BasePage*g_Machine->m_PageSize;
  1802. if (CheckUserInterrupt())
  1803. {
  1804. ErrOut("Creation of crashdump file interrupted\n");
  1805. Status = E_ABORT;
  1806. break;
  1807. }
  1808. for (j = 0; j< PhysMem->Run[i].PageCount; j++)
  1809. {
  1810. //
  1811. // printout the percent done every 5% increments
  1812. //
  1813. if ((CurrentPagesWritten*100) / PhysMem->NumberOfPages ==
  1814. Percent)
  1815. {
  1816. dprintf("Percent written %d \n", Percent);
  1817. FlushCallbacks();
  1818. if (KdTrans &&
  1819. KdTrans->m_DirectPhysicalMemory)
  1820. {
  1821. Percent += 5;
  1822. }
  1823. else
  1824. {
  1825. Percent += 1;
  1826. }
  1827. }
  1828. if (KdTrans &&
  1829. KdTrans->m_DirectPhysicalMemory)
  1830. {
  1831. Status = KdTrans->
  1832. ReadTargetPhysicalMemory(Offset,
  1833. PageBuffer,
  1834. g_Machine->m_PageSize,
  1835. &BytesWritten);
  1836. }
  1837. else
  1838. {
  1839. Status = g_Target->ReadPhysical(Offset,
  1840. PageBuffer,
  1841. g_Machine->m_PageSize,
  1842. PHYS_FLAG_DEFAULT,
  1843. &BytesWritten);
  1844. }
  1845. if (g_EngStatus & ENG_STATUS_USER_INTERRUPT)
  1846. {
  1847. break;
  1848. }
  1849. else if (Status != S_OK)
  1850. {
  1851. ErrOut("Failed Reading page for crashdump file\n");
  1852. break;
  1853. }
  1854. else
  1855. {
  1856. //
  1857. // now write the page to the local crashdump file
  1858. //
  1859. if (!WriteFile(File,
  1860. PageBuffer,
  1861. g_Machine->m_PageSize,
  1862. &BytesWritten,
  1863. NULL))
  1864. {
  1865. Status = WIN32_LAST_STATUS();
  1866. ErrOut("Failed writing header to crashdump file - %s\n \"%s\"\n",
  1867. FormatStatusCode(Status),
  1868. FormatStatusArgs(Status, NULL));
  1869. break;
  1870. }
  1871. Offset += g_Machine->m_PageSize;
  1872. CurrentPagesWritten++;
  1873. }
  1874. }
  1875. }
  1876. if (Status == S_OK)
  1877. {
  1878. dprintf("CrashDump write complete\n");
  1879. }
  1880. LocalFree(PageBuffer);
  1881. }
  1882. }
  1883. LocalFree(DumpHeader64);
  1884. return Status;
  1885. }
  1886. //----------------------------------------------------------------------------
  1887. //
  1888. // KernelFull32DumpTargetInfo::Write.
  1889. //
  1890. //----------------------------------------------------------------------------
  1891. HRESULT
  1892. KernelFull32DumpTargetInfo::Write(HANDLE File, ULONG FormatFlags,
  1893. PCSTR CommentA, PCWSTR CommentW)
  1894. {
  1895. PDUMP_HEADER32 DumpHeader32 = NULL;
  1896. HRESULT Status;
  1897. ULONG64 Offset;
  1898. PPHYSICAL_MEMORY_DESCRIPTOR32 PhysMem = NULL;
  1899. DWORD i, j;
  1900. PUCHAR PageBuffer = NULL;
  1901. DWORD BytesRead;
  1902. DWORD BytesWritten;
  1903. DWORD Percent;
  1904. ULONG CurrentPagesWritten;
  1905. DbgKdTransport* KdTrans;
  1906. DumpHeader32 = (PDUMP_HEADER32) LocalAlloc(LPTR, sizeof(DUMP_HEADER32));
  1907. if (DumpHeader32 == NULL)
  1908. {
  1909. ErrOut("Failed to allocate dump header buffer\n");
  1910. return E_OUTOFMEMORY;
  1911. }
  1912. if (!IS_REMOTE_KERNEL_TARGET(g_Target) && !IS_KERNEL_FULL_DUMP(g_Target))
  1913. {
  1914. ErrOut("\nKernel full dumps can only be written when all of physical "
  1915. "memory is accessible - aborting now\n");
  1916. return E_INVALIDARG;
  1917. }
  1918. if (IS_CONN_KERNEL_TARGET(g_Target))
  1919. {
  1920. KdTrans = ((ConnLiveKernelTargetInfo*)g_Target)->m_Transport;
  1921. }
  1922. else
  1923. {
  1924. KdTrans = NULL;
  1925. }
  1926. dprintf("Full kernel dump\n");
  1927. FlushCallbacks();
  1928. //
  1929. // Build the header
  1930. //
  1931. KernelDumpTargetInfo::InitDumpHeader32(DumpHeader32,
  1932. CommentA, CommentW, 0);
  1933. DumpHeader32->DumpType = DUMP_TYPE_FULL;
  1934. DumpHeader32->WriterStatus = DUMP_DBGENG_SUCCESS;
  1935. //
  1936. // now copy the memory descriptor list to our header..
  1937. // first get the pointer va
  1938. //
  1939. Status = g_Target->ReadPointer(g_Process, g_Target->m_Machine,
  1940. g_Target->m_KdDebuggerData.
  1941. MmPhysicalMemoryBlock,
  1942. &Offset);
  1943. if (Status != S_OK || (Offset == 0))
  1944. {
  1945. ErrOut("Unable to read MmPhysicalMemoryBlock\n");
  1946. Status = Status != S_OK ? Status : E_INVALIDARG;
  1947. }
  1948. else
  1949. {
  1950. //
  1951. // first read the memory descriptor size...
  1952. //
  1953. PhysMem = &DumpHeader32->PhysicalMemoryBlock;
  1954. Status = g_Target->
  1955. ReadVirtual(g_Process, Offset,
  1956. PhysMem, DMP_PHYSICAL_MEMORY_BLOCK_SIZE_32,
  1957. &BytesRead);
  1958. if (Status != S_OK ||
  1959. BytesRead < sizeof(*PhysMem) +
  1960. (sizeof(PhysMem->Run[0]) * (PhysMem->NumberOfRuns - 1)))
  1961. {
  1962. ErrOut("Unable to read MmPhysicalMemoryBlock\n");
  1963. Status = Status != S_OK ? Status : E_INVALIDARG;
  1964. }
  1965. else
  1966. {
  1967. //
  1968. // calculate total dump file size
  1969. //
  1970. DumpHeader32->RequiredDumpSpace.QuadPart =
  1971. DumpHeader32->PhysicalMemoryBlock.NumberOfPages *
  1972. g_Machine->m_PageSize;
  1973. //
  1974. // write dump header to crash dump file
  1975. //
  1976. if (!WriteFile(File,
  1977. DumpHeader32,
  1978. sizeof(DUMP_HEADER32),
  1979. &BytesWritten,
  1980. NULL))
  1981. {
  1982. Status = WIN32_LAST_STATUS();
  1983. ErrOut("Failed writing to crashdump file - %s\n \"%s\"\n",
  1984. FormatStatusCode(Status),
  1985. FormatStatusArgs(Status, NULL));
  1986. }
  1987. }
  1988. }
  1989. if (Status == S_OK)
  1990. {
  1991. PageBuffer = (PUCHAR) LocalAlloc(LPTR, g_Machine->m_PageSize);
  1992. if (PageBuffer == NULL)
  1993. {
  1994. ErrOut("Failed to allocate double buffer\n");
  1995. }
  1996. else
  1997. {
  1998. //
  1999. // now write the physical memory out to disk.
  2000. // we use the dump header to retrieve the physical memory base and
  2001. // run count then ask the transport to gecth these pages form the
  2002. // target. On 1394, the virtual debugger driver will do physical
  2003. // address reads on the remote host since there is a onoe-to-one
  2004. // relationships between physical 1394 and physical mem addresses.
  2005. //
  2006. CurrentPagesWritten = 0;
  2007. Percent = 0;
  2008. for (i = 0; i < PhysMem->NumberOfRuns; i++)
  2009. {
  2010. Offset = 0;
  2011. Offset = PhysMem->Run[i].BasePage*g_Machine->m_PageSize;
  2012. if (CheckUserInterrupt())
  2013. {
  2014. ErrOut("Creation of crashdump file interrupted\n");
  2015. Status = E_ABORT;
  2016. break;
  2017. }
  2018. for (j = 0; j< PhysMem->Run[i].PageCount; j++)
  2019. {
  2020. //
  2021. // printout the percent done every 5% increments
  2022. //
  2023. if ((CurrentPagesWritten*100) / PhysMem->NumberOfPages ==
  2024. Percent)
  2025. {
  2026. dprintf("Percent written %d \n", Percent);
  2027. FlushCallbacks();
  2028. if (KdTrans &&
  2029. KdTrans->m_DirectPhysicalMemory)
  2030. {
  2031. Percent += 5;
  2032. }
  2033. else
  2034. {
  2035. Percent += 1;
  2036. }
  2037. }
  2038. if (KdTrans &&
  2039. KdTrans->m_DirectPhysicalMemory)
  2040. {
  2041. Status = KdTrans->
  2042. ReadTargetPhysicalMemory(Offset,
  2043. PageBuffer,
  2044. g_Machine->m_PageSize,
  2045. &BytesWritten);
  2046. }
  2047. else
  2048. {
  2049. Status = g_Target->ReadPhysical(Offset,
  2050. PageBuffer,
  2051. g_Machine->m_PageSize,
  2052. PHYS_FLAG_DEFAULT,
  2053. &BytesWritten);
  2054. }
  2055. if (g_EngStatus & ENG_STATUS_USER_INTERRUPT)
  2056. {
  2057. break;
  2058. }
  2059. else if (Status != S_OK)
  2060. {
  2061. ErrOut("Failed Reading page for crashdump file\n");
  2062. break;
  2063. }
  2064. else
  2065. {
  2066. //
  2067. // now write the page to the local crashdump file
  2068. //
  2069. if (!WriteFile(File,
  2070. PageBuffer,
  2071. g_Machine->m_PageSize,
  2072. &BytesWritten,
  2073. NULL))
  2074. {
  2075. Status = WIN32_LAST_STATUS();
  2076. ErrOut("Failed writing header to crashdump file - %s\n \"%s\"\n",
  2077. FormatStatusCode(Status),
  2078. FormatStatusArgs(Status, NULL));
  2079. break;
  2080. }
  2081. Offset += g_Machine->m_PageSize;
  2082. CurrentPagesWritten++;
  2083. }
  2084. }
  2085. }
  2086. if (Status == S_OK)
  2087. {
  2088. dprintf("CrashDump write complete\n");
  2089. }
  2090. LocalFree(PageBuffer);
  2091. }
  2092. }
  2093. LocalFree(DumpHeader32);
  2094. return Status;
  2095. }
  2096. enum
  2097. {
  2098. GNME_ENTRY,
  2099. GNME_DONE,
  2100. GNME_NO_NAME,
  2101. GNME_CORRUPT,
  2102. };
  2103. DWORD
  2104. GetNextModuleEntry(
  2105. ModuleInfo *ModIter,
  2106. MODULE_INFO_ENTRY *ModEntry
  2107. )
  2108. {
  2109. HRESULT Status;
  2110. ZeroMemory(ModEntry, sizeof(MODULE_INFO_ENTRY));
  2111. if ((Status = ModIter->GetEntry(ModEntry)) != S_OK)
  2112. {
  2113. return Status == S_FALSE ? GNME_DONE : GNME_CORRUPT;
  2114. }
  2115. if (ModEntry->NameLength > (MAX_IMAGE_PATH - 1) *
  2116. (ModEntry->UnicodeNamePtr ? sizeof(WCHAR) : sizeof(CHAR)))
  2117. {
  2118. ErrOut("Module list is corrupt.");
  2119. if (IS_KERNEL_TARGET(g_Target))
  2120. {
  2121. ErrOut(" Check your kernel symbols.\n");
  2122. }
  2123. else
  2124. {
  2125. ErrOut(" Loader list may be invalid\n");
  2126. }
  2127. return GNME_CORRUPT;
  2128. }
  2129. // If this entry has no name just skip it.
  2130. if (!ModEntry->NamePtr || !ModEntry->NameLength)
  2131. {
  2132. ErrOut(" Module List has empty entry in it - skipping\n");
  2133. return GNME_NO_NAME;
  2134. }
  2135. // If the image header information couldn't be read
  2136. // we end up with placeholder values for certain entries.
  2137. // The kernel writes out zeroes in this case so copy
  2138. // its behavior so that there's one consistent value
  2139. // for unknown.
  2140. if (ModEntry->CheckSum == UNKNOWN_CHECKSUM)
  2141. {
  2142. ModEntry->CheckSum = 0;
  2143. }
  2144. if (ModEntry->TimeDateStamp == UNKNOWN_TIMESTAMP)
  2145. {
  2146. ModEntry->TimeDateStamp = 0;
  2147. }
  2148. return GNME_ENTRY;
  2149. }
  2150. //----------------------------------------------------------------------------
  2151. //
  2152. // Shared triage writing things.
  2153. //
  2154. //----------------------------------------------------------------------------
  2155. #define ExtractValue(NAME, val) { \
  2156. if (!g_Target->m_KdDebuggerData.NAME) { \
  2157. val = 0; \
  2158. ErrOut("KdDebuggerData." #NAME " is NULL\n"); \
  2159. } else { \
  2160. g_Target->ReadAllVirtual(g_Process, \
  2161. g_Target->m_KdDebuggerData.NAME, &(val), \
  2162. sizeof(val)); \
  2163. } \
  2164. }
  2165. inline ALIGN_8(unsigned Offset)
  2166. {
  2167. return (Offset + 7) & 0xfffffff8;
  2168. }
  2169. const unsigned MAX_TRIAGE_STACK_SIZE32 = 16 * 1024;
  2170. const unsigned MAX_TRIAGE_STACK_SIZE64 = 32 * 1024;
  2171. const unsigned MAX_TRIAGE_BSTORE_SIZE = 16 * 4096; // as defined in ntia64.h
  2172. const ULONG TRIAGE_DRIVER_NAME_SIZE_GUESS = 0x40;
  2173. typedef struct _TRIAGE_PTR_DATA_BLOCK
  2174. {
  2175. ULONG64 MinAddress;
  2176. ULONG64 MaxAddress;
  2177. } TRIAGE_PTR_DATA_BLOCK, *PTRIAGE_PTR_DATA_BLOCK;
  2178. // A triage dump is sixteen pages long. Some of that is
  2179. // header information and at least a few other pages will
  2180. // be used for basic dump information so limit the number
  2181. // of extra data blocks to something less than sixteen
  2182. // to save array space.
  2183. #define IO_MAX_TRIAGE_DUMP_DATA_BLOCKS 8
  2184. ULONG IopNumTriageDumpDataBlocks;
  2185. TRIAGE_PTR_DATA_BLOCK IopTriageDumpDataBlocks[IO_MAX_TRIAGE_DUMP_DATA_BLOCKS];
  2186. //
  2187. // If space is available in a triage dump it's possible
  2188. // to add "interesting" data pages referenced by runtime
  2189. // information such as context registers. The following
  2190. // lists are offsets into the CONTEXT structure of pointers
  2191. // which usually point to interesting data. They are
  2192. // in priority order.
  2193. //
  2194. #define IOP_LAST_CONTEXT_OFFSET 0xffff
  2195. USHORT IopRunTimeContextOffsetsX86[] =
  2196. {
  2197. FIELD_OFFSET(X86_NT5_CONTEXT, Ebx),
  2198. FIELD_OFFSET(X86_NT5_CONTEXT, Esi),
  2199. FIELD_OFFSET(X86_NT5_CONTEXT, Edi),
  2200. FIELD_OFFSET(X86_NT5_CONTEXT, Ecx),
  2201. FIELD_OFFSET(X86_NT5_CONTEXT, Edx),
  2202. FIELD_OFFSET(X86_NT5_CONTEXT, Eax),
  2203. FIELD_OFFSET(X86_NT5_CONTEXT, Eip),
  2204. IOP_LAST_CONTEXT_OFFSET
  2205. };
  2206. USHORT IopRunTimeContextOffsetsIa64[] =
  2207. {
  2208. FIELD_OFFSET(IA64_CONTEXT, IntS0),
  2209. FIELD_OFFSET(IA64_CONTEXT, IntS1),
  2210. FIELD_OFFSET(IA64_CONTEXT, IntS2),
  2211. FIELD_OFFSET(IA64_CONTEXT, IntS3),
  2212. FIELD_OFFSET(IA64_CONTEXT, StIIP),
  2213. IOP_LAST_CONTEXT_OFFSET
  2214. };
  2215. USHORT IopRunTimeContextOffsetsAmd64[] =
  2216. {
  2217. FIELD_OFFSET(AMD64_CONTEXT, Rbx),
  2218. FIELD_OFFSET(AMD64_CONTEXT, Rsi),
  2219. FIELD_OFFSET(AMD64_CONTEXT, Rdi),
  2220. FIELD_OFFSET(AMD64_CONTEXT, Rcx),
  2221. FIELD_OFFSET(AMD64_CONTEXT, Rdx),
  2222. FIELD_OFFSET(AMD64_CONTEXT, Rax),
  2223. FIELD_OFFSET(AMD64_CONTEXT, Rip),
  2224. IOP_LAST_CONTEXT_OFFSET
  2225. };
  2226. USHORT IopRunTimeContextOffsetsEmpty[] =
  2227. {
  2228. IOP_LAST_CONTEXT_OFFSET
  2229. };
  2230. BOOLEAN
  2231. IopIsAddressRangeValid(
  2232. IN ULONG64 VirtualAddress,
  2233. IN ULONG Length
  2234. )
  2235. {
  2236. VirtualAddress = PAGE_ALIGN(g_Machine, VirtualAddress);
  2237. Length = (Length + g_Machine->m_PageSize - 1) >> g_Machine->m_PageShift;
  2238. while (Length > 0)
  2239. {
  2240. UCHAR Data;
  2241. if (CurReadAllVirtual(VirtualAddress, &Data, sizeof(Data)) != S_OK)
  2242. {
  2243. return FALSE;
  2244. }
  2245. VirtualAddress += g_Machine->m_PageSize;
  2246. Length--;
  2247. }
  2248. return TRUE;
  2249. }
  2250. BOOLEAN
  2251. IoAddTriageDumpDataBlock(
  2252. IN ULONG64 Address,
  2253. IN ULONG Length
  2254. )
  2255. {
  2256. ULONG i;
  2257. PTRIAGE_PTR_DATA_BLOCK Block;
  2258. ULONG64 MinAddress, MaxAddress;
  2259. // Check against SIZE32 for both 32 and 64-bit dumps
  2260. // as no data block needs to be larger than that.
  2261. if (Length >= TRIAGE_DUMP_SIZE32 ||
  2262. !IopIsAddressRangeValid(Address, Length))
  2263. {
  2264. return FALSE;
  2265. }
  2266. MinAddress = Address;
  2267. MaxAddress = MinAddress + Length;
  2268. //
  2269. // Minimize overlap between the new block and existing blocks.
  2270. // Blocks cannot simply be merged as blocks are inserted in
  2271. // priority order for storage in the dump. Combining a low-priority
  2272. // block with a high-priority block could lead to a medium-
  2273. // priority block being bumped improperly from the dump.
  2274. //
  2275. Block = IopTriageDumpDataBlocks;
  2276. for (i = 0; i < IopNumTriageDumpDataBlocks; i++, Block++)
  2277. {
  2278. if (MinAddress >= Block->MaxAddress ||
  2279. MaxAddress <= Block->MinAddress)
  2280. {
  2281. // No overlap.
  2282. continue;
  2283. }
  2284. //
  2285. // Trim overlap out of the new block. If this
  2286. // would split the new block into pieces don't
  2287. // trim to keep things simple. Content may then
  2288. // be duplicated in the dump.
  2289. //
  2290. if (MinAddress >= Block->MinAddress)
  2291. {
  2292. if (MaxAddress <= Block->MaxAddress)
  2293. {
  2294. // New block is completely contained.
  2295. return TRUE;
  2296. }
  2297. // New block extends above the current block
  2298. // so trim off the low-range overlap.
  2299. MinAddress = Block->MaxAddress;
  2300. }
  2301. else if (MaxAddress <= Block->MaxAddress)
  2302. {
  2303. // New block extends below the current block
  2304. // so trim off the high-range overlap.
  2305. MaxAddress = Block->MinAddress;
  2306. }
  2307. }
  2308. if (IopNumTriageDumpDataBlocks >= IO_MAX_TRIAGE_DUMP_DATA_BLOCKS)
  2309. {
  2310. return FALSE;
  2311. }
  2312. Block = IopTriageDumpDataBlocks + IopNumTriageDumpDataBlocks++;
  2313. Block->MinAddress = MinAddress;
  2314. Block->MaxAddress = MaxAddress;
  2315. return TRUE;
  2316. }
  2317. VOID
  2318. IopAddRunTimeTriageDataBlocks(
  2319. IN PCROSS_PLATFORM_CONTEXT Context,
  2320. IN ULONG64 StackMin,
  2321. IN ULONG64 StackMax,
  2322. IN ULONG64 StoreMin,
  2323. IN ULONG64 StoreMax
  2324. )
  2325. {
  2326. PUSHORT ContextOffset;
  2327. switch(g_Target->m_MachineType)
  2328. {
  2329. case IMAGE_FILE_MACHINE_I386:
  2330. ContextOffset = IopRunTimeContextOffsetsX86;
  2331. break;
  2332. case IMAGE_FILE_MACHINE_IA64:
  2333. ContextOffset = IopRunTimeContextOffsetsIa64;
  2334. break;
  2335. case IMAGE_FILE_MACHINE_AMD64:
  2336. ContextOffset = IopRunTimeContextOffsetsAmd64;
  2337. break;
  2338. default:
  2339. ContextOffset = IopRunTimeContextOffsetsEmpty;
  2340. break;
  2341. }
  2342. while (*ContextOffset < IOP_LAST_CONTEXT_OFFSET)
  2343. {
  2344. ULONG64 Ptr;
  2345. //
  2346. // Retrieve possible pointers from the context
  2347. // registers.
  2348. //
  2349. if (g_Machine->m_Ptr64)
  2350. {
  2351. Ptr = *(PULONG64)((PUCHAR)Context + *ContextOffset);
  2352. }
  2353. else
  2354. {
  2355. Ptr = EXTEND64(*(PULONG)((PUCHAR)Context + *ContextOffset));
  2356. }
  2357. // Stack and backing store memory is already saved
  2358. // so ignore any pointers that fall into those ranges.
  2359. if ((Ptr < StackMin || Ptr >= StackMax) &&
  2360. (Ptr < StoreMin || Ptr >= StoreMax))
  2361. {
  2362. IoAddTriageDumpDataBlock(PAGE_ALIGN(g_Machine, Ptr),
  2363. g_Machine->m_PageSize);
  2364. }
  2365. ContextOffset++;
  2366. }
  2367. }
  2368. void
  2369. AddInMemoryTriageDataBlocks(void)
  2370. {
  2371. //
  2372. // Look at the global data for nt!IopTriageDumpDataBlocks
  2373. // and include the same data blocks so that dump conversion
  2374. // preserves data blocks.
  2375. //
  2376. // If we don't know where IopTriageDumpDataBlocks is then
  2377. // we don't have anything to do.
  2378. if (!g_Target->m_KdDebuggerData.IopNumTriageDumpDataBlocks ||
  2379. !g_Target->m_KdDebuggerData.IopTriageDumpDataBlocks)
  2380. {
  2381. return;
  2382. }
  2383. ULONG NumBlocks;
  2384. if (g_Target->
  2385. ReadAllVirtual(g_Process, g_Target->
  2386. m_KdDebuggerData.IopNumTriageDumpDataBlocks,
  2387. &NumBlocks, sizeof(NumBlocks)) != S_OK)
  2388. {
  2389. return;
  2390. }
  2391. if (NumBlocks > IO_MAX_TRIAGE_DUMP_DATA_BLOCKS)
  2392. {
  2393. NumBlocks = IO_MAX_TRIAGE_DUMP_DATA_BLOCKS;
  2394. }
  2395. ULONG64 BlockDescOffs =
  2396. g_Target->m_KdDebuggerData.IopTriageDumpDataBlocks;
  2397. TRIAGE_PTR_DATA_BLOCK BlockDesc;
  2398. ULONG i;
  2399. ULONG PtrSize = g_Machine->m_Ptr64 ? 8 : 4;
  2400. for (i = 0; i < NumBlocks; i++)
  2401. {
  2402. if (g_Target->ReadPointer(g_Process, g_Machine,
  2403. BlockDescOffs,
  2404. &BlockDesc.MinAddress) != S_OK ||
  2405. g_Target->ReadPointer(g_Process, g_Machine,
  2406. BlockDescOffs + PtrSize,
  2407. &BlockDesc.MaxAddress) != S_OK)
  2408. {
  2409. return;
  2410. }
  2411. BlockDescOffs += 2 * PtrSize;
  2412. IoAddTriageDumpDataBlock(BlockDesc.MinAddress,
  2413. (LONG)(BlockDesc.MaxAddress -
  2414. BlockDesc.MinAddress));
  2415. }
  2416. }
  2417. ULONG
  2418. IopSizeTriageDumpDataBlocks(
  2419. ULONG Offset,
  2420. ULONG BufferSize,
  2421. PULONG StartOffset,
  2422. PULONG Count
  2423. )
  2424. {
  2425. ULONG i;
  2426. ULONG Size;
  2427. PTRIAGE_PTR_DATA_BLOCK Block;
  2428. *Count = 0;
  2429. Block = IopTriageDumpDataBlocks;
  2430. for (i = 0; i < IopNumTriageDumpDataBlocks; i++, Block++)
  2431. {
  2432. Size = ALIGN_8(sizeof(TRIAGE_DATA_BLOCK)) +
  2433. ALIGN_8((ULONG)(Block->MaxAddress - Block->MinAddress));
  2434. if (Offset + Size >= BufferSize)
  2435. {
  2436. break;
  2437. }
  2438. if (i == 0)
  2439. {
  2440. *StartOffset = Offset;
  2441. }
  2442. Offset += Size;
  2443. (*Count)++;
  2444. }
  2445. return Offset;
  2446. }
  2447. VOID
  2448. IopWriteTriageDumpDataBlocks(
  2449. ULONG StartOffset,
  2450. ULONG Count,
  2451. PUCHAR BufferAddress
  2452. )
  2453. {
  2454. ULONG i;
  2455. PTRIAGE_PTR_DATA_BLOCK Block;
  2456. PUCHAR DataBuffer;
  2457. PTRIAGE_DATA_BLOCK DumpBlock;
  2458. DumpBlock = (PTRIAGE_DATA_BLOCK)
  2459. (BufferAddress + StartOffset);
  2460. DataBuffer = (PUCHAR)(DumpBlock + Count);
  2461. Block = IopTriageDumpDataBlocks;
  2462. for (i = 0; i < Count; i++, Block++)
  2463. {
  2464. DumpBlock->Address = Block->MinAddress;
  2465. DumpBlock->Offset = (ULONG)(DataBuffer - BufferAddress);
  2466. DumpBlock->Size = (ULONG)(Block->MaxAddress - Block->MinAddress);
  2467. CurReadAllVirtual(Block->MinAddress, DataBuffer, DumpBlock->Size);
  2468. DataBuffer += DumpBlock->Size;
  2469. DumpBlock++;
  2470. }
  2471. }
  2472. //----------------------------------------------------------------------------
  2473. //
  2474. // KernelTriage32DumpTargetInfo::Write.
  2475. //
  2476. //----------------------------------------------------------------------------
  2477. HRESULT
  2478. KernelTriage32DumpTargetInfo::Write(HANDLE File, ULONG FormatFlags,
  2479. PCSTR CommentA, PCWSTR CommentW)
  2480. {
  2481. HRESULT Status;
  2482. PMEMORY_DUMP32 NewHeader;
  2483. ULONG64 ThreadAddr;
  2484. ULONG CodeMod;
  2485. ULONG BugCheckCode;
  2486. ULONG64 BugCheckData[4];
  2487. ULONG64 SaveDataPage = 0;
  2488. ULONG64 PrcbAddr;
  2489. ContextSave* PushedContext;
  2490. if (!IS_KERNEL_TARGET(g_Target))
  2491. {
  2492. ErrOut("kernel minidumps can only be written "
  2493. "in kernel-mode sessions\n");
  2494. return E_UNEXPECTED;
  2495. }
  2496. dprintf("mini kernel dump\n");
  2497. FlushCallbacks();
  2498. NewHeader = (PMEMORY_DUMP32) malloc(TRIAGE_DUMP_SIZE32);
  2499. if (NewHeader == NULL)
  2500. {
  2501. return E_OUTOFMEMORY;
  2502. }
  2503. //
  2504. // Get the current thread address, used to extract various blocks of data.
  2505. // For some bugchecks the interesting thread is a different
  2506. // thread than the current thread, so make the following code
  2507. // generic so it handles any thread.
  2508. //
  2509. if ((Status = g_Target->
  2510. ReadBugCheckData(&BugCheckCode, BugCheckData)) != S_OK)
  2511. {
  2512. goto NewHeader;
  2513. }
  2514. // Set a special marker to indicate there is no pushed context.
  2515. PushedContext = (ContextSave*)&PushedContext;
  2516. if (BugCheckCode == THREAD_STUCK_IN_DEVICE_DRIVER)
  2517. {
  2518. CROSS_PLATFORM_CONTEXT Context;
  2519. // Modify the bugcheck code to indicate this
  2520. // minidump represents a special state.
  2521. CodeMod = MINIDUMP_BUGCHECK;
  2522. // The interesting thread is the first bugcheck parameter.
  2523. ThreadAddr = BugCheckData[0];
  2524. // We need to make the thread's context the current
  2525. // machine context for the duration of dump generation.
  2526. if ((Status = g_Target->
  2527. GetContextFromThreadStack(ThreadAddr, &Context, FALSE)) != S_OK)
  2528. {
  2529. goto NewHeader;
  2530. }
  2531. PushedContext = g_Machine->PushContext(&Context);
  2532. }
  2533. else if (BugCheckCode == SYSTEM_THREAD_EXCEPTION_NOT_HANDLED)
  2534. {
  2535. //
  2536. // System thread stores a context record as the 4th parameter.
  2537. // use that.
  2538. // Also save the context record in case someone needs to look
  2539. // at it.
  2540. //
  2541. if (BugCheckData[3])
  2542. {
  2543. CROSS_PLATFORM_CONTEXT TargetContext, Context;
  2544. if (CurReadAllVirtual(BugCheckData[3], &TargetContext,
  2545. g_Target->m_TypeInfo.
  2546. SizeTargetContext) == S_OK &&
  2547. g_Machine->ConvertContextFrom(&Context,
  2548. g_Target->m_SystemVersion,
  2549. g_Target->
  2550. m_TypeInfo.SizeTargetContext,
  2551. &TargetContext) == S_OK)
  2552. {
  2553. CodeMod = MINIDUMP_BUGCHECK;
  2554. PushedContext = g_Machine->PushContext(&Context);
  2555. SaveDataPage = BugCheckData[3];
  2556. }
  2557. }
  2558. }
  2559. else if (BugCheckCode == KERNEL_MODE_EXCEPTION_NOT_HANDLED)
  2560. {
  2561. CROSS_PLATFORM_CONTEXT Context;
  2562. //
  2563. // 3rd parameter is a trap frame.
  2564. //
  2565. // Build a context record out of that only if it's a kernel mode
  2566. // failure because esp may be wrong in that case ???.
  2567. //
  2568. if (BugCheckData[2] &&
  2569. g_Machine->GetContextFromTrapFrame(BugCheckData[2], &Context,
  2570. FALSE) == S_OK)
  2571. {
  2572. CodeMod = MINIDUMP_BUGCHECK;
  2573. PushedContext = g_Machine->PushContext(&Context);
  2574. SaveDataPage = BugCheckData[2];
  2575. }
  2576. }
  2577. else if (BugCheckCode == UNEXPECTED_KERNEL_MODE_TRAP)
  2578. {
  2579. CROSS_PLATFORM_CONTEXT Context;
  2580. //
  2581. // Double fault
  2582. //
  2583. // The thread is correct in this case.
  2584. // Second parameter is the TSS. If we have a TSS, convert
  2585. // the context and mark the bugcheck as converted.
  2586. //
  2587. if (BugCheckData[0] == 8 &&
  2588. BugCheckData[1] &&
  2589. g_Machine->GetContextFromTaskSegment(BugCheckData[1], &Context,
  2590. FALSE) == S_OK)
  2591. {
  2592. CodeMod = MINIDUMP_BUGCHECK;
  2593. PushedContext = g_Machine->PushContext(&Context);
  2594. }
  2595. }
  2596. else
  2597. {
  2598. CodeMod = 0;
  2599. if ((Status = g_Process->
  2600. GetImplicitThreadData(g_Thread, &ThreadAddr)) != S_OK)
  2601. {
  2602. goto NewHeader;
  2603. }
  2604. }
  2605. CCrashDumpWrapper32 Wrapper;
  2606. //
  2607. // setup the main header
  2608. //
  2609. KernelDumpTargetInfo::InitDumpHeader32(&NewHeader->Header,
  2610. CommentA, CommentW,
  2611. CodeMod);
  2612. NewHeader->Header.DumpType = DUMP_TYPE_TRIAGE;
  2613. NewHeader->Header.MiniDumpFields = TRIAGE_DUMP_BASIC_INFO;
  2614. NewHeader->Header.WriterStatus = DUMP_DBGENG_SUCCESS;
  2615. //
  2616. // triage dump header begins on second page
  2617. //
  2618. TRIAGE_DUMP32 *ptdh = &NewHeader->Triage;
  2619. ULONG i;
  2620. ptdh->ServicePackBuild = g_Target->m_ServicePackNumber;
  2621. ptdh->SizeOfDump = TRIAGE_DUMP_SIZE32;
  2622. ptdh->ContextOffset = FIELD_OFFSET (DUMP_HEADER32, ContextRecord);
  2623. ptdh->ExceptionOffset = FIELD_OFFSET (DUMP_HEADER32, Exception);
  2624. //
  2625. // starting offset in triage dump follows the triage dump header
  2626. //
  2627. unsigned Offset =
  2628. ALIGN_8(sizeof(DUMP_HEADER32) + sizeof(TRIAGE_DUMP32));
  2629. //
  2630. // write mm information for Win2K and above only
  2631. //
  2632. if (g_Target->m_SystemVersion >= NT_SVER_W2K)
  2633. {
  2634. ptdh->MmOffset = Offset;
  2635. Wrapper.WriteMmTriageInformation((PBYTE)NewHeader + ptdh->MmOffset);
  2636. Offset += ALIGN_8(sizeof(DUMP_MM_STORAGE32));
  2637. }
  2638. //
  2639. // write unloaded drivers
  2640. //
  2641. ptdh->UnloadedDriversOffset = Offset;
  2642. Wrapper.WriteUnloadedDrivers((PBYTE)NewHeader +
  2643. ptdh->UnloadedDriversOffset);
  2644. Offset += ALIGN_8(sizeof(ULONG) +
  2645. MI_UNLOADED_DRIVERS * sizeof(DUMP_UNLOADED_DRIVERS32));
  2646. //
  2647. // write processor control block (KPRCB)
  2648. //
  2649. if (S_OK == g_Target->GetProcessorSystemDataOffset(CURRENT_PROC,
  2650. DEBUG_DATA_KPRCB_OFFSET,
  2651. &PrcbAddr))
  2652. {
  2653. ptdh->PrcbOffset = Offset;
  2654. CurReadAllVirtual(PrcbAddr,
  2655. ((PBYTE)NewHeader) + ptdh->PrcbOffset,
  2656. g_Target->m_KdDebuggerData.SizePrcb);
  2657. Offset += ALIGN_8(g_Target->m_KdDebuggerData.SizePrcb);
  2658. }
  2659. else
  2660. {
  2661. PrcbAddr = 0;
  2662. }
  2663. //
  2664. // Write the thread and process data structures.
  2665. //
  2666. ptdh->ProcessOffset = Offset;
  2667. Offset += ALIGN_8(g_Target->m_KdDebuggerData.SizeEProcess);
  2668. ptdh->ThreadOffset = Offset;
  2669. Offset += ALIGN_8(g_Target->m_KdDebuggerData.SizeEThread);
  2670. CurReadAllVirtual(ThreadAddr +
  2671. g_Target->m_KdDebuggerData.OffsetKThreadApcProcess,
  2672. (PBYTE)NewHeader + ptdh->ProcessOffset,
  2673. g_Target->m_KdDebuggerData.SizeEProcess);
  2674. CurReadAllVirtual(ThreadAddr,
  2675. (PBYTE)NewHeader + ptdh->ThreadOffset,
  2676. g_Target->m_KdDebuggerData.SizeEThread);
  2677. //
  2678. // write the call stack
  2679. //
  2680. ADDR StackPtr;
  2681. ULONG64 StackBase = 0;
  2682. g_Machine->GetSP(&StackPtr);
  2683. ptdh->TopOfStack = (ULONG)(ULONG_PTR)Flat(StackPtr);
  2684. g_Target->ReadPointer(g_Process, g_Target->m_Machine,
  2685. g_Target->m_KdDebuggerData.OffsetKThreadInitialStack +
  2686. ThreadAddr,
  2687. &StackBase);
  2688. // Take the Min in case something goes wrong getting the stack base.
  2689. ptdh->SizeOfCallStack = min((ULONG)(ULONG_PTR)(StackBase - Flat(StackPtr)),
  2690. MAX_TRIAGE_STACK_SIZE32);
  2691. ptdh->CallStackOffset = Offset;
  2692. if (ptdh->SizeOfCallStack)
  2693. {
  2694. CurReadAllVirtual(EXTEND64(ptdh->TopOfStack),
  2695. ((PBYTE)NewHeader) + ptdh->CallStackOffset,
  2696. ptdh->SizeOfCallStack);
  2697. }
  2698. Offset += ALIGN_8(ptdh->SizeOfCallStack);
  2699. //
  2700. // write debugger data
  2701. //
  2702. if (g_Target->m_SystemVersion >= NT_SVER_XP &&
  2703. g_Target->m_KdDebuggerDataOffset &&
  2704. (!IS_KERNEL_TRIAGE_DUMP(g_Target) ||
  2705. ((KernelTriageDumpTargetInfo*)g_Target)->m_HasDebuggerData) &&
  2706. Offset +
  2707. ALIGN_8(sizeof(g_Target->m_KdDebuggerData)) < TRIAGE_DUMP_SIZE32)
  2708. {
  2709. NewHeader->Header.MiniDumpFields |= TRIAGE_DUMP_DEBUGGER_DATA;
  2710. ptdh->DebuggerDataOffset = Offset;
  2711. Offset += ALIGN_8(sizeof(g_Target->m_KdDebuggerData));
  2712. ptdh->DebuggerDataSize = sizeof(g_Target->m_KdDebuggerData);
  2713. memcpy((PBYTE)NewHeader + ptdh->DebuggerDataOffset,
  2714. &g_Target->m_KdDebuggerData,
  2715. sizeof(g_Target->m_KdDebuggerData));
  2716. }
  2717. //
  2718. // write loaded driver list
  2719. //
  2720. ModuleInfo* ModIter;
  2721. ULONG MaxEntries;
  2722. // Use a heuristic to guess how many entries we
  2723. // can pack into the remaining space.
  2724. MaxEntries = (TRIAGE_DUMP_SIZE32 - Offset) /
  2725. (sizeof(DUMP_DRIVER_ENTRY32) + TRIAGE_DRIVER_NAME_SIZE_GUESS);
  2726. ptdh->DriverCount = 0;
  2727. if (ModIter = g_Target->GetModuleInfo(FALSE))
  2728. {
  2729. if ((Status = ModIter->Initialize(g_Thread)) == S_OK)
  2730. {
  2731. while (ptdh->DriverCount < MaxEntries)
  2732. {
  2733. MODULE_INFO_ENTRY ModEntry;
  2734. ULONG retval = GetNextModuleEntry(ModIter, &ModEntry);
  2735. if (retval == GNME_CORRUPT ||
  2736. retval == GNME_DONE)
  2737. {
  2738. if (retval == GNME_CORRUPT)
  2739. {
  2740. NewHeader->Header.WriterStatus =
  2741. DUMP_DBGENG_CORRUPT_MODULE_LIST;
  2742. }
  2743. break;
  2744. }
  2745. else if (retval == GNME_NO_NAME)
  2746. {
  2747. continue;
  2748. }
  2749. ptdh->DriverCount++;
  2750. }
  2751. }
  2752. else
  2753. {
  2754. NewHeader->Header.WriterStatus =
  2755. DUMP_DBGENG_NO_MODULE_LIST;
  2756. }
  2757. }
  2758. ptdh->DriverListOffset = Offset;
  2759. Offset += ALIGN_8(ptdh->DriverCount * sizeof(DUMP_DRIVER_ENTRY32));
  2760. ptdh->StringPoolOffset = Offset;
  2761. ptdh->BrokenDriverOffset = 0;
  2762. Wrapper.WriteDriverList((PBYTE)NewHeader, ptdh);
  2763. Offset = ptdh->StringPoolOffset + ptdh->StringPoolSize;
  2764. Offset = ALIGN_8(Offset);
  2765. //
  2766. // For XP and above add in any additional data pages and write out
  2767. // whatever fits.
  2768. //
  2769. if (g_Target->m_SystemVersion >= NT_SVER_XP)
  2770. {
  2771. if (SaveDataPage)
  2772. {
  2773. IoAddTriageDumpDataBlock(PAGE_ALIGN(g_Machine, SaveDataPage),
  2774. g_Machine->m_PageSize);
  2775. }
  2776. // If there are other interesting data pages, such as
  2777. // alternate stacks for DPCs and such, pick them up.
  2778. if (PrcbAddr)
  2779. {
  2780. ADDR_RANGE AltData[MAX_ALT_ADDR_RANGES];
  2781. ZeroMemory(AltData, sizeof(AltData));
  2782. if (g_Machine->GetAlternateTriageDumpDataRanges(PrcbAddr,
  2783. ThreadAddr,
  2784. AltData) == S_OK)
  2785. {
  2786. for (i = 0; i < MAX_ALT_ADDR_RANGES; i++)
  2787. {
  2788. if (AltData[i].Base)
  2789. {
  2790. IoAddTriageDumpDataBlock(AltData[i].Base,
  2791. AltData[i].Size);
  2792. }
  2793. }
  2794. }
  2795. }
  2796. // Add any data blocks that were registered
  2797. // in the debuggee.
  2798. AddInMemoryTriageDataBlocks();
  2799. // Add data blocks which might be referred to by
  2800. // the context or other runtime state.
  2801. IopAddRunTimeTriageDataBlocks(&g_Machine->m_Context,
  2802. EXTEND64(ptdh->TopOfStack),
  2803. EXTEND64(ptdh->TopOfStack +
  2804. ptdh->SizeOfCallStack),
  2805. 0, 0);
  2806. // Check which data blocks fit and write them.
  2807. Offset = IopSizeTriageDumpDataBlocks(Offset, TRIAGE_DUMP_SIZE32,
  2808. &ptdh->DataBlocksOffset,
  2809. &ptdh->DataBlocksCount);
  2810. Offset = ALIGN_8(Offset);
  2811. if (ptdh->DataBlocksCount)
  2812. {
  2813. NewHeader->Header.MiniDumpFields |= TRIAGE_DUMP_DATA_BLOCKS;
  2814. IopWriteTriageDumpDataBlocks(ptdh->DataBlocksOffset,
  2815. ptdh->DataBlocksCount,
  2816. (PUCHAR)NewHeader);
  2817. }
  2818. }
  2819. //
  2820. // all options are enabled
  2821. //
  2822. ptdh->TriageOptions = 0xffffffff;
  2823. //
  2824. // end of triage dump validated
  2825. //
  2826. ptdh->ValidOffset = TRIAGE_DUMP_SIZE32 - sizeof(ULONG);
  2827. *(PULONG)(((PBYTE) NewHeader) + ptdh->ValidOffset) = TRIAGE_DUMP_VALID;
  2828. //
  2829. // Write it out to the file.
  2830. //
  2831. ULONG cbWritten;
  2832. if (!WriteFile(File,
  2833. NewHeader,
  2834. TRIAGE_DUMP_SIZE32,
  2835. &cbWritten,
  2836. NULL))
  2837. {
  2838. Status = WIN32_LAST_STATUS();
  2839. ErrOut("Write to minidump file failed for reason %s\n \"%s\"\n",
  2840. FormatStatusCode(Status),
  2841. FormatStatusArgs(Status, NULL));
  2842. }
  2843. else if (cbWritten != TRIAGE_DUMP_SIZE32)
  2844. {
  2845. ErrOut("Write to minidump failed because disk is full.\n");
  2846. Status = HRESULT_FROM_WIN32(ERROR_DISK_FULL);
  2847. }
  2848. else
  2849. {
  2850. Status = S_OK;
  2851. }
  2852. if (PushedContext != (ContextSave*)&PushedContext)
  2853. {
  2854. g_Machine->PopContext(PushedContext);
  2855. }
  2856. NewHeader:
  2857. free(NewHeader);
  2858. return Status;
  2859. }
  2860. //----------------------------------------------------------------------------
  2861. //
  2862. // KernelTriage64DumpTargetInfo::Write.
  2863. //
  2864. //----------------------------------------------------------------------------
  2865. HRESULT
  2866. KernelTriage64DumpTargetInfo::Write(HANDLE File, ULONG FormatFlags,
  2867. PCSTR CommentA, PCWSTR CommentW)
  2868. {
  2869. HRESULT Status;
  2870. PMEMORY_DUMP64 NewHeader;
  2871. ULONG64 ThreadAddr;
  2872. ULONG CodeMod;
  2873. ULONG BugCheckCode;
  2874. ULONG64 BugCheckData[4];
  2875. ULONG64 SaveDataPage = 0;
  2876. ULONG64 BStoreBase = 0;
  2877. ULONG BStoreSize = 0;
  2878. ULONG64 PrcbAddr;
  2879. ContextSave* PushedContext;
  2880. if (!IS_KERNEL_TARGET(g_Target))
  2881. {
  2882. ErrOut("kernel minidumps can only be written "
  2883. "in kernel-mode sessions\n");
  2884. return E_UNEXPECTED;
  2885. }
  2886. dprintf("mini kernel dump\n");
  2887. FlushCallbacks();
  2888. NewHeader = (PMEMORY_DUMP64) malloc(TRIAGE_DUMP_SIZE64);
  2889. if (NewHeader == NULL)
  2890. {
  2891. return E_OUTOFMEMORY;
  2892. }
  2893. //
  2894. // Get the current thread address, used to extract various blocks of data.
  2895. // For some bugchecks the interesting thread is a different
  2896. // thread than the current thread, so make the following code
  2897. // generic so it handles any thread.
  2898. //
  2899. if ((Status = g_Target->
  2900. ReadBugCheckData(&BugCheckCode, BugCheckData)) != S_OK)
  2901. {
  2902. goto NewHeader;
  2903. }
  2904. // Set a special marker to indicate there is no pushed context.
  2905. PushedContext = (ContextSave*)&PushedContext;
  2906. if (BugCheckCode == THREAD_STUCK_IN_DEVICE_DRIVER)
  2907. {
  2908. CROSS_PLATFORM_CONTEXT Context;
  2909. // Modify the bugcheck code to indicate this
  2910. // minidump represents a special state.
  2911. CodeMod = MINIDUMP_BUGCHECK;
  2912. // The interesting thread is the first bugcheck parameter.
  2913. ThreadAddr = BugCheckData[0];
  2914. // We need to make the thread's context the current
  2915. // machine context for the duration of dump generation.
  2916. if ((Status = g_Target->
  2917. GetContextFromThreadStack(ThreadAddr, &Context, FALSE)) != S_OK)
  2918. {
  2919. goto NewHeader;
  2920. }
  2921. PushedContext = g_Machine->PushContext(&Context);
  2922. }
  2923. else if (BugCheckCode == SYSTEM_THREAD_EXCEPTION_NOT_HANDLED)
  2924. {
  2925. //
  2926. // System thread stores a context record as the 4th parameter.
  2927. // use that.
  2928. // Also save the context record in case someone needs to look
  2929. // at it.
  2930. //
  2931. if (BugCheckData[3])
  2932. {
  2933. CROSS_PLATFORM_CONTEXT TargetContext, Context;
  2934. if (CurReadAllVirtual(BugCheckData[3], &TargetContext,
  2935. g_Target->
  2936. m_TypeInfo.SizeTargetContext) == S_OK &&
  2937. g_Machine->ConvertContextFrom(&Context,
  2938. g_Target->m_SystemVersion,
  2939. g_Target->
  2940. m_TypeInfo.SizeTargetContext,
  2941. &TargetContext) == S_OK)
  2942. {
  2943. CodeMod = MINIDUMP_BUGCHECK;
  2944. PushedContext = g_Machine->PushContext(&Context);
  2945. SaveDataPage = BugCheckData[3];
  2946. }
  2947. }
  2948. }
  2949. else if (BugCheckCode == KERNEL_MODE_EXCEPTION_NOT_HANDLED)
  2950. {
  2951. CROSS_PLATFORM_CONTEXT Context;
  2952. //
  2953. // 3rd parameter is a trap frame.
  2954. //
  2955. // Build a context record out of that only if it's a kernel mode
  2956. // failure because esp may be wrong in that case ???.
  2957. //
  2958. if (BugCheckData[2] &&
  2959. g_Machine->GetContextFromTrapFrame(BugCheckData[2], &Context,
  2960. FALSE) == S_OK)
  2961. {
  2962. CodeMod = MINIDUMP_BUGCHECK;
  2963. PushedContext = g_Machine->PushContext(&Context);
  2964. SaveDataPage = BugCheckData[2];
  2965. }
  2966. }
  2967. else
  2968. {
  2969. CodeMod = 0;
  2970. if ((Status = g_Process->
  2971. GetImplicitThreadData(g_Thread, &ThreadAddr)) != S_OK)
  2972. {
  2973. goto NewHeader;
  2974. }
  2975. }
  2976. CCrashDumpWrapper64 Wrapper;
  2977. //
  2978. // setup the main header
  2979. //
  2980. KernelDumpTargetInfo::InitDumpHeader64(&NewHeader->Header,
  2981. CommentA, CommentW,
  2982. CodeMod);
  2983. NewHeader->Header.DumpType = DUMP_TYPE_TRIAGE;
  2984. NewHeader->Header.MiniDumpFields = TRIAGE_DUMP_BASIC_INFO;
  2985. NewHeader->Header.WriterStatus = DUMP_DBGENG_SUCCESS;
  2986. //
  2987. // triage dump header begins on second page
  2988. //
  2989. TRIAGE_DUMP64 *ptdh = &NewHeader->Triage;
  2990. ULONG i;
  2991. ptdh->ServicePackBuild = g_Target->m_ServicePackNumber;
  2992. ptdh->SizeOfDump = TRIAGE_DUMP_SIZE64;
  2993. ptdh->ContextOffset = FIELD_OFFSET (DUMP_HEADER64, ContextRecord);
  2994. ptdh->ExceptionOffset = FIELD_OFFSET (DUMP_HEADER64, Exception);
  2995. //
  2996. // starting Offset in triage dump follows the triage dump header
  2997. //
  2998. unsigned Offset =
  2999. ALIGN_8(sizeof(DUMP_HEADER64) + sizeof(TRIAGE_DUMP64));
  3000. //
  3001. // write mm information
  3002. //
  3003. ptdh->MmOffset = Offset;
  3004. Wrapper.WriteMmTriageInformation((PBYTE)NewHeader + ptdh->MmOffset);
  3005. Offset += ALIGN_8(sizeof(DUMP_MM_STORAGE64));
  3006. //
  3007. // write unloaded drivers
  3008. //
  3009. ptdh->UnloadedDriversOffset = Offset;
  3010. Wrapper.WriteUnloadedDrivers((PBYTE)NewHeader + ptdh->UnloadedDriversOffset);
  3011. Offset += ALIGN_8(sizeof(ULONG64) +
  3012. MI_UNLOADED_DRIVERS * sizeof(DUMP_UNLOADED_DRIVERS64));
  3013. //
  3014. // write processor control block (KPRCB)
  3015. //
  3016. if (S_OK == g_Target->GetProcessorSystemDataOffset(CURRENT_PROC,
  3017. DEBUG_DATA_KPRCB_OFFSET,
  3018. &PrcbAddr))
  3019. {
  3020. ptdh->PrcbOffset = Offset;
  3021. CurReadAllVirtual(PrcbAddr,
  3022. ((PBYTE)NewHeader) + ptdh->PrcbOffset,
  3023. g_Target->m_KdDebuggerData.SizePrcb);
  3024. Offset += ALIGN_8(g_Target->m_KdDebuggerData.SizePrcb);
  3025. }
  3026. else
  3027. {
  3028. PrcbAddr = 0;
  3029. }
  3030. //
  3031. // Write the thread and process data structures.
  3032. //
  3033. ptdh->ProcessOffset = Offset;
  3034. Offset += ALIGN_8(g_Target->m_KdDebuggerData.SizeEProcess);
  3035. ptdh->ThreadOffset = Offset;
  3036. Offset += ALIGN_8(g_Target->m_KdDebuggerData.SizeEThread);
  3037. CurReadAllVirtual(ThreadAddr +
  3038. g_Target->m_KdDebuggerData.OffsetKThreadApcProcess,
  3039. (PBYTE)NewHeader + ptdh->ProcessOffset,
  3040. g_Target->m_KdDebuggerData.SizeEProcess);
  3041. CurReadAllVirtual(ThreadAddr,
  3042. (PBYTE)NewHeader + ptdh->ThreadOffset,
  3043. g_Target->m_KdDebuggerData.SizeEThread);
  3044. //
  3045. // write the call stack
  3046. //
  3047. ADDR StackPtr;
  3048. ULONG64 StackBase = 0;
  3049. g_Machine->GetSP(&StackPtr);
  3050. ptdh->TopOfStack = Flat(StackPtr);
  3051. g_Target->ReadPointer(g_Process, g_Target->m_Machine,
  3052. g_Target->m_KdDebuggerData.OffsetKThreadInitialStack +
  3053. ThreadAddr, &StackBase);
  3054. // Take the Min in case something goes wrong getting the stack base.
  3055. ptdh->SizeOfCallStack =
  3056. min((ULONG)(ULONG_PTR)(StackBase - Flat(StackPtr)),
  3057. MAX_TRIAGE_STACK_SIZE64);
  3058. ptdh->CallStackOffset = Offset;
  3059. if (ptdh->SizeOfCallStack)
  3060. {
  3061. CurReadAllVirtual(ptdh->TopOfStack,
  3062. ((PBYTE)NewHeader) + ptdh->CallStackOffset,
  3063. ptdh->SizeOfCallStack);
  3064. }
  3065. Offset += ALIGN_8(ptdh->SizeOfCallStack);
  3066. //
  3067. // The IA64 contains two callstacks. The first is the normal
  3068. // callstack, and the second is a scratch region where
  3069. // the processor can spill registers. It is this latter stack,
  3070. // the backing-store, that we now save.
  3071. //
  3072. if (g_Target->m_MachineType == IMAGE_FILE_MACHINE_IA64)
  3073. {
  3074. ULONG64 BStoreLimit;
  3075. g_Target->ReadPointer(g_Process, g_Target->m_Machine,
  3076. ThreadAddr +
  3077. g_Target->m_KdDebuggerData.OffsetKThreadBStore,
  3078. &BStoreBase);
  3079. g_Target->ReadPointer(g_Process, g_Target->m_Machine,
  3080. ThreadAddr +
  3081. g_Target->m_KdDebuggerData.OffsetKThreadBStoreLimit,
  3082. &BStoreLimit);
  3083. ptdh->ArchitectureSpecific.Ia64.BStoreOffset = Offset;
  3084. ptdh->ArchitectureSpecific.Ia64.LimitOfBStore = BStoreLimit;
  3085. ptdh->ArchitectureSpecific.Ia64.SizeOfBStore =
  3086. min((ULONG)(BStoreLimit - BStoreBase),
  3087. MAX_TRIAGE_BSTORE_SIZE);
  3088. BStoreSize = ptdh->ArchitectureSpecific.Ia64.SizeOfBStore;
  3089. if (ptdh->ArchitectureSpecific.Ia64.SizeOfBStore)
  3090. {
  3091. CurReadAllVirtual(BStoreBase, ((PBYTE)NewHeader) +
  3092. ptdh->ArchitectureSpecific.Ia64.BStoreOffset,
  3093. ptdh->ArchitectureSpecific.Ia64.SizeOfBStore);
  3094. Offset +=
  3095. ALIGN_8(ptdh->ArchitectureSpecific.Ia64.SizeOfBStore);
  3096. }
  3097. }
  3098. //
  3099. // write debugger data
  3100. //
  3101. if (g_Target->m_SystemVersion >= NT_SVER_XP &&
  3102. g_Target->m_KdDebuggerDataOffset &&
  3103. (!IS_KERNEL_TRIAGE_DUMP(g_Target) ||
  3104. ((KernelTriageDumpTargetInfo*)g_Target)->m_HasDebuggerData) &&
  3105. Offset +
  3106. ALIGN_8(sizeof(g_Target->m_KdDebuggerData)) < TRIAGE_DUMP_SIZE64)
  3107. {
  3108. NewHeader->Header.MiniDumpFields |= TRIAGE_DUMP_DEBUGGER_DATA;
  3109. ptdh->DebuggerDataOffset = Offset;
  3110. Offset += ALIGN_8(sizeof(g_Target->m_KdDebuggerData));
  3111. ptdh->DebuggerDataSize = sizeof(g_Target->m_KdDebuggerData);
  3112. memcpy((PBYTE)NewHeader + ptdh->DebuggerDataOffset,
  3113. &g_Target->m_KdDebuggerData,
  3114. sizeof(g_Target->m_KdDebuggerData));
  3115. }
  3116. //
  3117. // write loaded driver list
  3118. //
  3119. ModuleInfo* ModIter;
  3120. ULONG MaxEntries;
  3121. // Use a heuristic to guess how many entries we
  3122. // can pack into the remaining space.
  3123. MaxEntries = (TRIAGE_DUMP_SIZE64 - Offset) /
  3124. (sizeof(DUMP_DRIVER_ENTRY64) + TRIAGE_DRIVER_NAME_SIZE_GUESS);
  3125. ptdh->DriverCount = 0;
  3126. if (ModIter = g_Target->GetModuleInfo(FALSE))
  3127. {
  3128. if ((Status = ModIter->Initialize(g_Thread)) == S_OK)
  3129. {
  3130. while (ptdh->DriverCount < MaxEntries)
  3131. {
  3132. MODULE_INFO_ENTRY ModEntry;
  3133. ULONG retval = GetNextModuleEntry(ModIter, &ModEntry);
  3134. if (retval == GNME_CORRUPT ||
  3135. retval == GNME_DONE)
  3136. {
  3137. if (retval == GNME_CORRUPT)
  3138. {
  3139. NewHeader->Header.WriterStatus =
  3140. DUMP_DBGENG_CORRUPT_MODULE_LIST;
  3141. }
  3142. break;
  3143. }
  3144. else if (retval == GNME_NO_NAME)
  3145. {
  3146. continue;
  3147. }
  3148. ptdh->DriverCount++;
  3149. }
  3150. }
  3151. else
  3152. {
  3153. NewHeader->Header.WriterStatus =
  3154. DUMP_DBGENG_NO_MODULE_LIST;
  3155. }
  3156. }
  3157. ptdh->DriverListOffset = Offset;
  3158. Offset += ALIGN_8(ptdh->DriverCount * sizeof(DUMP_DRIVER_ENTRY64));
  3159. ptdh->StringPoolOffset = Offset;
  3160. ptdh->BrokenDriverOffset = 0;
  3161. Wrapper.WriteDriverList((PBYTE)NewHeader, ptdh);
  3162. Offset = ptdh->StringPoolOffset + ptdh->StringPoolSize;
  3163. Offset = ALIGN_8(Offset);
  3164. //
  3165. // For XP and above add in any additional data pages and write out
  3166. // whatever fits.
  3167. //
  3168. if (g_Target->m_SystemVersion >= NT_SVER_XP)
  3169. {
  3170. if (SaveDataPage)
  3171. {
  3172. IoAddTriageDumpDataBlock(PAGE_ALIGN(g_Machine, SaveDataPage),
  3173. g_Machine->m_PageSize);
  3174. }
  3175. // If there are other interesting data pages, such as
  3176. // alternate stacks for DPCs and such, pick them up.
  3177. if (PrcbAddr)
  3178. {
  3179. ADDR_RANGE AltData[MAX_ALT_ADDR_RANGES];
  3180. ZeroMemory(AltData, sizeof(AltData));
  3181. if (g_Machine->GetAlternateTriageDumpDataRanges(PrcbAddr,
  3182. ThreadAddr,
  3183. AltData) == S_OK)
  3184. {
  3185. for (i = 0; i < MAX_ALT_ADDR_RANGES; i++)
  3186. {
  3187. if (AltData[i].Base)
  3188. {
  3189. IoAddTriageDumpDataBlock(AltData[i].Base,
  3190. AltData[i].Size);
  3191. }
  3192. }
  3193. }
  3194. }
  3195. // Add any data blocks that were registered
  3196. // in the debuggee.
  3197. AddInMemoryTriageDataBlocks();
  3198. // Add data blocks which might be referred to by
  3199. // the context or other runtime state.
  3200. IopAddRunTimeTriageDataBlocks(&g_Machine->m_Context,
  3201. ptdh->TopOfStack,
  3202. ptdh->TopOfStack +
  3203. ptdh->SizeOfCallStack,
  3204. BStoreBase,
  3205. BStoreSize);
  3206. // Check which data blocks fit and write them.
  3207. Offset = IopSizeTriageDumpDataBlocks(Offset, TRIAGE_DUMP_SIZE64,
  3208. &ptdh->DataBlocksOffset,
  3209. &ptdh->DataBlocksCount);
  3210. Offset = ALIGN_8(Offset);
  3211. if (ptdh->DataBlocksCount)
  3212. {
  3213. NewHeader->Header.MiniDumpFields |= TRIAGE_DUMP_DATA_BLOCKS;
  3214. IopWriteTriageDumpDataBlocks(ptdh->DataBlocksOffset,
  3215. ptdh->DataBlocksCount,
  3216. (PUCHAR)NewHeader);
  3217. }
  3218. }
  3219. //
  3220. // all options are enabled
  3221. //
  3222. ptdh->TriageOptions = 0xffffffff;
  3223. //
  3224. // end of triage dump validated
  3225. //
  3226. ptdh->ValidOffset = TRIAGE_DUMP_SIZE64 - sizeof(ULONG);
  3227. *(PULONG)(((PBYTE) NewHeader) + ptdh->ValidOffset) = TRIAGE_DUMP_VALID;
  3228. //
  3229. // Write it out to the file.
  3230. //
  3231. ULONG cbWritten;
  3232. if (!WriteFile(File,
  3233. NewHeader,
  3234. TRIAGE_DUMP_SIZE64,
  3235. &cbWritten,
  3236. NULL))
  3237. {
  3238. Status = WIN32_LAST_STATUS();
  3239. ErrOut("Write to minidump file failed for reason %s\n \"%s\"\n",
  3240. FormatStatusCode(Status),
  3241. FormatStatusArgs(Status, NULL));
  3242. }
  3243. else if (cbWritten != TRIAGE_DUMP_SIZE64)
  3244. {
  3245. ErrOut("Write to minidump failed because disk is full.\n");
  3246. Status = HRESULT_FROM_WIN32(ERROR_DISK_FULL);
  3247. }
  3248. else
  3249. {
  3250. Status = S_OK;
  3251. }
  3252. if (PushedContext != (ContextSave*)&PushedContext)
  3253. {
  3254. g_Machine->PopContext(PushedContext);
  3255. }
  3256. NewHeader:
  3257. free(NewHeader);
  3258. return Status;
  3259. }
  3260. //----------------------------------------------------------------------------
  3261. //
  3262. // Functions.
  3263. //
  3264. //----------------------------------------------------------------------------
  3265. HRESULT
  3266. WriteDumpFile(PCWSTR FileName, ULONG64 FileHandle,
  3267. ULONG Qualifier, ULONG FormatFlags,
  3268. PCSTR CommentA, PCWSTR CommentW)
  3269. {
  3270. ULONG DumpType = DTYPE_COUNT;
  3271. DumpTargetInfo* WriteTarget;
  3272. HRESULT Status;
  3273. ULONG OldMachine;
  3274. WCHAR TempFile[2 * MAX_PATH];
  3275. PCWSTR DumpWriteFile;
  3276. HANDLE DumpWriteHandle;
  3277. PSTR AnsiFile = NULL;
  3278. BOOL CreatedAnsi = FALSE;
  3279. if (!IS_CUR_MACHINE_ACCESSIBLE())
  3280. {
  3281. return E_UNEXPECTED;
  3282. }
  3283. if (IS_KERNEL_TARGET(g_Target))
  3284. {
  3285. DbgKdTransport* KdTrans;
  3286. if (FormatFlags & ~GENERIC_FORMATS)
  3287. {
  3288. return E_INVALIDARG;
  3289. }
  3290. //
  3291. // not much we can do without the processor block
  3292. // or at least the PRCB for the current process in a minidump.
  3293. //
  3294. if (!g_Target->m_KdDebuggerData.KiProcessorBlock &&
  3295. IS_DUMP_TARGET(g_Target) &&
  3296. !((KernelDumpTargetInfo*)g_Target)->m_KiProcessors[CURRENT_PROC])
  3297. {
  3298. ErrOut("Cannot find KiProcessorBlock - "
  3299. "can not create dump file\n");
  3300. return E_FAIL;
  3301. }
  3302. if (IS_CONN_KERNEL_TARGET(g_Target))
  3303. {
  3304. KdTrans = ((ConnLiveKernelTargetInfo*)g_Target)->m_Transport;
  3305. }
  3306. else
  3307. {
  3308. KdTrans = NULL;
  3309. }
  3310. switch(Qualifier)
  3311. {
  3312. case DEBUG_KERNEL_SMALL_DUMP:
  3313. DumpType = g_Target->m_Machine->m_Ptr64 ?
  3314. DTYPE_KERNEL_TRIAGE64 : DTYPE_KERNEL_TRIAGE32;
  3315. break;
  3316. case DEBUG_KERNEL_FULL_DUMP:
  3317. if (KdTrans != NULL &&
  3318. KdTrans->m_DirectPhysicalMemory == FALSE)
  3319. {
  3320. WarnOut("Creating a full kernel dump over the COM port is a "
  3321. "VERY VERY slow operation.\n"
  3322. "This command may take many HOURS to complete. "
  3323. "Ctrl-C if you want to terminate the command.\n");
  3324. }
  3325. DumpType = g_Target->m_Machine->m_Ptr64 ?
  3326. DTYPE_KERNEL_FULL64 : DTYPE_KERNEL_FULL32;
  3327. break;
  3328. default:
  3329. // Other formats are not supported.
  3330. return E_INVALIDARG;
  3331. }
  3332. }
  3333. else
  3334. {
  3335. DBG_ASSERT(IS_USER_TARGET(g_Target));
  3336. switch(Qualifier)
  3337. {
  3338. case DEBUG_USER_WINDOWS_SMALL_DUMP:
  3339. if (FormatFlags & ~(GENERIC_FORMATS |
  3340. UMINI_FORMATS |
  3341. FORMAT_USER_MICRO))
  3342. {
  3343. return E_INVALIDARG;
  3344. }
  3345. DumpType = (FormatFlags & DEBUG_FORMAT_USER_SMALL_FULL_MEMORY) ?
  3346. DTYPE_USER_MINI_FULL : DTYPE_USER_MINI_PARTIAL;
  3347. break;
  3348. case DEBUG_USER_WINDOWS_DUMP:
  3349. if (FormatFlags & ~GENERIC_FORMATS)
  3350. {
  3351. return E_INVALIDARG;
  3352. }
  3353. DumpType = g_Target->m_Machine->m_Ptr64 ?
  3354. DTYPE_USER_FULL64 : DTYPE_USER_FULL32;
  3355. break;
  3356. default:
  3357. // Other formats are not supported.
  3358. return E_INVALIDARG;
  3359. }
  3360. }
  3361. WriteTarget = NewDumpTargetInfo(DumpType);
  3362. if (WriteTarget == NULL)
  3363. {
  3364. ErrOut("Unable to create dump write target\n");
  3365. return E_OUTOFMEMORY;
  3366. }
  3367. // Ensure that the dump is always written according to the
  3368. // target machine type and not any emulated machine.
  3369. OldMachine = g_Target->m_EffMachineType;
  3370. g_Target->SetEffMachine(g_Target->m_MachineType, FALSE);
  3371. // Flush context first so that the minidump reads the
  3372. // same register values the debugger has.
  3373. g_Target->FlushRegContext();
  3374. //
  3375. // If we're producing a CAB put the dump in a temp file.
  3376. //
  3377. if (FormatFlags & DEBUG_FORMAT_WRITE_CAB)
  3378. {
  3379. if (FileHandle)
  3380. {
  3381. Status = E_INVALIDARG;
  3382. goto Exit;
  3383. }
  3384. if (!GetTempPathW(DIMA(TempFile), TempFile))
  3385. {
  3386. wcscpy(TempFile, L".\\");
  3387. }
  3388. // Use the CAB name as the dump file name so the
  3389. // name in the CAB will match.
  3390. CatStringW(TempFile, PathTailW(FileName), DIMA(TempFile));
  3391. CatStringW(TempFile, L".dmp", DIMA(TempFile));
  3392. DumpWriteFile = TempFile;
  3393. FormatFlags &= ~DEBUG_FORMAT_NO_OVERWRITE;
  3394. }
  3395. else
  3396. {
  3397. DumpWriteFile = FileName;
  3398. if (!DumpWriteFile)
  3399. {
  3400. DumpWriteFile = L"<HandleOnly>";
  3401. }
  3402. }
  3403. if (FileHandle)
  3404. {
  3405. DumpWriteHandle = OS_HANDLE(FileHandle);
  3406. if (!DumpWriteHandle || DumpWriteHandle == INVALID_HANDLE_VALUE)
  3407. {
  3408. Status = E_INVALIDARG;
  3409. }
  3410. else
  3411. {
  3412. Status = S_OK;
  3413. }
  3414. }
  3415. else if ((Status = WideToAnsi(DumpWriteFile, &AnsiFile)) == S_OK)
  3416. {
  3417. // Dumps are almost always written sequentially so
  3418. // add that hint to the file flags.
  3419. DumpWriteHandle =
  3420. CreateFileW(DumpWriteFile,
  3421. GENERIC_READ | GENERIC_WRITE,
  3422. 0,
  3423. NULL,
  3424. (FormatFlags & DEBUG_FORMAT_NO_OVERWRITE) ?
  3425. CREATE_NEW : CREATE_ALWAYS,
  3426. FILE_ATTRIBUTE_NORMAL |
  3427. FILE_FLAG_SEQUENTIAL_SCAN,
  3428. NULL);
  3429. if ((!DumpWriteHandle || DumpWriteHandle == INVALID_HANDLE_VALUE) &&
  3430. GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
  3431. {
  3432. //
  3433. // ANSI-only system. It's Win9x so don't
  3434. // bother with sequential scan.
  3435. //
  3436. DumpWriteHandle =
  3437. CreateFileA(AnsiFile,
  3438. GENERIC_READ | GENERIC_WRITE,
  3439. 0,
  3440. NULL,
  3441. (FormatFlags & DEBUG_FORMAT_NO_OVERWRITE) ?
  3442. CREATE_NEW : CREATE_ALWAYS,
  3443. FILE_ATTRIBUTE_NORMAL,
  3444. NULL);
  3445. CreatedAnsi = TRUE;
  3446. }
  3447. if (!DumpWriteHandle || DumpWriteHandle == INVALID_HANDLE_VALUE)
  3448. {
  3449. Status = WIN32_LAST_STATUS();
  3450. ErrOut("Unable to create file '%ws' - %s\n \"%s\"\n",
  3451. DumpWriteFile,
  3452. FormatStatusCode(Status), FormatStatus(Status));
  3453. }
  3454. }
  3455. if (Status == S_OK)
  3456. {
  3457. dprintf("Creating %ws - ", DumpWriteFile);
  3458. Status = WriteTarget->Write(DumpWriteHandle, FormatFlags,
  3459. CommentA, CommentW);
  3460. if (!FileHandle)
  3461. {
  3462. CloseHandle(DumpWriteHandle);
  3463. if (Status != S_OK)
  3464. {
  3465. if (CreatedAnsi)
  3466. {
  3467. DeleteFileA(AnsiFile);
  3468. }
  3469. else
  3470. {
  3471. DeleteFileW(DumpWriteFile);
  3472. }
  3473. }
  3474. }
  3475. }
  3476. if (Status == S_OK && (FormatFlags & DEBUG_FORMAT_WRITE_CAB))
  3477. {
  3478. PSTR AnsiBaseFile;
  3479. if ((Status = WideToAnsi(FileName, &AnsiBaseFile)) == S_OK)
  3480. {
  3481. Status = CreateCabFromDump(AnsiFile, AnsiBaseFile, FormatFlags);
  3482. FreeAnsi(AnsiBaseFile);
  3483. }
  3484. if (CreatedAnsi)
  3485. {
  3486. DeleteFileA(AnsiFile);
  3487. }
  3488. else
  3489. {
  3490. DeleteFileW(TempFile);
  3491. }
  3492. }
  3493. Exit:
  3494. FreeAnsi(AnsiFile);
  3495. g_Target->SetEffMachine(OldMachine, FALSE);
  3496. delete WriteTarget;
  3497. return Status;
  3498. }
  3499. void
  3500. DotDump(PDOT_COMMAND Cmd, DebugClient* Client)
  3501. {
  3502. BOOL Usage = FALSE;
  3503. ULONG Qual;
  3504. ULONG FormatFlags;
  3505. //
  3506. // Default to minidumps
  3507. //
  3508. if (IS_KERNEL_TARGET(g_Target))
  3509. {
  3510. Qual = DEBUG_KERNEL_SMALL_DUMP;
  3511. if (IS_LOCAL_KERNEL_TARGET(g_Target))
  3512. {
  3513. error(SESSIONNOTSUP);
  3514. }
  3515. }
  3516. else
  3517. {
  3518. Qual = DEBUG_USER_WINDOWS_SMALL_DUMP;
  3519. }
  3520. FormatFlags = DEBUG_FORMAT_DEFAULT | DEBUG_FORMAT_NO_OVERWRITE;
  3521. //
  3522. // Scan for options.
  3523. //
  3524. CHAR Save;
  3525. PSTR FileName;
  3526. BOOL SubLoop;
  3527. PCSTR Comment = NULL;
  3528. PSTR CommentEnd = NULL;
  3529. BOOL Unique = FALSE;
  3530. ProcessInfo* DumpProcess = g_Process;
  3531. for (;;)
  3532. {
  3533. if (PeekChar() == '-' || *g_CurCmd == '/')
  3534. {
  3535. SubLoop = TRUE;
  3536. g_CurCmd++;
  3537. switch(*g_CurCmd)
  3538. {
  3539. case 'a':
  3540. DumpProcess = NULL;
  3541. break;
  3542. case 'b':
  3543. FormatFlags |= DEBUG_FORMAT_WRITE_CAB;
  3544. g_CurCmd++;
  3545. if (*g_CurCmd == 'a')
  3546. {
  3547. FormatFlags |= DEBUG_FORMAT_CAB_SECONDARY_FILES;
  3548. g_CurCmd++;
  3549. }
  3550. break;
  3551. case 'c':
  3552. g_CurCmd++;
  3553. Comment = StringValue(STRV_SPACE_IS_SEPARATOR |
  3554. STRV_TRIM_TRAILING_SPACE, &Save);
  3555. *g_CurCmd = Save;
  3556. CommentEnd = g_CurCmd;
  3557. break;
  3558. case 'f':
  3559. if (IS_KERNEL_TARGET(g_Target))
  3560. {
  3561. Qual = DEBUG_KERNEL_FULL_DUMP;
  3562. }
  3563. else
  3564. {
  3565. Qual = DEBUG_USER_WINDOWS_DUMP;
  3566. }
  3567. break;
  3568. case 'm':
  3569. if (IS_KERNEL_TARGET(g_Target))
  3570. {
  3571. Qual = DEBUG_KERNEL_SMALL_DUMP;
  3572. }
  3573. else
  3574. {
  3575. Qual = DEBUG_USER_WINDOWS_SMALL_DUMP;
  3576. for (;;)
  3577. {
  3578. switch(*(g_CurCmd + 1))
  3579. {
  3580. case 'a':
  3581. // Synthetic flag meaning "save the
  3582. // maximum amount of data."
  3583. FormatFlags |=
  3584. DEBUG_FORMAT_USER_SMALL_FULL_MEMORY |
  3585. DEBUG_FORMAT_USER_SMALL_HANDLE_DATA |
  3586. DEBUG_FORMAT_USER_SMALL_UNLOADED_MODULES;
  3587. break;
  3588. case 'C':
  3589. // Flag to test microdump code.
  3590. FormatFlags |= FORMAT_USER_MICRO;
  3591. break;
  3592. case 'd':
  3593. FormatFlags |=
  3594. DEBUG_FORMAT_USER_SMALL_DATA_SEGMENTS;
  3595. break;
  3596. case 'f':
  3597. FormatFlags |= DEBUG_FORMAT_USER_SMALL_FULL_MEMORY;
  3598. break;
  3599. case 'h':
  3600. FormatFlags |= DEBUG_FORMAT_USER_SMALL_HANDLE_DATA;
  3601. break;
  3602. case 'i':
  3603. FormatFlags |=
  3604. DEBUG_FORMAT_USER_SMALL_INDIRECT_MEMORY;
  3605. break;
  3606. case 'p':
  3607. FormatFlags |=
  3608. DEBUG_FORMAT_USER_SMALL_PROCESS_THREAD_DATA;
  3609. break;
  3610. case 'r':
  3611. FormatFlags |=
  3612. DEBUG_FORMAT_USER_SMALL_FILTER_MEMORY;
  3613. break;
  3614. case 'R':
  3615. FormatFlags |=
  3616. DEBUG_FORMAT_USER_SMALL_FILTER_PATHS;
  3617. break;
  3618. case 'u':
  3619. FormatFlags |=
  3620. DEBUG_FORMAT_USER_SMALL_UNLOADED_MODULES;
  3621. break;
  3622. case 'w':
  3623. FormatFlags |=
  3624. DEBUG_FORMAT_USER_SMALL_PRIVATE_READ_WRITE_MEMORY;
  3625. break;
  3626. default:
  3627. SubLoop = FALSE;
  3628. break;
  3629. }
  3630. if (SubLoop)
  3631. {
  3632. g_CurCmd++;
  3633. }
  3634. else
  3635. {
  3636. break;
  3637. }
  3638. }
  3639. }
  3640. break;
  3641. case 'o':
  3642. FormatFlags &= ~DEBUG_FORMAT_NO_OVERWRITE;
  3643. break;
  3644. case 'u':
  3645. Unique = TRUE;
  3646. break;
  3647. case '?':
  3648. Usage = TRUE;
  3649. break;
  3650. default:
  3651. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  3652. Usage = TRUE;
  3653. break;
  3654. }
  3655. g_CurCmd++;
  3656. }
  3657. else
  3658. {
  3659. FileName = StringValue(STRV_TRIM_TRAILING_SPACE, &Save);
  3660. if (*FileName)
  3661. {
  3662. break;
  3663. }
  3664. else
  3665. {
  3666. *g_CurCmd = Save;
  3667. Usage = TRUE;
  3668. }
  3669. }
  3670. if (Usage)
  3671. {
  3672. break;
  3673. }
  3674. }
  3675. if (DumpProcess == NULL && !Unique)
  3676. {
  3677. Usage = TRUE;
  3678. }
  3679. if (Usage)
  3680. {
  3681. ErrOut("Usage: .dump [options] filename\n");
  3682. ErrOut("Options are:\n");
  3683. ErrOut(" /a - Create dumps for all processes (requires -u)\n");
  3684. ErrOut(" /b[a] - Package dump in a CAB and delete dump\n");
  3685. ErrOut(" /c <comment> - Add a comment "
  3686. "(not supported in all formats)\n");
  3687. ErrOut(" /f - Create a full dump\n");
  3688. if (IS_KERNEL_TARGET(g_Target))
  3689. {
  3690. ErrOut(" /m - Create a minidump (default)\n");
  3691. }
  3692. else
  3693. {
  3694. ErrOut(" /m[adfhiprRuw] - Create a minidump (default)\n");
  3695. }
  3696. ErrOut(" /o - Overwrite any existing file\n");
  3697. ErrOut(" /u - Append unique identifier to dump name\n");
  3698. ErrOut("\nUse \".hh .dump\" or open debugger.chm in the "
  3699. "debuggers directory to get\n"
  3700. "detailed documentation on this command.\n\n");
  3701. return;
  3702. }
  3703. if (CommentEnd != NULL)
  3704. {
  3705. *CommentEnd = 0;
  3706. }
  3707. ThreadInfo* OldThread = g_Thread;
  3708. TargetInfo* Target;
  3709. ProcessInfo* Process;
  3710. ForAllLayersToProcess()
  3711. {
  3712. PSTR DumpFileName;
  3713. char UniqueName[2 * MAX_PATH];
  3714. if (DumpProcess != NULL && Process != DumpProcess)
  3715. {
  3716. continue;
  3717. }
  3718. if (Process != g_Process)
  3719. {
  3720. SetCurrentThread(Process->m_ThreadHead, TRUE);
  3721. }
  3722. if (Unique)
  3723. {
  3724. MakeFileNameUnique(FileName, UniqueName, DIMA(UniqueName),
  3725. TRUE, g_Process);
  3726. DumpFileName = UniqueName;
  3727. }
  3728. else
  3729. {
  3730. DumpFileName = FileName;
  3731. }
  3732. PWSTR WideName;
  3733. if (AnsiToWide(DumpFileName, &WideName) == S_OK)
  3734. {
  3735. WriteDumpFile(WideName, 0, Qual, FormatFlags, Comment, NULL);
  3736. FreeWide(WideName);
  3737. }
  3738. else
  3739. {
  3740. ErrOut("Unable to convert dump filename\n");
  3741. }
  3742. }
  3743. if (!OldThread || OldThread->m_Process != g_Process)
  3744. {
  3745. SetCurrentThread(OldThread, TRUE);
  3746. }
  3747. *g_CurCmd = Save;
  3748. }
  3749. BOOL
  3750. DumpCabAdd(PCSTR File)
  3751. {
  3752. HRESULT Status;
  3753. dprintf(" Adding %s - ", File);
  3754. FlushCallbacks();
  3755. if ((Status = AddToDumpCab(File)) != S_OK)
  3756. {
  3757. ErrOut("%s\n", FormatStatusCode(Status));
  3758. }
  3759. else
  3760. {
  3761. dprintf("added\n");
  3762. }
  3763. if (CheckUserInterrupt())
  3764. {
  3765. return FALSE;
  3766. }
  3767. FlushCallbacks();
  3768. return TRUE;
  3769. }
  3770. HRESULT
  3771. CreateCabFromDump(PCSTR DumpFile, PCSTR CabFile, ULONG Flags)
  3772. {
  3773. HRESULT Status;
  3774. if ((Status = CreateDumpCab(CabFile)) != S_OK)
  3775. {
  3776. ErrOut("Unable to create CAB, %s\n", FormatStatusCode(Status));
  3777. return Status;
  3778. }
  3779. WarnOut("Creating a cab file can take a VERY VERY long time\n."
  3780. "Ctrl-C can only interrupt the command after a file "
  3781. "has been added to the cab.\n");
  3782. //
  3783. // First add all base dump files.
  3784. //
  3785. if (!DumpFile)
  3786. {
  3787. DumpTargetInfo* Dump = (DumpTargetInfo*)g_Target;
  3788. ULONG i;
  3789. for (i = DUMP_INFO_DUMP; i < DUMP_INFO_COUNT; i++)
  3790. {
  3791. if (Dump->m_InfoFiles[i].m_File)
  3792. {
  3793. if (!DumpCabAdd(Dump->m_InfoFiles[i].m_FileNameA))
  3794. {
  3795. Status = E_UNEXPECTED;
  3796. goto Leave;
  3797. }
  3798. }
  3799. }
  3800. }
  3801. else
  3802. {
  3803. if (!DumpCabAdd(DumpFile))
  3804. {
  3805. Status = E_UNEXPECTED;
  3806. goto Leave;
  3807. }
  3808. }
  3809. if (Flags & DEBUG_FORMAT_CAB_SECONDARY_FILES)
  3810. {
  3811. ImageInfo* Image;
  3812. //
  3813. // Add all symbols and images.
  3814. //
  3815. for (Image = g_Process->m_ImageHead; Image; Image = Image->m_Next)
  3816. {
  3817. if (Image->m_MappedImagePath[0])
  3818. {
  3819. if (!DumpCabAdd(Image->m_MappedImagePath))
  3820. {
  3821. Status = E_UNEXPECTED;
  3822. break;
  3823. }
  3824. }
  3825. IMAGEHLP_MODULE64 ModInfo;
  3826. ModInfo.SizeOfStruct = sizeof(ModInfo);
  3827. if (SymGetModuleInfo64(g_Process->m_SymHandle,
  3828. Image->m_BaseOfImage, &ModInfo))
  3829. {
  3830. ULONG Len;
  3831. // The loaded image name often refers directly to the
  3832. // image. Only save the loaded image file if it
  3833. // refers to a .dbg file.
  3834. if (ModInfo.LoadedImageName[0] &&
  3835. (Len = strlen(ModInfo.LoadedImageName)) > 4 &&
  3836. !_stricmp(ModInfo.LoadedImageName + (Len - 4), ".dbg"))
  3837. {
  3838. if (!DumpCabAdd(ModInfo.LoadedImageName))
  3839. {
  3840. Status = E_UNEXPECTED;
  3841. break;
  3842. }
  3843. }
  3844. // Save any PDB that was opened.
  3845. if (ModInfo.LoadedPdbName[0])
  3846. {
  3847. if (!DumpCabAdd(ModInfo.LoadedPdbName))
  3848. {
  3849. Status = E_UNEXPECTED;
  3850. break;
  3851. }
  3852. }
  3853. }
  3854. }
  3855. }
  3856. Leave:
  3857. CloseDumpCab();
  3858. if (Status == S_OK)
  3859. {
  3860. dprintf("Wrote %s\n", CabFile);
  3861. }
  3862. return Status;
  3863. }
  3864. // extern PKDDEBUGGER_DATA64 blocks[];
  3865. #define ALIGN_DOWN_POINTER(address, type) \
  3866. ((PVOID)((ULONG_PTR)(address) & ~((ULONG_PTR)sizeof(type) - 1)))
  3867. #define ALIGN_UP_POINTER(address, type) \
  3868. (ALIGN_DOWN_POINTER(((ULONG_PTR)(address) + sizeof(type) - 1), type))
  3869. //----------------------------------------------------------------------------
  3870. //
  3871. // CCrashDumpWrapper32.
  3872. //
  3873. //----------------------------------------------------------------------------
  3874. void
  3875. CCrashDumpWrapper32::WriteDriverList(
  3876. BYTE *pb,
  3877. TRIAGE_DUMP32 *ptdh
  3878. )
  3879. {
  3880. PDUMP_DRIVER_ENTRY32 pdde;
  3881. PDUMP_STRING pds;
  3882. ModuleInfo* ModIter;
  3883. ULONG MaxEntries = ptdh->DriverCount;
  3884. ptdh->DriverCount = 0;
  3885. if (((ModIter = g_Target->GetModuleInfo(FALSE)) == NULL) ||
  3886. ((ModIter->Initialize(g_Thread)) != S_OK))
  3887. {
  3888. return;
  3889. }
  3890. // pointer to first driver entry to write out
  3891. pdde = (PDUMP_DRIVER_ENTRY32) (pb + ptdh->DriverListOffset);
  3892. // pointer to first module name to write out
  3893. pds = (PDUMP_STRING) (pb + ptdh->StringPoolOffset);
  3894. while ((PBYTE)(pds + 1) < pb + TRIAGE_DUMP_SIZE32 &&
  3895. ptdh->DriverCount < MaxEntries)
  3896. {
  3897. MODULE_INFO_ENTRY ModEntry;
  3898. ULONG retval = GetNextModuleEntry(ModIter, &ModEntry);
  3899. if (retval == GNME_CORRUPT ||
  3900. retval == GNME_DONE)
  3901. {
  3902. break;
  3903. }
  3904. else if (retval == GNME_NO_NAME)
  3905. {
  3906. continue;
  3907. }
  3908. pdde->LdrEntry.DllBase = (ULONG)(ULONG_PTR)ModEntry.Base;
  3909. pdde->LdrEntry.SizeOfImage = ModEntry.Size;
  3910. pdde->LdrEntry.CheckSum = ModEntry.CheckSum;
  3911. pdde->LdrEntry.TimeDateStamp = ModEntry.TimeDateStamp;
  3912. if (ModEntry.UnicodeNamePtr)
  3913. {
  3914. // convert length from bytes to characters
  3915. pds->Length = ModEntry.NameLength / sizeof(WCHAR);
  3916. if ((PBYTE)pds->Buffer + pds->Length + sizeof(WCHAR) >
  3917. pb + TRIAGE_DUMP_SIZE32)
  3918. {
  3919. break;
  3920. }
  3921. CopyMemory(pds->Buffer,
  3922. ModEntry.NamePtr,
  3923. ModEntry.NameLength);
  3924. }
  3925. else
  3926. {
  3927. pds->Length = ModEntry.NameLength;
  3928. if ((PBYTE)pds->Buffer + pds->Length + sizeof(WCHAR) >
  3929. pb + TRIAGE_DUMP_SIZE32)
  3930. {
  3931. break;
  3932. }
  3933. MultiByteToWideChar(CP_ACP, 0,
  3934. ModEntry.NamePtr, ModEntry.NameLength,
  3935. pds->Buffer, ModEntry.NameLength);
  3936. }
  3937. // null terminate string
  3938. pds->Buffer[pds->Length] = '\0';
  3939. pdde->DriverNameOffset = (ULONG)((ULONG_PTR) pds - (ULONG_PTR) pb);
  3940. // get pointer to next string
  3941. pds = (PDUMP_STRING) ALIGN_UP_POINTER(((LPBYTE) pds) +
  3942. sizeof(DUMP_STRING) + sizeof(WCHAR) * (pds->Length + 1),
  3943. ULONGLONG);
  3944. pdde = (PDUMP_DRIVER_ENTRY32)(((PUCHAR) pdde) + sizeof(*pdde));
  3945. ptdh->DriverCount++;
  3946. }
  3947. ptdh->StringPoolSize = (ULONG) ((ULONG_PTR)pds -
  3948. (ULONG_PTR)(pb + ptdh->StringPoolOffset));
  3949. }
  3950. void CCrashDumpWrapper32::WriteUnloadedDrivers(BYTE *pb)
  3951. {
  3952. ULONG i;
  3953. ULONG Index;
  3954. UNLOADED_DRIVERS32 ud;
  3955. PDUMP_UNLOADED_DRIVERS32 pdud;
  3956. ULONG64 pvMiUnloadedDrivers=0;
  3957. ULONG ulMiLastUnloadedDriver=0;
  3958. *((PULONG) pb) = 0;
  3959. //
  3960. // find location of unloaded drivers
  3961. //
  3962. if (!g_Target->m_KdDebuggerData.MmUnloadedDrivers ||
  3963. !g_Target->m_KdDebuggerData.MmLastUnloadedDriver)
  3964. {
  3965. return;
  3966. }
  3967. g_Target->ReadPointer(g_Process, g_Target->m_Machine,
  3968. g_Target->m_KdDebuggerData.MmUnloadedDrivers,
  3969. &pvMiUnloadedDrivers);
  3970. CurReadAllVirtual(g_Target->m_KdDebuggerData.MmLastUnloadedDriver,
  3971. &ulMiLastUnloadedDriver,
  3972. sizeof(ULONG));
  3973. if (pvMiUnloadedDrivers == NULL || ulMiLastUnloadedDriver == 0)
  3974. {
  3975. return;
  3976. }
  3977. // point to last unloaded drivers
  3978. pdud = (PDUMP_UNLOADED_DRIVERS32)(((PULONG) pb) + 1);
  3979. //
  3980. // Write the list with the most recently unloaded driver first to the
  3981. // least recently unloaded driver last.
  3982. //
  3983. Index = ulMiLastUnloadedDriver - 1;
  3984. for (i = 0; i < MI_UNLOADED_DRIVERS; i += 1)
  3985. {
  3986. if (Index >= MI_UNLOADED_DRIVERS)
  3987. {
  3988. Index = MI_UNLOADED_DRIVERS - 1;
  3989. }
  3990. // read in unloaded driver
  3991. if (CurReadAllVirtual(pvMiUnloadedDrivers +
  3992. Index * sizeof(UNLOADED_DRIVERS32),
  3993. &ud, sizeof(ud)) != S_OK)
  3994. {
  3995. ErrOut("Can't read memory from %s",
  3996. FormatAddr64(pvMiUnloadedDrivers +
  3997. Index * sizeof(UNLOADED_DRIVERS32)));
  3998. }
  3999. // copy name lengths
  4000. pdud->Name.MaximumLength = ud.Name.MaximumLength;
  4001. pdud->Name.Length = ud.Name.Length;
  4002. if (ud.Name.Buffer == NULL)
  4003. {
  4004. break;
  4005. }
  4006. // copy start and end address
  4007. pdud->StartAddress = ud.StartAddress;
  4008. pdud->EndAddress = ud.EndAddress;
  4009. // restrict name length and maximum name length to 12 characters
  4010. if (pdud->Name.Length > MAX_UNLOADED_NAME_LENGTH)
  4011. {
  4012. pdud->Name.Length = MAX_UNLOADED_NAME_LENGTH;
  4013. }
  4014. if (pdud->Name.MaximumLength > MAX_UNLOADED_NAME_LENGTH)
  4015. {
  4016. pdud->Name.MaximumLength = MAX_UNLOADED_NAME_LENGTH;
  4017. }
  4018. // Can't store pointers in the dump so just zero it.
  4019. pdud->Name.Buffer = 0;
  4020. // Read in name.
  4021. if (CurReadAllVirtual(EXTEND64(ud.Name.Buffer),
  4022. pdud->DriverName,
  4023. pdud->Name.MaximumLength) != S_OK)
  4024. {
  4025. ErrOut("Can't read memory at address %08x",
  4026. (ULONG)(ud.Name.Buffer));
  4027. }
  4028. // move to previous driver
  4029. pdud += 1;
  4030. Index -= 1;
  4031. }
  4032. // number of drivers in the list
  4033. *((PULONG) pb) = i;
  4034. }
  4035. void CCrashDumpWrapper32::WriteMmTriageInformation(BYTE *pb)
  4036. {
  4037. DUMP_MM_STORAGE32 TriageInformation;
  4038. ULONG64 pMmVerifierData;
  4039. ULONG64 pvMmPagedPoolInfo;
  4040. ULONG cbNonPagedPool;
  4041. ULONG cbPagedPool;
  4042. // version information
  4043. TriageInformation.Version = 1;
  4044. // size information
  4045. TriageInformation.Size = sizeof(TriageInformation);
  4046. // get special pool tag
  4047. ExtractValue(MmSpecialPoolTag, TriageInformation.MmSpecialPoolTag);
  4048. // get triage action taken
  4049. ExtractValue(MmTriageActionTaken, TriageInformation.MiTriageActionTaken);
  4050. pMmVerifierData = g_Target->m_KdDebuggerData.MmVerifierData;
  4051. // read in verifier level
  4052. // BUGBUG - should not read internal data structures in MM
  4053. //if (pMmVerifierData)
  4054. // DmpReadMemory(
  4055. // (ULONG64) &((MM_DRIVER_VERIFIER_DATA *) pMmVerifierData)->Level,
  4056. // &TriageInformation.MmVerifyDriverLevel,
  4057. // sizeof(TriageInformation.MmVerifyDriverLevel));
  4058. //else
  4059. TriageInformation.MmVerifyDriverLevel = 0;
  4060. // read in verifier
  4061. ExtractValue(KernelVerifier, TriageInformation.KernelVerifier);
  4062. // read non paged pool info
  4063. ExtractValue(MmMaximumNonPagedPoolInBytes, cbNonPagedPool);
  4064. TriageInformation.MmMaximumNonPagedPool = cbNonPagedPool /
  4065. g_Target->m_Machine->m_PageSize;
  4066. ExtractValue(MmAllocatedNonPagedPool, TriageInformation.MmAllocatedNonPagedPool);
  4067. // read paged pool info
  4068. ExtractValue(MmSizeOfPagedPoolInBytes, cbPagedPool);
  4069. TriageInformation.PagedPoolMaximum = cbPagedPool /
  4070. g_Target->m_Machine->m_PageSize;
  4071. pvMmPagedPoolInfo = g_Target->m_KdDebuggerData.MmPagedPoolInformation;
  4072. // BUGBUG - should not read internal data structures in MM
  4073. //if (pvMmPagedPoolInfo)
  4074. // DmpReadMemory(
  4075. // (ULONG64) &((MM_PAGED_POOL_INFO *) pvMmPagedPoolInfo)->AllocatedPagedPool,
  4076. // &TriageInformation.PagedPoolAllocated,
  4077. // sizeof(TriageInformation.PagedPoolAllocated));
  4078. //else
  4079. TriageInformation.PagedPoolAllocated = 0;
  4080. // read committed pages info
  4081. ExtractValue(MmTotalCommittedPages, TriageInformation.CommittedPages);
  4082. ExtractValue(MmPeakCommitment, TriageInformation.CommittedPagesPeak);
  4083. ExtractValue(MmTotalCommitLimitMaximum, TriageInformation.CommitLimitMaximum);
  4084. memcpy(pb, &TriageInformation, sizeof(TriageInformation));
  4085. }
  4086. //----------------------------------------------------------------------------
  4087. //
  4088. // CCrashDumpWrapper64.
  4089. //
  4090. //----------------------------------------------------------------------------
  4091. void
  4092. CCrashDumpWrapper64::WriteDriverList(
  4093. BYTE *pb,
  4094. TRIAGE_DUMP64 *ptdh
  4095. )
  4096. {
  4097. PDUMP_DRIVER_ENTRY64 pdde;
  4098. PDUMP_STRING pds;
  4099. ModuleInfo* ModIter;
  4100. ULONG MaxEntries = ptdh->DriverCount;
  4101. ptdh->DriverCount = 0;
  4102. if (((ModIter = g_Target->GetModuleInfo(FALSE)) == NULL) ||
  4103. ((ModIter->Initialize(g_Thread)) != S_OK))
  4104. {
  4105. return;
  4106. }
  4107. // pointer to first driver entry to write out
  4108. pdde = (PDUMP_DRIVER_ENTRY64) (pb + ptdh->DriverListOffset);
  4109. // pointer to first module name to write out
  4110. pds = (PDUMP_STRING) (pb + ptdh->StringPoolOffset);
  4111. while ((PBYTE)(pds + 1) < pb + TRIAGE_DUMP_SIZE64 &&
  4112. ptdh->DriverCount < MaxEntries)
  4113. {
  4114. MODULE_INFO_ENTRY ModEntry;
  4115. ULONG retval = GetNextModuleEntry(ModIter, &ModEntry);
  4116. if (retval == GNME_CORRUPT ||
  4117. retval == GNME_DONE)
  4118. {
  4119. break;
  4120. }
  4121. else if (retval == GNME_NO_NAME)
  4122. {
  4123. continue;
  4124. }
  4125. pdde->LdrEntry.DllBase = ModEntry.Base;
  4126. pdde->LdrEntry.SizeOfImage = ModEntry.Size;
  4127. pdde->LdrEntry.CheckSum = ModEntry.CheckSum;
  4128. pdde->LdrEntry.TimeDateStamp = ModEntry.TimeDateStamp;
  4129. if (ModEntry.UnicodeNamePtr)
  4130. {
  4131. // convert length from bytes to characters
  4132. pds->Length = ModEntry.NameLength / sizeof(WCHAR);
  4133. if ((PBYTE)pds->Buffer + pds->Length + sizeof(WCHAR) >
  4134. pb + TRIAGE_DUMP_SIZE64)
  4135. {
  4136. break;
  4137. }
  4138. CopyMemory(pds->Buffer,
  4139. ModEntry.NamePtr,
  4140. ModEntry.NameLength);
  4141. }
  4142. else
  4143. {
  4144. pds->Length = ModEntry.NameLength;
  4145. if ((PBYTE)pds->Buffer + pds->Length + sizeof(WCHAR) >
  4146. pb + TRIAGE_DUMP_SIZE64)
  4147. {
  4148. break;
  4149. }
  4150. MultiByteToWideChar(CP_ACP, 0,
  4151. ModEntry.NamePtr, ModEntry.NameLength,
  4152. pds->Buffer, ModEntry.NameLength);
  4153. }
  4154. // null terminate string
  4155. pds->Buffer[pds->Length] = '\0';
  4156. pdde->DriverNameOffset = (ULONG)((ULONG_PTR) pds - (ULONG_PTR) pb);
  4157. // get pointer to next string
  4158. pds = (PDUMP_STRING) ALIGN_UP_POINTER(((LPBYTE) pds) +
  4159. sizeof(DUMP_STRING) + sizeof(WCHAR) * (pds->Length + 1),
  4160. ULONGLONG);
  4161. pdde = (PDUMP_DRIVER_ENTRY64)(((PUCHAR) pdde) + sizeof(*pdde));
  4162. ptdh->DriverCount++;
  4163. }
  4164. ptdh->StringPoolSize = (ULONG) ((ULONG_PTR)pds -
  4165. (ULONG_PTR)(pb + ptdh->StringPoolOffset));
  4166. }
  4167. void CCrashDumpWrapper64::WriteUnloadedDrivers(BYTE *pb)
  4168. {
  4169. ULONG i;
  4170. ULONG Index;
  4171. UNLOADED_DRIVERS64 ud;
  4172. PDUMP_UNLOADED_DRIVERS64 pdud;
  4173. ULONG64 pvMiUnloadedDrivers;
  4174. ULONG ulMiLastUnloadedDriver;
  4175. *((PULONG) pb) = 0;
  4176. //
  4177. // find location of unloaded drivers
  4178. //
  4179. if (!g_Target->m_KdDebuggerData.MmUnloadedDrivers ||
  4180. !g_Target->m_KdDebuggerData.MmLastUnloadedDriver)
  4181. {
  4182. return;
  4183. }
  4184. g_Target->ReadPointer(g_Process, g_Target->m_Machine,
  4185. g_Target->m_KdDebuggerData.MmUnloadedDrivers,
  4186. &pvMiUnloadedDrivers);
  4187. CurReadAllVirtual(g_Target->m_KdDebuggerData.MmLastUnloadedDriver,
  4188. &ulMiLastUnloadedDriver,
  4189. sizeof(ULONG));
  4190. if (pvMiUnloadedDrivers == NULL || ulMiLastUnloadedDriver == 0)
  4191. {
  4192. return;
  4193. }
  4194. // point to last unloaded drivers
  4195. pdud = (PDUMP_UNLOADED_DRIVERS64)(((PULONG64) pb) + 1);
  4196. //
  4197. // Write the list with the most recently unloaded driver first to the
  4198. // least recently unloaded driver last.
  4199. //
  4200. Index = ulMiLastUnloadedDriver - 1;
  4201. for (i = 0; i < MI_UNLOADED_DRIVERS; i += 1)
  4202. {
  4203. if (Index >= MI_UNLOADED_DRIVERS)
  4204. {
  4205. Index = MI_UNLOADED_DRIVERS - 1;
  4206. }
  4207. // read in unloaded driver
  4208. if (CurReadAllVirtual(pvMiUnloadedDrivers +
  4209. Index * sizeof(UNLOADED_DRIVERS64),
  4210. &ud, sizeof(ud)) != S_OK)
  4211. {
  4212. ErrOut("Can't read memory from %s",
  4213. FormatAddr64(pvMiUnloadedDrivers +
  4214. Index * sizeof(UNLOADED_DRIVERS64)));
  4215. }
  4216. // copy name lengths
  4217. pdud->Name.MaximumLength = ud.Name.MaximumLength;
  4218. pdud->Name.Length = ud.Name.Length;
  4219. if (ud.Name.Buffer == NULL)
  4220. {
  4221. break;
  4222. }
  4223. // copy start and end address
  4224. pdud->StartAddress = ud.StartAddress;
  4225. pdud->EndAddress = ud.EndAddress;
  4226. // restrict name length and maximum name length to 12 characters
  4227. if (pdud->Name.Length > MAX_UNLOADED_NAME_LENGTH)
  4228. {
  4229. pdud->Name.Length = MAX_UNLOADED_NAME_LENGTH;
  4230. }
  4231. if (pdud->Name.MaximumLength > MAX_UNLOADED_NAME_LENGTH)
  4232. {
  4233. pdud->Name.MaximumLength = MAX_UNLOADED_NAME_LENGTH;
  4234. }
  4235. // Can't store pointers in the dump so just zero it.
  4236. pdud->Name.Buffer = 0;
  4237. // Read in name.
  4238. if (CurReadAllVirtual(ud.Name.Buffer,
  4239. pdud->DriverName,
  4240. pdud->Name.MaximumLength) != S_OK)
  4241. {
  4242. ErrOut("Can't read memory at address %s",
  4243. FormatAddr64(ud.Name.Buffer));
  4244. }
  4245. // move to previous driver
  4246. pdud += 1;
  4247. Index -= 1;
  4248. }
  4249. // number of drivers in the list
  4250. *((PULONG) pb) = i;
  4251. }
  4252. void CCrashDumpWrapper64::WriteMmTriageInformation(BYTE *pb)
  4253. {
  4254. DUMP_MM_STORAGE64 TriageInformation;
  4255. ULONG64 pMmVerifierData;
  4256. ULONG64 pvMmPagedPoolInfo;
  4257. ULONG64 cbNonPagedPool;
  4258. ULONG64 cbPagedPool;
  4259. // version information
  4260. TriageInformation.Version = 1;
  4261. // size information
  4262. TriageInformation.Size = sizeof(TriageInformation);
  4263. // get special pool tag
  4264. ExtractValue(MmSpecialPoolTag, TriageInformation.MmSpecialPoolTag);
  4265. // get triage action taken
  4266. ExtractValue(MmTriageActionTaken, TriageInformation.MiTriageActionTaken);
  4267. pMmVerifierData = g_Target->m_KdDebuggerData.MmVerifierData;
  4268. // read in verifier level
  4269. // BUGBUG - should not read internal data structures in MM
  4270. //if (pMmVerifierData)
  4271. // DmpReadMemory(
  4272. // (ULONG64) &((MM_DRIVER_VERIFIER_DATA *) pMmVerifierData)->Level,
  4273. // &TriageInformation.MmVerifyDriverLevel,
  4274. // sizeof(TriageInformation.MmVerifyDriverLevel));
  4275. //else
  4276. TriageInformation.MmVerifyDriverLevel = 0;
  4277. // read in verifier
  4278. ExtractValue(KernelVerifier, TriageInformation.KernelVerifier);
  4279. // read non paged pool info
  4280. ExtractValue(MmMaximumNonPagedPoolInBytes, cbNonPagedPool);
  4281. TriageInformation.MmMaximumNonPagedPool = cbNonPagedPool /
  4282. g_Target->m_Machine->m_PageSize;
  4283. ExtractValue(MmAllocatedNonPagedPool, TriageInformation.MmAllocatedNonPagedPool);
  4284. // read paged pool info
  4285. ExtractValue(MmSizeOfPagedPoolInBytes, cbPagedPool);
  4286. TriageInformation.PagedPoolMaximum = cbPagedPool /
  4287. g_Target->m_Machine->m_PageSize;
  4288. pvMmPagedPoolInfo = g_Target->m_KdDebuggerData.MmPagedPoolInformation;
  4289. // BUGBUG - should not read internal data structures in MM
  4290. //if (pvMmPagedPoolInfo)
  4291. // DmpReadMemory(
  4292. // (ULONG64) &((MM_PAGED_POOL_INFO *) pvMmPagedPoolInfo)->AllocatedPagedPool,
  4293. // &TriageInformation.PagedPoolAllocated,
  4294. // sizeof(TriageInformation.PagedPoolAllocated));
  4295. //else
  4296. TriageInformation.PagedPoolAllocated = 0;
  4297. // read committed pages info
  4298. ExtractValue(MmTotalCommittedPages, TriageInformation.CommittedPages);
  4299. ExtractValue(MmPeakCommitment, TriageInformation.CommittedPagesPeak);
  4300. ExtractValue(MmTotalCommitLimitMaximum, TriageInformation.CommitLimitMaximum);
  4301. memcpy(pb, &TriageInformation, sizeof(TriageInformation));
  4302. }