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

3695 lines
88 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // IDebugDataSpaces implementations.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999-2001.
  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 = (Offset + g_TargetMachine->m_PageSize) &
  26. ~((ULONG64)g_TargetMachine->m_PageSize - 1);
  27. if (NextOffset != NULL)
  28. {
  29. *NextOffset = Page;
  30. }
  31. if (NextPage != NULL)
  32. {
  33. *NextPage = Page;
  34. }
  35. }
  36. HRESULT
  37. TargetInfo::ReadVirtualUncached(
  38. THIS_
  39. IN ULONG64 Offset,
  40. OUT PVOID Buffer,
  41. IN ULONG BufferSize,
  42. OUT PULONG BytesRead
  43. )
  44. {
  45. return ReadVirtual(Offset, Buffer, BufferSize, BytesRead);
  46. }
  47. HRESULT
  48. TargetInfo::WriteVirtualUncached(
  49. THIS_
  50. IN ULONG64 Offset,
  51. IN PVOID Buffer,
  52. IN ULONG BufferSize,
  53. OUT PULONG BytesWritten
  54. )
  55. {
  56. return WriteVirtual(Offset, Buffer, BufferSize, BytesWritten);
  57. }
  58. // #define DBG_SEARCH
  59. HRESULT
  60. TargetInfo::SearchVirtual(
  61. IN ULONG64 Offset,
  62. IN ULONG64 Length,
  63. IN PVOID Pattern,
  64. IN ULONG PatternSize,
  65. IN ULONG PatternGranularity,
  66. OUT PULONG64 MatchOffset
  67. )
  68. {
  69. HRESULT Status;
  70. ULONG64 SearchEnd;
  71. UCHAR Buffer[4096];
  72. PUCHAR Buf, Pat, BufEnd, PatEnd;
  73. ULONG ReadLen;
  74. ULONG64 BufOffset;
  75. ULONG64 PatOffset;
  76. ULONG64 StartOffset;
  77. SearchEnd = Offset + Length;
  78. Buf = Buffer;
  79. BufEnd = Buffer;
  80. Pat = (PUCHAR)Pattern;
  81. PatEnd = Pat + PatternSize;
  82. ReadLen = Length < sizeof(Buffer) ? (ULONG)Length : sizeof(Buffer);
  83. BufOffset = Offset;
  84. PatOffset = Offset;
  85. StartOffset = Offset;
  86. #ifdef DBG_SEARCH
  87. g_NtDllCalls.DbgPrint("Search %d bytes from %I64X to %I64X, gran %X\n",
  88. PatternSize, Offset, SearchEnd - 1,
  89. Granularity);
  90. #endif
  91. for (;;)
  92. {
  93. #ifdef DBG_SEARCH_VERBOSE
  94. g_NtDllCalls.DbgPrint(" %I64X: matched %d\n",
  95. Offset + (Buf - Buffer),
  96. (ULONG)(Pat - (PUCHAR)Pattern));
  97. #endif
  98. if (Pat == PatEnd)
  99. {
  100. // Made it to the end of the pattern so there's
  101. // a match.
  102. *MatchOffset = PatOffset;
  103. Status = S_OK;
  104. break;
  105. }
  106. if (Buf >= BufEnd)
  107. {
  108. ULONG Read;
  109. // Ran out of buffered memory so get some more.
  110. for (;;)
  111. {
  112. if (CheckUserInterrupt())
  113. {
  114. dprintf("User interrupt during memory search - "
  115. "exiting.\n");
  116. Status = HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT);
  117. goto Exit;
  118. }
  119. if (Offset >= SearchEnd)
  120. {
  121. // Return a result code that's specific and
  122. // consistent with the kernel version.
  123. Status = HRESULT_FROM_NT(STATUS_NO_MORE_ENTRIES);
  124. goto Exit;
  125. }
  126. Status = ReadVirtual(Offset, Buffer, ReadLen, &Read);
  127. #ifdef DBG_SEARCH
  128. g_NtDllCalls.DbgPrint(" Read %X bytes at %I64X, ret %X:%X\n",
  129. ReadLen, Offset,
  130. Status, Read);
  131. #endif
  132. if (Status != S_OK)
  133. {
  134. // Skip to the start of the next page.
  135. NearestDifferentlyValidOffsets(Offset, NULL, &Offset);
  136. // Restart search due to the address discontinuity.
  137. Pat = (PUCHAR)Pattern;
  138. PatOffset = Offset;
  139. }
  140. else
  141. {
  142. break;
  143. }
  144. }
  145. Buf = Buffer;
  146. BufEnd = Buffer + Read;
  147. BufOffset = Offset;
  148. Offset += Read;
  149. }
  150. // If this is the first byte of the pattern it
  151. // must match on a granularity boundary.
  152. if (*Buf++ == *Pat &&
  153. (Pat != (PUCHAR)Pattern ||
  154. (((PatOffset - StartOffset) % PatternGranularity) == 0)))
  155. {
  156. Pat++;
  157. }
  158. else
  159. {
  160. Buf -= Pat - (PUCHAR)Pattern;
  161. Pat = (PUCHAR)Pattern;
  162. PatOffset = BufOffset + (Buf - Buffer);
  163. }
  164. }
  165. Exit:
  166. return Status;
  167. }
  168. HRESULT
  169. TargetInfo::ReadPhysicalUncached(
  170. THIS_
  171. IN ULONG64 Offset,
  172. OUT PVOID Buffer,
  173. IN ULONG BufferSize,
  174. OUT PULONG BytesRead
  175. )
  176. {
  177. return ReadPhysical(Offset, Buffer, BufferSize, BytesRead);
  178. }
  179. HRESULT
  180. TargetInfo::WritePhysicalUncached(
  181. THIS_
  182. IN ULONG64 Offset,
  183. IN PVOID Buffer,
  184. IN ULONG BufferSize,
  185. OUT PULONG BytesWritten
  186. )
  187. {
  188. return WritePhysical(Offset, Buffer, BufferSize, BytesWritten);
  189. }
  190. HRESULT
  191. TargetInfo::FillVirtual(
  192. THIS_
  193. IN ULONG64 Start,
  194. IN ULONG Size,
  195. IN PVOID Pattern,
  196. IN ULONG PatternSize,
  197. OUT PULONG Filled
  198. )
  199. {
  200. HRESULT Status = S_OK;
  201. PUCHAR Pat = (PUCHAR)Pattern;
  202. PUCHAR PatEnd = Pat + PatternSize;
  203. *Filled = 0;
  204. while (Size-- > 0)
  205. {
  206. ULONG Done;
  207. if (CheckUserInterrupt())
  208. {
  209. dprintf("User interrupt during fill - exiting.\n");
  210. Status = HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT);
  211. *Filled = 0;
  212. break;
  213. }
  214. if ((Status = WriteVirtual(Start, Pat, 1, &Done)) != S_OK)
  215. {
  216. break;
  217. }
  218. if (Done != 1)
  219. {
  220. Status = HRESULT_FROM_WIN32(ERROR_WRITE_FAULT);
  221. break;
  222. }
  223. Start++;
  224. if (++Pat == PatEnd)
  225. {
  226. Pat = (PUCHAR)Pattern;
  227. }
  228. (*Filled)++;
  229. }
  230. // If nothing was filled return an error, otherwise
  231. // consider it a success.
  232. return *Filled > 0 ? S_OK : Status;
  233. }
  234. HRESULT
  235. TargetInfo::FillPhysical(
  236. THIS_
  237. IN ULONG64 Start,
  238. IN ULONG Size,
  239. IN PVOID Pattern,
  240. IN ULONG PatternSize,
  241. OUT PULONG Filled
  242. )
  243. {
  244. HRESULT Status = S_OK;
  245. PUCHAR Pat = (PUCHAR)Pattern;
  246. PUCHAR PatEnd = Pat + PatternSize;
  247. *Filled = 0;
  248. while (Size-- > 0)
  249. {
  250. ULONG Done;
  251. if (CheckUserInterrupt())
  252. {
  253. dprintf("User interrupt during fill - exiting.\n");
  254. Status = HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT);
  255. *Filled = 0;
  256. break;
  257. }
  258. if ((Status = WritePhysical(Start, Pat, 1, &Done)) != S_OK)
  259. {
  260. break;
  261. }
  262. if (Done != 1)
  263. {
  264. Status = HRESULT_FROM_WIN32(ERROR_WRITE_FAULT);
  265. break;
  266. }
  267. Start++;
  268. if (++Pat == PatEnd)
  269. {
  270. Pat = (PUCHAR)Pattern;
  271. }
  272. (*Filled)++;
  273. }
  274. // If nothing was filled return an error, otherwise
  275. // consider it a success.
  276. return *Filled > 0 ? S_OK : Status;
  277. }
  278. HRESULT
  279. TargetInfo::GetProcessorId(ULONG Processor,
  280. PDEBUG_PROCESSOR_IDENTIFICATION_ALL Id)
  281. {
  282. // Base implementation which silently fails for modes
  283. // where the ID cannot be retrieved.
  284. return E_UNEXPECTED;
  285. }
  286. HRESULT
  287. TargetInfo::ReadPageFile(ULONG PfIndex, ULONG64 PfOffset,
  288. PVOID Buffer, ULONG Size)
  289. {
  290. // Default implementation for targets which do not
  291. // support reading the page file.
  292. return HR_PAGE_NOT_AVAILABLE;
  293. }
  294. HRESULT
  295. TargetInfo::GetFunctionTableListHead(void)
  296. {
  297. // Get the address of the dynamic function table list head which is the
  298. // the same for all processes. This only has to be done once.
  299. if (g_CurrentProcess->DynFuncTableList)
  300. {
  301. return S_OK;
  302. }
  303. GetOffsetFromSym("ntdll!RtlpDynamicFunctionTable",
  304. &g_CurrentProcess->DynFuncTableList, NULL);
  305. if (!g_CurrentProcess->DynFuncTableList)
  306. {
  307. // No error message here as it's a common case when
  308. // symbols are bad.
  309. return E_NOINTERFACE;
  310. }
  311. return S_OK;
  312. }
  313. // These procedures support dynamic function table entries for user-mode
  314. // run-time code. Dynamic function tables are stored in a linked list
  315. // inside ntdll. The address of the linked list head is returned by
  316. // RtlGetFunctionTableListHead. Since dynamic function tables are
  317. // only supported in user-mode the address of the list head will be
  318. // the same in all processes. Dynamic function tables are very rare,
  319. // so in most cases this the list will be unitialized and this routine
  320. // will return NULL. dbghelp only calls this when it
  321. // is unable to find a function entry in any of the images.
  322. PVOID
  323. TargetInfo::FindDynamicFunctionEntry(MachineInfo* Machine, ULONG64 Address)
  324. {
  325. LIST_ENTRY64 DynamicFunctionTableHead;
  326. ULONG64 Entry;
  327. if (GetFunctionTableListHead() != S_OK)
  328. {
  329. return NULL;
  330. }
  331. // Read the dynamic function table list head
  332. if (ReadListEntry(Machine,
  333. g_CurrentProcess->DynFuncTableList,
  334. &DynamicFunctionTableHead) != S_OK)
  335. {
  336. // This failure happens almost all the time in minidumps
  337. // because the function table list symbol can be resolved
  338. // but the memory isn't part of the minidump.
  339. if (!IS_USER_MINI_DUMP())
  340. {
  341. ErrOut("Unable to read dynamic function table list head\n");
  342. }
  343. return NULL;
  344. }
  345. Entry = DynamicFunctionTableHead.Flink;
  346. // The list head is initialized the first time it's used so check
  347. // for an uninitialized pointers. This is the most common result.
  348. if (Entry == 0)
  349. {
  350. return NULL;
  351. }
  352. // Loop through the dynamic function table list reading the headers.
  353. // If the range of a dynamic function table contains Address then
  354. // search the function table. Dynamic function table ranges are not
  355. // mututally exclusive like those in images so an address may be
  356. // in more than one range. However, there can be only one dynamic function
  357. // entry that contains the address (if there are any at all).
  358. while (Entry != g_CurrentProcess->DynFuncTableList)
  359. {
  360. ULONG64 Table, MinAddress, MaxAddress, BaseAddress, TableData;
  361. ULONG TableSize;
  362. WCHAR OutOfProcessDll[MAX_PATH];
  363. CROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE RawTable;
  364. PVOID FunctionTable;
  365. PVOID FunctionEntry;
  366. Table = Entry;
  367. if (Machine->ReadDynamicFunctionTable(Table, &Entry,
  368. &MinAddress, &MaxAddress,
  369. &BaseAddress,
  370. &TableData, &TableSize,
  371. OutOfProcessDll,
  372. &RawTable) != S_OK)
  373. {
  374. ErrOut("Unable to read dynamic function table entry\n");
  375. continue;
  376. }
  377. if (Address >= MinAddress && Address < MaxAddress &&
  378. (OutOfProcessDll[0] ||
  379. (TableData && TableSize > 0)))
  380. {
  381. if (OutOfProcessDll[0])
  382. {
  383. if (ReadOutOfProcessDynamicFunctionTable
  384. (OutOfProcessDll, Table, &TableSize,
  385. &FunctionTable) != S_OK)
  386. {
  387. ErrOut("Unable to read dynamic function table entries\n");
  388. continue;
  389. }
  390. }
  391. else
  392. {
  393. FunctionTable = malloc(TableSize);
  394. if (FunctionTable == NULL)
  395. {
  396. ErrOut("Unable to allocate memory for "
  397. "dynamic function table\n");
  398. continue;
  399. }
  400. // Read the dynamic function table
  401. if (ReadAllVirtual(TableData, FunctionTable,
  402. TableSize) != S_OK)
  403. {
  404. ErrOut("Unable to read dynamic function table entries\n");
  405. free(FunctionTable);
  406. continue;
  407. }
  408. }
  409. FunctionEntry = Machine->
  410. FindDynamicFunctionEntry(&RawTable, Address,
  411. FunctionTable, TableSize);
  412. free(FunctionTable);
  413. if (FunctionEntry)
  414. {
  415. return FunctionEntry;
  416. }
  417. }
  418. }
  419. return NULL;
  420. }
  421. ULONG64
  422. TargetInfo::GetDynamicFunctionTableBase(MachineInfo* Machine,
  423. ULONG64 Address)
  424. {
  425. LIST_ENTRY64 ListHead;
  426. ULONG64 Entry;
  427. // If the process dynamic function table list head hasn't
  428. // been looked up yet that means that no dynamic function
  429. // table entry could be in use yet, so there's no need to look.
  430. if (!g_CurrentProcess->DynFuncTableList)
  431. {
  432. return 0;
  433. }
  434. if (ReadListEntry(Machine, g_CurrentProcess->DynFuncTableList,
  435. &ListHead) != S_OK)
  436. {
  437. return 0;
  438. }
  439. Entry = ListHead.Flink;
  440. // The list head is initialized the first time it's used so check
  441. // for an uninitialized pointers. This is the most common result.
  442. if (Entry == 0)
  443. {
  444. return 0;
  445. }
  446. // Loop through the dynamic function table list reading the headers.
  447. // If the range of a dynamic function table contains Address then
  448. // return the function table's base.
  449. while (Entry != g_CurrentProcess->DynFuncTableList)
  450. {
  451. ULONG64 MinAddress, MaxAddress, BaseAddress, TableData;
  452. ULONG TableSize;
  453. WCHAR OutOfProcessDll[MAX_PATH];
  454. CROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE RawTable;
  455. if (Machine->ReadDynamicFunctionTable(Entry, &Entry,
  456. &MinAddress, &MaxAddress,
  457. &BaseAddress,
  458. &TableData, &TableSize,
  459. OutOfProcessDll,
  460. &RawTable) == S_OK &&
  461. Address >= MinAddress &&
  462. Address < MaxAddress)
  463. {
  464. return BaseAddress;
  465. }
  466. }
  467. return 0;
  468. }
  469. HRESULT
  470. TargetInfo::ReadOutOfProcessDynamicFunctionTable(PWSTR Dll,
  471. ULONG64 Table,
  472. PULONG TableSize,
  473. PVOID* TableData)
  474. {
  475. // Empty base implementation to avoid error messages
  476. // that would be produced by an UNEXPECTED_HR implementation.
  477. return E_UNEXPECTED;
  478. }
  479. PVOID CALLBACK
  480. TargetInfo::DynamicFunctionTableCallback(HANDLE Process,
  481. ULONG64 Address,
  482. ULONG64 Context)
  483. {
  484. DBG_ASSERT(Process == g_CurrentProcess->Handle);
  485. return g_Target->FindDynamicFunctionEntry((MachineInfo*)Context,
  486. Address);
  487. }
  488. HRESULT
  489. TargetInfo::QueryAddressInformation(ULONG64 Address, ULONG InSpace,
  490. PULONG OutSpace, PULONG OutFlags)
  491. {
  492. // Default implementation which just returns the
  493. // least restrictive settings.
  494. *OutSpace = IS_KERNEL_TARGET() ?
  495. DBGKD_QUERY_MEMORY_KERNEL : DBGKD_QUERY_MEMORY_PROCESS;
  496. *OutFlags =
  497. DBGKD_QUERY_MEMORY_READ |
  498. DBGKD_QUERY_MEMORY_WRITE |
  499. DBGKD_QUERY_MEMORY_EXECUTE;
  500. return S_OK;
  501. }
  502. HRESULT
  503. TargetInfo::ReadPointer(
  504. MachineInfo* Machine,
  505. ULONG64 Address,
  506. PULONG64 Pointer64
  507. )
  508. {
  509. HRESULT Status;
  510. ULONG Result;
  511. ULONG SizeToRead;
  512. ULONG Pointer32;
  513. if (Machine->m_Ptr64)
  514. {
  515. SizeToRead = sizeof(ULONG64);
  516. Status = ReadVirtual(Address, Pointer64, SizeToRead, &Result);
  517. }
  518. else
  519. {
  520. SizeToRead = sizeof(ULONG32);
  521. Status = ReadVirtual(Address, &Pointer32, SizeToRead, &Result);
  522. *Pointer64 = EXTEND64(Pointer32);
  523. }
  524. if (Status != S_OK)
  525. {
  526. return Status;
  527. }
  528. if (Result != SizeToRead)
  529. {
  530. return E_FAIL;
  531. }
  532. return S_OK;
  533. }
  534. HRESULT
  535. TargetInfo::WritePointer(
  536. MachineInfo* Machine,
  537. ULONG64 Address,
  538. ULONG64 Pointer64
  539. )
  540. {
  541. HRESULT Status;
  542. ULONG Result;
  543. ULONG SizeToWrite;
  544. ULONG Pointer32;
  545. if (Machine->m_Ptr64)
  546. {
  547. SizeToWrite = sizeof(ULONG64);
  548. Status = WriteVirtual(Address, &Pointer64, SizeToWrite, &Result);
  549. }
  550. else
  551. {
  552. SizeToWrite = sizeof(ULONG32);
  553. Pointer32 = (ULONG)Pointer64;
  554. Status = WriteVirtual(Address, &Pointer32, SizeToWrite, &Result);
  555. }
  556. if (Status != S_OK)
  557. {
  558. return Status;
  559. }
  560. if (Result != SizeToWrite)
  561. {
  562. return HRESULT_FROM_WIN32(ERROR_WRITE_FAULT);
  563. }
  564. return S_OK;
  565. }
  566. HRESULT
  567. TargetInfo::ReadListEntry(
  568. MachineInfo* Machine,
  569. ULONG64 Address,
  570. PLIST_ENTRY64 List64
  571. )
  572. {
  573. HRESULT Status;
  574. ULONG Result;
  575. ULONG SizeToRead;
  576. LIST_ENTRY32 List32;
  577. if (Machine->m_Ptr64)
  578. {
  579. SizeToRead = sizeof(LIST_ENTRY64);
  580. Status = ReadVirtual(Address, List64, SizeToRead, &Result);
  581. }
  582. else
  583. {
  584. SizeToRead = sizeof(LIST_ENTRY32);
  585. Status = ReadVirtual(Address, &List32, SizeToRead, &Result);
  586. }
  587. if (Status != S_OK)
  588. {
  589. return Status;
  590. }
  591. if (Result != SizeToRead)
  592. {
  593. return E_FAIL;
  594. }
  595. if (!Machine->m_Ptr64)
  596. {
  597. List64->Flink = EXTEND64(List32.Flink);
  598. List64->Blink = EXTEND64(List32.Blink);
  599. }
  600. return S_OK;
  601. }
  602. void
  603. ConvertLoaderEntry32To64(
  604. PKLDR_DATA_TABLE_ENTRY32 b32,
  605. PKLDR_DATA_TABLE_ENTRY64 b64
  606. )
  607. {
  608. #define COPYSE2(p64,s32,f) p64->f = (ULONG64)(LONG64)(LONG)s32->f
  609. COPYSE2(b64,b32,InLoadOrderLinks.Flink);
  610. COPYSE2(b64,b32,InLoadOrderLinks.Blink);
  611. COPYSE2(b64,b32,__Undefined1);
  612. COPYSE2(b64,b32,__Undefined2);
  613. COPYSE2(b64,b32,__Undefined3);
  614. COPYSE2(b64,b32,NonPagedDebugInfo);
  615. COPYSE2(b64,b32,DllBase);
  616. COPYSE2(b64,b32,EntryPoint);
  617. b64->SizeOfImage = b32->SizeOfImage;
  618. b64->FullDllName.Length = b32->FullDllName.Length;
  619. b64->FullDllName.MaximumLength = b32->FullDllName.MaximumLength;
  620. COPYSE2(b64,b32,FullDllName.Buffer);
  621. b64->BaseDllName.Length = b32->BaseDllName.Length;
  622. b64->BaseDllName.MaximumLength = b32->BaseDllName.MaximumLength;
  623. COPYSE2(b64,b32,BaseDllName.Buffer);
  624. b64->Flags = b32->Flags;
  625. b64->LoadCount = b32->LoadCount;
  626. b64->__Undefined5 = b32->__Undefined5;
  627. COPYSE2(b64,b32,__Undefined6);
  628. b64->CheckSum = b32->CheckSum;
  629. b64->TimeDateStamp = b32->TimeDateStamp;
  630. #undef COPYSE2
  631. return;
  632. }
  633. HRESULT
  634. TargetInfo::ReadLoaderEntry(
  635. MachineInfo* Machine,
  636. ULONG64 Address,
  637. PKLDR_DATA_TABLE_ENTRY64 Entry
  638. )
  639. {
  640. HRESULT Status;
  641. ULONG Result;
  642. ULONG SizeToRead;
  643. KLDR_DATA_TABLE_ENTRY32 Ent32;
  644. if (Machine->m_Ptr64)
  645. {
  646. SizeToRead = sizeof(KLDR_DATA_TABLE_ENTRY64);
  647. Status = ReadVirtual(Address, Entry, SizeToRead, &Result);
  648. }
  649. else
  650. {
  651. SizeToRead = sizeof(KLDR_DATA_TABLE_ENTRY32);
  652. Status = ReadVirtual(Address, &Ent32, SizeToRead, &Result);
  653. ConvertLoaderEntry32To64(&Ent32, Entry);
  654. }
  655. if (Status != S_OK)
  656. {
  657. return Status;
  658. }
  659. if (Result != SizeToRead)
  660. {
  661. return E_FAIL;
  662. }
  663. return S_OK;
  664. }
  665. HRESULT
  666. TargetInfo::ReadUnicodeString(MachineInfo* Machine,
  667. ULONG64 Address, PUNICODE_STRING64 String)
  668. {
  669. HRESULT Status;
  670. ULONG Result;
  671. ULONG SizeToRead;
  672. UNICODE_STRING32 Str32;
  673. if (Machine->m_Ptr64)
  674. {
  675. SizeToRead = sizeof(UNICODE_STRING64);
  676. Status = ReadVirtual(Address, String, SizeToRead, &Result);
  677. }
  678. else
  679. {
  680. SizeToRead = sizeof(UNICODE_STRING32);
  681. Status = ReadVirtual(Address, &Str32, SizeToRead, &Result);
  682. String->Length = Str32.Length;
  683. String->MaximumLength = Str32.MaximumLength;
  684. String->Buffer = EXTEND64(Str32.Buffer);
  685. }
  686. if (Status != S_OK)
  687. {
  688. return Status;
  689. }
  690. if (Result != SizeToRead)
  691. {
  692. return E_FAIL;
  693. }
  694. return S_OK;
  695. }
  696. HRESULT
  697. TargetInfo::ReadDirectoryTableBase(PULONG64 DirBase)
  698. {
  699. HRESULT Status;
  700. ULONG64 CurProc;
  701. // Retrieve the current EPROCESS's DirectoryTableBase[0] value.
  702. Status = GetProcessInfoDataOffset(g_CurrentProcess->CurrentThread,
  703. 0, 0, &CurProc);
  704. if (Status != S_OK)
  705. {
  706. return Status;
  707. }
  708. CurProc += g_TargetMachine->m_OffsetEprocessDirectoryTableBase;
  709. return ReadPointer(g_TargetMachine, CurProc, DirBase);
  710. }
  711. HRESULT
  712. TargetInfo::ReadImplicitThreadInfoPointer(ULONG Offset, PULONG64 Ptr)
  713. {
  714. HRESULT Status;
  715. ULONG64 CurThread;
  716. // Retrieve the current ETHREAD.
  717. if ((Status = GetImplicitThreadData(&CurThread)) != S_OK)
  718. {
  719. return Status;
  720. }
  721. return ReadPointer(g_TargetMachine, CurThread + Offset, Ptr);
  722. }
  723. HRESULT
  724. TargetInfo::ReadImplicitProcessInfoPointer(ULONG Offset, PULONG64 Ptr)
  725. {
  726. HRESULT Status;
  727. ULONG64 CurProc;
  728. // Retrieve the current EPROCESS.
  729. if ((Status = GetImplicitProcessData(&CurProc)) != S_OK)
  730. {
  731. return Status;
  732. }
  733. return ReadPointer(g_TargetMachine, CurProc + Offset, Ptr);
  734. }
  735. HRESULT
  736. TargetInfo::ReadSharedUserTimeDateN(PULONG64 TimeDate)
  737. {
  738. HRESULT Status;
  739. ULONG Done;
  740. Status = ReadVirtual(g_TargetMachine->m_SharedUserDataOffset +
  741. FIELD_OFFSET(KUSER_SHARED_DATA, SystemTime),
  742. TimeDate, sizeof(*TimeDate), &Done);
  743. if (Status != S_OK)
  744. {
  745. return Status;
  746. }
  747. if (Done != sizeof(*TimeDate))
  748. {
  749. return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
  750. }
  751. return S_OK;
  752. }
  753. HRESULT
  754. TargetInfo::ReadSharedUserUpTimeN(PULONG64 UpTime)
  755. {
  756. HRESULT Status;
  757. ULONG Done;
  758. Status = ReadVirtual(g_TargetMachine->m_SharedUserDataOffset +
  759. FIELD_OFFSET(KUSER_SHARED_DATA, InterruptTime),
  760. UpTime, sizeof(*UpTime), &Done);
  761. if (Status != S_OK)
  762. {
  763. return Status;
  764. }
  765. if (Done != sizeof(*UpTime))
  766. {
  767. return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
  768. }
  769. return S_OK;
  770. }
  771. // VS_VERSIONINFO has a variable format but in the case we
  772. // care about it's fixed.
  773. struct PARTIAL_VERSIONINFO
  774. {
  775. WORD wLength;
  776. WORD wValueLength;
  777. WORD wType;
  778. WCHAR szKey[17];
  779. VS_FIXEDFILEINFO Value;
  780. };
  781. #define VER2_SIG ((ULONG)'X2EF')
  782. HRESULT
  783. TargetInfo::ReadImageVersionInfo(ULONG64 ImageBase,
  784. PCSTR Item,
  785. PVOID Buffer,
  786. ULONG BufferSize,
  787. PULONG VerInfoSize,
  788. PIMAGE_DATA_DIRECTORY ResDataDir)
  789. {
  790. if (ResDataDir->VirtualAddress == 0 ||
  791. ResDataDir->Size < sizeof(IMAGE_RESOURCE_DIRECTORY))
  792. {
  793. return E_NOINTERFACE;
  794. }
  795. HRESULT Status;
  796. IMAGE_RESOURCE_DIRECTORY ResDir;
  797. ULONG64 Offset, DirOffset;
  798. Offset = ImageBase + ResDataDir->VirtualAddress;
  799. if ((Status = ReadAllVirtual(Offset, &ResDir, sizeof(ResDir))) != S_OK)
  800. {
  801. return Status;
  802. }
  803. //
  804. // Search for the resource directory entry named by VS_FILE_INFO.
  805. //
  806. IMAGE_RESOURCE_DIRECTORY_ENTRY DirEnt;
  807. ULONG i;
  808. DirOffset = Offset;
  809. Offset += sizeof(ResDir) +
  810. ((ULONG64)ResDir.NumberOfNamedEntries * sizeof(DirEnt));
  811. for (i = 0; i < (ULONG)ResDir.NumberOfIdEntries; i++)
  812. {
  813. if ((Status = ReadAllVirtual(Offset, &DirEnt, sizeof(DirEnt))) != S_OK)
  814. {
  815. return Status;
  816. }
  817. if (!DirEnt.NameIsString &&
  818. MAKEINTRESOURCE(DirEnt.Id) == VS_FILE_INFO)
  819. {
  820. break;
  821. }
  822. Offset += sizeof(DirEnt);
  823. }
  824. if (i >= (ULONG)ResDir.NumberOfIdEntries ||
  825. !DirEnt.DataIsDirectory)
  826. {
  827. return E_NOINTERFACE;
  828. }
  829. Offset = DirOffset + DirEnt.OffsetToDirectory;
  830. if ((Status = ReadAllVirtual(Offset, &ResDir, sizeof(ResDir))) != S_OK)
  831. {
  832. return Status;
  833. }
  834. //
  835. // Search for the resource directory entry named by VS_VERSION_INFO.
  836. //
  837. Offset += sizeof(ResDir) +
  838. ((ULONG64)ResDir.NumberOfNamedEntries * sizeof(DirEnt));
  839. for (i = 0; i < (ULONG)ResDir.NumberOfIdEntries; i++)
  840. {
  841. if ((Status = ReadAllVirtual(Offset, &DirEnt, sizeof(DirEnt))) != S_OK)
  842. {
  843. return Status;
  844. }
  845. if (DirEnt.Name == VS_VERSION_INFO)
  846. {
  847. break;
  848. }
  849. Offset += sizeof(DirEnt);
  850. }
  851. if (i >= (ULONG)ResDir.NumberOfIdEntries ||
  852. !DirEnt.DataIsDirectory)
  853. {
  854. return E_NOINTERFACE;
  855. }
  856. Offset = DirOffset + DirEnt.OffsetToDirectory;
  857. if ((Status = ReadAllVirtual(Offset, &ResDir, sizeof(ResDir))) != S_OK)
  858. {
  859. return Status;
  860. }
  861. //
  862. // We now have the VS_VERSION_INFO directory. Just take
  863. // the first entry as we don't care about languages.
  864. //
  865. Offset += sizeof(ResDir);
  866. if ((Status = ReadAllVirtual(Offset, &DirEnt, sizeof(DirEnt))) != S_OK)
  867. {
  868. return Status;
  869. }
  870. if (DirEnt.DataIsDirectory)
  871. {
  872. return E_NOINTERFACE;
  873. }
  874. IMAGE_RESOURCE_DATA_ENTRY DataEnt;
  875. Offset = DirOffset + DirEnt.OffsetToData;
  876. if ((Status = ReadAllVirtual(Offset, &DataEnt, sizeof(DataEnt))) != S_OK)
  877. {
  878. return Status;
  879. }
  880. if (DataEnt.Size < sizeof(PARTIAL_VERSIONINFO))
  881. {
  882. return E_NOINTERFACE;
  883. }
  884. PARTIAL_VERSIONINFO RawInfo;
  885. Offset = ImageBase + DataEnt.OffsetToData;
  886. if ((Status = ReadAllVirtual(Offset, &RawInfo, sizeof(RawInfo))) != S_OK)
  887. {
  888. return Status;
  889. }
  890. if (RawInfo.wLength < sizeof(RawInfo) ||
  891. wcscmp(RawInfo.szKey, L"VS_VERSION_INFO") != 0)
  892. {
  893. return E_NOINTERFACE;
  894. }
  895. //
  896. // VerQueryValueA needs extra data space for ANSI translations
  897. // of version strings. VQVA assumes that this space is available
  898. // at the end of the data block passed in. GetFileVersionInformationSize
  899. // makes this work by returning a size that's big enough
  900. // for the actual data plus space for ANSI translations. We
  901. // need to do the same thing here so that we also provide
  902. // the necessary translation area.
  903. //
  904. ULONG DataSize = (RawInfo.wLength + 3) & ~3;
  905. PVOID VerData = malloc(DataSize * 2 + sizeof(ULONG));
  906. if (VerData == NULL)
  907. {
  908. return E_OUTOFMEMORY;
  909. }
  910. if ((Status = ReadAllVirtual(Offset, VerData, RawInfo.wLength)) == S_OK)
  911. {
  912. // Stamp the buffer with the signature that indicates
  913. // a full-size translation buffer is available after
  914. // the raw data.
  915. *(PULONG)((PUCHAR)VerData + DataSize) = VER2_SIG;
  916. Status = QueryVersionDataBuffer(VerData, Item,
  917. Buffer, BufferSize, VerInfoSize);
  918. }
  919. free(VerData);
  920. return Status;
  921. }
  922. //----------------------------------------------------------------------------
  923. //
  924. // LiveKernelTargetInfo data space methods.
  925. //
  926. //----------------------------------------------------------------------------
  927. HRESULT
  928. LiveKernelTargetInfo::GetProcessorId
  929. (ULONG Processor, PDEBUG_PROCESSOR_IDENTIFICATION_ALL Id)
  930. {
  931. return g_TargetMachine->ReadKernelProcessorId(Processor, Id);
  932. }
  933. //----------------------------------------------------------------------------
  934. //
  935. // ConnLiveKernelTargetInfo data space methods.
  936. //
  937. //----------------------------------------------------------------------------
  938. HRESULT
  939. ConnLiveKernelTargetInfo::ReadVirtual(
  940. THIS_
  941. IN ULONG64 Offset,
  942. OUT PVOID Buffer,
  943. IN ULONG BufferSize,
  944. OUT PULONG BytesRead
  945. )
  946. {
  947. return g_VirtualCache.Read(Offset, Buffer, BufferSize, BytesRead);
  948. }
  949. HRESULT
  950. ConnLiveKernelTargetInfo::WriteVirtual(
  951. THIS_
  952. IN ULONG64 Offset,
  953. IN PVOID Buffer,
  954. IN ULONG BufferSize,
  955. OUT PULONG BytesWritten
  956. )
  957. {
  958. HRESULT Status =
  959. g_VirtualCache.Write(Offset, Buffer, BufferSize, BytesWritten);
  960. if (Status == S_OK)
  961. {
  962. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_VIRTUAL);
  963. }
  964. return Status;
  965. }
  966. HRESULT
  967. ConnLiveKernelTargetInfo::SearchVirtual(
  968. IN ULONG64 Offset,
  969. IN ULONG64 Length,
  970. IN PVOID Pattern,
  971. IN ULONG PatternSize,
  972. IN ULONG PatternGranularity,
  973. OUT PULONG64 MatchOffset
  974. )
  975. {
  976. // In NT 4.0, the search API is not supported at the kernel protocol
  977. // level. Fall back to the default ReamMemory \ search.
  978. //
  979. HRESULT Status;
  980. if (g_SystemVersion <= NT_SVER_NT4 || PatternGranularity != 1)
  981. {
  982. Status = TargetInfo::SearchVirtual(Offset, Length, (PUCHAR)Pattern,
  983. PatternSize, PatternGranularity,
  984. MatchOffset);
  985. }
  986. else
  987. {
  988. NTSTATUS NtStatus =
  989. DbgKdSearchMemory(Offset, Length, (PUCHAR)Pattern,
  990. PatternSize, MatchOffset);
  991. Status = CONV_NT_STATUS(NtStatus);
  992. }
  993. return Status;
  994. }
  995. HRESULT
  996. ConnLiveKernelTargetInfo::ReadVirtualUncached(
  997. THIS_
  998. IN ULONG64 Offset,
  999. OUT PVOID Buffer,
  1000. IN ULONG BufferSize,
  1001. OUT PULONG BytesRead
  1002. )
  1003. {
  1004. ULONG Length, Read;
  1005. NTSTATUS Status;
  1006. *BytesRead = 0;
  1007. while (BufferSize)
  1008. {
  1009. Length = BufferSize;
  1010. for (;;)
  1011. {
  1012. Status = DbgKdReadVirtualMemoryNow(Offset, Buffer, Length, &Read);
  1013. if (NT_SUCCESS(Status))
  1014. {
  1015. break;
  1016. }
  1017. if (Status == STATUS_CONTROL_C_EXIT)
  1018. {
  1019. return HRESULT_FROM_NT(Status);
  1020. }
  1021. if ((Offset & ~((ULONG64)g_TargetMachine->m_PageSize - 1)) !=
  1022. ((Offset + Length - 1) & ~((ULONG64)g_TargetMachine->m_PageSize - 1)))
  1023. {
  1024. //
  1025. // Before accepting the error, make sure request
  1026. // didn't fail because it crossed multiple pages
  1027. //
  1028. Length = (ULONG)
  1029. ((Offset | (g_TargetMachine->m_PageSize - 1)) -
  1030. Offset + 1);
  1031. }
  1032. else
  1033. {
  1034. if (Status == STATUS_UNSUCCESSFUL &&
  1035. g_VirtualCache.m_DecodePTEs &&
  1036. !g_VirtualCache.m_ForceDecodePTEs)
  1037. {
  1038. //
  1039. // Try getting the memory by looking up the physical
  1040. // location of the page
  1041. //
  1042. Status = DbgKdReadVirtualTranslatedMemory(Offset, Buffer,
  1043. Length, &Read);
  1044. if (NT_SUCCESS(Status))
  1045. {
  1046. break;
  1047. }
  1048. }
  1049. //
  1050. // Unable to get more memory. If we already read
  1051. // some return success, otherwise return error to
  1052. // the caller.
  1053. //
  1054. return *BytesRead > 0 ? S_OK : HRESULT_FROM_NT(Status);
  1055. }
  1056. }
  1057. BufferSize -= Read;
  1058. Offset += Read;
  1059. Buffer = (PVOID)((PUCHAR)Buffer + Read);
  1060. *BytesRead += Read;
  1061. }
  1062. return S_OK;
  1063. }
  1064. HRESULT
  1065. ConnLiveKernelTargetInfo::WriteVirtualUncached(
  1066. THIS_
  1067. IN ULONG64 Offset,
  1068. IN PVOID Buffer,
  1069. IN ULONG BufferSize,
  1070. OUT PULONG BytesWritten
  1071. )
  1072. {
  1073. NTSTATUS Status =
  1074. DbgKdWriteVirtualMemoryNow(Offset, Buffer, BufferSize, BytesWritten);
  1075. if (Status == STATUS_UNSUCCESSFUL &&
  1076. g_VirtualCache.m_DecodePTEs &&
  1077. !g_VirtualCache.m_ForceDecodePTEs)
  1078. {
  1079. //
  1080. // Try getting the memory by looking up the physical
  1081. // location of the page
  1082. //
  1083. Status = DbgKdWriteVirtualTranslatedMemory(Offset, Buffer,
  1084. BufferSize, BytesWritten);
  1085. }
  1086. if (NT_SUCCESS(Status))
  1087. {
  1088. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_VIRTUAL);
  1089. }
  1090. return CONV_NT_STATUS(Status);
  1091. }
  1092. HRESULT
  1093. ConnLiveKernelTargetInfo::ReadPhysical(
  1094. THIS_
  1095. IN ULONG64 Offset,
  1096. OUT PVOID Buffer,
  1097. IN ULONG BufferSize,
  1098. OUT PULONG BytesRead
  1099. )
  1100. {
  1101. if (g_PhysicalCacheActive)
  1102. {
  1103. return g_PhysicalCache.Read(Offset, Buffer, BufferSize, BytesRead);
  1104. }
  1105. else
  1106. {
  1107. return ReadPhysicalUncached(Offset, Buffer, BufferSize, BytesRead);
  1108. }
  1109. }
  1110. HRESULT
  1111. ConnLiveKernelTargetInfo::WritePhysical(
  1112. THIS_
  1113. IN ULONG64 Offset,
  1114. IN PVOID Buffer,
  1115. IN ULONG BufferSize,
  1116. OUT PULONG BytesWritten
  1117. )
  1118. {
  1119. if (g_PhysicalCacheActive)
  1120. {
  1121. return g_PhysicalCache.Write(Offset, Buffer, BufferSize,
  1122. BytesWritten);
  1123. }
  1124. else
  1125. {
  1126. return WritePhysicalUncached(Offset, Buffer, BufferSize,
  1127. BytesWritten);
  1128. }
  1129. }
  1130. HRESULT
  1131. ConnLiveKernelTargetInfo::ReadPhysicalUncached(
  1132. THIS_
  1133. IN ULONG64 Offset,
  1134. OUT PVOID Buffer,
  1135. IN ULONG BufferSize,
  1136. OUT PULONG BytesRead
  1137. )
  1138. {
  1139. NTSTATUS Status =
  1140. DbgKdReadPhysicalMemory(Offset, Buffer, BufferSize,
  1141. BytesRead);
  1142. return CONV_NT_STATUS(Status);
  1143. }
  1144. HRESULT
  1145. ConnLiveKernelTargetInfo::WritePhysicalUncached(
  1146. THIS_
  1147. IN ULONG64 Offset,
  1148. IN PVOID Buffer,
  1149. IN ULONG BufferSize,
  1150. OUT PULONG BytesWritten
  1151. )
  1152. {
  1153. NTSTATUS Status =
  1154. DbgKdWritePhysicalMemory(Offset, Buffer, BufferSize,
  1155. BytesWritten);
  1156. if (NT_SUCCESS(Status))
  1157. {
  1158. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_PHYSICAL);
  1159. }
  1160. return CONV_NT_STATUS(Status);
  1161. }
  1162. HRESULT
  1163. ConnLiveKernelTargetInfo::ReadControl(
  1164. THIS_
  1165. IN ULONG Processor,
  1166. IN ULONG64 Offset,
  1167. OUT PVOID Buffer,
  1168. IN ULONG BufferSize,
  1169. OUT PULONG BytesRead
  1170. )
  1171. {
  1172. NTSTATUS Status =
  1173. DbgKdReadControlSpace((USHORT)Processor, (ULONG)Offset,
  1174. Buffer, BufferSize, BytesRead);
  1175. return CONV_NT_STATUS(Status);
  1176. }
  1177. HRESULT
  1178. ConnLiveKernelTargetInfo::WriteControl(
  1179. THIS_
  1180. IN ULONG Processor,
  1181. IN ULONG64 Offset,
  1182. IN PVOID Buffer,
  1183. IN ULONG BufferSize,
  1184. OUT PULONG BytesWritten
  1185. )
  1186. {
  1187. NTSTATUS Status =
  1188. DbgKdWriteControlSpace((USHORT)Processor, (ULONG)Offset,
  1189. Buffer, BufferSize,
  1190. BytesWritten);
  1191. if (NT_SUCCESS(Status))
  1192. {
  1193. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_CONTROL);
  1194. }
  1195. return CONV_NT_STATUS(Status);
  1196. }
  1197. HRESULT
  1198. ConnLiveKernelTargetInfo::ReadIo(
  1199. THIS_
  1200. IN ULONG InterfaceType,
  1201. IN ULONG BusNumber,
  1202. IN ULONG AddressSpace,
  1203. IN ULONG64 Offset,
  1204. OUT PVOID Buffer,
  1205. IN ULONG BufferSize,
  1206. OUT PULONG BytesRead
  1207. )
  1208. {
  1209. NTSTATUS Status;
  1210. // Convert trivially extended I/O requests down into simple
  1211. // requests as not all platform support extended requests.
  1212. if (InterfaceType == Isa && BusNumber == 0 && AddressSpace == 1)
  1213. {
  1214. Status = DbgKdReadIoSpace(Offset, Buffer, BufferSize);
  1215. }
  1216. else
  1217. {
  1218. Status = DbgKdReadIoSpaceExtended(Offset, Buffer, BufferSize,
  1219. (INTERFACE_TYPE)InterfaceType,
  1220. BusNumber, AddressSpace);
  1221. }
  1222. if (NT_SUCCESS(Status))
  1223. {
  1224. // I/O access currently can't successfully return anything
  1225. // than the requested size.
  1226. if (BytesRead != NULL)
  1227. {
  1228. *BytesRead = BufferSize;
  1229. }
  1230. return S_OK;
  1231. }
  1232. else
  1233. {
  1234. return HRESULT_FROM_NT(Status);
  1235. }
  1236. }
  1237. HRESULT
  1238. ConnLiveKernelTargetInfo::WriteIo(
  1239. THIS_
  1240. IN ULONG InterfaceType,
  1241. IN ULONG BusNumber,
  1242. IN ULONG AddressSpace,
  1243. IN ULONG64 Offset,
  1244. IN PVOID Buffer,
  1245. IN ULONG BufferSize,
  1246. OUT PULONG BytesWritten
  1247. )
  1248. {
  1249. NTSTATUS Status;
  1250. // Convert trivially extended I/O requests down into simple
  1251. // requests as not all platform support extended requests.
  1252. if (InterfaceType == Isa && BusNumber == 0 && AddressSpace == 1)
  1253. {
  1254. Status = DbgKdWriteIoSpace(Offset, *(ULONG *)Buffer, BufferSize);
  1255. }
  1256. else
  1257. {
  1258. Status = DbgKdWriteIoSpaceExtended(Offset, *(ULONG *)Buffer,
  1259. BufferSize,
  1260. (INTERFACE_TYPE)InterfaceType,
  1261. BusNumber, AddressSpace);
  1262. }
  1263. if (NT_SUCCESS(Status))
  1264. {
  1265. // I/O access currently can't successfully return anything
  1266. // than the requested size.
  1267. if (BytesWritten != NULL)
  1268. {
  1269. *BytesWritten = BufferSize;
  1270. }
  1271. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_IO);
  1272. return S_OK;
  1273. }
  1274. else
  1275. {
  1276. return HRESULT_FROM_NT(Status);
  1277. }
  1278. }
  1279. HRESULT
  1280. ConnLiveKernelTargetInfo::ReadMsr(
  1281. THIS_
  1282. IN ULONG Msr,
  1283. OUT PULONG64 Value
  1284. )
  1285. {
  1286. NTSTATUS Status =
  1287. DbgKdReadMsr(Msr, Value);
  1288. return CONV_NT_STATUS(Status);
  1289. }
  1290. HRESULT
  1291. ConnLiveKernelTargetInfo::WriteMsr(
  1292. THIS_
  1293. IN ULONG Msr,
  1294. IN ULONG64 Value
  1295. )
  1296. {
  1297. NTSTATUS Status =
  1298. DbgKdWriteMsr(Msr, Value);
  1299. if (NT_SUCCESS(Status))
  1300. {
  1301. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_MSR);
  1302. }
  1303. return CONV_NT_STATUS(Status);
  1304. }
  1305. HRESULT
  1306. ConnLiveKernelTargetInfo::ReadBusData(
  1307. THIS_
  1308. IN ULONG BusDataType,
  1309. IN ULONG BusNumber,
  1310. IN ULONG SlotNumber,
  1311. IN ULONG Offset,
  1312. OUT PVOID Buffer,
  1313. IN ULONG BufferSize,
  1314. OUT PULONG BytesRead
  1315. )
  1316. {
  1317. NTSTATUS Status =
  1318. DbgKdGetBusData(BusDataType, BusNumber, SlotNumber,
  1319. Buffer, Offset, &BufferSize);
  1320. if (NT_SUCCESS(Status) && BytesRead != NULL)
  1321. {
  1322. *BytesRead = BufferSize;
  1323. }
  1324. return CONV_NT_STATUS(Status);
  1325. }
  1326. HRESULT
  1327. ConnLiveKernelTargetInfo::WriteBusData(
  1328. THIS_
  1329. IN ULONG BusDataType,
  1330. IN ULONG BusNumber,
  1331. IN ULONG SlotNumber,
  1332. IN ULONG Offset,
  1333. IN PVOID Buffer,
  1334. IN ULONG BufferSize,
  1335. OUT PULONG BytesWritten
  1336. )
  1337. {
  1338. NTSTATUS Status =
  1339. DbgKdSetBusData(BusDataType, BusNumber, SlotNumber,
  1340. Buffer, Offset, &BufferSize);
  1341. if (NT_SUCCESS(Status) && BytesWritten != NULL)
  1342. {
  1343. *BytesWritten = BufferSize;
  1344. }
  1345. if (NT_SUCCESS(Status))
  1346. {
  1347. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_BUS_DATA);
  1348. }
  1349. return CONV_NT_STATUS(Status);
  1350. }
  1351. HRESULT
  1352. ConnLiveKernelTargetInfo::CheckLowMemory(
  1353. THIS
  1354. )
  1355. {
  1356. NTSTATUS Status =
  1357. DbgKdCheckLowMemory();
  1358. return CONV_NT_STATUS(Status);
  1359. }
  1360. HRESULT
  1361. ConnLiveKernelTargetInfo::FillVirtual(
  1362. THIS_
  1363. IN ULONG64 Start,
  1364. IN ULONG Size,
  1365. IN PVOID Pattern,
  1366. IN ULONG PatternSize,
  1367. OUT PULONG Filled
  1368. )
  1369. {
  1370. HRESULT Status;
  1371. if (g_KdMaxManipulate <= DbgKdFillMemoryApi ||
  1372. PatternSize > PACKET_MAX_SIZE)
  1373. {
  1374. Status = TargetInfo::FillVirtual(Start, Size, Pattern,
  1375. PatternSize, Filled);
  1376. }
  1377. else
  1378. {
  1379. NTSTATUS NtStatus =
  1380. DbgKdFillMemory(DBGKD_FILL_MEMORY_VIRTUAL, Start, Size,
  1381. Pattern, PatternSize, Filled);
  1382. Status = CONV_NT_STATUS(NtStatus);
  1383. }
  1384. return Status;
  1385. }
  1386. HRESULT
  1387. ConnLiveKernelTargetInfo::FillPhysical(
  1388. THIS_
  1389. IN ULONG64 Start,
  1390. IN ULONG Size,
  1391. IN PVOID Pattern,
  1392. IN ULONG PatternSize,
  1393. OUT PULONG Filled
  1394. )
  1395. {
  1396. HRESULT Status;
  1397. if (g_KdMaxManipulate <= DbgKdFillMemoryApi ||
  1398. PatternSize > PACKET_MAX_SIZE)
  1399. {
  1400. Status = TargetInfo::FillPhysical(Start, Size, Pattern,
  1401. PatternSize, Filled);
  1402. }
  1403. else
  1404. {
  1405. NTSTATUS NtStatus =
  1406. DbgKdFillMemory(DBGKD_FILL_MEMORY_PHYSICAL, Start, Size,
  1407. Pattern, PatternSize, Filled);
  1408. Status = CONV_NT_STATUS(NtStatus);
  1409. }
  1410. return Status;
  1411. }
  1412. HRESULT
  1413. ConnLiveKernelTargetInfo::QueryAddressInformation(ULONG64 Address,
  1414. ULONG InSpace,
  1415. PULONG OutSpace,
  1416. PULONG OutFlags)
  1417. {
  1418. HRESULT Status;
  1419. if (g_KdMaxManipulate <= DbgKdQueryMemoryApi)
  1420. {
  1421. Status = TargetInfo::QueryAddressInformation(Address, InSpace,
  1422. OutSpace, OutFlags);
  1423. }
  1424. else
  1425. {
  1426. NTSTATUS NtStatus =
  1427. DbgKdQueryMemory(Address, InSpace, OutSpace, OutFlags);
  1428. Status = CONV_NT_STATUS(NtStatus);
  1429. }
  1430. return Status;
  1431. }
  1432. //----------------------------------------------------------------------------
  1433. //
  1434. // LocalLiveKernelTargetInfo data space methods.
  1435. //
  1436. //----------------------------------------------------------------------------
  1437. HRESULT
  1438. LocalLiveKernelTargetInfo::ReadVirtual(
  1439. THIS_
  1440. IN ULONG64 Offset,
  1441. OUT PVOID Buffer,
  1442. IN ULONG BufferSize,
  1443. OUT PULONG BytesRead
  1444. )
  1445. {
  1446. SYSDBG_VIRTUAL Cmd;
  1447. NTSTATUS Status = STATUS_SUCCESS;
  1448. //
  1449. // The kernel only allows operations up to
  1450. // KDP_MESSAGE_BUFFER_SIZE, so break things up
  1451. // into chunks if necessary.
  1452. //
  1453. *BytesRead = 0;
  1454. Cmd.Address = (PVOID)(ULONG_PTR)Offset;
  1455. Cmd.Buffer = Buffer;
  1456. while (BufferSize > 0)
  1457. {
  1458. ULONG ChunkDone;
  1459. if (BufferSize > PACKET_MAX_SIZE)
  1460. {
  1461. Cmd.Request = PACKET_MAX_SIZE;
  1462. }
  1463. else
  1464. {
  1465. Cmd.Request = BufferSize;
  1466. }
  1467. // The kernel stubs avoid faults so all memory
  1468. // must be paged in ahead of time. There's
  1469. // still the possibility that something could
  1470. // get paged out after this but the assumption is
  1471. // that the vulnerability is small and it's much
  1472. // better than implementing dual code paths in
  1473. // the kernel.
  1474. if (IsBadWritePtr(Cmd.Buffer, Cmd.Request))
  1475. {
  1476. Status = STATUS_INVALID_PARAMETER;
  1477. break;
  1478. }
  1479. ChunkDone = 0;
  1480. Status =
  1481. g_NtDllCalls.NtSystemDebugControl(SysDbgReadVirtual,
  1482. &Cmd, sizeof(Cmd),
  1483. NULL, 0,
  1484. &ChunkDone);
  1485. if (!NT_SUCCESS(Status) && Status != STATUS_UNSUCCESSFUL)
  1486. {
  1487. break;
  1488. }
  1489. if (ChunkDone == 0)
  1490. {
  1491. // If some data was processed consider it a success.
  1492. Status = *BytesRead > 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  1493. break;
  1494. }
  1495. Cmd.Address = (PVOID)((PUCHAR)Cmd.Address + ChunkDone);
  1496. Cmd.Buffer = (PVOID)((PUCHAR)Cmd.Buffer + ChunkDone);
  1497. BufferSize -= ChunkDone;
  1498. *BytesRead += ChunkDone;
  1499. }
  1500. return CONV_NT_STATUS(Status);
  1501. }
  1502. HRESULT
  1503. LocalLiveKernelTargetInfo::WriteVirtual(
  1504. THIS_
  1505. IN ULONG64 Offset,
  1506. IN PVOID Buffer,
  1507. IN ULONG BufferSize,
  1508. OUT PULONG BytesWritten
  1509. )
  1510. {
  1511. SYSDBG_VIRTUAL Cmd;
  1512. NTSTATUS Status = STATUS_SUCCESS;
  1513. //
  1514. // The kernel only allows operations up to
  1515. // KDP_MESSAGE_BUFFER_SIZE, so break things up
  1516. // into chunks if necessary.
  1517. //
  1518. *BytesWritten = 0;
  1519. Cmd.Address = (PVOID)(ULONG_PTR)Offset;
  1520. Cmd.Buffer = Buffer;
  1521. while (BufferSize > 0)
  1522. {
  1523. ULONG ChunkDone;
  1524. if (BufferSize > PACKET_MAX_SIZE)
  1525. {
  1526. Cmd.Request = PACKET_MAX_SIZE;
  1527. }
  1528. else
  1529. {
  1530. Cmd.Request = BufferSize;
  1531. }
  1532. // The kernel stubs avoid faults so all memory
  1533. // must be paged in ahead of time. There's
  1534. // still the possibility that something could
  1535. // get paged out after this but the assumption is
  1536. // that the vulnerability is small and it's much
  1537. // better than implementing dual code paths in
  1538. // the kernel.
  1539. if (IsBadReadPtr(Cmd.Buffer, Cmd.Request))
  1540. {
  1541. Status = STATUS_INVALID_PARAMETER;
  1542. break;
  1543. }
  1544. ChunkDone = 0;
  1545. Status =
  1546. g_NtDllCalls.NtSystemDebugControl(SysDbgWriteVirtual,
  1547. &Cmd, sizeof(Cmd),
  1548. NULL, 0,
  1549. &ChunkDone);
  1550. if (!NT_SUCCESS(Status) && Status != STATUS_UNSUCCESSFUL)
  1551. {
  1552. break;
  1553. }
  1554. if (ChunkDone == 0)
  1555. {
  1556. // If some data was processed consider it a success.
  1557. Status = *BytesWritten > 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  1558. break;
  1559. }
  1560. Cmd.Address = (PVOID)((PUCHAR)Cmd.Address + ChunkDone);
  1561. Cmd.Buffer = (PVOID)((PUCHAR)Cmd.Buffer + ChunkDone);
  1562. BufferSize -= ChunkDone;
  1563. *BytesWritten += ChunkDone;
  1564. }
  1565. if (NT_SUCCESS(Status))
  1566. {
  1567. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_VIRTUAL);
  1568. }
  1569. return CONV_NT_STATUS(Status);
  1570. }
  1571. HRESULT
  1572. LocalLiveKernelTargetInfo::ReadPhysical(
  1573. THIS_
  1574. IN ULONG64 Offset,
  1575. OUT PVOID Buffer,
  1576. IN ULONG BufferSize,
  1577. OUT PULONG BytesRead
  1578. )
  1579. {
  1580. SYSDBG_PHYSICAL Cmd;
  1581. NTSTATUS Status = STATUS_SUCCESS;
  1582. //
  1583. // The kernel only allows operations up to
  1584. // KDP_MESSAGE_BUFFER_SIZE, so break things up
  1585. // into chunks if necessary.
  1586. //
  1587. *BytesRead = 0;
  1588. Cmd.Address.QuadPart = Offset;
  1589. Cmd.Buffer = Buffer;
  1590. while (BufferSize > 0)
  1591. {
  1592. ULONG ChunkDone;
  1593. if (BufferSize > PACKET_MAX_SIZE)
  1594. {
  1595. Cmd.Request = PACKET_MAX_SIZE;
  1596. }
  1597. else
  1598. {
  1599. Cmd.Request = BufferSize;
  1600. }
  1601. // The kernel stubs avoid faults so all memory
  1602. // must be paged in ahead of time. There's
  1603. // still the possibility that something could
  1604. // get paged out after this but the assumption is
  1605. // that the vulnerability is small and it's much
  1606. // better than implementing dual code paths in
  1607. // the kernel.
  1608. if (IsBadWritePtr(Cmd.Buffer, Cmd.Request))
  1609. {
  1610. Status = STATUS_INVALID_PARAMETER;
  1611. break;
  1612. }
  1613. ChunkDone = 0;
  1614. Status =
  1615. g_NtDllCalls.NtSystemDebugControl(SysDbgReadPhysical,
  1616. &Cmd, sizeof(Cmd),
  1617. NULL, 0,
  1618. &ChunkDone);
  1619. if (!NT_SUCCESS(Status) && Status != STATUS_UNSUCCESSFUL)
  1620. {
  1621. break;
  1622. }
  1623. if (ChunkDone == 0)
  1624. {
  1625. // If some data was processed consider it a success.
  1626. Status = *BytesRead > 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  1627. break;
  1628. }
  1629. Cmd.Address.QuadPart += ChunkDone;
  1630. Cmd.Buffer = (PVOID)((PUCHAR)Cmd.Buffer + ChunkDone);
  1631. BufferSize -= ChunkDone;
  1632. *BytesRead += ChunkDone;
  1633. }
  1634. return CONV_NT_STATUS(Status);
  1635. }
  1636. HRESULT
  1637. LocalLiveKernelTargetInfo::WritePhysical(
  1638. THIS_
  1639. IN ULONG64 Offset,
  1640. IN PVOID Buffer,
  1641. IN ULONG BufferSize,
  1642. OUT PULONG BytesWritten
  1643. )
  1644. {
  1645. SYSDBG_PHYSICAL Cmd;
  1646. NTSTATUS Status = STATUS_SUCCESS;
  1647. //
  1648. // The kernel only allows operations up to
  1649. // KDP_MESSAGE_BUFFER_SIZE, so break things up
  1650. // into chunks if necessary.
  1651. //
  1652. *BytesWritten = 0;
  1653. Cmd.Address.QuadPart = Offset;
  1654. Cmd.Buffer = Buffer;
  1655. while (BufferSize > 0)
  1656. {
  1657. ULONG ChunkDone;
  1658. if (BufferSize > PACKET_MAX_SIZE)
  1659. {
  1660. Cmd.Request = PACKET_MAX_SIZE;
  1661. }
  1662. else
  1663. {
  1664. Cmd.Request = BufferSize;
  1665. }
  1666. // The kernel stubs avoid faults so all memory
  1667. // must be paged in ahead of time. There's
  1668. // still the possibility that something could
  1669. // get paged out after this but the assumption is
  1670. // that the vulnerability is small and it's much
  1671. // better than implementing dual code paths in
  1672. // the kernel.
  1673. if (IsBadReadPtr(Cmd.Buffer, Cmd.Request))
  1674. {
  1675. Status = STATUS_INVALID_PARAMETER;
  1676. break;
  1677. }
  1678. ChunkDone = 0;
  1679. Status =
  1680. g_NtDllCalls.NtSystemDebugControl(SysDbgWritePhysical,
  1681. &Cmd, sizeof(Cmd),
  1682. NULL, 0,
  1683. &ChunkDone);
  1684. if (!NT_SUCCESS(Status) && Status != STATUS_UNSUCCESSFUL)
  1685. {
  1686. break;
  1687. }
  1688. if (ChunkDone == 0)
  1689. {
  1690. // If some data was processed consider it a success.
  1691. Status = *BytesWritten > 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  1692. break;
  1693. }
  1694. Cmd.Address.QuadPart += ChunkDone;
  1695. Cmd.Buffer = (PVOID)((PUCHAR)Cmd.Buffer + ChunkDone);
  1696. BufferSize -= ChunkDone;
  1697. *BytesWritten += ChunkDone;
  1698. }
  1699. if (NT_SUCCESS(Status))
  1700. {
  1701. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_PHYSICAL);
  1702. }
  1703. return CONV_NT_STATUS(Status);
  1704. }
  1705. HRESULT
  1706. LocalLiveKernelTargetInfo::ReadControl(
  1707. THIS_
  1708. IN ULONG Processor,
  1709. IN ULONG64 Offset,
  1710. OUT PVOID Buffer,
  1711. IN ULONG BufferSize,
  1712. OUT PULONG BytesRead
  1713. )
  1714. {
  1715. // The kernel stubs avoid faults so all memory
  1716. // must be paged in ahead of time. There's
  1717. // still the possibility that something could
  1718. // get paged out after this but the assumption is
  1719. // that the vulnerability is small and it's much
  1720. // better than implementing dual code paths in
  1721. // the kernel.
  1722. if (IsBadWritePtr(Buffer, BufferSize))
  1723. {
  1724. return E_INVALIDARG;
  1725. }
  1726. SYSDBG_CONTROL_SPACE Cmd;
  1727. Cmd.Address = Offset;
  1728. Cmd.Buffer = Buffer;
  1729. Cmd.Request = BufferSize;
  1730. Cmd.Processor = Processor;
  1731. NTSTATUS Status =
  1732. g_NtDllCalls.NtSystemDebugControl(SysDbgReadControlSpace,
  1733. &Cmd, sizeof(Cmd),
  1734. NULL, 0,
  1735. BytesRead);
  1736. return CONV_NT_STATUS(Status);
  1737. }
  1738. HRESULT
  1739. LocalLiveKernelTargetInfo::WriteControl(
  1740. THIS_
  1741. IN ULONG Processor,
  1742. IN ULONG64 Offset,
  1743. IN PVOID Buffer,
  1744. IN ULONG BufferSize,
  1745. OUT PULONG BytesWritten
  1746. )
  1747. {
  1748. // The kernel stubs avoid faults so all memory
  1749. // must be paged in ahead of time. There's
  1750. // still the possibility that something could
  1751. // get paged out after this but the assumption is
  1752. // that the vulnerability is small and it's much
  1753. // better than implementing dual code paths in
  1754. // the kernel.
  1755. if (IsBadReadPtr(Buffer, BufferSize))
  1756. {
  1757. return E_INVALIDARG;
  1758. }
  1759. SYSDBG_CONTROL_SPACE Cmd;
  1760. Cmd.Address = Offset;
  1761. Cmd.Buffer = Buffer;
  1762. Cmd.Request = BufferSize;
  1763. Cmd.Processor = Processor;
  1764. NTSTATUS Status =
  1765. g_NtDllCalls.NtSystemDebugControl(SysDbgWriteControlSpace,
  1766. &Cmd, sizeof(Cmd),
  1767. NULL, 0,
  1768. BytesWritten);
  1769. if (NT_SUCCESS(Status))
  1770. {
  1771. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_CONTROL);
  1772. }
  1773. return CONV_NT_STATUS(Status);
  1774. }
  1775. HRESULT
  1776. LocalLiveKernelTargetInfo::ReadIo(
  1777. THIS_
  1778. IN ULONG InterfaceType,
  1779. IN ULONG BusNumber,
  1780. IN ULONG AddressSpace,
  1781. IN ULONG64 Offset,
  1782. OUT PVOID Buffer,
  1783. IN ULONG BufferSize,
  1784. OUT PULONG BytesRead
  1785. )
  1786. {
  1787. // The kernel stubs avoid faults so all memory
  1788. // must be paged in ahead of time. There's
  1789. // still the possibility that something could
  1790. // get paged out after this but the assumption is
  1791. // that the vulnerability is small and it's much
  1792. // better than implementing dual code paths in
  1793. // the kernel.
  1794. if (IsBadWritePtr(Buffer, BufferSize))
  1795. {
  1796. return E_INVALIDARG;
  1797. }
  1798. SYSDBG_IO_SPACE Cmd;
  1799. Cmd.Address = Offset;
  1800. Cmd.Buffer = Buffer;
  1801. Cmd.Request = BufferSize;
  1802. Cmd.InterfaceType = (INTERFACE_TYPE)InterfaceType;
  1803. Cmd.BusNumber = BusNumber;
  1804. Cmd.AddressSpace = AddressSpace;
  1805. NTSTATUS Status =
  1806. g_NtDllCalls.NtSystemDebugControl(SysDbgReadIoSpace,
  1807. &Cmd, sizeof(Cmd),
  1808. NULL, 0,
  1809. BytesRead);
  1810. return CONV_NT_STATUS(Status);
  1811. }
  1812. HRESULT
  1813. LocalLiveKernelTargetInfo::WriteIo(
  1814. THIS_
  1815. IN ULONG InterfaceType,
  1816. IN ULONG BusNumber,
  1817. IN ULONG AddressSpace,
  1818. IN ULONG64 Offset,
  1819. IN PVOID Buffer,
  1820. IN ULONG BufferSize,
  1821. OUT PULONG BytesWritten
  1822. )
  1823. {
  1824. // The kernel stubs avoid faults so all memory
  1825. // must be paged in ahead of time. There's
  1826. // still the possibility that something could
  1827. // get paged out after this but the assumption is
  1828. // that the vulnerability is small and it's much
  1829. // better than implementing dual code paths in
  1830. // the kernel.
  1831. if (IsBadReadPtr(Buffer, BufferSize))
  1832. {
  1833. return E_INVALIDARG;
  1834. }
  1835. SYSDBG_IO_SPACE Cmd;
  1836. Cmd.Address = Offset;
  1837. Cmd.Buffer = Buffer;
  1838. Cmd.Request = BufferSize;
  1839. Cmd.InterfaceType = (INTERFACE_TYPE)InterfaceType;
  1840. Cmd.BusNumber = BusNumber;
  1841. Cmd.AddressSpace = AddressSpace;
  1842. NTSTATUS Status =
  1843. g_NtDllCalls.NtSystemDebugControl(SysDbgWriteIoSpace,
  1844. &Cmd, sizeof(Cmd),
  1845. NULL, 0,
  1846. BytesWritten);
  1847. if (NT_SUCCESS(Status))
  1848. {
  1849. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_IO);
  1850. }
  1851. return CONV_NT_STATUS(Status);
  1852. }
  1853. HRESULT
  1854. LocalLiveKernelTargetInfo::ReadMsr(
  1855. THIS_
  1856. IN ULONG Msr,
  1857. OUT PULONG64 Value
  1858. )
  1859. {
  1860. SYSDBG_MSR Cmd;
  1861. Cmd.Msr = Msr;
  1862. NTSTATUS Status =
  1863. g_NtDllCalls.NtSystemDebugControl(SysDbgReadMsr,
  1864. &Cmd, sizeof(Cmd),
  1865. &Cmd, sizeof(Cmd),
  1866. NULL);
  1867. if (NT_SUCCESS(Status))
  1868. {
  1869. *Value = Cmd.Data;
  1870. }
  1871. return CONV_NT_STATUS(Status);
  1872. }
  1873. HRESULT
  1874. LocalLiveKernelTargetInfo::WriteMsr(
  1875. THIS_
  1876. IN ULONG Msr,
  1877. IN ULONG64 Value
  1878. )
  1879. {
  1880. SYSDBG_MSR Cmd;
  1881. Cmd.Msr = Msr;
  1882. Cmd.Data = Value;
  1883. NTSTATUS Status =
  1884. g_NtDllCalls.NtSystemDebugControl(SysDbgWriteMsr,
  1885. &Cmd, sizeof(Cmd),
  1886. NULL, 0,
  1887. NULL);
  1888. if (NT_SUCCESS(Status))
  1889. {
  1890. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_MSR);
  1891. }
  1892. return CONV_NT_STATUS(Status);
  1893. }
  1894. HRESULT
  1895. LocalLiveKernelTargetInfo::ReadBusData(
  1896. THIS_
  1897. IN ULONG BusDataType,
  1898. IN ULONG BusNumber,
  1899. IN ULONG SlotNumber,
  1900. IN ULONG Offset,
  1901. OUT PVOID Buffer,
  1902. IN ULONG BufferSize,
  1903. OUT PULONG BytesRead
  1904. )
  1905. {
  1906. // The kernel stubs avoid faults so all memory
  1907. // must be paged in ahead of time. There's
  1908. // still the possibility that something could
  1909. // get paged out after this but the assumption is
  1910. // that the vulnerability is small and it's much
  1911. // better than implementing dual code paths in
  1912. // the kernel.
  1913. if (IsBadWritePtr(Buffer, BufferSize))
  1914. {
  1915. return E_INVALIDARG;
  1916. }
  1917. SYSDBG_BUS_DATA Cmd;
  1918. Cmd.Address = Offset;
  1919. Cmd.Buffer = Buffer;
  1920. Cmd.Request = BufferSize;
  1921. Cmd.BusDataType = (BUS_DATA_TYPE)BusDataType;
  1922. Cmd.BusNumber = BusNumber;
  1923. Cmd.SlotNumber = SlotNumber;
  1924. NTSTATUS Status =
  1925. g_NtDllCalls.NtSystemDebugControl(SysDbgReadBusData,
  1926. &Cmd, sizeof(Cmd),
  1927. NULL, 0,
  1928. BytesRead);
  1929. return CONV_NT_STATUS(Status);
  1930. }
  1931. HRESULT
  1932. LocalLiveKernelTargetInfo::WriteBusData(
  1933. THIS_
  1934. IN ULONG BusDataType,
  1935. IN ULONG BusNumber,
  1936. IN ULONG SlotNumber,
  1937. IN ULONG Offset,
  1938. IN PVOID Buffer,
  1939. IN ULONG BufferSize,
  1940. OUT PULONG BytesWritten
  1941. )
  1942. {
  1943. // The kernel stubs avoid faults so all memory
  1944. // must be paged in ahead of time. There's
  1945. // still the possibility that something could
  1946. // get paged out after this but the assumption is
  1947. // that the vulnerability is small and it's much
  1948. // better than implementing dual code paths in
  1949. // the kernel.
  1950. if (IsBadReadPtr(Buffer, BufferSize))
  1951. {
  1952. return E_INVALIDARG;
  1953. }
  1954. SYSDBG_BUS_DATA Cmd;
  1955. Cmd.Address = Offset;
  1956. Cmd.Buffer = Buffer;
  1957. Cmd.Request = BufferSize;
  1958. Cmd.BusDataType = (BUS_DATA_TYPE)BusDataType;
  1959. Cmd.BusNumber = BusNumber;
  1960. Cmd.SlotNumber = SlotNumber;
  1961. NTSTATUS Status =
  1962. g_NtDllCalls.NtSystemDebugControl(SysDbgWriteBusData,
  1963. &Cmd, sizeof(Cmd),
  1964. NULL, 0,
  1965. BytesWritten);
  1966. if (NT_SUCCESS(Status))
  1967. {
  1968. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_BUS_DATA);
  1969. }
  1970. return CONV_NT_STATUS(Status);
  1971. }
  1972. HRESULT
  1973. LocalLiveKernelTargetInfo::CheckLowMemory(
  1974. THIS
  1975. )
  1976. {
  1977. NTSTATUS Status =
  1978. g_NtDllCalls.NtSystemDebugControl(SysDbgCheckLowMemory,
  1979. NULL, 0,
  1980. NULL, 0,
  1981. NULL);
  1982. return CONV_NT_STATUS(Status);
  1983. }
  1984. //----------------------------------------------------------------------------
  1985. //
  1986. // ExdiLiveKernelTargetInfo data space methods.
  1987. //
  1988. //----------------------------------------------------------------------------
  1989. HRESULT
  1990. ExdiLiveKernelTargetInfo::ReadVirtual(
  1991. THIS_
  1992. IN ULONG64 Offset,
  1993. OUT PVOID Buffer,
  1994. IN ULONG BufferSize,
  1995. OUT PULONG BytesRead
  1996. )
  1997. {
  1998. HRESULT Status = m_Server->
  1999. ReadVirtualMemory(Offset, BufferSize, 8, (PBYTE)Buffer, BytesRead);
  2000. return Status;
  2001. }
  2002. HRESULT
  2003. ExdiLiveKernelTargetInfo::WriteVirtual(
  2004. THIS_
  2005. IN ULONG64 Offset,
  2006. IN PVOID Buffer,
  2007. IN ULONG BufferSize,
  2008. OUT PULONG BytesWritten
  2009. )
  2010. {
  2011. HRESULT Status = m_Server->
  2012. WriteVirtualMemory(Offset, BufferSize, 8, (PBYTE)Buffer, BytesWritten);
  2013. if (Status == S_OK)
  2014. {
  2015. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_VIRTUAL);
  2016. }
  2017. return Status;
  2018. }
  2019. HRESULT
  2020. ExdiLiveKernelTargetInfo::ReadPhysical(
  2021. THIS_
  2022. IN ULONG64 Offset,
  2023. OUT PVOID Buffer,
  2024. IN ULONG BufferSize,
  2025. OUT PULONG BytesRead
  2026. )
  2027. {
  2028. HRESULT Status = m_Server->
  2029. ReadPhysicalMemoryOrPeriphIO(Offset, 0, BufferSize, 8, (PBYTE)Buffer);
  2030. if (Status == S_OK)
  2031. {
  2032. *BytesRead = BufferSize;
  2033. }
  2034. return Status;
  2035. }
  2036. HRESULT
  2037. ExdiLiveKernelTargetInfo::WritePhysical(
  2038. THIS_
  2039. IN ULONG64 Offset,
  2040. IN PVOID Buffer,
  2041. IN ULONG BufferSize,
  2042. OUT PULONG BytesWritten
  2043. )
  2044. {
  2045. HRESULT Status = m_Server->
  2046. WritePhysicalMemoryOrPeriphIO(Offset, 0, BufferSize, 8, (PBYTE)Buffer);
  2047. if (Status == S_OK)
  2048. {
  2049. *BytesWritten = BufferSize;
  2050. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_PHYSICAL);
  2051. }
  2052. return Status;
  2053. }
  2054. // XXX drewb - Guessing at how to implement these spaces.
  2055. #define EXDI_ADDR_CONTROL_SPACE 2
  2056. #define EXDI_ADDR_MSR 3
  2057. #define EXDI_ADDR_BUS_DATA 4
  2058. HRESULT
  2059. ExdiLiveKernelTargetInfo::ReadControl(
  2060. THIS_
  2061. IN ULONG Processor,
  2062. IN ULONG64 Offset,
  2063. OUT PVOID Buffer,
  2064. IN ULONG BufferSize,
  2065. OUT PULONG BytesRead
  2066. )
  2067. {
  2068. if (m_KdSupport != EXDI_KD_IOCTL)
  2069. {
  2070. return E_UNEXPECTED;
  2071. }
  2072. HRESULT Status = m_Server->
  2073. ReadPhysicalMemoryOrPeriphIO(Offset, EXDI_ADDR_CONTROL_SPACE,
  2074. BufferSize, 8, (PBYTE)Buffer);
  2075. if (Status == S_OK)
  2076. {
  2077. *BytesRead = BufferSize;
  2078. }
  2079. return Status;
  2080. }
  2081. HRESULT
  2082. ExdiLiveKernelTargetInfo::WriteControl(
  2083. THIS_
  2084. IN ULONG Processor,
  2085. IN ULONG64 Offset,
  2086. IN PVOID Buffer,
  2087. IN ULONG BufferSize,
  2088. OUT PULONG BytesWritten
  2089. )
  2090. {
  2091. if (m_KdSupport != EXDI_KD_IOCTL)
  2092. {
  2093. return E_UNEXPECTED;
  2094. }
  2095. HRESULT Status = m_Server->
  2096. WritePhysicalMemoryOrPeriphIO(Offset, EXDI_ADDR_CONTROL_SPACE,
  2097. BufferSize, 8, (PBYTE)Buffer);
  2098. if (Status == S_OK)
  2099. {
  2100. *BytesWritten = BufferSize;
  2101. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_CONTROL);
  2102. }
  2103. return Status;
  2104. }
  2105. HRESULT
  2106. ExdiLiveKernelTargetInfo::ReadIo(
  2107. THIS_
  2108. IN ULONG InterfaceType,
  2109. IN ULONG BusNumber,
  2110. IN ULONG AddressSpace,
  2111. IN ULONG64 Offset,
  2112. OUT PVOID Buffer,
  2113. IN ULONG BufferSize,
  2114. OUT PULONG BytesRead
  2115. )
  2116. {
  2117. HRESULT Status = m_Server->
  2118. ReadPhysicalMemoryOrPeriphIO(Offset, 1, BufferSize, 8, (PBYTE)Buffer);
  2119. if (Status == S_OK)
  2120. {
  2121. *BytesRead = BufferSize;
  2122. }
  2123. return Status;
  2124. }
  2125. HRESULT
  2126. ExdiLiveKernelTargetInfo::WriteIo(
  2127. THIS_
  2128. IN ULONG InterfaceType,
  2129. IN ULONG BusNumber,
  2130. IN ULONG AddressSpace,
  2131. IN ULONG64 Offset,
  2132. IN PVOID Buffer,
  2133. IN ULONG BufferSize,
  2134. OUT PULONG BytesWritten
  2135. )
  2136. {
  2137. HRESULT Status = m_Server->
  2138. WritePhysicalMemoryOrPeriphIO(Offset, 1, BufferSize, 8, (PBYTE)Buffer);
  2139. if (Status == S_OK)
  2140. {
  2141. *BytesWritten = BufferSize;
  2142. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_IO);
  2143. }
  2144. return Status;
  2145. }
  2146. HRESULT
  2147. ExdiLiveKernelTargetInfo::ReadMsr(
  2148. THIS_
  2149. IN ULONG Msr,
  2150. OUT PULONG64 Value
  2151. )
  2152. {
  2153. if (m_KdSupport != EXDI_KD_IOCTL)
  2154. {
  2155. return E_UNEXPECTED;
  2156. }
  2157. HRESULT Status = m_Server->
  2158. ReadPhysicalMemoryOrPeriphIO(Msr, EXDI_ADDR_MSR,
  2159. 1, 64, (PBYTE)Value);
  2160. return Status;
  2161. }
  2162. HRESULT
  2163. ExdiLiveKernelTargetInfo::WriteMsr(
  2164. THIS_
  2165. IN ULONG Msr,
  2166. IN ULONG64 Value
  2167. )
  2168. {
  2169. if (m_KdSupport != EXDI_KD_IOCTL)
  2170. {
  2171. return E_UNEXPECTED;
  2172. }
  2173. HRESULT Status = m_Server->
  2174. WritePhysicalMemoryOrPeriphIO(Msr, EXDI_ADDR_MSR,
  2175. 1, 64, (PBYTE)&Value);
  2176. if (Status == S_OK)
  2177. {
  2178. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_MSR);
  2179. }
  2180. return Status;
  2181. }
  2182. HRESULT
  2183. ExdiLiveKernelTargetInfo::ReadBusData(
  2184. THIS_
  2185. IN ULONG BusDataType,
  2186. IN ULONG BusNumber,
  2187. IN ULONG SlotNumber,
  2188. IN ULONG Offset,
  2189. OUT PVOID Buffer,
  2190. IN ULONG BufferSize,
  2191. OUT PULONG BytesRead
  2192. )
  2193. {
  2194. if (m_KdSupport != EXDI_KD_IOCTL)
  2195. {
  2196. return E_UNEXPECTED;
  2197. }
  2198. HRESULT Status = m_Server->
  2199. ReadPhysicalMemoryOrPeriphIO(Offset, EXDI_ADDR_BUS_DATA,
  2200. BufferSize, 8, (PBYTE)Buffer);
  2201. if (Status == S_OK)
  2202. {
  2203. *BytesRead = BufferSize;
  2204. }
  2205. return Status;
  2206. }
  2207. HRESULT
  2208. ExdiLiveKernelTargetInfo::WriteBusData(
  2209. THIS_
  2210. IN ULONG BusDataType,
  2211. IN ULONG BusNumber,
  2212. IN ULONG SlotNumber,
  2213. IN ULONG Offset,
  2214. IN PVOID Buffer,
  2215. IN ULONG BufferSize,
  2216. OUT PULONG BytesWritten
  2217. )
  2218. {
  2219. if (m_KdSupport != EXDI_KD_IOCTL)
  2220. {
  2221. return E_UNEXPECTED;
  2222. }
  2223. HRESULT Status = m_Server->
  2224. WritePhysicalMemoryOrPeriphIO(Offset, EXDI_ADDR_BUS_DATA,
  2225. BufferSize, 8, (PBYTE)Buffer);
  2226. if (Status == S_OK)
  2227. {
  2228. *BytesWritten = BufferSize;
  2229. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_BUS_DATA);
  2230. }
  2231. return Status;
  2232. }
  2233. HRESULT
  2234. ExdiLiveKernelTargetInfo::CheckLowMemory(
  2235. THIS
  2236. )
  2237. {
  2238. // XXX drewb - This doesn't have any meaning in
  2239. // the general case. What about when we know it's
  2240. // NT on the other side of the emulator?
  2241. return E_UNEXPECTED;
  2242. }
  2243. //----------------------------------------------------------------------------
  2244. //
  2245. // UserTargetInfo data space methods.
  2246. //
  2247. //----------------------------------------------------------------------------
  2248. HRESULT
  2249. UserTargetInfo::ReadVirtualUncached(
  2250. THIS_
  2251. IN ULONG64 Offset,
  2252. OUT PVOID Buffer,
  2253. IN ULONG BufferSize,
  2254. OUT PULONG BytesRead
  2255. )
  2256. {
  2257. // ReadProcessMemory will fail if any part of the
  2258. // region to read does not have read access. This
  2259. // routine attempts to read the largest valid prefix
  2260. // so it has to break up reads on page boundaries.
  2261. HRESULT Status = S_OK;
  2262. ULONG TotalBytesRead = 0;
  2263. ULONG Read;
  2264. ULONG ReadSize;
  2265. while (BufferSize > 0)
  2266. {
  2267. // Calculate bytes to read and don't let read cross
  2268. // a page boundary.
  2269. ReadSize = g_TargetMachine->m_PageSize - (ULONG)
  2270. (Offset & (g_TargetMachine->m_PageSize - 1));
  2271. ReadSize = min(BufferSize, ReadSize);
  2272. if ((Status = m_Services->
  2273. ReadVirtual(g_CurrentProcess->FullHandle, Offset,
  2274. Buffer, ReadSize, &Read)) != S_OK)
  2275. {
  2276. if (TotalBytesRead != 0)
  2277. {
  2278. // If we've read something consider this a success.
  2279. Status = S_OK;
  2280. }
  2281. break;
  2282. }
  2283. TotalBytesRead += Read;
  2284. Offset += Read;
  2285. Buffer = (PVOID)((PUCHAR)Buffer + Read);
  2286. BufferSize -= (DWORD)Read;
  2287. }
  2288. if (Status == S_OK)
  2289. {
  2290. if (BytesRead != NULL)
  2291. {
  2292. *BytesRead = (DWORD)TotalBytesRead;
  2293. }
  2294. }
  2295. return Status;
  2296. }
  2297. HRESULT
  2298. UserTargetInfo::WriteVirtualUncached(
  2299. THIS_
  2300. IN ULONG64 Offset,
  2301. IN PVOID Buffer,
  2302. IN ULONG BufferSize,
  2303. OUT PULONG BytesWritten
  2304. )
  2305. {
  2306. ULONG RealBytesWritten;
  2307. HRESULT Status =
  2308. m_Services->WriteVirtual(g_CurrentProcess->FullHandle,
  2309. Offset, Buffer, BufferSize,
  2310. &RealBytesWritten);
  2311. *BytesWritten = (DWORD) RealBytesWritten;
  2312. if (Status == S_OK)
  2313. {
  2314. NotifyChangeDebuggeeState(DEBUG_CDS_DATA, DEBUG_DATA_SPACE_VIRTUAL);
  2315. }
  2316. return Status;
  2317. }
  2318. HRESULT
  2319. UserTargetInfo::GetFunctionTableListHead(void)
  2320. {
  2321. // Get the address of the dynamic function table list head which is the
  2322. // the same for all processes. This only has to be done once.
  2323. if (g_CurrentProcess->DynFuncTableList)
  2324. {
  2325. return S_OK;
  2326. }
  2327. if (m_Services->
  2328. GetFunctionTableListHead(g_CurrentProcess->FullHandle,
  2329. &g_CurrentProcess->DynFuncTableList) == S_OK)
  2330. {
  2331. return S_OK;
  2332. }
  2333. return TargetInfo::GetFunctionTableListHead();
  2334. }
  2335. HRESULT
  2336. UserTargetInfo::ReadOutOfProcessDynamicFunctionTable(PWSTR Dll,
  2337. ULONG64 Table,
  2338. PULONG RetTableSize,
  2339. PVOID* RetTableData)
  2340. {
  2341. HRESULT Status;
  2342. char DllA[MAX_PATH];
  2343. PVOID TableData;
  2344. ULONG TableSize;
  2345. if (!WideCharToMultiByte(CP_ACP, 0, Dll, -1,
  2346. DllA, sizeof(DllA), NULL, NULL))
  2347. {
  2348. return WIN32_LAST_STATUS();
  2349. }
  2350. // Allocate an initial buffer of a reasonable size to try
  2351. // and get the data in a single call.
  2352. TableSize = 65536;
  2353. for (;;)
  2354. {
  2355. TableData = malloc(TableSize);
  2356. if (TableData == NULL)
  2357. {
  2358. return E_OUTOFMEMORY;
  2359. }
  2360. Status = m_Services->
  2361. GetOutOfProcessFunctionTable(g_CurrentProcess->FullHandle,
  2362. DllA, Table, TableData,
  2363. TableSize, &TableSize);
  2364. if (Status == S_OK)
  2365. {
  2366. break;
  2367. }
  2368. free(TableData);
  2369. if (Status == S_FALSE)
  2370. {
  2371. // Buffer was too small so loop and try again with
  2372. // the newly retrieved size.
  2373. }
  2374. else
  2375. {
  2376. return Status;
  2377. }
  2378. }
  2379. *RetTableSize = TableSize;
  2380. *RetTableData = TableData;
  2381. return S_OK;
  2382. }
  2383. HRESULT
  2384. UserTargetInfo::QueryMemoryRegion(PULONG64 Handle,
  2385. BOOL HandleIsOffset,
  2386. PMEMORY_BASIC_INFORMATION64 Info)
  2387. {
  2388. MEMORY_BASIC_INFORMATION64 MemInfo;
  2389. HRESULT Status;
  2390. for (;;)
  2391. {
  2392. ULONG Used;
  2393. // The handle is always an offset in this mode so
  2394. // there's no need to check.
  2395. if ((Status = m_Services->
  2396. QueryVirtual(g_CurrentProcess->FullHandle,
  2397. *Handle, &MemInfo, sizeof(MemInfo), &Used)) != S_OK)
  2398. {
  2399. return Status;
  2400. }
  2401. if (g_TargetMachine->m_Ptr64)
  2402. {
  2403. if (Used != sizeof(MEMORY_BASIC_INFORMATION64))
  2404. {
  2405. return E_FAIL;
  2406. }
  2407. *Info = MemInfo;
  2408. }
  2409. else
  2410. {
  2411. if (Used != sizeof(MEMORY_BASIC_INFORMATION32))
  2412. {
  2413. return E_FAIL;
  2414. }
  2415. MemoryBasicInformation32To64((MEMORY_BASIC_INFORMATION32*)&MemInfo,
  2416. Info);
  2417. }
  2418. if (!((Info->Protect & PAGE_GUARD) ||
  2419. (Info->Protect & PAGE_NOACCESS) ||
  2420. (Info->State & MEM_FREE) ||
  2421. (Info->State & MEM_RESERVE)))
  2422. {
  2423. break;
  2424. }
  2425. *Handle = Info->BaseAddress + Info->RegionSize;
  2426. }
  2427. *Handle = Info->BaseAddress + Info->RegionSize;
  2428. return S_OK;
  2429. }
  2430. HRESULT
  2431. UserTargetInfo::ReadHandleData(
  2432. IN ULONG64 Handle,
  2433. IN ULONG DataType,
  2434. OUT OPTIONAL PVOID Buffer,
  2435. IN ULONG BufferSize,
  2436. OUT OPTIONAL PULONG DataSize
  2437. )
  2438. {
  2439. return m_Services->ReadHandleData(g_CurrentProcess->FullHandle,
  2440. Handle, DataType, Buffer, BufferSize,
  2441. DataSize);
  2442. }
  2443. HRESULT
  2444. UserTargetInfo::GetProcessorId
  2445. (ULONG Processor, PDEBUG_PROCESSOR_IDENTIFICATION_ALL Id)
  2446. {
  2447. ULONG Done;
  2448. return m_Services->GetProcessorId(Id, sizeof(*Id), &Done);
  2449. }
  2450. HRESULT
  2451. LocalUserTargetInfo::ReadVirtual(
  2452. THIS_
  2453. IN ULONG64 Offset,
  2454. OUT PVOID Buffer,
  2455. IN ULONG BufferSize,
  2456. OUT PULONG BytesRead
  2457. )
  2458. {
  2459. return ReadVirtualUncached(Offset, Buffer, BufferSize, BytesRead);
  2460. }
  2461. HRESULT
  2462. LocalUserTargetInfo::WriteVirtual(
  2463. THIS_
  2464. IN ULONG64 Offset,
  2465. IN PVOID Buffer,
  2466. IN ULONG BufferSize,
  2467. OUT PULONG BytesWritten
  2468. )
  2469. {
  2470. return WriteVirtualUncached(Offset, Buffer, BufferSize, BytesWritten);
  2471. }
  2472. HRESULT
  2473. RemoteUserTargetInfo::ReadVirtual(
  2474. THIS_
  2475. IN ULONG64 Offset,
  2476. OUT PVOID Buffer,
  2477. IN ULONG BufferSize,
  2478. OUT PULONG BytesRead
  2479. )
  2480. {
  2481. return g_VirtualCache.Read(Offset, Buffer, BufferSize, BytesRead);
  2482. }
  2483. HRESULT
  2484. RemoteUserTargetInfo::WriteVirtual(
  2485. THIS_
  2486. IN ULONG64 Offset,
  2487. IN PVOID Buffer,
  2488. IN ULONG BufferSize,
  2489. OUT PULONG BytesWritten
  2490. )
  2491. {
  2492. return g_VirtualCache.Write(Offset, Buffer, BufferSize, BytesWritten);
  2493. }
  2494. //----------------------------------------------------------------------------
  2495. //
  2496. // IDebugDataSpaces.
  2497. //
  2498. //----------------------------------------------------------------------------
  2499. STDMETHODIMP
  2500. DebugClient::ReadVirtual(
  2501. THIS_
  2502. IN ULONG64 Offset,
  2503. OUT PVOID Buffer,
  2504. IN ULONG BufferSize,
  2505. OUT PULONG BytesRead
  2506. )
  2507. {
  2508. if (!IS_MACHINE_ACCESSIBLE())
  2509. {
  2510. return E_UNEXPECTED;
  2511. }
  2512. ENTER_ENGINE();
  2513. ULONG BytesTemp;
  2514. HRESULT Status =
  2515. g_Target->ReadVirtual(Offset, Buffer, BufferSize,
  2516. BytesRead != NULL ? BytesRead : &BytesTemp);
  2517. LEAVE_ENGINE();
  2518. return Status;
  2519. }
  2520. STDMETHODIMP
  2521. DebugClient::WriteVirtual(
  2522. THIS_
  2523. IN ULONG64 Offset,
  2524. IN PVOID Buffer,
  2525. IN ULONG BufferSize,
  2526. OUT PULONG BytesWritten
  2527. )
  2528. {
  2529. if (!IS_MACHINE_ACCESSIBLE())
  2530. {
  2531. return E_UNEXPECTED;
  2532. }
  2533. ENTER_ENGINE();
  2534. ULONG BytesTemp;
  2535. HRESULT Status =
  2536. g_Target->WriteVirtual(Offset, Buffer, BufferSize,
  2537. BytesWritten != NULL ? BytesWritten :
  2538. &BytesTemp);
  2539. LEAVE_ENGINE();
  2540. return Status;
  2541. }
  2542. STDMETHODIMP
  2543. DebugClient::SearchVirtual(
  2544. THIS_
  2545. IN ULONG64 Offset,
  2546. IN ULONG64 Length,
  2547. IN PVOID Pattern,
  2548. IN ULONG PatternSize,
  2549. IN ULONG PatternGranularity,
  2550. OUT PULONG64 MatchOffset
  2551. )
  2552. {
  2553. if (PatternGranularity == 0 ||
  2554. PatternSize % PatternGranularity)
  2555. {
  2556. return E_INVALIDARG;
  2557. }
  2558. if (!IS_MACHINE_ACCESSIBLE())
  2559. {
  2560. return E_UNEXPECTED;
  2561. }
  2562. HRESULT Status;
  2563. ENTER_ENGINE();
  2564. Status = g_Target->SearchVirtual(Offset, Length, Pattern,
  2565. PatternSize, PatternGranularity,
  2566. MatchOffset);
  2567. LEAVE_ENGINE();
  2568. return Status;
  2569. }
  2570. STDMETHODIMP
  2571. DebugClient::ReadVirtualUncached(
  2572. THIS_
  2573. IN ULONG64 Offset,
  2574. OUT PVOID Buffer,
  2575. IN ULONG BufferSize,
  2576. OUT PULONG BytesRead
  2577. )
  2578. {
  2579. if (!IS_MACHINE_ACCESSIBLE())
  2580. {
  2581. return E_UNEXPECTED;
  2582. }
  2583. ENTER_ENGINE();
  2584. ULONG BytesTemp;
  2585. HRESULT Status =
  2586. g_Target->ReadVirtualUncached(Offset, Buffer, BufferSize,
  2587. BytesRead != NULL ? BytesRead :
  2588. &BytesTemp);
  2589. LEAVE_ENGINE();
  2590. return Status;
  2591. }
  2592. STDMETHODIMP
  2593. DebugClient::WriteVirtualUncached(
  2594. THIS_
  2595. IN ULONG64 Offset,
  2596. IN PVOID Buffer,
  2597. IN ULONG BufferSize,
  2598. OUT PULONG BytesWritten
  2599. )
  2600. {
  2601. if (!IS_MACHINE_ACCESSIBLE())
  2602. {
  2603. return E_UNEXPECTED;
  2604. }
  2605. ENTER_ENGINE();
  2606. ULONG BytesTemp;
  2607. HRESULT Status =
  2608. g_Target->WriteVirtualUncached(Offset, Buffer, BufferSize,
  2609. BytesWritten != NULL ? BytesWritten :
  2610. &BytesTemp);
  2611. LEAVE_ENGINE();
  2612. return Status;
  2613. }
  2614. STDMETHODIMP
  2615. DebugClient::ReadPointersVirtual(
  2616. THIS_
  2617. IN ULONG Count,
  2618. IN ULONG64 Offset,
  2619. OUT /* size_is(Count) */ PULONG64 Ptrs
  2620. )
  2621. {
  2622. HRESULT Status;
  2623. ENTER_ENGINE();
  2624. if (!IS_MACHINE_ACCESSIBLE())
  2625. {
  2626. Status = E_UNEXPECTED;
  2627. }
  2628. else
  2629. {
  2630. ULONG Done;
  2631. Status = S_OK;
  2632. while (Count-- > 0)
  2633. {
  2634. if ((Status = g_Target->
  2635. ReadPointer(g_Machine, Offset, Ptrs)) != S_OK)
  2636. {
  2637. break;
  2638. }
  2639. Offset += g_Machine->m_Ptr64 ? sizeof(ULONG64) : sizeof(ULONG);
  2640. Ptrs++;
  2641. }
  2642. }
  2643. LEAVE_ENGINE();
  2644. return Status;
  2645. }
  2646. STDMETHODIMP
  2647. DebugClient::WritePointersVirtual(
  2648. THIS_
  2649. IN ULONG Count,
  2650. IN ULONG64 Offset,
  2651. IN /* size_is(Count) */ PULONG64 Ptrs
  2652. )
  2653. {
  2654. HRESULT Status;
  2655. ENTER_ENGINE();
  2656. if (!IS_MACHINE_ACCESSIBLE())
  2657. {
  2658. Status = E_UNEXPECTED;
  2659. }
  2660. else
  2661. {
  2662. ULONG Done;
  2663. Status = S_OK;
  2664. while (Count-- > 0)
  2665. {
  2666. if ((Status = g_Target->
  2667. WritePointer(g_Machine, Offset, *Ptrs)) != S_OK)
  2668. {
  2669. break;
  2670. }
  2671. Offset += g_Machine->m_Ptr64 ? sizeof(ULONG64) : sizeof(ULONG);
  2672. Ptrs++;
  2673. }
  2674. }
  2675. LEAVE_ENGINE();
  2676. return Status;
  2677. }
  2678. STDMETHODIMP
  2679. DebugClient::ReadPhysical(
  2680. THIS_
  2681. IN ULONG64 Offset,
  2682. OUT PVOID Buffer,
  2683. IN ULONG BufferSize,
  2684. OUT PULONG BytesRead
  2685. )
  2686. {
  2687. if (!IS_MACHINE_ACCESSIBLE())
  2688. {
  2689. return E_UNEXPECTED;
  2690. }
  2691. ENTER_ENGINE();
  2692. ULONG BytesTemp;
  2693. HRESULT Status =
  2694. g_Target->ReadPhysical(Offset, Buffer, BufferSize,
  2695. BytesRead != NULL ? BytesRead : &BytesTemp);
  2696. LEAVE_ENGINE();
  2697. return Status;
  2698. }
  2699. STDMETHODIMP
  2700. DebugClient::WritePhysical(
  2701. THIS_
  2702. IN ULONG64 Offset,
  2703. IN PVOID Buffer,
  2704. IN ULONG BufferSize,
  2705. OUT PULONG BytesWritten
  2706. )
  2707. {
  2708. if (!IS_MACHINE_ACCESSIBLE())
  2709. {
  2710. return E_UNEXPECTED;
  2711. }
  2712. ENTER_ENGINE();
  2713. ULONG BytesTemp;
  2714. HRESULT Status =
  2715. g_Target->WritePhysical(Offset, Buffer, BufferSize,
  2716. BytesWritten != NULL ? BytesWritten :
  2717. &BytesTemp);
  2718. LEAVE_ENGINE();
  2719. return Status;
  2720. }
  2721. STDMETHODIMP
  2722. DebugClient::ReadControl(
  2723. THIS_
  2724. IN ULONG Processor,
  2725. IN ULONG64 Offset,
  2726. OUT PVOID Buffer,
  2727. IN ULONG BufferSize,
  2728. OUT PULONG BytesRead
  2729. )
  2730. {
  2731. if (!IS_MACHINE_ACCESSIBLE())
  2732. {
  2733. return E_UNEXPECTED;
  2734. }
  2735. ENTER_ENGINE();
  2736. // KSPECIAL_REGISTER content is kept in control space
  2737. // so accessing control space may touch data that's
  2738. // cached in the current machine KSPECIAL_REGISTERS.
  2739. // Flush the current machine to maintain consistency.
  2740. FlushRegContext();
  2741. ULONG BytesTemp;
  2742. HRESULT Status =
  2743. g_Target->ReadControl(Processor, Offset, Buffer, BufferSize,
  2744. BytesRead != NULL ? BytesRead : &BytesTemp);
  2745. LEAVE_ENGINE();
  2746. return Status;
  2747. }
  2748. STDMETHODIMP
  2749. DebugClient::WriteControl(
  2750. THIS_
  2751. IN ULONG Processor,
  2752. IN ULONG64 Offset,
  2753. IN PVOID Buffer,
  2754. IN ULONG BufferSize,
  2755. OUT PULONG BytesWritten
  2756. )
  2757. {
  2758. if (!IS_MACHINE_ACCESSIBLE())
  2759. {
  2760. return E_UNEXPECTED;
  2761. }
  2762. ENTER_ENGINE();
  2763. // KSPECIAL_REGISTER content is kept in control space
  2764. // so accessing control space may touch data that's
  2765. // cached in the current machine KSPECIAL_REGISTERS.
  2766. // Flush the current machine to maintain consistency.
  2767. FlushRegContext();
  2768. ULONG BytesTemp;
  2769. HRESULT Status =
  2770. g_Target->WriteControl(Processor, Offset, Buffer, BufferSize,
  2771. BytesWritten != NULL ? BytesWritten :
  2772. &BytesTemp);
  2773. LEAVE_ENGINE();
  2774. return Status;
  2775. }
  2776. STDMETHODIMP
  2777. DebugClient::ReadIo(
  2778. THIS_
  2779. IN ULONG InterfaceType,
  2780. IN ULONG BusNumber,
  2781. IN ULONG AddressSpace,
  2782. IN ULONG64 Offset,
  2783. OUT PVOID Buffer,
  2784. IN ULONG BufferSize,
  2785. OUT PULONG BytesRead
  2786. )
  2787. {
  2788. if (!IS_MACHINE_ACCESSIBLE())
  2789. {
  2790. return E_UNEXPECTED;
  2791. }
  2792. ENTER_ENGINE();
  2793. ULONG BytesTemp;
  2794. HRESULT Status =
  2795. g_Target->ReadIo(InterfaceType, BusNumber, AddressSpace,
  2796. Offset, Buffer, BufferSize,
  2797. BytesRead != NULL ? BytesRead : &BytesTemp);
  2798. LEAVE_ENGINE();
  2799. return Status;
  2800. }
  2801. STDMETHODIMP
  2802. DebugClient::WriteIo(
  2803. THIS_
  2804. IN ULONG InterfaceType,
  2805. IN ULONG BusNumber,
  2806. IN ULONG AddressSpace,
  2807. IN ULONG64 Offset,
  2808. IN PVOID Buffer,
  2809. IN ULONG BufferSize,
  2810. OUT PULONG BytesWritten
  2811. )
  2812. {
  2813. if (!IS_MACHINE_ACCESSIBLE())
  2814. {
  2815. return E_UNEXPECTED;
  2816. }
  2817. ENTER_ENGINE();
  2818. ULONG BytesTemp;
  2819. HRESULT Status =
  2820. g_Target->WriteIo(InterfaceType, BusNumber, AddressSpace,
  2821. Offset, Buffer, BufferSize,
  2822. BytesWritten != NULL ? BytesWritten : &BytesTemp);
  2823. LEAVE_ENGINE();
  2824. return Status;
  2825. }
  2826. STDMETHODIMP
  2827. DebugClient::ReadMsr(
  2828. THIS_
  2829. IN ULONG Msr,
  2830. OUT PULONG64 Value
  2831. )
  2832. {
  2833. if (!IS_MACHINE_ACCESSIBLE())
  2834. {
  2835. return E_UNEXPECTED;
  2836. }
  2837. ENTER_ENGINE();
  2838. HRESULT Status =
  2839. g_Target->ReadMsr(Msr, Value);
  2840. LEAVE_ENGINE();
  2841. return Status;
  2842. }
  2843. STDMETHODIMP
  2844. DebugClient::WriteMsr(
  2845. THIS_
  2846. IN ULONG Msr,
  2847. IN ULONG64 Value
  2848. )
  2849. {
  2850. if (!IS_MACHINE_ACCESSIBLE())
  2851. {
  2852. return E_UNEXPECTED;
  2853. }
  2854. ENTER_ENGINE();
  2855. HRESULT Status =
  2856. g_Target->WriteMsr(Msr, Value);
  2857. LEAVE_ENGINE();
  2858. return Status;
  2859. }
  2860. STDMETHODIMP
  2861. DebugClient::ReadBusData(
  2862. THIS_
  2863. IN ULONG BusDataType,
  2864. IN ULONG BusNumber,
  2865. IN ULONG SlotNumber,
  2866. IN ULONG Offset,
  2867. OUT PVOID Buffer,
  2868. IN ULONG BufferSize,
  2869. OUT PULONG BytesRead
  2870. )
  2871. {
  2872. if (!IS_MACHINE_ACCESSIBLE())
  2873. {
  2874. return E_UNEXPECTED;
  2875. }
  2876. ENTER_ENGINE();
  2877. ULONG BytesTemp;
  2878. HRESULT Status =
  2879. g_Target->ReadBusData(BusDataType, BusNumber, SlotNumber,
  2880. Offset, Buffer, BufferSize,
  2881. BytesRead != NULL ? BytesRead : &BytesTemp);
  2882. LEAVE_ENGINE();
  2883. return Status;
  2884. }
  2885. STDMETHODIMP
  2886. DebugClient::WriteBusData(
  2887. THIS_
  2888. IN ULONG BusDataType,
  2889. IN ULONG BusNumber,
  2890. IN ULONG SlotNumber,
  2891. IN ULONG Offset,
  2892. IN PVOID Buffer,
  2893. IN ULONG BufferSize,
  2894. OUT PULONG BytesWritten
  2895. )
  2896. {
  2897. if (!IS_MACHINE_ACCESSIBLE())
  2898. {
  2899. return E_UNEXPECTED;
  2900. }
  2901. ENTER_ENGINE();
  2902. ULONG BytesTemp;
  2903. HRESULT Status =
  2904. g_Target->WriteBusData(BusDataType, BusNumber, SlotNumber,
  2905. Offset, Buffer, BufferSize,
  2906. BytesWritten != NULL ? BytesWritten :
  2907. &BytesTemp);
  2908. LEAVE_ENGINE();
  2909. return Status;
  2910. }
  2911. STDMETHODIMP
  2912. DebugClient::CheckLowMemory(
  2913. THIS
  2914. )
  2915. {
  2916. if (!IS_MACHINE_ACCESSIBLE())
  2917. {
  2918. return E_UNEXPECTED;
  2919. }
  2920. ENTER_ENGINE();
  2921. HRESULT Status =
  2922. g_Target->CheckLowMemory();
  2923. LEAVE_ENGINE();
  2924. return Status;
  2925. }
  2926. STDMETHODIMP
  2927. DebugClient::ReadDebuggerData(
  2928. THIS_
  2929. IN ULONG Index,
  2930. OUT PVOID Buffer,
  2931. IN ULONG BufferSize,
  2932. OUT OPTIONAL PULONG DataSize
  2933. )
  2934. {
  2935. HRESULT Status;
  2936. ENTER_ENGINE();
  2937. // Wait till the machine is accessible because on dump files the
  2938. // debugger data block requires symbols to be loaded.
  2939. if (!IS_MACHINE_ACCESSIBLE())
  2940. {
  2941. Status = E_UNEXPECTED;
  2942. goto Exit;
  2943. }
  2944. PVOID Data;
  2945. ULONG Size;
  2946. ULONG64 DataSpace;
  2947. if (Index < sizeof(KdDebuggerData))
  2948. {
  2949. // Even though internally all of the debugger data is
  2950. // a single buffer that could be read arbitrarily we
  2951. // restrict access to the defined constants to
  2952. // preserve the abstraction that each constant refers
  2953. // to a separate piece of data.
  2954. if (Index & (sizeof(ULONG64) - 1))
  2955. {
  2956. Status = E_INVALIDARG;
  2957. goto Exit;
  2958. }
  2959. Data = (PUCHAR)&KdDebuggerData + Index;
  2960. Size = sizeof(ULONG64);
  2961. }
  2962. else
  2963. {
  2964. switch(Index)
  2965. {
  2966. case DEBUG_DATA_PaeEnabled:
  2967. DataSpace = KdDebuggerData.PaeEnabled;
  2968. Data = &DataSpace;
  2969. Size = sizeof(BOOLEAN);
  2970. break;
  2971. case DEBUG_DATA_SharedUserData:
  2972. DataSpace = g_TargetMachine->m_SharedUserDataOffset;
  2973. Data = &DataSpace;
  2974. Size = sizeof(ULONG64);
  2975. break;
  2976. default:
  2977. Status = E_INVALIDARG;
  2978. goto Exit;
  2979. }
  2980. }
  2981. Status = FillDataBuffer(Data, Size, Buffer, BufferSize, DataSize);
  2982. Exit:
  2983. LEAVE_ENGINE();
  2984. return Status;
  2985. }
  2986. STDMETHODIMP
  2987. DebugClient::ReadProcessorSystemData(
  2988. THIS_
  2989. IN ULONG Processor,
  2990. IN ULONG Index,
  2991. OUT PVOID Buffer,
  2992. IN ULONG BufferSize,
  2993. OUT OPTIONAL PULONG DataSize
  2994. )
  2995. {
  2996. HRESULT Status = S_OK;
  2997. PVOID Data;
  2998. ULONG Size;
  2999. ULONG64 DataSpace;
  3000. DEBUG_PROCESSOR_IDENTIFICATION_ALL AllId;
  3001. ENTER_ENGINE();
  3002. switch(Index)
  3003. {
  3004. case DEBUG_DATA_KPCR_OFFSET:
  3005. case DEBUG_DATA_KPRCB_OFFSET:
  3006. case DEBUG_DATA_KTHREAD_OFFSET:
  3007. if (!IS_MACHINE_SET())
  3008. {
  3009. Status = E_UNEXPECTED;
  3010. }
  3011. else
  3012. {
  3013. Status = g_Target->
  3014. GetProcessorSystemDataOffset(Processor, Index, &DataSpace);
  3015. Data = &DataSpace;
  3016. Size = sizeof(DataSpace);
  3017. }
  3018. break;
  3019. case DEBUG_DATA_BASE_TRANSLATION_VIRTUAL_OFFSET:
  3020. if (!IS_MACHINE_SET())
  3021. {
  3022. Status = E_UNEXPECTED;
  3023. }
  3024. else
  3025. {
  3026. Status = g_Machine->GetBaseTranslationVirtualOffset(&DataSpace);
  3027. Data = &DataSpace;
  3028. Size = sizeof(DataSpace);
  3029. }
  3030. break;
  3031. case DEBUG_DATA_PROCESSOR_IDENTIFICATION:
  3032. if (!IS_TARGET_SET())
  3033. {
  3034. Status = E_UNEXPECTED;
  3035. }
  3036. else
  3037. {
  3038. ZeroMemory(&AllId, sizeof(AllId));
  3039. Status = g_Target->GetProcessorId(Processor, &AllId);
  3040. Data = &AllId;
  3041. Size = sizeof(AllId);
  3042. }
  3043. break;
  3044. default:
  3045. Status = E_INVALIDARG;
  3046. break;
  3047. }
  3048. if (Status == S_OK)
  3049. {
  3050. if (DataSize != NULL)
  3051. {
  3052. *DataSize = Size;
  3053. }
  3054. if (BufferSize < Size)
  3055. {
  3056. Status = S_FALSE;
  3057. Size = BufferSize;
  3058. }
  3059. memcpy(Buffer, Data, Size);
  3060. }
  3061. LEAVE_ENGINE();
  3062. return Status;
  3063. }
  3064. STDMETHODIMP
  3065. DebugClient::VirtualToPhysical(
  3066. THIS_
  3067. IN ULONG64 Virtual,
  3068. OUT PULONG64 Physical
  3069. )
  3070. {
  3071. HRESULT Status;
  3072. ENTER_ENGINE();
  3073. if (!IS_MACHINE_ACCESSIBLE())
  3074. {
  3075. Status = E_UNEXPECTED;
  3076. }
  3077. else
  3078. {
  3079. ULONG Levels;
  3080. ULONG PfIndex;
  3081. Status = g_Machine->
  3082. GetVirtualTranslationPhysicalOffsets(Virtual, NULL, 0,
  3083. &Levels, &PfIndex, Physical);
  3084. // GVTPO returns a special error code if the translation
  3085. // succeeded down to the level of the actual data but
  3086. // the data page itself is in the page file. This is used
  3087. // for the page file dump support. To an external caller,
  3088. // though, it's not useful so translate it into the standard
  3089. // page-not-available error.
  3090. if (Status == HR_PAGE_IN_PAGE_FILE)
  3091. {
  3092. Status = HR_PAGE_NOT_AVAILABLE;
  3093. }
  3094. }
  3095. LEAVE_ENGINE();
  3096. return Status;
  3097. }
  3098. STDMETHODIMP
  3099. DebugClient::GetVirtualTranslationPhysicalOffsets(
  3100. THIS_
  3101. IN ULONG64 Virtual,
  3102. OUT OPTIONAL /* size_is(OffsetsSize) */ PULONG64 Offsets,
  3103. IN ULONG OffsetsSize,
  3104. OUT OPTIONAL PULONG Levels
  3105. )
  3106. {
  3107. HRESULT Status;
  3108. ENTER_ENGINE();
  3109. ULONG _Levels = 0;
  3110. if (!IS_MACHINE_ACCESSIBLE())
  3111. {
  3112. Status = E_UNEXPECTED;
  3113. }
  3114. else
  3115. {
  3116. ULONG PfIndex;
  3117. ULONG64 LastPhys;
  3118. Status = g_Machine->
  3119. GetVirtualTranslationPhysicalOffsets(Virtual, Offsets,
  3120. OffsetsSize, &_Levels,
  3121. &PfIndex, &LastPhys);
  3122. // GVTPO returns a special error code if the translation
  3123. // succeeded down to the level of the actual data but
  3124. // the data page itself is in the page file. This is used
  3125. // for the page file dump support. To an external caller,
  3126. // though, it's not useful so translate it into the standard
  3127. // page-not-available error.
  3128. if (Status == HR_PAGE_IN_PAGE_FILE)
  3129. {
  3130. Status = HR_PAGE_NOT_AVAILABLE;
  3131. }
  3132. // If no translations occurred return the given failure.
  3133. // If there was a failure but translations occurred return
  3134. // S_FALSE to indicate the translation was incomplete.
  3135. if (_Levels > 0 && Status != S_OK)
  3136. {
  3137. Status = S_FALSE;
  3138. }
  3139. }
  3140. if (Levels != NULL)
  3141. {
  3142. *Levels = _Levels;
  3143. }
  3144. LEAVE_ENGINE();
  3145. return Status;
  3146. }
  3147. STDMETHODIMP
  3148. DebugClient::ReadHandleData(
  3149. THIS_
  3150. IN ULONG64 Handle,
  3151. IN ULONG DataType,
  3152. OUT OPTIONAL PVOID Buffer,
  3153. IN ULONG BufferSize,
  3154. OUT OPTIONAL PULONG DataSize
  3155. )
  3156. {
  3157. HRESULT Status;
  3158. ENTER_ENGINE();
  3159. if (!IS_TARGET_SET())
  3160. {
  3161. Status = E_UNEXPECTED;
  3162. }
  3163. else
  3164. {
  3165. Status = g_Target->ReadHandleData(Handle, DataType, Buffer,
  3166. BufferSize, DataSize);
  3167. }
  3168. LEAVE_ENGINE();
  3169. return Status;
  3170. }
  3171. STDMETHODIMP
  3172. DebugClient::FillVirtual(
  3173. THIS_
  3174. IN ULONG64 Start,
  3175. IN ULONG Size,
  3176. IN PVOID Pattern,
  3177. IN ULONG PatternSize,
  3178. OUT OPTIONAL PULONG Filled
  3179. )
  3180. {
  3181. HRESULT Status;
  3182. ENTER_ENGINE();
  3183. if (PatternSize == 0)
  3184. {
  3185. Status = E_INVALIDARG;
  3186. }
  3187. else if (!IS_TARGET_SET())
  3188. {
  3189. Status = E_UNEXPECTED;
  3190. }
  3191. else
  3192. {
  3193. ULONG _Filled = 0;
  3194. Status = g_Target->FillVirtual(Start, Size, Pattern, PatternSize,
  3195. &_Filled);
  3196. if (Filled != NULL)
  3197. {
  3198. *Filled = _Filled;
  3199. }
  3200. }
  3201. LEAVE_ENGINE();
  3202. return Status;
  3203. }
  3204. STDMETHODIMP
  3205. DebugClient::FillPhysical(
  3206. THIS_
  3207. IN ULONG64 Start,
  3208. IN ULONG Size,
  3209. IN PVOID Pattern,
  3210. IN ULONG PatternSize,
  3211. OUT OPTIONAL PULONG Filled
  3212. )
  3213. {
  3214. HRESULT Status;
  3215. ENTER_ENGINE();
  3216. if (PatternSize == 0)
  3217. {
  3218. Status = E_INVALIDARG;
  3219. }
  3220. else if (!IS_TARGET_SET())
  3221. {
  3222. Status = E_UNEXPECTED;
  3223. }
  3224. else
  3225. {
  3226. ULONG _Filled = 0;
  3227. Status = g_Target->FillPhysical(Start, Size, Pattern, PatternSize,
  3228. &_Filled);
  3229. if (Filled != NULL)
  3230. {
  3231. *Filled = _Filled;
  3232. }
  3233. }
  3234. LEAVE_ENGINE();
  3235. return Status;
  3236. }
  3237. STDMETHODIMP
  3238. DebugClient::QueryVirtual(
  3239. THIS_
  3240. IN ULONG64 Offset,
  3241. OUT PMEMORY_BASIC_INFORMATION64 Info
  3242. )
  3243. {
  3244. HRESULT Status;
  3245. ENTER_ENGINE();
  3246. if (!IS_TARGET_SET())
  3247. {
  3248. Status = E_UNEXPECTED;
  3249. }
  3250. else if (!IS_USER_TARGET())
  3251. {
  3252. return E_NOTIMPL;
  3253. }
  3254. else
  3255. {
  3256. ULONG64 Handle = Offset;
  3257. Status = g_Target->QueryMemoryRegion(&Handle, TRUE, Info);
  3258. }
  3259. LEAVE_ENGINE();
  3260. return Status;
  3261. }