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.

3741 lines
91 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Low-level debugging service interface implementations.
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000-2001.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "pch.hpp"
  9. #include <time.h>
  10. #include <comsvcs.h>
  11. #include "dbgsvc.hpp"
  12. #ifndef NT_NATIVE
  13. // #include <winbasep.h>
  14. extern "C" {
  15. BOOL
  16. WINAPI
  17. CloseProfileUserMapping(
  18. VOID
  19. );
  20. };
  21. // winbasep.h
  22. #else
  23. #define CloseProfileUserMapping()
  24. #endif
  25. // SYSTEM_PROCESS_INFORMATION can change in size, requiring
  26. // different offsets to get to thread information.
  27. #define NT4_SYSTEM_PROCESS_INFORMATION_SIZE 136
  28. #define W2K_SYSTEM_PROCESS_INFORMATION_SIZE 184
  29. #define SYSTEM_PROCESS_NAME "System Process"
  30. #define SYSTEM_PROCESS_NAME_W L"System Process"
  31. #define PEBLESS_PROCESS_NAME "System"
  32. ULONG g_UserServicesUninitialized;
  33. //----------------------------------------------------------------------------
  34. //
  35. // UserDebugServices.
  36. //
  37. //----------------------------------------------------------------------------
  38. UserDebugServices::UserDebugServices(void)
  39. {
  40. m_Refs = 1;
  41. m_Initialized = FALSE;
  42. }
  43. UserDebugServices::~UserDebugServices(void)
  44. {
  45. }
  46. STDMETHODIMP
  47. UserDebugServices::QueryInterface(
  48. THIS_
  49. IN REFIID InterfaceId,
  50. OUT PVOID* Interface
  51. )
  52. {
  53. HRESULT Status;
  54. *Interface = NULL;
  55. Status = S_OK;
  56. if (DbgIsEqualIID(InterfaceId, __uuidof(IUnknown)) ||
  57. DbgIsEqualIID(InterfaceId, __uuidof(IUserDebugServices)))
  58. {
  59. *Interface = (IUserDebugServices *)this;
  60. }
  61. else
  62. {
  63. Status = E_NOINTERFACE;
  64. }
  65. if (Status == S_OK)
  66. {
  67. AddRef();
  68. }
  69. return Status;
  70. }
  71. STDMETHODIMP_(ULONG)
  72. UserDebugServices::AddRef(
  73. THIS
  74. )
  75. {
  76. return InterlockedIncrement((PLONG)&m_Refs);
  77. }
  78. STDMETHODIMP_(ULONG)
  79. UserDebugServices::Release(
  80. THIS
  81. )
  82. {
  83. LONG Refs = InterlockedDecrement((PLONG)&m_Refs);
  84. if (Refs == 0)
  85. {
  86. delete this;
  87. }
  88. return Refs;
  89. }
  90. HRESULT
  91. UserDebugServices::Initialize(
  92. THIS_
  93. OUT PULONG Flags
  94. )
  95. {
  96. m_Initialized = TRUE;
  97. *Flags = 0;
  98. return S_OK;
  99. }
  100. HRESULT
  101. UserDebugServices::Uninitialize(
  102. THIS_
  103. IN BOOL Global
  104. )
  105. {
  106. m_Initialized = FALSE;
  107. if (Global)
  108. {
  109. g_UserServicesUninitialized++;
  110. }
  111. return S_OK;
  112. }
  113. HRESULT
  114. UserDebugServices::Initialize(PSTR Identity, PVOID* Interface)
  115. {
  116. HRESULT Status;
  117. ULONG Flags;
  118. if ((Status = Initialize(&Flags)) != S_OK)
  119. {
  120. return Status;
  121. }
  122. *Interface = (IUserDebugServices*)this;
  123. return S_OK;
  124. }
  125. void
  126. UserDebugServices::Finalize(void)
  127. {
  128. // Take a reference on this object for the RPC client
  129. // thread to hold.
  130. AddRef();
  131. }
  132. void
  133. UserDebugServices::Uninitialize(void)
  134. {
  135. // Directly destroy the client object rather than releasing
  136. // as the remote client may have exited without politely
  137. // cleaning up references.
  138. delete this;
  139. }
  140. //----------------------------------------------------------------------------
  141. //
  142. // LiveUserDebugServices.
  143. //
  144. //----------------------------------------------------------------------------
  145. // This global instance is intended for direct use only
  146. // by routines which need a temporary local service instance.
  147. LiveUserDebugServices g_LiveUserDebugServices(FALSE);
  148. LiveUserDebugServices::LiveUserDebugServices(BOOL Remote)
  149. {
  150. m_Remote = Remote;
  151. m_EventProcessId = 0;
  152. m_ContextSize = 0;
  153. m_SysProcInfoSize = 0;
  154. m_PlatformId = VER_PLATFORM_WIN32s;
  155. m_DebugObject = NULL;
  156. }
  157. LiveUserDebugServices::~LiveUserDebugServices(void)
  158. {
  159. if (m_DebugObject != NULL)
  160. {
  161. g_NtDllCalls.NtClose(m_DebugObject);
  162. }
  163. }
  164. HRESULT
  165. GetOsVerInfo(LPOSVERSIONINFOW OsVersionInfo, PBOOL WideCsd)
  166. {
  167. *WideCsd = TRUE;
  168. ZeroMemory(OsVersionInfo, sizeof(*OsVersionInfo));
  169. OsVersionInfo->dwOSVersionInfoSize = sizeof(*OsVersionInfo);
  170. #ifdef NT_NATIVE
  171. NTSTATUS NtStatus;
  172. if (!NT_SUCCESS(NtStatus = RtlGetVersion(OsVersionInfo)))
  173. {
  174. return HRESULT_FROM_NT(NtStatus);
  175. }
  176. #else
  177. if (!GetVersionExW(OsVersionInfo))
  178. {
  179. if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
  180. {
  181. OSVERSIONINFOA InfoA;
  182. // Must be Win9x.
  183. ZeroMemory(&InfoA, sizeof(InfoA));
  184. InfoA.dwOSVersionInfoSize = sizeof(InfoA);
  185. if (!::GetVersionExA(&InfoA))
  186. {
  187. return WIN32_LAST_STATUS();
  188. }
  189. OsVersionInfo->dwMajorVersion = InfoA.dwMajorVersion;
  190. OsVersionInfo->dwMinorVersion = InfoA.dwMinorVersion;
  191. OsVersionInfo->dwBuildNumber = InfoA.dwBuildNumber;
  192. OsVersionInfo->dwPlatformId = InfoA.dwPlatformId;
  193. memcpy(OsVersionInfo->szCSDVersion, InfoA.szCSDVersion,
  194. sizeof(InfoA.szCSDVersion));
  195. *WideCsd = FALSE;
  196. }
  197. else
  198. {
  199. return WIN32_LAST_STATUS();
  200. }
  201. }
  202. #endif
  203. return S_OK;
  204. }
  205. HRESULT
  206. LiveUserDebugServices::Initialize(
  207. THIS_
  208. OUT PULONG Flags
  209. )
  210. {
  211. HRESULT Status;
  212. OSVERSIONINFOW OsVersionInfo;
  213. BOOL WideCsd;
  214. if ((Status = GetOsVerInfo(&OsVersionInfo, &WideCsd)) != S_OK)
  215. {
  216. return Status;
  217. }
  218. ULONG BaseFlags;
  219. if ((Status = UserDebugServices::Initialize(&BaseFlags)) != S_OK)
  220. {
  221. return Status;
  222. }
  223. m_PlatformId = OsVersionInfo.dwPlatformId;
  224. // System structures may change size depending on the OS
  225. // version. Pick the right size to use later.
  226. if (m_PlatformId == VER_PLATFORM_WIN32_NT)
  227. {
  228. if (OsVersionInfo.dwBuildNumber <= 1381)
  229. {
  230. m_SysProcInfoSize = NT4_SYSTEM_PROCESS_INFORMATION_SIZE;
  231. }
  232. else if (OsVersionInfo.dwBuildNumber <= 2195)
  233. {
  234. m_SysProcInfoSize = W2K_SYSTEM_PROCESS_INFORMATION_SIZE;
  235. }
  236. else
  237. {
  238. m_SysProcInfoSize = sizeof(SYSTEM_PROCESS_INFORMATION);
  239. }
  240. }
  241. // If the direct NT debugging APIs are available use them
  242. // as they offer more flexibility.
  243. if (g_NtDllCalls.DbgUiSetThreadDebugObject != NULL)
  244. {
  245. // The NtWait/Continue APIs do not automatically manage
  246. // process and thread handles so the caller must close them.
  247. BaseFlags |= DBGSVC_CLOSE_PROC_THREAD_HANDLES;
  248. m_UseDebugObject = TRUE;
  249. }
  250. else
  251. {
  252. m_UseDebugObject = FALSE;
  253. }
  254. *Flags = BaseFlags | DBGSVC_GENERIC_CODE_BREAKPOINTS;
  255. return S_OK;
  256. }
  257. HRESULT
  258. LiveUserDebugServices::Uninitialize(
  259. THIS_
  260. IN BOOL Global
  261. )
  262. {
  263. HRESULT Status;
  264. if ((Status = UserDebugServices::Uninitialize(Global)) != S_OK)
  265. {
  266. return Status;
  267. }
  268. m_Remote = FALSE;
  269. m_EventProcessId = 0;
  270. m_ContextSize = 0;
  271. m_PlatformId = VER_PLATFORM_WIN32s;
  272. if (m_DebugObject != NULL)
  273. {
  274. ::CloseHandle(m_DebugObject);
  275. m_DebugObject = NULL;
  276. }
  277. return S_OK;
  278. }
  279. STDMETHODIMP
  280. LiveUserDebugServices::GetTargetInfo(
  281. THIS_
  282. OUT PULONG MachineType,
  283. OUT PULONG NumberProcessors,
  284. OUT PULONG PlatformId,
  285. OUT PULONG BuildNumber,
  286. OUT PULONG CheckedBuild,
  287. OUT PSTR CsdString,
  288. IN ULONG CsdStringSize,
  289. OUT PSTR BuildString,
  290. IN ULONG BuildStringSize
  291. )
  292. {
  293. HRESULT Status;
  294. OSVERSIONINFOW OsVersionInfo;
  295. BOOL WideCsd;
  296. if ((Status = GetOsVerInfo(&OsVersionInfo, &WideCsd)) != S_OK)
  297. {
  298. return Status;
  299. }
  300. ULONG ProcArch, NumProc;
  301. #ifdef NT_NATIVE
  302. NTSTATUS NtStatus;
  303. SYSTEM_BASIC_INFORMATION BasicInfo;
  304. SYSTEM_PROCESSOR_INFORMATION ProcInfo;
  305. if (!NT_SUCCESS(NtStatus =
  306. NtQuerySystemInformation(SystemBasicInformation,
  307. &BasicInfo, sizeof(BasicInfo),
  308. NULL)) ||
  309. !NT_SUCCESS(NtStatus =
  310. NtQuerySystemInformation(SystemProcessorInformation,
  311. &ProcInfo, sizeof(ProcInfo),
  312. NULL)))
  313. {
  314. return HRESULT_FROM_NT(NtStatus);
  315. }
  316. ProcArch = ProcInfo.ProcessorArchitecture;
  317. NumProc = BasicInfo.NumberOfProcessors;
  318. #else
  319. SYSTEM_INFO SystemInfo;
  320. ::GetSystemInfo(&SystemInfo);
  321. ProcArch = SystemInfo.wProcessorArchitecture;
  322. NumProc = SystemInfo.dwNumberOfProcessors;
  323. #endif
  324. switch(ProcArch)
  325. {
  326. case PROCESSOR_ARCHITECTURE_INTEL:
  327. *MachineType = IMAGE_FILE_MACHINE_I386;
  328. if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
  329. {
  330. if (OsVersionInfo.dwBuildNumber <= 1381)
  331. {
  332. m_ContextSize = sizeof(X86_CONTEXT);
  333. }
  334. else
  335. {
  336. m_ContextSize = sizeof(X86_NT5_CONTEXT);
  337. }
  338. }
  339. else if ((OsVersionInfo.dwBuildNumber & 0xffff) <= 1998)
  340. {
  341. // Win9x prior to Win98SE didn't support the extended context.
  342. m_ContextSize = sizeof(X86_CONTEXT);
  343. }
  344. else
  345. {
  346. m_ContextSize = sizeof(X86_NT5_CONTEXT);
  347. }
  348. break;
  349. case PROCESSOR_ARCHITECTURE_ALPHA:
  350. *MachineType = IMAGE_FILE_MACHINE_ALPHA;
  351. // The "NT5" is a misnomer, this context
  352. // applies to all versions.
  353. m_ContextSize = sizeof(ALPHA_NT5_CONTEXT);
  354. break;
  355. case PROCESSOR_ARCHITECTURE_ALPHA64:
  356. *MachineType = IMAGE_FILE_MACHINE_AXP64;
  357. m_ContextSize = sizeof(ALPHA_NT5_CONTEXT);
  358. break;
  359. case PROCESSOR_ARCHITECTURE_IA64:
  360. *MachineType = IMAGE_FILE_MACHINE_IA64;
  361. m_ContextSize = sizeof(IA64_CONTEXT);
  362. break;
  363. default:
  364. return E_UNEXPECTED;
  365. }
  366. *NumberProcessors = NumProc;
  367. *PlatformId = OsVersionInfo.dwPlatformId;
  368. *BuildNumber = OsVersionInfo.dwBuildNumber;
  369. *CheckedBuild = 0;
  370. if (WideCsd)
  371. {
  372. if (!WideCharToMultiByte(CP_ACP, 0, OsVersionInfo.szCSDVersion, -1,
  373. CsdString, CsdStringSize, NULL, NULL))
  374. {
  375. CsdString[0] = 0;
  376. }
  377. }
  378. else
  379. {
  380. CsdString[0] = 0;
  381. strncat(CsdString, (PSTR)OsVersionInfo.szCSDVersion, CsdStringSize);
  382. }
  383. BuildString[0] = 0;
  384. #ifndef NT_NATIVE
  385. if (VER_PLATFORM_WIN32_NT == OsVersionInfo.dwPlatformId)
  386. {
  387. HKEY hkey = NULL;
  388. TCHAR sz[40] = {0};
  389. DWORD dwType;
  390. DWORD dwSize = sizeof(sz);
  391. if (ERROR_SUCCESS ==
  392. RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  393. "Software\\Microsoft\\Windows NT\\CurrentVersion",
  394. 0,
  395. KEY_READ,
  396. &hkey))
  397. {
  398. if (ERROR_SUCCESS ==
  399. RegQueryValueEx(hkey,
  400. "CurrentType",
  401. NULL,
  402. &dwType,
  403. (PUCHAR) sz,
  404. &dwSize))
  405. {
  406. if (*sz)
  407. {
  408. _strlwr(sz);
  409. if (strstr(sz, "checked"))
  410. {
  411. *CheckedBuild = 0xC;
  412. }
  413. }
  414. }
  415. RegCloseKey(hkey);
  416. }
  417. if (OsVersionInfo.dwBuildNumber > 2195)
  418. {
  419. char RawString[128];
  420. // Look up the file version string for a system DLL to
  421. // try and get the build lab information.
  422. strcpy(RawString, "kernel32.dll version: ");
  423. GetFileStringFileInfo("kernel32.dll", "FileVersion",
  424. RawString + strlen(RawString),
  425. sizeof(RawString) - strlen(RawString));
  426. strncat(BuildString, RawString, BuildStringSize);
  427. }
  428. }
  429. #endif // #ifndef NT_NATIVE
  430. return S_OK;
  431. }
  432. BOOL
  433. X86CpuId(
  434. IN ULONG SubFunction,
  435. OUT PULONG EaxRegister,
  436. OUT PULONG EbxRegister,
  437. OUT PULONG EcxRegister,
  438. OUT PULONG EdxRegister
  439. )
  440. {
  441. #ifdef _X86_
  442. ULONG _Eax;
  443. ULONG _Ebx;
  444. ULONG _Ecx;
  445. ULONG _Edx;
  446. __asm
  447. {
  448. mov eax, SubFunction
  449. __emit 0x0F
  450. __emit 0xA2 ;; CPUID
  451. mov _Eax, eax
  452. mov _Ebx, ebx
  453. mov _Ecx, ecx
  454. mov _Edx, edx
  455. }
  456. *EaxRegister = _Eax;
  457. *EbxRegister = _Ebx;
  458. *EcxRegister = _Ecx;
  459. *EdxRegister = _Edx;
  460. return TRUE;
  461. #else
  462. return FALSE;
  463. #endif // #ifdef _X86_
  464. }
  465. BOOL
  466. Ia64CpuId(ULONG Reg, PULONG64 Val)
  467. {
  468. // XXX drewb - How should this be implemented?
  469. #if defined(_IA64_) && defined(IA64_INLINE_ASSEMBLY)
  470. ULONG64 _Val;
  471. __asm mov t0, Reg;
  472. __asm mov _Val, cpuid[t0];
  473. *Val = _Val;
  474. return TRUE;
  475. #else
  476. return FALSE;
  477. #endif
  478. }
  479. STDMETHODIMP
  480. LiveUserDebugServices::GetProcessorId(
  481. THIS_
  482. OUT PVOID Buffer,
  483. IN ULONG BufferSize,
  484. OUT PULONG BufferUsed
  485. )
  486. {
  487. if (BufferSize < sizeof(DEBUG_PROCESSOR_IDENTIFICATION_ALL))
  488. {
  489. return E_INVALIDARG;
  490. }
  491. ZeroMemory(Buffer, sizeof(DEBUG_PROCESSOR_IDENTIFICATION_ALL));
  492. ULONG ProcArch, ProcLevel, ProcRevision;
  493. #ifdef NT_NATIVE
  494. NTSTATUS NtStatus;
  495. SYSTEM_PROCESSOR_INFORMATION ProcInfo;
  496. if (!NT_SUCCESS(NtStatus =
  497. NtQuerySystemInformation(SystemProcessorInformation,
  498. &ProcInfo, sizeof(ProcInfo),
  499. NULL)))
  500. {
  501. return HRESULT_FROM_NT(NtStatus);
  502. }
  503. ProcArch = ProcInfo.ProcessorArchitecture;
  504. ProcLevel = ProcInfo.ProcessorLevel;
  505. ProcRevision = ProcInfo.ProcessorRevision;
  506. #else
  507. SYSTEM_INFO SystemInfo;
  508. ::GetSystemInfo(&SystemInfo);
  509. ProcArch = SystemInfo.wProcessorArchitecture;
  510. ProcLevel = SystemInfo.wProcessorLevel;
  511. ProcRevision = SystemInfo.wProcessorRevision;
  512. #endif
  513. PDEBUG_PROCESSOR_IDENTIFICATION_ALL Id =
  514. (PDEBUG_PROCESSOR_IDENTIFICATION_ALL)Buffer;
  515. ULONG64 Val;
  516. switch(ProcArch)
  517. {
  518. case PROCESSOR_ARCHITECTURE_INTEL:
  519. *BufferUsed = sizeof(DEBUG_PROCESSOR_IDENTIFICATION_X86);
  520. Id->X86.Family = ProcLevel;
  521. Id->X86.Model = (ProcRevision >> 8) & 0xf;
  522. Id->X86.Stepping = ProcRevision & 0xf;
  523. if (ProcLevel >= 5)
  524. {
  525. ULONG Eax, Ebx, Ecx, Edx;
  526. if (X86CpuId(0, &Eax, &Ebx, &Ecx, &Edx))
  527. {
  528. *(PULONG)(Id->X86.VendorString + 0 * sizeof(ULONG)) = Ebx;
  529. *(PULONG)(Id->X86.VendorString + 1 * sizeof(ULONG)) = Edx;
  530. *(PULONG)(Id->X86.VendorString + 2 * sizeof(ULONG)) = Ecx;
  531. }
  532. }
  533. break;
  534. case PROCESSOR_ARCHITECTURE_ALPHA:
  535. *BufferUsed = sizeof(DEBUG_PROCESSOR_IDENTIFICATION_ALPHA);
  536. Id->Alpha.Type = ProcLevel;
  537. Id->Alpha.Revision = ProcRevision;
  538. break;
  539. case PROCESSOR_ARCHITECTURE_IA64:
  540. *BufferUsed = sizeof(DEBUG_PROCESSOR_IDENTIFICATION_IA64);
  541. Id->Ia64.Model = ProcLevel;
  542. Id->Ia64.Revision = ProcRevision;
  543. if (Ia64CpuId(3, &Val))
  544. {
  545. Id->Ia64.ArchRev = (ULONG)((Val >> 32) & 0xff);
  546. Id->Ia64.Family = (ULONG)((Val >> 24) & 0xff);
  547. Ia64CpuId(0, (PULONG64)
  548. (Id->Ia64.VendorString + 0 * sizeof(ULONG64)));
  549. Ia64CpuId(1, (PULONG64)
  550. (Id->Ia64.VendorString + 1 * sizeof(ULONG64)));
  551. }
  552. break;
  553. case PROCESSOR_ARCHITECTURE_AMD64:
  554. *BufferUsed = sizeof(DEBUG_PROCESSOR_IDENTIFICATION_AMD64);
  555. Id->Amd64.Family = ProcLevel;
  556. Id->Amd64.Model = (ProcRevision >> 8) & 0xf;
  557. Id->Amd64.Stepping = ProcRevision & 0xf;
  558. break;
  559. }
  560. return S_OK;
  561. }
  562. STDMETHODIMP
  563. LiveUserDebugServices::GetFileVersionInformation(
  564. THIS_
  565. IN PCSTR File,
  566. IN PCSTR Item,
  567. OUT OPTIONAL PVOID Buffer,
  568. IN ULONG BufferSize,
  569. OUT OPTIONAL PULONG VerInfoSize
  570. )
  571. {
  572. #ifndef NT_NATIVE
  573. PVOID AllInfo = GetAllFileVersionInfo((PSTR)File);
  574. if (AllInfo == NULL)
  575. {
  576. return E_OUTOFMEMORY;
  577. }
  578. HRESULT Status;
  579. PVOID Val;
  580. UINT ValSize;
  581. if (VerQueryValue(AllInfo, (PSTR)Item, &Val, &ValSize))
  582. {
  583. Status = FillDataBuffer(Val, ValSize,
  584. Buffer, BufferSize, VerInfoSize);
  585. }
  586. else
  587. {
  588. Status = WIN32_LAST_STATUS();
  589. }
  590. free(AllInfo);
  591. return Status;
  592. #else // #ifndef NT_NATIVE
  593. return E_UNEXPECTED;
  594. #endif // #ifndef NT_NATIVE
  595. }
  596. HRESULT
  597. GetNtSystemProcessInformation(PSYSTEM_PROCESS_INFORMATION* ProcInfo)
  598. {
  599. NTSTATUS NtStatus;
  600. PVOID Buffer;
  601. SIZE_T BufferSize = 8192;
  602. for (;;)
  603. {
  604. Buffer = NULL;
  605. NtStatus = g_NtDllCalls.
  606. NtAllocateVirtualMemory(NtCurrentProcess(),
  607. &Buffer, 0, &BufferSize,
  608. MEM_COMMIT, PAGE_READWRITE);
  609. if (!NT_SUCCESS(NtStatus))
  610. {
  611. return HRESULT_FROM_NT(NtStatus);
  612. }
  613. NtStatus = g_NtDllCalls.
  614. NtQuerySystemInformation(SystemProcessInformation,
  615. Buffer, (ULONG)BufferSize, NULL);
  616. if (NT_SUCCESS(NtStatus))
  617. {
  618. break;
  619. }
  620. g_NtDllCalls.NtFreeVirtualMemory(NtCurrentProcess(),
  621. &Buffer, &BufferSize, MEM_RELEASE);
  622. if (NtStatus == STATUS_INFO_LENGTH_MISMATCH)
  623. {
  624. BufferSize += 8192;
  625. }
  626. else
  627. {
  628. return HRESULT_FROM_NT(NtStatus);
  629. }
  630. }
  631. *ProcInfo = (PSYSTEM_PROCESS_INFORMATION)Buffer;
  632. return S_OK;
  633. }
  634. HRESULT
  635. NtGetProcessIds(PULONG Ids, ULONG Count, PULONG ActualCount)
  636. {
  637. HRESULT Status;
  638. PSYSTEM_PROCESS_INFORMATION ProcessInfo, ProcInfoBuffer;
  639. if ((Status = GetNtSystemProcessInformation(&ProcInfoBuffer)) != S_OK)
  640. {
  641. return Status;
  642. }
  643. ULONG TotalOffset;
  644. ULONG ProcessCount;
  645. ProcessInfo = ProcInfoBuffer;
  646. TotalOffset = 0;
  647. ProcessCount = 0;
  648. for (;;)
  649. {
  650. if (ProcessCount < Count)
  651. {
  652. Ids[ProcessCount] = (ULONG)(ULONG_PTR)ProcessInfo->UniqueProcessId;
  653. }
  654. ProcessCount++;
  655. if (ProcessInfo->NextEntryOffset == 0)
  656. {
  657. break;
  658. }
  659. TotalOffset += ProcessInfo->NextEntryOffset;
  660. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
  661. ((PUCHAR)ProcInfoBuffer + TotalOffset);
  662. }
  663. if (ActualCount != NULL)
  664. {
  665. *ActualCount = ProcessCount;
  666. }
  667. SIZE_T MemSize;
  668. g_NtDllCalls.NtFreeVirtualMemory(NtCurrentProcess(),
  669. (PVOID*)&ProcInfoBuffer, &MemSize,
  670. MEM_RELEASE);
  671. return Status;
  672. }
  673. HRESULT
  674. W9xGetProcessIds(PULONG Ids, ULONG Count, PULONG ActualCount)
  675. {
  676. #ifndef NT_NATIVE
  677. HRESULT Status;
  678. HANDLE Snap;
  679. Snap = g_Kernel32Calls.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  680. if (Snap == INVALID_HANDLE_VALUE)
  681. {
  682. return WIN32_LAST_STATUS();
  683. }
  684. ULONG ProcessCount = 0;
  685. for (;;)
  686. {
  687. PROCESSENTRY32 Proc;
  688. BOOL Succ;
  689. Proc.dwSize = sizeof(Proc);
  690. if (ProcessCount == 0)
  691. {
  692. Succ = g_Kernel32Calls.Process32First(Snap, &Proc);
  693. }
  694. else
  695. {
  696. Succ = g_Kernel32Calls.Process32Next(Snap, &Proc);
  697. }
  698. if (!Succ)
  699. {
  700. break;
  701. }
  702. if (ProcessCount < Count)
  703. {
  704. Ids[ProcessCount] = Proc.th32ProcessID;
  705. }
  706. ProcessCount++;
  707. }
  708. if (ActualCount != NULL)
  709. {
  710. *ActualCount = ProcessCount;
  711. }
  712. CloseHandle(Snap);
  713. return S_OK;
  714. #else
  715. return E_UNEXPECTED;
  716. #endif
  717. }
  718. STDMETHODIMP
  719. LiveUserDebugServices::GetProcessIds(
  720. THIS_
  721. OUT OPTIONAL /* size_is(Count) */ PULONG Ids,
  722. IN ULONG Count,
  723. OUT OPTIONAL PULONG ActualCount
  724. )
  725. {
  726. HRESULT Status;
  727. // Allow privileged enumeration.
  728. if ((Status = EnableDebugPrivilege()) != S_OK)
  729. {
  730. return Status;
  731. }
  732. switch(m_PlatformId)
  733. {
  734. case VER_PLATFORM_WIN32_NT:
  735. return NtGetProcessIds(Ids, Count, ActualCount);
  736. case VER_PLATFORM_WIN32_WINDOWS:
  737. return W9xGetProcessIds(Ids, Count, ActualCount);
  738. default:
  739. return E_UNEXPECTED;
  740. }
  741. }
  742. HRESULT
  743. NtGetPidByExe(PCSTR ExeName, ULONG Flags, PULONG Id)
  744. {
  745. HRESULT Status;
  746. // Rather than converting each process name to ANSI and
  747. // comparing, convert the incoming name to Unicode so
  748. // only one conversion is needed.
  749. WCHAR WideName[MAX_PATH];
  750. BOOL WideHasPath;
  751. if (!MultiByteToWideChar(CP_ACP, 0, ExeName, -1,
  752. WideName, sizeof(WideName) / sizeof(WCHAR)))
  753. {
  754. return WIN32_LAST_STATUS();
  755. }
  756. // Check if the given name has path components.
  757. WideHasPath =
  758. wcschr(WideName, '\\') != NULL ||
  759. wcschr(WideName, '/') != NULL ||
  760. (WideName[0] && WideName[1] == ':');
  761. PSYSTEM_PROCESS_INFORMATION ProcessInfo, ProcInfoBuffer;
  762. if ((Status = GetNtSystemProcessInformation(&ProcInfoBuffer)) != S_OK)
  763. {
  764. return Status;
  765. }
  766. ULONG TotalOffset;
  767. ULONG FoundId;
  768. ProcessInfo = ProcInfoBuffer;
  769. TotalOffset = 0;
  770. FoundId = DEBUG_ANY_ID;
  771. Status = E_NOINTERFACE;
  772. for (;;)
  773. {
  774. PWSTR ImageName;
  775. if (ProcessInfo->ImageName.Buffer == NULL)
  776. {
  777. ImageName = SYSTEM_PROCESS_NAME_W;
  778. }
  779. else
  780. {
  781. ImageName = ProcessInfo->ImageName.Buffer;
  782. }
  783. if ((Flags & DEBUG_GET_PROC_FULL_MATCH) == 0 &&
  784. !WideHasPath)
  785. {
  786. PWSTR Slash;
  787. Slash = wcsrchr(ImageName, '\\');
  788. if (Slash == NULL)
  789. {
  790. Slash = wcsrchr(ImageName, '/');
  791. }
  792. if (Slash != NULL)
  793. {
  794. ImageName = Slash + 1;
  795. }
  796. }
  797. if (!_wcsicmp(ImageName, WideName))
  798. {
  799. if ((Flags & DEBUG_GET_PROC_ONLY_MATCH) &&
  800. FoundId != DEBUG_ANY_ID)
  801. {
  802. Status = S_FALSE;
  803. break;
  804. }
  805. Status = S_OK;
  806. FoundId = (ULONG)(ULONG_PTR)ProcessInfo->UniqueProcessId;
  807. *Id = FoundId;
  808. if ((Flags & DEBUG_GET_PROC_ONLY_MATCH) == 0)
  809. {
  810. break;
  811. }
  812. }
  813. if (ProcessInfo->NextEntryOffset == 0)
  814. {
  815. break;
  816. }
  817. TotalOffset += ProcessInfo->NextEntryOffset;
  818. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
  819. ((PUCHAR)ProcInfoBuffer + TotalOffset);
  820. }
  821. SIZE_T MemSize;
  822. g_NtDllCalls.NtFreeVirtualMemory(NtCurrentProcess(),
  823. (PVOID*)&ProcInfoBuffer, &MemSize,
  824. MEM_RELEASE);
  825. return Status;
  826. }
  827. HRESULT
  828. W9xGetPidByExe(PCSTR ExeName, ULONG Flags, PULONG Id)
  829. {
  830. #ifndef NT_NATIVE
  831. HRESULT Status;
  832. HANDLE Snap;
  833. Snap = g_Kernel32Calls.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  834. if (Snap == INVALID_HANDLE_VALUE)
  835. {
  836. return WIN32_LAST_STATUS();
  837. }
  838. // Check if the given name has path components.
  839. BOOL HasPath =
  840. strchr(ExeName, '\\') != NULL ||
  841. strchr(ExeName, '/') != NULL ||
  842. (ExeName[0] && ExeName[1] == ':');
  843. ULONG FoundId = DEBUG_ANY_ID;
  844. BOOL First = TRUE;
  845. for (;;)
  846. {
  847. PROCESSENTRY32 Proc;
  848. BOOL Succ;
  849. Proc.dwSize = sizeof(Proc);
  850. if (First)
  851. {
  852. Succ = g_Kernel32Calls.Process32First(Snap, &Proc);
  853. First = FALSE;
  854. }
  855. else
  856. {
  857. Succ = g_Kernel32Calls.Process32Next(Snap, &Proc);
  858. }
  859. if (!Succ)
  860. {
  861. break;
  862. }
  863. PSTR ImageName = Proc.szExeFile;
  864. if ((Flags & DEBUG_GET_PROC_FULL_MATCH) == 0 &&
  865. !HasPath)
  866. {
  867. PSTR Slash;
  868. Slash = strrchr(ImageName, '\\');
  869. if (Slash == NULL)
  870. {
  871. Slash = strrchr(ImageName, '/');
  872. }
  873. if (Slash != NULL)
  874. {
  875. ImageName = Slash + 1;
  876. }
  877. }
  878. if (!_stricmp(ImageName, ExeName))
  879. {
  880. if ((Flags & DEBUG_GET_PROC_ONLY_MATCH) &&
  881. FoundId != DEBUG_ANY_ID)
  882. {
  883. Status = S_FALSE;
  884. break;
  885. }
  886. Status = S_OK;
  887. FoundId = Proc.th32ProcessID;
  888. *Id = FoundId;
  889. if ((Flags & DEBUG_GET_PROC_ONLY_MATCH) == 0)
  890. {
  891. break;
  892. }
  893. }
  894. }
  895. CloseHandle(Snap);
  896. return S_OK;
  897. #else
  898. return E_UNEXPECTED;
  899. #endif
  900. }
  901. STDMETHODIMP
  902. LiveUserDebugServices::GetProcessIdByExecutableName(
  903. THIS_
  904. IN PCSTR ExeName,
  905. IN ULONG Flags,
  906. OUT PULONG Id
  907. )
  908. {
  909. HRESULT Status;
  910. // Allow privileged enumeration.
  911. if ((Status = EnableDebugPrivilege()) != S_OK)
  912. {
  913. return Status;
  914. }
  915. switch(m_PlatformId)
  916. {
  917. case VER_PLATFORM_WIN32_NT:
  918. return NtGetPidByExe(ExeName, Flags, Id);
  919. case VER_PLATFORM_WIN32_WINDOWS:
  920. return W9xGetPidByExe(ExeName, Flags, Id);
  921. default:
  922. return E_UNEXPECTED;
  923. }
  924. }
  925. HRESULT
  926. ConvertProcessUnicodeString(HANDLE Process,
  927. PUNICODE_STRING UniString,
  928. PSTR* AnsiString)
  929. {
  930. HRESULT Status;
  931. PSTR Ansi = NULL;
  932. PWSTR Wide = NULL;
  933. SIZE_T Done;
  934. Wide = new WCHAR[UniString->Length + 1];
  935. if (Wide == NULL)
  936. {
  937. return E_OUTOFMEMORY;
  938. }
  939. Ansi = new CHAR[UniString->Length + 1];
  940. if (Ansi == NULL)
  941. {
  942. Status = E_OUTOFMEMORY;
  943. goto Exit;
  944. }
  945. if (!::ReadProcessMemory(Process, UniString->Buffer, Wide,
  946. (UniString->Length + 1) * sizeof(WCHAR), &Done))
  947. {
  948. Status = WIN32_LAST_STATUS();
  949. goto Exit;
  950. }
  951. if (Done != (UniString->Length + 1) * sizeof(WCHAR))
  952. {
  953. Status = E_FAIL;
  954. goto Exit;
  955. }
  956. if (!WideCharToMultiByte(CP_ACP, 0, Wide, UniString->Length + 1,
  957. Ansi, UniString->Length + 1, NULL, NULL))
  958. {
  959. Status = WIN32_LAST_STATUS();
  960. goto Exit;
  961. }
  962. *AnsiString = Ansi;
  963. Ansi = NULL;
  964. Status = S_OK;
  965. Exit:
  966. delete Ansi;
  967. delete Wide;
  968. return Status;
  969. }
  970. #ifndef NT_NATIVE
  971. HRESULT
  972. NtGetServiceStatus(PULONG NumServices,
  973. LPENUM_SERVICE_STATUS_PROCESS* ServiceStatus)
  974. {
  975. SC_HANDLE Scm;
  976. Scm = g_Advapi32Calls.OpenSCManagerA(NULL, NULL,
  977. SC_MANAGER_CONNECT |
  978. SC_MANAGER_ENUMERATE_SERVICE);
  979. if (!Scm)
  980. {
  981. return WIN32_LAST_STATUS();
  982. }
  983. HRESULT Status;
  984. LPENUM_SERVICE_STATUS_PROCESS Info;
  985. ULONG InfoSize = 8 * 1024;
  986. ULONG ExtraNeeded;
  987. ULONG Resume;
  988. ULONG Loop = 0;
  989. //
  990. // First pass through the loop allocates from an initial guess.
  991. // If that isn't sufficient, we make another pass and allocate
  992. // what is actually needed. Things may have changed due to
  993. // other machine changes, so loop around a few times before
  994. // giving up.
  995. //
  996. for (;;)
  997. {
  998. Info = (LPENUM_SERVICE_STATUS_PROCESS)malloc(InfoSize);
  999. if (!Info)
  1000. {
  1001. Status = E_OUTOFMEMORY;
  1002. break;
  1003. }
  1004. Resume = 0;
  1005. if (!g_Advapi32Calls.EnumServicesStatusExA(Scm,
  1006. SC_ENUM_PROCESS_INFO,
  1007. SERVICE_WIN32,
  1008. SERVICE_ACTIVE,
  1009. (LPBYTE)Info,
  1010. InfoSize,
  1011. &ExtraNeeded,
  1012. NumServices,
  1013. &Resume,
  1014. NULL))
  1015. {
  1016. free(Info);
  1017. if (Loop > 2 || GetLastError() != ERROR_MORE_DATA)
  1018. {
  1019. Status = WIN32_LAST_STATUS();
  1020. break;
  1021. }
  1022. }
  1023. else
  1024. {
  1025. *ServiceStatus = Info;
  1026. Status = S_OK;
  1027. break;
  1028. }
  1029. InfoSize += ExtraNeeded;
  1030. Loop++;
  1031. }
  1032. CloseServiceHandle(Scm);
  1033. return Status;
  1034. }
  1035. HRESULT
  1036. NtGetProcessServiceNames(HRESULT RetStatus, ULONG ProcessId,
  1037. PSTR* Description, ULONG* DescriptionSize,
  1038. PULONG ActualDescriptionSize, PBOOL Any)
  1039. {
  1040. HRESULT Status;
  1041. if (!g_Advapi32Calls.EnumServicesStatusExA ||
  1042. !g_Advapi32Calls.OpenSCManagerA)
  1043. {
  1044. return RetStatus;
  1045. }
  1046. ULONG i, NumServices;
  1047. LPENUM_SERVICE_STATUS_PROCESS ServiceStatus;
  1048. BOOL AnyServices = FALSE;
  1049. if ((Status = NtGetServiceStatus(&NumServices, &ServiceStatus)) != S_OK)
  1050. {
  1051. // If we can't get the service status just leave the
  1052. // string unchanged and do not consider it a serious error.
  1053. return RetStatus;
  1054. }
  1055. for (i = 0; i < NumServices; i++)
  1056. {
  1057. if (ServiceStatus[i].ServiceStatusProcess.dwProcessId != ProcessId ||
  1058. !ServiceStatus[i].lpServiceName ||
  1059. !ServiceStatus[i].lpServiceName[0])
  1060. {
  1061. continue;
  1062. }
  1063. PSTR Intro;
  1064. if (AnyServices)
  1065. {
  1066. Intro = ",";
  1067. }
  1068. else if (*Any)
  1069. {
  1070. Intro = " Services: ";
  1071. }
  1072. else
  1073. {
  1074. Intro = "Services: ";
  1075. }
  1076. RetStatus = AppendToStringBuffer(RetStatus, Intro, !*Any,
  1077. Description, DescriptionSize,
  1078. ActualDescriptionSize);
  1079. RetStatus = AppendToStringBuffer(RetStatus,
  1080. ServiceStatus[i].lpServiceName, FALSE,
  1081. Description, DescriptionSize,
  1082. ActualDescriptionSize);
  1083. *Any = TRUE;
  1084. AnyServices = TRUE;
  1085. }
  1086. free(ServiceStatus);
  1087. return RetStatus;
  1088. }
  1089. HRESULT
  1090. NtGetProcessMtsPackageNames(HRESULT RetStatus, ULONG ProcessId,
  1091. PSTR* Description, ULONG* DescriptionSize,
  1092. PULONG ActualDescriptionSize, PBOOL Any)
  1093. {
  1094. HRESULT Status;
  1095. // Load and initialize ole32.dll so we can call CoCreateInstance.
  1096. if ((Status = InitDynamicCalls(&g_Ole32CallsDesc)) != S_OK ||
  1097. (Status = InitDynamicCalls(&g_OleAut32CallsDesc)) != S_OK ||
  1098. (Status = g_Ole32Calls.
  1099. CoInitializeEx(NULL, COINIT_MULTITHREADED)) != S_OK)
  1100. {
  1101. // Just leave things unchanged on failure.
  1102. return RetStatus;
  1103. }
  1104. IMtsGrp* MtsGrp = NULL;
  1105. long Packages;
  1106. long i;
  1107. BOOL AnyPackages = FALSE;
  1108. if ((Status = g_Ole32Calls.
  1109. CoCreateInstance(CLSID_MtsGrp, NULL, CLSCTX_ALL,
  1110. __uuidof(IMtsGrp), (void **)&MtsGrp)) != S_OK ||
  1111. (Status = MtsGrp->Refresh()) != S_OK ||
  1112. (Status = MtsGrp->get_Count(&Packages)) != S_OK)
  1113. {
  1114. goto Exit;
  1115. }
  1116. for (i = 0; i < Packages; i++)
  1117. {
  1118. IUnknown* Unk;
  1119. IMtsEvents* Events;
  1120. BSTR Name;
  1121. ULONG Pid;
  1122. if ((Status = MtsGrp->Item(i, &Unk)) != S_OK)
  1123. {
  1124. continue;
  1125. }
  1126. Status = Unk->QueryInterface(IID_IMtsEvents, (void **)&Events);
  1127. Unk->Release();
  1128. if (Status != S_OK)
  1129. {
  1130. continue;
  1131. }
  1132. Status = Events->GetProcessID((PLONG)&Pid);
  1133. if (Status == S_OK && Pid == ProcessId)
  1134. {
  1135. Status = Events->get_PackageName(&Name);
  1136. }
  1137. Events->Release();
  1138. if (Status != S_OK || Pid != ProcessId)
  1139. {
  1140. continue;
  1141. }
  1142. char NameA[MAX_PATH];
  1143. int Conv;
  1144. Conv = WideCharToMultiByte(CP_ACP, 0, Name, -1, NameA, sizeof(NameA),
  1145. NULL, NULL);
  1146. g_OleAut32Calls.SysFreeString(Name);
  1147. if (Conv > 0)
  1148. {
  1149. PSTR Intro;
  1150. if (AnyPackages)
  1151. {
  1152. Intro = ",";
  1153. }
  1154. else if (*Any)
  1155. {
  1156. Intro = " MTS Packages: ";
  1157. }
  1158. else
  1159. {
  1160. Intro = "MTS Packages: ";
  1161. }
  1162. RetStatus = AppendToStringBuffer(RetStatus, Intro, !*Any,
  1163. Description, DescriptionSize,
  1164. ActualDescriptionSize);
  1165. RetStatus = AppendToStringBuffer(RetStatus, NameA, FALSE,
  1166. Description, DescriptionSize,
  1167. ActualDescriptionSize);
  1168. *Any = TRUE;
  1169. AnyPackages = TRUE;
  1170. }
  1171. }
  1172. Exit:
  1173. if (MtsGrp)
  1174. {
  1175. MtsGrp->Release();
  1176. }
  1177. g_Ole32Calls.CoUninitialize();
  1178. return RetStatus;
  1179. }
  1180. #endif // #ifndef NT_NATIVE
  1181. HRESULT
  1182. NtGetProcDesc(ULONG ProcessId, ULONG Flags,
  1183. PSTR ExeName, ULONG ExeNameSize, PULONG ActualExeNameSize,
  1184. PSTR Description, ULONG DescriptionSize,
  1185. PULONG ActualDescriptionSize)
  1186. {
  1187. HRESULT Status;
  1188. if (ProcessId == 0)
  1189. {
  1190. // This is base system process so fake the description.
  1191. Status = FillStringBuffer(SYSTEM_PROCESS_NAME, 0,
  1192. ExeName, ExeNameSize, ActualExeNameSize);
  1193. FillStringBuffer("", 0,
  1194. Description, DescriptionSize, ActualDescriptionSize);
  1195. return Status;
  1196. }
  1197. NTSTATUS NtStatus;
  1198. HANDLE Process;
  1199. OBJECT_ATTRIBUTES ObjAttr;
  1200. CLIENT_ID ClientId;
  1201. ClientId.UniqueThread = NULL;
  1202. ClientId.UniqueProcess = (HANDLE)(ULONG_PTR)ProcessId;
  1203. InitializeObjectAttributes(&ObjAttr, NULL, 0, NULL, NULL);
  1204. NtStatus = g_NtDllCalls.NtOpenProcess(&Process, PROCESS_ALL_ACCESS,
  1205. &ObjAttr, &ClientId);
  1206. if (!NT_SUCCESS(NtStatus))
  1207. {
  1208. Status = HRESULT_FROM_NT(NtStatus);
  1209. goto EH_Exit;
  1210. }
  1211. PROCESS_BASIC_INFORMATION ProcBasic;
  1212. ULONG Done;
  1213. NtStatus = g_NtDllCalls.
  1214. NtQueryInformationProcess(Process, ProcessBasicInformation,
  1215. &ProcBasic, sizeof(ProcBasic), &Done);
  1216. if (!NT_SUCCESS(NtStatus))
  1217. {
  1218. Status = HRESULT_FROM_NT(NtStatus);
  1219. goto EH_Process;
  1220. }
  1221. if (Done != sizeof(ProcBasic))
  1222. {
  1223. Status = E_FAIL;
  1224. goto EH_Process;
  1225. }
  1226. if (ProcBasic.PebBaseAddress == 0)
  1227. {
  1228. // This process has no PEB so fake the description.
  1229. Status = FillStringBuffer(PEBLESS_PROCESS_NAME, 0,
  1230. ExeName, ExeNameSize, ActualExeNameSize);
  1231. FillStringBuffer("", 0,
  1232. Description, DescriptionSize, ActualDescriptionSize);
  1233. goto EH_Process;
  1234. }
  1235. PEB Peb;
  1236. SIZE_T DoneSize;
  1237. if (!::ReadProcessMemory(Process, ProcBasic.PebBaseAddress,
  1238. &Peb, sizeof(Peb), &DoneSize))
  1239. {
  1240. Status = WIN32_LAST_STATUS();
  1241. goto EH_Process;
  1242. }
  1243. if (DoneSize != sizeof(Peb))
  1244. {
  1245. Status = E_FAIL;
  1246. goto EH_Process;
  1247. }
  1248. RTL_USER_PROCESS_PARAMETERS Params;
  1249. if (!::ReadProcessMemory(Process, Peb.ProcessParameters,
  1250. &Params, sizeof(Params), &DoneSize))
  1251. {
  1252. Status = WIN32_LAST_STATUS();
  1253. goto EH_Process;
  1254. }
  1255. if (DoneSize != sizeof(Params))
  1256. {
  1257. Status = E_FAIL;
  1258. goto EH_Process;
  1259. }
  1260. if (Params.ImagePathName.Buffer != NULL)
  1261. {
  1262. PSTR AnsiImage, ImageName;
  1263. if ((Status = ConvertProcessUnicodeString(Process,
  1264. &Params.ImagePathName,
  1265. &AnsiImage)) != S_OK)
  1266. {
  1267. goto EH_Process;
  1268. }
  1269. if (Flags & DEBUG_PROC_DESC_NO_PATHS)
  1270. {
  1271. ImageName = strrchr(AnsiImage, '\\');
  1272. if (ImageName == NULL)
  1273. {
  1274. ImageName = strrchr(AnsiImage, '/');
  1275. }
  1276. if (ImageName == NULL)
  1277. {
  1278. ImageName = AnsiImage;
  1279. }
  1280. else
  1281. {
  1282. ImageName++;
  1283. }
  1284. }
  1285. else
  1286. {
  1287. ImageName = AnsiImage;
  1288. }
  1289. Status = FillStringBuffer(ImageName, 0,
  1290. ExeName, ExeNameSize, ActualExeNameSize);
  1291. delete AnsiImage;
  1292. }
  1293. else
  1294. {
  1295. Status = FillStringBuffer(SYSTEM_PROCESS_NAME, 0,
  1296. ExeName, ExeNameSize, ActualExeNameSize);
  1297. }
  1298. #ifndef NT_NATIVE
  1299. if ((Description && DescriptionSize) || ActualDescriptionSize)
  1300. {
  1301. BOOL Any = FALSE;
  1302. Status = NtGetProcessServiceNames(Status, ProcessId,
  1303. &Description, &DescriptionSize,
  1304. ActualDescriptionSize, &Any);
  1305. Status = NtGetProcessMtsPackageNames(Status, ProcessId,
  1306. &Description, &DescriptionSize,
  1307. ActualDescriptionSize, &Any);
  1308. if (!Any)
  1309. {
  1310. if (FillStringBuffer("", 0,
  1311. Description, DescriptionSize,
  1312. ActualDescriptionSize) == S_FALSE)
  1313. {
  1314. Status = S_FALSE;
  1315. }
  1316. }
  1317. }
  1318. else
  1319. #endif // #ifndef NT_NATIVE
  1320. {
  1321. FillStringBuffer("", 0,
  1322. Description, DescriptionSize, ActualDescriptionSize);
  1323. }
  1324. EH_Process:
  1325. g_NtDllCalls.NtClose(Process);
  1326. EH_Exit:
  1327. return Status;
  1328. }
  1329. HRESULT
  1330. W9xGetProcDesc(ULONG ProcessId, ULONG Flags,
  1331. PSTR ExeName, ULONG ExeNameSize, PULONG ActualExeNameSize,
  1332. PSTR Description, ULONG DescriptionSize,
  1333. PULONG ActualDescriptionSize)
  1334. {
  1335. #ifndef NT_NATIVE
  1336. HRESULT Status;
  1337. HANDLE Snap;
  1338. Snap = g_Kernel32Calls.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  1339. if (Snap == INVALID_HANDLE_VALUE)
  1340. {
  1341. return WIN32_LAST_STATUS();
  1342. }
  1343. BOOL First = TRUE;
  1344. Status = E_NOINTERFACE;
  1345. for (;;)
  1346. {
  1347. PROCESSENTRY32 Proc;
  1348. BOOL Succ;
  1349. Proc.dwSize = sizeof(Proc);
  1350. if (First)
  1351. {
  1352. Succ = g_Kernel32Calls.Process32First(Snap, &Proc);
  1353. First = FALSE;
  1354. }
  1355. else
  1356. {
  1357. Succ = g_Kernel32Calls.Process32Next(Snap, &Proc);
  1358. }
  1359. if (!Succ)
  1360. {
  1361. break;
  1362. }
  1363. if (Proc.th32ProcessID == ProcessId)
  1364. {
  1365. PSTR AnsiImage = Proc.szExeFile;
  1366. PSTR ImageName;
  1367. if (Flags & DEBUG_PROC_DESC_NO_PATHS)
  1368. {
  1369. ImageName = strrchr(AnsiImage, '\\');
  1370. if (ImageName == NULL)
  1371. {
  1372. ImageName = strrchr(AnsiImage, '/');
  1373. }
  1374. if (ImageName == NULL)
  1375. {
  1376. ImageName = AnsiImage;
  1377. }
  1378. else
  1379. {
  1380. ImageName++;
  1381. }
  1382. }
  1383. else
  1384. {
  1385. ImageName = AnsiImage;
  1386. }
  1387. Status = FillStringBuffer(ImageName, 0,
  1388. ExeName, ExeNameSize, ActualExeNameSize);
  1389. break;
  1390. }
  1391. }
  1392. CloseHandle(Snap);
  1393. // Win9x doesn't have services and we don't have to
  1394. // worry about IIS so there's currently nothing we provide
  1395. // as a description.
  1396. FillStringBuffer("", 0,
  1397. Description, DescriptionSize, ActualDescriptionSize);
  1398. return Status;
  1399. #else
  1400. return E_UNEXPECTED;
  1401. #endif
  1402. }
  1403. STDMETHODIMP
  1404. LiveUserDebugServices::GetProcessDescription(
  1405. THIS_
  1406. IN ULONG ProcessId,
  1407. IN ULONG Flags,
  1408. OUT OPTIONAL PSTR ExeName,
  1409. IN ULONG ExeNameSize,
  1410. OUT OPTIONAL PULONG ActualExeNameSize,
  1411. OUT OPTIONAL PSTR Description,
  1412. IN ULONG DescriptionSize,
  1413. OUT OPTIONAL PULONG ActualDescriptionSize
  1414. )
  1415. {
  1416. HRESULT Status;
  1417. // Allow privileged access.
  1418. if ((Status = EnableDebugPrivilege()) != S_OK)
  1419. {
  1420. return Status;
  1421. }
  1422. switch(m_PlatformId)
  1423. {
  1424. case VER_PLATFORM_WIN32_NT:
  1425. return NtGetProcDesc(ProcessId, Flags, ExeName, ExeNameSize,
  1426. ActualExeNameSize, Description, DescriptionSize,
  1427. ActualDescriptionSize);
  1428. case VER_PLATFORM_WIN32_WINDOWS:
  1429. return W9xGetProcDesc(ProcessId, Flags, ExeName, ExeNameSize,
  1430. ActualExeNameSize, Description, DescriptionSize,
  1431. ActualDescriptionSize);
  1432. default:
  1433. return E_UNEXPECTED;
  1434. }
  1435. }
  1436. HRESULT
  1437. InsertUserThread(PUSER_THREAD_INFO Threads, ULONG Index,
  1438. HRESULT Status, ULONG ThreadId, HANDLE ThreadHandle,
  1439. PUSER_THREAD_INFO PrevThreads, ULONG PrevInfoCount)
  1440. {
  1441. // Suspend the thread immediately to try and keep the
  1442. // process state as static as we can.
  1443. if (::SuspendThread(ThreadHandle) == -1)
  1444. {
  1445. Status = WIN32_LAST_STATUS();
  1446. ::CloseHandle(ThreadHandle);
  1447. }
  1448. if (Status != S_OK)
  1449. {
  1450. while (Index-- > 0)
  1451. {
  1452. ::ResumeThread(OS_HANDLE(Threads[Index].Handle));
  1453. ::CloseHandle(OS_HANDLE(Threads[Index].Handle));
  1454. }
  1455. return Status;
  1456. }
  1457. Threads[Index].Handle = SERVICE_HANDLE(ThreadHandle);
  1458. Threads[Index].Id = ThreadId;
  1459. Threads[Index].Reserved = 0;
  1460. //
  1461. // Search for this thread in any previous information.
  1462. //
  1463. if (PrevThreads == NULL)
  1464. {
  1465. return S_OK;
  1466. }
  1467. ULONG i;
  1468. Status = S_FALSE;
  1469. for (i = 0; i < PrevInfoCount; i++)
  1470. {
  1471. if (PrevThreads[i].Id == ThreadId)
  1472. {
  1473. // Found a match.
  1474. Status = S_OK;
  1475. break;
  1476. }
  1477. }
  1478. return Status;
  1479. }
  1480. HRESULT
  1481. NtGetProcThreads(ULONG ProcessId, PUSER_THREAD_INFO Threads,
  1482. ULONG InfoCount, PULONG ThreadCount,
  1483. ULONG SysProcInfoSize,
  1484. PUSER_THREAD_INFO PrevThreads, ULONG PrevInfoCount)
  1485. {
  1486. HRESULT Status;
  1487. PSYSTEM_PROCESS_INFORMATION ProcessInfo, ProcInfoBuffer;
  1488. if ((Status = GetNtSystemProcessInformation(&ProcInfoBuffer)) != S_OK)
  1489. {
  1490. return Status;
  1491. }
  1492. ULONG TotalOffset;
  1493. ProcessInfo = ProcInfoBuffer;
  1494. TotalOffset = 0;
  1495. for (;;)
  1496. {
  1497. if (ProcessInfo->UniqueProcessId == (HANDLE)(ULONG_PTR)ProcessId ||
  1498. ProcessInfo->NextEntryOffset == 0)
  1499. {
  1500. break;
  1501. }
  1502. TotalOffset += ProcessInfo->NextEntryOffset;
  1503. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
  1504. ((PUCHAR)ProcInfoBuffer + TotalOffset);
  1505. }
  1506. if (ProcessInfo->UniqueProcessId == (HANDLE)(ULONG_PTR)ProcessId)
  1507. {
  1508. if (ThreadCount != NULL)
  1509. {
  1510. *ThreadCount = ProcessInfo->NumberOfThreads;
  1511. }
  1512. if (ProcessInfo->NumberOfThreads < InfoCount)
  1513. {
  1514. InfoCount = ProcessInfo->NumberOfThreads;
  1515. }
  1516. // If the last iteration returned a different number
  1517. // of threads there's a mismatch so we need to return S_FALSE.
  1518. Status = (PrevThreads != NULL &&
  1519. PrevInfoCount != ProcessInfo->NumberOfThreads) ?
  1520. S_FALSE : S_OK;
  1521. PSYSTEM_THREAD_INFORMATION ThreadInfo = (PSYSTEM_THREAD_INFORMATION)
  1522. ((PUCHAR)ProcessInfo + SysProcInfoSize);
  1523. for (ULONG i = 0; i < InfoCount; i++)
  1524. {
  1525. NTSTATUS NtStatus;
  1526. OBJECT_ATTRIBUTES ObjAttr;
  1527. HANDLE Thread;
  1528. HRESULT SingleStatus;
  1529. InitializeObjectAttributes(&ObjAttr, NULL, 0, NULL, NULL);
  1530. NtStatus = g_NtDllCalls.
  1531. NtOpenThread(&Thread, THREAD_ALL_ACCESS, &ObjAttr,
  1532. &ThreadInfo->ClientId);
  1533. SingleStatus = InsertUserThread
  1534. (Threads, i, CONV_NT_STATUS(NtStatus),
  1535. (ULONG)(ULONG_PTR)ThreadInfo->ClientId.UniqueThread,
  1536. Thread, PrevThreads, PrevInfoCount);
  1537. if (SingleStatus == S_FALSE)
  1538. {
  1539. // Inserted thread didn't match so return S_FALSE.
  1540. Status = S_FALSE;
  1541. }
  1542. else if (SingleStatus != S_OK)
  1543. {
  1544. Status = SingleStatus;
  1545. break;
  1546. }
  1547. ThreadInfo++;
  1548. }
  1549. }
  1550. else
  1551. {
  1552. Status = E_NOINTERFACE;
  1553. }
  1554. SIZE_T MemSize;
  1555. g_NtDllCalls.NtFreeVirtualMemory(NtCurrentProcess(),
  1556. (PVOID*)&ProcInfoBuffer, &MemSize,
  1557. MEM_RELEASE);
  1558. return Status;
  1559. }
  1560. // These functions are in the minidump library and are
  1561. // not really public functions, but we need them so
  1562. // just extern them here.
  1563. #ifdef _X86_
  1564. extern "C" BOOL WinInitialize(void);
  1565. extern "C" HANDLE WINAPI WinOpenThread(DWORD dwAccess, BOOL bInheritHandle,
  1566. DWORD ThreadId);
  1567. #else
  1568. #define WinInitialize() FALSE
  1569. #define WinOpenThread(dwAccess, bInheritHandle, ThreadId) NULL
  1570. #endif
  1571. HRESULT
  1572. W9xGetProcThreads(ULONG ProcessId, PUSER_THREAD_INFO Threads,
  1573. ULONG InfoCount, PULONG ThreadCount,
  1574. PUSER_THREAD_INFO PrevThreads, ULONG PrevInfoCount)
  1575. {
  1576. #ifndef NT_NATIVE
  1577. HRESULT Status;
  1578. HANDLE Snap;
  1579. if (!WinInitialize())
  1580. {
  1581. return WIN32_LAST_STATUS();
  1582. }
  1583. Snap = g_Kernel32Calls.CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,
  1584. ProcessId);
  1585. if (Snap == INVALID_HANDLE_VALUE)
  1586. {
  1587. return WIN32_LAST_STATUS();
  1588. }
  1589. BOOL First = TRUE;
  1590. ULONG NumThreads = 0;
  1591. Status = S_OK;
  1592. for (;;)
  1593. {
  1594. THREADENTRY32 Thread;
  1595. BOOL Succ;
  1596. Thread.dwSize = sizeof(Thread);
  1597. if (First)
  1598. {
  1599. Succ = g_Kernel32Calls.Thread32First(Snap, &Thread);
  1600. First = FALSE;
  1601. }
  1602. else
  1603. {
  1604. Succ = g_Kernel32Calls.Thread32Next(Snap, &Thread);
  1605. }
  1606. if (!Succ)
  1607. {
  1608. break;
  1609. }
  1610. if (Thread.th32OwnerProcessID == ProcessId)
  1611. {
  1612. if (NumThreads < InfoCount)
  1613. {
  1614. HRESULT SingleStatus;
  1615. HANDLE Handle = WinOpenThread(THREAD_ALL_ACCESS, FALSE,
  1616. Thread.th32ThreadID);
  1617. SingleStatus = InsertUserThread
  1618. (Threads, NumThreads, CONV_W32_STATUS(Handle != NULL),
  1619. Thread.th32ThreadID, Handle, PrevThreads, PrevInfoCount);
  1620. if (SingleStatus == S_FALSE)
  1621. {
  1622. // Inserted thread didn't match so return S_FALSE.
  1623. Status = S_FALSE;
  1624. }
  1625. else if (SingleStatus != S_OK)
  1626. {
  1627. Status = SingleStatus;
  1628. break;
  1629. }
  1630. }
  1631. NumThreads++;
  1632. }
  1633. }
  1634. if (ThreadCount != NULL)
  1635. {
  1636. *ThreadCount = NumThreads;
  1637. }
  1638. if (Status == S_OK)
  1639. {
  1640. // If no threads were found the process must be invalid.
  1641. if (NumThreads == 0)
  1642. {
  1643. Status = E_NOINTERFACE;
  1644. }
  1645. else if (PrevThreads != NULL && NumThreads != PrevInfoCount)
  1646. {
  1647. // Thread count didn't match so return S_FALSE.
  1648. Status = S_FALSE;
  1649. }
  1650. }
  1651. CloseHandle(Snap);
  1652. return Status;
  1653. #else
  1654. return E_UNEXPECTED;
  1655. #endif
  1656. }
  1657. STDMETHODIMP
  1658. LiveUserDebugServices::GetProcessInfo(
  1659. THIS_
  1660. IN ULONG ProcessId,
  1661. OUT OPTIONAL PULONG64 Handle,
  1662. OUT OPTIONAL /* size_is(InfoCount) */ PUSER_THREAD_INFO Threads,
  1663. IN ULONG InfoCount,
  1664. OUT OPTIONAL PULONG ThreadCount
  1665. )
  1666. {
  1667. HANDLE Process;
  1668. HRESULT Status;
  1669. // Enable the privilege that allows the user to debug
  1670. // another process.
  1671. if ((Status = EnableDebugPrivilege()) != S_OK)
  1672. {
  1673. return Status;
  1674. }
  1675. if (Handle != NULL)
  1676. {
  1677. // This should always be a real process ID so there's
  1678. // no need to look for the special CSR value.
  1679. Process = ::OpenProcess(PROCESS_ALL_ACCESS, 0, ProcessId);
  1680. if (Process == NULL)
  1681. {
  1682. return WIN32_LAST_STATUS();
  1683. }
  1684. *Handle = SERVICE_HANDLE(Process);
  1685. }
  1686. else
  1687. {
  1688. Process = NULL;
  1689. }
  1690. if (Threads != NULL || ThreadCount != NULL)
  1691. {
  1692. PUSER_THREAD_INFO PrevThreads;
  1693. ULONG PrevInfoCount;
  1694. ULONG _ThreadCount;
  1695. //
  1696. // We need to enumerate the threads in the process.
  1697. // This is a difficult thing to get right as
  1698. // the thread state for the process can continuously
  1699. // change. In order to try and get a clean snapshot
  1700. // of the thread state we iteratively enumerate until
  1701. // we get two consecutive snapshots that match.
  1702. //
  1703. // We suspend enumerated threads immediately to
  1704. // reduce churn from inside the process itself.
  1705. // We can't do anything about external processes so
  1706. // the enumeration could still get stale right after
  1707. // we return but by stopping everything in the process
  1708. // itself we do what we can.
  1709. //
  1710. // If the caller is just getting the count and
  1711. // not the actual thread information we don't bother
  1712. // iterating as there's no expectation that the
  1713. // thread state will be the same from one call to
  1714. // the next so there's no need to do the extra work.
  1715. //
  1716. if (Threads != NULL)
  1717. {
  1718. // Allocate an array to hold previous results. This
  1719. // can always be the same size as the return array
  1720. // because if there are more threads than can fit in
  1721. // the return array the snapshot will be wrong anyway
  1722. // so we just return without doing comparisons.
  1723. PrevThreads = new USER_THREAD_INFO[InfoCount];
  1724. if (PrevThreads == NULL)
  1725. {
  1726. Status = E_OUTOFMEMORY;
  1727. goto EH_CloseProc;
  1728. }
  1729. }
  1730. else
  1731. {
  1732. PrevThreads = NULL;
  1733. }
  1734. PrevInfoCount = 0;
  1735. for (;;)
  1736. {
  1737. switch(m_PlatformId)
  1738. {
  1739. case VER_PLATFORM_WIN32_NT:
  1740. Status = NtGetProcThreads(ProcessId, Threads, InfoCount,
  1741. &_ThreadCount, m_SysProcInfoSize,
  1742. PrevThreads, PrevInfoCount);
  1743. break;
  1744. case VER_PLATFORM_WIN32_WINDOWS:
  1745. Status = W9xGetProcThreads(ProcessId, Threads, InfoCount,
  1746. &_ThreadCount, PrevThreads,
  1747. PrevInfoCount);
  1748. break;
  1749. default:
  1750. Status = E_UNEXPECTED;
  1751. break;
  1752. }
  1753. //
  1754. // We can clean up any previous information now.
  1755. //
  1756. ULONG i;
  1757. for (i = 0; i < PrevInfoCount; i++)
  1758. {
  1759. ::ResumeThread(OS_HANDLE(PrevThreads[i].Handle));
  1760. ::CloseHandle(OS_HANDLE(PrevThreads[i].Handle));
  1761. }
  1762. if (Status != S_FALSE ||
  1763. _ThreadCount > InfoCount)
  1764. {
  1765. // The snapshot either matched the previous
  1766. // snapshot or there was an error. Also,
  1767. // if the snapshot overflowed the return array
  1768. // quit and give the caller the option of
  1769. // calling again when they notice they didn't
  1770. // get a complete snapshot.
  1771. break;
  1772. }
  1773. // There was a snapshot mismatch so loop again
  1774. // with this snapshot as the previous data.
  1775. PrevInfoCount = _ThreadCount;
  1776. if (PrevInfoCount > InfoCount)
  1777. {
  1778. PrevInfoCount = InfoCount;
  1779. }
  1780. RtlCopyMemory(PrevThreads, Threads,
  1781. PrevInfoCount * sizeof(*PrevThreads));
  1782. }
  1783. if (ThreadCount != NULL)
  1784. {
  1785. *ThreadCount = _ThreadCount;
  1786. }
  1787. delete PrevThreads;
  1788. EH_CloseProc:
  1789. if (Status != S_OK && Process != NULL)
  1790. {
  1791. ::CloseHandle(Process);
  1792. }
  1793. }
  1794. else
  1795. {
  1796. Status = S_OK;
  1797. }
  1798. return Status;
  1799. }
  1800. HRESULT
  1801. ProcessIdToHandle(ULONG ProcessId, PHANDLE Process)
  1802. {
  1803. if (ProcessId == CSRSS_PROCESS_ID)
  1804. {
  1805. if (g_NtDllCalls.CsrGetProcessId != NULL)
  1806. {
  1807. ProcessId = (ULONG)(ULONG_PTR)g_NtDllCalls.CsrGetProcessId();
  1808. }
  1809. else
  1810. {
  1811. *Process = NULL;
  1812. return S_OK;
  1813. }
  1814. }
  1815. *Process = ::OpenProcess(PROCESS_ALL_ACCESS, 0, ProcessId);
  1816. if (*Process == NULL)
  1817. {
  1818. return WIN32_LAST_STATUS();
  1819. }
  1820. return S_OK;
  1821. }
  1822. NTSTATUS
  1823. CreateDebugObject(PHANDLE Object)
  1824. {
  1825. if (*Object != NULL)
  1826. {
  1827. return STATUS_SUCCESS;
  1828. }
  1829. OBJECT_ATTRIBUTES Attr;
  1830. InitializeObjectAttributes(&Attr, NULL, 0, NULL, g_AllAccessSecDesc);
  1831. return g_NtDllCalls.NtCreateDebugObject(Object, DEBUG_ALL_ACCESS,
  1832. &Attr, DEBUG_KILL_ON_CLOSE);
  1833. }
  1834. HRESULT
  1835. LiveUserDebugServices::SysGetProcessOptions(HANDLE Process, PULONG Options)
  1836. {
  1837. NTSTATUS NtStatus;
  1838. ULONG Flags;
  1839. if (m_PlatformId == VER_PLATFORM_WIN32_NT)
  1840. {
  1841. NtStatus = g_NtDllCalls.
  1842. NtQueryInformationProcess(Process, ProcessDebugFlags,
  1843. &Flags, sizeof(Flags), NULL);
  1844. }
  1845. else
  1846. {
  1847. NtStatus = STATUS_INVALID_INFO_CLASS;
  1848. }
  1849. if (NtStatus == STATUS_INVALID_INFO_CLASS)
  1850. {
  1851. // The system doesn't support control over the
  1852. // debug flags. In the attach case this means
  1853. // the flags will be DEBUG_ONLY_THIS_PROCESS.
  1854. *Options = DEBUG_PROCESS_ONLY_THIS_PROCESS;
  1855. NtStatus = STATUS_SUCCESS;
  1856. }
  1857. else if (NT_SUCCESS(NtStatus))
  1858. {
  1859. *Options = 0;
  1860. if ((Flags & PROCESS_DEBUG_INHERIT) == 0)
  1861. {
  1862. *Options = DEBUG_PROCESS_ONLY_THIS_PROCESS;
  1863. }
  1864. }
  1865. return CONV_NT_STATUS(NtStatus);
  1866. }
  1867. HRESULT
  1868. LiveUserDebugServices::OpenDebugActiveProcess(ULONG ProcessId,
  1869. HANDLE Process)
  1870. {
  1871. if (m_PlatformId != VER_PLATFORM_WIN32_NT ||
  1872. !m_UseDebugObject)
  1873. {
  1874. return E_NOTIMPL;
  1875. }
  1876. // We're going to open the process's existing debug
  1877. // object and use it so we can't already have a debug object.
  1878. if (Process == NULL || m_DebugObject != NULL)
  1879. {
  1880. return E_UNEXPECTED;
  1881. }
  1882. NTSTATUS NtStatus;
  1883. NtStatus = g_NtDllCalls.
  1884. NtQueryInformationProcess(Process, ProcessDebugObjectHandle,
  1885. &m_DebugObject, sizeof(m_DebugObject), NULL);
  1886. if (!NT_SUCCESS(NtStatus))
  1887. {
  1888. return HRESULT_FROM_NT(NtStatus);
  1889. }
  1890. return S_OK;
  1891. }
  1892. HRESULT
  1893. LiveUserDebugServices::CreateDebugActiveProcess(ULONG ProcessId,
  1894. HANDLE Process)
  1895. {
  1896. if (m_UseDebugObject)
  1897. {
  1898. if (Process == NULL)
  1899. {
  1900. return E_FAIL;
  1901. }
  1902. if (g_NtDllCalls.NtDebugActiveProcess == NULL)
  1903. {
  1904. return E_NOTIMPL;
  1905. }
  1906. NTSTATUS NtStatus;
  1907. NtStatus = CreateDebugObject(&m_DebugObject);
  1908. if (NT_SUCCESS(NtStatus))
  1909. {
  1910. NtStatus = g_NtDllCalls.NtDebugActiveProcess(Process,
  1911. m_DebugObject);
  1912. if (NT_SUCCESS(NtStatus))
  1913. {
  1914. g_NtDllCalls.DbgUiIssueRemoteBreakin(Process);
  1915. }
  1916. }
  1917. if (!NT_SUCCESS(NtStatus))
  1918. {
  1919. return HRESULT_FROM_NT(NtStatus);
  1920. }
  1921. }
  1922. #ifndef NT_NATIVE
  1923. else if (!::DebugActiveProcess(ProcessId))
  1924. {
  1925. return WIN32_LAST_STATUS();
  1926. }
  1927. #else
  1928. else
  1929. {
  1930. return E_UNEXPECTED;
  1931. }
  1932. #endif
  1933. return S_OK;
  1934. }
  1935. STDMETHODIMP
  1936. LiveUserDebugServices::AttachProcess(
  1937. THIS_
  1938. IN ULONG ProcessId,
  1939. IN ULONG AttachFlags,
  1940. OUT PULONG64 ProcessHandle,
  1941. OUT PULONG ProcessOptions
  1942. )
  1943. {
  1944. HRESULT Status;
  1945. // Enable the privilege that allows the user to debug
  1946. // another process.
  1947. if ((Status = EnableDebugPrivilege()) != S_OK)
  1948. {
  1949. return Status;
  1950. }
  1951. HANDLE Process;
  1952. if (ProcessId == CSRSS_PROCESS_ID)
  1953. {
  1954. CloseProfileUserMapping();
  1955. }
  1956. if ((Status = ProcessIdToHandle(ProcessId, &Process)) != S_OK)
  1957. {
  1958. return Status;
  1959. }
  1960. if ((Status = SysGetProcessOptions(Process, ProcessOptions)) != S_OK)
  1961. {
  1962. if (Process != NULL)
  1963. {
  1964. ::CloseHandle(Process);
  1965. }
  1966. return Status;
  1967. }
  1968. if (AttachFlags & DEBUG_ATTACH_EXISTING)
  1969. {
  1970. Status = OpenDebugActiveProcess(ProcessId, Process);
  1971. }
  1972. else
  1973. {
  1974. Status = CreateDebugActiveProcess(ProcessId, Process);
  1975. }
  1976. if (Status != S_OK)
  1977. {
  1978. if (Process != NULL)
  1979. {
  1980. ::CloseHandle(Process);
  1981. }
  1982. return Status;
  1983. }
  1984. *ProcessHandle = SERVICE_HANDLE(Process);
  1985. return S_OK;
  1986. }
  1987. STDMETHODIMP
  1988. LiveUserDebugServices::DetachProcess(
  1989. THIS_
  1990. IN ULONG ProcessId
  1991. )
  1992. {
  1993. HRESULT Status;
  1994. //
  1995. // A ProcessId of zero means that the caller is just
  1996. // checking for detach support and no actual detach
  1997. // should occur.
  1998. //
  1999. if (m_UseDebugObject)
  2000. {
  2001. if (g_NtDllCalls.NtRemoveProcessDebug == NULL)
  2002. {
  2003. return E_NOTIMPL;
  2004. }
  2005. // Check for the query before checking the debug
  2006. // object as the query may come in early.
  2007. if (ProcessId == 0)
  2008. {
  2009. return S_OK;
  2010. }
  2011. if (m_DebugObject == NULL)
  2012. {
  2013. return E_UNEXPECTED;
  2014. }
  2015. HANDLE Process;
  2016. if ((Status = ProcessIdToHandle(ProcessId, &Process)) != S_OK)
  2017. {
  2018. return Status;
  2019. }
  2020. if (Process == NULL)
  2021. {
  2022. return E_FAIL;
  2023. }
  2024. NTSTATUS NtStatus;
  2025. NtStatus = g_NtDllCalls.
  2026. NtRemoveProcessDebug(Process, m_DebugObject);
  2027. Status = CONV_NT_STATUS(NtStatus);
  2028. ::CloseHandle(Process);
  2029. }
  2030. else
  2031. {
  2032. if (g_Kernel32Calls.DebugActiveProcessStop == NULL)
  2033. {
  2034. return E_NOTIMPL;
  2035. }
  2036. if (ProcessId == 0)
  2037. {
  2038. return S_OK;
  2039. }
  2040. if (!g_Kernel32Calls.DebugActiveProcessStop(ProcessId))
  2041. {
  2042. return WIN32_LAST_STATUS();
  2043. }
  2044. }
  2045. return S_OK;
  2046. }
  2047. #ifdef NT_NATIVE
  2048. NTSTATUS
  2049. NtSimpleCreateProcess(PCSTR CommandLine, ULONG CreateFlags,
  2050. HANDLE DebugObject, PPROCESS_INFORMATION RetInfo)
  2051. {
  2052. NTSTATUS Status;
  2053. ANSI_STRING Ansi;
  2054. UNICODE_STRING RawAppName, AppName;
  2055. UNICODE_STRING WideCmdLine;
  2056. PRTL_USER_PROCESS_PARAMETERS Params;
  2057. RTL_USER_PROCESS_INFORMATION Info;
  2058. if (CreateFlags & DEBUG_ONLY_THIS_PROCESS)
  2059. {
  2060. // The hacked way of controlling debug inheritance
  2061. // is via the low bit of the debug object handle.
  2062. // If the bit is set it means do not inherit.
  2063. DebugObject = (HANDLE)((ULONG_PTR)DebugObject | 1);
  2064. }
  2065. //
  2066. // This is a simple interface, so assume the first
  2067. // space-delimited token is the executable to run.
  2068. //
  2069. PCSTR ExeStart, ExeEnd;
  2070. ExeStart = CommandLine;
  2071. while (*ExeStart == ' ' || *ExeStart == '\t')
  2072. {
  2073. ExeStart++;
  2074. }
  2075. if (*ExeStart == 0)
  2076. {
  2077. return STATUS_INVALID_PARAMETER;
  2078. }
  2079. ExeEnd = ExeStart;
  2080. while (*ExeEnd && !(*ExeEnd == ' ' || *ExeEnd == '\t'))
  2081. {
  2082. ExeEnd++;
  2083. }
  2084. Ansi.Buffer = (PSTR)ExeStart;
  2085. Ansi.Length = (USHORT)(ExeEnd - ExeStart);
  2086. Ansi.MaximumLength = Ansi.Length;
  2087. Status = RtlAnsiStringToUnicodeString(&RawAppName, &Ansi, TRUE);
  2088. if (!NT_SUCCESS(Status))
  2089. {
  2090. return Status;
  2091. }
  2092. Status = RtlDosPathNameToNtPathName_U(RawAppName.Buffer, &AppName,
  2093. NULL, NULL);
  2094. if (!NT_SUCCESS(Status))
  2095. {
  2096. goto EH_RawAppName;
  2097. }
  2098. RtlInitAnsiString(&Ansi, CommandLine);
  2099. Status = RtlAnsiStringToUnicodeString(&WideCmdLine, &Ansi, TRUE);
  2100. if (!NT_SUCCESS(Status))
  2101. {
  2102. goto EH_AppName;
  2103. }
  2104. Status = RtlCreateProcessParameters(&Params, &AppName, NULL, NULL,
  2105. &WideCmdLine, NULL, NULL, NULL,
  2106. NULL, NULL);
  2107. if (!NT_SUCCESS(Status))
  2108. {
  2109. goto EH_WideCmdLine;
  2110. }
  2111. Info.Length = sizeof(Info);
  2112. Status = RtlCreateUserProcess(&AppName, OBJ_CASE_INSENSITIVE,
  2113. Params, NULL, NULL, NULL, FALSE,
  2114. DebugObject, NULL, &Info);
  2115. RtlDestroyProcessParameters(Params);
  2116. if (NT_SUCCESS(Status))
  2117. {
  2118. RetInfo->dwProcessId = HandleToUlong(Info.ClientId.UniqueProcess);
  2119. RetInfo->dwThreadId = HandleToUlong(Info.ClientId.UniqueThread);
  2120. RetInfo->hProcess = Info.Process;
  2121. RetInfo->hThread = Info.Thread;
  2122. if ((CreateFlags & CREATE_SUSPENDED) == 0)
  2123. {
  2124. NtResumeThread(Info.Thread, NULL);
  2125. }
  2126. }
  2127. EH_WideCmdLine:
  2128. RtlFreeUnicodeString(&WideCmdLine);
  2129. EH_AppName:
  2130. RtlFreeUnicodeString(&AppName);
  2131. EH_RawAppName:
  2132. RtlFreeUnicodeString(&RawAppName);
  2133. return Status;
  2134. }
  2135. #endif // #ifdef NT_NATIVE
  2136. #define DHEAP_ENV "_NO_DEBUG_HEAP"
  2137. STDMETHODIMP
  2138. LiveUserDebugServices::CreateProcess(
  2139. THIS_
  2140. IN PSTR CommandLine,
  2141. IN ULONG CreateFlags,
  2142. OUT PULONG ProcessId,
  2143. OUT PULONG ThreadId,
  2144. OUT PULONG64 ProcessHandle,
  2145. OUT PULONG64 ThreadHandle
  2146. )
  2147. {
  2148. HRESULT Status;
  2149. // Enable the privilege that allows the user to debug
  2150. // another process.
  2151. if ((Status = EnableDebugPrivilege()) != S_OK)
  2152. {
  2153. return Status;
  2154. }
  2155. // The system looks at the environment variable
  2156. // _NO_DEBUG_HEAP to determine whether the new
  2157. // process should use the debug heap or not. If
  2158. // the caller has requested the normal heap
  2159. // set this environment variable so that it's
  2160. // inherited.
  2161. if (CreateFlags & DEBUG_CREATE_PROCESS_NO_DEBUG_HEAP)
  2162. {
  2163. ::SetEnvironmentVariable(DHEAP_ENV, "1");
  2164. // Turn off this flag since it's not meaningful
  2165. // to CreateProcess itself.
  2166. CreateFlags &= ~DEBUG_CREATE_PROCESS_NO_DEBUG_HEAP;
  2167. }
  2168. PROCESS_INFORMATION ProcInfo;
  2169. #ifndef NT_NATIVE
  2170. HANDLE OldDebugObject;
  2171. BOOL SetOldDebugObject = FALSE;
  2172. Status = S_OK;
  2173. if (m_UseDebugObject)
  2174. {
  2175. //
  2176. // Set up this thread's debug object to the one that
  2177. // we're using so that our debug object is used when
  2178. // debugging the new process. This lets us continue
  2179. // to use the normal Win32 CreateProcess call rather
  2180. // than trying to go through NtCreateProcessEx and
  2181. // guarantees we get all the Win32 process creation logic.
  2182. //
  2183. if (g_NtDllCalls.DbgUiSetThreadDebugObject == NULL)
  2184. {
  2185. Status = E_NOTIMPL;
  2186. }
  2187. else
  2188. {
  2189. NTSTATUS NtStatus;
  2190. OldDebugObject = g_NtDllCalls.DbgUiGetThreadDebugObject();
  2191. NtStatus = CreateDebugObject(&m_DebugObject);
  2192. if (NT_SUCCESS(NtStatus))
  2193. {
  2194. g_NtDllCalls.DbgUiSetThreadDebugObject(m_DebugObject);
  2195. SetOldDebugObject = TRUE;
  2196. }
  2197. else
  2198. {
  2199. Status = HRESULT_FROM_NT(NtStatus);
  2200. }
  2201. }
  2202. }
  2203. if (Status == S_OK)
  2204. {
  2205. STARTUPINFO StartupInfo;
  2206. ZeroMemory(&StartupInfo, sizeof(StartupInfo));
  2207. StartupInfo.cb = sizeof(StartupInfo);
  2208. if (!::CreateProcess(NULL, CommandLine, NULL, NULL, TRUE,
  2209. CreateFlags, NULL, NULL,
  2210. &StartupInfo, &ProcInfo))
  2211. {
  2212. Status = WIN32_LAST_STATUS();
  2213. }
  2214. else
  2215. {
  2216. Status = S_OK;
  2217. }
  2218. }
  2219. if (SetOldDebugObject)
  2220. {
  2221. g_NtDllCalls.DbgUiSetThreadDebugObject(OldDebugObject);
  2222. }
  2223. #else // #ifndef NT_NATIVE
  2224. if (!m_UseDebugObject)
  2225. {
  2226. Status = E_UNEXPECTED;
  2227. }
  2228. else
  2229. {
  2230. NTSTATUS NtStatus;
  2231. NtStatus = CreateDebugObject(&m_DebugObject);
  2232. if (NT_SUCCESS(NtStatus))
  2233. {
  2234. NtStatus = NtSimpleCreateProcess(CommandLine, CreateFlags,
  2235. m_DebugObject, &ProcInfo);
  2236. }
  2237. Status = CONV_NT_STATUS(NtStatus);
  2238. }
  2239. #endif // #ifndef NT_NATIVE
  2240. // Clear the special debug heap variable so it
  2241. // isn't inadvertently used somewhere else.
  2242. ::SetEnvironmentVariable(DHEAP_ENV, NULL);
  2243. if (Status == S_OK)
  2244. {
  2245. *ProcessId = ProcInfo.dwProcessId;
  2246. *ThreadId = ProcInfo.dwThreadId;
  2247. *ProcessHandle = SERVICE_HANDLE(ProcInfo.hProcess);
  2248. *ThreadHandle = SERVICE_HANDLE(ProcInfo.hThread);
  2249. }
  2250. return Status;
  2251. }
  2252. STDMETHODIMP
  2253. LiveUserDebugServices::TerminateProcess(
  2254. THIS_
  2255. IN ULONG64 Process,
  2256. IN ULONG ExitCode
  2257. )
  2258. {
  2259. if (!::TerminateProcess(OS_HANDLE(Process), ExitCode))
  2260. {
  2261. return WIN32_LAST_STATUS();
  2262. }
  2263. return S_OK;
  2264. }
  2265. STDMETHODIMP
  2266. LiveUserDebugServices::AbandonProcess(
  2267. THIS_
  2268. IN ULONG64 Process
  2269. )
  2270. {
  2271. HRESULT Status;
  2272. //
  2273. // In order to abandon a process but still leave it
  2274. // as being debugged we need to get the process's
  2275. // debug object and duplicate it into the debuggee
  2276. // process. This gives the debuggee process itself
  2277. // a reference to its debug object, creating a circle
  2278. // that will keep the process alive and in the debugged
  2279. // state.
  2280. //
  2281. // This circular reference will also mean that the
  2282. // process must be manually killed. This may be
  2283. // something interesting to address at some point.
  2284. //
  2285. if (m_DebugObject == NULL)
  2286. {
  2287. return E_NOTIMPL;
  2288. }
  2289. HANDLE Dup;
  2290. if (!::DuplicateHandle(GetCurrentProcess(), m_DebugObject,
  2291. OS_HANDLE(Process), &Dup, 0, FALSE,
  2292. DUPLICATE_SAME_ACCESS))
  2293. {
  2294. return WIN32_LAST_STATUS();
  2295. }
  2296. return S_OK;
  2297. }
  2298. STDMETHODIMP
  2299. LiveUserDebugServices::GetProcessExitCode(
  2300. THIS_
  2301. IN ULONG64 Process,
  2302. OUT PULONG ExitCode
  2303. )
  2304. {
  2305. if (!::GetExitCodeProcess(OS_HANDLE(Process), ExitCode))
  2306. {
  2307. return WIN32_LAST_STATUS();
  2308. }
  2309. return *ExitCode == STILL_ACTIVE ? S_FALSE : S_OK;
  2310. }
  2311. STDMETHODIMP
  2312. LiveUserDebugServices::CloseHandle(
  2313. THIS_
  2314. IN ULONG64 Handle
  2315. )
  2316. {
  2317. if (Handle == 0)
  2318. {
  2319. return S_FALSE;
  2320. }
  2321. if (!::CloseHandle(OS_HANDLE(Handle)))
  2322. {
  2323. return WIN32_LAST_STATUS();
  2324. }
  2325. return S_OK;
  2326. }
  2327. STDMETHODIMP
  2328. LiveUserDebugServices::SetProcessOptions(
  2329. THIS_
  2330. IN ULONG64 Process,
  2331. IN ULONG Options
  2332. )
  2333. {
  2334. if (m_PlatformId != VER_PLATFORM_WIN32_NT)
  2335. {
  2336. return E_NOTIMPL;
  2337. }
  2338. NTSTATUS NtStatus;
  2339. ULONG NtFlags = 0;
  2340. if ((Options & DEBUG_PROCESS_ONLY_THIS_PROCESS) == 0)
  2341. {
  2342. NtFlags |= PROCESS_DEBUG_INHERIT;
  2343. }
  2344. NtStatus = g_NtDllCalls.
  2345. NtSetInformationProcess(OS_HANDLE(Process), ProcessDebugFlags,
  2346. &NtFlags, sizeof(NtFlags));
  2347. if (NtStatus == STATUS_INVALID_INFO_CLASS)
  2348. {
  2349. return E_NOTIMPL;
  2350. }
  2351. else
  2352. {
  2353. return CONV_NT_STATUS(NtStatus);
  2354. }
  2355. }
  2356. STDMETHODIMP
  2357. LiveUserDebugServices::SetDebugObjectOptions(
  2358. THIS_
  2359. IN ULONG64 DebugObject,
  2360. IN ULONG Options
  2361. )
  2362. {
  2363. if (DebugObject == 0)
  2364. {
  2365. if (m_DebugObject == NULL)
  2366. {
  2367. if (g_Kernel32Calls.DebugSetProcessKillOnExit == NULL)
  2368. {
  2369. return E_NOTIMPL;
  2370. }
  2371. if (!g_Kernel32Calls.
  2372. DebugSetProcessKillOnExit((Options &
  2373. DEBUG_PROCESS_DETACH_ON_EXIT) == 0))
  2374. {
  2375. return WIN32_LAST_STATUS();
  2376. }
  2377. return S_OK;
  2378. }
  2379. DebugObject = SERVICE_HANDLE(m_DebugObject);
  2380. }
  2381. if (g_NtDllCalls.NtSetInformationDebugObject == NULL)
  2382. {
  2383. return E_NOTIMPL;
  2384. }
  2385. NTSTATUS NtStatus;
  2386. ULONG NtFlags = 0;
  2387. if ((Options & DEBUG_PROCESS_DETACH_ON_EXIT) == 0)
  2388. {
  2389. NtFlags |= DEBUG_KILL_ON_CLOSE;
  2390. }
  2391. NtStatus = g_NtDllCalls.
  2392. NtSetInformationDebugObject(OS_HANDLE(DebugObject), DebugObjectFlags,
  2393. &NtFlags, sizeof(NtFlags), NULL);
  2394. return CONV_NT_STATUS(NtStatus);
  2395. }
  2396. STDMETHODIMP
  2397. LiveUserDebugServices::GetProcessDebugObject(
  2398. THIS_
  2399. IN ULONG64 Process,
  2400. OUT PULONG64 DebugObject
  2401. )
  2402. {
  2403. if (m_PlatformId != VER_PLATFORM_WIN32_NT)
  2404. {
  2405. return E_NOTIMPL;
  2406. }
  2407. NTSTATUS NtStatus;
  2408. HANDLE ObjHandle;
  2409. NtStatus = g_NtDllCalls.
  2410. NtQueryInformationProcess(OS_HANDLE(Process), ProcessDebugObjectHandle,
  2411. &ObjHandle, sizeof(ObjHandle), NULL);
  2412. if (!NT_SUCCESS(NtStatus))
  2413. {
  2414. return HRESULT_FROM_NT(NtStatus);
  2415. }
  2416. *DebugObject = SERVICE_HANDLE(ObjHandle);
  2417. return S_OK;
  2418. }
  2419. STDMETHODIMP
  2420. LiveUserDebugServices::DuplicateHandle(
  2421. THIS_
  2422. IN ULONG64 InProcess,
  2423. IN ULONG64 InHandle,
  2424. IN ULONG64 OutProcess,
  2425. IN ULONG DesiredAccess,
  2426. IN ULONG Inherit,
  2427. IN ULONG Options,
  2428. OUT PULONG64 OutHandle
  2429. )
  2430. {
  2431. HANDLE Dup;
  2432. if (!::DuplicateHandle(OS_HANDLE(InProcess), OS_HANDLE(InHandle),
  2433. OS_HANDLE(OutProcess), &Dup,
  2434. DesiredAccess, Inherit, Options))
  2435. {
  2436. return WIN32_LAST_STATUS();
  2437. }
  2438. *OutHandle = SERVICE_HANDLE(Dup);
  2439. return S_OK;
  2440. }
  2441. STDMETHODIMP
  2442. LiveUserDebugServices::ReadVirtual(
  2443. THIS_
  2444. IN ULONG64 Process,
  2445. IN ULONG64 Offset,
  2446. OUT PVOID Buffer,
  2447. IN ULONG BufferSize,
  2448. OUT OPTIONAL PULONG BytesRead
  2449. )
  2450. {
  2451. SIZE_T SizeRead;
  2452. if (!::ReadProcessMemory(OS_HANDLE(Process),
  2453. (LPCVOID)(ULONG_PTR)Offset,
  2454. Buffer, BufferSize, &SizeRead))
  2455. {
  2456. return WIN32_LAST_STATUS();
  2457. }
  2458. if (BytesRead != NULL)
  2459. {
  2460. *BytesRead = (ULONG)SizeRead;
  2461. }
  2462. return S_OK;
  2463. }
  2464. STDMETHODIMP
  2465. LiveUserDebugServices::WriteVirtual(
  2466. THIS_
  2467. IN ULONG64 Process,
  2468. IN ULONG64 Offset,
  2469. IN PVOID Buffer,
  2470. IN ULONG BufferSize,
  2471. OUT OPTIONAL PULONG BytesWritten
  2472. )
  2473. {
  2474. SIZE_T SizeWritten;
  2475. if (!::WriteProcessMemory(OS_HANDLE(Process),
  2476. (LPVOID)(ULONG_PTR)Offset,
  2477. Buffer, BufferSize, &SizeWritten))
  2478. {
  2479. return WIN32_LAST_STATUS();
  2480. }
  2481. if (BytesWritten != NULL)
  2482. {
  2483. *BytesWritten = (ULONG)SizeWritten;
  2484. }
  2485. return S_OK;
  2486. }
  2487. STDMETHODIMP
  2488. LiveUserDebugServices::QueryVirtual(
  2489. THIS_
  2490. IN ULONG64 Process,
  2491. IN ULONG64 Offset,
  2492. OUT PVOID Buffer,
  2493. IN ULONG BufferSize,
  2494. OUT OPTIONAL PULONG BufferUsed
  2495. )
  2496. {
  2497. if (BufferSize < sizeof(MEMORY_BASIC_INFORMATION))
  2498. {
  2499. return E_INVALIDARG;
  2500. }
  2501. if (BufferUsed != NULL)
  2502. {
  2503. *BufferUsed = sizeof(MEMORY_BASIC_INFORMATION);
  2504. }
  2505. if (!::VirtualQueryEx(OS_HANDLE(Process),
  2506. (LPCVOID)(ULONG_PTR)Offset,
  2507. (PMEMORY_BASIC_INFORMATION)Buffer,
  2508. sizeof(MEMORY_BASIC_INFORMATION)))
  2509. {
  2510. return WIN32_LAST_STATUS();
  2511. }
  2512. return S_OK;
  2513. }
  2514. STDMETHODIMP
  2515. LiveUserDebugServices::ProtectVirtual(
  2516. THIS_
  2517. IN ULONG64 Process,
  2518. IN ULONG64 Offset,
  2519. IN ULONG64 Size,
  2520. IN ULONG NewProtect,
  2521. OUT PULONG OldProtect
  2522. )
  2523. {
  2524. BOOL Status = ::VirtualProtectEx(OS_HANDLE(Process),
  2525. (PVOID)(ULONG_PTR)Offset, (SIZE_T)Size,
  2526. NewProtect, OldProtect);
  2527. return CONV_W32_STATUS(Status);
  2528. }
  2529. STDMETHODIMP
  2530. LiveUserDebugServices::AllocVirtual(
  2531. THIS_
  2532. IN ULONG64 Process,
  2533. IN ULONG64 Offset,
  2534. IN ULONG64 Size,
  2535. IN ULONG Type,
  2536. IN ULONG Protect,
  2537. OUT PULONG64 AllocOffset
  2538. )
  2539. {
  2540. PVOID Addr = ::VirtualAllocEx(OS_HANDLE(Process), (PVOID)(ULONG_PTR)Offset,
  2541. (SIZE_T)Size, Type, Protect);
  2542. if (Addr == NULL)
  2543. {
  2544. return WIN32_LAST_STATUS();
  2545. }
  2546. *AllocOffset = (ULONG64)(LONG64)(ULONG_PTR)Addr;
  2547. return S_OK;
  2548. }
  2549. STDMETHODIMP
  2550. LiveUserDebugServices::FreeVirtual(
  2551. THIS_
  2552. IN ULONG64 Process,
  2553. IN ULONG64 Offset,
  2554. IN ULONG64 Size,
  2555. IN ULONG Type
  2556. )
  2557. {
  2558. BOOL Status = ::VirtualFreeEx(OS_HANDLE(Process), (PVOID)(ULONG_PTR)Offset,
  2559. (SIZE_T)Size, Type);
  2560. return CONV_W32_STATUS(Status);
  2561. }
  2562. STDMETHODIMP
  2563. LiveUserDebugServices::ReadHandleData(
  2564. THIS_
  2565. IN ULONG64 Process,
  2566. IN ULONG64 Handle,
  2567. IN ULONG DataType,
  2568. OUT OPTIONAL PVOID Buffer,
  2569. IN ULONG BufferSize,
  2570. OUT OPTIONAL PULONG DataSize
  2571. )
  2572. {
  2573. if (m_PlatformId != VER_PLATFORM_WIN32_NT)
  2574. {
  2575. return E_NOTIMPL;
  2576. }
  2577. HANDLE Dup = NULL;
  2578. if (DataType != DEBUG_HANDLE_DATA_TYPE_HANDLE_COUNT &&
  2579. !::DuplicateHandle(OS_HANDLE(Process), OS_HANDLE(Handle),
  2580. GetCurrentProcess(), &Dup, 0, FALSE,
  2581. DUPLICATE_SAME_ACCESS))
  2582. {
  2583. return WIN32_LAST_STATUS();
  2584. }
  2585. ULONG64 NtBuffer[1024 / sizeof(ULONG64)];
  2586. ULONG Used = 0;
  2587. NTSTATUS NtStatus;
  2588. HRESULT Status = S_OK;
  2589. switch(DataType)
  2590. {
  2591. case DEBUG_HANDLE_DATA_TYPE_BASIC:
  2592. Used = sizeof(DEBUG_HANDLE_DATA_BASIC);
  2593. if (Buffer == NULL)
  2594. {
  2595. break;
  2596. }
  2597. if (BufferSize < Used)
  2598. {
  2599. Status = E_INVALIDARG;
  2600. break;
  2601. }
  2602. POBJECT_BASIC_INFORMATION NtBasic;
  2603. NtBasic = (POBJECT_BASIC_INFORMATION)NtBuffer;
  2604. NtStatus = g_NtDllCalls.NtQueryObject(Dup, ObjectBasicInformation,
  2605. NtBasic, sizeof(*NtBasic), NULL);
  2606. if (!NT_SUCCESS(NtStatus))
  2607. {
  2608. Status = HRESULT_FROM_NT(NtStatus);
  2609. break;
  2610. }
  2611. PDEBUG_HANDLE_DATA_BASIC Basic;
  2612. Basic = (PDEBUG_HANDLE_DATA_BASIC)Buffer;
  2613. Basic->TypeNameSize = NtBasic->TypeInfoSize / sizeof(WCHAR);
  2614. Basic->ObjectNameSize = NtBasic->NameInfoSize / sizeof(WCHAR);
  2615. Basic->Attributes = NtBasic->Attributes;
  2616. Basic->GrantedAccess = NtBasic->GrantedAccess;
  2617. Basic->HandleCount = NtBasic->HandleCount;
  2618. Basic->PointerCount = NtBasic->PointerCount;
  2619. break;
  2620. case DEBUG_HANDLE_DATA_TYPE_TYPE_NAME:
  2621. POBJECT_TYPE_INFORMATION NtType;
  2622. NtType = (POBJECT_TYPE_INFORMATION)NtBuffer;
  2623. NtStatus = g_NtDllCalls.NtQueryObject(Dup, ObjectTypeInformation,
  2624. NtType, sizeof(NtBuffer), NULL);
  2625. if (!NT_SUCCESS(NtStatus))
  2626. {
  2627. Status = HRESULT_FROM_NT(NtStatus);
  2628. break;
  2629. }
  2630. if (NtType->TypeName.Buffer == NULL)
  2631. {
  2632. Used = 1;
  2633. if (Buffer != NULL && BufferSize > 0)
  2634. {
  2635. *(PCHAR)Buffer = 0;
  2636. }
  2637. break;
  2638. }
  2639. Used = NtType->TypeName.Length / sizeof(WCHAR) + 1;
  2640. NtType->TypeName.Buffer[Used - 1] = 0;
  2641. if (Buffer != NULL &&
  2642. WideCharToMultiByte(CP_ACP, 0, NtType->TypeName.Buffer,
  2643. -1, (LPSTR)Buffer, BufferSize,
  2644. NULL, NULL) == 0)
  2645. {
  2646. Status = WIN32_LAST_STATUS();
  2647. break;
  2648. }
  2649. break;
  2650. case DEBUG_HANDLE_DATA_TYPE_OBJECT_NAME:
  2651. POBJECT_NAME_INFORMATION NtName;
  2652. NtName = (POBJECT_NAME_INFORMATION)NtBuffer;
  2653. NtStatus = g_NtDllCalls.NtQueryObject(Dup, ObjectNameInformation,
  2654. NtName, sizeof(NtBuffer), NULL);
  2655. if (!NT_SUCCESS(NtStatus))
  2656. {
  2657. Status = HRESULT_FROM_NT(NtStatus);
  2658. break;
  2659. }
  2660. if (NtName->Name.Buffer == NULL)
  2661. {
  2662. Used = 1;
  2663. if (Buffer != NULL && BufferSize > 0)
  2664. {
  2665. *(PCHAR)Buffer = 0;
  2666. }
  2667. break;
  2668. }
  2669. Used = NtName->Name.Length / sizeof(WCHAR) + 1;
  2670. NtName->Name.Buffer[Used - 1] = 0;
  2671. if (Buffer != NULL &&
  2672. WideCharToMultiByte(CP_ACP, 0, NtName->Name.Buffer,
  2673. -1, (LPSTR)Buffer, BufferSize,
  2674. NULL, NULL) == 0)
  2675. {
  2676. Status = WIN32_LAST_STATUS();
  2677. break;
  2678. }
  2679. break;
  2680. case DEBUG_HANDLE_DATA_TYPE_HANDLE_COUNT:
  2681. NtStatus = g_NtDllCalls.
  2682. NtQueryInformationProcess(OS_HANDLE(Process), ProcessHandleCount,
  2683. Buffer, BufferSize, &Used);
  2684. if (!NT_SUCCESS(NtStatus))
  2685. {
  2686. Status = HRESULT_FROM_NT(NtStatus);
  2687. }
  2688. break;
  2689. }
  2690. if (DataSize != NULL)
  2691. {
  2692. *DataSize = Used;
  2693. }
  2694. if (Dup != NULL)
  2695. {
  2696. ::CloseHandle(Dup);
  2697. }
  2698. return Status;
  2699. }
  2700. STDMETHODIMP
  2701. LiveUserDebugServices::SuspendThreads(
  2702. THIS_
  2703. IN ULONG Count,
  2704. IN /* size_is(Count) */ PULONG64 Threads,
  2705. OUT OPTIONAL /* size_is(Count) */ PULONG SuspendCounts
  2706. )
  2707. {
  2708. ULONG i;
  2709. HRESULT Status;
  2710. Status = S_OK;
  2711. for (i = 0; i < Count; i++)
  2712. {
  2713. ULONG OldCount = ::SuspendThread(OS_HANDLE(Threads[i]));
  2714. if (OldCount == -1)
  2715. {
  2716. Status = WIN32_LAST_STATUS();
  2717. }
  2718. if (SuspendCounts != NULL)
  2719. {
  2720. SuspendCounts[i] = OldCount + 1;
  2721. }
  2722. }
  2723. return Status;
  2724. }
  2725. STDMETHODIMP
  2726. LiveUserDebugServices::ResumeThreads(
  2727. THIS_
  2728. IN ULONG Count,
  2729. IN /* size_is(Count) */ PULONG64 Threads,
  2730. OUT OPTIONAL /* size_is(Count) */ PULONG SuspendCounts
  2731. )
  2732. {
  2733. ULONG i;
  2734. HRESULT Status;
  2735. Status = S_OK;
  2736. for (i = 0; i < Count; i++)
  2737. {
  2738. ULONG OldCount = ::ResumeThread(OS_HANDLE(Threads[i]));
  2739. if (OldCount == -1)
  2740. {
  2741. Status = WIN32_LAST_STATUS();
  2742. }
  2743. if (SuspendCounts != NULL)
  2744. {
  2745. SuspendCounts[i] = OldCount - 1;
  2746. }
  2747. }
  2748. return Status;
  2749. }
  2750. STDMETHODIMP
  2751. LiveUserDebugServices::GetContext(
  2752. THIS_
  2753. IN ULONG64 Thread,
  2754. IN ULONG Flags,
  2755. IN ULONG FlagsOffset,
  2756. OUT PVOID Context,
  2757. IN ULONG ContextSize,
  2758. OUT OPTIONAL PULONG ContextUsed
  2759. )
  2760. {
  2761. if (ContextSize < m_ContextSize)
  2762. {
  2763. return E_INVALIDARG;
  2764. }
  2765. if (ContextUsed != NULL)
  2766. {
  2767. *ContextUsed = m_ContextSize;
  2768. }
  2769. // Some platforms have alignment requirements for
  2770. // context information, so just get data into a
  2771. // local context structure, which presumably the
  2772. // compiler will properly align, and then copy
  2773. // it into the output buffer.
  2774. #ifndef _X86_
  2775. CONTEXT _LocalContext;
  2776. PCONTEXT LocalContext = &_LocalContext;
  2777. #else
  2778. PCONTEXT LocalContext = (PCONTEXT)Context;
  2779. #endif
  2780. // Initialize context flags here rather than making Context
  2781. // IN OUT to avoid sending a full CONTEXT just for a
  2782. // ULONG's worth of flags.
  2783. *(PULONG)((PUCHAR)LocalContext + FlagsOffset) = Flags;
  2784. if (!::GetThreadContext(OS_HANDLE(Thread), LocalContext))
  2785. {
  2786. return WIN32_LAST_STATUS();
  2787. }
  2788. #ifndef _X86_
  2789. memcpy(Context, LocalContext, m_ContextSize);
  2790. #endif
  2791. return S_OK;
  2792. }
  2793. STDMETHODIMP
  2794. LiveUserDebugServices::SetContext(
  2795. THIS_
  2796. IN ULONG64 Thread,
  2797. IN PVOID Context,
  2798. IN ULONG ContextSize,
  2799. OUT OPTIONAL PULONG ContextUsed
  2800. )
  2801. {
  2802. if (ContextSize < m_ContextSize)
  2803. {
  2804. return E_INVALIDARG;
  2805. }
  2806. if (ContextUsed != NULL)
  2807. {
  2808. *ContextUsed = m_ContextSize;
  2809. }
  2810. // Some platforms have alignment requirements for
  2811. // context information, so just get data into a
  2812. // local context structure, which presumably the
  2813. // compiler will properly align.
  2814. #ifndef _X86_
  2815. CONTEXT _LocalContext;
  2816. PCONTEXT LocalContext = &_LocalContext;
  2817. memcpy(LocalContext, Context, m_ContextSize);
  2818. #else
  2819. PCONTEXT LocalContext = (PCONTEXT)Context;
  2820. #endif
  2821. if (!::SetThreadContext(OS_HANDLE(Thread), LocalContext))
  2822. {
  2823. return WIN32_LAST_STATUS();
  2824. }
  2825. return S_OK;
  2826. }
  2827. STDMETHODIMP
  2828. LiveUserDebugServices::GetProcessDataOffset(
  2829. THIS_
  2830. IN ULONG64 Process,
  2831. OUT PULONG64 Offset
  2832. )
  2833. {
  2834. if (m_PlatformId != VER_PLATFORM_WIN32_NT)
  2835. {
  2836. // XXX drewb - Equivalent?
  2837. return E_NOTIMPL;
  2838. }
  2839. NTSTATUS NtStatus;
  2840. PROCESS_BASIC_INFORMATION ProcessInformation;
  2841. NtStatus = g_NtDllCalls.
  2842. NtQueryInformationProcess(OS_HANDLE(Process),
  2843. ProcessBasicInformation,
  2844. &ProcessInformation,
  2845. sizeof(ProcessInformation),
  2846. NULL);
  2847. *Offset = (ULONG64)(ProcessInformation.PebBaseAddress);
  2848. return CONV_NT_STATUS(NtStatus);
  2849. }
  2850. STDMETHODIMP
  2851. LiveUserDebugServices::GetThreadDataOffset(
  2852. THIS_
  2853. IN ULONG64 Thread,
  2854. OUT PULONG64 Offset
  2855. )
  2856. {
  2857. if (m_PlatformId != VER_PLATFORM_WIN32_NT)
  2858. {
  2859. // XXX drewb - Equivalent?
  2860. return E_NOTIMPL;
  2861. }
  2862. NTSTATUS NtStatus;
  2863. THREAD_BASIC_INFORMATION ThreadInformation;
  2864. NtStatus = g_NtDllCalls.
  2865. NtQueryInformationThread(OS_HANDLE(Thread),
  2866. ThreadBasicInformation,
  2867. &ThreadInformation,
  2868. sizeof(ThreadInformation),
  2869. NULL);
  2870. *Offset = (ULONG64)(ThreadInformation.TebBaseAddress);
  2871. return CONV_NT_STATUS(NtStatus);
  2872. }
  2873. STDMETHODIMP
  2874. LiveUserDebugServices::DescribeSelector(
  2875. THIS_
  2876. IN ULONG64 Thread,
  2877. IN ULONG Selector,
  2878. OUT PVOID Buffer,
  2879. IN ULONG BufferSize,
  2880. OUT OPTIONAL PULONG BufferUsed
  2881. )
  2882. {
  2883. #ifdef _X86_
  2884. if (BufferSize < sizeof(LDT_ENTRY))
  2885. {
  2886. return E_INVALIDARG;
  2887. }
  2888. if (BufferUsed != NULL)
  2889. {
  2890. *BufferUsed = sizeof(LDT_ENTRY);
  2891. }
  2892. #endif
  2893. if (!::GetThreadSelectorEntry(OS_HANDLE(Thread), Selector,
  2894. (LPLDT_ENTRY)Buffer))
  2895. {
  2896. return WIN32_LAST_STATUS();
  2897. }
  2898. return S_OK;
  2899. }
  2900. STDMETHODIMP
  2901. LiveUserDebugServices::GetCurrentTimeDateN(
  2902. THIS_
  2903. OUT PULONG64 TimeDate
  2904. )
  2905. {
  2906. // On NT only: *TimeDate = USER_SHARED_DATA->SystemTime;
  2907. *TimeDate = TimeDateStampToFileTime((ULONG)time(NULL));
  2908. return S_OK;
  2909. }
  2910. STDMETHODIMP
  2911. LiveUserDebugServices::GetCurrentSystemUpTimeN(
  2912. THIS_
  2913. OUT PULONG64 UpTime
  2914. )
  2915. {
  2916. // On NT only: *UpTime = USER_SHARED_DATA->InterruptTime;
  2917. *UpTime = TimeToFileTime(GetTickCount() / 1000);
  2918. return S_OK;
  2919. }
  2920. STDMETHODIMP
  2921. LiveUserDebugServices::GetProcessUpTimeN(
  2922. THIS_
  2923. IN ULONG64 Process,
  2924. OUT PULONG64 UpTime
  2925. )
  2926. {
  2927. if (m_PlatformId == VER_PLATFORM_WIN32_NT)
  2928. {
  2929. NTSTATUS NtStatus;
  2930. KERNEL_USER_TIMES KernelUserTimes;
  2931. NtStatus = g_NtDllCalls.
  2932. NtQueryInformationProcess(OS_HANDLE(Process),
  2933. ProcessTimes,
  2934. &KernelUserTimes,
  2935. sizeof(KernelUserTimes),
  2936. NULL);
  2937. if (NT_SUCCESS(NtStatus))
  2938. {
  2939. ULONG64 SystemUpTime;
  2940. GetCurrentTimeDateN(&SystemUpTime);
  2941. *UpTime = SystemUpTime - KernelUserTimes.CreateTime.QuadPart;
  2942. }
  2943. return CONV_NT_STATUS(NtStatus);
  2944. }
  2945. else
  2946. {
  2947. return E_NOTIMPL;
  2948. }
  2949. }
  2950. STDMETHODIMP
  2951. LiveUserDebugServices::RequestBreakIn(
  2952. THIS_
  2953. IN ULONG64 Process
  2954. )
  2955. {
  2956. if (g_Kernel32Calls.DebugBreakProcess != NULL)
  2957. {
  2958. if (!g_Kernel32Calls.DebugBreakProcess(OS_HANDLE(Process)))
  2959. {
  2960. return WIN32_LAST_STATUS();
  2961. }
  2962. }
  2963. else if (g_NtDllCalls.DbgUiIssueRemoteBreakin != NULL)
  2964. {
  2965. NTSTATUS Status;
  2966. Status = g_NtDllCalls.DbgUiIssueRemoteBreakin(OS_HANDLE(Process));
  2967. return CONV_NT_STATUS(Status);
  2968. }
  2969. else
  2970. {
  2971. HANDLE Thread;
  2972. DWORD ThreadId;
  2973. LPTHREAD_START_ROUTINE BreakFn;
  2974. #if defined(_WIN64)
  2975. BreakFn = (LPTHREAD_START_ROUTINE)g_NtDllCalls.DbgBreakPoint;
  2976. #else
  2977. BreakFn = (LPTHREAD_START_ROUTINE)g_Kernel32Calls.DebugBreak;
  2978. #endif
  2979. Thread =
  2980. ::CreateRemoteThread(OS_HANDLE(Process), NULL, 0, BreakFn,
  2981. NULL, 0, &ThreadId);
  2982. if (Thread != NULL)
  2983. {
  2984. ::CloseHandle(Thread);
  2985. }
  2986. else
  2987. {
  2988. return WIN32_LAST_STATUS();
  2989. }
  2990. }
  2991. return S_OK;
  2992. }
  2993. STDMETHODIMP
  2994. LiveUserDebugServices::WaitForEvent(
  2995. THIS_
  2996. IN ULONG Timeout,
  2997. OUT PVOID Buffer,
  2998. IN ULONG BufferSize,
  2999. OUT OPTIONAL PULONG BufferUsed
  3000. )
  3001. {
  3002. if (BufferSize < sizeof(DEBUG_EVENT))
  3003. {
  3004. return E_INVALIDARG;
  3005. }
  3006. if (BufferUsed != NULL)
  3007. {
  3008. *BufferUsed = sizeof(DEBUG_EVENT);
  3009. }
  3010. LPDEBUG_EVENT Event = (LPDEBUG_EVENT)Buffer;
  3011. HRESULT Status = E_NOTIMPL;
  3012. if (m_DebugObject == NULL)
  3013. {
  3014. #ifndef NT_NATIVE
  3015. if (!::WaitForDebugEvent(Event, Timeout))
  3016. {
  3017. if (GetLastError() == ERROR_SEM_TIMEOUT)
  3018. {
  3019. Status = S_FALSE;
  3020. }
  3021. else
  3022. {
  3023. Status = WIN32_LAST_STATUS();
  3024. }
  3025. }
  3026. else
  3027. {
  3028. Status = S_OK;
  3029. }
  3030. #endif
  3031. }
  3032. else if (g_NtDllCalls.NtWaitForDebugEvent != NULL &&
  3033. g_NtDllCalls.DbgUiConvertStateChangeStructure != NULL)
  3034. {
  3035. NTSTATUS NtStatus;
  3036. LARGE_INTEGER NtTimeout;
  3037. DBGUI_WAIT_STATE_CHANGE StateChange;
  3038. Win32ToNtTimeout(Timeout, &NtTimeout);
  3039. NtStatus = g_NtDllCalls.NtWaitForDebugEvent(m_DebugObject, FALSE,
  3040. &NtTimeout, &StateChange);
  3041. if (NtStatus == STATUS_TIMEOUT)
  3042. {
  3043. Status = S_FALSE;
  3044. }
  3045. else if (!NT_SUCCESS(NtStatus))
  3046. {
  3047. Status = HRESULT_FROM_NT(NtStatus);
  3048. }
  3049. else
  3050. {
  3051. NtStatus = g_NtDllCalls.
  3052. DbgUiConvertStateChangeStructure(&StateChange, Event);
  3053. // If the conversion fails we'll lose an event, but
  3054. // there's nothing else that can be done. Conversion
  3055. // failures will only occur in out-of-resource situations
  3056. // so normal debugging will not be affected.
  3057. Status = CONV_NT_STATUS(NtStatus);
  3058. }
  3059. }
  3060. if (Status != S_OK)
  3061. {
  3062. return Status;
  3063. }
  3064. m_EventProcessId = Event->dwProcessId;
  3065. m_EventThreadId = Event->dwThreadId;
  3066. #ifdef DBG_WAITFOREVENT
  3067. g_NtDllCalls.DbgPrint("Event %d for %X.%X\n",
  3068. Event->dwDebugEventCode, Event->dwProcessId,
  3069. Event->dwThreadId);
  3070. #endif
  3071. // If this is responding to a remote request then
  3072. // we can't return file handles.
  3073. if (m_Remote)
  3074. {
  3075. switch(Event->dwDebugEventCode)
  3076. {
  3077. case CREATE_PROCESS_DEBUG_EVENT:
  3078. ::CloseHandle(Event->u.CreateProcessInfo.hFile);
  3079. Event->u.CreateProcessInfo.hFile = NULL;
  3080. break;
  3081. case LOAD_DLL_DEBUG_EVENT:
  3082. ::CloseHandle(Event->u.LoadDll.hFile);
  3083. Event->u.LoadDll.hFile = NULL;
  3084. break;
  3085. }
  3086. }
  3087. return S_OK;
  3088. }
  3089. STDMETHODIMP
  3090. LiveUserDebugServices::ContinueEvent(
  3091. THIS_
  3092. IN ULONG ContinueStatus
  3093. )
  3094. {
  3095. #ifdef DBG_WAITFOREVENT
  3096. g_NtDllCalls.DbgPrint("Continue event for %X.%X\n",
  3097. m_EventProcessId, m_EventThreadId);
  3098. #endif
  3099. if (m_EventProcessId == 0)
  3100. {
  3101. return E_UNEXPECTED;
  3102. }
  3103. if (m_DebugObject != NULL && g_NtDllCalls.NtDebugContinue != NULL)
  3104. {
  3105. NTSTATUS NtStatus;
  3106. CLIENT_ID ClientId;
  3107. ClientId.UniqueProcess = UlongToHandle(m_EventProcessId);
  3108. ClientId.UniqueThread = UlongToHandle(m_EventThreadId);
  3109. NtStatus = g_NtDllCalls.NtDebugContinue(m_DebugObject, &ClientId,
  3110. ContinueStatus);
  3111. if (!NT_SUCCESS(NtStatus))
  3112. {
  3113. return HRESULT_FROM_NT(NtStatus);
  3114. }
  3115. }
  3116. #ifndef NT_NATIVE
  3117. else if (!::ContinueDebugEvent(m_EventProcessId, m_EventThreadId,
  3118. ContinueStatus))
  3119. {
  3120. return WIN32_LAST_STATUS();
  3121. }
  3122. #else
  3123. else
  3124. {
  3125. return E_UNEXPECTED;
  3126. }
  3127. #endif
  3128. m_EventProcessId = 0;
  3129. return S_OK;
  3130. }
  3131. STDMETHODIMP
  3132. LiveUserDebugServices::InsertCodeBreakpoint(
  3133. THIS_
  3134. IN ULONG64 Process,
  3135. IN ULONG64 Offset,
  3136. IN ULONG MachineType,
  3137. OUT PVOID Storage,
  3138. IN ULONG StorageSize
  3139. )
  3140. {
  3141. // Generic breakpoint support is used so this method
  3142. // does not do anything.
  3143. return E_UNEXPECTED;
  3144. }
  3145. STDMETHODIMP
  3146. LiveUserDebugServices::RemoveCodeBreakpoint(
  3147. THIS_
  3148. IN ULONG64 Process,
  3149. IN ULONG64 Offset,
  3150. IN ULONG MachineType,
  3151. IN PVOID Storage,
  3152. IN ULONG StorageSize
  3153. )
  3154. {
  3155. // Generic breakpoint support is used so this method
  3156. // does not do anything.
  3157. return E_UNEXPECTED;
  3158. }
  3159. STDMETHODIMP
  3160. LiveUserDebugServices::GetFunctionTableListHead(
  3161. THIS_
  3162. IN ULONG64 Process,
  3163. OUT PULONG64 Offset
  3164. )
  3165. {
  3166. if (!g_NtDllCalls.RtlGetFunctionTableListHead)
  3167. {
  3168. *Offset = 0;
  3169. return E_NOINTERFACE;
  3170. }
  3171. else
  3172. {
  3173. *Offset = (ULONG64)(ULONG_PTR)
  3174. g_NtDllCalls.RtlGetFunctionTableListHead();
  3175. return S_OK;
  3176. }
  3177. }
  3178. STDMETHODIMP
  3179. LiveUserDebugServices::GetOutOfProcessFunctionTable(
  3180. THIS_
  3181. IN ULONG64 Process,
  3182. IN PSTR Dll,
  3183. IN ULONG64 Table,
  3184. IN OPTIONAL PVOID Buffer,
  3185. IN ULONG BufferSize,
  3186. OUT OPTIONAL PULONG TableSize
  3187. )
  3188. {
  3189. #if !defined(NT_NATIVE) && defined(OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME)
  3190. HRESULT Status;
  3191. NTSTATUS NtStatus;
  3192. HMODULE DllHandle;
  3193. POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK Callback;
  3194. ULONG Entries;
  3195. PRUNTIME_FUNCTION Functions;
  3196. if ((DllHandle = LoadLibrary(Dll)) == NULL)
  3197. {
  3198. return WIN32_LAST_STATUS();
  3199. }
  3200. Callback = (POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)GetProcAddress
  3201. (DllHandle, OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME);
  3202. if (!Callback)
  3203. {
  3204. Status = WIN32_LAST_STATUS();
  3205. goto Exit;
  3206. }
  3207. NtStatus = Callback(OS_HANDLE(Process), (PVOID)(ULONG_PTR)Table,
  3208. &Entries, &Functions);
  3209. if (!NT_SUCCESS(NtStatus))
  3210. {
  3211. Status = HRESULT_FROM_NT(NtStatus);
  3212. goto Exit;
  3213. }
  3214. if (Functions == NULL)
  3215. {
  3216. Status = E_NOINTERFACE;
  3217. goto Exit;
  3218. }
  3219. Status = FillDataBuffer(Functions, Entries * sizeof(RUNTIME_FUNCTION),
  3220. Buffer, BufferSize, TableSize);
  3221. // RtlProcessHeap turns into a TEB reference so it doesn't
  3222. // need to (and can't) be a dynamic reference.
  3223. g_NtDllCalls.RtlFreeHeap(RtlProcessHeap(), 0, Functions);
  3224. Exit:
  3225. FreeLibrary(DllHandle);
  3226. return Status;
  3227. #else
  3228. return E_UNEXPECTED;
  3229. #endif
  3230. }
  3231. //----------------------------------------------------------------------------
  3232. //
  3233. // Generated RPC proxies and stubs.
  3234. //
  3235. //----------------------------------------------------------------------------
  3236. // Generated headers.
  3237. #include "dbgsvc_p.hpp"
  3238. #include "dbgsvc_s.hpp"
  3239. #include "dbgsvc_p.cpp"
  3240. #include "dbgsvc_s.cpp"