Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

911 lines
26 KiB

  1. /*++
  2. Copyright(c) 1999-2002 Microsoft Corporation
  3. Module Name:
  4. ntx.c
  5. Abstract:
  6. Minidump user-mode crashdump NT specific functions. These routines work on
  7. NT-based operating systems from NT5 on.
  8. Author:
  9. Matthew D Hendel (math) 20-Aug-1999
  10. --*/
  11. #include "pch.h"
  12. #include "impl.h"
  13. PINTERNAL_MODULE
  14. NtxAllocateModuleObject(
  15. IN PINTERNAL_PROCESS Process,
  16. IN HANDLE ProcessHandle,
  17. IN ULONG_PTR BaseOfModule,
  18. IN ULONG DumpType,
  19. IN ULONG WriteFlags,
  20. IN PWSTR ModuleName OPTIONAL
  21. )
  22. {
  23. WCHAR FullPath [ MAX_PATH + 10 ];
  24. //
  25. // The basic LdrQueryProcessModule API that toolhelp uses
  26. // always returns ANSI strings for module paths. This
  27. // means that even if you use the wide toolhelp calls
  28. // you still lose Unicode information because the original
  29. // Unicode path was converted to ANSI and then back to Unicode.
  30. // To avoid this problem, always try and look up the true
  31. // Unicode path first. This doesn't work for 32-bit modules
  32. // in WOW64, though, so if there's a failure just use the
  33. // incoming string.
  34. //
  35. if (GetModuleFileNameExW(ProcessHandle,
  36. (HMODULE) BaseOfModule,
  37. FullPath,
  38. sizeof (FullPath))) {
  39. ModuleName = FullPath;
  40. } else if (!ModuleName) {
  41. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  42. return NULL;
  43. }
  44. //
  45. // Translate funky \??\... module name.
  46. //
  47. return GenAllocateModuleObject (Process, ModuleName, BaseOfModule,
  48. DumpType, WriteFlags);
  49. }
  50. typedef
  51. PLIST_ENTRY
  52. (*FN_RtlGetFunctionTableListHead) (
  53. VOID
  54. );
  55. BOOL
  56. NtxGetFunctionTables(
  57. IN HANDLE hProcess,
  58. IN PINTERNAL_PROCESS Process,
  59. IN ULONG DumpType
  60. )
  61. {
  62. #ifdef _WIN32_WCE
  63. return FALSE;
  64. #else
  65. HMODULE NtDll;
  66. FN_RtlGetFunctionTableListHead GetHead = NULL;
  67. PLIST_ENTRY HeadAddr;
  68. LIST_ENTRY Head;
  69. PVOID Next;
  70. SIZE_T Done;
  71. DYNAMIC_FUNCTION_TABLE Table;
  72. //
  73. // On systems that support dynamic function tables
  74. // ntdll exports a function called RtlGetFunctionTableListHead
  75. // to retrieve the head of a process's function table list.
  76. // Currently this is always a global LIST_ENTRY in ntdll
  77. // and so is at the same address in all processes since ntdll
  78. // is mapped at the same address in every process. This
  79. // means we can call it in our process and get a pointer
  80. // that's valid in the process being dumped.
  81. //
  82. // We also use the presence of RGFTLH as a signal of
  83. // whether dynamic function tables are supported or not.
  84. //
  85. NtDll = GetModuleHandle("ntdll");
  86. if (NtDll) {
  87. GetHead = (FN_RtlGetFunctionTableListHead)
  88. GetProcAddress(NtDll, "RtlGetFunctionTableListHead");
  89. }
  90. if (!GetHead) {
  91. // Dynamic function tables are not supported.
  92. return TRUE;
  93. }
  94. HeadAddr = GetHead();
  95. if (!ReadProcessMemory(hProcess, HeadAddr, &Head, sizeof(Head),
  96. &Done) || Done != sizeof(Head)) {
  97. GenAccumulateStatus(MDSTATUS_UNABLE_TO_READ_MEMORY);
  98. return FALSE;
  99. }
  100. Next = Head.Flink;
  101. while (Next && Next != HeadAddr) {
  102. PINTERNAL_FUNCTION_TABLE IntTable;
  103. PVOID HeapEntries;
  104. PVOID TableAddr;
  105. ULONG EntryCount;
  106. TableAddr = Next;
  107. if (!ReadProcessMemory(hProcess, TableAddr, &Table, sizeof(Table),
  108. &Done) || Done != sizeof(Table)) {
  109. GenAccumulateStatus(MDSTATUS_UNABLE_TO_READ_MEMORY);
  110. return FALSE;
  111. }
  112. #ifdef _AMD64_
  113. Next = Table.ListEntry.Flink;
  114. #else
  115. Next = Table.Links.Flink;
  116. #endif
  117. HeapEntries = NULL;
  118. #if defined(_AMD64_) || defined(_IA64_)
  119. //
  120. // AMD64 and IA64 support a type of function table
  121. // where the data is retrieved via a callback rather
  122. // than being is a plain data table. In order to
  123. // get at the data from out-of-process the table
  124. // must have an out-of-process access DLL registered.
  125. //
  126. if (Table.Type == RF_CALLBACK) {
  127. WCHAR DllName[MAX_PATH];
  128. HMODULE OopDll;
  129. POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK OopCb;
  130. if (!Table.OutOfProcessCallbackDll) {
  131. // No out-of-process access is possible.
  132. continue;
  133. }
  134. if (!ReadProcessMemory(hProcess, Table.OutOfProcessCallbackDll,
  135. DllName, sizeof(DllName) - sizeof(WCHAR),
  136. &Done)) {
  137. GenAccumulateStatus(MDSTATUS_UNABLE_TO_READ_MEMORY);
  138. return FALSE;
  139. }
  140. DllName[Done / sizeof(WCHAR)] = 0;
  141. OopDll = LoadLibraryW(DllName);
  142. if (!OopDll) {
  143. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  144. return FALSE;
  145. }
  146. OopCb = (POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)GetProcAddress
  147. (OopDll, OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME);
  148. if (OopCb == NULL) {
  149. FreeLibrary(OopDll);
  150. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  151. return FALSE;
  152. }
  153. if (!NT_SUCCESS(OopCb(hProcess, TableAddr,
  154. &EntryCount,
  155. (PRUNTIME_FUNCTION*)&HeapEntries))) {
  156. FreeLibrary(OopDll);
  157. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  158. return FALSE;
  159. }
  160. FreeLibrary(OopDll);
  161. } else {
  162. EntryCount = Table.EntryCount;
  163. }
  164. #else
  165. EntryCount = Table.EntryCount;
  166. #endif
  167. IntTable = GenAllocateFunctionTableObject(Table.MinimumAddress,
  168. Table.MaximumAddress,
  169. #ifdef _ALPHA_
  170. Table.MinimumAddress,
  171. #else
  172. Table.BaseAddress,
  173. #endif
  174. EntryCount,
  175. &Table);
  176. if (IntTable) {
  177. #if defined(_AMD64_) || defined(_IA64_)
  178. if (Table.Type == RF_CALLBACK) {
  179. memcpy(IntTable->RawEntries, HeapEntries,
  180. EntryCount * sizeof(RUNTIME_FUNCTION));
  181. } else
  182. #endif
  183. {
  184. if (!ReadProcessMemory(hProcess, Table.FunctionTable,
  185. IntTable->RawEntries,
  186. EntryCount * sizeof(RUNTIME_FUNCTION),
  187. &Done) ||
  188. Done != EntryCount * sizeof(RUNTIME_FUNCTION)) {
  189. GenFreeFunctionTableObject(IntTable);
  190. IntTable = NULL;
  191. }
  192. }
  193. }
  194. if (HeapEntries) {
  195. RtlFreeHeap(RtlProcessHeap(), 0, HeapEntries);
  196. }
  197. if (!IntTable) {
  198. return FALSE;
  199. }
  200. if (!GenIncludeUnwindInfoMemory(hProcess, DumpType, IntTable)) {
  201. return FALSE;
  202. }
  203. Process->NumberOfFunctionTables++;
  204. InsertTailList(&Process->FunctionTableList, &IntTable->TableLink);
  205. }
  206. return TRUE;
  207. #endif // _WIN32_WCE
  208. }
  209. #ifdef RTL_UNLOAD_EVENT_TRACE_NUMBER
  210. typedef
  211. PRTL_UNLOAD_EVENT_TRACE
  212. (*FN_RtlGetUnloadEventTrace) (
  213. VOID
  214. );
  215. #endif
  216. BOOL
  217. NtxGetUnloadedModules(
  218. IN HANDLE hProcess,
  219. IN PINTERNAL_PROCESS Process,
  220. IN ULONG DumpType
  221. )
  222. {
  223. #if defined(_WIN32_WCE) || !defined(RTL_UNLOAD_EVENT_TRACE_NUMBER)
  224. return FALSE;
  225. #else
  226. HMODULE NtDll;
  227. FN_RtlGetUnloadEventTrace GetTrace = NULL;
  228. PRTL_UNLOAD_EVENT_TRACE TraceAddr;
  229. PRTL_UNLOAD_EVENT_TRACE TraceArray;
  230. SIZE_T Done;
  231. ULONG Entries;
  232. PRTL_UNLOAD_EVENT_TRACE Oldest;
  233. ULONG i;
  234. PINTERNAL_UNLOADED_MODULE IntModule;
  235. if (!(DumpType & MiniDumpWithUnloadedModules)) {
  236. // No unloaded module info requested.
  237. return TRUE;
  238. }
  239. //
  240. // On systems that support unload traces
  241. // ntdll exports a function called RtlGetUnloadEventTrace
  242. // to retrieve the base of an unload trace array.
  243. // Currently this is always a global in ntdll
  244. // and so is at the same address in all processes since ntdll
  245. // is mapped at the same address in every process. This
  246. // means we can call it in our process and get a pointer
  247. // that's valid in the process being dumped.
  248. //
  249. // We also use the presence of RGUET as a signal of
  250. // whether unload traces are supported or not.
  251. //
  252. NtDll = GetModuleHandle("ntdll");
  253. if (NtDll) {
  254. GetTrace = (FN_RtlGetUnloadEventTrace)
  255. GetProcAddress(NtDll, "RtlGetUnloadEventTrace");
  256. }
  257. if (!GetTrace) {
  258. // Unload traces are not supported.
  259. return TRUE;
  260. }
  261. TraceAddr = GetTrace();
  262. // Currently there are always 16 entries.
  263. Entries = 16;
  264. TraceArray = (PRTL_UNLOAD_EVENT_TRACE)
  265. AllocMemory(sizeof(*TraceArray) * Entries);
  266. if (!TraceArray) {
  267. return FALSE;
  268. }
  269. if (!ReadProcessMemory(hProcess, TraceAddr,
  270. TraceArray, sizeof(*TraceArray) * Entries,
  271. &Done) ||
  272. Done != sizeof(*TraceArray) * Entries) {
  273. GenAccumulateStatus(MDSTATUS_UNABLE_TO_READ_MEMORY);
  274. return FALSE;
  275. }
  276. //
  277. // Find the true number of entries in use and sort.
  278. // The sequence numbers of the trace records increase with
  279. // time and we want to have the head of the list be the
  280. // most recent record, so sort by decreasing sequence number.
  281. // We know that the array is a circular buffer, so things
  282. // are already in order except there may be a transition
  283. // of sequence after the newest record. Find that transition
  284. // and sorting becomes trivial.
  285. //
  286. Oldest = TraceArray;
  287. for (i = 0; i < Entries; i++) {
  288. if (!TraceArray[i].BaseAddress || !TraceArray[i].SizeOfImage) {
  289. // Unused entry, no need to continue.
  290. Entries = i;
  291. break;
  292. }
  293. if (TraceArray[i].Sequence < Oldest->Sequence) {
  294. Oldest = TraceArray + i;
  295. }
  296. }
  297. //
  298. // Now push the entries on from the oldest to the youngest.
  299. //
  300. for (i = 0; i < Entries; i++) {
  301. IntModule =
  302. GenAllocateUnloadedModuleObject(Oldest->ImageName,
  303. (ULONG_PTR)Oldest->BaseAddress,
  304. (ULONG)Oldest->SizeOfImage,
  305. Oldest->CheckSum,
  306. Oldest->TimeDateStamp);
  307. if (!IntModule) {
  308. return FALSE;
  309. }
  310. Process->NumberOfUnloadedModules++;
  311. InsertHeadList(&Process->UnloadedModuleList, &IntModule->ModulesLink);
  312. if (Oldest == TraceArray + (Entries - 1)) {
  313. Oldest = TraceArray;
  314. } else {
  315. Oldest++;
  316. }
  317. }
  318. return TRUE;
  319. #endif // _WIN32_WCE || !RTL_UNLOAD_EVENT_TRACE_NUMBER
  320. }
  321. BOOL
  322. NtxGetProcessInfo(
  323. IN HANDLE hProcess,
  324. IN ULONG ProcessId,
  325. IN ULONG DumpType,
  326. IN MINIDUMP_CALLBACK_ROUTINE CallbackRoutine,
  327. IN PVOID CallbackParam,
  328. OUT PINTERNAL_PROCESS * ProcessRet
  329. )
  330. /*++
  331. Routine Description:
  332. Using toolhelp, obtain the process information for this process.
  333. Return Values:
  334. TRUE - Success.
  335. FALSE - Failure:
  336. Environment:
  337. Win9x/Win2k+ only.
  338. --*/
  339. {
  340. BOOL Succ;
  341. ULONG i;
  342. BOOL MoreThreads;
  343. HANDLE Snapshot, ModuleSnapshot = INVALID_HANDLE_VALUE;
  344. THREADENTRY32 ThreadInfo;
  345. PINTERNAL_THREAD Thread;
  346. PINTERNAL_PROCESS Process;
  347. PINTERNAL_MODULE Module;
  348. HMODULE Modules [ 512 ];
  349. ULONG ModulesSize;
  350. ULONG NumberOfModules;
  351. ULONG BuildNumber;
  352. ASSERT ( hProcess );
  353. ASSERT ( ProcessId != 0 );
  354. ASSERT ( ProcessRet );
  355. Process = NULL;
  356. Thread = NULL;
  357. Module = NULL;
  358. Snapshot = NULL;
  359. ThreadInfo.dwSize = sizeof (THREADENTRY32);
  360. Process = GenAllocateProcessObject ( hProcess, ProcessId );
  361. if ( Process == NULL ) {
  362. return FALSE;
  363. }
  364. Snapshot = CreateToolhelp32Snapshot (
  365. TH32CS_SNAPTHREAD,
  366. ProcessId
  367. );
  368. if ( Snapshot == INVALID_HANDLE_VALUE ) {
  369. Succ = FALSE;
  370. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  371. goto Exit;
  372. }
  373. //
  374. // Walk thread list, suspending all threads and getting thread info.
  375. //
  376. for (MoreThreads = ProcessThread32First (Snapshot, ProcessId, &ThreadInfo );
  377. MoreThreads;
  378. MoreThreads = ProcessThread32Next ( Snapshot, ProcessId, &ThreadInfo ) ) {
  379. HRESULT Status;
  380. ULONG WriteFlags;
  381. if (!GenExecuteIncludeThreadCallback(hProcess,
  382. ProcessId,
  383. DumpType,
  384. ThreadInfo.th32ThreadID,
  385. CallbackRoutine,
  386. CallbackParam,
  387. &WriteFlags) ||
  388. IsFlagClear(WriteFlags, ThreadWriteThread)) {
  389. continue;
  390. }
  391. Status = GenAllocateThreadObject (
  392. Process,
  393. hProcess,
  394. ThreadInfo.th32ThreadID,
  395. DumpType,
  396. WriteFlags,
  397. &Thread
  398. );
  399. if ( FAILED(Status) ) {
  400. Succ = FALSE;
  401. goto Exit;
  402. }
  403. // If Status is S_FALSE it means that the thread
  404. // couldn't be opened and probably exited before
  405. // we got to it. Just continue on.
  406. if (Status == S_OK) {
  407. Process->NumberOfThreads++;
  408. InsertTailList (&Process->ThreadList, &Thread->ThreadsLink);
  409. }
  410. }
  411. GenGetSystemType (NULL, NULL, NULL, NULL, &BuildNumber);
  412. if (BuildNumber > 2468) {
  413. //
  414. // toolhelp had been changed to perform noninvasive
  415. // module enumeration
  416. //
  417. MODULEENTRY32W ModuleEntry;
  418. BOOL ModuleFound;
  419. NumberOfModules = 0;
  420. Succ = TRUE;
  421. ModuleSnapshot = CreateToolhelp32Snapshot(
  422. TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32,
  423. ProcessId
  424. );
  425. if (ModuleSnapshot == INVALID_HANDLE_VALUE) {
  426. Succ = FALSE;
  427. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  428. goto Exit;
  429. }
  430. ZeroMemory(&ModuleEntry, sizeof(ModuleEntry));
  431. ModuleEntry.dwSize = sizeof(ModuleEntry);
  432. ModuleFound = Module32FirstW(ModuleSnapshot, &ModuleEntry);
  433. while (ModuleFound) {
  434. ULONG WriteFlags;
  435. if (GenExecuteIncludeModuleCallback(hProcess,
  436. ProcessId,
  437. DumpType,
  438. (LONG_PTR)ModuleEntry.modBaseAddr,
  439. CallbackRoutine,
  440. CallbackParam,
  441. &WriteFlags) &&
  442. IsFlagSet(WriteFlags, ModuleWriteModule)) {
  443. Module = NtxAllocateModuleObject (Process,
  444. Process->ProcessHandle,
  445. (LONG_PTR)ModuleEntry.modBaseAddr,
  446. DumpType,
  447. WriteFlags,
  448. ModuleEntry.szExePath);
  449. if ( Module == NULL ) {
  450. Succ = FALSE;
  451. goto Exit;
  452. }
  453. InsertTailList (&Process->ModuleList, &Module->ModulesLink);
  454. ++NumberOfModules;
  455. }
  456. ModuleFound = Module32NextW(ModuleSnapshot, &ModuleEntry);
  457. }
  458. }
  459. else {
  460. //
  461. // Walk module list, getting module information. Use PSAPI instead of
  462. // toolhelp since it it does not exhibit the deadlock issues with
  463. // the loader lock. ( on old versions of os )
  464. //
  465. ModulesSize = 0;
  466. Succ = EnumProcessModules (
  467. Process->ProcessHandle,
  468. Modules,
  469. sizeof (Modules),
  470. &ModulesSize
  471. );
  472. if ( !Succ ) {
  473. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  474. goto Exit;
  475. }
  476. NumberOfModules = ModulesSize / sizeof (HMODULE);
  477. for (i = 0; i < NumberOfModules; i++) {
  478. ULONG WriteFlags;
  479. if (!GenExecuteIncludeModuleCallback(hProcess,
  480. ProcessId,
  481. DumpType,
  482. (LONG_PTR)Modules[i],
  483. CallbackRoutine,
  484. CallbackParam,
  485. &WriteFlags) ||
  486. IsFlagClear(WriteFlags, ModuleWriteModule)) {
  487. continue;
  488. }
  489. Module = NtxAllocateModuleObject (
  490. Process,
  491. Process->ProcessHandle,
  492. (LONG_PTR) Modules [ i ],
  493. DumpType,
  494. WriteFlags,
  495. NULL
  496. );
  497. if ( Module == NULL ) {
  498. Succ = FALSE;
  499. goto Exit;
  500. }
  501. InsertTailList (&Process->ModuleList, &Module->ModulesLink);
  502. }
  503. }
  504. Process->NumberOfModules = NumberOfModules;
  505. Succ = NtxGetFunctionTables(hProcess, Process, DumpType);
  506. // If we can't get unloaded modules that's not a critical problem.
  507. NtxGetUnloadedModules(hProcess, Process, DumpType);
  508. Exit:
  509. if ( Snapshot && (Snapshot != INVALID_HANDLE_VALUE) ) {
  510. CloseHandle ( Snapshot );
  511. Snapshot = NULL;
  512. }
  513. if ( ModuleSnapshot && (ModuleSnapshot != INVALID_HANDLE_VALUE) ) {
  514. CloseHandle ( ModuleSnapshot );
  515. ModuleSnapshot = NULL;
  516. }
  517. if ( !Succ && Process != NULL ) {
  518. GenFreeProcessObject ( Process );
  519. Process = NULL;
  520. }
  521. *ProcessRet = Process;
  522. return Succ;
  523. }
  524. LPVOID
  525. NtxGetTebAddress(
  526. IN HANDLE Thread,
  527. OUT PULONG SizeOfTeb
  528. )
  529. {
  530. #ifdef _WIN32_WCE
  531. *SizeOfTeb = 0;
  532. return NULL;
  533. #else
  534. THREAD_BASIC_INFORMATION ThreadInformation;
  535. NTSTATUS NtStatus;
  536. NtStatus = NtQueryInformationThread(Thread,
  537. ThreadBasicInformation,
  538. &ThreadInformation,
  539. sizeof(ThreadInformation),
  540. NULL);
  541. if (NT_SUCCESS(NtStatus)) {
  542. // The TEB is a little smaller than a page but
  543. // save the entire page so that adjacent TEB
  544. // pages get coalesced into a single region.
  545. // As TEBs are normally adjacent this is a common case.
  546. *SizeOfTeb = PAGE_SIZE;
  547. return ThreadInformation.TebBaseAddress;
  548. } else {
  549. *SizeOfTeb = 0;
  550. return NULL;
  551. }
  552. #endif
  553. }
  554. HRESULT
  555. TibGetThreadInfo(
  556. IN HANDLE Process,
  557. IN LPVOID TibBase,
  558. OUT PULONG64 StackBase,
  559. OUT PULONG64 StackLimit,
  560. OUT PULONG64 StoreBase,
  561. OUT PULONG64 StoreLimit
  562. )
  563. {
  564. #ifdef _WIN32_WCE
  565. return E_NOTIMPL;
  566. #else
  567. TEB Teb;
  568. HRESULT Succ;
  569. SIZE_T BytesRead;
  570. #if defined (DUMP_BACKING_STORE)
  571. Succ = ReadProcessMemory(Process,
  572. TibBase,
  573. &Teb,
  574. sizeof (Teb),
  575. &BytesRead) ? S_OK : E_FAIL;
  576. if ( Succ != S_OK || BytesRead != sizeof (Teb) ) {
  577. return E_FAIL;
  578. }
  579. *StoreBase = SIGN_EXTEND(BSTORE_BASE(&Teb));
  580. *StoreLimit = SIGN_EXTEND(BSTORE_LIMIT(&Teb));
  581. #else
  582. Succ = ReadProcessMemory(Process,
  583. TibBase,
  584. &Teb,
  585. sizeof (Teb.NtTib),
  586. &BytesRead) ? S_OK : E_FAIL;
  587. if ( Succ != S_OK || BytesRead != sizeof (Teb.NtTib) ) {
  588. return E_FAIL;
  589. }
  590. *StoreBase = 0;
  591. *StoreLimit = 0;
  592. #endif
  593. *StackBase = SIGN_EXTEND((LONG_PTR)Teb.NtTib.StackBase);
  594. *StackLimit = SIGN_EXTEND((LONG_PTR)Teb.NtTib.StackLimit);
  595. return S_OK;
  596. #endif // #ifdef _WIN32_WCE
  597. }
  598. LPVOID
  599. NtxGetPebAddress(
  600. IN HANDLE Process,
  601. OUT PULONG SizeOfPeb
  602. )
  603. {
  604. #ifdef _WIN32_WCE
  605. *SizeOfPeb = 0;
  606. return NULL;
  607. #else
  608. PROCESS_BASIC_INFORMATION Information;
  609. NTSTATUS NtStatus;
  610. NtStatus = NtQueryInformationProcess(Process,
  611. ProcessBasicInformation,
  612. &Information,
  613. sizeof(Information),
  614. NULL);
  615. if (NT_SUCCESS(NtStatus)) {
  616. *SizeOfPeb = sizeof(PEB);
  617. return Information.PebBaseAddress;
  618. } else {
  619. *SizeOfPeb = 0;
  620. return NULL;
  621. }
  622. #endif
  623. }
  624. BOOL
  625. NtxWriteHandleData(
  626. IN HANDLE ProcessHandle,
  627. IN HANDLE hFile,
  628. IN struct _MINIDUMP_STREAM_INFO * StreamInfo
  629. )
  630. {
  631. #ifdef _WIN32_WCE
  632. return FALSE;
  633. #else
  634. NTSTATUS NtStatus;
  635. ULONG HandleCount;
  636. ULONG Hits;
  637. ULONG Handle;
  638. ULONG64 Buffer[1024 / sizeof(ULONG64)];
  639. POBJECT_TYPE_INFORMATION TypeInfo =
  640. (POBJECT_TYPE_INFORMATION)Buffer;
  641. POBJECT_NAME_INFORMATION NameInfo =
  642. (POBJECT_NAME_INFORMATION)Buffer;
  643. OBJECT_BASIC_INFORMATION BasicInfo;
  644. HANDLE Dup;
  645. PMINIDUMP_HANDLE_DESCRIPTOR Descs, Desc;
  646. RVA Rva;
  647. ULONG32 Len;
  648. ULONG Done;
  649. MINIDUMP_HANDLE_DATA_STREAM DataStream;
  650. BOOL Succ;
  651. NtStatus = NtQueryInformationProcess(ProcessHandle,
  652. ProcessHandleCount,
  653. &HandleCount,
  654. sizeof(HandleCount),
  655. NULL);
  656. if (!NT_SUCCESS(NtStatus)) {
  657. return FALSE;
  658. }
  659. Descs = AllocMemory(HandleCount * sizeof(*Desc));
  660. if (Descs == NULL) {
  661. return FALSE;
  662. }
  663. Hits = 0;
  664. Handle = 0;
  665. Desc = Descs;
  666. Rva = StreamInfo->RvaOfHandleData;
  667. while (Hits < HandleCount && Handle < (1 << 24)) {
  668. if (!DuplicateHandle(ProcessHandle, (HANDLE)(ULONG_PTR)Handle,
  669. GetCurrentProcess(), &Dup,
  670. 0, FALSE, DUPLICATE_SAME_ACCESS)) {
  671. Handle += 4;
  672. continue;
  673. }
  674. // Successfully got a handle, so consider this a hit.
  675. Hits++;
  676. if (!NT_SUCCESS(NtQueryObject(Dup, ObjectBasicInformation,
  677. &BasicInfo, sizeof(BasicInfo), NULL)) ||
  678. !NT_SUCCESS(NtQueryObject(Dup, ObjectTypeInformation,
  679. TypeInfo, sizeof(Buffer), NULL))) {
  680. // If we can't get the basic info and type there isn't much
  681. // point in writing anything out so skip the handle.
  682. goto CloseDup;
  683. }
  684. Len = TypeInfo->TypeName.Length;
  685. TypeInfo->TypeName.Buffer[Len / sizeof(WCHAR)] = 0;
  686. Desc->TypeNameRva = Rva;
  687. if (!WriteFile(hFile, &Len, sizeof(Len), &Done, NULL) ||
  688. Done != sizeof(Len)) {
  689. goto ExitCloseDup;
  690. }
  691. Len += sizeof(WCHAR);
  692. if (!WriteFile(hFile, TypeInfo->TypeName.Buffer, Len, &Done, NULL) ||
  693. Done != Len) {
  694. goto ExitCloseDup;
  695. }
  696. Rva += Len + sizeof(Len);
  697. // Don't get the name of file objects as it
  698. // can cause deadlocks. If we fail getting the
  699. // name just leave it out and don't consider it fatal.
  700. if (lstrcmpW(TypeInfo->TypeName.Buffer, L"File") &&
  701. NT_SUCCESS(NtQueryObject(Dup, ObjectNameInformation,
  702. NameInfo, sizeof(Buffer), NULL)) &&
  703. NameInfo->Name.Buffer != NULL) {
  704. Len = NameInfo->Name.Length;
  705. NameInfo->Name.Buffer[Len / sizeof(WCHAR)] = 0;
  706. Desc->ObjectNameRva = Rva;
  707. if (!WriteFile(hFile, &Len, sizeof(Len), &Done, NULL) ||
  708. Done != sizeof(Len)) {
  709. goto ExitCloseDup;
  710. }
  711. Len += sizeof(WCHAR);
  712. if (!WriteFile(hFile, NameInfo->Name.Buffer, Len, &Done, NULL) ||
  713. Done != Len) {
  714. goto ExitCloseDup;
  715. }
  716. Rva += Len + sizeof(Len);
  717. } else {
  718. Desc->ObjectNameRva = 0;
  719. }
  720. Desc->Handle = Handle;
  721. Desc->Attributes = BasicInfo.Attributes;
  722. Desc->GrantedAccess = BasicInfo.GrantedAccess;
  723. Desc->HandleCount = BasicInfo.HandleCount;
  724. Desc->PointerCount = BasicInfo.PointerCount;
  725. Desc++;
  726. CloseDup:
  727. CloseHandle(Dup);
  728. Handle += 4;
  729. }
  730. DataStream.SizeOfHeader = sizeof(DataStream);
  731. DataStream.SizeOfDescriptor = sizeof(*Descs);
  732. DataStream.NumberOfDescriptors = (ULONG)(Desc - Descs);
  733. DataStream.Reserved = 0;
  734. StreamInfo->RvaOfHandleData = Rva;
  735. StreamInfo->SizeOfHandleData = sizeof(DataStream) +
  736. DataStream.NumberOfDescriptors * sizeof(*Descs);
  737. Succ =
  738. WriteFile(hFile, &DataStream, sizeof(DataStream), &Done, NULL) &&
  739. Done == sizeof(DataStream) &&
  740. WriteFile(hFile, Descs, DataStream.NumberOfDescriptors *
  741. sizeof(*Descs), &Done, NULL) &&
  742. Done == DataStream.NumberOfDescriptors * sizeof(*Descs);
  743. FreeMemory(Descs);
  744. return Succ;
  745. ExitCloseDup:
  746. CloseHandle(Dup);
  747. FreeMemory(Descs);
  748. return FALSE;
  749. #endif // #ifdef _WIN32_WCE
  750. }