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.

5905 lines
149 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // IDebugDataSpaces implementations.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999-2002.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. //----------------------------------------------------------------------------
  10. //
  11. // TargetInfo data space methods.
  12. //
  13. //----------------------------------------------------------------------------
  14. void
  15. TargetInfo::NearestDifferentlyValidOffsets(ULONG64 Offset,
  16. PULONG64 NextOffset,
  17. PULONG64 NextPage)
  18. {
  19. //
  20. // In the default case we assume that address validity
  21. // is controlled on a per-page basis so the next possibly
  22. // valid page and offset are both the offset of the next
  23. // page.
  24. //
  25. ULONG64 Page = NEXT_PAGE(m_Machine, Offset);
  26. if (NextOffset != NULL)
  27. {
  28. *NextOffset = Page;
  29. }
  30. if (NextPage != NULL)
  31. {
  32. *NextPage = Page;
  33. }
  34. }
  35. HRESULT
  36. TargetInfo::ReadVirtualUncached(
  37. THIS_
  38. IN ProcessInfo* Process,
  39. IN ULONG64 Offset,
  40. OUT PVOID Buffer,
  41. IN ULONG BufferSize,
  42. OUT PULONG BytesRead
  43. )
  44. {
  45. return ReadVirtual(Process, Offset, Buffer, BufferSize, BytesRead);
  46. }
  47. HRESULT
  48. TargetInfo::WriteVirtualUncached(
  49. THIS_
  50. IN ProcessInfo* Process,
  51. IN ULONG64 Offset,
  52. IN PVOID Buffer,
  53. IN ULONG BufferSize,
  54. OUT PULONG BytesWritten
  55. )
  56. {
  57. return WriteVirtual(Process, Offset, Buffer, BufferSize, BytesWritten);
  58. }
  59. // #define DBG_SEARCH
  60. HRESULT
  61. TargetInfo::SearchVirtual(
  62. IN ProcessInfo* Process,
  63. IN ULONG64 Offset,
  64. IN ULONG64 Length,
  65. IN PVOID Pattern,
  66. IN ULONG PatternSize,
  67. IN ULONG PatternGranularity,
  68. OUT PULONG64 MatchOffset
  69. )
  70. {
  71. HRESULT Status;
  72. ULONG64 SearchEnd;
  73. UCHAR Buffer[4096];
  74. PUCHAR Buf, Pat, BufEnd, PatEnd;
  75. ULONG ReadLen;
  76. ULONG64 BufOffset;
  77. ULONG64 PatOffset;
  78. ULONG64 StartOffset;
  79. SearchEnd = Offset + Length;
  80. Buf = Buffer;
  81. BufEnd = Buffer;
  82. Pat = (PUCHAR)Pattern;
  83. PatEnd = Pat + PatternSize;
  84. ReadLen = Length < sizeof(Buffer) ? (ULONG)Length : sizeof(Buffer);
  85. BufOffset = Offset;
  86. PatOffset = Offset;
  87. StartOffset = Offset;
  88. #ifdef DBG_SEARCH
  89. g_NtDllCalls.DbgPrint("Search %d bytes from %I64X to %I64X, gran %X\n",
  90. PatternSize, Offset, SearchEnd - 1,
  91. Granularity);
  92. #endif
  93. for (;;)
  94. {
  95. #ifdef DBG_SEARCH_VERBOSE
  96. g_NtDllCalls.DbgPrint(" %I64X: matched %d\n",
  97. Offset + (Buf - Buffer),
  98. (ULONG)(Pat - (PUCHAR)Pattern));
  99. #endif
  100. if (Pat == PatEnd)
  101. {
  102. // Made it to the end of the pattern so there's
  103. // a match.
  104. *MatchOffset = PatOffset;
  105. Status = S_OK;
  106. break;
  107. }
  108. if (Buf >= BufEnd)
  109. {
  110. ULONG Read;
  111. // Ran out of buffered memory so get some more.
  112. for (;;)
  113. {
  114. if (CheckUserInterrupt())
  115. {
  116. WarnOut("-- Memory search interrupted at %s\n",
  117. FormatAddr64(Offset));
  118. Status = HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT);
  119. goto Exit;
  120. }
  121. if (Offset >= SearchEnd)
  122. {
  123. // Return a result code that's specific and
  124. // consistent with the kernel version.
  125. Status = HRESULT_FROM_NT(STATUS_NO_MORE_ENTRIES);
  126. goto Exit;
  127. }
  128. Status = ReadVirtual(Process, Offset, Buffer, ReadLen, &Read);
  129. #ifdef DBG_SEARCH
  130. g_NtDllCalls.DbgPrint(" Read %X bytes at %I64X, ret %X:%X\n",
  131. ReadLen, Offset,
  132. Status, Read);
  133. #endif
  134. if (Status != S_OK)
  135. {
  136. // Skip to the start of the next page.
  137. NearestDifferentlyValidOffsets(Offset, NULL, &Offset);
  138. // Restart search due to the address discontinuity.
  139. Pat = (PUCHAR)Pattern;
  140. PatOffset = Offset;
  141. }
  142. else
  143. {
  144. break;
  145. }
  146. }
  147. Buf = Buffer;
  148. BufEnd = Buffer + Read;
  149. BufOffset = Offset;
  150. Offset += Read;
  151. }
  152. // If this is the first byte of the pattern it
  153. // must match on a granularity boundary.
  154. if (*Buf++ == *Pat &&
  155. (Pat != (PUCHAR)Pattern ||
  156. (((PatOffset - StartOffset) % PatternGranularity) == 0)))
  157. {
  158. Pat++;
  159. }
  160. else
  161. {
  162. Buf -= Pat - (PUCHAR)Pattern;
  163. Pat = (PUCHAR)Pattern;
  164. PatOffset = BufOffset + (Buf - Buffer);
  165. }
  166. }
  167. Exit:
  168. return Status;
  169. }
  170. ULONG
  171. HammingDistance(ULONG64 Left, ULONG64 Right, ULONG WordLength)
  172. {
  173. ULONG64 Value;
  174. ULONG Index;
  175. ULONG Distance;
  176. Value = Left ^ Right;
  177. Distance = 0;
  178. for (Index = 0; Index < 8 * WordLength; Index++)
  179. {
  180. if ((Value & 1))
  181. {
  182. Distance++;
  183. }
  184. Value >>= 1;
  185. }
  186. return Distance;
  187. }
  188. HRESULT
  189. TargetInfo::PointerSearchPhysical(
  190. IN ULONG64 Offset,
  191. IN ULONG64 Length,
  192. IN ULONG64 PointerMin,
  193. IN ULONG64 PointerMax,
  194. IN ULONG Flags,
  195. OUT PULONG64 MatchOffsets,
  196. IN ULONG MatchOffsetsSize,
  197. OUT PULONG MatchOffsetsCount
  198. )
  199. {
  200. HRESULT Status;
  201. ULONG ReadSize;
  202. if (Flags & PTR_SEARCH_PHYS_PTE)
  203. {
  204. ReadSize = m_TypeInfo.SizePte;
  205. }
  206. else
  207. {
  208. if (m_Machine->m_Ptr64)
  209. {
  210. ReadSize = 8;
  211. }
  212. else
  213. {
  214. ReadSize = 4;
  215. PointerMin &= 0xffffffff;
  216. PointerMax &= 0xffffffff;
  217. }
  218. }
  219. // Make sure things are aligned properly.
  220. if ((Offset & (ReadSize - 1)) ||
  221. (Length & (ReadSize - 1)))
  222. {
  223. return E_INVALIDARG;
  224. }
  225. ULONG Hits;
  226. Hits = 0;
  227. Status = S_OK;
  228. while (Length > 0)
  229. {
  230. ULONG64 Data;
  231. BOOL Hit;
  232. if (g_EngStatus & ENG_STATUS_USER_INTERRUPT)
  233. {
  234. Status = HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT);
  235. // Leave the interrupt flag on so that !search
  236. // interrupts itself.
  237. }
  238. Data = 0;
  239. if ((Status = ReadAllPhysical(Offset, &Data, ReadSize)) != S_OK)
  240. {
  241. return Status;
  242. }
  243. Hit = FALSE;
  244. if (Flags & PTR_SEARCH_PHYS_PTE)
  245. {
  246. ULONG64 Pfn;
  247. ULONG PteFlags;
  248. m_Machine->DecodePte(Data, &Pfn, &PteFlags);
  249. if (Pfn == PointerMin)
  250. {
  251. Hit = TRUE;
  252. }
  253. }
  254. else
  255. {
  256. if ((Data >= PointerMin && Data <= PointerMax) ||
  257. HammingDistance(Data, PointerMin, ReadSize) == 1)
  258. {
  259. Hit = TRUE;
  260. }
  261. }
  262. if (Hit)
  263. {
  264. if (Hits < MatchOffsetsSize)
  265. {
  266. MatchOffsets[Hits] = Offset;
  267. }
  268. Hits++;
  269. if (!(Flags & PTR_SEARCH_PHYS_ALL_HITS))
  270. {
  271. ULONG64 ToNextPage;
  272. //
  273. // The caller has asked for just the first
  274. // hit per page, so we can skip to the next page.
  275. //
  276. ToNextPage = NEXT_PAGE(m_Machine, Offset);
  277. if (ToNextPage == 0)
  278. {
  279. // Wrapped around, so we're done.
  280. break;
  281. }
  282. ToNextPage -= Offset;
  283. if (ToNextPage > Length)
  284. {
  285. ToNextPage = Length;
  286. }
  287. Offset += ToNextPage;
  288. Length -= ToNextPage;
  289. continue;
  290. }
  291. }
  292. Offset += ReadSize;
  293. Length -= ReadSize;
  294. }
  295. if (MatchOffsetsCount)
  296. {
  297. *MatchOffsetsCount = Hits;
  298. }
  299. return Status;
  300. }
  301. HRESULT
  302. TargetInfo::ReadPhysicalUncached(
  303. THIS_
  304. IN ULONG64 Offset,
  305. OUT PVOID Buffer,
  306. IN ULONG BufferSize,
  307. IN ULONG Flags,
  308. OUT PULONG BytesRead
  309. )
  310. {
  311. return ReadPhysical(Offset, Buffer, BufferSize, Flags, BytesRead);
  312. }
  313. HRESULT
  314. TargetInfo::WritePhysicalUncached(
  315. THIS_
  316. IN ULONG64 Offset,
  317. IN PVOID Buffer,
  318. IN ULONG BufferSize,
  319. IN ULONG Flags,
  320. OUT PULONG BytesWritten
  321. )
  322. {
  323. return WritePhysical(Offset, Buffer, BufferSize, Flags, BytesWritten);
  324. }
  325. HRESULT
  326. TargetInfo::ReadHandleData(
  327. IN ProcessInfo* Process,
  328. IN ULONG64 Handle,
  329. IN ULONG DataType,
  330. OUT OPTIONAL PVOID Buffer,
  331. IN ULONG BufferSize,
  332. OUT OPTIONAL PULONG DataSize
  333. )
  334. {
  335. // Base implementation which silently fails for modes
  336. // where there is no way to retrieve handle data.
  337. return E_UNEXPECTED;
  338. }
  339. HRESULT
  340. TargetInfo::FillVirtual(
  341. THIS_
  342. IN ProcessInfo* Process,
  343. IN ULONG64 Start,
  344. IN ULONG Size,
  345. IN PVOID Pattern,
  346. IN ULONG PatternSize,
  347. OUT PULONG Filled
  348. )
  349. {
  350. HRESULT Status = S_OK;
  351. PUCHAR Pat = (PUCHAR)Pattern;
  352. PUCHAR PatEnd = Pat + PatternSize;
  353. *Filled = 0;
  354. while (Size-- > 0)
  355. {
  356. ULONG Done;
  357. if (CheckUserInterrupt())
  358. {
  359. dprintf("User interrupt during fill - exiting.\n");
  360. Status = HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT);
  361. *Filled = 0;
  362. break;
  363. }
  364. if ((Status = WriteVirtual(Process, Start, Pat, 1, &Done)) != S_OK)
  365. {
  366. break;
  367. }
  368. if (Done != 1)
  369. {
  370. Status = HRESULT_FROM_WIN32(ERROR_WRITE_FAULT);
  371. break;
  372. }
  373. Start++;
  374. if (++Pat == PatEnd)
  375. {
  376. Pat = (PUCHAR)Pattern;
  377. }
  378. (*Filled)++;
  379. }
  380. // If nothing was filled return an error, otherwise
  381. // consider it a success.
  382. return *Filled > 0 ? S_OK : Status;
  383. }
  384. HRESULT
  385. TargetInfo::FillPhysical(
  386. THIS_
  387. IN ULONG64 Start,
  388. IN ULONG Size,
  389. IN PVOID Pattern,
  390. IN ULONG PatternSize,
  391. OUT PULONG Filled
  392. )
  393. {
  394. HRESULT Status = S_OK;
  395. PUCHAR Pat = (PUCHAR)Pattern;
  396. PUCHAR PatEnd = Pat + PatternSize;
  397. *Filled = 0;
  398. while (Size-- > 0)
  399. {
  400. ULONG Done;
  401. if (CheckUserInterrupt())
  402. {
  403. dprintf("User interrupt during fill - exiting.\n");
  404. Status = HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT);
  405. *Filled = 0;
  406. break;
  407. }
  408. if ((Status = WritePhysical(Start, Pat, 1, PHYS_FLAG_DEFAULT,
  409. &Done)) != S_OK)
  410. {
  411. break;
  412. }
  413. if (Done != 1)
  414. {
  415. Status = HRESULT_FROM_WIN32(ERROR_WRITE_FAULT);
  416. break;
  417. }
  418. Start++;
  419. if (++Pat == PatEnd)
  420. {
  421. Pat = (PUCHAR)Pattern;
  422. }
  423. (*Filled)++;
  424. }
  425. // If nothing was filled return an error, otherwise
  426. // consider it a success.
  427. return *Filled > 0 ? S_OK : Status;
  428. }
  429. HRESULT
  430. TargetInfo::GetProcessorId(ULONG Processor,
  431. PDEBUG_PROCESSOR_IDENTIFICATION_ALL Id)
  432. {
  433. // Base implementation which silently fails for modes
  434. // where the ID cannot be retrieved.
  435. return E_UNEXPECTED;
  436. }
  437. HRESULT
  438. TargetInfo::GetProcessorSpeed(ULONG Processor,
  439. PULONG Speed)
  440. {
  441. // Base implementation which silently fails for modes
  442. // where the speed cannot be retrieved.
  443. return E_UNEXPECTED;
  444. }
  445. HRESULT
  446. TargetInfo::GetGenericProcessorFeatures(
  447. ULONG Processor,
  448. PULONG64 Features,
  449. ULONG FeaturesSize,
  450. PULONG Used
  451. )
  452. {
  453. // Base implementation which silently fails for modes
  454. // where the information cannot be retrieved.
  455. return E_UNEXPECTED;
  456. }
  457. HRESULT
  458. TargetInfo::GetSpecificProcessorFeatures(
  459. ULONG Processor,
  460. PULONG64 Features,
  461. ULONG FeaturesSize,
  462. PULONG Used
  463. )
  464. {
  465. // Base implementation which silently fails for modes
  466. // where the information cannot be retrieved.
  467. return E_UNEXPECTED;
  468. }
  469. HRESULT
  470. TargetInfo::GetTaggedBaseOffset(PULONG64 Offset)
  471. {
  472. // Base implementation silently fails for
  473. // targets with no tagged data.
  474. return E_NOINTERFACE;
  475. }
  476. HRESULT
  477. TargetInfo::ReadTagged(ULONG64 Offset, PVOID Buffer, ULONG BufferSize)
  478. {
  479. // Base implementation silently fails for
  480. // targets with no tagged data.
  481. return E_NOINTERFACE;
  482. }
  483. HRESULT
  484. TargetInfo::ReadPageFile(ULONG PfIndex, ULONG64 PfOffset,
  485. PVOID Buffer, ULONG Size)
  486. {
  487. // Default implementation for targets which do not
  488. // support reading the page file.
  489. return HR_PAGE_NOT_AVAILABLE;
  490. }
  491. HRESULT
  492. TargetInfo::GetUnloadedModuleListHead(ProcessInfo* Process, PULONG64 Head)
  493. {
  494. // Get the address of the dynamic function table list head which is the
  495. // the same for all processes. This only has to be done once.
  496. if (Process->m_RtlUnloadList)
  497. {
  498. *Head = Process->m_RtlUnloadList;
  499. return S_OK;
  500. }
  501. GetOffsetFromSym(Process, "ntdll!RtlpUnloadEventTrace",
  502. &Process->m_RtlUnloadList, NULL);
  503. if (!Process->m_RtlUnloadList)
  504. {
  505. // No error message here as it's a common case when
  506. // symbols are bad.
  507. return E_NOINTERFACE;
  508. }
  509. *Head = Process->m_RtlUnloadList;
  510. return S_OK;
  511. }
  512. HRESULT
  513. TargetInfo::GetFunctionTableListHead(ProcessInfo* Process, PULONG64 Head)
  514. {
  515. // Get the address of the dynamic function table list head which is the
  516. // the same for all processes. This only has to be done once.
  517. if (Process->m_DynFuncTableList)
  518. {
  519. *Head = Process->m_DynFuncTableList;
  520. return S_OK;
  521. }
  522. GetOffsetFromSym(Process, "ntdll!RtlpDynamicFunctionTable",
  523. &Process->m_DynFuncTableList, NULL);
  524. if (!Process->m_DynFuncTableList)
  525. {
  526. // No error message here as it's a common case when
  527. // symbols are bad.
  528. return E_NOINTERFACE;
  529. }
  530. *Head = Process->m_DynFuncTableList;
  531. return S_OK;
  532. }
  533. // These procedures support dynamic function table entries for user-mode
  534. // run-time code. Dynamic function tables are stored in a linked list
  535. // inside ntdll. The address of the linked list head is returned by
  536. // RtlGetFunctionTableListHead. Since dynamic function tables are
  537. // only supported in user-mode the address of the list head will be
  538. // the same in all processes. Dynamic function tables are very rare,
  539. // so in most cases this the list will be unitialized and this routine
  540. // will return NULL. dbghelp only calls this when it
  541. // is unable to find a function entry in any of the images.
  542. PVOID
  543. TargetInfo::FindDynamicFunctionEntry(ProcessInfo* Process, ULONG64 Address)
  544. {
  545. ULONG64 ListHeadAddr;
  546. LIST_ENTRY64 DynamicFunctionTableHead;
  547. ULONG64 Entry;
  548. if (GetFunctionTableListHead(Process, &ListHeadAddr) != S_OK)
  549. {
  550. return NULL;
  551. }
  552. // Read the dynamic function table list head
  553. if (ReadListEntry(Process, m_Machine, ListHeadAddr,
  554. &DynamicFunctionTableHead) != S_OK)
  555. {
  556. // This failure happens almost all the time in minidumps
  557. // because the function table list symbol can be resolved
  558. // but the memory isn't part of the minidump.
  559. if (!IS_USER_MINI_DUMP(this))
  560. {
  561. ErrOut("Unable to read dynamic function table list head\n");
  562. }
  563. return NULL;
  564. }
  565. Entry = DynamicFunctionTableHead.Flink;
  566. // The list head is initialized the first time it's used so check
  567. // for an uninitialized pointers. This is the most common result.
  568. if (Entry == 0)
  569. {
  570. return NULL;
  571. }
  572. // Loop through the dynamic function table list reading the headers.
  573. // If the range of a dynamic function table contains Address then
  574. // search the function table. Dynamic function table ranges are not
  575. // mututally exclusive like those in images so an address may be
  576. // in more than one range. However, there can be only one dynamic function
  577. // entry that contains the address (if there are any at all).
  578. while (Entry != ListHeadAddr)
  579. {
  580. ULONG64 Table, MinAddress, MaxAddress, BaseAddress, TableData;
  581. ULONG TableSize;
  582. WCHAR OutOfProcessDll[MAX_PATH];
  583. CROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE RawTable;
  584. PVOID FunctionTable;
  585. PVOID FunctionEntry;
  586. Table = Entry;
  587. if (m_Machine->
  588. ReadDynamicFunctionTable(Process, Table, &Entry,
  589. &MinAddress, &MaxAddress,
  590. &BaseAddress,
  591. &TableData, &TableSize,
  592. OutOfProcessDll,
  593. &RawTable) != S_OK)
  594. {
  595. ErrOut("Unable to read dynamic function table entry\n");
  596. continue;
  597. }
  598. if (Address >= MinAddress && Address < MaxAddress &&
  599. (OutOfProcessDll[0] ||
  600. (TableData && TableSize > 0)))
  601. {
  602. if (OutOfProcessDll[0])
  603. {
  604. if (ReadOutOfProcessDynamicFunctionTable
  605. (Process, OutOfProcessDll, Table, &TableSize,
  606. &FunctionTable) != S_OK)
  607. {
  608. ErrOut("Unable to read dynamic function table entries\n");
  609. continue;
  610. }
  611. }
  612. else
  613. {
  614. FunctionTable = malloc(TableSize);
  615. if (FunctionTable == NULL)
  616. {
  617. ErrOut("Unable to allocate memory for "
  618. "dynamic function table\n");
  619. continue;
  620. }
  621. // Read the dynamic function table
  622. if (ReadAllVirtual(Process, TableData, FunctionTable,
  623. TableSize) != S_OK)
  624. {
  625. ErrOut("Unable to read dynamic function table entries\n");
  626. free(FunctionTable);
  627. continue;
  628. }
  629. }
  630. FunctionEntry = m_Machine->
  631. FindDynamicFunctionEntry(&RawTable, Address,
  632. FunctionTable, TableSize);
  633. free(FunctionTable);
  634. if (FunctionEntry)
  635. {
  636. return FunctionEntry;
  637. }
  638. }
  639. }
  640. return NULL;
  641. }
  642. ULONG64
  643. TargetInfo::GetDynamicFunctionTableBase(ProcessInfo* Process,
  644. ULONG64 Address)
  645. {
  646. LIST_ENTRY64 ListHead;
  647. ULONG64 Entry;
  648. // If the process dynamic function table list head hasn't
  649. // been looked up yet that means that no dynamic function
  650. // table entry could be in use yet, so there's no need to look.
  651. if (!Process->m_DynFuncTableList)
  652. {
  653. return 0;
  654. }
  655. if (ReadListEntry(Process, m_Machine,
  656. Process->m_DynFuncTableList,
  657. &ListHead) != S_OK)
  658. {
  659. return 0;
  660. }
  661. Entry = ListHead.Flink;
  662. // The list head is initialized the first time it's used so check
  663. // for an uninitialized pointers. This is the most common result.
  664. if (Entry == 0)
  665. {
  666. return 0;
  667. }
  668. // Loop through the dynamic function table list reading the headers.
  669. // If the range of a dynamic function table contains Address then
  670. // return the function table's base.
  671. while (Entry != Process->m_DynFuncTableList)
  672. {
  673. ULONG64 MinAddress, MaxAddress, BaseAddress, TableData;
  674. ULONG TableSize;
  675. WCHAR OutOfProcessDll[MAX_PATH];
  676. CROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE RawTable;
  677. if (m_Machine->
  678. ReadDynamicFunctionTable(Process, Entry, &Entry,
  679. &MinAddress, &MaxAddress,
  680. &BaseAddress,
  681. &TableData, &TableSize,
  682. OutOfProcessDll,
  683. &RawTable) == S_OK &&
  684. Address >= MinAddress &&
  685. Address < MaxAddress)
  686. {
  687. return BaseAddress;
  688. }
  689. }
  690. return 0;
  691. }
  692. HRESULT
  693. TargetInfo::ReadOutOfProcessDynamicFunctionTable(ProcessInfo* Process,
  694. PWSTR Dll,
  695. ULONG64 Table,
  696. PULONG TableSize,
  697. PVOID* TableData)
  698. {
  699. // Empty base implementation to avoid error messages
  700. // that would be produced by an UNEXPECTED_HR implementation.
  701. return E_UNEXPECTED;
  702. }
  703. PVOID CALLBACK
  704. TargetInfo::DynamicFunctionTableCallback(HANDLE ProcessHandle,
  705. ULONG64 Address,
  706. ULONG64 Context)
  707. {
  708. ProcessInfo* Process = (ProcessInfo*)Context;
  709. DBG_ASSERT(ProcessHandle == OS_HANDLE(Process->m_SysHandle));
  710. return Process->m_Target->
  711. FindDynamicFunctionEntry(Process, Address);
  712. }
  713. HRESULT
  714. TargetInfo::EnumFunctionTables(IN ProcessInfo* Process,
  715. IN OUT PULONG64 Start,
  716. IN OUT PULONG64 Handle,
  717. OUT PULONG64 MinAddress,
  718. OUT PULONG64 MaxAddress,
  719. OUT PULONG64 BaseAddress,
  720. OUT PULONG EntryCount,
  721. OUT PCROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE RawTable,
  722. OUT PVOID* RawEntries)
  723. {
  724. HRESULT Status;
  725. if (*Start == 0)
  726. {
  727. LIST_ENTRY64 DynamicFunctionTableHead;
  728. if ((Status = GetFunctionTableListHead(Process, Start)) != S_OK)
  729. {
  730. return Status;
  731. }
  732. if ((Status = ReadListEntry(Process, m_Machine, *Start,
  733. &DynamicFunctionTableHead)) != S_OK)
  734. {
  735. return Status;
  736. }
  737. *Handle = DynamicFunctionTableHead.Flink;
  738. }
  739. if (!*Handle || *Handle == *Start)
  740. {
  741. return S_FALSE;
  742. }
  743. ULONG64 Table, TableData;
  744. ULONG TableSize;
  745. WCHAR OutOfProcessDll[MAX_PATH];
  746. Table = *Handle;
  747. if ((Status = m_Machine->
  748. ReadDynamicFunctionTable(Process, Table, Handle,
  749. MinAddress, MaxAddress,
  750. BaseAddress,
  751. &TableData, &TableSize,
  752. OutOfProcessDll,
  753. RawTable)) != S_OK)
  754. {
  755. return Status;
  756. }
  757. if (OutOfProcessDll[0])
  758. {
  759. if ((Status = ReadOutOfProcessDynamicFunctionTable
  760. (Process, OutOfProcessDll, Table, &TableSize,
  761. RawEntries)) != S_OK)
  762. {
  763. return Status;
  764. }
  765. }
  766. else
  767. {
  768. *RawEntries = malloc(TableSize);
  769. if (!*RawEntries)
  770. {
  771. return E_OUTOFMEMORY;
  772. }
  773. // Read the dynamic function table
  774. if ((Status = ReadAllVirtual(Process, TableData,
  775. *RawEntries, TableSize)) != S_OK)
  776. {
  777. free(*RawEntries);
  778. return Status;
  779. }
  780. }
  781. *EntryCount = TableSize / m_TypeInfo.SizeRuntimeFunction;
  782. return S_OK;
  783. }
  784. HRESULT
  785. TargetInfo::QueryAddressInformation(ProcessInfo* Process,
  786. ULONG64 Address, ULONG InSpace,
  787. PULONG OutSpace, PULONG OutFlags)
  788. {
  789. // Default implementation which just returns the
  790. // least restrictive settings.
  791. *OutSpace = (Process && IS_KERNEL_TARGET(this)) ?
  792. DBGKD_QUERY_MEMORY_KERNEL : DBGKD_QUERY_MEMORY_PROCESS;
  793. *OutFlags =
  794. DBGKD_QUERY_MEMORY_READ |
  795. DBGKD_QUERY_MEMORY_WRITE |
  796. DBGKD_QUERY_MEMORY_EXECUTE;
  797. return S_OK;
  798. }
  799. HRESULT
  800. TargetInfo::ReadPointer(
  801. ProcessInfo* Process,
  802. MachineInfo* Machine,
  803. ULONG64 Address,
  804. PULONG64 Pointer64
  805. )
  806. {
  807. HRESULT Status;
  808. ULONG Result;
  809. ULONG SizeToRead;
  810. ULONG Pointer32;
  811. ULONG64 Data;
  812. if (Machine->m_Ptr64)
  813. {
  814. SizeToRead = sizeof(ULONG64);
  815. Status = ReadVirtual(Process, Address, &Data, SizeToRead, &Result);
  816. }
  817. else
  818. {
  819. SizeToRead = sizeof(ULONG32);
  820. Status = ReadVirtual(Process,
  821. Address, &Pointer32, SizeToRead, &Result);
  822. Data = EXTEND64(Pointer32);
  823. }
  824. if (Status != S_OK)
  825. {
  826. return Status;
  827. }
  828. if (Result != SizeToRead)
  829. {
  830. return E_FAIL;
  831. }
  832. *Pointer64 = Data;
  833. return S_OK;
  834. }
  835. HRESULT
  836. TargetInfo::WritePointer(
  837. ProcessInfo* Process,
  838. MachineInfo* Machine,
  839. ULONG64 Address,
  840. ULONG64 Pointer64
  841. )
  842. {
  843. HRESULT Status;
  844. ULONG Result;
  845. ULONG SizeToWrite;
  846. ULONG Pointer32;
  847. if (Machine->m_Ptr64)
  848. {
  849. SizeToWrite = sizeof(ULONG64);
  850. Status = WriteVirtual(Process,
  851. Address, &Pointer64, SizeToWrite, &Result);
  852. }
  853. else
  854. {
  855. SizeToWrite = sizeof(ULONG32);
  856. Pointer32 = (ULONG)Pointer64;
  857. Status = WriteVirtual(Process,
  858. Address, &Pointer32, SizeToWrite, &Result);
  859. }
  860. if (Status != S_OK)
  861. {
  862. return Status;
  863. }
  864. if (Result != SizeToWrite)
  865. {
  866. return HRESULT_FROM_WIN32(ERROR_WRITE_FAULT);
  867. }
  868. return S_OK;
  869. }
  870. HRESULT
  871. TargetInfo::ReadListEntry(
  872. ProcessInfo* Process,
  873. MachineInfo* Machine,
  874. ULONG64 Address,
  875. PLIST_ENTRY64 List64
  876. )
  877. {
  878. HRESULT Status;
  879. ULONG Result;
  880. ULONG SizeToRead;
  881. LIST_ENTRY32 List32;
  882. if (Machine->m_Ptr64)
  883. {
  884. SizeToRead = sizeof(LIST_ENTRY64);
  885. Status = ReadVirtual(Process, Address, List64, SizeToRead, &Result);
  886. }
  887. else
  888. {
  889. SizeToRead = sizeof(LIST_ENTRY32);
  890. Status = ReadVirtual(Process, Address, &List32, SizeToRead, &Result);
  891. }
  892. if (Status != S_OK)
  893. {
  894. return Status;
  895. }
  896. if (Result != SizeToRead)
  897. {
  898. return E_FAIL;
  899. }
  900. if (!Machine->m_Ptr64)
  901. {
  902. List64->Flink = EXTEND64(List32.Flink);
  903. List64->Blink = EXTEND64(List32.Blink);
  904. }
  905. return S_OK;
  906. }
  907. void
  908. ConvertLoaderEntry32To64(
  909. PKLDR_DATA_TABLE_ENTRY32 b32,
  910. PKLDR_DATA_TABLE_ENTRY64 b64
  911. )
  912. {
  913. #define COPYSE2(p64,s32,f) p64->f = (ULONG64)(LONG64)(LONG)s32->f
  914. COPYSE2(b64,b32,InLoadOrderLinks.Flink);
  915. COPYSE2(b64,b32,InLoadOrderLinks.Blink);
  916. COPYSE2(b64,b32,__Undefined1);
  917. COPYSE2(b64,b32,__Undefined2);
  918. COPYSE2(b64,b32,__Undefined3);
  919. COPYSE2(b64,b32,NonPagedDebugInfo);
  920. COPYSE2(b64,b32,DllBase);
  921. COPYSE2(b64,b32,EntryPoint);
  922. b64->SizeOfImage = b32->SizeOfImage;
  923. b64->FullDllName.Length = b32->FullDllName.Length;
  924. b64->FullDllName.MaximumLength = b32->FullDllName.MaximumLength;
  925. COPYSE2(b64,b32,FullDllName.Buffer);
  926. b64->BaseDllName.Length = b32->BaseDllName.Length;
  927. b64->BaseDllName.MaximumLength = b32->BaseDllName.MaximumLength;
  928. COPYSE2(b64,b32,BaseDllName.Buffer);
  929. b64->Flags = b32->Flags;
  930. b64->LoadCount = b32->LoadCount;
  931. b64->__Undefined5 = b32->__Undefined5;
  932. COPYSE2(b64,b32,__Undefined6);
  933. b64->CheckSum = b32->CheckSum;
  934. b64->TimeDateStamp = b32->TimeDateStamp;
  935. #undef COPYSE2
  936. return;
  937. }
  938. HRESULT
  939. TargetInfo::ReadLoaderEntry(
  940. ProcessInfo* Process,
  941. MachineInfo* Machine,
  942. ULONG64 Address,
  943. PKLDR_DATA_TABLE_ENTRY64 Entry
  944. )
  945. {
  946. HRESULT Status;
  947. ULONG Result;
  948. ULONG SizeToRead;
  949. KLDR_DATA_TABLE_ENTRY32 Ent32;
  950. if (Machine->m_Ptr64)
  951. {
  952. SizeToRead = sizeof(KLDR_DATA_TABLE_ENTRY64);
  953. Status = ReadVirtual(Process, Address, Entry, SizeToRead, &Result);
  954. }
  955. else
  956. {
  957. SizeToRead = sizeof(KLDR_DATA_TABLE_ENTRY32);
  958. Status = ReadVirtual(Process, Address, &Ent32, SizeToRead, &Result);
  959. ConvertLoaderEntry32To64(&Ent32, Entry);
  960. }
  961. if (Status != S_OK)
  962. {
  963. return Status;
  964. }
  965. if (Result != SizeToRead)
  966. {
  967. return E_FAIL;
  968. }
  969. return S_OK;
  970. }
  971. HRESULT
  972. TargetInfo::ReadUnicodeString(ProcessInfo* Process,
  973. MachineInfo* Machine,
  974. ULONG64 Address, PUNICODE_STRING64 String)
  975. {
  976. HRESULT Status;
  977. ULONG Result;
  978. ULONG SizeToRead;
  979. UNICODE_STRING32 Str32;
  980. if (Machine->m_Ptr64)
  981. {
  982. SizeToRead = sizeof(UNICODE_STRING64);
  983. Status = ReadVirtual(Process, Address, String, SizeToRead, &Result);
  984. }
  985. else
  986. {
  987. SizeToRead = sizeof(UNICODE_STRING32);
  988. Status = ReadVirtual(Process, Address, &Str32, SizeToRead, &Result);
  989. String->Length = Str32.Length;
  990. String->MaximumLength = Str32.MaximumLength;
  991. String->Buffer = EXTEND64(Str32.Buffer);
  992. }
  993. if (Status != S_OK)
  994. {
  995. return Status;
  996. }
  997. if (Result != SizeToRead)
  998. {
  999. return E_FAIL;
  1000. }
  1001. return S_OK;
  1002. }
  1003. // VS_VERSIONINFO has a variable format but in the case we
  1004. // care about it's fixed.
  1005. struct PARTIAL_VERSIONINFO
  1006. {
  1007. WORD wLength;
  1008. WORD wValueLength;
  1009. WORD wType;
  1010. WCHAR szKey[17];
  1011. VS_FIXEDFILEINFO Value;
  1012. };
  1013. #define VER2_SIG ((ULONG)'X2EF')
  1014. HRESULT
  1015. TargetInfo::ReadImageVersionInfo(ProcessInfo* Process,
  1016. ULONG64 ImageBase,
  1017. PCSTR Item,
  1018. PVOID Buffer,
  1019. ULONG BufferSize,
  1020. PULONG VerInfoSize,
  1021. PIMAGE_DATA_DIRECTORY ResDataDir)
  1022. {
  1023. if (ResDataDir->VirtualAddress == 0 ||
  1024. ResDataDir->Size < sizeof(IMAGE_RESOURCE_DIRECTORY))
  1025. {
  1026. return E_NOINTERFACE;
  1027. }
  1028. HRESULT Status;
  1029. IMAGE_RESOURCE_DIRECTORY ResDir;
  1030. ULONG64 Offset, DirOffset;
  1031. Offset = ImageBase + ResDataDir->VirtualAddress;
  1032. if ((Status = ReadAllVirtual(Process,
  1033. Offset, &ResDir, sizeof(ResDir))) != S_OK)
  1034. {
  1035. return Status;
  1036. }
  1037. //
  1038. // Search for the resource directory entry named by VS_FILE_INFO.
  1039. //
  1040. IMAGE_RESOURCE_DIRECTORY_ENTRY DirEnt;
  1041. ULONG i;
  1042. DirOffset = Offset;
  1043. Offset += sizeof(ResDir) +
  1044. ((ULONG64)ResDir.NumberOfNamedEntries * sizeof(DirEnt));
  1045. for (i = 0; i < (ULONG)ResDir.NumberOfIdEntries; i++)
  1046. {
  1047. if ((Status = ReadAllVirtual(Process,
  1048. Offset, &DirEnt, sizeof(DirEnt))) != S_OK)
  1049. {
  1050. return Status;
  1051. }
  1052. if (!DirEnt.NameIsString &&
  1053. MAKEINTRESOURCE(DirEnt.Id) == VS_FILE_INFO)
  1054. {
  1055. break;
  1056. }
  1057. Offset += sizeof(DirEnt);
  1058. }
  1059. if (i >= (ULONG)ResDir.NumberOfIdEntries ||
  1060. !DirEnt.DataIsDirectory)
  1061. {
  1062. return E_NOINTERFACE;
  1063. }
  1064. Offset = DirOffset + DirEnt.OffsetToDirectory;
  1065. if ((Status = ReadAllVirtual(Process,
  1066. Offset, &ResDir, sizeof(ResDir))) != S_OK)
  1067. {
  1068. return Status;
  1069. }
  1070. //
  1071. // Search for the resource directory entry named by VS_VERSION_INFO.
  1072. //
  1073. Offset += sizeof(ResDir) +
  1074. ((ULONG64)ResDir.NumberOfNamedEntries * sizeof(DirEnt));
  1075. for (i = 0; i < (ULONG)ResDir.NumberOfIdEntries; i++)
  1076. {
  1077. if ((Status = ReadAllVirtual(Process,
  1078. Offset, &DirEnt, sizeof(DirEnt))) != S_OK)
  1079. {
  1080. return Status;
  1081. }
  1082. if (DirEnt.Name == VS_VERSION_INFO)
  1083. {
  1084. break;
  1085. }
  1086. Offset += sizeof(DirEnt);
  1087. }
  1088. if (i >= (ULONG)ResDir.NumberOfIdEntries ||
  1089. !DirEnt.DataIsDirectory)
  1090. {
  1091. return E_NOINTERFACE;
  1092. }
  1093. Offset = DirOffset + DirEnt.OffsetToDirectory;
  1094. if ((Status = ReadAllVirtual(Process,
  1095. Offset, &ResDir, sizeof(ResDir))) != S_OK)
  1096. {
  1097. return Status;
  1098. }
  1099. //
  1100. // We now have the VS_VERSION_INFO directory. Just take
  1101. // the first entry as we don't care about languages.
  1102. //
  1103. Offset += sizeof(ResDir);
  1104. if ((Status = ReadAllVirtual(Process,
  1105. Offset, &DirEnt, sizeof(DirEnt))) != S_OK)
  1106. {
  1107. return Status;
  1108. }
  1109. if (DirEnt.DataIsDirectory)
  1110. {
  1111. return E_NOINTERFACE;
  1112. }
  1113. IMAGE_RESOURCE_DATA_ENTRY DataEnt;
  1114. Offset = DirOffset + DirEnt.OffsetToData;
  1115. if ((Status = ReadAllVirtual(Process,
  1116. Offset, &DataEnt, sizeof(DataEnt))) != S_OK)
  1117. {
  1118. return Status;
  1119. }
  1120. if (DataEnt.Size < sizeof(PARTIAL_VERSIONINFO))
  1121. {
  1122. return E_NOINTERFACE;
  1123. }
  1124. PARTIAL_VERSIONINFO RawInfo;
  1125. Offset = ImageBase + DataEnt.OffsetToData;
  1126. if ((Status = ReadAllVirtual(Process,
  1127. Offset, &RawInfo, sizeof(RawInfo))) != S_OK)
  1128. {
  1129. return Status;
  1130. }
  1131. if (RawInfo.wLength < sizeof(RawInfo) ||
  1132. wcscmp(RawInfo.szKey, L"VS_VERSION_INFO") != 0)
  1133. {
  1134. return E_NOINTERFACE;
  1135. }
  1136. //
  1137. // VerQueryValueA needs extra data space for ANSI translations
  1138. // of version strings. VQVA assumes that this space is available
  1139. // at the end of the data block passed in. GetFileVersionInformationSize
  1140. // makes this work by returning a size that's big enough
  1141. // for the actual data plus space for ANSI translations. We
  1142. // need to do the same thing here so that we also provide
  1143. // the necessary translation area.
  1144. //
  1145. ULONG DataSize = (RawInfo.wLength + 3) & ~3;
  1146. PVOID VerData = malloc(DataSize * 2 + sizeof(ULONG));
  1147. if (VerData == NULL)
  1148. {
  1149. return E_OUTOFMEMORY;
  1150. }
  1151. if ((Status = ReadAllVirtual(Process,
  1152. Offset, VerData, RawInfo.wLength)) == S_OK)
  1153. {
  1154. // Stamp the buffer with the signature that indicates
  1155. // a full-size translation buffer is available after
  1156. // the raw data.
  1157. *(PULONG)((PUCHAR)VerData + DataSize) = VER2_SIG;
  1158. Status = QueryVersionDataBuffer(VerData, Item,
  1159. Buffer, BufferSize, VerInfoSize);
  1160. }
  1161. free(VerData);
  1162. return Status;
  1163. }
  1164. HRESULT
  1165. TargetInfo::ReadImageNtHeaders(ProcessInfo* Process,
  1166. ULONG64 ImageBase,
  1167. PIMAGE_NT_HEADERS64 Headers)
  1168. {
  1169. HRESULT Status;
  1170. IMAGE_DOS_HEADER DosHdr;
  1171. IMAGE_NT_HEADERS32 Hdr32;
  1172. if ((Status = ReadAllVirtual(Process, ImageBase,
  1173. &DosHdr, sizeof(DosHdr))) != S_OK)
  1174. {
  1175. return Status;
  1176. }
  1177. if (DosHdr.e_magic != IMAGE_DOS_SIGNATURE)
  1178. {
  1179. return E_INVALIDARG;
  1180. }
  1181. // Only read HEADERS32 worth of data first in case
  1182. // that's all the memory that's available.
  1183. if ((Status = ReadAllVirtual(Process, ImageBase + DosHdr.e_lfanew,
  1184. &Hdr32, sizeof(Hdr32))) != S_OK)
  1185. {
  1186. return Status;
  1187. }
  1188. if (Hdr32.Signature != IMAGE_NT_SIGNATURE)
  1189. {
  1190. return E_INVALIDARG;
  1191. }
  1192. switch(Hdr32.OptionalHeader.Magic)
  1193. {
  1194. case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
  1195. ImageNtHdr32To64(&Hdr32, Headers);
  1196. Status = S_OK;
  1197. break;
  1198. case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
  1199. // Read the remainder of the header.
  1200. memcpy(Headers, &Hdr32, sizeof(Hdr32));
  1201. Status = ReadAllVirtual(Process,
  1202. ImageBase + DosHdr.e_lfanew + sizeof(Hdr32),
  1203. (PUCHAR)Headers + sizeof(Hdr32),
  1204. sizeof(*Headers) - sizeof(Hdr32));
  1205. break;
  1206. default:
  1207. Status = E_INVALIDARG;
  1208. break;
  1209. }
  1210. return Status;
  1211. }
  1212. HRESULT
  1213. TargetInfo::ReadDirectoryTableBase(PULONG64 DirBase)
  1214. {
  1215. HRESULT Status;
  1216. ULONG64 CurProc;
  1217. // Retrieve the current EPROCESS's DirectoryTableBase[0] value.
  1218. Status = GetProcessInfoDataOffset(m_RegContextThread, 0, 0, &CurProc);
  1219. if (Status != S_OK)
  1220. {
  1221. return Status;
  1222. }
  1223. CurProc += m_KdDebuggerData.OffsetEprocessDirectoryTableBase;
  1224. return ReadPointer(m_ProcessHead, m_Machine, CurProc, DirBase);
  1225. }
  1226. HRESULT
  1227. TargetInfo::ReadSharedUserTimeDateN(PULONG64 TimeDate)
  1228. {
  1229. return ReadAllVirtual(m_ProcessHead, m_TypeInfo.SharedUserDataOffset +
  1230. FIELD_OFFSET(KUSER_SHARED_DATA, SystemTime),
  1231. TimeDate, sizeof(*TimeDate));
  1232. }
  1233. HRESULT
  1234. TargetInfo::ReadSharedUserUpTimeN(PULONG64 UpTime)
  1235. {
  1236. return ReadAllVirtual(m_ProcessHead, m_TypeInfo.SharedUserDataOffset +
  1237. FIELD_OFFSET(KUSER_SHARED_DATA, InterruptTime),
  1238. UpTime, sizeof(*UpTime));
  1239. }
  1240. HRESULT
  1241. TargetInfo::ReadSharedUserProductInfo(PULONG ProductType, PULONG SuiteMask)
  1242. {
  1243. HRESULT Status;
  1244. BOOLEAN IsValid;
  1245. if ((Status =
  1246. ReadAllVirtual(m_ProcessHead, m_TypeInfo.SharedUserDataOffset +
  1247. FIELD_OFFSET(KUSER_SHARED_DATA, ProductTypeIsValid),
  1248. &IsValid, sizeof(IsValid))) != S_OK)
  1249. {
  1250. return Status;
  1251. }
  1252. if (!IsValid)
  1253. {
  1254. return E_NOTIMPL;
  1255. }
  1256. if ((Status =
  1257. ReadAllVirtual(m_ProcessHead, m_TypeInfo.SharedUserDataOffset +
  1258. FIELD_OFFSET(KUSER_SHARED_DATA, NtProductType),
  1259. ProductType, sizeof(*ProductType))) != S_OK)
  1260. {
  1261. return Status;
  1262. }
  1263. return ReadAllVirtual(m_ProcessHead, m_TypeInfo.SharedUserDataOffset +
  1264. FIELD_OFFSET(KUSER_SHARED_DATA, SuiteMask),
  1265. SuiteMask, sizeof(*SuiteMask));
  1266. }
  1267. //----------------------------------------------------------------------------
  1268. //
  1269. // LiveKernelTargetInfo data space methods.
  1270. //
  1271. //----------------------------------------------------------------------------
  1272. HRESULT
  1273. LiveKernelTargetInfo::GetProcessorId
  1274. (ULONG Processor, PDEBUG_PROCESSOR_IDENTIFICATION_ALL Id)
  1275. {
  1276. return m_Machine->ReadKernelProcessorId(Processor, Id);
  1277. }
  1278. HRESULT
  1279. LiveKernelTargetInfo::GetProcessorSpeed
  1280. (ULONG Processor, PULONG Speed)
  1281. {
  1282. HRESULT Status;
  1283. ULONG64 Prcb;
  1284. if ((Status =
  1285. GetProcessorSystemDataOffset(Processor, DEBUG_DATA_KPRCB_OFFSET,
  1286. &Prcb)) != S_OK)
  1287. {
  1288. return Status;
  1289. }
  1290. if (!m_KdDebuggerData.OffsetPrcbMhz)
  1291. {
  1292. return E_NOTIMPL;
  1293. }
  1294. return
  1295. ReadAllVirtual(m_ProcessHead,
  1296. Prcb + m_KdDebuggerData.OffsetPrcbMhz, Speed,
  1297. sizeof(ULONG));
  1298. }
  1299. //----------------------------------------------------------------------------
  1300. //
  1301. // ConnLiveKernelTargetInfo data space methods.
  1302. //
  1303. //----------------------------------------------------------------------------
  1304. HRESULT
  1305. ConnLiveKernelTargetInfo::ReadVirtual(
  1306. THIS_
  1307. IN ProcessInfo* Process,
  1308. IN ULONG64 Offset,
  1309. OUT PVOID Buffer,
  1310. IN ULONG BufferSize,
  1311. OUT PULONG BytesRead
  1312. )
  1313. {
  1314. if (Process)
  1315. {
  1316. return Process->m_VirtualCache.
  1317. Read(Offset, Buffer, BufferSize, BytesRead);
  1318. }
  1319. else
  1320. {
  1321. return ReadVirtualUncached(Process,
  1322. Offset, Buffer, BufferSize, BytesRead);
  1323. }
  1324. }
  1325. HRESULT
  1326. ConnLiveKernelTargetInfo::WriteVirtual(
  1327. THIS_
  1328. IN ProcessInfo* Process,
  1329. IN ULONG64 Offset,
  1330. IN PVOID Buffer,
  1331. IN ULONG BufferSize,
  1332. OUT PULONG BytesWritten
  1333. )
  1334. {
  1335. HRESULT Status;
  1336. if (Process)
  1337. {
  1338. Status = Process->m_VirtualCache.
  1339. Write(Offset, Buffer, BufferSize, BytesWritten);
  1340. }
  1341. else
  1342. {
  1343. Status = WriteVirtualUncached(Process, Offset, Buffer, BufferSize,
  1344. BytesWritten);
  1345. }
  1346. if (Status == S_OK)
  1347. {
  1348. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_VIRTUAL);
  1349. }
  1350. return Status;
  1351. }
  1352. HRESULT
  1353. ConnLiveKernelTargetInfo::SearchVirtual(
  1354. IN ProcessInfo* Process,
  1355. IN ULONG64 Offset,
  1356. IN ULONG64 Length,
  1357. IN PVOID Pattern,
  1358. IN ULONG PatternSize,
  1359. IN ULONG PatternGranularity,
  1360. OUT PULONG64 MatchOffset
  1361. )
  1362. {
  1363. // In NT 4.0, the search API is not supported at the kernel protocol
  1364. // level. Fall back to the default ReadMemory \ search.
  1365. //
  1366. HRESULT Status;
  1367. if (m_SystemVersion <= NT_SVER_NT4 ||
  1368. PatternGranularity != 1)
  1369. {
  1370. Status = TargetInfo::SearchVirtual(Process,
  1371. Offset, Length, (PUCHAR)Pattern,
  1372. PatternSize, PatternGranularity,
  1373. MatchOffset);
  1374. }
  1375. else
  1376. {
  1377. DBGKD_MANIPULATE_STATE64 m;
  1378. PDBGKD_MANIPULATE_STATE64 Reply;
  1379. PDBGKD_SEARCH_MEMORY a = &m.u.SearchMemory;
  1380. ULONG rc;
  1381. NTSTATUS st;
  1382. KdOut("Search called %s, length %I64x\n",
  1383. FormatAddr64(Offset), Length);
  1384. *MatchOffset = 0;
  1385. a->SearchAddress = Offset;
  1386. a->SearchLength = Length;
  1387. a->PatternLength = PatternSize;
  1388. m.ApiNumber = DbgKdSearchMemoryApi;
  1389. m.ReturnStatus = STATUS_PENDING;
  1390. //
  1391. // Send the message and data to write and then wait for reply
  1392. //
  1393. do
  1394. {
  1395. m_Transport->WritePacket(&m, sizeof(m),
  1396. PACKET_TYPE_KD_STATE_MANIPULATE,
  1397. Pattern, (USHORT)PatternSize);
  1398. rc = m_Transport->
  1399. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  1400. } while (rc != DBGKD_WAIT_PACKET ||
  1401. Reply->ApiNumber != DbgKdSearchMemoryApi);
  1402. st = Reply->ReturnStatus;
  1403. if (NT_SUCCESS(st))
  1404. {
  1405. if (m_Machine->m_Ptr64)
  1406. {
  1407. *MatchOffset = Reply->u.SearchMemory.FoundAddress;
  1408. }
  1409. else
  1410. {
  1411. *MatchOffset = EXTEND64(Reply->u.SearchMemory.FoundAddress);
  1412. }
  1413. }
  1414. KdOut("DbgKdSearchMemory %08lx\n", st);
  1415. Status = CONV_NT_STATUS(st);
  1416. }
  1417. return Status;
  1418. }
  1419. HRESULT
  1420. ConnLiveKernelTargetInfo::ReadVirtualUncached(
  1421. THIS_
  1422. IN ProcessInfo* Process,
  1423. IN ULONG64 Offset,
  1424. OUT PVOID Buffer,
  1425. IN ULONG BufferSize,
  1426. OUT PULONG BytesRead
  1427. )
  1428. {
  1429. BOOL TranslateVirt = Process &&
  1430. Process->m_VirtualCache.m_ForceDecodePTEs;
  1431. ULONG Done;
  1432. ULONG Left;
  1433. HRESULT Status = S_OK;
  1434. if (!m_Machine->m_Ptr64 && EXTEND64((ULONG)Offset) != Offset)
  1435. {
  1436. ErrOut("ReadVirtual: %08x not properly sign extended\n",
  1437. (ULONG)Offset);
  1438. }
  1439. Restart:
  1440. Done = 0;
  1441. Left = BufferSize;
  1442. while (Left)
  1443. {
  1444. ULONG64 ReqOffs;
  1445. ULONG Req;
  1446. // Exit if the user is tired of waiting.
  1447. if (g_EngStatus & ENG_STATUS_USER_INTERRUPT)
  1448. {
  1449. Done = 0;
  1450. Status = HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT);
  1451. break;
  1452. }
  1453. ReqOffs = Offset + Done;
  1454. Req = Left;
  1455. if (Req > MAX_MANIP_TRANSFER)
  1456. {
  1457. Req = MAX_MANIP_TRANSFER;
  1458. }
  1459. // Split all requests at page boundaries. This
  1460. // handles different translations per page in the
  1461. // case where the debugger is translating and also
  1462. // avoids failures in partial success cases where
  1463. // the lead page is valid but followers are not.
  1464. if (PAGE_ALIGN(m_Machine, ReqOffs) !=
  1465. PAGE_ALIGN(m_Machine, ReqOffs + Req - 1))
  1466. {
  1467. Req = (ULONG)
  1468. ((ReqOffs | (m_Machine->m_PageSize - 1)) - ReqOffs + 1);
  1469. }
  1470. if (TranslateVirt)
  1471. {
  1472. Status = KdReadVirtualTranslated(ReqOffs, (PUCHAR)Buffer + Done,
  1473. Req, &Req);
  1474. }
  1475. else
  1476. {
  1477. NTSTATUS NtStatus =
  1478. KdReadVirtual(ReqOffs, (PUCHAR)Buffer + Done, Req, &Req);
  1479. Status = CONV_NT_STATUS(NtStatus);
  1480. }
  1481. if (Status != S_OK)
  1482. {
  1483. // If the target machine failed the write it
  1484. // may be because there's a page in transition
  1485. // which it didn't want to access. Try again
  1486. // with the debugger doing the translations so
  1487. // that it can override certain protections.
  1488. if (Status != HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT) &&
  1489. !TranslateVirt &&
  1490. Process && Process->m_VirtualCache.m_DecodePTEs)
  1491. {
  1492. TranslateVirt = TRUE;
  1493. goto Restart;
  1494. }
  1495. break;
  1496. }
  1497. else
  1498. {
  1499. Left -= Req;
  1500. Done += Req;
  1501. }
  1502. }
  1503. *BytesRead = Done;
  1504. return Done > 0 ? S_OK : Status;
  1505. }
  1506. HRESULT
  1507. ConnLiveKernelTargetInfo::WriteVirtualUncached(
  1508. THIS_
  1509. IN ProcessInfo* Process,
  1510. IN ULONG64 Offset,
  1511. IN PVOID Buffer,
  1512. IN ULONG BufferSize,
  1513. OUT PULONG BytesWritten
  1514. )
  1515. {
  1516. BOOL TranslateVirt = Process &&
  1517. Process->m_VirtualCache.m_ForceDecodePTEs;
  1518. ULONG Done;
  1519. ULONG Left;
  1520. HRESULT Status = S_OK;
  1521. if (!m_Machine->m_Ptr64 && EXTEND64((ULONG)Offset) != Offset)
  1522. {
  1523. ErrOut("WriteVirtual: %08x not properly sign extended\n",
  1524. (ULONG)Offset);
  1525. }
  1526. // Restrict notifications to a single notify at the end.
  1527. g_EngNotify++;
  1528. Restart:
  1529. Done = 0;
  1530. Left = BufferSize;
  1531. while (Left)
  1532. {
  1533. ULONG64 ReqOffs;
  1534. ULONG Req;
  1535. ReqOffs = Offset + Done;
  1536. Req = Left;
  1537. if (Req > MAX_MANIP_TRANSFER)
  1538. {
  1539. Req = MAX_MANIP_TRANSFER;
  1540. }
  1541. // Split all requests at page boundaries. This
  1542. // handles different translations per page in the
  1543. // case where the debugger is translating and also
  1544. // avoids failures in partial success cases where
  1545. // the lead page is valid but followers are not.
  1546. if (PAGE_ALIGN(m_Machine, ReqOffs) !=
  1547. PAGE_ALIGN(m_Machine, ReqOffs + Req - 1))
  1548. {
  1549. Req = (ULONG)
  1550. ((ReqOffs | (m_Machine->m_PageSize - 1)) - ReqOffs + 1);
  1551. }
  1552. if (TranslateVirt)
  1553. {
  1554. Status = KdWriteVirtualTranslated(ReqOffs, (PUCHAR)Buffer + Done,
  1555. Req, &Req);
  1556. }
  1557. else
  1558. {
  1559. NTSTATUS NtStatus =
  1560. KdWriteVirtual(ReqOffs, (PUCHAR)Buffer + Done, Req, &Req);
  1561. Status = CONV_NT_STATUS(NtStatus);
  1562. }
  1563. if (Status != S_OK)
  1564. {
  1565. // If the target machine failed the write it
  1566. // may be because there's a page in transition
  1567. // which it didn't want to access. Try again
  1568. // with the debugger doing the translations so
  1569. // that it can override certain protections.
  1570. if (Status != HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT) &&
  1571. !TranslateVirt &&
  1572. Process && Process->m_VirtualCache.m_DecodePTEs)
  1573. {
  1574. TranslateVirt = TRUE;
  1575. goto Restart;
  1576. }
  1577. break;
  1578. }
  1579. else
  1580. {
  1581. Left -= Req;
  1582. Done += Req;
  1583. }
  1584. }
  1585. *BytesWritten = Done;
  1586. Status = Done > 0 ? S_OK : Status;
  1587. g_EngNotify--;
  1588. if (Status == S_OK)
  1589. {
  1590. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_VIRTUAL);
  1591. }
  1592. return Status;
  1593. }
  1594. NTSTATUS
  1595. ConnLiveKernelTargetInfo::KdReadVirtual(
  1596. IN ULONG64 Offset,
  1597. OUT PVOID Buffer,
  1598. IN ULONG BufferSize,
  1599. OUT OPTIONAL PULONG BytesRead
  1600. )
  1601. {
  1602. DBGKD_MANIPULATE_STATE64 m;
  1603. PDBGKD_MANIPULATE_STATE64 Reply;
  1604. ULONG rc;
  1605. //
  1606. // Initialize state manipulate message to read virtual memory.
  1607. //
  1608. m.ApiNumber = DbgKdReadVirtualMemoryApi;
  1609. m.u.ReadMemory.TargetBaseAddress = Offset;
  1610. m.u.ReadMemory.TransferCount = BufferSize;
  1611. //
  1612. // Send the read virtual message to the target system and wait for
  1613. // a reply.
  1614. //
  1615. do
  1616. {
  1617. m_Transport->WritePacket(&m, sizeof(m),
  1618. PACKET_TYPE_KD_STATE_MANIPULATE,
  1619. NULL, 0);
  1620. rc = m_Transport->
  1621. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  1622. }
  1623. while ((rc != DBGKD_WAIT_PACKET) ||
  1624. (Reply->ApiNumber != DbgKdReadVirtualMemoryApi));
  1625. if (NT_SUCCESS(Reply->ReturnStatus))
  1626. {
  1627. if (Reply->u.ReadMemory.ActualBytesRead == 0)
  1628. {
  1629. Reply->ReturnStatus = STATUS_UNSUCCESSFUL;
  1630. }
  1631. else
  1632. {
  1633. if (Reply->u.ReadMemory.ActualBytesRead > BufferSize)
  1634. {
  1635. ErrOut("KdReadVirtual: Asked for %d, got %d\n",
  1636. BufferSize, Reply->u.ReadMemory.ActualBytesRead);
  1637. Reply->u.ReadMemory.ActualBytesRead = BufferSize;
  1638. }
  1639. memcpy(Buffer, Reply + 1, Reply->u.ReadMemory.ActualBytesRead);
  1640. }
  1641. }
  1642. *BytesRead = Reply->u.ReadMemory.ActualBytesRead;
  1643. KdOut("KdReadVirtual(%s, %x) returns %08lx, %x\n",
  1644. FormatAddr64(Offset), BufferSize,
  1645. Reply->ReturnStatus, *BytesRead);
  1646. return Reply->ReturnStatus;
  1647. }
  1648. NTSTATUS
  1649. ConnLiveKernelTargetInfo::KdWriteVirtual(
  1650. IN ULONG64 Offset,
  1651. IN PVOID Buffer,
  1652. IN ULONG BufferSize,
  1653. OUT OPTIONAL PULONG BytesWritten
  1654. )
  1655. {
  1656. DBGKD_MANIPULATE_STATE64 m;
  1657. PDBGKD_MANIPULATE_STATE64 Reply;
  1658. ULONG rc;
  1659. //
  1660. // Initialize state manipulate message to write virtual memory.
  1661. //
  1662. m.ApiNumber = DbgKdWriteVirtualMemoryApi;
  1663. m.u.WriteMemory.TargetBaseAddress = Offset;
  1664. m.u.WriteMemory.TransferCount = BufferSize;
  1665. //
  1666. // Send the write message and data to the target system and wait
  1667. // for a reply.
  1668. //
  1669. do
  1670. {
  1671. m_Transport->WritePacket(&m, sizeof(m),
  1672. PACKET_TYPE_KD_STATE_MANIPULATE,
  1673. Buffer, (USHORT)BufferSize);
  1674. rc = m_Transport->
  1675. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  1676. }
  1677. while ((rc != DBGKD_WAIT_PACKET) ||
  1678. (Reply->ApiNumber != DbgKdWriteVirtualMemoryApi));
  1679. KdOut("DbgKdWriteVirtualMemory returns %08lx\n", Reply->ReturnStatus);
  1680. *BytesWritten = Reply->u.WriteMemory.ActualBytesWritten;
  1681. KdOut("KdWriteVirtual(%s, %x) returns %08lx, %x\n",
  1682. FormatAddr64(Offset), BufferSize,
  1683. Reply->ReturnStatus, *BytesWritten);
  1684. return Reply->ReturnStatus;
  1685. }
  1686. HRESULT
  1687. ConnLiveKernelTargetInfo::KdReadVirtualTranslated(
  1688. IN ULONG64 Offset,
  1689. OUT PVOID Buffer,
  1690. IN ULONG BufferSize,
  1691. OUT OPTIONAL PULONG BytesRead
  1692. )
  1693. {
  1694. //
  1695. // Virtual addresses are not necessarily contiguous
  1696. // after translation to physical addresses so do
  1697. // not allow transfers that cross a page boundary.
  1698. // Higher-level code is responsible for splitting
  1699. // up requests.
  1700. //
  1701. DBG_ASSERT(PAGE_ALIGN(m_Machine, Offset) ==
  1702. PAGE_ALIGN(m_Machine, Offset + BufferSize - 1));
  1703. ULONG64 TargetPhysicalAddress;
  1704. ULONG Levels;
  1705. ULONG PfIndex;
  1706. HRESULT Status;
  1707. BOOL ChangedSuspend;
  1708. // Allow the page table physical accesses to be cached.
  1709. ChangedSuspend = m_PhysicalCache.ChangeSuspend(TRUE);
  1710. Status = m_Machine->
  1711. GetVirtualTranslationPhysicalOffsets(m_ProcessHead->m_CurrentThread,
  1712. Offset, NULL, 0,
  1713. &Levels, &PfIndex,
  1714. &TargetPhysicalAddress);
  1715. if (ChangedSuspend)
  1716. {
  1717. m_PhysicalCache.ChangeSuspend(FALSE);
  1718. }
  1719. if (Status == S_OK)
  1720. {
  1721. Status = ReadPhysicalUncached(TargetPhysicalAddress,
  1722. Buffer, BufferSize,
  1723. PHYS_FLAG_DEFAULT,
  1724. BytesRead);
  1725. }
  1726. else if (Status == HR_PAGE_IN_PAGE_FILE ||
  1727. Status == HR_PAGE_NOT_AVAILABLE)
  1728. {
  1729. // Translate specific errors into generic memory
  1730. // failure errors.
  1731. Status = HRESULT_FROM_NT(STATUS_UNSUCCESSFUL);
  1732. }
  1733. return Status;
  1734. }
  1735. HRESULT
  1736. ConnLiveKernelTargetInfo::KdWriteVirtualTranslated(
  1737. IN ULONG64 Offset,
  1738. IN PVOID Buffer,
  1739. IN ULONG BufferSize,
  1740. OUT OPTIONAL PULONG BytesWritten
  1741. )
  1742. {
  1743. //
  1744. // Virtual addresses are not necessarily contiguous
  1745. // after translation to physical addresses so do
  1746. // not allow transfers that cross a page boundary.
  1747. // Higher-level code is responsible for splitting
  1748. // up requests.
  1749. //
  1750. DBG_ASSERT(PAGE_ALIGN(m_Machine, Offset) ==
  1751. PAGE_ALIGN(m_Machine, Offset + BufferSize - 1));
  1752. ULONG64 TargetPhysicalAddress;
  1753. ULONG Levels;
  1754. ULONG PfIndex;
  1755. HRESULT Status;
  1756. BOOL ChangedSuspend;
  1757. // Allow the page table physical accesses to be cached.
  1758. ChangedSuspend = m_PhysicalCache.ChangeSuspend(TRUE);
  1759. Status = m_Machine->
  1760. GetVirtualTranslationPhysicalOffsets(m_ProcessHead->m_CurrentThread,
  1761. Offset, NULL, 0,
  1762. &Levels, &PfIndex,
  1763. &TargetPhysicalAddress);
  1764. if (ChangedSuspend)
  1765. {
  1766. m_PhysicalCache.ChangeSuspend(FALSE);
  1767. }
  1768. if (Status == S_OK)
  1769. {
  1770. Status = WritePhysicalUncached(TargetPhysicalAddress,
  1771. Buffer, BufferSize,
  1772. PHYS_FLAG_DEFAULT,
  1773. BytesWritten);
  1774. }
  1775. else if (Status == HR_PAGE_IN_PAGE_FILE ||
  1776. Status == HR_PAGE_NOT_AVAILABLE)
  1777. {
  1778. // Translate specific errors into generic memory
  1779. // failure errors.
  1780. Status = HRESULT_FROM_NT(STATUS_UNSUCCESSFUL);
  1781. }
  1782. return Status;
  1783. }
  1784. HRESULT
  1785. ConnLiveKernelTargetInfo::ReadPhysical(
  1786. THIS_
  1787. IN ULONG64 Offset,
  1788. OUT PVOID Buffer,
  1789. IN ULONG BufferSize,
  1790. IN ULONG Flags,
  1791. OUT PULONG BytesRead
  1792. )
  1793. {
  1794. if (!m_PhysicalCache.m_Suspend)
  1795. {
  1796. if (Flags != PHYS_FLAG_DEFAULT)
  1797. {
  1798. return E_NOTIMPL;
  1799. }
  1800. return m_PhysicalCache.
  1801. Read(Offset, Buffer, BufferSize, BytesRead);
  1802. }
  1803. else
  1804. {
  1805. return ReadPhysicalUncached(Offset, Buffer, BufferSize, Flags,
  1806. BytesRead);
  1807. }
  1808. }
  1809. HRESULT
  1810. ConnLiveKernelTargetInfo::WritePhysical(
  1811. THIS_
  1812. IN ULONG64 Offset,
  1813. IN PVOID Buffer,
  1814. IN ULONG BufferSize,
  1815. IN ULONG Flags,
  1816. OUT PULONG BytesWritten
  1817. )
  1818. {
  1819. if (!m_PhysicalCache.m_Suspend)
  1820. {
  1821. if (Flags != PHYS_FLAG_DEFAULT)
  1822. {
  1823. return E_NOTIMPL;
  1824. }
  1825. return m_PhysicalCache.
  1826. Write(Offset, Buffer, BufferSize, BytesWritten);
  1827. }
  1828. else
  1829. {
  1830. return WritePhysicalUncached(Offset, Buffer, BufferSize, Flags,
  1831. BytesWritten);
  1832. }
  1833. }
  1834. HRESULT
  1835. ConnLiveKernelTargetInfo::PointerSearchPhysical(
  1836. IN ULONG64 Offset,
  1837. IN ULONG64 Length,
  1838. IN ULONG64 PointerMin,
  1839. IN ULONG64 PointerMax,
  1840. IN ULONG Flags,
  1841. OUT PULONG64 MatchOffsets,
  1842. IN ULONG MatchOffsetsSize,
  1843. OUT PULONG MatchOffsetsCount
  1844. )
  1845. {
  1846. const ULONG SEARCH_SYMBOL_CHECK = 0xABCDDCBA;
  1847. HRESULT Status;
  1848. // The kernel stubs only handle page-based searches,
  1849. // so if the search isn't page aligned fall back on
  1850. // the base implementation.
  1851. // The kernel also will only return a single hit if
  1852. // the search range is greater than a page.
  1853. if ((Offset & ((1 << m_Machine->m_PageShift) - 1)) ||
  1854. (Length & ((1 << m_Machine->m_PageShift) - 1)) ||
  1855. ((Flags & PTR_SEARCH_PHYS_ALL_HITS) &&
  1856. Length != m_Machine->m_PageSize))
  1857. {
  1858. return TargetInfo::PointerSearchPhysical(Offset, Length,
  1859. PointerMin, PointerMax,
  1860. Flags, MatchOffsets,
  1861. MatchOffsetsSize,
  1862. MatchOffsetsCount);
  1863. }
  1864. if (!m_KdpSearchInProgress)
  1865. {
  1866. if (!GetOffsetFromSym(m_ProcessHead,
  1867. "nt!KdpSearchPageHits",
  1868. &m_KdpSearchPageHits, NULL) ||
  1869. !GetOffsetFromSym(m_ProcessHead,
  1870. "nt!KdpSearchPageHitOffsets",
  1871. &m_KdpSearchPageHitOffsets, NULL) ||
  1872. !GetOffsetFromSym(m_ProcessHead,
  1873. "nt!KdpSearchPageHitIndex",
  1874. &m_KdpSearchPageHitIndex, NULL) ||
  1875. !GetOffsetFromSym(m_ProcessHead,
  1876. "nt!KdpSearchInProgress",
  1877. &m_KdpSearchInProgress, NULL) ||
  1878. !GetOffsetFromSym(m_ProcessHead,
  1879. "nt!KdpSearchStartPageFrame",
  1880. &m_KdpSearchStartPageFrame, NULL) ||
  1881. !GetOffsetFromSym(m_ProcessHead,
  1882. "nt!KdpSearchEndPageFrame",
  1883. &m_KdpSearchEndPageFrame, NULL) ||
  1884. !GetOffsetFromSym(m_ProcessHead,
  1885. "nt!KdpSearchAddressRangeStart",
  1886. &m_KdpSearchAddressRangeStart, NULL) ||
  1887. !GetOffsetFromSym(m_ProcessHead,
  1888. "nt!KdpSearchAddressRangeEnd",
  1889. &m_KdpSearchAddressRangeEnd, NULL) ||
  1890. !GetOffsetFromSym(m_ProcessHead,
  1891. "nt!KdpSearchPfnValue",
  1892. &m_KdpSearchPfnValue, NULL))
  1893. {
  1894. m_KdpSearchInProgress = 0;
  1895. ErrOut("Search error: Unable to resolve symbols for kernel\n");
  1896. return E_INVALIDARG;
  1897. }
  1898. if (!(Flags & PTR_SEARCH_NO_SYMBOL_CHECK))
  1899. {
  1900. ULONG Check;
  1901. if (!GetOffsetFromSym(m_ProcessHead,
  1902. "nt!KdpSearchCheckPoint",
  1903. &m_KdpSearchCheckPoint, NULL) ||
  1904. ReadAllVirtual(m_ProcessHead, m_KdpSearchCheckPoint,
  1905. &Check, sizeof(Check)) != S_OK ||
  1906. Check != SEARCH_SYMBOL_CHECK)
  1907. {
  1908. m_KdpSearchInProgress = 0;
  1909. ErrOut("Search error: Incorrect symbols for kernel\n");
  1910. return E_INVALIDARG;
  1911. }
  1912. }
  1913. }
  1914. ULONG Ul;
  1915. //
  1916. // Perform some sanity checks on the values.
  1917. //
  1918. if (ReadAllVirtual(m_ProcessHead,
  1919. m_KdpSearchInProgress, &Ul, sizeof(Ul)) != S_OK ||
  1920. Ul != 0)
  1921. {
  1922. ErrOut("Search error: "
  1923. "Inconsistent value for nt!KdpSearchInProgress \n");
  1924. return E_INVALIDARG;
  1925. }
  1926. //
  1927. // Set up the search engine
  1928. //
  1929. if ((Status = WritePointer(m_ProcessHead, m_Machine,
  1930. m_KdpSearchAddressRangeStart,
  1931. PointerMin)) != S_OK ||
  1932. (Status = WritePointer(m_ProcessHead, m_Machine,
  1933. m_KdpSearchAddressRangeEnd,
  1934. PointerMax)) != S_OK ||
  1935. (Status = WritePointer(m_ProcessHead, m_Machine,
  1936. m_KdpSearchStartPageFrame,
  1937. Offset >> m_Machine->
  1938. m_PageShift)) != S_OK ||
  1939. (Status = WritePointer(m_ProcessHead, m_Machine,
  1940. m_KdpSearchEndPageFrame,
  1941. (Offset + Length - 1) >>
  1942. m_Machine->m_PageShift)) != S_OK)
  1943. {
  1944. return Status;
  1945. }
  1946. Ul = 0;
  1947. if ((Status = WriteAllVirtual(m_ProcessHead,
  1948. m_KdpSearchPageHitIndex,
  1949. &Ul, sizeof(Ul))) != S_OK ||
  1950. (Status = WriteAllVirtual(m_ProcessHead,
  1951. m_KdpSearchPageHits,
  1952. &Ul, sizeof(Ul))) != S_OK ||
  1953. (Status = WriteAllVirtual(m_ProcessHead,
  1954. m_KdpSearchPageHitOffsets,
  1955. &Ul, sizeof(Ul))) != S_OK)
  1956. {
  1957. return Status;
  1958. }
  1959. Ul = (Flags & PTR_SEARCH_PHYS_PTE) ? 1 : 0;
  1960. if ((Status = WriteAllVirtual(m_ProcessHead,
  1961. m_KdpSearchPfnValue,
  1962. &Ul, sizeof(Ul))) != S_OK)
  1963. {
  1964. return Status;
  1965. }
  1966. Ul = 1;
  1967. if ((Status = WriteAllVirtual(m_ProcessHead,
  1968. m_KdpSearchInProgress,
  1969. &Ul, sizeof(Ul))) != S_OK)
  1970. {
  1971. goto Exit;
  1972. }
  1973. // The kernel check-low-memory code checks the variables
  1974. // set above and automatically changes its behavior to
  1975. // the given search rather than the standard low-memory check.
  1976. if (FAILED(Status = CheckLowMemory()))
  1977. {
  1978. goto Exit;
  1979. }
  1980. ULONG Hits;
  1981. ULONG i;
  1982. if ((Status = ReadAllVirtual(m_ProcessHead,
  1983. m_KdpSearchPageHitIndex,
  1984. &Hits, sizeof(Hits))) != S_OK)
  1985. {
  1986. goto Exit;
  1987. }
  1988. if (MatchOffsetsCount)
  1989. {
  1990. *MatchOffsetsCount = Hits;
  1991. }
  1992. if (Hits > MatchOffsetsSize)
  1993. {
  1994. Hits = MatchOffsetsSize;
  1995. Status = S_FALSE;
  1996. }
  1997. for (i = 0; i < Hits; i++)
  1998. {
  1999. ULONG64 Pfn;
  2000. ULONG Offs;
  2001. HRESULT ReadStatus;
  2002. Pfn = 0;
  2003. if ((ReadStatus = ReadAllVirtual
  2004. (m_ProcessHead, m_KdpSearchPageHits +
  2005. i * m_TypeInfo.SizePageFrameNumber,
  2006. &Pfn,
  2007. m_TypeInfo.SizePageFrameNumber)) != S_OK ||
  2008. (ReadStatus = ReadAllVirtual
  2009. (m_ProcessHead,
  2010. m_KdpSearchPageHitOffsets + i * sizeof(ULONG),
  2011. &Offs, sizeof(Offs))) != S_OK)
  2012. {
  2013. Status = ReadStatus;
  2014. goto Exit;
  2015. }
  2016. MatchOffsets[i] = (Pfn << m_Machine->m_PageShift) +
  2017. (Offs & ((1 << m_Machine->m_PageShift) - 1));
  2018. }
  2019. Exit:
  2020. Ul = 0;
  2021. // Can't do much on failures.
  2022. WriteAllVirtual(m_ProcessHead,
  2023. m_KdpSearchPfnValue, &Ul, sizeof(Ul));
  2024. WriteAllVirtual(m_ProcessHead,
  2025. m_KdpSearchInProgress, &Ul, sizeof(Ul));
  2026. return Status;
  2027. }
  2028. HRESULT
  2029. ConnLiveKernelTargetInfo::ReadPhysicalUncached(
  2030. THIS_
  2031. IN ULONG64 Offset,
  2032. OUT PVOID Buffer,
  2033. IN ULONG BufferSize,
  2034. IN ULONG Flags,
  2035. OUT PULONG BytesRead
  2036. )
  2037. {
  2038. DBGKD_MANIPULATE_STATE64 m;
  2039. PDBGKD_MANIPULATE_STATE64 Reply;
  2040. PDBGKD_READ_MEMORY64 a;
  2041. NTSTATUS st;
  2042. ULONG rc;
  2043. ULONG cb, cb2;
  2044. ULONG OrigBufferSize = BufferSize;
  2045. cb2 = 0;
  2046. if (ARGUMENT_PRESENT(BytesRead))
  2047. {
  2048. *BytesRead = 0;
  2049. }
  2050. readmore:
  2051. cb = BufferSize;
  2052. if (cb > MAX_MANIP_TRANSFER)
  2053. {
  2054. cb = MAX_MANIP_TRANSFER;
  2055. }
  2056. //
  2057. // Format state manipulate message
  2058. //
  2059. m.ApiNumber = DbgKdReadPhysicalMemoryApi;
  2060. m.ReturnStatus = STATUS_PENDING;
  2061. a = &m.u.ReadMemory;
  2062. a->TargetBaseAddress = Offset + cb2;
  2063. a->TransferCount = cb;
  2064. // The ActualBytes fields have been overloaded to
  2065. // allow passing in flags for the request. Previous
  2066. // debuggers passed zero so that should always be
  2067. // the default.
  2068. a->ActualBytesRead = Flags;
  2069. //
  2070. // Send the message and then wait for reply
  2071. //
  2072. do
  2073. {
  2074. m_Transport->WritePacket(&m, sizeof(m),
  2075. PACKET_TYPE_KD_STATE_MANIPULATE,
  2076. NULL, 0);
  2077. rc = m_Transport->
  2078. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  2079. } while (rc != DBGKD_WAIT_PACKET ||
  2080. Reply->ApiNumber != DbgKdReadPhysicalMemoryApi);
  2081. st = Reply->ReturnStatus;
  2082. a = &Reply->u.ReadMemory;
  2083. DBG_ASSERT(a->ActualBytesRead <= cb);
  2084. //
  2085. // Return actual bytes read, and then transfer the bytes
  2086. //
  2087. if (ARGUMENT_PRESENT(BytesRead))
  2088. {
  2089. *BytesRead += a->ActualBytesRead;
  2090. }
  2091. //
  2092. // Since read response data follows message, Reply+1 should point
  2093. // at the data
  2094. //
  2095. if (NT_SUCCESS(st))
  2096. {
  2097. memcpy((PCHAR)((ULONG_PTR)Buffer + cb2), Reply + 1,
  2098. (int)a->ActualBytesRead);
  2099. BufferSize -= a->ActualBytesRead;
  2100. cb2 += a->ActualBytesRead;
  2101. if (BufferSize)
  2102. {
  2103. goto readmore;
  2104. }
  2105. }
  2106. KdOut("KdReadPhysical(%s, %x) returns %08lx, %x\n",
  2107. FormatAddr64(Offset), OrigBufferSize, st, cb2);
  2108. return CONV_NT_STATUS(st);
  2109. }
  2110. HRESULT
  2111. ConnLiveKernelTargetInfo::WritePhysicalUncached(
  2112. THIS_
  2113. IN ULONG64 Offset,
  2114. IN PVOID Buffer,
  2115. IN ULONG BufferSize,
  2116. IN ULONG Flags,
  2117. OUT PULONG BytesWritten
  2118. )
  2119. {
  2120. DBGKD_MANIPULATE_STATE64 m;
  2121. PDBGKD_MANIPULATE_STATE64 Reply;
  2122. PDBGKD_WRITE_MEMORY64 a;
  2123. NTSTATUS st;
  2124. ULONG rc;
  2125. ULONG cb, cb2;
  2126. ULONG OrigBufferSize = BufferSize;
  2127. InvalidateMemoryCaches(TRUE);
  2128. cb2 = 0;
  2129. if (ARGUMENT_PRESENT(BytesWritten))
  2130. {
  2131. *BytesWritten = 0;
  2132. }
  2133. writemore:
  2134. cb = BufferSize;
  2135. if (cb > MAX_MANIP_TRANSFER)
  2136. {
  2137. cb = MAX_MANIP_TRANSFER;
  2138. }
  2139. //
  2140. // Format state manipulate message
  2141. //
  2142. m.ApiNumber = DbgKdWritePhysicalMemoryApi;
  2143. m.ReturnStatus = STATUS_PENDING;
  2144. a = &m.u.WriteMemory;
  2145. a->TargetBaseAddress = Offset + cb2;
  2146. a->TransferCount = cb;
  2147. // The ActualBytes fields have been overloaded to
  2148. // allow passing in flags for the request. Previous
  2149. // debuggers passed zero so that should always be
  2150. // the default.
  2151. a->ActualBytesWritten = Flags;
  2152. //
  2153. // Send the message and data to write and then wait for reply
  2154. //
  2155. do
  2156. {
  2157. m_Transport->WritePacket(&m, sizeof(m),
  2158. PACKET_TYPE_KD_STATE_MANIPULATE,
  2159. (PVOID)((ULONG_PTR)Buffer + cb2),
  2160. (USHORT)cb);
  2161. rc = m_Transport->
  2162. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  2163. } while (rc != DBGKD_WAIT_PACKET ||
  2164. Reply->ApiNumber != DbgKdWritePhysicalMemoryApi);
  2165. st = Reply->ReturnStatus;
  2166. a = &Reply->u.WriteMemory;
  2167. DBG_ASSERT(a->ActualBytesWritten <= cb);
  2168. //
  2169. // Return actual bytes written
  2170. //
  2171. if (ARGUMENT_PRESENT(BytesWritten))
  2172. {
  2173. *BytesWritten += a->ActualBytesWritten;
  2174. }
  2175. if (NT_SUCCESS(st))
  2176. {
  2177. BufferSize -= a->ActualBytesWritten;
  2178. cb2 += a->ActualBytesWritten;
  2179. if (BufferSize)
  2180. {
  2181. goto writemore;
  2182. }
  2183. }
  2184. KdOut("KdWritePhysical(%s, %x) returns %08lx, %x\n",
  2185. FormatAddr64(Offset), OrigBufferSize, st, cb2);
  2186. if (NT_SUCCESS(st))
  2187. {
  2188. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_PHYSICAL);
  2189. }
  2190. return CONV_NT_STATUS(st);
  2191. }
  2192. HRESULT
  2193. ConnLiveKernelTargetInfo::ReadControl(
  2194. THIS_
  2195. IN ULONG Processor,
  2196. IN ULONG64 Offset,
  2197. OUT PVOID Buffer,
  2198. IN ULONG BufferSize,
  2199. OUT PULONG BytesRead
  2200. )
  2201. {
  2202. DBGKD_MANIPULATE_STATE64 m;
  2203. PDBGKD_MANIPULATE_STATE64 Reply;
  2204. PDBGKD_READ_MEMORY64 a = &m.u.ReadMemory;
  2205. NTSTATUS st = STATUS_UNSUCCESSFUL;
  2206. ULONG rc;
  2207. if (BufferSize > MAX_MANIP_TRANSFER)
  2208. {
  2209. return E_INVALIDARG;
  2210. }
  2211. //
  2212. // Format state manipulate message
  2213. //
  2214. m.ApiNumber = DbgKdReadControlSpaceApi;
  2215. m.ReturnStatus = STATUS_PENDING;
  2216. m.Processor = (SHORT)Processor;
  2217. a->TargetBaseAddress = Offset;
  2218. a->TransferCount = BufferSize;
  2219. a->ActualBytesRead = 0L;
  2220. //
  2221. // Send the message and then wait for reply
  2222. //
  2223. do
  2224. {
  2225. m_Transport->WritePacket(&m, sizeof(m),
  2226. PACKET_TYPE_KD_STATE_MANIPULATE,
  2227. NULL, 0);
  2228. rc = m_Transport->
  2229. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  2230. } while (rc != DBGKD_WAIT_PACKET ||
  2231. Reply->ApiNumber != DbgKdReadControlSpaceApi);
  2232. st = Reply->ReturnStatus;
  2233. //
  2234. // Reset message address to reply.
  2235. //
  2236. a = &Reply->u.ReadMemory;
  2237. DBG_ASSERT(a->ActualBytesRead <= BufferSize);
  2238. //
  2239. // Return actual bytes read, and then transfer the bytes
  2240. //
  2241. if (ARGUMENT_PRESENT(BytesRead))
  2242. {
  2243. *BytesRead = a->ActualBytesRead;
  2244. }
  2245. //
  2246. // Since read response data follows message, Reply+1 should point
  2247. // at the data
  2248. //
  2249. memcpy(Buffer, Reply + 1, (int)a->ActualBytesRead);
  2250. KdOut("DbgKdReadControlSpace returns %08lx\n", st);
  2251. return CONV_NT_STATUS(st);
  2252. }
  2253. HRESULT
  2254. ConnLiveKernelTargetInfo::WriteControl(
  2255. THIS_
  2256. IN ULONG Processor,
  2257. IN ULONG64 Offset,
  2258. IN PVOID Buffer,
  2259. IN ULONG BufferSize,
  2260. OUT PULONG BytesWritten
  2261. )
  2262. {
  2263. DBGKD_MANIPULATE_STATE64 m;
  2264. PDBGKD_MANIPULATE_STATE64 Reply;
  2265. PDBGKD_WRITE_MEMORY64 a = &m.u.WriteMemory;
  2266. NTSTATUS st;
  2267. ULONG rc;
  2268. if (BufferSize > MAX_MANIP_TRANSFER)
  2269. {
  2270. return E_INVALIDARG;
  2271. }
  2272. //
  2273. // Format state manipulate message
  2274. //
  2275. m.ApiNumber = DbgKdWriteControlSpaceApi;
  2276. m.ReturnStatus = STATUS_PENDING;
  2277. m.Processor = (USHORT)Processor;
  2278. a->TargetBaseAddress = Offset;
  2279. a->TransferCount = BufferSize;
  2280. a->ActualBytesWritten = 0L;
  2281. //
  2282. // Send the message and data to write and then wait for reply
  2283. //
  2284. do
  2285. {
  2286. m_Transport->WritePacket(&m, sizeof(m),
  2287. PACKET_TYPE_KD_STATE_MANIPULATE,
  2288. Buffer, (USHORT)BufferSize);
  2289. rc = m_Transport->
  2290. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  2291. } while (rc != DBGKD_WAIT_PACKET ||
  2292. Reply->ApiNumber != DbgKdWriteControlSpaceApi);
  2293. st = Reply->ReturnStatus;
  2294. a = &Reply->u.WriteMemory;
  2295. DBG_ASSERT(a->ActualBytesWritten <= BufferSize);
  2296. //
  2297. // Return actual bytes written
  2298. //
  2299. *BytesWritten = a->ActualBytesWritten;
  2300. KdOut("DbgWriteControlSpace returns %08lx\n", st);
  2301. if (NT_SUCCESS(st))
  2302. {
  2303. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_CONTROL);
  2304. }
  2305. return CONV_NT_STATUS(st);
  2306. }
  2307. HRESULT
  2308. ConnLiveKernelTargetInfo::ReadIo(
  2309. THIS_
  2310. IN ULONG InterfaceType,
  2311. IN ULONG BusNumber,
  2312. IN ULONG AddressSpace,
  2313. IN ULONG64 Offset,
  2314. OUT PVOID Buffer,
  2315. IN ULONG BufferSize,
  2316. OUT PULONG BytesRead
  2317. )
  2318. {
  2319. DBGKD_MANIPULATE_STATE64 m;
  2320. PDBGKD_MANIPULATE_STATE64 Reply;
  2321. NTSTATUS st;
  2322. ULONG rc;
  2323. ULONG DataValue;
  2324. switch(BufferSize)
  2325. {
  2326. case 1:
  2327. case 2:
  2328. case 4:
  2329. break;
  2330. default:
  2331. return E_INVALIDARG;
  2332. }
  2333. if (!(AddressSpace == 0 || AddressSpace == 1))
  2334. {
  2335. return E_INVALIDARG;
  2336. }
  2337. // Convert trivially extended I/O requests down into simple
  2338. // requests as not all platform support extended requests.
  2339. if (InterfaceType == Isa && BusNumber == 0 && AddressSpace == 1)
  2340. {
  2341. PDBGKD_READ_WRITE_IO64 a = &m.u.ReadWriteIo;
  2342. //
  2343. // Format state manipulate message
  2344. //
  2345. m.ApiNumber = DbgKdReadIoSpaceApi;
  2346. m.ReturnStatus = STATUS_PENDING;
  2347. a->DataSize = BufferSize;
  2348. a->IoAddress = Offset;
  2349. //
  2350. // Send the message and then wait for reply
  2351. //
  2352. do
  2353. {
  2354. m_Transport->WritePacket(&m, sizeof(m),
  2355. PACKET_TYPE_KD_STATE_MANIPULATE,
  2356. NULL, 0);
  2357. rc = m_Transport->
  2358. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  2359. } while (rc != DBGKD_WAIT_PACKET ||
  2360. Reply->ApiNumber != DbgKdReadIoSpaceApi);
  2361. st = Reply->ReturnStatus;
  2362. DataValue = Reply->u.ReadWriteIo.DataValue;
  2363. KdOut("DbgKdReadIoSpace returns %08lx\n", st);
  2364. }
  2365. else
  2366. {
  2367. PDBGKD_READ_WRITE_IO_EXTENDED64 a = &m.u.ReadWriteIoExtended;
  2368. //
  2369. // Format state manipulate message
  2370. //
  2371. m.ApiNumber = DbgKdReadIoSpaceExtendedApi;
  2372. m.ReturnStatus = STATUS_PENDING;
  2373. a->DataSize = BufferSize;
  2374. a->IoAddress = Offset;
  2375. a->InterfaceType = InterfaceType;
  2376. a->BusNumber = BusNumber;
  2377. a->AddressSpace = AddressSpace;
  2378. //
  2379. // Send the message and then wait for reply
  2380. //
  2381. do
  2382. {
  2383. m_Transport->WritePacket(&m, sizeof(m),
  2384. PACKET_TYPE_KD_STATE_MANIPULATE,
  2385. NULL, 0);
  2386. rc = m_Transport->
  2387. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  2388. } while (rc != DBGKD_WAIT_PACKET ||
  2389. Reply->ApiNumber != DbgKdReadIoSpaceExtendedApi);
  2390. st = Reply->ReturnStatus;
  2391. DataValue = Reply->u.ReadWriteIoExtended.DataValue;
  2392. KdOut("DbgKdReadIoSpaceExtended returns %08lx\n", st);
  2393. }
  2394. if (NT_SUCCESS(st))
  2395. {
  2396. switch(BufferSize)
  2397. {
  2398. case 1:
  2399. *(PUCHAR)Buffer = (UCHAR)DataValue;
  2400. break;
  2401. case 2:
  2402. *(PUSHORT)Buffer = (USHORT)DataValue;
  2403. break;
  2404. case 4:
  2405. *(PULONG)Buffer = DataValue;
  2406. break;
  2407. }
  2408. // I/O access currently can't successfully return anything
  2409. // other than the requested size.
  2410. if (BytesRead != NULL)
  2411. {
  2412. *BytesRead = BufferSize;
  2413. }
  2414. return S_OK;
  2415. }
  2416. else
  2417. {
  2418. return HRESULT_FROM_NT(st);
  2419. }
  2420. }
  2421. HRESULT
  2422. ConnLiveKernelTargetInfo::WriteIo(
  2423. THIS_
  2424. IN ULONG InterfaceType,
  2425. IN ULONG BusNumber,
  2426. IN ULONG AddressSpace,
  2427. IN ULONG64 Offset,
  2428. IN PVOID Buffer,
  2429. IN ULONG BufferSize,
  2430. OUT PULONG BytesWritten
  2431. )
  2432. {
  2433. DBGKD_MANIPULATE_STATE64 m;
  2434. PDBGKD_MANIPULATE_STATE64 Reply;
  2435. NTSTATUS st;
  2436. ULONG rc;
  2437. ULONG DataValue;
  2438. switch(BufferSize)
  2439. {
  2440. case 1:
  2441. DataValue = *(PUCHAR)Buffer;
  2442. break;
  2443. case 2:
  2444. DataValue = *(PUSHORT)Buffer;
  2445. break;
  2446. case 4:
  2447. DataValue = *(PULONG)Buffer;
  2448. break;
  2449. default:
  2450. return E_INVALIDARG;
  2451. }
  2452. if (!(AddressSpace == 0 || AddressSpace == 1))
  2453. {
  2454. return E_INVALIDARG;
  2455. }
  2456. // Convert trivially extended I/O requests down into simple
  2457. // requests as not all platform support extended requests.
  2458. if (InterfaceType == Isa && BusNumber == 0 && AddressSpace == 1)
  2459. {
  2460. PDBGKD_READ_WRITE_IO64 a = &m.u.ReadWriteIo;
  2461. //
  2462. // Format state manipulate message
  2463. //
  2464. m.ApiNumber = DbgKdWriteIoSpaceApi;
  2465. m.ReturnStatus = STATUS_PENDING;
  2466. a->DataSize = BufferSize;
  2467. a->IoAddress = Offset;
  2468. a->DataValue = DataValue;
  2469. //
  2470. // Send the message and then wait for reply
  2471. //
  2472. do
  2473. {
  2474. m_Transport->WritePacket(&m, sizeof(m),
  2475. PACKET_TYPE_KD_STATE_MANIPULATE,
  2476. NULL, 0);
  2477. rc = m_Transport->
  2478. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  2479. } while (rc != DBGKD_WAIT_PACKET ||
  2480. Reply->ApiNumber != DbgKdWriteIoSpaceApi);
  2481. st = Reply->ReturnStatus;
  2482. KdOut("DbgKdWriteIoSpace returns %08lx\n", st);
  2483. }
  2484. else
  2485. {
  2486. PDBGKD_READ_WRITE_IO_EXTENDED64 a = &m.u.ReadWriteIoExtended;
  2487. //
  2488. // Format state manipulate message
  2489. //
  2490. m.ApiNumber = DbgKdWriteIoSpaceExtendedApi;
  2491. m.ReturnStatus = STATUS_PENDING;
  2492. a->DataSize = BufferSize;
  2493. a->IoAddress = Offset;
  2494. a->DataValue = DataValue;
  2495. a->InterfaceType = InterfaceType;
  2496. a->BusNumber = BusNumber;
  2497. a->AddressSpace = AddressSpace;
  2498. //
  2499. // Send the message and then wait for reply
  2500. //
  2501. do
  2502. {
  2503. m_Transport->WritePacket(&m, sizeof(m),
  2504. PACKET_TYPE_KD_STATE_MANIPULATE,
  2505. NULL, 0);
  2506. rc = m_Transport->
  2507. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  2508. } while (rc != DBGKD_WAIT_PACKET ||
  2509. Reply->ApiNumber != DbgKdWriteIoSpaceExtendedApi);
  2510. st = Reply->ReturnStatus;
  2511. KdOut("DbgKdWriteIoSpaceExtended returns %08lx\n", st);
  2512. }
  2513. if (NT_SUCCESS(st))
  2514. {
  2515. // I/O access currently can't successfully return anything
  2516. // other than the requested size.
  2517. if (BytesWritten != NULL)
  2518. {
  2519. *BytesWritten = BufferSize;
  2520. }
  2521. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_IO);
  2522. return S_OK;
  2523. }
  2524. else
  2525. {
  2526. return HRESULT_FROM_NT(st);
  2527. }
  2528. }
  2529. HRESULT
  2530. ConnLiveKernelTargetInfo::ReadMsr(
  2531. THIS_
  2532. IN ULONG Msr,
  2533. OUT PULONG64 Value
  2534. )
  2535. {
  2536. DBGKD_MANIPULATE_STATE64 m;
  2537. PDBGKD_MANIPULATE_STATE64 Reply;
  2538. PDBGKD_READ_WRITE_MSR a = &m.u.ReadWriteMsr;
  2539. LARGE_INTEGER li;
  2540. NTSTATUS st;
  2541. ULONG rc;
  2542. //
  2543. // Format state manipulate message
  2544. //
  2545. m.ApiNumber = DbgKdReadMachineSpecificRegister;
  2546. m.ReturnStatus = STATUS_PENDING;
  2547. a->Msr = Msr;
  2548. //
  2549. // Send the message and then wait for reply
  2550. //
  2551. do
  2552. {
  2553. m_Transport->WritePacket(&m, sizeof(m),
  2554. PACKET_TYPE_KD_STATE_MANIPULATE,
  2555. NULL, 0);
  2556. rc = m_Transport->
  2557. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  2558. } while (rc != DBGKD_WAIT_PACKET ||
  2559. Reply->ApiNumber != DbgKdReadMachineSpecificRegister);
  2560. st = Reply->ReturnStatus;
  2561. a = &Reply->u.ReadWriteMsr;
  2562. li.LowPart = a->DataValueLow;
  2563. li.HighPart = a->DataValueHigh;
  2564. *Value = li.QuadPart;
  2565. KdOut("DbgKdReadMsr returns %08lx\n", st);
  2566. return CONV_NT_STATUS(st);
  2567. }
  2568. HRESULT
  2569. ConnLiveKernelTargetInfo::WriteMsr(
  2570. THIS_
  2571. IN ULONG Msr,
  2572. IN ULONG64 Value
  2573. )
  2574. {
  2575. DBGKD_MANIPULATE_STATE64 m;
  2576. PDBGKD_MANIPULATE_STATE64 Reply;
  2577. PDBGKD_READ_WRITE_MSR a = &m.u.ReadWriteMsr;
  2578. LARGE_INTEGER li;
  2579. NTSTATUS st;
  2580. ULONG rc;
  2581. li.QuadPart = Value;
  2582. //
  2583. // Format state manipulate message
  2584. //
  2585. m.ApiNumber = DbgKdWriteMachineSpecificRegister;
  2586. m.ReturnStatus = STATUS_PENDING;
  2587. // Quiet PREfix warnings.
  2588. m.Processor = 0;
  2589. m.ProcessorLevel = 0;
  2590. a->Msr = Msr;
  2591. a->DataValueLow = li.LowPart;
  2592. a->DataValueHigh = li.HighPart;
  2593. //
  2594. // Send the message and then wait for reply
  2595. //
  2596. do
  2597. {
  2598. m_Transport->WritePacket(&m, sizeof(m),
  2599. PACKET_TYPE_KD_STATE_MANIPULATE,
  2600. NULL, 0);
  2601. rc = m_Transport->
  2602. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  2603. } while (rc != DBGKD_WAIT_PACKET ||
  2604. Reply->ApiNumber != DbgKdWriteMachineSpecificRegister);
  2605. st = Reply->ReturnStatus;
  2606. KdOut("DbgKdWriteMsr returns %08lx\n", st);
  2607. if (NT_SUCCESS(st))
  2608. {
  2609. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_MSR);
  2610. }
  2611. return CONV_NT_STATUS(st);
  2612. }
  2613. HRESULT
  2614. ConnLiveKernelTargetInfo::ReadBusData(
  2615. THIS_
  2616. IN ULONG BusDataType,
  2617. IN ULONG BusNumber,
  2618. IN ULONG SlotNumber,
  2619. IN ULONG Offset,
  2620. OUT PVOID Buffer,
  2621. IN ULONG BufferSize,
  2622. OUT PULONG BytesRead
  2623. )
  2624. {
  2625. DBGKD_MANIPULATE_STATE64 m;
  2626. PDBGKD_MANIPULATE_STATE64 Reply;
  2627. PDBGKD_GET_SET_BUS_DATA a = &m.u.GetSetBusData;
  2628. NTSTATUS st;
  2629. ULONG rc;
  2630. //
  2631. // Check the buffer size.
  2632. //
  2633. if (BufferSize > MAX_MANIP_TRANSFER)
  2634. {
  2635. return E_INVALIDARG;
  2636. }
  2637. //
  2638. // Format state manipulate message
  2639. //
  2640. m.ApiNumber = DbgKdGetBusDataApi;
  2641. m.ReturnStatus = STATUS_PENDING;
  2642. a->BusDataType = BusDataType;
  2643. a->BusNumber = BusNumber;
  2644. a->SlotNumber = SlotNumber;
  2645. a->Offset = Offset;
  2646. a->Length = BufferSize;
  2647. //
  2648. // Send the message and then wait for reply
  2649. //
  2650. do
  2651. {
  2652. m_Transport->WritePacket(&m, sizeof(m),
  2653. PACKET_TYPE_KD_STATE_MANIPULATE,
  2654. NULL, 0);
  2655. rc = m_Transport->
  2656. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  2657. } while (rc != DBGKD_WAIT_PACKET ||
  2658. Reply->ApiNumber != DbgKdGetBusDataApi);
  2659. st = Reply->ReturnStatus;
  2660. if (NT_SUCCESS(st))
  2661. {
  2662. a = &Reply->u.GetSetBusData;
  2663. memcpy(Buffer, Reply + 1, a->Length);
  2664. if (BytesRead != NULL)
  2665. {
  2666. *BytesRead = a->Length;
  2667. }
  2668. }
  2669. KdOut("DbgKdGetBusData returns %08lx\n", st);
  2670. return CONV_NT_STATUS(st);
  2671. }
  2672. HRESULT
  2673. ConnLiveKernelTargetInfo::WriteBusData(
  2674. THIS_
  2675. IN ULONG BusDataType,
  2676. IN ULONG BusNumber,
  2677. IN ULONG SlotNumber,
  2678. IN ULONG Offset,
  2679. IN PVOID Buffer,
  2680. IN ULONG BufferSize,
  2681. OUT PULONG BytesWritten
  2682. )
  2683. {
  2684. DBGKD_MANIPULATE_STATE64 m;
  2685. PDBGKD_MANIPULATE_STATE64 Reply;
  2686. PDBGKD_GET_SET_BUS_DATA a = &m.u.GetSetBusData;
  2687. NTSTATUS st;
  2688. ULONG rc;
  2689. //
  2690. // Check the buffer size.
  2691. //
  2692. if (BufferSize > MAX_MANIP_TRANSFER)
  2693. {
  2694. return E_INVALIDARG;
  2695. }
  2696. //
  2697. // Format state manipulate message
  2698. //
  2699. m.ApiNumber = DbgKdSetBusDataApi;
  2700. m.ReturnStatus = STATUS_PENDING;
  2701. a->BusDataType = BusDataType;
  2702. a->BusNumber = BusNumber;
  2703. a->SlotNumber = SlotNumber;
  2704. a->Offset = Offset;
  2705. a->Length = BufferSize;
  2706. //
  2707. // Send the message and then wait for reply
  2708. //
  2709. do
  2710. {
  2711. m_Transport->WritePacket(&m, sizeof(m),
  2712. PACKET_TYPE_KD_STATE_MANIPULATE,
  2713. Buffer, (USHORT)BufferSize);
  2714. rc = m_Transport->
  2715. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  2716. } while (rc != DBGKD_WAIT_PACKET ||
  2717. Reply->ApiNumber != DbgKdSetBusDataApi);
  2718. st = Reply->ReturnStatus;
  2719. if (NT_SUCCESS(st) && BytesWritten != NULL)
  2720. {
  2721. a = &Reply->u.GetSetBusData;
  2722. *BytesWritten = a->Length;
  2723. }
  2724. KdOut("DbgKdSetBusData returns %08lx\n", st);
  2725. if (NT_SUCCESS(st))
  2726. {
  2727. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_BUS_DATA);
  2728. }
  2729. return CONV_NT_STATUS(st);
  2730. }
  2731. HRESULT
  2732. ConnLiveKernelTargetInfo::CheckLowMemory(void)
  2733. {
  2734. DBGKD_MANIPULATE_STATE64 m;
  2735. PDBGKD_MANIPULATE_STATE64 Reply;
  2736. ULONG rc;
  2737. //
  2738. // Format state manipulate message
  2739. //
  2740. ZeroMemory(&m, sizeof(m));
  2741. m.ApiNumber = DbgKdCheckLowMemoryApi;
  2742. m.ReturnStatus = STATUS_PENDING;
  2743. //
  2744. // We wait for an answer from the kernel side.
  2745. //
  2746. do
  2747. {
  2748. m_Transport->WritePacket(&m, sizeof(m),
  2749. PACKET_TYPE_KD_STATE_MANIPULATE,
  2750. NULL, 0);
  2751. rc = m_Transport->
  2752. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  2753. } while (rc != DBGKD_WAIT_PACKET);
  2754. if (Reply->ReturnStatus != STATUS_SUCCESS)
  2755. {
  2756. ErrOut("Corrupted page with pfn %x\n", Reply->ReturnStatus);
  2757. }
  2758. KdOut("DbgKdCheckLowMemory 0x00000000\n");
  2759. return S_OK;
  2760. }
  2761. NTSTATUS
  2762. ConnLiveKernelTargetInfo::KdFillMemory(IN ULONG Flags,
  2763. IN ULONG64 Start,
  2764. IN ULONG Size,
  2765. IN PVOID Pattern,
  2766. IN ULONG PatternSize,
  2767. OUT PULONG Filled)
  2768. {
  2769. ULONG NtStatus;
  2770. DBGKD_MANIPULATE_STATE64 Manip;
  2771. PDBGKD_MANIPULATE_STATE64 Reply;
  2772. NTSTATUS Status = STATUS_SUCCESS;
  2773. DBG_ASSERT(m_KdMaxManipulate > DbgKdFillMemoryApi &&
  2774. (Flags & 0xffff0000) == 0 &&
  2775. PatternSize <= MAX_MANIP_TRANSFER);
  2776. // Invalidate any cached memory.
  2777. if (Flags & DBGKD_FILL_MEMORY_VIRTUAL)
  2778. {
  2779. InvalidateMemoryCaches(TRUE);
  2780. }
  2781. else if (Flags & DBGKD_FILL_MEMORY_PHYSICAL)
  2782. {
  2783. m_PhysicalCache.Remove(Start, Size);
  2784. }
  2785. //
  2786. // Initialize state manipulate message to fill memory.
  2787. //
  2788. Manip.ApiNumber = DbgKdFillMemoryApi;
  2789. Manip.u.FillMemory.Address = Start;
  2790. Manip.u.FillMemory.Length = Size;
  2791. Manip.u.FillMemory.Flags = (USHORT)Flags;
  2792. Manip.u.FillMemory.PatternLength = (USHORT)PatternSize;
  2793. //
  2794. // Send the message and data to the target system and wait
  2795. // for a reply.
  2796. //
  2797. ULONG Recv;
  2798. do
  2799. {
  2800. m_Transport->WritePacket(&Manip, sizeof(Manip),
  2801. PACKET_TYPE_KD_STATE_MANIPULATE,
  2802. Pattern, (USHORT)PatternSize);
  2803. Recv = m_Transport->
  2804. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  2805. }
  2806. while ((Recv != DBGKD_WAIT_PACKET) ||
  2807. (Reply->ApiNumber != DbgKdFillMemoryApi));
  2808. NtStatus = Reply->ReturnStatus;
  2809. *Filled = Reply->u.FillMemory.Length;
  2810. KdOut("DbgKdFillMemory returns %08lx\n", NtStatus);
  2811. return NtStatus;
  2812. }
  2813. HRESULT
  2814. ConnLiveKernelTargetInfo::FillVirtual(
  2815. THIS_
  2816. IN ProcessInfo* Process,
  2817. IN ULONG64 Start,
  2818. IN ULONG Size,
  2819. IN PVOID Pattern,
  2820. IN ULONG PatternSize,
  2821. OUT PULONG Filled
  2822. )
  2823. {
  2824. HRESULT Status;
  2825. if (m_KdMaxManipulate <= DbgKdFillMemoryApi ||
  2826. PatternSize > MAX_MANIP_TRANSFER)
  2827. {
  2828. Status = TargetInfo::FillVirtual(Process, Start, Size, Pattern,
  2829. PatternSize, Filled);
  2830. }
  2831. else
  2832. {
  2833. NTSTATUS NtStatus =
  2834. KdFillMemory(DBGKD_FILL_MEMORY_VIRTUAL, Start, Size,
  2835. Pattern, PatternSize, Filled);
  2836. Status = CONV_NT_STATUS(NtStatus);
  2837. }
  2838. return Status;
  2839. }
  2840. HRESULT
  2841. ConnLiveKernelTargetInfo::FillPhysical(
  2842. THIS_
  2843. IN ULONG64 Start,
  2844. IN ULONG Size,
  2845. IN PVOID Pattern,
  2846. IN ULONG PatternSize,
  2847. OUT PULONG Filled
  2848. )
  2849. {
  2850. HRESULT Status;
  2851. if (m_KdMaxManipulate <= DbgKdFillMemoryApi ||
  2852. PatternSize > MAX_MANIP_TRANSFER)
  2853. {
  2854. Status = TargetInfo::FillPhysical(Start, Size, Pattern,
  2855. PatternSize, Filled);
  2856. }
  2857. else
  2858. {
  2859. NTSTATUS NtStatus =
  2860. KdFillMemory(DBGKD_FILL_MEMORY_PHYSICAL, Start, Size,
  2861. Pattern, PatternSize, Filled);
  2862. Status = CONV_NT_STATUS(NtStatus);
  2863. }
  2864. return Status;
  2865. }
  2866. HRESULT
  2867. ConnLiveKernelTargetInfo::QueryAddressInformation(ProcessInfo* Process,
  2868. ULONG64 Address,
  2869. ULONG InSpace,
  2870. PULONG OutSpace,
  2871. PULONG OutFlags)
  2872. {
  2873. HRESULT Status;
  2874. if (m_KdMaxManipulate <= DbgKdQueryMemoryApi)
  2875. {
  2876. Status = TargetInfo::QueryAddressInformation(Process, Address, InSpace,
  2877. OutSpace, OutFlags);
  2878. }
  2879. else
  2880. {
  2881. DBGKD_MANIPULATE_STATE64 Manip;
  2882. PDBGKD_MANIPULATE_STATE64 Reply;
  2883. NTSTATUS NtStatus;
  2884. //
  2885. // Initialize state manipulate message to query memory.
  2886. //
  2887. Manip.ApiNumber = DbgKdQueryMemoryApi;
  2888. Manip.u.QueryMemory.Address = Address;
  2889. Manip.u.QueryMemory.Reserved = 0;
  2890. Manip.u.QueryMemory.AddressSpace = InSpace;
  2891. Manip.u.QueryMemory.Flags = 0;
  2892. //
  2893. // Send the message and data to the target system and wait
  2894. // for a reply.
  2895. //
  2896. ULONG Recv;
  2897. do
  2898. {
  2899. m_Transport->WritePacket(&Manip, sizeof(Manip),
  2900. PACKET_TYPE_KD_STATE_MANIPULATE,
  2901. NULL, 0);
  2902. Recv = m_Transport->
  2903. WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
  2904. }
  2905. while ((Recv != DBGKD_WAIT_PACKET) ||
  2906. (Reply->ApiNumber != DbgKdQueryMemoryApi));
  2907. NtStatus = Reply->ReturnStatus;
  2908. *OutSpace = Reply->u.QueryMemory.AddressSpace;
  2909. *OutFlags = Reply->u.QueryMemory.Flags;
  2910. KdOut("DbgKdQueryMemory returns %08lx\n", NtStatus);
  2911. Status = CONV_NT_STATUS(NtStatus);
  2912. }
  2913. return Status;
  2914. }
  2915. //----------------------------------------------------------------------------
  2916. //
  2917. // LocalLiveKernelTargetInfo data space methods.
  2918. //
  2919. //----------------------------------------------------------------------------
  2920. HRESULT
  2921. LocalLiveKernelTargetInfo::ReadVirtual(
  2922. THIS_
  2923. IN ProcessInfo* Process,
  2924. IN ULONG64 Offset,
  2925. OUT PVOID Buffer,
  2926. IN ULONG BufferSize,
  2927. OUT PULONG BytesRead
  2928. )
  2929. {
  2930. SYSDBG_VIRTUAL Cmd;
  2931. NTSTATUS Status = STATUS_SUCCESS;
  2932. //
  2933. // The kernel only allows operations up to
  2934. // KDP_MESSAGE_BUFFER_SIZE, so break things up
  2935. // into chunks if necessary.
  2936. //
  2937. *BytesRead = 0;
  2938. Cmd.Address = (PVOID)(ULONG_PTR)Offset;
  2939. Cmd.Buffer = Buffer;
  2940. while (BufferSize > 0)
  2941. {
  2942. ULONG ChunkDone;
  2943. if (BufferSize > PACKET_MAX_SIZE)
  2944. {
  2945. Cmd.Request = PACKET_MAX_SIZE;
  2946. }
  2947. else
  2948. {
  2949. Cmd.Request = BufferSize;
  2950. }
  2951. // The kernel stubs avoid faults so all memory
  2952. // must be paged in ahead of time. There's
  2953. // still the possibility that something could
  2954. // get paged out after this but the assumption is
  2955. // that the vulnerability is small and it's much
  2956. // better than implementing dual code paths in
  2957. // the kernel.
  2958. if (IsBadWritePtr(Cmd.Buffer, Cmd.Request))
  2959. {
  2960. Status = STATUS_INVALID_PARAMETER;
  2961. break;
  2962. }
  2963. ChunkDone = 0;
  2964. Status =
  2965. g_NtDllCalls.NtSystemDebugControl(SysDbgReadVirtual,
  2966. &Cmd, sizeof(Cmd),
  2967. NULL, 0,
  2968. &ChunkDone);
  2969. if (!NT_SUCCESS(Status) && Status != STATUS_UNSUCCESSFUL)
  2970. {
  2971. break;
  2972. }
  2973. if (ChunkDone == 0)
  2974. {
  2975. // If some data was processed consider it a success.
  2976. Status = *BytesRead > 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  2977. break;
  2978. }
  2979. Cmd.Address = (PVOID)((PUCHAR)Cmd.Address + ChunkDone);
  2980. Cmd.Buffer = (PVOID)((PUCHAR)Cmd.Buffer + ChunkDone);
  2981. BufferSize -= ChunkDone;
  2982. *BytesRead += ChunkDone;
  2983. }
  2984. return CONV_NT_STATUS(Status);
  2985. }
  2986. HRESULT
  2987. LocalLiveKernelTargetInfo::WriteVirtual(
  2988. THIS_
  2989. IN ProcessInfo* Process,
  2990. IN ULONG64 Offset,
  2991. IN PVOID Buffer,
  2992. IN ULONG BufferSize,
  2993. OUT PULONG BytesWritten
  2994. )
  2995. {
  2996. SYSDBG_VIRTUAL Cmd;
  2997. NTSTATUS Status = STATUS_SUCCESS;
  2998. //
  2999. // The kernel only allows operations up to
  3000. // KDP_MESSAGE_BUFFER_SIZE, so break things up
  3001. // into chunks if necessary.
  3002. //
  3003. *BytesWritten = 0;
  3004. Cmd.Address = (PVOID)(ULONG_PTR)Offset;
  3005. Cmd.Buffer = Buffer;
  3006. while (BufferSize > 0)
  3007. {
  3008. ULONG ChunkDone;
  3009. if (BufferSize > PACKET_MAX_SIZE)
  3010. {
  3011. Cmd.Request = PACKET_MAX_SIZE;
  3012. }
  3013. else
  3014. {
  3015. Cmd.Request = BufferSize;
  3016. }
  3017. // The kernel stubs avoid faults so all memory
  3018. // must be paged in ahead of time. There's
  3019. // still the possibility that something could
  3020. // get paged out after this but the assumption is
  3021. // that the vulnerability is small and it's much
  3022. // better than implementing dual code paths in
  3023. // the kernel.
  3024. if (IsBadReadPtr(Cmd.Buffer, Cmd.Request))
  3025. {
  3026. Status = STATUS_INVALID_PARAMETER;
  3027. break;
  3028. }
  3029. ChunkDone = 0;
  3030. Status =
  3031. g_NtDllCalls.NtSystemDebugControl(SysDbgWriteVirtual,
  3032. &Cmd, sizeof(Cmd),
  3033. NULL, 0,
  3034. &ChunkDone);
  3035. if (!NT_SUCCESS(Status) && Status != STATUS_UNSUCCESSFUL)
  3036. {
  3037. break;
  3038. }
  3039. if (ChunkDone == 0)
  3040. {
  3041. // If some data was processed consider it a success.
  3042. Status = *BytesWritten > 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  3043. break;
  3044. }
  3045. Cmd.Address = (PVOID)((PUCHAR)Cmd.Address + ChunkDone);
  3046. Cmd.Buffer = (PVOID)((PUCHAR)Cmd.Buffer + ChunkDone);
  3047. BufferSize -= ChunkDone;
  3048. *BytesWritten += ChunkDone;
  3049. }
  3050. if (NT_SUCCESS(Status))
  3051. {
  3052. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_VIRTUAL);
  3053. }
  3054. return CONV_NT_STATUS(Status);
  3055. }
  3056. HRESULT
  3057. LocalLiveKernelTargetInfo::ReadPhysical(
  3058. THIS_
  3059. IN ULONG64 Offset,
  3060. OUT PVOID Buffer,
  3061. IN ULONG BufferSize,
  3062. IN ULONG Flags,
  3063. OUT PULONG BytesRead
  3064. )
  3065. {
  3066. SYSDBG_PHYSICAL Cmd;
  3067. NTSTATUS Status = STATUS_SUCCESS;
  3068. if (Flags != PHYS_FLAG_DEFAULT)
  3069. {
  3070. return E_NOTIMPL;
  3071. }
  3072. //
  3073. // The kernel only allows operations up to
  3074. // KDP_MESSAGE_BUFFER_SIZE, so break things up
  3075. // into chunks if necessary.
  3076. //
  3077. *BytesRead = 0;
  3078. Cmd.Address.QuadPart = Offset;
  3079. Cmd.Buffer = Buffer;
  3080. while (BufferSize > 0)
  3081. {
  3082. ULONG ChunkDone;
  3083. if (BufferSize > PACKET_MAX_SIZE)
  3084. {
  3085. Cmd.Request = PACKET_MAX_SIZE;
  3086. }
  3087. else
  3088. {
  3089. Cmd.Request = BufferSize;
  3090. }
  3091. // The kernel stubs avoid faults so all memory
  3092. // must be paged in ahead of time. There's
  3093. // still the possibility that something could
  3094. // get paged out after this but the assumption is
  3095. // that the vulnerability is small and it's much
  3096. // better than implementing dual code paths in
  3097. // the kernel.
  3098. if (IsBadWritePtr(Cmd.Buffer, Cmd.Request))
  3099. {
  3100. Status = STATUS_INVALID_PARAMETER;
  3101. break;
  3102. }
  3103. ChunkDone = 0;
  3104. Status =
  3105. g_NtDllCalls.NtSystemDebugControl(SysDbgReadPhysical,
  3106. &Cmd, sizeof(Cmd),
  3107. NULL, 0,
  3108. &ChunkDone);
  3109. if (!NT_SUCCESS(Status) && Status != STATUS_UNSUCCESSFUL)
  3110. {
  3111. break;
  3112. }
  3113. if (ChunkDone == 0)
  3114. {
  3115. // If some data was processed consider it a success.
  3116. Status = *BytesRead > 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  3117. break;
  3118. }
  3119. Cmd.Address.QuadPart += ChunkDone;
  3120. Cmd.Buffer = (PVOID)((PUCHAR)Cmd.Buffer + ChunkDone);
  3121. BufferSize -= ChunkDone;
  3122. *BytesRead += ChunkDone;
  3123. }
  3124. return CONV_NT_STATUS(Status);
  3125. }
  3126. HRESULT
  3127. LocalLiveKernelTargetInfo::WritePhysical(
  3128. THIS_
  3129. IN ULONG64 Offset,
  3130. IN PVOID Buffer,
  3131. IN ULONG BufferSize,
  3132. IN ULONG Flags,
  3133. OUT PULONG BytesWritten
  3134. )
  3135. {
  3136. SYSDBG_PHYSICAL Cmd;
  3137. NTSTATUS Status = STATUS_SUCCESS;
  3138. if (Flags != PHYS_FLAG_DEFAULT)
  3139. {
  3140. return E_NOTIMPL;
  3141. }
  3142. //
  3143. // The kernel only allows operations up to
  3144. // KDP_MESSAGE_BUFFER_SIZE, so break things up
  3145. // into chunks if necessary.
  3146. //
  3147. *BytesWritten = 0;
  3148. Cmd.Address.QuadPart = Offset;
  3149. Cmd.Buffer = Buffer;
  3150. while (BufferSize > 0)
  3151. {
  3152. ULONG ChunkDone;
  3153. if (BufferSize > PACKET_MAX_SIZE)
  3154. {
  3155. Cmd.Request = PACKET_MAX_SIZE;
  3156. }
  3157. else
  3158. {
  3159. Cmd.Request = BufferSize;
  3160. }
  3161. // The kernel stubs avoid faults so all memory
  3162. // must be paged in ahead of time. There's
  3163. // still the possibility that something could
  3164. // get paged out after this but the assumption is
  3165. // that the vulnerability is small and it's much
  3166. // better than implementing dual code paths in
  3167. // the kernel.
  3168. if (IsBadReadPtr(Cmd.Buffer, Cmd.Request))
  3169. {
  3170. Status = STATUS_INVALID_PARAMETER;
  3171. break;
  3172. }
  3173. ChunkDone = 0;
  3174. Status =
  3175. g_NtDllCalls.NtSystemDebugControl(SysDbgWritePhysical,
  3176. &Cmd, sizeof(Cmd),
  3177. NULL, 0,
  3178. &ChunkDone);
  3179. if (!NT_SUCCESS(Status) && Status != STATUS_UNSUCCESSFUL)
  3180. {
  3181. break;
  3182. }
  3183. if (ChunkDone == 0)
  3184. {
  3185. // If some data was processed consider it a success.
  3186. Status = *BytesWritten > 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  3187. break;
  3188. }
  3189. Cmd.Address.QuadPart += ChunkDone;
  3190. Cmd.Buffer = (PVOID)((PUCHAR)Cmd.Buffer + ChunkDone);
  3191. BufferSize -= ChunkDone;
  3192. *BytesWritten += ChunkDone;
  3193. }
  3194. if (NT_SUCCESS(Status))
  3195. {
  3196. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_PHYSICAL);
  3197. }
  3198. return CONV_NT_STATUS(Status);
  3199. }
  3200. HRESULT
  3201. LocalLiveKernelTargetInfo::ReadControl(
  3202. THIS_
  3203. IN ULONG Processor,
  3204. IN ULONG64 Offset,
  3205. OUT PVOID Buffer,
  3206. IN ULONG BufferSize,
  3207. OUT PULONG BytesRead
  3208. )
  3209. {
  3210. // The kernel stubs avoid faults so all memory
  3211. // must be paged in ahead of time. There's
  3212. // still the possibility that something could
  3213. // get paged out after this but the assumption is
  3214. // that the vulnerability is small and it's much
  3215. // better than implementing dual code paths in
  3216. // the kernel.
  3217. if (IsBadWritePtr(Buffer, BufferSize))
  3218. {
  3219. return E_INVALIDARG;
  3220. }
  3221. SYSDBG_CONTROL_SPACE Cmd;
  3222. Cmd.Address = Offset;
  3223. Cmd.Buffer = Buffer;
  3224. Cmd.Request = BufferSize;
  3225. Cmd.Processor = Processor;
  3226. NTSTATUS Status =
  3227. g_NtDllCalls.NtSystemDebugControl(SysDbgReadControlSpace,
  3228. &Cmd, sizeof(Cmd),
  3229. NULL, 0,
  3230. BytesRead);
  3231. return CONV_NT_STATUS(Status);
  3232. }
  3233. HRESULT
  3234. LocalLiveKernelTargetInfo::WriteControl(
  3235. THIS_
  3236. IN ULONG Processor,
  3237. IN ULONG64 Offset,
  3238. IN PVOID Buffer,
  3239. IN ULONG BufferSize,
  3240. OUT PULONG BytesWritten
  3241. )
  3242. {
  3243. // The kernel stubs avoid faults so all memory
  3244. // must be paged in ahead of time. There's
  3245. // still the possibility that something could
  3246. // get paged out after this but the assumption is
  3247. // that the vulnerability is small and it's much
  3248. // better than implementing dual code paths in
  3249. // the kernel.
  3250. if (IsBadReadPtr(Buffer, BufferSize))
  3251. {
  3252. return E_INVALIDARG;
  3253. }
  3254. SYSDBG_CONTROL_SPACE Cmd;
  3255. Cmd.Address = Offset;
  3256. Cmd.Buffer = Buffer;
  3257. Cmd.Request = BufferSize;
  3258. Cmd.Processor = Processor;
  3259. NTSTATUS Status =
  3260. g_NtDllCalls.NtSystemDebugControl(SysDbgWriteControlSpace,
  3261. &Cmd, sizeof(Cmd),
  3262. NULL, 0,
  3263. BytesWritten);
  3264. if (NT_SUCCESS(Status))
  3265. {
  3266. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_CONTROL);
  3267. }
  3268. return CONV_NT_STATUS(Status);
  3269. }
  3270. HRESULT
  3271. LocalLiveKernelTargetInfo::ReadIo(
  3272. THIS_
  3273. IN ULONG InterfaceType,
  3274. IN ULONG BusNumber,
  3275. IN ULONG AddressSpace,
  3276. IN ULONG64 Offset,
  3277. OUT PVOID Buffer,
  3278. IN ULONG BufferSize,
  3279. OUT PULONG BytesRead
  3280. )
  3281. {
  3282. // The kernel stubs avoid faults so all memory
  3283. // must be paged in ahead of time. There's
  3284. // still the possibility that something could
  3285. // get paged out after this but the assumption is
  3286. // that the vulnerability is small and it's much
  3287. // better than implementing dual code paths in
  3288. // the kernel.
  3289. if (IsBadWritePtr(Buffer, BufferSize))
  3290. {
  3291. return E_INVALIDARG;
  3292. }
  3293. SYSDBG_IO_SPACE Cmd;
  3294. Cmd.Address = Offset;
  3295. Cmd.Buffer = Buffer;
  3296. Cmd.Request = BufferSize;
  3297. Cmd.InterfaceType = (INTERFACE_TYPE)InterfaceType;
  3298. Cmd.BusNumber = BusNumber;
  3299. Cmd.AddressSpace = AddressSpace;
  3300. NTSTATUS Status =
  3301. g_NtDllCalls.NtSystemDebugControl(SysDbgReadIoSpace,
  3302. &Cmd, sizeof(Cmd),
  3303. NULL, 0,
  3304. BytesRead);
  3305. return CONV_NT_STATUS(Status);
  3306. }
  3307. HRESULT
  3308. LocalLiveKernelTargetInfo::WriteIo(
  3309. THIS_
  3310. IN ULONG InterfaceType,
  3311. IN ULONG BusNumber,
  3312. IN ULONG AddressSpace,
  3313. IN ULONG64 Offset,
  3314. IN PVOID Buffer,
  3315. IN ULONG BufferSize,
  3316. OUT PULONG BytesWritten
  3317. )
  3318. {
  3319. // The kernel stubs avoid faults so all memory
  3320. // must be paged in ahead of time. There's
  3321. // still the possibility that something could
  3322. // get paged out after this but the assumption is
  3323. // that the vulnerability is small and it's much
  3324. // better than implementing dual code paths in
  3325. // the kernel.
  3326. if (IsBadReadPtr(Buffer, BufferSize))
  3327. {
  3328. return E_INVALIDARG;
  3329. }
  3330. SYSDBG_IO_SPACE Cmd;
  3331. Cmd.Address = Offset;
  3332. Cmd.Buffer = Buffer;
  3333. Cmd.Request = BufferSize;
  3334. Cmd.InterfaceType = (INTERFACE_TYPE)InterfaceType;
  3335. Cmd.BusNumber = BusNumber;
  3336. Cmd.AddressSpace = AddressSpace;
  3337. NTSTATUS Status =
  3338. g_NtDllCalls.NtSystemDebugControl(SysDbgWriteIoSpace,
  3339. &Cmd, sizeof(Cmd),
  3340. NULL, 0,
  3341. BytesWritten);
  3342. if (NT_SUCCESS(Status))
  3343. {
  3344. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_IO);
  3345. }
  3346. return CONV_NT_STATUS(Status);
  3347. }
  3348. HRESULT
  3349. LocalLiveKernelTargetInfo::ReadMsr(
  3350. THIS_
  3351. IN ULONG Msr,
  3352. OUT PULONG64 Value
  3353. )
  3354. {
  3355. SYSDBG_MSR Cmd;
  3356. Cmd.Msr = Msr;
  3357. NTSTATUS Status =
  3358. g_NtDllCalls.NtSystemDebugControl(SysDbgReadMsr,
  3359. &Cmd, sizeof(Cmd),
  3360. &Cmd, sizeof(Cmd),
  3361. NULL);
  3362. if (NT_SUCCESS(Status))
  3363. {
  3364. *Value = Cmd.Data;
  3365. }
  3366. return CONV_NT_STATUS(Status);
  3367. }
  3368. HRESULT
  3369. LocalLiveKernelTargetInfo::WriteMsr(
  3370. THIS_
  3371. IN ULONG Msr,
  3372. IN ULONG64 Value
  3373. )
  3374. {
  3375. SYSDBG_MSR Cmd;
  3376. Cmd.Msr = Msr;
  3377. Cmd.Data = Value;
  3378. NTSTATUS Status =
  3379. g_NtDllCalls.NtSystemDebugControl(SysDbgWriteMsr,
  3380. &Cmd, sizeof(Cmd),
  3381. NULL, 0,
  3382. NULL);
  3383. if (NT_SUCCESS(Status))
  3384. {
  3385. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_MSR);
  3386. }
  3387. return CONV_NT_STATUS(Status);
  3388. }
  3389. HRESULT
  3390. LocalLiveKernelTargetInfo::ReadBusData(
  3391. THIS_
  3392. IN ULONG BusDataType,
  3393. IN ULONG BusNumber,
  3394. IN ULONG SlotNumber,
  3395. IN ULONG Offset,
  3396. OUT PVOID Buffer,
  3397. IN ULONG BufferSize,
  3398. OUT PULONG BytesRead
  3399. )
  3400. {
  3401. // The kernel stubs avoid faults so all memory
  3402. // must be paged in ahead of time. There's
  3403. // still the possibility that something could
  3404. // get paged out after this but the assumption is
  3405. // that the vulnerability is small and it's much
  3406. // better than implementing dual code paths in
  3407. // the kernel.
  3408. if (IsBadWritePtr(Buffer, BufferSize))
  3409. {
  3410. return E_INVALIDARG;
  3411. }
  3412. SYSDBG_BUS_DATA Cmd;
  3413. Cmd.Address = Offset;
  3414. Cmd.Buffer = Buffer;
  3415. Cmd.Request = BufferSize;
  3416. Cmd.BusDataType = (BUS_DATA_TYPE)BusDataType;
  3417. Cmd.BusNumber = BusNumber;
  3418. Cmd.SlotNumber = SlotNumber;
  3419. NTSTATUS Status =
  3420. g_NtDllCalls.NtSystemDebugControl(SysDbgReadBusData,
  3421. &Cmd, sizeof(Cmd),
  3422. NULL, 0,
  3423. BytesRead);
  3424. return CONV_NT_STATUS(Status);
  3425. }
  3426. HRESULT
  3427. LocalLiveKernelTargetInfo::WriteBusData(
  3428. THIS_
  3429. IN ULONG BusDataType,
  3430. IN ULONG BusNumber,
  3431. IN ULONG SlotNumber,
  3432. IN ULONG Offset,
  3433. IN PVOID Buffer,
  3434. IN ULONG BufferSize,
  3435. OUT PULONG BytesWritten
  3436. )
  3437. {
  3438. // The kernel stubs avoid faults so all memory
  3439. // must be paged in ahead of time. There's
  3440. // still the possibility that something could
  3441. // get paged out after this but the assumption is
  3442. // that the vulnerability is small and it's much
  3443. // better than implementing dual code paths in
  3444. // the kernel.
  3445. if (IsBadReadPtr(Buffer, BufferSize))
  3446. {
  3447. return E_INVALIDARG;
  3448. }
  3449. SYSDBG_BUS_DATA Cmd;
  3450. Cmd.Address = Offset;
  3451. Cmd.Buffer = Buffer;
  3452. Cmd.Request = BufferSize;
  3453. Cmd.BusDataType = (BUS_DATA_TYPE)BusDataType;
  3454. Cmd.BusNumber = BusNumber;
  3455. Cmd.SlotNumber = SlotNumber;
  3456. NTSTATUS Status =
  3457. g_NtDllCalls.NtSystemDebugControl(SysDbgWriteBusData,
  3458. &Cmd, sizeof(Cmd),
  3459. NULL, 0,
  3460. BytesWritten);
  3461. if (NT_SUCCESS(Status))
  3462. {
  3463. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_BUS_DATA);
  3464. }
  3465. return CONV_NT_STATUS(Status);
  3466. }
  3467. HRESULT
  3468. LocalLiveKernelTargetInfo::CheckLowMemory(
  3469. )
  3470. {
  3471. NTSTATUS Status =
  3472. g_NtDllCalls.NtSystemDebugControl(SysDbgCheckLowMemory,
  3473. NULL, 0,
  3474. NULL, 0,
  3475. NULL);
  3476. return CONV_NT_STATUS(Status);
  3477. }
  3478. //----------------------------------------------------------------------------
  3479. //
  3480. // ExdiLiveKernelTargetInfo data space methods.
  3481. //
  3482. //----------------------------------------------------------------------------
  3483. HRESULT
  3484. ExdiLiveKernelTargetInfo::ReadVirtual(
  3485. THIS_
  3486. IN ProcessInfo* Process,
  3487. IN ULONG64 Offset,
  3488. OUT PVOID Buffer,
  3489. IN ULONG BufferSize,
  3490. OUT PULONG BytesRead
  3491. )
  3492. {
  3493. HRESULT Status = m_Server->
  3494. ReadVirtualMemory(Offset, BufferSize, 8, (PBYTE)Buffer, BytesRead);
  3495. return Status;
  3496. }
  3497. HRESULT
  3498. ExdiLiveKernelTargetInfo::WriteVirtual(
  3499. THIS_
  3500. IN ProcessInfo* Process,
  3501. IN ULONG64 Offset,
  3502. IN PVOID Buffer,
  3503. IN ULONG BufferSize,
  3504. OUT PULONG BytesWritten
  3505. )
  3506. {
  3507. HRESULT Status = m_Server->
  3508. WriteVirtualMemory(Offset, BufferSize, 8, (PBYTE)Buffer, BytesWritten);
  3509. if (Status == S_OK)
  3510. {
  3511. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_VIRTUAL);
  3512. }
  3513. return Status;
  3514. }
  3515. HRESULT
  3516. ExdiLiveKernelTargetInfo::ReadPhysical(
  3517. THIS_
  3518. IN ULONG64 Offset,
  3519. OUT PVOID Buffer,
  3520. IN ULONG BufferSize,
  3521. IN ULONG Flags,
  3522. OUT PULONG BytesRead
  3523. )
  3524. {
  3525. if (Flags != PHYS_FLAG_DEFAULT)
  3526. {
  3527. return E_NOTIMPL;
  3528. }
  3529. HRESULT Status = m_Server->
  3530. ReadPhysicalMemoryOrPeriphIO(Offset, 0, BufferSize, 8, (PBYTE)Buffer);
  3531. if (Status == S_OK)
  3532. {
  3533. *BytesRead = BufferSize;
  3534. }
  3535. return Status;
  3536. }
  3537. HRESULT
  3538. ExdiLiveKernelTargetInfo::WritePhysical(
  3539. THIS_
  3540. IN ULONG64 Offset,
  3541. IN PVOID Buffer,
  3542. IN ULONG BufferSize,
  3543. IN ULONG Flags,
  3544. OUT PULONG BytesWritten
  3545. )
  3546. {
  3547. if (Flags != PHYS_FLAG_DEFAULT)
  3548. {
  3549. return E_NOTIMPL;
  3550. }
  3551. HRESULT Status = m_Server->
  3552. WritePhysicalMemoryOrPeriphIO(Offset, 0, BufferSize, 8, (PBYTE)Buffer);
  3553. if (Status == S_OK)
  3554. {
  3555. *BytesWritten = BufferSize;
  3556. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_PHYSICAL);
  3557. }
  3558. return Status;
  3559. }
  3560. HRESULT
  3561. ExdiLiveKernelTargetInfo::ReadControl(
  3562. THIS_
  3563. IN ULONG Processor,
  3564. IN ULONG64 Offset,
  3565. OUT PVOID Buffer,
  3566. IN ULONG BufferSize,
  3567. OUT PULONG BytesRead
  3568. )
  3569. {
  3570. // No Ioctl defined for this.
  3571. return E_UNEXPECTED;
  3572. }
  3573. HRESULT
  3574. ExdiLiveKernelTargetInfo::WriteControl(
  3575. THIS_
  3576. IN ULONG Processor,
  3577. IN ULONG64 Offset,
  3578. IN PVOID Buffer,
  3579. IN ULONG BufferSize,
  3580. OUT PULONG BytesWritten
  3581. )
  3582. {
  3583. // No Ioctl defined for this.
  3584. return E_UNEXPECTED;
  3585. }
  3586. HRESULT
  3587. ExdiLiveKernelTargetInfo::ReadIo(
  3588. THIS_
  3589. IN ULONG InterfaceType,
  3590. IN ULONG BusNumber,
  3591. IN ULONG AddressSpace,
  3592. IN ULONG64 Offset,
  3593. OUT PVOID Buffer,
  3594. IN ULONG BufferSize,
  3595. OUT PULONG BytesRead
  3596. )
  3597. {
  3598. HRESULT Status = m_Server->
  3599. ReadPhysicalMemoryOrPeriphIO(Offset, 1, BufferSize, 8, (PBYTE)Buffer);
  3600. if (Status == S_OK)
  3601. {
  3602. *BytesRead = BufferSize;
  3603. }
  3604. return Status;
  3605. }
  3606. HRESULT
  3607. ExdiLiveKernelTargetInfo::WriteIo(
  3608. THIS_
  3609. IN ULONG InterfaceType,
  3610. IN ULONG BusNumber,
  3611. IN ULONG AddressSpace,
  3612. IN ULONG64 Offset,
  3613. IN PVOID Buffer,
  3614. IN ULONG BufferSize,
  3615. OUT PULONG BytesWritten
  3616. )
  3617. {
  3618. HRESULT Status = m_Server->
  3619. WritePhysicalMemoryOrPeriphIO(Offset, 1, BufferSize, 8, (PBYTE)Buffer);
  3620. if (Status == S_OK)
  3621. {
  3622. *BytesWritten = BufferSize;
  3623. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_IO);
  3624. }
  3625. return Status;
  3626. }
  3627. HRESULT
  3628. ExdiLiveKernelTargetInfo::ReadMsr(
  3629. THIS_
  3630. IN ULONG Msr,
  3631. OUT PULONG64 Value
  3632. )
  3633. {
  3634. HRESULT Status;
  3635. if (DBGENG_EXDI_IOC_READ_MSR <= m_IoctlMin ||
  3636. DBGENG_EXDI_IOC_READ_MSR >= m_IoctlMax)
  3637. {
  3638. // Read MSR Ioctl not supported.
  3639. return E_NOTIMPL;
  3640. }
  3641. DBGENG_EXDI_IOCTL_MSR_IN IoctlIn;
  3642. DBGENG_EXDI_IOCTL_READ_MSR_OUT IoctlOut;
  3643. ULONG OutUsed;
  3644. IoctlIn.Code = DBGENG_EXDI_IOC_READ_MSR;
  3645. IoctlIn.Index = Msr;
  3646. if ((Status = m_Server->
  3647. Ioctl(sizeof(IoctlIn), (PBYTE)&IoctlIn,
  3648. sizeof(IoctlOut), &OutUsed, (PBYTE)&IoctlOut)) != S_OK)
  3649. {
  3650. return Status;
  3651. }
  3652. *Value = IoctlOut.Value;
  3653. return S_OK;
  3654. }
  3655. HRESULT
  3656. ExdiLiveKernelTargetInfo::WriteMsr(
  3657. THIS_
  3658. IN ULONG Msr,
  3659. IN ULONG64 Value
  3660. )
  3661. {
  3662. HRESULT Status;
  3663. if (DBGENG_EXDI_IOC_WRITE_MSR <= m_IoctlMin ||
  3664. DBGENG_EXDI_IOC_WRITE_MSR >= m_IoctlMax)
  3665. {
  3666. // Write MSR Ioctl not supported.
  3667. return E_NOTIMPL;
  3668. }
  3669. DBGENG_EXDI_IOCTL_MSR_IN IoctlIn;
  3670. ULONG OutUsed;
  3671. IoctlIn.Code = DBGENG_EXDI_IOC_WRITE_MSR;
  3672. IoctlIn.Index = Msr;
  3673. IoctlIn.Value = Value;
  3674. Status = m_Server->Ioctl(sizeof(IoctlIn), (PBYTE)&IoctlIn,
  3675. 0, &OutUsed, (PBYTE)&IoctlIn);
  3676. if (Status == S_OK)
  3677. {
  3678. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_MSR);
  3679. }
  3680. return Status;
  3681. }
  3682. HRESULT
  3683. ExdiLiveKernelTargetInfo::ReadBusData(
  3684. THIS_
  3685. IN ULONG BusDataType,
  3686. IN ULONG BusNumber,
  3687. IN ULONG SlotNumber,
  3688. IN ULONG Offset,
  3689. OUT PVOID Buffer,
  3690. IN ULONG BufferSize,
  3691. OUT PULONG BytesRead
  3692. )
  3693. {
  3694. // No Ioctl defined for this.
  3695. return E_UNEXPECTED;
  3696. }
  3697. HRESULT
  3698. ExdiLiveKernelTargetInfo::WriteBusData(
  3699. THIS_
  3700. IN ULONG BusDataType,
  3701. IN ULONG BusNumber,
  3702. IN ULONG SlotNumber,
  3703. IN ULONG Offset,
  3704. IN PVOID Buffer,
  3705. IN ULONG BufferSize,
  3706. OUT PULONG BytesWritten
  3707. )
  3708. {
  3709. // No Ioctl defined for this.
  3710. return E_UNEXPECTED;
  3711. }
  3712. HRESULT
  3713. ExdiLiveKernelTargetInfo::CheckLowMemory(
  3714. )
  3715. {
  3716. // XXX drewb - This doesn't have any meaning in
  3717. // the general case. What about when we know it's
  3718. // NT on the other side of the emulator?
  3719. return E_UNEXPECTED;
  3720. }
  3721. //----------------------------------------------------------------------------
  3722. //
  3723. // UserTargetInfo data space methods.
  3724. //
  3725. //----------------------------------------------------------------------------
  3726. HRESULT
  3727. LiveUserTargetInfo::ReadVirtual(
  3728. THIS_
  3729. IN ProcessInfo* Process,
  3730. IN ULONG64 Offset,
  3731. OUT PVOID Buffer,
  3732. IN ULONG BufferSize,
  3733. OUT PULONG BytesRead
  3734. )
  3735. {
  3736. if (m_Local)
  3737. {
  3738. return ReadVirtualUncached(Process,
  3739. Offset, Buffer, BufferSize, BytesRead);
  3740. }
  3741. else
  3742. {
  3743. return Process->m_VirtualCache.
  3744. Read(Offset, Buffer, BufferSize, BytesRead);
  3745. }
  3746. }
  3747. HRESULT
  3748. LiveUserTargetInfo::WriteVirtual(
  3749. THIS_
  3750. IN ProcessInfo* Process,
  3751. IN ULONG64 Offset,
  3752. IN PVOID Buffer,
  3753. IN ULONG BufferSize,
  3754. OUT PULONG BytesWritten
  3755. )
  3756. {
  3757. if (m_Local)
  3758. {
  3759. return WriteVirtualUncached(Process,
  3760. Offset, Buffer, BufferSize, BytesWritten);
  3761. }
  3762. else
  3763. {
  3764. return Process->m_VirtualCache.
  3765. Write(Offset, Buffer, BufferSize, BytesWritten);
  3766. }
  3767. }
  3768. HRESULT
  3769. LiveUserTargetInfo::ReadVirtualUncached(
  3770. THIS_
  3771. IN ProcessInfo* Process,
  3772. IN ULONG64 Offset,
  3773. OUT PVOID Buffer,
  3774. IN ULONG BufferSize,
  3775. OUT PULONG BytesRead
  3776. )
  3777. {
  3778. // ReadProcessMemory will fail if any part of the
  3779. // region to read does not have read access. This
  3780. // routine attempts to read the largest valid prefix
  3781. // so it has to break up reads on page boundaries.
  3782. HRESULT Status = S_OK;
  3783. ULONG TotalBytesRead = 0;
  3784. ULONG Read;
  3785. ULONG ReadSize;
  3786. while (BufferSize > 0)
  3787. {
  3788. // Calculate bytes to read and don't let read cross
  3789. // a page boundary.
  3790. ReadSize = m_Machine->m_PageSize - (ULONG)
  3791. (Offset & (m_Machine->m_PageSize - 1));
  3792. ReadSize = min(BufferSize, ReadSize);
  3793. if ((Status = m_Services->
  3794. ReadVirtual(Process->m_SysHandle, Offset,
  3795. Buffer, ReadSize, &Read)) != S_OK)
  3796. {
  3797. if (TotalBytesRead != 0)
  3798. {
  3799. // If we've read something consider this a success.
  3800. Status = S_OK;
  3801. }
  3802. break;
  3803. }
  3804. TotalBytesRead += Read;
  3805. Offset += Read;
  3806. Buffer = (PVOID)((PUCHAR)Buffer + Read);
  3807. BufferSize -= (DWORD)Read;
  3808. }
  3809. if (Status == S_OK)
  3810. {
  3811. if (BytesRead != NULL)
  3812. {
  3813. *BytesRead = (DWORD)TotalBytesRead;
  3814. }
  3815. }
  3816. return Status;
  3817. }
  3818. HRESULT
  3819. LiveUserTargetInfo::WriteVirtualUncached(
  3820. THIS_
  3821. IN ProcessInfo* Process,
  3822. IN ULONG64 Offset,
  3823. IN PVOID Buffer,
  3824. IN ULONG BufferSize,
  3825. OUT PULONG BytesWritten
  3826. )
  3827. {
  3828. ULONG RealBytesWritten;
  3829. HRESULT Status = m_Services->
  3830. WriteVirtual(Process->m_SysHandle, Offset, Buffer, BufferSize,
  3831. &RealBytesWritten);
  3832. *BytesWritten = (DWORD) RealBytesWritten;
  3833. if (Status == S_OK)
  3834. {
  3835. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_VIRTUAL);
  3836. }
  3837. return Status;
  3838. }
  3839. HRESULT
  3840. LiveUserTargetInfo::GetUnloadedModuleListHead(ProcessInfo* Process,
  3841. PULONG64 Head)
  3842. {
  3843. // Get the address of the dynamic function table list head which is the
  3844. // the same for all processes. This only has to be done once.
  3845. if (Process->m_RtlUnloadList)
  3846. {
  3847. *Head = Process->m_RtlUnloadList;
  3848. return S_OK;
  3849. }
  3850. if (m_Services->
  3851. GetUnloadedModuleListHead(Process->m_SysHandle,
  3852. &Process->m_RtlUnloadList) == S_OK)
  3853. {
  3854. *Head = Process->m_RtlUnloadList;
  3855. return S_OK;
  3856. }
  3857. return TargetInfo::GetUnloadedModuleListHead(Process, Head);
  3858. }
  3859. HRESULT
  3860. LiveUserTargetInfo::GetFunctionTableListHead(ProcessInfo* Process, PULONG64 Head)
  3861. {
  3862. // Get the address of the dynamic function table list head which is the
  3863. // the same for all processes. This only has to be done once.
  3864. if (Process->m_DynFuncTableList)
  3865. {
  3866. *Head = Process->m_DynFuncTableList;
  3867. return S_OK;
  3868. }
  3869. if (m_Services->
  3870. GetFunctionTableListHead(Process->m_SysHandle,
  3871. &Process->m_DynFuncTableList) == S_OK)
  3872. {
  3873. *Head = Process->m_DynFuncTableList;
  3874. return S_OK;
  3875. }
  3876. return TargetInfo::GetFunctionTableListHead(Process, Head);
  3877. }
  3878. HRESULT
  3879. LiveUserTargetInfo::ReadOutOfProcessDynamicFunctionTable(ProcessInfo* Process,
  3880. PWSTR Dll,
  3881. ULONG64 Table,
  3882. PULONG RetTableSize,
  3883. PVOID* RetTableData)
  3884. {
  3885. HRESULT Status;
  3886. PVOID TableData;
  3887. ULONG TableSize;
  3888. // Allocate an initial buffer of a reasonable size to try
  3889. // and get the data in a single call.
  3890. TableSize = 65536;
  3891. for (;;)
  3892. {
  3893. TableData = malloc(TableSize);
  3894. if (TableData == NULL)
  3895. {
  3896. return E_OUTOFMEMORY;
  3897. }
  3898. //
  3899. // We assume that the function table data doesn't
  3900. // change between OOP calls as long as the debuggee isn't
  3901. // executing. To increase performance we cache loaded
  3902. // DLLs as long as things are halted.
  3903. //
  3904. OUT_OF_PROC_FUNC_TABLE_DLL* OopDll =
  3905. Process->FindOopFuncTableDll(Dll);
  3906. ULONG64 DllHandle;
  3907. Status = m_Services->
  3908. GetOutOfProcessFunctionTableW(Process->m_SysHandle,
  3909. Dll, OopDll ? OopDll->Handle : 0,
  3910. Table, TableData,
  3911. TableSize, &TableSize,
  3912. &DllHandle);
  3913. if (Status == S_OK)
  3914. {
  3915. // If we haven't cached this DLL yet do so now.
  3916. if (!OopDll)
  3917. {
  3918. // Failure to cache isn't critical, it
  3919. // just means more loads later.
  3920. if (Process->AddOopFuncTableDll(Dll, DllHandle) != S_OK)
  3921. {
  3922. m_Services->FreeLibrary(DllHandle);
  3923. }
  3924. }
  3925. break;
  3926. }
  3927. free(TableData);
  3928. if (Status == S_FALSE)
  3929. {
  3930. // Buffer was too small so loop and try again with
  3931. // the newly retrieved size.
  3932. }
  3933. else
  3934. {
  3935. return Status;
  3936. }
  3937. }
  3938. *RetTableSize = TableSize;
  3939. *RetTableData = TableData;
  3940. return S_OK;
  3941. }
  3942. HRESULT
  3943. LiveUserTargetInfo::QueryMemoryRegion(ProcessInfo* Process,
  3944. PULONG64 Handle,
  3945. BOOL HandleIsOffset,
  3946. PMEMORY_BASIC_INFORMATION64 Info)
  3947. {
  3948. MEMORY_BASIC_INFORMATION64 MemInfo;
  3949. HRESULT Status;
  3950. for (;;)
  3951. {
  3952. ULONG Used;
  3953. // The handle is always an offset in this mode so
  3954. // there's no need to check.
  3955. if ((Status = m_Services->
  3956. QueryVirtual(Process->m_SysHandle,
  3957. *Handle, &MemInfo, sizeof(MemInfo), &Used)) != S_OK)
  3958. {
  3959. return Status;
  3960. }
  3961. if (m_Machine->m_Ptr64)
  3962. {
  3963. if (Used != sizeof(MEMORY_BASIC_INFORMATION64))
  3964. {
  3965. return E_FAIL;
  3966. }
  3967. *Info = MemInfo;
  3968. }
  3969. else
  3970. {
  3971. if (Used != sizeof(MEMORY_BASIC_INFORMATION32))
  3972. {
  3973. return E_FAIL;
  3974. }
  3975. MemoryBasicInformation32To64((MEMORY_BASIC_INFORMATION32*)&MemInfo,
  3976. Info);
  3977. }
  3978. if (HandleIsOffset ||
  3979. !((Info->Protect & PAGE_GUARD) ||
  3980. (Info->Protect & PAGE_NOACCESS) ||
  3981. (Info->State & MEM_FREE) ||
  3982. (Info->State & MEM_RESERVE)))
  3983. {
  3984. break;
  3985. }
  3986. *Handle = Info->BaseAddress + Info->RegionSize;
  3987. }
  3988. *Handle = Info->BaseAddress + Info->RegionSize;
  3989. return S_OK;
  3990. }
  3991. HRESULT
  3992. LiveUserTargetInfo::ReadHandleData(
  3993. IN ProcessInfo* Process,
  3994. IN ULONG64 Handle,
  3995. IN ULONG DataType,
  3996. OUT OPTIONAL PVOID Buffer,
  3997. IN ULONG BufferSize,
  3998. OUT OPTIONAL PULONG DataSize
  3999. )
  4000. {
  4001. return m_Services->
  4002. ReadHandleData(Process->m_SysHandle,
  4003. Handle, DataType, Buffer, BufferSize,
  4004. DataSize);
  4005. }
  4006. HRESULT
  4007. LiveUserTargetInfo::GetProcessorId(
  4008. ULONG Processor,
  4009. PDEBUG_PROCESSOR_IDENTIFICATION_ALL Id
  4010. )
  4011. {
  4012. ULONG Done;
  4013. return m_Services->GetProcessorId(Id, sizeof(*Id), &Done);
  4014. }
  4015. HRESULT
  4016. LiveUserTargetInfo::GetProcessorSpeed(
  4017. ULONG Processor,
  4018. PULONG Speed
  4019. )
  4020. {
  4021. return E_UNEXPECTED;
  4022. }
  4023. HRESULT
  4024. LiveUserTargetInfo::GetGenericProcessorFeatures(
  4025. ULONG Processor,
  4026. PULONG64 Features,
  4027. ULONG FeaturesSize,
  4028. PULONG Used
  4029. )
  4030. {
  4031. return m_Services->
  4032. GetGenericProcessorFeatures(Features, FeaturesSize, Used);
  4033. }
  4034. HRESULT
  4035. LiveUserTargetInfo::GetSpecificProcessorFeatures(
  4036. ULONG Processor,
  4037. PULONG64 Features,
  4038. ULONG FeaturesSize,
  4039. PULONG Used
  4040. )
  4041. {
  4042. return m_Services->
  4043. GetSpecificProcessorFeatures(Features, FeaturesSize, Used);
  4044. }
  4045. //----------------------------------------------------------------------------
  4046. //
  4047. // IDebugDataSpaces.
  4048. //
  4049. //----------------------------------------------------------------------------
  4050. STDMETHODIMP
  4051. DebugClient::ReadVirtual(
  4052. THIS_
  4053. IN ULONG64 Offset,
  4054. OUT PVOID Buffer,
  4055. IN ULONG BufferSize,
  4056. OUT PULONG BytesRead
  4057. )
  4058. {
  4059. HRESULT Status;
  4060. ENTER_ENGINE();
  4061. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4062. {
  4063. Status = E_UNEXPECTED;
  4064. }
  4065. else
  4066. {
  4067. ULONG BytesTemp;
  4068. Status = CurReadVirtual(Offset, Buffer, BufferSize,
  4069. BytesRead != NULL ? BytesRead : &BytesTemp);
  4070. }
  4071. LEAVE_ENGINE();
  4072. return Status;
  4073. }
  4074. STDMETHODIMP
  4075. DebugClient::WriteVirtual(
  4076. THIS_
  4077. IN ULONG64 Offset,
  4078. IN PVOID Buffer,
  4079. IN ULONG BufferSize,
  4080. OUT PULONG BytesWritten
  4081. )
  4082. {
  4083. HRESULT Status;
  4084. ENTER_ENGINE();
  4085. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4086. {
  4087. Status = E_UNEXPECTED;
  4088. }
  4089. else
  4090. {
  4091. ULONG BytesTemp;
  4092. Status = g_Target->WriteVirtual(g_Process, Offset, Buffer, BufferSize,
  4093. BytesWritten != NULL ? BytesWritten :
  4094. &BytesTemp);
  4095. }
  4096. LEAVE_ENGINE();
  4097. return Status;
  4098. }
  4099. STDMETHODIMP
  4100. DebugClient::SearchVirtual(
  4101. THIS_
  4102. IN ULONG64 Offset,
  4103. IN ULONG64 Length,
  4104. IN PVOID Pattern,
  4105. IN ULONG PatternSize,
  4106. IN ULONG PatternGranularity,
  4107. OUT PULONG64 MatchOffset
  4108. )
  4109. {
  4110. if (PatternGranularity == 0 ||
  4111. PatternSize % PatternGranularity)
  4112. {
  4113. return E_INVALIDARG;
  4114. }
  4115. HRESULT Status;
  4116. ENTER_ENGINE();
  4117. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4118. {
  4119. Status = E_UNEXPECTED;
  4120. }
  4121. else
  4122. {
  4123. Status = g_Target->SearchVirtual(g_Process, Offset, Length, Pattern,
  4124. PatternSize, PatternGranularity,
  4125. MatchOffset);
  4126. }
  4127. LEAVE_ENGINE();
  4128. return Status;
  4129. }
  4130. STDMETHODIMP
  4131. DebugClient::ReadVirtualUncached(
  4132. THIS_
  4133. IN ULONG64 Offset,
  4134. OUT PVOID Buffer,
  4135. IN ULONG BufferSize,
  4136. OUT PULONG BytesRead
  4137. )
  4138. {
  4139. HRESULT Status;
  4140. ENTER_ENGINE();
  4141. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4142. {
  4143. Status = E_UNEXPECTED;
  4144. }
  4145. else
  4146. {
  4147. ULONG BytesTemp;
  4148. Status = g_Target->
  4149. ReadVirtualUncached(g_Process, Offset, Buffer, BufferSize,
  4150. BytesRead != NULL ? BytesRead :
  4151. &BytesTemp);
  4152. }
  4153. LEAVE_ENGINE();
  4154. return Status;
  4155. }
  4156. STDMETHODIMP
  4157. DebugClient::WriteVirtualUncached(
  4158. THIS_
  4159. IN ULONG64 Offset,
  4160. IN PVOID Buffer,
  4161. IN ULONG BufferSize,
  4162. OUT PULONG BytesWritten
  4163. )
  4164. {
  4165. HRESULT Status;
  4166. ENTER_ENGINE();
  4167. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4168. {
  4169. Status = E_UNEXPECTED;
  4170. }
  4171. else
  4172. {
  4173. ULONG BytesTemp;
  4174. Status = g_Target->
  4175. WriteVirtualUncached(g_Process, Offset, Buffer, BufferSize,
  4176. BytesWritten != NULL ? BytesWritten :
  4177. &BytesTemp);
  4178. }
  4179. LEAVE_ENGINE();
  4180. return Status;
  4181. }
  4182. STDMETHODIMP
  4183. DebugClient::ReadPointersVirtual(
  4184. THIS_
  4185. IN ULONG Count,
  4186. IN ULONG64 Offset,
  4187. OUT /* size_is(Count) */ PULONG64 Ptrs
  4188. )
  4189. {
  4190. HRESULT Status;
  4191. ENTER_ENGINE();
  4192. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4193. {
  4194. Status = E_UNEXPECTED;
  4195. }
  4196. else
  4197. {
  4198. Status = S_OK;
  4199. while (Count-- > 0)
  4200. {
  4201. if ((Status = g_Target->
  4202. ReadPointer(g_Process, g_Machine, Offset, Ptrs)) != S_OK)
  4203. {
  4204. break;
  4205. }
  4206. Offset += g_Machine->m_Ptr64 ? sizeof(ULONG64) : sizeof(ULONG);
  4207. Ptrs++;
  4208. }
  4209. }
  4210. LEAVE_ENGINE();
  4211. return Status;
  4212. }
  4213. STDMETHODIMP
  4214. DebugClient::WritePointersVirtual(
  4215. THIS_
  4216. IN ULONG Count,
  4217. IN ULONG64 Offset,
  4218. IN /* size_is(Count) */ PULONG64 Ptrs
  4219. )
  4220. {
  4221. HRESULT Status;
  4222. ENTER_ENGINE();
  4223. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4224. {
  4225. Status = E_UNEXPECTED;
  4226. }
  4227. else
  4228. {
  4229. Status = S_OK;
  4230. while (Count-- > 0)
  4231. {
  4232. if ((Status = g_Target->
  4233. WritePointer(g_Process, g_Machine, Offset, *Ptrs)) != S_OK)
  4234. {
  4235. break;
  4236. }
  4237. Offset += g_Machine->m_Ptr64 ? sizeof(ULONG64) : sizeof(ULONG);
  4238. Ptrs++;
  4239. }
  4240. }
  4241. LEAVE_ENGINE();
  4242. return Status;
  4243. }
  4244. STDMETHODIMP
  4245. DebugClient::ReadPhysical(
  4246. THIS_
  4247. IN ULONG64 Offset,
  4248. OUT PVOID Buffer,
  4249. IN ULONG BufferSize,
  4250. OUT PULONG BytesRead
  4251. )
  4252. {
  4253. HRESULT Status;
  4254. ENTER_ENGINE();
  4255. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4256. {
  4257. Status = E_UNEXPECTED;
  4258. }
  4259. else
  4260. {
  4261. ULONG BytesTemp;
  4262. Status = g_Target->
  4263. ReadPhysical(Offset, Buffer, BufferSize,
  4264. PHYS_FLAG_DEFAULT,
  4265. BytesRead != NULL ? BytesRead : &BytesTemp);
  4266. }
  4267. LEAVE_ENGINE();
  4268. return Status;
  4269. }
  4270. STDMETHODIMP
  4271. DebugClient::WritePhysical(
  4272. THIS_
  4273. IN ULONG64 Offset,
  4274. IN PVOID Buffer,
  4275. IN ULONG BufferSize,
  4276. OUT PULONG BytesWritten
  4277. )
  4278. {
  4279. HRESULT Status;
  4280. ENTER_ENGINE();
  4281. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4282. {
  4283. Status = E_UNEXPECTED;
  4284. }
  4285. else
  4286. {
  4287. ULONG BytesTemp;
  4288. Status = g_Target->
  4289. WritePhysical(Offset, Buffer, BufferSize,
  4290. PHYS_FLAG_DEFAULT,
  4291. BytesWritten != NULL ? BytesWritten :
  4292. &BytesTemp);
  4293. }
  4294. LEAVE_ENGINE();
  4295. return Status;
  4296. }
  4297. STDMETHODIMP
  4298. DebugClient::ReadControl(
  4299. THIS_
  4300. IN ULONG Processor,
  4301. IN ULONG64 Offset,
  4302. OUT PVOID Buffer,
  4303. IN ULONG BufferSize,
  4304. OUT PULONG BytesRead
  4305. )
  4306. {
  4307. HRESULT Status;
  4308. ENTER_ENGINE();
  4309. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4310. {
  4311. Status = E_UNEXPECTED;
  4312. }
  4313. else
  4314. {
  4315. ULONG BytesTemp;
  4316. // KSPECIAL_REGISTER content is kept in control space
  4317. // so accessing control space may touch data that's
  4318. // cached in the current machine KSPECIAL_REGISTERS.
  4319. // Flush the current machine to maintain consistency.
  4320. g_Target->FlushRegContext();
  4321. Status = g_Target->
  4322. ReadControl(Processor, Offset, Buffer, BufferSize,
  4323. BytesRead != NULL ? BytesRead : &BytesTemp);
  4324. }
  4325. LEAVE_ENGINE();
  4326. return Status;
  4327. }
  4328. STDMETHODIMP
  4329. DebugClient::WriteControl(
  4330. THIS_
  4331. IN ULONG Processor,
  4332. IN ULONG64 Offset,
  4333. IN PVOID Buffer,
  4334. IN ULONG BufferSize,
  4335. OUT PULONG BytesWritten
  4336. )
  4337. {
  4338. HRESULT Status;
  4339. ENTER_ENGINE();
  4340. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4341. {
  4342. Status = E_UNEXPECTED;
  4343. }
  4344. else
  4345. {
  4346. ULONG BytesTemp;
  4347. // KSPECIAL_REGISTER content is kept in control space
  4348. // so accessing control space may touch data that's
  4349. // cached in the current machine KSPECIAL_REGISTERS.
  4350. // Flush the current machine to maintain consistency.
  4351. g_Target->FlushRegContext();
  4352. Status = g_Target->
  4353. WriteControl(Processor, Offset, Buffer, BufferSize,
  4354. BytesWritten != NULL ? BytesWritten :
  4355. &BytesTemp);
  4356. }
  4357. LEAVE_ENGINE();
  4358. return Status;
  4359. }
  4360. STDMETHODIMP
  4361. DebugClient::ReadIo(
  4362. THIS_
  4363. IN ULONG InterfaceType,
  4364. IN ULONG BusNumber,
  4365. IN ULONG AddressSpace,
  4366. IN ULONG64 Offset,
  4367. OUT PVOID Buffer,
  4368. IN ULONG BufferSize,
  4369. OUT PULONG BytesRead
  4370. )
  4371. {
  4372. HRESULT Status;
  4373. ENTER_ENGINE();
  4374. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4375. {
  4376. Status = E_UNEXPECTED;
  4377. }
  4378. else
  4379. {
  4380. ULONG BytesTemp;
  4381. Status = g_Target->
  4382. ReadIo(InterfaceType, BusNumber, AddressSpace,
  4383. Offset, Buffer, BufferSize,
  4384. BytesRead != NULL ? BytesRead : &BytesTemp);
  4385. }
  4386. LEAVE_ENGINE();
  4387. return Status;
  4388. }
  4389. STDMETHODIMP
  4390. DebugClient::WriteIo(
  4391. THIS_
  4392. IN ULONG InterfaceType,
  4393. IN ULONG BusNumber,
  4394. IN ULONG AddressSpace,
  4395. IN ULONG64 Offset,
  4396. IN PVOID Buffer,
  4397. IN ULONG BufferSize,
  4398. OUT PULONG BytesWritten
  4399. )
  4400. {
  4401. HRESULT Status;
  4402. ENTER_ENGINE();
  4403. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4404. {
  4405. Status = E_UNEXPECTED;
  4406. }
  4407. else
  4408. {
  4409. ULONG BytesTemp;
  4410. Status = g_Target->
  4411. WriteIo(InterfaceType, BusNumber, AddressSpace,
  4412. Offset, Buffer, BufferSize,
  4413. BytesWritten != NULL ? BytesWritten : &BytesTemp);
  4414. }
  4415. LEAVE_ENGINE();
  4416. return Status;
  4417. }
  4418. STDMETHODIMP
  4419. DebugClient::ReadMsr(
  4420. THIS_
  4421. IN ULONG Msr,
  4422. OUT PULONG64 Value
  4423. )
  4424. {
  4425. HRESULT Status;
  4426. ENTER_ENGINE();
  4427. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4428. {
  4429. Status = E_UNEXPECTED;
  4430. }
  4431. else
  4432. {
  4433. Status = g_Target->ReadMsr(Msr, Value);
  4434. }
  4435. LEAVE_ENGINE();
  4436. return Status;
  4437. }
  4438. STDMETHODIMP
  4439. DebugClient::WriteMsr(
  4440. THIS_
  4441. IN ULONG Msr,
  4442. IN ULONG64 Value
  4443. )
  4444. {
  4445. HRESULT Status;
  4446. ENTER_ENGINE();
  4447. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4448. {
  4449. Status = E_UNEXPECTED;
  4450. }
  4451. else
  4452. {
  4453. Status = g_Target->WriteMsr(Msr, Value);
  4454. }
  4455. LEAVE_ENGINE();
  4456. return Status;
  4457. }
  4458. STDMETHODIMP
  4459. DebugClient::ReadBusData(
  4460. THIS_
  4461. IN ULONG BusDataType,
  4462. IN ULONG BusNumber,
  4463. IN ULONG SlotNumber,
  4464. IN ULONG Offset,
  4465. OUT PVOID Buffer,
  4466. IN ULONG BufferSize,
  4467. OUT PULONG BytesRead
  4468. )
  4469. {
  4470. HRESULT Status;
  4471. ENTER_ENGINE();
  4472. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4473. {
  4474. Status = E_UNEXPECTED;
  4475. }
  4476. else
  4477. {
  4478. ULONG BytesTemp;
  4479. Status = g_Target->
  4480. ReadBusData(BusDataType, BusNumber, SlotNumber,
  4481. Offset, Buffer, BufferSize,
  4482. BytesRead != NULL ? BytesRead : &BytesTemp);
  4483. }
  4484. LEAVE_ENGINE();
  4485. return Status;
  4486. }
  4487. STDMETHODIMP
  4488. DebugClient::WriteBusData(
  4489. THIS_
  4490. IN ULONG BusDataType,
  4491. IN ULONG BusNumber,
  4492. IN ULONG SlotNumber,
  4493. IN ULONG Offset,
  4494. IN PVOID Buffer,
  4495. IN ULONG BufferSize,
  4496. OUT PULONG BytesWritten
  4497. )
  4498. {
  4499. HRESULT Status;
  4500. ENTER_ENGINE();
  4501. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4502. {
  4503. Status = E_UNEXPECTED;
  4504. }
  4505. else
  4506. {
  4507. ULONG BytesTemp;
  4508. Status = g_Target->
  4509. WriteBusData(BusDataType, BusNumber, SlotNumber,
  4510. Offset, Buffer, BufferSize,
  4511. BytesWritten != NULL ? BytesWritten :
  4512. &BytesTemp);
  4513. }
  4514. LEAVE_ENGINE();
  4515. return Status;
  4516. }
  4517. STDMETHODIMP
  4518. DebugClient::CheckLowMemory(
  4519. THIS
  4520. )
  4521. {
  4522. HRESULT Status;
  4523. ENTER_ENGINE();
  4524. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4525. {
  4526. Status = E_UNEXPECTED;
  4527. }
  4528. else
  4529. {
  4530. Status = g_Target->CheckLowMemory();
  4531. }
  4532. LEAVE_ENGINE();
  4533. return Status;
  4534. }
  4535. STDMETHODIMP
  4536. DebugClient::ReadDebuggerData(
  4537. THIS_
  4538. IN ULONG Index,
  4539. OUT PVOID Buffer,
  4540. IN ULONG BufferSize,
  4541. OUT OPTIONAL PULONG DataSize
  4542. )
  4543. {
  4544. HRESULT Status;
  4545. ENTER_ENGINE();
  4546. // Wait till the machine is accessible because on dump files the
  4547. // debugger data block requires symbols to be loaded.
  4548. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4549. {
  4550. Status = E_UNEXPECTED;
  4551. goto Exit;
  4552. }
  4553. PVOID Data;
  4554. ULONG Size;
  4555. ULONG64 DataSpace;
  4556. if (Index < sizeof(g_Target->m_KdDebuggerData))
  4557. {
  4558. // Even though internally all of the debugger data is
  4559. // a single buffer that could be read arbitrarily we
  4560. // restrict access to the defined constants to
  4561. // preserve the abstraction that each constant refers
  4562. // to a separate piece of data.
  4563. Data = (PUCHAR)&g_Target->m_KdDebuggerData + Index;
  4564. Size = sizeof(ULONG64);
  4565. if ((Index >= DEBUG_DATA_OffsetKThreadNextProcessor) &&
  4566. (Index <= DEBUG_DATA_SizeEThread))
  4567. {
  4568. Size = sizeof(USHORT);
  4569. }
  4570. else if (Index & (sizeof(ULONG64) - 1))
  4571. {
  4572. Status = E_INVALIDARG;
  4573. goto Exit;
  4574. }
  4575. }
  4576. else
  4577. {
  4578. switch(Index)
  4579. {
  4580. case DEBUG_DATA_PaeEnabled:
  4581. DataSpace = (BOOLEAN)g_Target->m_KdDebuggerData.PaeEnabled;
  4582. Data = &DataSpace;
  4583. Size = sizeof(BOOLEAN);
  4584. break;
  4585. case DEBUG_DATA_SharedUserData:
  4586. DataSpace = g_Target->m_TypeInfo.SharedUserDataOffset;
  4587. Data = &DataSpace;
  4588. Size = sizeof(ULONG64);
  4589. break;
  4590. case DEBUG_DATA_ProductType:
  4591. Data = &g_Target->m_ProductType;
  4592. Size = sizeof(g_Target->m_ProductType);
  4593. break;
  4594. case DEBUG_DATA_SuiteMask:
  4595. Data = &g_Target->m_SuiteMask;
  4596. Size = sizeof(g_Target->m_SuiteMask);
  4597. break;
  4598. default:
  4599. Status = E_INVALIDARG;
  4600. goto Exit;
  4601. }
  4602. }
  4603. Status = FillDataBuffer(Data, Size, Buffer, BufferSize, DataSize);
  4604. Exit:
  4605. LEAVE_ENGINE();
  4606. return Status;
  4607. }
  4608. STDMETHODIMP
  4609. DebugClient::ReadProcessorSystemData(
  4610. THIS_
  4611. IN ULONG Processor,
  4612. IN ULONG Index,
  4613. OUT PVOID Buffer,
  4614. IN ULONG BufferSize,
  4615. OUT OPTIONAL PULONG DataSize
  4616. )
  4617. {
  4618. HRESULT Status = S_OK;
  4619. PVOID Data;
  4620. ULONG Size;
  4621. ULONG64 DataSpace;
  4622. DEBUG_PROCESSOR_IDENTIFICATION_ALL AllId;
  4623. ENTER_ENGINE();
  4624. switch(Index)
  4625. {
  4626. case DEBUG_DATA_KPCR_OFFSET:
  4627. case DEBUG_DATA_KPRCB_OFFSET:
  4628. case DEBUG_DATA_KTHREAD_OFFSET:
  4629. if (!IS_MACHINE_SET(g_Target))
  4630. {
  4631. Status = E_UNEXPECTED;
  4632. }
  4633. else
  4634. {
  4635. Status = g_Target->
  4636. GetProcessorSystemDataOffset(Processor, Index, &DataSpace);
  4637. Data = &DataSpace;
  4638. Size = sizeof(DataSpace);
  4639. }
  4640. break;
  4641. case DEBUG_DATA_BASE_TRANSLATION_VIRTUAL_OFFSET:
  4642. if (!IS_MACHINE_SET(g_Target))
  4643. {
  4644. Status = E_UNEXPECTED;
  4645. }
  4646. else
  4647. {
  4648. Status = g_Machine->GetBaseTranslationVirtualOffset(&DataSpace);
  4649. Data = &DataSpace;
  4650. Size = sizeof(DataSpace);
  4651. }
  4652. break;
  4653. case DEBUG_DATA_PROCESSOR_IDENTIFICATION:
  4654. if (!g_Target)
  4655. {
  4656. Status = E_UNEXPECTED;
  4657. }
  4658. else
  4659. {
  4660. ZeroMemory(&AllId, sizeof(AllId));
  4661. Status = g_Target->GetProcessorId(Processor, &AllId);
  4662. Data = &AllId;
  4663. Size = sizeof(AllId);
  4664. }
  4665. break;
  4666. case DEBUG_DATA_PROCESSOR_SPEED:
  4667. if (!g_Target)
  4668. {
  4669. Status = E_UNEXPECTED;
  4670. }
  4671. else
  4672. {
  4673. DataSpace = 0;
  4674. Status = g_Target->
  4675. GetProcessorSpeed(Processor, (PULONG) &DataSpace);
  4676. Data = &DataSpace;
  4677. Size = sizeof(ULONG);
  4678. }
  4679. break;
  4680. default:
  4681. Status = E_INVALIDARG;
  4682. break;
  4683. }
  4684. if (Status == S_OK)
  4685. {
  4686. if (DataSize != NULL)
  4687. {
  4688. *DataSize = Size;
  4689. }
  4690. if (BufferSize < Size)
  4691. {
  4692. Status = S_FALSE;
  4693. Size = BufferSize;
  4694. }
  4695. memcpy(Buffer, Data, Size);
  4696. }
  4697. LEAVE_ENGINE();
  4698. return Status;
  4699. }
  4700. STDMETHODIMP
  4701. DebugClient::VirtualToPhysical(
  4702. THIS_
  4703. IN ULONG64 Virtual,
  4704. OUT PULONG64 Physical
  4705. )
  4706. {
  4707. HRESULT Status;
  4708. ENTER_ENGINE();
  4709. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4710. {
  4711. Status = E_UNEXPECTED;
  4712. }
  4713. else
  4714. {
  4715. ULONG Levels;
  4716. ULONG PfIndex;
  4717. Status = g_Machine->
  4718. GetVirtualTranslationPhysicalOffsets(g_Thread, Virtual, NULL, 0,
  4719. &Levels, &PfIndex, Physical);
  4720. // GVTPO returns a special error code if the translation
  4721. // succeeded down to the level of the actual data but
  4722. // the data page itself is in the page file. This is used
  4723. // for the page file dump support. To an external caller,
  4724. // though, it's not useful so translate it into the standard
  4725. // page-not-available error.
  4726. if (Status == HR_PAGE_IN_PAGE_FILE)
  4727. {
  4728. Status = HR_PAGE_NOT_AVAILABLE;
  4729. }
  4730. }
  4731. LEAVE_ENGINE();
  4732. return Status;
  4733. }
  4734. STDMETHODIMP
  4735. DebugClient::GetVirtualTranslationPhysicalOffsets(
  4736. THIS_
  4737. IN ULONG64 Virtual,
  4738. OUT OPTIONAL /* size_is(OffsetsSize) */ PULONG64 Offsets,
  4739. IN ULONG OffsetsSize,
  4740. OUT OPTIONAL PULONG Levels
  4741. )
  4742. {
  4743. HRESULT Status;
  4744. ENTER_ENGINE();
  4745. ULONG _Levels = 0;
  4746. if (!IS_CUR_MACHINE_ACCESSIBLE())
  4747. {
  4748. Status = E_UNEXPECTED;
  4749. }
  4750. else
  4751. {
  4752. ULONG PfIndex;
  4753. ULONG64 LastPhys;
  4754. Status = g_Machine->
  4755. GetVirtualTranslationPhysicalOffsets(g_Thread, Virtual, Offsets,
  4756. OffsetsSize, &_Levels,
  4757. &PfIndex, &LastPhys);
  4758. // GVTPO returns a special error code if the translation
  4759. // succeeded down to the level of the actual data but
  4760. // the data page itself is in the page file. This is used
  4761. // for the page file dump support. To an external caller,
  4762. // though, it's not useful so translate it into the standard
  4763. // page-not-available error.
  4764. if (Status == HR_PAGE_IN_PAGE_FILE)
  4765. {
  4766. Status = HR_PAGE_NOT_AVAILABLE;
  4767. }
  4768. // If no translations occurred return the given failure.
  4769. // If there was a failure but translations occurred return
  4770. // S_FALSE to indicate the translation was incomplete.
  4771. if (_Levels > 0 && Status != S_OK)
  4772. {
  4773. Status = S_FALSE;
  4774. }
  4775. }
  4776. if (Levels != NULL)
  4777. {
  4778. *Levels = _Levels;
  4779. }
  4780. LEAVE_ENGINE();
  4781. return Status;
  4782. }
  4783. STDMETHODIMP
  4784. DebugClient::ReadHandleData(
  4785. THIS_
  4786. IN ULONG64 Handle,
  4787. IN ULONG DataType,
  4788. OUT OPTIONAL PVOID Buffer,
  4789. IN ULONG BufferSize,
  4790. OUT OPTIONAL PULONG DataSize
  4791. )
  4792. {
  4793. HRESULT Status;
  4794. ENTER_ENGINE();
  4795. if (!g_Process)
  4796. {
  4797. Status = E_UNEXPECTED;
  4798. }
  4799. else
  4800. {
  4801. Status = g_Target->ReadHandleData(g_Process, Handle, DataType, Buffer,
  4802. BufferSize, DataSize);
  4803. }
  4804. LEAVE_ENGINE();
  4805. return Status;
  4806. }
  4807. STDMETHODIMP
  4808. DebugClient::FillVirtual(
  4809. THIS_
  4810. IN ULONG64 Start,
  4811. IN ULONG Size,
  4812. IN PVOID Pattern,
  4813. IN ULONG PatternSize,
  4814. OUT OPTIONAL PULONG Filled
  4815. )
  4816. {
  4817. HRESULT Status;
  4818. ENTER_ENGINE();
  4819. if (PatternSize == 0)
  4820. {
  4821. Status = E_INVALIDARG;
  4822. }
  4823. else if (!g_Target || !g_Process)
  4824. {
  4825. Status = E_UNEXPECTED;
  4826. }
  4827. else
  4828. {
  4829. ULONG _Filled = 0;
  4830. Status = g_Target->FillVirtual(g_Process,
  4831. Start, Size, Pattern, PatternSize,
  4832. &_Filled);
  4833. if (Filled != NULL)
  4834. {
  4835. *Filled = _Filled;
  4836. }
  4837. }
  4838. LEAVE_ENGINE();
  4839. return Status;
  4840. }
  4841. STDMETHODIMP
  4842. DebugClient::FillPhysical(
  4843. THIS_
  4844. IN ULONG64 Start,
  4845. IN ULONG Size,
  4846. IN PVOID Pattern,
  4847. IN ULONG PatternSize,
  4848. OUT OPTIONAL PULONG Filled
  4849. )
  4850. {
  4851. HRESULT Status;
  4852. ENTER_ENGINE();
  4853. if (PatternSize == 0)
  4854. {
  4855. Status = E_INVALIDARG;
  4856. }
  4857. else if (!g_Target)
  4858. {
  4859. Status = E_UNEXPECTED;
  4860. }
  4861. else
  4862. {
  4863. ULONG _Filled = 0;
  4864. Status = g_Target->
  4865. FillPhysical(Start, Size, Pattern, PatternSize, &_Filled);
  4866. if (Filled != NULL)
  4867. {
  4868. *Filled = _Filled;
  4869. }
  4870. }
  4871. LEAVE_ENGINE();
  4872. return Status;
  4873. }
  4874. STDMETHODIMP
  4875. DebugClient::QueryVirtual(
  4876. THIS_
  4877. IN ULONG64 Offset,
  4878. OUT PMEMORY_BASIC_INFORMATION64 Info
  4879. )
  4880. {
  4881. HRESULT Status;
  4882. ENTER_ENGINE();
  4883. if (!g_Target || !g_Process)
  4884. {
  4885. Status = E_UNEXPECTED;
  4886. }
  4887. else if (!IS_USER_TARGET(g_Target))
  4888. {
  4889. return E_NOTIMPL;
  4890. }
  4891. else
  4892. {
  4893. ULONG64 Handle = Offset;
  4894. Status = g_Target->QueryMemoryRegion(g_Process, &Handle, TRUE, Info);
  4895. }
  4896. LEAVE_ENGINE();
  4897. return Status;
  4898. }
  4899. STDMETHODIMP
  4900. DebugClient::ReadImageNtHeaders(
  4901. THIS_
  4902. IN ULONG64 ImageBase,
  4903. OUT PIMAGE_NT_HEADERS64 Headers
  4904. )
  4905. {
  4906. HRESULT Status;
  4907. ENTER_ENGINE();
  4908. if (!g_Target || !g_Process)
  4909. {
  4910. Status = E_UNEXPECTED;
  4911. }
  4912. else
  4913. {
  4914. Status = g_Target->ReadImageNtHeaders(g_Process, ImageBase, Headers);
  4915. }
  4916. LEAVE_ENGINE();
  4917. return Status;
  4918. }
  4919. HRESULT
  4920. GetFirstBlobHeaderOffset(PULONG64 OffsetRet)
  4921. {
  4922. HRESULT Status;
  4923. ULONG64 Offset;
  4924. DUMP_BLOB_FILE_HEADER FileHdr;
  4925. if ((Status = g_Target->
  4926. GetTaggedBaseOffset(&Offset)) != S_OK ||
  4927. (Status = g_Target->
  4928. ReadTagged(Offset, &FileHdr, sizeof(FileHdr))) != S_OK)
  4929. {
  4930. return Status;
  4931. }
  4932. if (FileHdr.Signature1 != DUMP_BLOB_SIGNATURE1 ||
  4933. FileHdr.Signature2 != DUMP_BLOB_SIGNATURE2)
  4934. {
  4935. // No blob data.
  4936. return E_NOINTERFACE;
  4937. }
  4938. if (FileHdr.HeaderSize != sizeof(FileHdr))
  4939. {
  4940. return HR_DATA_CORRUPT;
  4941. }
  4942. *OffsetRet = Offset + FileHdr.HeaderSize;
  4943. return S_OK;
  4944. }
  4945. HRESULT
  4946. ReadBlobHeaderAtOffset(ULONG64 Offset, PDUMP_BLOB_HEADER BlobHdr)
  4947. {
  4948. HRESULT Status;
  4949. if ((Status = g_Target->
  4950. ReadTagged(Offset, BlobHdr, sizeof(*BlobHdr))) != S_OK)
  4951. {
  4952. return Status;
  4953. }
  4954. if (BlobHdr->HeaderSize != sizeof(*BlobHdr))
  4955. {
  4956. return HR_DATA_CORRUPT;
  4957. }
  4958. return S_OK;
  4959. }
  4960. STDMETHODIMP
  4961. DebugClient::ReadTagged(
  4962. THIS_
  4963. IN LPGUID Tag,
  4964. IN ULONG Offset,
  4965. OUT OPTIONAL PVOID Buffer,
  4966. IN ULONG BufferSize,
  4967. OUT OPTIONAL PULONG TotalSize
  4968. )
  4969. {
  4970. HRESULT Status;
  4971. ENTER_ENGINE();
  4972. if (!g_Target)
  4973. {
  4974. Status = E_UNEXPECTED;
  4975. goto Exit;
  4976. }
  4977. ULONG64 HdrOffs;
  4978. DUMP_BLOB_HEADER BlobHdr;
  4979. if ((Status = GetFirstBlobHeaderOffset(&HdrOffs)) != S_OK)
  4980. {
  4981. goto Exit;
  4982. }
  4983. for (;;)
  4984. {
  4985. if ((Status = ReadBlobHeaderAtOffset(HdrOffs, &BlobHdr)) != S_OK)
  4986. {
  4987. // There's no way to know whether a blob should
  4988. // be present or not so all failures just turn
  4989. // into blob-not-present.
  4990. Status = E_NOINTERFACE;
  4991. goto Exit;
  4992. }
  4993. HdrOffs += BlobHdr.HeaderSize + BlobHdr.PrePad;
  4994. if (DbgIsEqualIID(*Tag, BlobHdr.Tag))
  4995. {
  4996. break;
  4997. }
  4998. HdrOffs += BlobHdr.DataSize + BlobHdr.PostPad;
  4999. }
  5000. if (Offset >= BlobHdr.DataSize)
  5001. {
  5002. Status = E_INVALIDARG;
  5003. goto Exit;
  5004. }
  5005. if (TotalSize)
  5006. {
  5007. *TotalSize = BlobHdr.DataSize;
  5008. }
  5009. if (Buffer)
  5010. {
  5011. if (BufferSize > BlobHdr.DataSize)
  5012. {
  5013. BufferSize = BlobHdr.DataSize;
  5014. }
  5015. Status = g_Target->ReadTagged(HdrOffs + Offset, Buffer, BufferSize);
  5016. }
  5017. else
  5018. {
  5019. Status = S_OK;
  5020. }
  5021. Exit:
  5022. LEAVE_ENGINE();
  5023. return Status;
  5024. }
  5025. struct TaggedEnum
  5026. {
  5027. ULONG64 Offset;
  5028. };
  5029. STDMETHODIMP
  5030. DebugClient::StartEnumTagged(
  5031. THIS_
  5032. OUT PULONG64 Handle
  5033. )
  5034. {
  5035. HRESULT Status;
  5036. ENTER_ENGINE();
  5037. TaggedEnum* Enum;
  5038. if (!g_Target)
  5039. {
  5040. Status = E_UNEXPECTED;
  5041. }
  5042. else if (!(Enum = new TaggedEnum))
  5043. {
  5044. Status = E_OUTOFMEMORY;
  5045. }
  5046. else
  5047. {
  5048. Status = GetFirstBlobHeaderOffset(&Enum->Offset);
  5049. if (Status == S_OK)
  5050. {
  5051. *Handle = (ULONG64)(ULONG_PTR)Enum;
  5052. }
  5053. else
  5054. {
  5055. delete Enum;
  5056. }
  5057. }
  5058. LEAVE_ENGINE();
  5059. return Status;
  5060. }
  5061. STDMETHODIMP
  5062. DebugClient::GetNextTagged(
  5063. THIS_
  5064. IN ULONG64 Handle,
  5065. OUT LPGUID Tag,
  5066. OUT PULONG Size
  5067. )
  5068. {
  5069. HRESULT Status;
  5070. ENTER_ENGINE();
  5071. TaggedEnum* Enum = (TaggedEnum*)(ULONG_PTR)Handle;
  5072. DUMP_BLOB_HEADER BlobHdr;
  5073. if (!g_Target)
  5074. {
  5075. Status = E_UNEXPECTED;
  5076. }
  5077. else if ((Status = ReadBlobHeaderAtOffset(Enum->Offset,
  5078. &BlobHdr)) != S_OK)
  5079. {
  5080. // There's no way to know whether a blob should
  5081. // be present or not so all failures just turn
  5082. // into blob-not-present.
  5083. Status = S_FALSE;
  5084. ZeroMemory(Tag, sizeof(*Tag));
  5085. *Size = 0;
  5086. }
  5087. else
  5088. {
  5089. *Tag = BlobHdr.Tag;
  5090. *Size = BlobHdr.DataSize;
  5091. Enum->Offset += BlobHdr.HeaderSize + BlobHdr.PrePad +
  5092. BlobHdr.DataSize + BlobHdr.PostPad;
  5093. }
  5094. LEAVE_ENGINE();
  5095. return Status;
  5096. }
  5097. STDMETHODIMP
  5098. DebugClient::EndEnumTagged(
  5099. THIS_
  5100. IN ULONG64 Handle
  5101. )
  5102. {
  5103. HRESULT Status;
  5104. ENTER_ENGINE();
  5105. if (!g_Target)
  5106. {
  5107. Status = E_UNEXPECTED;
  5108. }
  5109. else
  5110. {
  5111. delete (TaggedEnum*)(ULONG_PTR)Handle;
  5112. Status = S_OK;
  5113. }
  5114. LEAVE_ENGINE();
  5115. return Status;
  5116. }