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.

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