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.

863 lines
24 KiB

  1. /*++
  2. Copyright (c) 1995-1998 Microsoft Corporation
  3. Module Name:
  4. suspend.c
  5. Abstract:
  6. This module implements CpuSuspendThread, CpuGetContext and CpuSetContext.
  7. Author:
  8. 16-Dec-1999 SamerA
  9. Revision History:
  10. --*/
  11. #define _WOW64CPUAPI_
  12. #ifdef _X86_
  13. #include "ia6432.h"
  14. #else
  15. #define _NTDDK_
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <ntos.h>
  20. #include "wow64.h"
  21. #include "wow64cpu.h"
  22. #include "ia64cpu.h"
  23. #endif
  24. #include <stdio.h>
  25. #include <stdarg.h>
  26. //
  27. // This is to prevent this library from linking to wow64 to use wow64!Wow64LogPrint
  28. //
  29. #if defined(LOGPRINT)
  30. #undef LOGPRINT
  31. #endif
  32. #define LOGPRINT(_x_) CpupDebugPrint _x_
  33. ASSERTNAME;
  34. #define DECLARE_CPU \
  35. PCPUCONTEXT cpu = (PCPUCONTEXT)Wow64TlsGetValue(WOW64_TLS_CPURESERVED)
  36. ULONG_PTR ia32ShowContext = 0;
  37. VOID
  38. CpupDebugPrint(
  39. IN ULONG_PTR Flags,
  40. IN PCHAR Format,
  41. ...)
  42. {
  43. va_list ArgList;
  44. int BytesWritten;
  45. CHAR Buffer[ 512 ];
  46. if ((ia32ShowContext & Flags) || (Flags == ERRORLOG))
  47. {
  48. va_start(ArgList, Format);
  49. BytesWritten = _vsnprintf(Buffer,
  50. sizeof(Buffer) - 1,
  51. Format,
  52. ArgList);
  53. if (BytesWritten > 0)
  54. {
  55. DbgPrint(Buffer);
  56. }
  57. va_end(ArgList);
  58. }
  59. return;
  60. }
  61. VOID
  62. CpupPrintContext(
  63. IN PCHAR str,
  64. IN PCPUCONTEXT cpu
  65. )
  66. /*++
  67. Routine Description:
  68. Print out the ia32 context based on the passed in cpu context
  69. Arguments:
  70. str - String to print out as a header
  71. cpu - Pointer to the per-thread wow64 ia32 context.
  72. Return Value:
  73. none
  74. --*/
  75. {
  76. DbgPrint(str);
  77. DbgPrint("Context addr(0x%p): EIP=0x%08x\n", &(cpu->Context), cpu->Context.Eip);
  78. DbgPrint("Context EAX=0x%08x, EBX=0x%08x, ECX=0x%08x, EDX=0x%08x\n",
  79. cpu->Context.Eax,
  80. cpu->Context.Ebx,
  81. cpu->Context.Ecx,
  82. cpu->Context.Edx);
  83. DbgPrint("Context ESP=0x%08x, EBP=0x%08x, ESI=0x%08x, EDI=0x%08x\n",
  84. cpu->Context.Esp,
  85. cpu->Context.Ebp,
  86. cpu->Context.Esi,
  87. cpu->Context.Edi);
  88. try {
  89. //
  90. // The stack may not yet be fully formed, so don't
  91. // let a missing stack cause the process to abort
  92. //
  93. DbgPrint("Context stack=0x%08x 0x%08x 0x%08x 0x%08x\n",
  94. *((PULONG) cpu->Context.Esp),
  95. *(((PULONG) cpu->Context.Esp) + 1),
  96. *(((PULONG) cpu->Context.Esp) + 2),
  97. *(((PULONG) cpu->Context.Esp) + 3));
  98. }
  99. except ((GetExceptionCode() == STATUS_ACCESS_VIOLATION)?1:0) {
  100. //
  101. // Got an access violation, so don't print any of the stack
  102. //
  103. DbgPrint("Context stack: Can't get stack contents\n");
  104. }
  105. DbgPrint("Context EFLAGS=0x%08x\n", cpu->Context.EFlags);
  106. }
  107. WOW64CPUAPI
  108. NTSTATUS
  109. CpuSuspendThread(
  110. IN HANDLE ThreadHandle,
  111. IN HANDLE ProcessHandle,
  112. IN PTEB Teb,
  113. OUT PULONG PreviousSuspendCount OPTIONAL)
  114. /*++
  115. Routine Description:
  116. This routine is entered while the target thread is actually suspended, however, it's
  117. not known if the target thread is in a consistent state relative to
  118. the CPU.
  119. Arguments:
  120. ThreadHandle - Handle of target thread to suspend
  121. ProcessHandle - Handle of target thread's process
  122. Teb - Address of the target thread's TEB
  123. PreviousSuspendCount - Previous suspend count
  124. Return Value:
  125. NTSTATUS.
  126. --*/
  127. {
  128. return STATUS_SUCCESS;
  129. }
  130. NTSTATUS CpupReadBuffer(
  131. IN HANDLE ProcessHandle,
  132. IN PVOID Source,
  133. OUT PVOID Destination,
  134. IN ULONG Size)
  135. /*++
  136. Routine Description:
  137. This routine setup the arguments for the remoted SuspendThread call.
  138. Arguments:
  139. ProcessHandle - Target process handle to read data from
  140. Source - Target base address to read data from
  141. Destination - Address of buffer to receive data read from the specified address space
  142. Size - Size of data to read
  143. Return Value:
  144. NTSTATUS.
  145. --*/
  146. {
  147. return NtReadVirtualMemory(ProcessHandle,
  148. Source,
  149. Destination,
  150. Size,
  151. NULL);
  152. }
  153. NTSTATUS
  154. CpupWriteBuffer(
  155. IN HANDLE ProcessHandle,
  156. IN PVOID Target,
  157. IN PVOID Source,
  158. IN ULONG Size)
  159. /*++
  160. Routine Description:
  161. Writes data to memory taken into consideration if the write is cross-process
  162. or not
  163. Arguments:
  164. ProcessHandle - Target process handle to write data into
  165. Target - Target base address to write data at
  166. Source - Address of contents to write in the specified address space
  167. Size - Size of data to write
  168. Return Value:
  169. NTSTATUS.
  170. --*/
  171. {
  172. return NtWriteVirtualMemory(ProcessHandle,
  173. Target,
  174. Source,
  175. Size,
  176. NULL);
  177. }
  178. NTSTATUS
  179. GetContextRecord(
  180. IN PCPUCONTEXT cpu,
  181. IN OUT PCONTEXT32 Context
  182. )
  183. /*++
  184. Routine Description:
  185. Retrevies the context record of the specified CPU
  186. Arguments:
  187. cpu - CPU to retreive the context record for.
  188. Context - IN/OUT pointer to CONTEXT32 to fill in. Context->ContextFlags
  189. should be used to determine how much of the context to copy.
  190. Return Value:
  191. None.
  192. --*/
  193. {
  194. NTSTATUS NtStatus = STATUS_SUCCESS;
  195. ULONG ContextFlags;
  196. try
  197. {
  198. ContextFlags = Context->ContextFlags;
  199. if (ContextFlags & CONTEXT_IA64)
  200. {
  201. LOGPRINT((ERRORLOG, "CpuGetContext: Request for ia64 context (0x%x) being FAILED\n", ContextFlags));
  202. ASSERT((ContextFlags & CONTEXT_IA64) == 0);
  203. }
  204. if ((ContextFlags & CONTEXT32_CONTROL) == CONTEXT32_CONTROL)
  205. {
  206. //
  207. // i386 control registers are:
  208. // ebp, eip, cs, eflag, esp and ss
  209. //
  210. Context->Ebp = cpu->Context.Ebp;
  211. Context->Eip = cpu->Context.Eip;
  212. Context->SegCs = KGDT_R3_CODE|3; // Force reality
  213. Context->EFlags = SANITIZE_X86EFLAGS(cpu->Context.EFlags);
  214. Context->Esp = cpu->Context.Esp;
  215. Context->SegSs = KGDT_R3_DATA|3; // Force reality
  216. }
  217. if ((ContextFlags & CONTEXT32_INTEGER) == CONTEXT32_INTEGER)
  218. {
  219. //
  220. // i386 integer registers are:
  221. // edi, esi, ebx, edx, ecx, eax
  222. //
  223. Context->Edi = cpu->Context.Edi;
  224. Context->Esi = cpu->Context.Esi;
  225. Context->Ebx = cpu->Context.Ebx;
  226. Context->Edx = cpu->Context.Edx;
  227. Context->Ecx = cpu->Context.Ecx;
  228. Context->Eax = cpu->Context.Eax;
  229. }
  230. if ((ContextFlags & CONTEXT32_SEGMENTS) == CONTEXT32_SEGMENTS)
  231. {
  232. //
  233. // i386 segment registers are:
  234. // ds, es, fs, gs
  235. // And since they are a constant, force them to be the right values
  236. //
  237. Context->SegDs = KGDT_R3_CODE|3;
  238. Context->SegEs = KGDT_R3_CODE|3;
  239. Context->SegFs = KGDT_R3_TEB|3;
  240. Context->SegGs = KGDT_R3_CODE|3;
  241. }
  242. if ((ContextFlags & CONTEXT32_EXTENDED_REGISTERS) == CONTEXT32_EXTENDED_REGISTERS)
  243. {
  244. LOGPRINT((TRACELOG, "CpuGetContext: Request to get Katmai registers(0x%x)\n", ContextFlags));
  245. RtlCopyMemory(&(Context->ExtendedRegisters[0]),
  246. &(cpu->Context.ExtendedRegisters[0]),
  247. MAXIMUM_SUPPORTED_EXTENSION);
  248. }
  249. if ((ContextFlags & CONTEXT32_FLOATING_POINT) == CONTEXT32_FLOATING_POINT)
  250. {
  251. //
  252. // For the ISA transition routine, these floats need to be
  253. // in the ExtendedRegister area. So grab the values requested
  254. // from that area
  255. //
  256. PFXSAVE_FORMAT_WX86 xmmi = (PFXSAVE_FORMAT_WX86) &(cpu->Context.ExtendedRegisters[0]);
  257. LOGPRINT((TRACELOG, "CpuGetContext: Request to get float registers(0x%x)\n", ContextFlags));
  258. //
  259. // Start by grabbing the status/control portion
  260. //
  261. Context->FloatSave.ControlWord = xmmi->ControlWord;
  262. Context->FloatSave.StatusWord = xmmi->StatusWord;
  263. Context->FloatSave.TagWord = xmmi->TagWord;
  264. Context->FloatSave.ErrorOffset = xmmi->ErrorOffset;
  265. Context->FloatSave.ErrorSelector = xmmi->ErrorSelector;
  266. Context->FloatSave.DataOffset = xmmi->DataOffset;
  267. Context->FloatSave.DataSelector = xmmi->DataSelector;
  268. //
  269. // Now get the packed 10-byte fp data registers
  270. //
  271. Wow64CopyFpFromIa64Byte16(&(xmmi->RegisterArea[0]),
  272. &(Context->FloatSave.RegisterArea[0]),
  273. NUMBER_OF_387REGS);
  274. //
  275. // For performance reasons, the PCPU context leaves the
  276. // fp registers un-rotated. So we need to rotate them now
  277. // to make it follow the proper FSAVE fotmat
  278. //
  279. Wow64RotateFpTop(xmmi->StatusWord, (PFLOAT128) &(Context->FloatSave.RegisterArea[0]));
  280. }
  281. if ((ContextFlags & CONTEXT32_DEBUG_REGISTERS) == CONTEXT32_DEBUG_REGISTERS)
  282. {
  283. LOGPRINT((TRACELOG, "CpuGetContext: Request to get debug registers(0x%x)\n", ContextFlags));
  284. Context->Dr0 = cpu->Context.Dr0;
  285. Context->Dr1 = cpu->Context.Dr1;
  286. Context->Dr2 = cpu->Context.Dr2;
  287. Context->Dr3 = cpu->Context.Dr3;
  288. Context->Dr6 = cpu->Context.Dr6;
  289. Context->Dr7 = cpu->Context.Dr7;
  290. }
  291. }
  292. except(EXCEPTION_EXECUTE_HANDLER)
  293. {
  294. NtStatus = GetExceptionCode();
  295. }
  296. if (ia32ShowContext & LOG_CONTEXT_GETSET)
  297. {
  298. CpupPrintContext("Getting ia32 context: ", cpu);
  299. }
  300. return NtStatus;
  301. }
  302. NTSTATUS
  303. CpupGetContext(
  304. IN OUT PCONTEXT32 Context
  305. )
  306. /*++
  307. Routine Description:
  308. This routine extracts the context record for the currently executing thread.
  309. Arguments:
  310. Context - Context record to fill
  311. Return Value:
  312. NTSTATUS.
  313. --*/
  314. {
  315. DECLARE_CPU;
  316. return GetContextRecord(cpu, Context);
  317. }
  318. NTSTATUS
  319. CpupGetContextThread(
  320. IN HANDLE ThreadHandle,
  321. IN HANDLE ProcessHandle,
  322. IN PTEB Teb,
  323. IN OUT PCONTEXT32 Context)
  324. /*++
  325. Routine Description:
  326. This routine extract the context record of any thread. This is a generic routine.
  327. When entered, if the target thread isn't the current thread, then it should be
  328. guaranteed that the target thread is suspended at a proper CPU state.
  329. Arguments:
  330. ThreadHandle - Target thread handle to retreive the context for
  331. ProcessHandle - Open handle to the process that the thread runs in
  332. Teb - Pointer to the target's thread TEB
  333. Context - Context record to fill
  334. Return Value:
  335. NTSTATUS.
  336. --*/
  337. {
  338. NTSTATUS NtStatus = STATUS_SUCCESS;
  339. CONTEXT ContextEM;
  340. PCPUCONTEXT CpuRemoteContext;
  341. CPUCONTEXT CpuContext;
  342. ContextEM.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG;
  343. NtStatus = NtGetContextThread(ThreadHandle,
  344. &ContextEM);
  345. if (!NT_SUCCESS(NtStatus))
  346. {
  347. LOGPRINT((ERRORLOG, "CpupGetContextThread: NtGetContextThread (%lx) failed - %lx\n",
  348. ThreadHandle, NtStatus));
  349. return NtStatus;
  350. }
  351. if (ContextEM.StIPSR & (1i64 << PSR_IS))
  352. {
  353. Wow64CtxFromIa64(Context->ContextFlags, &ContextEM, Context);
  354. LOGPRINT((TRACELOG, "Getting context while thread is executing 32-bit instructions - %lx\n", NtStatus));
  355. }
  356. else
  357. {
  358. LOGPRINT((TRACELOG, "Getting context while thread is executing 64-bit instructions\n"));
  359. NtStatus = CpupReadBuffer(ProcessHandle,
  360. ((PCHAR)Teb + FIELD_OFFSET(TEB, TlsSlots[WOW64_TLS_CPURESERVED])),
  361. &CpuRemoteContext,
  362. sizeof(CpuRemoteContext));
  363. if (NT_SUCCESS(NtStatus))
  364. {
  365. NtStatus = CpupReadBuffer(ProcessHandle,
  366. CpuRemoteContext,
  367. &CpuContext,
  368. sizeof(CpuContext));
  369. if (NT_SUCCESS(NtStatus))
  370. {
  371. NtStatus = GetContextRecord(&CpuContext, Context);
  372. }
  373. else
  374. {
  375. LOGPRINT((ERRORLOG, "CpupGetContextThread: Couldn't read CPU context %lx - %lx\n",
  376. CpuRemoteContext, NtStatus));
  377. }
  378. }
  379. else
  380. {
  381. LOGPRINT((ERRORLOG, "CpupGetContextThread: Couldn't read CPU context address - %lx\n",
  382. NtStatus));
  383. }
  384. }
  385. return NtStatus;
  386. }
  387. WOW64CPUAPI
  388. NTSTATUS
  389. CpuGetContext(
  390. IN HANDLE ThreadHandle,
  391. IN HANDLE ProcessHandle,
  392. IN PTEB Teb,
  393. OUT PCONTEXT32 Context)
  394. /*++
  395. Routine Description:
  396. Extracts the cpu context of the specified thread.
  397. When entered, it is guaranteed that the target thread is suspended at
  398. a proper CPU state.
  399. Arguments:
  400. ThreadHandle - Target thread handle to retreive the context for
  401. ProcessHandle - Open handle to the process that the thread runs in
  402. Teb - Pointer to the target's thread TEB
  403. Context - Context record to fill
  404. Return Value:
  405. NTSTATUS.
  406. --*/
  407. {
  408. if (NtCurrentThread() == ThreadHandle)
  409. {
  410. return CpupGetContext(Context);
  411. }
  412. return CpupGetContextThread(ThreadHandle,
  413. ProcessHandle,
  414. Teb,
  415. Context);
  416. }
  417. NTSTATUS
  418. SetContextRecord(
  419. IN PCPUCONTEXT cpu,
  420. IN OUT PCONTEXT32 Context
  421. )
  422. /*++
  423. Routine Description:
  424. Update the CPU's register set for the specified CPU.
  425. Arguments:
  426. cpu - CPU to update its registers
  427. Context - IN pointer to CONTEXT32 to use. Context->ContextFlags
  428. should be used to determine how much of the context to update.
  429. Return Value:
  430. None.
  431. --*/
  432. {
  433. NTSTATUS NtStatus = STATUS_SUCCESS;
  434. ULONG ContextFlags;
  435. try
  436. {
  437. ContextFlags = Context->ContextFlags;
  438. if (ContextFlags & CONTEXT_IA64)
  439. {
  440. LOGPRINT((ERRORLOG, "CpuSetContext: Request with ia64 context (0x%x) FAILED\n", ContextFlags));
  441. ASSERT((ContextFlags & CONTEXT_IA64) == 0);
  442. }
  443. if ((ContextFlags & CONTEXT32_CONTROL) == CONTEXT32_CONTROL)
  444. {
  445. //
  446. // i386 control registers are:
  447. // ebp, eip, cs, eflag, esp and ss
  448. //
  449. cpu->Context.Ebp = Context->Ebp;
  450. cpu->Context.Eip = Context->Eip;
  451. cpu->Context.SegCs = KGDT_R3_CODE|3; // Force Reality
  452. cpu->Context.EFlags = SANITIZE_X86EFLAGS(Context->EFlags);
  453. cpu->Context.Esp = Context->Esp;
  454. cpu->Context.SegSs = KGDT_R3_DATA|3; // Force Reality
  455. }
  456. if ((ContextFlags & CONTEXT32_INTEGER) == CONTEXT32_INTEGER)
  457. {
  458. //
  459. // i386 integer registers are:
  460. // edi, esi, ebx, edx, ecx, eax
  461. //
  462. cpu->Context.Edi = Context->Edi;
  463. cpu->Context.Esi = Context->Esi;
  464. cpu->Context.Ebx = Context->Ebx;
  465. cpu->Context.Edx = Context->Edx;
  466. cpu->Context.Ecx = Context->Ecx;
  467. cpu->Context.Eax = Context->Eax;
  468. }
  469. if ((ContextFlags & CONTEXT32_SEGMENTS) == CONTEXT32_SEGMENTS)
  470. {
  471. //
  472. // i386 segment registers are:
  473. // ds, es, fs, gs
  474. // And since they are a constant, force them to be the right values
  475. //
  476. cpu->Context.SegDs = KGDT_R3_DATA|3;
  477. cpu->Context.SegEs = KGDT_R3_DATA|3;
  478. cpu->Context.SegFs = KGDT_R3_TEB|3;
  479. cpu->Context.SegGs = KGDT_R3_DATA|3;
  480. }
  481. //
  482. // To follow the way ia32 does get/set context, you need to make sure
  483. // that the older FP context is saved second. That way if both
  484. // old and new context is passed in, the old takes precedence
  485. // This happens, for example, when handling an FP exception... The
  486. // exception handler says both context is available, and older programs
  487. // only clean up the older FP area...
  488. //
  489. if ((ContextFlags & CONTEXT32_EXTENDED_REGISTERS) == CONTEXT32_EXTENDED_REGISTERS)
  490. {
  491. LOGPRINT((TRACELOG, "CpuSetContext: Request to set Katmai registers(0x%x)\n", ContextFlags));
  492. RtlCopyMemory(&(cpu->Context.ExtendedRegisters[0]),
  493. &(Context->ExtendedRegisters[0]),
  494. MAXIMUM_SUPPORTED_EXTENSION);
  495. }
  496. if ((ContextFlags & CONTEXT32_FLOATING_POINT) == CONTEXT32_FLOATING_POINT)
  497. {
  498. //
  499. // For the ISA transition routine, these floats need to be
  500. // in the ExtendedRegister area. So put the values requested
  501. // into that area
  502. //
  503. PFXSAVE_FORMAT_WX86 xmmi = (PFXSAVE_FORMAT_WX86) &(cpu->Context.ExtendedRegisters[0]);
  504. LOGPRINT((TRACELOG, "CpuSetContext: Request to set float registers(0x%x)\n", ContextFlags));
  505. //
  506. // Start by grabbing the status/control portion
  507. //
  508. xmmi->ControlWord = (USHORT) (Context->FloatSave.ControlWord & 0xFFFF);
  509. xmmi->StatusWord = (USHORT) (Context->FloatSave.StatusWord & 0xFFFF);
  510. xmmi->TagWord = (USHORT) (Context->FloatSave.TagWord & 0xFFFF);
  511. xmmi->ErrorOffset = Context->FloatSave.ErrorOffset;
  512. xmmi->ErrorSelector = Context->FloatSave.ErrorSelector;
  513. xmmi->DataOffset = Context->FloatSave.DataOffset;
  514. xmmi->DataSelector = Context->FloatSave.DataSelector;
  515. //
  516. // Now get the packed 10-byte fp data registers and convert
  517. // them into the 16-byte format used by FXSAVE (and the
  518. // ISA transition routine)
  519. //
  520. Wow64CopyFpToIa64Byte16(&(Context->FloatSave.RegisterArea[0]),
  521. &(xmmi->RegisterArea[0]),
  522. NUMBER_OF_387REGS);
  523. //
  524. // For performance reasons, the PCPU context leaves the
  525. // fp registers un-rotated. So we need to rotate them back
  526. // now into the optimized format used for isa transisions
  527. //
  528. {
  529. ULONGLONG RotateFSR = (NUMBER_OF_387REGS -
  530. ((xmmi->StatusWord >> 11) & 0x7)) << 11;
  531. Wow64RotateFpTop(RotateFSR, (PFLOAT128) &(xmmi->RegisterArea[0]));
  532. }
  533. }
  534. if ((ContextFlags & CONTEXT32_DEBUG_REGISTERS) == CONTEXT32_DEBUG_REGISTERS)
  535. {
  536. LOGPRINT((TRACELOG, "CpuSetContext: Request to set debug registers(0x%x)\n", ContextFlags));
  537. cpu->Context.Dr0 = Context->Dr0;
  538. cpu->Context.Dr1 = Context->Dr1;
  539. cpu->Context.Dr2 = Context->Dr2;
  540. cpu->Context.Dr3 = Context->Dr3;
  541. cpu->Context.Dr6 = Context->Dr6;
  542. cpu->Context.Dr7 = Context->Dr7;
  543. }
  544. //
  545. // Whatever they passed in before, it's an X86 context now...
  546. //
  547. cpu->Context.ContextFlags = ContextFlags;
  548. }
  549. except(EXCEPTION_EXECUTE_HANDLER)
  550. {
  551. NtStatus = GetExceptionCode();
  552. }
  553. if (ia32ShowContext & LOG_CONTEXT_GETSET)
  554. {
  555. CpupPrintContext("Setting ia32 context: ", cpu);
  556. }
  557. return NtStatus;
  558. }
  559. NTSTATUS
  560. CpupSetContext(
  561. IN OUT PCONTEXT32 Context
  562. )
  563. /*++
  564. Routine Description:
  565. This routine sets the context record for the currently executing thread.
  566. Arguments:
  567. Context - Context record to fill
  568. Return Value:
  569. NTSTATUS.
  570. --*/
  571. {
  572. DECLARE_CPU;
  573. return SetContextRecord(cpu, Context);
  574. }
  575. NTSTATUS
  576. CpupSetContextThread(
  577. IN HANDLE ThreadHandle,
  578. IN HANDLE ProcessHandle,
  579. IN PTEB Teb,
  580. IN OUT PCONTEXT32 Context)
  581. /*++
  582. Routine Description:
  583. This routine sets the context record of any thread. This is a generic routine.
  584. When entered, if the target thread isn't the currently executing thread, then it should be
  585. guaranteed that the target thread is suspended at a proper CPU state.
  586. Arguments:
  587. ThreadHandle - Target thread handle to retreive the context for
  588. ProcessHandle - Open handle to the process that the thread runs in
  589. Teb - Pointer to the target's thread TEB
  590. Context - Context record to set
  591. Return Value:
  592. NTSTATUS.
  593. --*/
  594. {
  595. NTSTATUS NtStatus = STATUS_SUCCESS;
  596. CONTEXT ContextEM;
  597. PCPUCONTEXT CpuRemoteContext;
  598. CPUCONTEXT CpuContext;
  599. ContextEM.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG;
  600. NtStatus = NtGetContextThread(ThreadHandle,
  601. &ContextEM);
  602. if (!NT_SUCCESS(NtStatus))
  603. {
  604. LOGPRINT((ERRORLOG, "CpupGetContextThread: NtGetContextThread (%lx) failed - %lx\n",
  605. ThreadHandle, NtStatus));
  606. return NtStatus;
  607. }
  608. if (ContextEM.StIPSR & (1i64 << PSR_IS))
  609. {
  610. Wow64CtxToIa64(Context->ContextFlags, Context, &ContextEM);
  611. NtStatus = NtSetContextThread(ThreadHandle, &ContextEM);
  612. LOGPRINT((TRACELOG, "Setting context while thread is executing 32-bit instructions - %lx\n", NtStatus));
  613. }
  614. else
  615. {
  616. LOGPRINT((TRACELOG, "Setting context while thread is executing 64-bit instructions\n"));
  617. NtStatus = CpupReadBuffer(ProcessHandle,
  618. ((PCHAR)Teb + FIELD_OFFSET(TEB, TlsSlots[WOW64_TLS_CPURESERVED])),
  619. &CpuRemoteContext,
  620. sizeof(CpuRemoteContext));
  621. if (NT_SUCCESS(NtStatus))
  622. {
  623. NtStatus = CpupReadBuffer(ProcessHandle,
  624. CpuRemoteContext,
  625. &CpuContext,
  626. sizeof(CpuContext));
  627. if (NT_SUCCESS(NtStatus))
  628. {
  629. NtStatus = SetContextRecord(&CpuContext, Context);
  630. if (NT_SUCCESS(NtStatus))
  631. {
  632. NtStatus = CpupWriteBuffer(ProcessHandle,
  633. CpuRemoteContext,
  634. &CpuContext,
  635. sizeof(CpuContext));
  636. }
  637. else
  638. {
  639. LOGPRINT((ERRORLOG, "CpupSetContextThread: Couldn't read CPU context %lx - %lx\n",
  640. CpuRemoteContext, NtStatus));
  641. }
  642. }
  643. }
  644. else
  645. {
  646. LOGPRINT((ERRORLOG, "CpupSetContextThread: Couldn't read CPU context address - %lx\n",
  647. NtStatus));
  648. }
  649. }
  650. return NtStatus;
  651. }
  652. WOW64CPUAPI
  653. NTSTATUS
  654. CpuSetContext(
  655. IN HANDLE ThreadHandle,
  656. IN HANDLE ProcessHandle,
  657. IN PTEB Teb,
  658. PCONTEXT32 Context)
  659. /*++
  660. Routine Description:
  661. Sets the cpu context for the specified thread.
  662. When entered, if the target thread isn't the currently executing thread, then it is
  663. guaranteed that the target thread is suspended at a proper CPU state.
  664. Arguments:
  665. ThreadHandle - Target thread handle to retreive the context for
  666. ProcessHandle - Open handle to the process that the thread runs in
  667. Teb - Pointer to the target's thread TEB
  668. Context - Context record to set
  669. Return Value:
  670. NTSTATUS.
  671. --*/
  672. {
  673. if (NtCurrentThread() == ThreadHandle)
  674. {
  675. return CpupSetContext(Context);
  676. }
  677. return CpupSetContextThread(ThreadHandle,
  678. ProcessHandle,
  679. Teb,
  680. Context);
  681. }