Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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