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.

4885 lines
155 KiB

  1. /*++
  2. INTEL CORPORATION PROPRIETARY INFORMATION
  3. This software is supplied under the terms of a license
  4. agreement or nondisclosure agreement with Intel Corporation
  5. and may not be copied or disclosed except in accordance with
  6. the terms of that agreement.
  7. Copyright (c) 1991-2002 INTEL CORPORATION
  8. Module Name:
  9. btlib.c
  10. Abstract:
  11. The OS dependent part of IA-32 Execution Layer for Windows.
  12. It is a Windows operating-system-specific component of the dynamic binary translator.
  13. Its responsibility is to locate and load OS-independent component
  14. (IA32Exec.bin), to forward Wow64 calls to the OS-independent part
  15. and to supply OS-dependent services to it when necessary.
  16. Part of the services in this module are not used for windows,
  17. and part of them are needed for debugging and/or performance tuning only.
  18. --*/
  19. #define _WOW64BTAPI_
  20. #ifndef NODEBUG
  21. #define OVERRIDE_TIA 1
  22. #endif
  23. #include "btlib.h"
  24. #ifndef IA32EX_G_NAME
  25. #define IA32EX_G_NAME L"IA32Exec"
  26. #endif
  27. #ifndef IA32EX_G_SUFFIX
  28. #define IA32EX_G_SUFFIX L"bin"
  29. #endif
  30. #define WOW64BT_IMPL __declspec(dllexport)
  31. extern VOID Wow64LogPrint(UCHAR LogLevel, char *format, ...);
  32. #define LF_TRACE 2
  33. #define LF_ERROR 1
  34. /*
  35. * File location enumerator
  36. */
  37. #define F_NOT_FOUND 0
  38. #define F_CURRENT_DIR 1
  39. #define F_BTLIB 2
  40. #define F_HKLM 3
  41. #define F_HKCU 4
  42. /*
  43. * Initial memory allocation addresses for code and data
  44. */
  45. #define INITIAL_CODE_ADDRESS ((void *)0x44000000)
  46. #define INITIAL_DATA_ADDRESS ((void *)0x40000000)
  47. ASSERTNAME;
  48. // Persistent variables
  49. U32 BtlpInfoOffset; // Offset of the wowIA32X.dll-specific info in Wow64Cpu TLS
  50. U32 BtlpGenericIA32ContextOffset; // Offset of the IA32 context in IA32Exec.bin's TLS
  51. PLABEL_PTR_TYPE BtlpPlaceHolderTable[NO_OF_APIS];
  52. WCHAR ImageName[128], LogDirName[128];
  53. // Interface for debug printing
  54. HANDLE BtlpWow64LogFile = INVALID_HANDLE_VALUE;
  55. DWORD BtlpLogOffset = 0;
  56. #ifndef NODEBUG
  57. WCHAR BtlpLogFileFullPath[1024];
  58. BOOL BtlpLogFilePerThread = FALSE;
  59. #endif
  60. // Temporary workaround for IA32 debugging support.
  61. //To be removed after fixing FlushIC(ProcessHandle).
  62. BOOL BeingDebugged; //copy of the PEB->BeingDebugged; can be overriden by the
  63. //debug_btrans switch
  64. //Critical section interface
  65. #define BtlpInitializeCriticalSection(pCS) RtlInitializeCriticalSection (pCS)
  66. #define BtlpDeleteCriticalSection(pCS) RtlDeleteCriticalSection (pCS)
  67. __inline void BtlpEnterCriticalSection(PRTL_CRITICAL_SECTION pCS)
  68. {
  69. BTL_THREAD_INITIALIZED() && BTLIB_DISABLE_SUSPENSION();
  70. RtlEnterCriticalSection(pCS);
  71. }
  72. __inline void BtlpLeaveCriticalSection(PRTL_CRITICAL_SECTION pCS)
  73. {
  74. RtlLeaveCriticalSection(pCS);
  75. BTL_THREAD_INITIALIZED() && BTLIB_ENABLE_SUSPENSION();
  76. }
  77. //Report failure in NT service
  78. // msg - error message text
  79. // status - error status
  80. #define BTLP_REPORT_NT_FAILURE(msg, status) \
  81. DBCODE((status != STATUS_SUCCESS), BtlpPrintf("\n%s : NT FAILURE STATUS = 0x%X\n" , msg, status))
  82. VOID BtlDebugPrint (
  83. U8 * buffer
  84. )
  85. /*++
  86. Routine Description:
  87. Debug print of the buffer.
  88. The text is printed into the debugging log file,
  89. or through Wow64 debugging facility, if the file is not available
  90. Arguments:
  91. buffer - IN Text to be printed
  92. Return Value:
  93. None.
  94. --*/
  95. {
  96. extern U64 BtAtomicInc(U64 * pCounter);
  97. extern U64 BtAtomicDec(U64 * pCounter);
  98. HANDLE hTarget = INVALID_HANDLE_VALUE;
  99. static U64 InLogging = 0; //counter of concurrent entrances to the function
  100. if (BtAtomicInc(&InLogging)) {
  101. //Some thread is printing at this moment. Exit if BTLIB_BLOCKED_LOG_DISABLED
  102. if (BTL_THREAD_INITIALIZED() && BTLIB_BLOCKED_LOG_DISABLED()) {
  103. return;
  104. }
  105. }
  106. #ifndef NODEBUG
  107. if ( BtlpLogFilePerThread ) {
  108. if (BTL_THREAD_INITIALIZED()) {
  109. hTarget = BTLIB_LOG_FILE();
  110. }
  111. }
  112. else
  113. #endif
  114. {
  115. hTarget = BtlpWow64LogFile;
  116. }
  117. if ( hTarget != INVALID_HANDLE_VALUE ) {
  118. NTSTATUS ret;
  119. IO_STATUS_BLOCK IoStatusBlock;
  120. size_t size;
  121. LARGE_INTEGER offset;
  122. //Disable suspension during blocked (synchronized) file access
  123. BTL_THREAD_INITIALIZED() && BTLIB_DISABLE_SUSPENSION();
  124. Wow64LogPrint(LF_TRACE, "%s", buffer);
  125. BTL_THREAD_INITIALIZED() && BTLIB_ENABLE_SUSPENSION();
  126. size = strlen(buffer);
  127. offset.HighPart = 0;
  128. #ifndef NODEBUG
  129. if ( BtlpLogFilePerThread ) {
  130. offset.LowPart = BTLIB_INFO_PTR()->LogOffset;
  131. BTLIB_INFO_PTR()->LogOffset += size;
  132. } else
  133. #endif
  134. {
  135. //Following two lines should be replaced with atomic operation:
  136. //offset.LowPart = InterlockedExchangeAdd(&BtlpLogOffset, size);
  137. offset.LowPart = BtlpLogOffset;
  138. BtlpLogOffset += size;
  139. }
  140. //Disable suspension during blocked (synchronized) file access
  141. BTL_THREAD_INITIALIZED() && BTLIB_DISABLE_SUSPENSION();
  142. ret = NtWriteFile(hTarget, NULL, NULL, NULL, &IoStatusBlock,
  143. (void *)buffer, (ULONG)size, &offset, NULL);
  144. BTL_THREAD_INITIALIZED() && BTLIB_ENABLE_SUSPENSION();
  145. } else {
  146. //Disable suspension during blocked (synchronized) file access
  147. BTL_THREAD_INITIALIZED() && BTLIB_DISABLE_SUSPENSION();
  148. Wow64LogPrint(LF_ERROR, "%s", buffer);
  149. BTL_THREAD_INITIALIZED() && BTLIB_ENABLE_SUSPENSION();
  150. }
  151. BtAtomicDec(&InLogging);
  152. }
  153. int BtlpPrintf (
  154. IN char * Format,
  155. ...
  156. )
  157. /*++
  158. Routine Description:
  159. Helper function for format printing.
  160. Arguments:
  161. Format - IN Format string to be printed
  162. ... - IN parameter(s) according to the format string
  163. Return Value:
  164. Just like in vsprintf.
  165. --*/
  166. {
  167. #define MAX_DEBUG_PRINT_BUF_SZ 4096
  168. extern U64 DisableFPInterrupt();
  169. extern void RestoreFPInterrupt(U64 prev_fpsr);
  170. U64 prev_fpsr;
  171. va_list ParmList;
  172. int res;
  173. char PrintBuffer[MAX_DEBUG_PRINT_BUF_SZ];
  174. prev_fpsr = DisableFPInterrupt();
  175. va_start(ParmList, Format);
  176. res = vsprintf(PrintBuffer, Format, ParmList);
  177. BtlDebugPrint (PrintBuffer);
  178. RestoreFPInterrupt(prev_fpsr);
  179. return res;
  180. }
  181. VOID __cdecl _assert (
  182. VOID *expr,
  183. VOID *file_name,
  184. unsigned line_no
  185. )
  186. /*++
  187. Routine Description:
  188. Helper assert function (in order to print assert message our way)
  189. Arguments:
  190. expr - IN failing expression string
  191. file_name - IN name of the source file
  192. line_no - IN number of the source line
  193. Return Value:
  194. None.
  195. --*/
  196. {
  197. BtlpPrintf ("wowIA32X.dll: Assertion failed %s/%d: %s\n", (const char *)file_name, line_no, (char *)expr);
  198. BTLIB_ABORT ();
  199. }
  200. VOID BtlAbort(
  201. VOID
  202. )
  203. /*++
  204. Routine Description:
  205. Abort function (in order to avoid using run-time library in WINNT)
  206. Arguments:
  207. None.
  208. Return Value:
  209. None.
  210. --*/
  211. {
  212. BtlpPrintf ("Execution aborted, TEB=%p\n", BT_CURRENT_TEB());
  213. // Cause failure
  214. ((VOID (*)()) 0) ();
  215. }
  216. VOID BtlInitializeTables(
  217. IN API_TABLE_TYPE * BTGenericTable
  218. )
  219. /*++
  220. Routine Description:
  221. Initialize placeholder table with plabels of IA32Exec.bin functions
  222. Arguments:
  223. BTGenericTable - IN pointer to IA32Exec.bin API table.
  224. Return Value:
  225. None.
  226. --*/
  227. {
  228. unsigned int i;
  229. // initialize wowIA32X.dll placeholder table
  230. for(i=0; i < BTGenericTable->NoOfAPIs; i++) {
  231. BtlPlaceHolderTable[i] = BTGenericTable->APITable[i].PLabelPtr;
  232. }
  233. }
  234. // VTUNE support
  235. HANDLE BtlpVtuneTIADmpFileHandle = INVALID_HANDLE_VALUE;
  236. LARGE_INTEGER BtlpVtuneOffset = { 0, 0 };
  237. static VOID BtlpVtuneOpenTIADmpFile (
  238. VOID
  239. )
  240. /*++
  241. Routine Description:
  242. Open file fot VTUNE analysis
  243. Arguments:
  244. None.
  245. Return Value:
  246. None.
  247. --*/
  248. {
  249. int i;
  250. UNICODE_STRING tiaFileName;
  251. LARGE_INTEGER AllocSz = { 0, 0 };
  252. OBJECT_ATTRIBUTES ObjectAttributes;
  253. NTSTATUS ret;
  254. WCHAR CurDirBuf[512];
  255. WCHAR CurrentDir[1024];
  256. IO_STATUS_BLOCK IoStatusBlock;
  257. //swprintf(CurDirBuf, L"\\DosDevices\\%s\\tia.dmp", CurrentDir);
  258. if (0==LogDirName[0] && 0==LogDirName[1]) {
  259. RtlGetCurrentDirectory_U(512, CurrentDir);
  260. swprintf(CurDirBuf, L"\\DosDevices\\%s\\%s.tia.dmp", CurrentDir, ImageName);
  261. }
  262. else {
  263. swprintf(CurDirBuf, L"\\DosDevices\\%s\\%s.tia.dmp", LogDirName, ImageName);
  264. }
  265. RtlInitUnicodeString(&tiaFileName, CurDirBuf);
  266. InitializeObjectAttributes(&ObjectAttributes, &tiaFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
  267. ret = NtCreateFile (&BtlpVtuneTIADmpFileHandle,
  268. FILE_GENERIC_WRITE,
  269. &ObjectAttributes,
  270. &IoStatusBlock,
  271. &AllocSz,
  272. FILE_ATTRIBUTE_NORMAL,
  273. 0,
  274. FILE_SUPERSEDE,
  275. FILE_NON_DIRECTORY_FILE|FILE_RANDOM_ACCESS|FILE_SYNCHRONOUS_IO_NONALERT,
  276. NULL, 0);
  277. if ( ret != STATUS_SUCCESS ) {
  278. BtlpPrintf("Save: NtCreateFile() failed: status = 0x%X\n", ret);
  279. return;
  280. }
  281. }
  282. static VOID BtlpVtuneWriteU64 (
  283. IN U64 value
  284. )
  285. /*++
  286. Routine Description:
  287. Write 64 bit unsigned value into VTUNE file
  288. Arguments:
  289. value - IN 64bit unsigned value to be send to VTUNE file.
  290. Return Value:
  291. None.
  292. --*/
  293. {
  294. char space = ' ';
  295. NTSTATUS ret;
  296. IO_STATUS_BLOCK IoStatusBlock;
  297. if (BtlpVtuneTIADmpFileHandle == INVALID_HANDLE_VALUE) {
  298. BtlpVtuneOpenTIADmpFile ();
  299. }
  300. //Disable suspension during blocked (synchronized) file access
  301. BTL_THREAD_INITIALIZED() && BTLIB_DISABLE_SUSPENSION();
  302. ret = NtWriteFile ( BtlpVtuneTIADmpFileHandle,
  303. NULL,
  304. NULL,
  305. NULL,
  306. &IoStatusBlock,
  307. (VOID *) &value,
  308. sizeof(U64),
  309. &BtlpVtuneOffset,
  310. NULL);
  311. BTL_THREAD_INITIALIZED() && BTLIB_ENABLE_SUSPENSION();
  312. if ( ret != STATUS_SUCCESS ) {
  313. BtlpPrintf("-1. NtWriteFile() failed: status = 0x%X\n", ret);
  314. }
  315. BtlpVtuneOffset.LowPart += sizeof(U64);
  316. //Disable suspension during blocked (synchronized) file access
  317. BTL_THREAD_INITIALIZED() && BTLIB_DISABLE_SUSPENSION();
  318. ret = NtWriteFile ( BtlpVtuneTIADmpFileHandle,
  319. NULL,
  320. NULL,
  321. NULL,
  322. &IoStatusBlock,
  323. (VOID *) &space,
  324. sizeof(space),
  325. &BtlpVtuneOffset,
  326. NULL);
  327. BTL_THREAD_INITIALIZED() && BTLIB_ENABLE_SUSPENSION();
  328. if ( ret != STATUS_SUCCESS ) {
  329. BtlpPrintf("-1. NtWriteFile() failed: status = 0x%X\n", ret);
  330. }
  331. BtlpVtuneOffset.LowPart += sizeof(char);
  332. }
  333. static VOID BtlpVtuneWriteU32 (
  334. IN U32 value
  335. )
  336. /*++
  337. Routine Description:
  338. Write 64 bit unsigned value into VTUNE file
  339. Arguments:
  340. value - IN 32bit unsigned value to be send to VTUNE file.
  341. Return Value:
  342. None.
  343. --*/
  344. {
  345. U64 valueToWrite;
  346. char space = ' ';
  347. NTSTATUS ret;
  348. IO_STATUS_BLOCK IoStatusBlock;
  349. if (BtlpVtuneTIADmpFileHandle == INVALID_HANDLE_VALUE) {
  350. BtlpVtuneOpenTIADmpFile ();
  351. }
  352. valueToWrite = value;
  353. //Disable suspension during blocked (synchronized) file access
  354. BTL_THREAD_INITIALIZED() && BTLIB_DISABLE_SUSPENSION();
  355. ret = NtWriteFile ( BtlpVtuneTIADmpFileHandle,
  356. NULL,
  357. NULL,
  358. NULL,
  359. &IoStatusBlock,
  360. (VOID *) &valueToWrite,
  361. sizeof(U64),
  362. &BtlpVtuneOffset,
  363. NULL);
  364. BTL_THREAD_INITIALIZED() && BTLIB_ENABLE_SUSPENSION();
  365. if ( ret != STATUS_SUCCESS ) {
  366. BtlpPrintf("-1. NtWriteFile() failed: status = 0x%X\n", ret);
  367. }
  368. BtlpVtuneOffset.LowPart += sizeof(U64);
  369. //Disable suspension during blocked (synchronized) file access
  370. BTL_THREAD_INITIALIZED() && BTLIB_DISABLE_SUSPENSION();
  371. ret = NtWriteFile ( BtlpVtuneTIADmpFileHandle,
  372. NULL,
  373. NULL,
  374. NULL,
  375. &IoStatusBlock,
  376. (VOID *) &space,
  377. sizeof(space),
  378. &BtlpVtuneOffset,
  379. NULL);
  380. BTL_THREAD_INITIALIZED() && BTLIB_ENABLE_SUSPENSION();
  381. if ( ret != STATUS_SUCCESS ) {
  382. BtlpPrintf("-1. NtWriteFile() failed: status = 0x%X\n", ret);
  383. }
  384. BtlpVtuneOffset.LowPart += sizeof(char);
  385. }
  386. VOID BtlVtuneCodeToTIADmpFile (
  387. IN U64 * emCode,
  388. IN U64 emSize
  389. )
  390. /*++
  391. Routine Description:
  392. Report translated code block to VTUNE file
  393. Arguments:
  394. emCode - IN code start pointer
  395. emSize - IN code size in bytes
  396. Return Value:
  397. None.
  398. --*/
  399. {
  400. #if 0
  401. U64 bundle;
  402. assert ((emSize % (2*sizeof (U64))) == 0);
  403. emSize /= (2*sizeof (U64));
  404. BtlpVtuneWriteU64 (emSize);
  405. for (; emSize; --emSize) {
  406. bundle = *emCode++;
  407. BtlpVtuneWriteU64 (bundle);
  408. bundle = *emCode++;
  409. BtlpVtuneWriteU64 (bundle);
  410. }
  411. #endif
  412. }
  413. VOID BtlVtuneEnteringDynamicCode(
  414. VOID
  415. )
  416. /*++
  417. Routine Description:
  418. Notify VTUNE about entering dynamically generated code (no action for NT)
  419. Arguments:
  420. None.
  421. Return Value:
  422. None.
  423. --*/
  424. {
  425. }
  426. VOID BtlVtuneExitingDynamicCode(
  427. VOID
  428. )
  429. /*++
  430. Routine Description:
  431. Notify VTUNE about leaving dynamically generated code (no action for NT)
  432. Arguments:
  433. None.
  434. Return Value:
  435. None.
  436. --*/
  437. {
  438. }
  439. VOID BtlVtuneCodeDeleted(
  440. IN U64 blockStart
  441. )
  442. /*++
  443. Routine Description:
  444. Notify VTUNE about removal of dynamically generated code (no action for NT)
  445. Arguments:
  446. blockStart - IN start of the block.
  447. Return Value:
  448. None.
  449. --*/
  450. {
  451. }
  452. VOID BtlVtuneCodeCreated(
  453. IN VTUNE_BLOCK_TYPE *block
  454. )
  455. /*++
  456. Routine Description:
  457. Notify VTUNE about generation of a code block
  458. Arguments:
  459. block - IN VTUNE block descriptor.
  460. Return Value:
  461. None.
  462. --*/
  463. {
  464. // keep this order of fields, it's expected on the reader side to be in that order
  465. BtlpVtuneWriteU32(VTUNE_CALL_ID_CREATED);
  466. BtlpVtuneWriteU64(block->name);
  467. BtlpVtuneWriteU32(block->type);
  468. BtlpVtuneWriteU64(block->start);
  469. BtlpVtuneWriteU64(block->size);
  470. BtlpVtuneWriteU32(block->IA32start);
  471. BtlpVtuneWriteU64(block->traversal);
  472. BtlpVtuneWriteU64(block->reserved);
  473. }
  474. // SSC Client support - absent in NT
  475. U64 BtlSscPerfGetCounter64(
  476. IN U32 Handle
  477. )
  478. /*++
  479. Routine Description:
  480. Get SSE client performance counter (Unavailable in NT)
  481. Arguments:
  482. Handle - IN SSE client handle
  483. Return Value:
  484. Counter value.
  485. --*/
  486. {
  487. return STATUS_SUCCESS;
  488. }
  489. U32 BtlSscPerfSetCounter64(
  490. IN U32 Handle,
  491. IN U64 Value
  492. )
  493. /*++
  494. Routine Description:
  495. Set SSE client performance counter (Unavailable in NT)
  496. Arguments:
  497. Handle - IN SSE client handle
  498. Value - IN new counter value
  499. Return Value:
  500. Status.
  501. --*/
  502. {
  503. return STATUS_SUCCESS;
  504. }
  505. U32 BtlSscPerfSendEvent(
  506. IN U32 Handle
  507. )
  508. /*++
  509. Routine Description:
  510. Send event to SSE client (Unavailable in NT)
  511. Arguments:
  512. Handle - IN SSE client handle
  513. Return Value:
  514. Status.
  515. --*/
  516. {
  517. return STATUS_SUCCESS;
  518. }
  519. U64 BtlSscPerfEventHandle(
  520. IN U64 EventName
  521. )
  522. /*++
  523. Routine Description:
  524. Receive event handle from SSE client (Unavailable in NT)
  525. Arguments:
  526. EventName - IN handle identification
  527. Return Value:
  528. SSE client handle.
  529. --*/
  530. {
  531. return STATUS_SUCCESS;
  532. }
  533. U64 BtlSscPerfCounterHandle(
  534. IN U64 DataItemName
  535. )
  536. /*++
  537. Routine Description:
  538. Receive counter handle from SSE client (Unavailable in NT)
  539. Arguments:
  540. DataItemName - IN handle identification
  541. Return Value:
  542. SSE client handle.
  543. --*/
  544. {
  545. return STATUS_SUCCESS;
  546. }
  547. // wowIA32X.dll/IA32Exec.bin support
  548. static NTSTATUS BtlpBt2NtExceptCode (
  549. IN BT_EXCEPTION_CODE BtExceptCode
  550. )
  551. /*++
  552. Routine Description:
  553. Convert given BT exception code to NT-specific exception code.
  554. Arguments:
  555. BtExceptCode - BT exception code
  556. Return Value:
  557. NTSTATUS representing converted BT exception code.
  558. --*/
  559. {
  560. NTSTATUS ret;
  561. switch (BtExceptCode) {
  562. case BT_EXCEPT_ILLEGAL_INSTRUCTION:
  563. ret = EXCEPTION_ILLEGAL_INSTRUCTION;
  564. break;
  565. case BT_EXCEPT_ACCESS_VIOLATION:
  566. ret = EXCEPTION_ACCESS_VIOLATION;
  567. break;
  568. case BT_EXCEPT_DATATYPE_MISALIGNMENT:
  569. ret = EXCEPTION_DATATYPE_MISALIGNMENT;
  570. break;
  571. case BT_EXCEPT_ARRAY_BOUNDS_EXCEEDED:
  572. ret = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
  573. break;
  574. case BT_EXCEPT_FLT_DENORMAL_OPERAND:
  575. ret = EXCEPTION_FLT_DENORMAL_OPERAND;
  576. break;
  577. case BT_EXCEPT_FLT_DIVIDE_BY_ZERO:
  578. ret = EXCEPTION_FLT_DIVIDE_BY_ZERO;
  579. break;
  580. case BT_EXCEPT_FLT_INEXACT_RESULT:
  581. ret = EXCEPTION_FLT_INEXACT_RESULT;
  582. break;
  583. case BT_EXCEPT_FLT_INVALID_OPERATION:
  584. ret = EXCEPTION_FLT_INVALID_OPERATION;
  585. break;
  586. case BT_EXCEPT_FLT_OVERFLOW:
  587. ret = EXCEPTION_FLT_OVERFLOW;
  588. break;
  589. case BT_EXCEPT_FLT_UNDERFLOW:
  590. ret = EXCEPTION_FLT_UNDERFLOW;
  591. break;
  592. case BT_EXCEPT_FLT_STACK_CHECK:
  593. ret = EXCEPTION_FLT_STACK_CHECK;
  594. break;
  595. case BT_EXCEPT_INT_DIVIDE_BY_ZERO:
  596. ret = EXCEPTION_INT_DIVIDE_BY_ZERO;
  597. break;
  598. case BT_EXCEPT_INT_OVERFLOW:
  599. ret = EXCEPTION_INT_OVERFLOW;
  600. break;
  601. case BT_EXCEPT_PRIV_INSTRUCTION:
  602. ret = EXCEPTION_PRIV_INSTRUCTION;
  603. break;
  604. case BT_EXCEPT_FLOAT_MULTIPLE_FAULTS:
  605. ret = STATUS_FLOAT_MULTIPLE_FAULTS;
  606. break;
  607. case BT_EXCEPT_FLOAT_MULTIPLE_TRAPS:
  608. ret = STATUS_FLOAT_MULTIPLE_TRAPS;
  609. break;
  610. case BT_EXCEPT_STACK_OVERFLOW:
  611. ret = STATUS_STACK_OVERFLOW;
  612. break;
  613. case BT_EXCEPT_GUARD_PAGE:
  614. ret = STATUS_GUARD_PAGE_VIOLATION;
  615. break;
  616. case BT_EXCEPT_BREAKPOINT:
  617. ret = STATUS_WX86_BREAKPOINT;
  618. break;
  619. case BT_EXCEPT_SINGLE_STEP:
  620. ret = STATUS_WX86_SINGLE_STEP;
  621. break;
  622. default:
  623. DBCODE(TRUE, BtlpPrintf ("\nConverting unknown BT exception 0x%X to EXCEPTION_ACCESS_VIOLATION", BtExceptCode));
  624. ret = EXCEPTION_ACCESS_VIOLATION;
  625. }
  626. return ret;
  627. }
  628. static BT_EXCEPTION_CODE BtlpNt2BtExceptCode (
  629. IN NTSTATUS NtExceptCode
  630. )
  631. /*++
  632. Routine Description:
  633. Convert given NT-specific exception code to BT-generic exception code.
  634. Arguments:
  635. NtExceptCode - NT exception code
  636. Return Value:
  637. BT_EXCEPTION_CODE representing converted NT exception code.
  638. --*/
  639. {
  640. BT_EXCEPTION_CODE ret;
  641. switch (NtExceptCode) {
  642. case EXCEPTION_ILLEGAL_INSTRUCTION:
  643. ret = BT_EXCEPT_ILLEGAL_INSTRUCTION;
  644. break;
  645. case EXCEPTION_ACCESS_VIOLATION:
  646. ret = BT_EXCEPT_ACCESS_VIOLATION;
  647. break;
  648. case EXCEPTION_DATATYPE_MISALIGNMENT:
  649. ret = BT_EXCEPT_DATATYPE_MISALIGNMENT;
  650. break;
  651. case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
  652. ret = BT_EXCEPT_ARRAY_BOUNDS_EXCEEDED;
  653. break;
  654. case EXCEPTION_FLT_DENORMAL_OPERAND:
  655. ret = BT_EXCEPT_FLT_DENORMAL_OPERAND;
  656. break;
  657. case EXCEPTION_FLT_DIVIDE_BY_ZERO:
  658. ret = BT_EXCEPT_FLT_DIVIDE_BY_ZERO;
  659. break;
  660. case EXCEPTION_FLT_INEXACT_RESULT:
  661. ret = BT_EXCEPT_FLT_INEXACT_RESULT;
  662. break;
  663. case EXCEPTION_FLT_INVALID_OPERATION:
  664. ret = BT_EXCEPT_FLT_INVALID_OPERATION;
  665. break;
  666. case EXCEPTION_FLT_OVERFLOW:
  667. ret = BT_EXCEPT_FLT_OVERFLOW;
  668. break;
  669. case EXCEPTION_FLT_UNDERFLOW:
  670. ret = BT_EXCEPT_FLT_UNDERFLOW;
  671. break;
  672. case EXCEPTION_FLT_STACK_CHECK:
  673. ret = BT_EXCEPT_FLT_STACK_CHECK;
  674. break;
  675. case EXCEPTION_INT_DIVIDE_BY_ZERO:
  676. ret = BT_EXCEPT_INT_DIVIDE_BY_ZERO;
  677. break;
  678. case EXCEPTION_INT_OVERFLOW:
  679. ret = BT_EXCEPT_INT_OVERFLOW;
  680. break;
  681. case EXCEPTION_PRIV_INSTRUCTION:
  682. ret = BT_EXCEPT_PRIV_INSTRUCTION;
  683. break;
  684. case STATUS_FLOAT_MULTIPLE_FAULTS:
  685. ret = BT_EXCEPT_FLOAT_MULTIPLE_FAULTS;
  686. break;
  687. case STATUS_FLOAT_MULTIPLE_TRAPS:
  688. ret = BT_EXCEPT_FLOAT_MULTIPLE_TRAPS;
  689. break;
  690. case STATUS_STACK_OVERFLOW:
  691. ret = BT_EXCEPT_STACK_OVERFLOW;
  692. break;
  693. case STATUS_GUARD_PAGE_VIOLATION:
  694. ret = BT_EXCEPT_GUARD_PAGE;
  695. break;
  696. case EXCEPTION_BREAKPOINT:
  697. case STATUS_WX86_BREAKPOINT:
  698. ret = BT_EXCEPT_BREAKPOINT;
  699. break;
  700. case EXCEPTION_SINGLE_STEP:
  701. case STATUS_WX86_SINGLE_STEP:
  702. ret = BT_EXCEPT_SINGLE_STEP;
  703. break;
  704. default:
  705. DBCODE(TRUE, BtlpPrintf ("\nConverting unknown NT exception 0x%X to BT_EXCEPT_UNKNOWN", NtExceptCode));
  706. ret = BT_EXCEPT_UNKNOWN;
  707. }
  708. return ret;
  709. }
  710. static void BtlpNt2BtExceptRecord (
  711. IN const EXCEPTION_RECORD * NtExceptRecordP,
  712. OUT BT_EXCEPTION_RECORD * BtExceptRecordP
  713. )
  714. /*++
  715. Routine Description:
  716. Convert given NT-specific exception record to BT-generic exception record.
  717. The NT exception record should represent a real 64-bit exception (fault or trap)
  718. Arguments:
  719. NtExceptRecordP - Pointer to NT exception record to be converted
  720. BtExceptRecordP - Pointer to BT exception record to be constructed
  721. Return Value:
  722. None.
  723. --*/
  724. {
  725. BtExceptRecordP->ExceptionCode = BtlpNt2BtExceptCode(NtExceptRecordP->ExceptionCode);
  726. if (NtExceptRecordP->NumberParameters >= 5) {
  727. BtExceptRecordP->Ia64IIPA = NtExceptRecordP->ExceptionInformation[3];
  728. BtExceptRecordP->Ia64ISR = NtExceptRecordP->ExceptionInformation[4];
  729. }
  730. else {
  731. BtExceptRecordP->Ia64IIPA = 0;
  732. BtExceptRecordP->Ia64ISR = UNKNOWN_ISR_VALUE;
  733. }
  734. }
  735. static NTSTATUS BtlpBt2NtStatusCode (
  736. IN BT_STATUS_CODE BtStatus
  737. )
  738. /*++
  739. Routine Description:
  740. Convert given BT staus code to NT-specific status code.
  741. Arguments:
  742. BtStatus - BT status code
  743. Return Value:
  744. NTSTATUS representing converted BT status code.
  745. --*/
  746. {
  747. NTSTATUS ret;
  748. switch (BtStatus) {
  749. case BT_STATUS_SUCCESS:
  750. ret = STATUS_SUCCESS;
  751. break;
  752. case BT_STATUS_UNSUCCESSFUL:
  753. ret = STATUS_UNSUCCESSFUL;
  754. break;
  755. case BT_STATUS_NO_MEMORY:
  756. ret = STATUS_NO_MEMORY;
  757. break;
  758. case BT_STATUS_ACCESS_VIOLATION:
  759. ret = STATUS_ACCESS_VIOLATION;
  760. break;
  761. default:
  762. DBCODE(TRUE, BtlpPrintf ("\nConverting unknown status 0x%X to STATUS_UNSUCCESSFUL", BtStatus));
  763. ret = STATUS_UNSUCCESSFUL;
  764. }
  765. return ret;
  766. }
  767. static BT_FLUSH_REASON BtlpWow2BtFlushReason (
  768. IN WOW64_FLUSH_REASON Wow64FlushReason
  769. )
  770. /*++
  771. Routine Description:
  772. Convert given WOW64_FLUSH_REASON code to BT-generic code.
  773. Arguments:
  774. Wow64FlushReason - WOW64_FLUSH_REASON code
  775. Return Value:
  776. BT_FLUSH_REASON code representing converted WOW64_FLUSH_REASON code.
  777. --*/
  778. {
  779. BT_FLUSH_REASON ret;
  780. switch (Wow64FlushReason) {
  781. case WOW64_FLUSH_FORCE:
  782. ret = BT_FLUSH_FORCE;
  783. break;
  784. case WOW64_FLUSH_FREE:
  785. ret = BT_FLUSH_FREE;
  786. break;
  787. case WOW64_FLUSH_ALLOC:
  788. ret = BT_FLUSH_ALLOC;
  789. break;
  790. case WOW64_FLUSH_PROTECT:
  791. ret = BT_FLUSH_PROTECT;
  792. break;
  793. default:
  794. //BtlpPrintf ("\nConverting unknown WOW64_FLUSH_REASON %d to BT_FLUSH_PROTECT", Wow64FlushReason);
  795. ret = BT_FLUSH_PROTECT;
  796. }
  797. return ret;
  798. }
  799. static SIZE_T BtlpGetMemAllocSize(
  800. IN PVOID AllocationBase,
  801. OUT BOOL * pIsCommited
  802. )
  803. /*++
  804. Routine Description:
  805. Calculate size of a region allocated by the NtAllocateVirtualMemory function.
  806. Arguments:
  807. AllocationBase - Allocation base address
  808. pIsCommited - Pointer to returned boolean flag that indicates is there exist
  809. a commited page in the allocated region
  810. Return Value:
  811. Size of the allocated region starting from the given base address.
  812. --*/
  813. {
  814. NTSTATUS status;
  815. MEMORY_BASIC_INFORMATION memInfo;
  816. SIZE_T dwRetSize;
  817. PVOID BaseAddress = AllocationBase;
  818. *pIsCommited = FALSE;
  819. //Iterate through all regions with the same allocation base address
  820. for (;;) {
  821. status = NtQueryVirtualMemory(NtCurrentProcess(),
  822. BaseAddress,
  823. MemoryBasicInformation,
  824. &memInfo,
  825. sizeof (memInfo),
  826. &dwRetSize);
  827. if ((status != STATUS_SUCCESS) ||
  828. (memInfo.State == MEM_FREE) ||
  829. (AllocationBase != memInfo.AllocationBase)) {
  830. break;
  831. }
  832. assert(memInfo.RegionSize != 0);
  833. BaseAddress = (PVOID)((UINT_PTR)(memInfo.BaseAddress) + memInfo.RegionSize);
  834. *pIsCommited |= (memInfo.State == MEM_COMMIT);
  835. }
  836. return ((UINT_PTR)BaseAddress - (UINT_PTR)AllocationBase);
  837. }
  838. // Registry access section
  839. static BOOL BtlpRetrieveHKCUValue (
  840. IN PWCHAR RegistryEntryName,
  841. OUT PWCHAR RegistryValueBuf
  842. )
  843. /*++
  844. Routine Description:
  845. Retrieve a registry value from HKCU
  846. Arguments:
  847. RegistryEntryName - IN Registry Entry Name
  848. RegistryValueBuf - OUT Buffer for the result (pointer to WCHAR string)
  849. Return Value:
  850. Success/failure (TRUE/FALSE)
  851. --*/
  852. {
  853. WCHAR wBuf[256], cmpbuf[128];
  854. UNICODE_STRING us_Buffer, us_EnvVarUserName, us_UserName, us_HiveList;
  855. OBJECT_ATTRIBUTES oa;
  856. HANDLE hHiveList, hCurUser;
  857. PKEY_FULL_INFORMATION pkfi1, pkfi2;
  858. PKEY_VALUE_FULL_INFORMATION pkvfi1, pkvfi2;
  859. ULONG ret_len, i, j, values1, values2;
  860. NTSTATUS ret;
  861. WCHAR UserNameBuf[80];
  862. // Check the HKEY_CURRENT_USER\Software\Intel\Btrans registry key for the
  863. // 'RegistryEntryName' entry.
  864. //
  865. // The problem is that the HKEY_CURRENT_USER hive is not directly available if
  866. // we are limited only to using the NTDLL interface. In fact, only two high-level
  867. // keys are available: HKEY_LOCAL_MACHINE and HKEY_USERS. To sidestep this,
  868. // the following mechanism is used, based on these two keys' data and process
  869. // environment:
  870. //
  871. // The key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\hivelist
  872. // contains list of registry entries corresponding to all users, like:
  873. //
  874. // Key Value
  875. //----------------------------------------------------------------------------------------
  876. // ..............
  877. // \REGISTRY\USER\S-1-5-21-... ...\Documents And Settings\<username>[...]\NTUSER.DAT
  878. // \REGISTRY\USER\S-1-5-21-..._Class ...\Documents And Settings\<username>[...]\.......
  879. //
  880. // The key fo the value with correct username (without _Class) is actually
  881. // a reference to HKEY_CURRENT_USER registry key
  882. //
  883. // <username> can be easily obtained from the process environment
  884. // Environment -> <username>
  885. memset (UserNameBuf, L' ', sizeof (UserNameBuf)/sizeof (UserNameBuf[0]) - 1);
  886. UserNameBuf[sizeof (UserNameBuf)/sizeof (UserNameBuf[0]) - 1] = L'\0';
  887. RtlInitUnicodeString(&us_UserName, UserNameBuf);
  888. RtlInitUnicodeString(&us_EnvVarUserName, L"USERNAME");
  889. ret = RtlQueryEnvironmentVariable_U(NULL, &us_EnvVarUserName, &us_UserName);
  890. if ( ret == STATUS_SUCCESS ) {
  891. swprintf(cmpbuf, L"\\%s", us_UserName.Buffer);
  892. DBCODE (FALSE, BtlpPrintf("cmpbuf=%S, wcslen(cmpbuf)=%d\n", cmpbuf, wcslen(cmpbuf)));
  893. }
  894. else {
  895. DBCODE (FALSE, BtlpPrintf("RtlQueryEnvironmentVariable_U failed: status=%X\n", ret));
  896. }
  897. // Go over the entries for HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\hivelist
  898. swprintf(wBuf, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\hivelist");
  899. RtlInitUnicodeString(&us_Buffer, wBuf);
  900. InitializeObjectAttributes(&oa, &us_Buffer, OBJ_CASE_INSENSITIVE, NULL, NULL);
  901. ret = NtOpenKey(&hHiveList, KEY_READ, &oa);
  902. DBCODE (FALSE, BtlpPrintf ("NtOpenKey ret=0x%X\n",ret));
  903. if ( ret == STATUS_SUCCESS ) {
  904. KEY_FULL_INFORMATION buf[128];
  905. memset(buf, 0, sizeof(buf));
  906. ret = NtQueryKey(hHiveList, KeyFullInformation, buf, sizeof(buf), &ret_len);
  907. DBCODE (FALSE, BtlpPrintf ("NtQueryKey ret=0x%X\n",ret));
  908. if ( ret == STATUS_SUCCESS ) {
  909. pkfi1 = (PKEY_FULL_INFORMATION)buf;
  910. values1 = pkfi1->Values;
  911. for ( i = 0; i < values1; i++ ) {
  912. KEY_FULL_INFORMATION bufv[128];
  913. memset(bufv, 0, sizeof(bufv));
  914. ret = NtEnumerateValueKey(hHiveList, i, KeyValueFullInformation, bufv, sizeof(bufv), &ret_len);
  915. DBCODE (FALSE, BtlpPrintf ("NtEnumerateValueKey ret=0x%X\n",ret));
  916. if ( ret == STATUS_SUCCESS ) {
  917. WCHAR * foundp;
  918. pkvfi1 = (PKEY_VALUE_FULL_INFORMATION)bufv;
  919. DBCODE (FALSE, BtlpPrintf("name=%S data=%S nl=%d, do=%d, dl=%d\n",
  920. pkvfi1->Name, (WCHAR *)((char *)pkvfi1 + pkvfi1->DataOffset),
  921. pkvfi1->NameLength, pkvfi1->DataOffset, pkvfi1->DataLength);
  922. BtlpPrintf("tail=%S\n",
  923. (WCHAR *)((char *)pkvfi1 + pkvfi1->DataOffset + pkvfi1->DataLength - 2) - wcslen(cmpbuf) - 1));
  924. // DataLength is in number of bytes, not number of WCHARs
  925. // DataOffset is offset in bytes from the start of the data structure
  926. DBCODE (FALSE, BtlpPrintf("User=%S, Compare cmpbuf=%S, HKEY_CURRENT_USER maps to %S\n", us_UserName.Buffer, cmpbuf, pkvfi1->Name));
  927. foundp = wcsstr ((WCHAR *)((char *)pkvfi1 + pkvfi1->DataOffset), cmpbuf);
  928. if (foundp
  929. && !iswalnum (foundp[wcslen(cmpbuf)])
  930. && foundp[wcslen(cmpbuf)] != L'_') {
  931. DBCODE (FALSE, BtlpPrintf("User=%S, HKEY_CURRENT_USER maps to %S\n", us_UserName.Buffer, pkvfi1->Name));
  932. // Found the entry in Users hive corresponding to the current user.
  933. // Use its name to open the registry key HKEY_CURRENT_USER
  934. swprintf(wBuf, L"%s\\Software\\Intel\\Btrans", pkvfi1->Name);
  935. RtlInitUnicodeString(&us_Buffer, wBuf);
  936. InitializeObjectAttributes(&oa, &us_Buffer, OBJ_CASE_INSENSITIVE, NULL, NULL);
  937. ret = NtOpenKey(&hCurUser, KEY_READ, &oa);
  938. if ( ret == STATUS_SUCCESS ) {
  939. KEY_FULL_INFORMATION bufv2[128];
  940. memset(bufv2, 0, sizeof(bufv2));
  941. ret = NtQueryKey(hCurUser, KeyFullInformation, bufv2, sizeof(bufv2), &ret_len);
  942. if ( ret == STATUS_SUCCESS ) {
  943. pkfi2 = (PKEY_FULL_INFORMATION)bufv2;
  944. values2 = pkfi2->Values;
  945. for ( j = 0; j < values2; j++ ) {
  946. KEY_FULL_INFORMATION bufi2[128];
  947. memset(bufi2, 0, sizeof(bufi2));
  948. ret = NtEnumerateValueKey(hCurUser, j, KeyValueFullInformation, bufi2, sizeof(bufi2), &ret_len);
  949. if ( ret == STATUS_SUCCESS ) {
  950. pkvfi2 = (PKEY_VALUE_FULL_INFORMATION)bufi2;
  951. DBCODE (FALSE, BtlpPrintf("name: %S value: %S\n", pkvfi2->Name, (WCHAR *)((char *)pkvfi2 + pkvfi2->DataOffset)));
  952. // The entry contains the fullpath of the file
  953. if (pkvfi2->Type == REG_SZ
  954. && wcsncmp(RegistryEntryName, pkvfi2->Name, wcslen(RegistryEntryName)) == 0 ) {
  955. DBCODE (FALSE, BtlpPrintf("File in HKEY_CURRENT_USER: %S\n", (WCHAR *)((char *)pkvfi2 + pkvfi2->DataOffset)));
  956. wcscpy(RegistryValueBuf, (WCHAR *)((char *)pkvfi2 + pkvfi2->DataOffset));
  957. NtClose(hCurUser);
  958. NtClose(hHiveList);
  959. return TRUE;
  960. }
  961. }
  962. }
  963. }
  964. NtClose(hCurUser);
  965. }
  966. break;
  967. }
  968. }
  969. }
  970. }
  971. NtClose(hHiveList);
  972. }
  973. return FALSE;
  974. }
  975. static BOOL BtlpRetrieveHKLMValue (
  976. IN PWCHAR RegistryEntryName,
  977. OUT PWCHAR RegistryValueBuf
  978. )
  979. /*++
  980. Routine Description:
  981. Retrieve a registry value from HKLM
  982. Arguments:
  983. RegistryEntryName - IN Registry Entry Name
  984. RegistryValueBuf - OUT Buffer for the result (pointer to WCHAR string)
  985. Return Value:
  986. Success/failure (TRUE/FALSE)
  987. --*/
  988. {
  989. WCHAR wBuf[256], cmpbuf[128];
  990. UNICODE_STRING us_Buffer;
  991. OBJECT_ATTRIBUTES oa;
  992. HANDLE hLocalMachine;
  993. PKEY_FULL_INFORMATION pkfi1, pkfi2;
  994. PKEY_VALUE_FULL_INFORMATION pkvfi1, pkvfi2;
  995. ULONG ret_len, i, j, values1, values2;
  996. NTSTATUS ret;
  997. // Check the HKEY_LOCAL_MACHINE\Software\Intel\Btrans registry key for the
  998. // 'RegistryEntryName' entry.
  999. swprintf(wBuf, L"\\Registry\\Machine\\Software\\Intel\\Btrans");
  1000. RtlInitUnicodeString(&us_Buffer, wBuf);
  1001. InitializeObjectAttributes(&oa, &us_Buffer, OBJ_CASE_INSENSITIVE, NULL, NULL);
  1002. ret = NtOpenKey(&hLocalMachine, KEY_READ, &oa);
  1003. if ( ret == STATUS_SUCCESS ) {
  1004. KEY_FULL_INFORMATION buf[128];
  1005. memset(buf, 0, sizeof(buf));
  1006. ret = NtQueryKey(hLocalMachine, KeyFullInformation, buf, sizeof(buf), &ret_len);
  1007. if ( ret == STATUS_SUCCESS) {
  1008. pkfi1 = (PKEY_FULL_INFORMATION)buf;
  1009. for ( j = 0; j < pkfi1->Values; j++ ) {
  1010. KEY_FULL_INFORMATION bufv[128];
  1011. memset(bufv, 0, sizeof(bufv));
  1012. ret = NtEnumerateValueKey(hLocalMachine, j, KeyValueFullInformation, bufv, sizeof(bufv), &ret_len);
  1013. if ( ret == STATUS_SUCCESS ) {
  1014. pkvfi1 = (PKEY_VALUE_FULL_INFORMATION)bufv;
  1015. if (pkvfi1->Type == REG_SZ
  1016. && wcsncmp(RegistryEntryName, pkvfi1->Name, wcslen(RegistryEntryName)) == 0 ) {
  1017. wcscpy(RegistryValueBuf, (WCHAR *)((char *)pkvfi1 + pkvfi1->DataOffset));
  1018. NtClose(hLocalMachine);
  1019. return TRUE;
  1020. }
  1021. }
  1022. }
  1023. }
  1024. NtClose(hLocalMachine);
  1025. }
  1026. return FALSE;
  1027. }
  1028. static BOOL BtlpBtlibDirectory (
  1029. OUT PWCHAR ValueBuf
  1030. )
  1031. /*++
  1032. Routine Description:
  1033. Retrieve the actual directory of the wowIA32X.dll and use it as
  1034. a last resort if no specific registry pointer
  1035. is found for IA32Exec.bin and BTrans.ini files.
  1036. Arguments:
  1037. ValueBuf - OUT Buffer for the result (pointer to WCHAR string)
  1038. Return Value:
  1039. Success/failure (TRUE/FALSE)
  1040. --*/
  1041. {
  1042. PPEB_LDR_DATA LdrP;
  1043. PLDR_DATA_TABLE_ENTRY LdrDtP;
  1044. RtlAcquirePebLock();
  1045. LdrP = BT_CURRENT_TEB()->ProcessEnvironmentBlock->Ldr;
  1046. LdrDtP = (PLDR_DATA_TABLE_ENTRY)(LdrP->InLoadOrderModuleList.Flink);
  1047. do {
  1048. // Our own address belongs to the wowIA32X.dll module
  1049. if ( (ULONG_PTR)BtlpBtlibDirectory >= (ULONG_PTR)LdrDtP->DllBase
  1050. && (ULONG_PTR)BtlpBtlibDirectory < (ULONG_PTR)LdrDtP->DllBase + LdrDtP->SizeOfImage) {
  1051. // Found
  1052. WCHAR * EndPtr;
  1053. wcscpy(ValueBuf, LdrDtP->FullDllName.Buffer);
  1054. // Remove file name at the end (until '\\' inclusively)
  1055. EndPtr = wcsrchr(ValueBuf,L'\\');
  1056. if (EndPtr) {
  1057. *EndPtr = L'\0';
  1058. }
  1059. RtlReleasePebLock();
  1060. return TRUE;
  1061. }
  1062. LdrDtP = (PLDR_DATA_TABLE_ENTRY)(LdrDtP->InLoadOrderLinks.Flink);
  1063. } while (LdrDtP != (PLDR_DATA_TABLE_ENTRY)&(LdrP->InLoadOrderModuleList.Flink));
  1064. RtlReleasePebLock();
  1065. return FALSE;
  1066. }
  1067. #ifndef RELEASE
  1068. static int BtlpIniFileExists(
  1069. IN PWCHAR CurrentDir,
  1070. IN int fBTGenericHandle,
  1071. OUT PHANDLE phIniFile
  1072. )
  1073. /*++
  1074. Routine Description:
  1075. Locate and open BTrans.ini file
  1076. Arguments:
  1077. CurrentDir - IN current directory
  1078. phIniFile - OUT Handle of the file
  1079. Return Value:
  1080. Success/failure (TRUE/FALSE)
  1081. --*/
  1082. {
  1083. WCHAR RegEntry[16] = L"SETUP_FILE";
  1084. WCHAR RegistryValueBuf[1024];
  1085. WCHAR IniFileFullPath[1024];
  1086. UNICODE_STRING us_IniFile;
  1087. OBJECT_ATTRIBUTES oa;
  1088. IO_STATUS_BLOCK IoStatusBlock;
  1089. LARGE_INTEGER AllocSz = { 0, 0 };
  1090. NTSTATUS ret;
  1091. // 1. Check for existence of Btrans.ini file in the current work directory
  1092. swprintf(IniFileFullPath, L"\\DosDevices\\%s\\BTrans.ini", CurrentDir);
  1093. RtlInitUnicodeString(&us_IniFile, IniFileFullPath);
  1094. InitializeObjectAttributes(&oa, &us_IniFile, OBJ_CASE_INSENSITIVE, NULL, NULL);
  1095. ret = NtCreateFile(phIniFile, FILE_GENERIC_READ, &oa, &IoStatusBlock, &AllocSz,
  1096. FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
  1097. FILE_NON_DIRECTORY_FILE|FILE_RANDOM_ACCESS|FILE_SYNCHRONOUS_IO_NONALERT,
  1098. NULL, 0);
  1099. if ( ret == STATUS_SUCCESS && (*phIniFile) != INVALID_HANDLE_VALUE ) {
  1100. //BtlpPrintf("Setup file in current work directory: %S\n", IniFileFullPath);
  1101. return F_CURRENT_DIR;
  1102. }
  1103. #ifndef NODEBUG
  1104. // 2. Check the HKEY_CURRENT_USER\Software\Intel\Btrans registry key for the
  1105. // SETUP_FILE entry that should contain the fullpath of the IA-32 Execution Layer setup file
  1106. // (only if IA32Exec.bin found there as well)
  1107. if (F_HKCU == fBTGenericHandle
  1108. && BtlpRetrieveHKCUValue (RegEntry, RegistryValueBuf)) {
  1109. swprintf(IniFileFullPath, L"\\DosDevices\\%s", RegistryValueBuf);
  1110. RtlInitUnicodeString(&us_IniFile, IniFileFullPath);
  1111. InitializeObjectAttributes(&oa, &us_IniFile, OBJ_CASE_INSENSITIVE, NULL, NULL);
  1112. ret = NtCreateFile(phIniFile, FILE_GENERIC_READ, &oa, &IoStatusBlock, &AllocSz,
  1113. FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
  1114. FILE_NON_DIRECTORY_FILE|FILE_RANDOM_ACCESS|FILE_SYNCHRONOUS_IO_NONALERT,
  1115. NULL, 0);
  1116. if ( ret == STATUS_SUCCESS && (*phIniFile) != INVALID_HANDLE_VALUE ) {
  1117. return F_HKCU;
  1118. }
  1119. }
  1120. #endif
  1121. // 3. Check the HKEY_LOCAL_MACHINE\Software\Intel\Btrans registry key for the
  1122. // SETUP_FILE entry that contains the fullpath of the IA-32 Execution Layer setup file
  1123. // (only if IA32Exec.bin found there as well)
  1124. if (F_HKLM == fBTGenericHandle
  1125. && BtlpRetrieveHKLMValue (RegEntry, RegistryValueBuf)) {
  1126. swprintf(IniFileFullPath, L"\\DosDevices\\%s", RegistryValueBuf);
  1127. RtlInitUnicodeString(&us_IniFile, IniFileFullPath);
  1128. InitializeObjectAttributes(&oa, &us_IniFile, OBJ_CASE_INSENSITIVE, NULL, NULL);
  1129. ret = NtCreateFile(phIniFile, FILE_GENERIC_READ, &oa, &IoStatusBlock, &AllocSz,
  1130. FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
  1131. FILE_NON_DIRECTORY_FILE|FILE_RANDOM_ACCESS|FILE_SYNCHRONOUS_IO_NONALERT,
  1132. NULL, 0);
  1133. if ( ret == STATUS_SUCCESS && (*phIniFile) != INVALID_HANDLE_VALUE ) {
  1134. return F_HKLM;
  1135. }
  1136. }
  1137. // 4. Last resort - directory that wowIA32X.dll was loaded from
  1138. // (only if IA32Exec.bin found there as well)
  1139. if (F_BTLIB == fBTGenericHandle
  1140. && BtlpBtlibDirectory (RegistryValueBuf)) {
  1141. swprintf(IniFileFullPath, L"\\DosDevices\\%s\\BTrans.ini", RegistryValueBuf);
  1142. RtlInitUnicodeString(&us_IniFile, IniFileFullPath);
  1143. InitializeObjectAttributes(&oa, &us_IniFile, OBJ_CASE_INSENSITIVE, NULL, NULL);
  1144. ret = NtCreateFile(phIniFile, FILE_GENERIC_READ, &oa, &IoStatusBlock, &AllocSz,
  1145. FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
  1146. FILE_NON_DIRECTORY_FILE|FILE_RANDOM_ACCESS|FILE_SYNCHRONOUS_IO_NONALERT,
  1147. NULL, 0);
  1148. if ( ret == STATUS_SUCCESS && (*phIniFile) != INVALID_HANDLE_VALUE ) {
  1149. return F_BTLIB;
  1150. }
  1151. }
  1152. *phIniFile = INVALID_HANDLE_VALUE;
  1153. return F_NOT_FOUND;
  1154. }
  1155. #endif /* RELEASE */
  1156. static int BtlpLoadBTGeneric(
  1157. IN PWCHAR CurrentDir,
  1158. OUT PHANDLE phBTGenericLibrary
  1159. )
  1160. /*++
  1161. Routine Description:
  1162. Locate and load IA32Exec.bin component
  1163. Arguments:
  1164. CurrentDir - IN current directory
  1165. phBTGenericLibrary - OUT Handle of the IA32Exec.bin
  1166. Return Value:
  1167. Success/failure (TRUE/FALSE)
  1168. --*/
  1169. {
  1170. WCHAR RegistryValueBuf[1024];
  1171. UNICODE_STRING us_BTGenericLibrary;
  1172. WCHAR BTGenericLibraryFullPath[1024];
  1173. NTSTATUS ret;
  1174. #ifndef RELEASE
  1175. WCHAR RegEntry[16] = L"GENERIC_FILE";
  1176. // 1. Check for existence of IA32Exec.bin file in the current work directory
  1177. swprintf(BTGenericLibraryFullPath, L"%s\\%s.%s", CurrentDir, IA32EX_G_NAME,
  1178. IA32EX_G_SUFFIX);
  1179. RtlInitUnicodeString(&us_BTGenericLibrary, BTGenericLibraryFullPath);
  1180. ret = LdrLoadDll((PWSTR)NULL, (PULONG)0, &us_BTGenericLibrary, phBTGenericLibrary);
  1181. if ( ret == STATUS_SUCCESS && (*phBTGenericLibrary) != INVALID_HANDLE_VALUE ) {
  1182. //BtlpPrintf("IA32Exec.bin file in current work directory: %S\n", BTGenericLibraryFullPath);
  1183. return F_CURRENT_DIR;
  1184. }
  1185. #ifndef NODEBUG
  1186. // 2. Check the HKEY_CURRENT_USER\Software\Intel\Btrans registry key for the
  1187. // BTGENERIC_FILE entry that should contain the fullpath of the IA32Exec.bin file
  1188. if (BtlpRetrieveHKCUValue (RegEntry, RegistryValueBuf)) {
  1189. swprintf(BTGenericLibraryFullPath, L"%s", RegistryValueBuf);
  1190. RtlInitUnicodeString(&us_BTGenericLibrary, BTGenericLibraryFullPath);
  1191. ret = LdrLoadDll((PWSTR)NULL, (PULONG)0, &us_BTGenericLibrary, phBTGenericLibrary);
  1192. if ( ret == STATUS_SUCCESS && (*phBTGenericLibrary) != INVALID_HANDLE_VALUE ) {
  1193. return F_HKCU;
  1194. }
  1195. }
  1196. #endif
  1197. // 3. Check the HKEY_LOCAL_MACHINE\Software\Intel\Btrans registry key for the
  1198. // BTGENERIC_FILE entry that contains the fullpath of the IA32Exec.bin file
  1199. if (BtlpRetrieveHKLMValue (RegEntry, RegistryValueBuf)) {
  1200. swprintf(BTGenericLibraryFullPath, L"%s", RegistryValueBuf);
  1201. RtlInitUnicodeString(&us_BTGenericLibrary, BTGenericLibraryFullPath);
  1202. ret = LdrLoadDll((PWSTR)NULL, (PULONG)0, &us_BTGenericLibrary, phBTGenericLibrary);
  1203. if ( ret == STATUS_SUCCESS && (*phBTGenericLibrary) != INVALID_HANDLE_VALUE ) {
  1204. return F_HKLM;
  1205. }
  1206. }
  1207. #endif /* RELEASE */
  1208. // 4. Last resort - directory that wowIA32X.dll was loaded from
  1209. // This is the only option in RELEASE mode
  1210. if (BtlpBtlibDirectory (RegistryValueBuf)) {
  1211. swprintf(BTGenericLibraryFullPath, L"%s\\%s.%s", RegistryValueBuf, IA32EX_G_NAME,
  1212. IA32EX_G_SUFFIX);
  1213. RtlInitUnicodeString(&us_BTGenericLibrary, BTGenericLibraryFullPath);
  1214. ret = LdrLoadDll((PWSTR)NULL, (PULONG)0, &us_BTGenericLibrary, phBTGenericLibrary);
  1215. if ( ret == STATUS_SUCCESS && (*phBTGenericLibrary) != INVALID_HANDLE_VALUE ) {
  1216. return F_BTLIB;
  1217. }
  1218. }
  1219. *phBTGenericLibrary = INVALID_HANDLE_VALUE;
  1220. return F_NOT_FOUND;
  1221. }
  1222. // Extract DOS header from NT executable (NULL if it is not one)
  1223. static PIMAGE_DOS_HEADER WINAPI BtlpExtractDosHeader (IN HANDLE hModule) {
  1224. PIMAGE_DOS_HEADER DosHeaderP;
  1225. DosHeaderP = (PIMAGE_DOS_HEADER) hModule;
  1226. assert (!((ULONG_PTR)DosHeaderP & 0xFFFF));
  1227. if (DosHeaderP->e_magic != IMAGE_DOS_SIGNATURE) {
  1228. return NULL;
  1229. }
  1230. return DosHeaderP;
  1231. }
  1232. // Extract NT header from NT executable (abort if not one)
  1233. static PIMAGE_NT_HEADERS WINAPI BtlpExtractNTHeader (IN HINSTANCE hModule) {
  1234. PIMAGE_DOS_HEADER DosHeaderP;
  1235. PIMAGE_NT_HEADERS NTHeaderP;
  1236. DosHeaderP = BtlpExtractDosHeader ((HANDLE)hModule);
  1237. assert (DosHeaderP != NULL);
  1238. NTHeaderP = (PIMAGE_NT_HEADERS) ((ULONG_PTR)DosHeaderP + DosHeaderP->e_lfanew);
  1239. assert (NTHeaderP->Signature == IMAGE_NT_SIGNATURE);
  1240. assert ((NTHeaderP->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) != 0);
  1241. assert ((NTHeaderP->FileHeader.Characteristics & IMAGE_FILE_32BIT_MACHINE) != 0);
  1242. assert (NTHeaderP->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC);
  1243. assert (NTHeaderP->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64);
  1244. return NTHeaderP;
  1245. }
  1246. static void BtlpInitIA32Context(
  1247. BTGENERIC_IA32_CONTEXT * IA32ContextP,
  1248. PTEB32 pTEB32
  1249. )
  1250. /*++
  1251. Routine Description:
  1252. Initialize IA32 thread context
  1253. Arguments:
  1254. IA32ContextP - Pointer to IA32 context to be initialized
  1255. pTEB32 - Pointer to IA32 TEB of the thread whose context is
  1256. to be initialized
  1257. Return Value:
  1258. none
  1259. --*/
  1260. {
  1261. memset(IA32ContextP, 0, sizeof(*IA32ContextP) );
  1262. IA32ContextP->SegCs = CS_INIT_VAL;
  1263. IA32ContextP->SegDs = DS_INIT_VAL;
  1264. IA32ContextP->SegEs = ES_INIT_VAL;
  1265. IA32ContextP->SegFs = FS_INIT_VAL;
  1266. IA32ContextP->SegSs = SS_INIT_VAL;
  1267. IA32ContextP->EFlags = EFLAGS_INIT_VAL;
  1268. IA32ContextP->Esp = (U32)pTEB32->NtTib.StackBase - sizeof(U32);
  1269. IA32ContextP->FloatSave.ControlWord = FPCW_INIT_VAL;
  1270. IA32ContextP->FloatSave.TagWord = FPTW_INIT_VAL;
  1271. *(U32 *)&(IA32ContextP->ExtendedRegisters[24]) = MXCSR_INIT_VAL;
  1272. }
  1273. __inline NTSTATUS BtlpGetProcessInfo(
  1274. IN HANDLE ProcessHandle,
  1275. PROCESS_BASIC_INFORMATION * pInfo
  1276. )
  1277. /*++
  1278. Routine Description:
  1279. Given a process handle, return basic process information
  1280. Arguments:
  1281. ProcessHandle - Process handle
  1282. pInfo - Buffer to receive PROCESS_BASIC_INFORMATION
  1283. Return Value:
  1284. NTSTATUS.
  1285. --*/
  1286. {
  1287. NTSTATUS status;
  1288. status = NtQueryInformationProcess(
  1289. ProcessHandle,
  1290. ProcessBasicInformation,
  1291. pInfo,
  1292. sizeof(*pInfo),
  1293. 0);
  1294. BTLP_REPORT_NT_FAILURE("NtQueryInformationProcess", status);
  1295. return status;
  1296. }
  1297. __inline NTSTATUS BtlpGetProcessUniqueIdByHandle(
  1298. IN HANDLE ProcessHandle,
  1299. OUT U64 * ProcessIdP
  1300. )
  1301. /*++
  1302. Routine Description:
  1303. Given a process handle, return unique (throughout the system) ID of the process
  1304. Arguments:
  1305. ProcessHandle - Process handle
  1306. ProcessIdP - Pointer to a variable that receives unique process ID
  1307. Return Value:
  1308. NTSTATUS.
  1309. --*/
  1310. {
  1311. NTSTATUS status;
  1312. PROCESS_BASIC_INFORMATION info;
  1313. status = BtlpGetProcessInfo(ProcessHandle,&info);
  1314. if (status == STATUS_SUCCESS) {
  1315. *ProcessIdP = (U64)(info.UniqueProcessId);
  1316. }
  1317. return status;
  1318. }
  1319. __inline NTSTATUS BtlpGetThreadUniqueIdByHandle(
  1320. IN HANDLE ThreadHandle,
  1321. OUT U64 * ThreadIdP
  1322. )
  1323. /*++
  1324. Routine Description:
  1325. Given a thread handle, return unique (throughout the system) ID of the thread
  1326. Arguments:
  1327. ThreadHandle - Thread handle
  1328. ThreadIdP - Pointer to a variable that receives unique thread ID
  1329. Return Value:
  1330. NTSTATUS.
  1331. --*/
  1332. {
  1333. NTSTATUS status;
  1334. THREAD_BASIC_INFORMATION info;
  1335. status = NtQueryInformationThread(
  1336. ThreadHandle,
  1337. ThreadBasicInformation,
  1338. &info,
  1339. sizeof(info),
  1340. 0);
  1341. if (status == STATUS_SUCCESS) {
  1342. *ThreadIdP = (U64)(info.ClientId.UniqueThread);
  1343. }
  1344. return status;
  1345. }
  1346. __inline BOOL BtlpIsCurrentProcess(
  1347. IN HANDLE ProcessHandle
  1348. )
  1349. /*++
  1350. Routine Description:
  1351. Check to see if a process handle represents the current process
  1352. Arguments:
  1353. ProcessHandle - Process handle
  1354. Return Value:
  1355. TRUE if ProcessHandle represents the current process, FALSE - otherwise.
  1356. --*/
  1357. {
  1358. U64 ProcessId;
  1359. return ((ProcessHandle == NtCurrentProcess()) ||
  1360. ((BtlpGetProcessUniqueIdByHandle(ProcessHandle, &ProcessId) == STATUS_SUCCESS) &&
  1361. (BT_CURRENT_PROC_UID() == ProcessId)));
  1362. }
  1363. __inline PVOID BtlpGetTlsPtr(
  1364. IN HANDLE ProcessHandle,
  1365. IN PTEB pTEB,
  1366. IN BOOL IsLocal
  1367. )
  1368. /*++
  1369. Routine Description:
  1370. Read BT_TLS pointer of a local or remote thread
  1371. Arguments:
  1372. ProcessHandle - Process handle
  1373. pTEB - TEB of a local/remote thread
  1374. IsLocal - TRUE for local thread
  1375. Return Value:
  1376. BT_TLS pointer. NULL if access failed.
  1377. --*/
  1378. {
  1379. NTSTATUS status;
  1380. PVOID GlstP;
  1381. if (IsLocal) {
  1382. GlstP = BT_TLS_OF(pTEB);
  1383. }
  1384. else {
  1385. status = NtReadVirtualMemory(ProcessHandle,
  1386. (VOID * )((UINT_PTR)pTEB + BT_TLS_OFFSET),
  1387. &GlstP,
  1388. sizeof(GlstP),
  1389. NULL);
  1390. if (status != STATUS_SUCCESS) {
  1391. BTLP_REPORT_NT_FAILURE("NtReadVirtualMemory", status);
  1392. GlstP = NULL;
  1393. }
  1394. }
  1395. return GlstP;
  1396. }
  1397. __inline NTSTATUS BtlpInitSharedInfo()
  1398. /*++
  1399. Routine Description:
  1400. Initialize thread shared info
  1401. Arguments:
  1402. None
  1403. Return Value:
  1404. NTSTATUS
  1405. --*/
  1406. {
  1407. BTLIB_INIT_SUSPENSION_PERMISSION();
  1408. BTLIB_INIT_SUSPEND_REQUEST();
  1409. BTLIB_SET_CONSISTENT_EXCEPT_STATE();
  1410. BTLIB_SET_SIGNATURE();
  1411. return STATUS_SUCCESS;
  1412. }
  1413. static NTSTATUS BtlpReadSharedInfo(
  1414. IN HANDLE ProcessHandle,
  1415. IN PVOID pTLS,
  1416. IN BOOL IsLocal,
  1417. OUT BTLIB_SHARED_INFO_TYPE * SharedInfoP
  1418. )
  1419. /*++
  1420. Routine Description:
  1421. Read shared wowIA32X.dll info of a local or remote thread. The function
  1422. fails if wowIA32X.dll signature does not match.
  1423. Arguments:
  1424. ProcessHandle - Process handle
  1425. pTLS - pointer to BT_TLS of a local/remote thread
  1426. IsLocal - TRUE for local thread
  1427. SharedInfoP - buffer to read shared wowIA32X.dll info to
  1428. Return Value:
  1429. NTSTATUS
  1430. --*/
  1431. {
  1432. NTSTATUS status;
  1433. if (IsLocal) {
  1434. *SharedInfoP = *((BTLIB_SHARED_INFO_TYPE *)BTLIB_MEMBER_PTR(pTLS, SharedInfo));
  1435. status = STATUS_SUCCESS;
  1436. }
  1437. else {
  1438. status = NtReadVirtualMemory(ProcessHandle,
  1439. BTLIB_MEMBER_PTR(pTLS, SharedInfo),
  1440. SharedInfoP,
  1441. sizeof(*SharedInfoP),
  1442. NULL);
  1443. if (status != STATUS_SUCCESS) {
  1444. BTLP_REPORT_NT_FAILURE("NtReadVirtualMemory", status);
  1445. }
  1446. else if (!BTLIB_SI_CHECK_SIGNATURE(SharedInfoP)) {
  1447. DBCODE (TRUE, BtlpPrintf("\nwowIA32X.dll Signature mismatch!!!!\n"));
  1448. status = STATUS_UNSUCCESSFUL;
  1449. }
  1450. }
  1451. return status;
  1452. }
  1453. static NTSTATUS BtlpWriteSuspendRequest(
  1454. IN HANDLE ProcessHandle,
  1455. IN PVOID pTLS,
  1456. IN BOOL IsLocal,
  1457. IN BTLIB_SUSPEND_REQUEST * SuspendRequestP
  1458. )
  1459. /*++
  1460. Routine Description:
  1461. Write BTLIB_SUSPEND_REQUEST to a local or remote thread.
  1462. Arguments:
  1463. ProcessHandle - Process handle
  1464. pTLS - pointer to BT_TLS of a local/remote thread
  1465. IsLocal - TRUE for local thread
  1466. SharedInfoP - buffer to write BTLIB_SUSPEND_REQUEST from
  1467. Return Value:
  1468. NTSTATUS
  1469. --*/
  1470. {
  1471. NTSTATUS status;
  1472. if (IsLocal) {
  1473. *((BTLIB_SUSPEND_REQUEST *)BTLIB_MEMBER_PTR(pTLS, SharedInfo.SuspendRequest)) = *SuspendRequestP;
  1474. status = STATUS_SUCCESS;
  1475. }
  1476. else {
  1477. status = NtWriteVirtualMemory(ProcessHandle,
  1478. BTLIB_MEMBER_PTR(pTLS, SharedInfo.SuspendRequest),
  1479. SuspendRequestP,
  1480. sizeof(*SuspendRequestP),
  1481. NULL);
  1482. BTLP_REPORT_NT_FAILURE("NtWriteVirtualMemory", status);
  1483. }
  1484. return status;
  1485. }
  1486. static NTSTATUS BtlpSendSuspensionRequest(
  1487. IN HANDLE ProcessHandle,
  1488. IN HANDLE ThreadHandle,
  1489. IN PVOID pTLS,
  1490. IN BOOL IsLocal,
  1491. IN CONTEXT * ResumeContextP,
  1492. IN OUT PULONG PreviousSuspendCountP
  1493. )
  1494. /*++
  1495. Routine Description:
  1496. The function is called when the target thread is ready to perform self-canonization
  1497. and exit simulation.
  1498. The function fills in BTLIB_SUSPEND_REQUEST, resumes target thread and suspends
  1499. it in a consistent state.
  1500. Caller is responsible for serialization of SUSPEND_REQUESTs.
  1501. Arguments:
  1502. ProcessHandle - target process handle
  1503. ThreadHandle - target thread handle
  1504. pTLS - pointer to BT_TLS of a local/remote thread
  1505. IsLocal - TRUE for local thread
  1506. ResumeContextP - IA64 context to resume target thread for self-canonization
  1507. PreviousSuspendCountP - IN OUT pointer to thread's previous suspend count.
  1508. Return Value:
  1509. NTSTATUS
  1510. --*/
  1511. {
  1512. NTSTATUS status;
  1513. BTLIB_SUSPEND_REQUEST SuspendRequest;
  1514. HANDLE ReadyEvent = INVALID_HANDLE_VALUE;
  1515. HANDLE ResumeEvent = INVALID_HANDLE_VALUE;
  1516. HANDLE WaitArray[2];
  1517. //This function call must be serialized
  1518. assert(*PreviousSuspendCountP ==0);
  1519. SuspendRequest.ReadyEvent = INVALID_HANDLE_VALUE;
  1520. SuspendRequest.ResumeEvent = INVALID_HANDLE_VALUE;
  1521. do {
  1522. //Prepare SUSPEND_REQUEST for sending to the target process
  1523. //Create pair of synchronization events in current process and duplicate
  1524. //them to the target process
  1525. status = NtCreateEvent(&ReadyEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
  1526. if (status != STATUS_SUCCESS) {
  1527. BTLP_REPORT_NT_FAILURE("NtCreateEvent", status);
  1528. break;
  1529. }
  1530. status = NtCreateEvent(&ResumeEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
  1531. if (status != STATUS_SUCCESS) {
  1532. BTLP_REPORT_NT_FAILURE("NtCreateEvent", status);
  1533. break;
  1534. }
  1535. status = NtDuplicateObject(NtCurrentProcess(),
  1536. ReadyEvent,
  1537. ProcessHandle,
  1538. &(SuspendRequest.ReadyEvent),
  1539. 0,
  1540. FALSE,
  1541. DUPLICATE_SAME_ACCESS);
  1542. if (status != STATUS_SUCCESS) {
  1543. BTLP_REPORT_NT_FAILURE("NtDuplicateObject", status);
  1544. break;
  1545. }
  1546. status = NtDuplicateObject(NtCurrentProcess(),
  1547. ResumeEvent,
  1548. ProcessHandle,
  1549. &(SuspendRequest.ResumeEvent),
  1550. 0,
  1551. FALSE,
  1552. DUPLICATE_SAME_ACCESS);
  1553. if (status != STATUS_SUCCESS) {
  1554. BTLP_REPORT_NT_FAILURE("NtDuplicateObject", status);
  1555. break;
  1556. }
  1557. // First write SUSPEND_REQUEST to the the target thread,
  1558. // tnen set ContextIA64 and resume target thread.
  1559. // The order is important! The BtlpEnsureSuspensionConsistency function
  1560. // relies on that.
  1561. SuspendRequest.Active = TRUE;
  1562. status = BtlpWriteSuspendRequest(ProcessHandle, pTLS, IsLocal, &SuspendRequest);
  1563. if (status != STATUS_SUCCESS) {
  1564. //Sending request failed, do not try to remove it.
  1565. SuspendRequest.Active = FALSE;
  1566. break;
  1567. }
  1568. status = NtSetContextThread(ThreadHandle, ResumeContextP);
  1569. if (status != STATUS_SUCCESS) {
  1570. //abort request and report failure.
  1571. BTLP_REPORT_NT_FAILURE("NtSetContextThread", status);
  1572. break;
  1573. }
  1574. status = NtResumeThread(ThreadHandle, NULL);
  1575. if (status != STATUS_SUCCESS) {
  1576. //abort request and report failure.
  1577. BTLP_REPORT_NT_FAILURE("NtResumeThread", status);
  1578. break;
  1579. }
  1580. //Wait until remote thread receives request or dies
  1581. WaitArray[0] = ThreadHandle;
  1582. WaitArray[1] = ReadyEvent;
  1583. status = NtWaitForMultipleObjects(2, WaitArray, WaitAny, FALSE, NULL);
  1584. if (status == STATUS_WAIT_0) {
  1585. //the target thread is died along with its event handles.
  1586. //No need to remove request.
  1587. BTLP_REPORT_NT_FAILURE("NtWaitForMultipleObjects", status);
  1588. SuspendRequest.ReadyEvent = INVALID_HANDLE_VALUE;
  1589. SuspendRequest.ResumeEvent = INVALID_HANDLE_VALUE;
  1590. SuspendRequest.Active = FALSE;
  1591. }
  1592. //Suspend target thread and signal the ResumeEvent event to release
  1593. //target thread after it will be awaken (later on)
  1594. status = NtSuspendThread(ThreadHandle, PreviousSuspendCountP);
  1595. if (status != STATUS_SUCCESS) {
  1596. //remove request and report failure.
  1597. BTLP_REPORT_NT_FAILURE("NtSuspendThread", status);
  1598. break;
  1599. }
  1600. status = NtSetEvent(ResumeEvent, NULL);
  1601. BTLP_REPORT_NT_FAILURE("NtSetEvent", status);
  1602. } while (FALSE);
  1603. //Close local event handles
  1604. if (ReadyEvent != INVALID_HANDLE_VALUE) {
  1605. NtClose(ReadyEvent);
  1606. }
  1607. if (ResumeEvent != INVALID_HANDLE_VALUE) {
  1608. NtClose(ResumeEvent);
  1609. }
  1610. //Close remote event handles if needed
  1611. if (status != STATUS_SUCCESS) {
  1612. if (SuspendRequest.ReadyEvent != INVALID_HANDLE_VALUE) {
  1613. NtDuplicateObject(ProcessHandle,
  1614. SuspendRequest.ReadyEvent,
  1615. NtCurrentProcess(),
  1616. &ReadyEvent,
  1617. EVENT_ALL_ACCESS,
  1618. FALSE,
  1619. DUPLICATE_CLOSE_SOURCE);
  1620. NtClose(ReadyEvent);
  1621. SuspendRequest.ReadyEvent = INVALID_HANDLE_VALUE;
  1622. }
  1623. if (SuspendRequest.ResumeEvent != INVALID_HANDLE_VALUE) {
  1624. NtDuplicateObject(ProcessHandle,
  1625. SuspendRequest.ResumeEvent,
  1626. NtCurrentProcess(),
  1627. &ResumeEvent,
  1628. EVENT_ALL_ACCESS,
  1629. FALSE,
  1630. DUPLICATE_CLOSE_SOURCE);
  1631. NtClose(ResumeEvent);
  1632. SuspendRequest.ResumeEvent = INVALID_HANDLE_VALUE;
  1633. }
  1634. }
  1635. //Close SUSPEND_REQUEST
  1636. if (SuspendRequest.Active) {
  1637. SuspendRequest.Active = FALSE;
  1638. BtlpWriteSuspendRequest(ProcessHandle, pTLS, IsLocal, &SuspendRequest);
  1639. }
  1640. return status;
  1641. }
  1642. static NTSTATUS BtlpReceiveSuspensionRequest()
  1643. /*++
  1644. Routine Description:
  1645. The function handles active SUSPEND_REQUEST sent to this thread by
  1646. another thread. It notifies request sender about reaching the point
  1647. where suspension is possible and waits for real suspension to be
  1648. performed by the request's sender.
  1649. Arguments:
  1650. none
  1651. Return Value:
  1652. NTSTATUS
  1653. --*/
  1654. {
  1655. NTSTATUS status;
  1656. HANDLE ReadyEvent;
  1657. HANDLE ResumeEvent;
  1658. //local SUSPEND_REQUEST should be active at this point
  1659. assert(BTLIB_INFO_PTR()->SharedInfo.SuspendRequest.Active);
  1660. //Copy events from SUSPEND_REQUEST to local vars. It is important
  1661. //because after suspend/resume the event handles should be closed but
  1662. //SUSPEND_REQUEST could be rewritten
  1663. ReadyEvent = BTLIB_INFO_PTR()->SharedInfo.SuspendRequest.ReadyEvent;
  1664. ResumeEvent = BTLIB_INFO_PTR()->SharedInfo.SuspendRequest.ResumeEvent;
  1665. assert ((ReadyEvent != INVALID_HANDLE_VALUE) && (ResumeEvent != INVALID_HANDLE_VALUE));
  1666. //Release ReadyEvent and wait for ResumeEvent. The thread can be
  1667. //suspended at this point
  1668. status = NtSignalAndWaitForSingleObject(ReadyEvent, ResumeEvent, FALSE, NULL);
  1669. //Close local event handles
  1670. NtClose(ReadyEvent);
  1671. NtClose(ResumeEvent);
  1672. return status;
  1673. }
  1674. // Wow64CPU forwarded APIs implementations:
  1675. // Note that all names are defined with PTAPI() macro which adds either BTCpu or Cpu prefix,
  1676. // depending on the mode we build the DLL.
  1677. // In release mode all names will be BTCpu only.
  1678. WOW64BT_IMPL NTSTATUS BTAPI(ProcessInit)(
  1679. PWSTR pImageName,
  1680. PSIZE_T pCpuThreadDataSize)
  1681. /*++
  1682. Routine Description:
  1683. Per-process initialization code
  1684. Locates, reads and parses parameters file BTrans.ini
  1685. Locates, load and initializes IA32Exec.bin component
  1686. Arguments:
  1687. pImageName - IN the name of the image. The memory for this
  1688. is freed after the call, so if the callee wants
  1689. to keep the name around, they need to allocate space
  1690. and copy it. DON'T SAVE THE POINTER!
  1691. pCpuThreadSize - OUT ptr to number of bytes of memory the CPU
  1692. wants allocated for each thread.
  1693. Return Value:
  1694. NTSTATUS.
  1695. --*/
  1696. {
  1697. char * argv[128] = { NULL };
  1698. int argc = 1;
  1699. static WCHAR CurrentDir[1024];
  1700. HANDLE BTGenericHandle;
  1701. int fBTGenericFound;
  1702. #ifdef OVERRIDE_TIA
  1703. HANDLE BtlpOverrideTiaFile = INVALID_HANDLE_VALUE;
  1704. OBJECT_ATTRIBUTES oa;
  1705. IO_STATUS_BLOCK iosb;
  1706. LARGE_INTEGER as = { 0, 0 }, offst = { 0, 0 };
  1707. #endif /* OVERRIDE_TIA */
  1708. {
  1709. // Temporary workaround for IA32 debugging support.
  1710. //To be removed after fixing FlushIC(ProcessHandle) by MS.
  1711. NTSTATUS status;
  1712. PROCESS_BASIC_INFORMATION info;
  1713. //Check to see if current process is being debugged
  1714. status = BtlpGetProcessInfo(NtCurrentProcess(), &info);
  1715. BeingDebugged = ((status == STATUS_SUCCESS) &&
  1716. (info.PebBaseAddress->BeingDebugged));
  1717. }
  1718. RtlGetCurrentDirectory_U(512, CurrentDir);
  1719. // Load IA32Exec.bin ...
  1720. fBTGenericFound = BtlpLoadBTGeneric(CurrentDir, &BTGenericHandle);
  1721. if (F_NOT_FOUND == fBTGenericFound) {
  1722. return STATUS_NOT_FOUND;
  1723. }
  1724. #ifndef RELEASE
  1725. // Load parameters file
  1726. {
  1727. UNICODE_STRING IniFileName, LogFileName;
  1728. HANDLE IniFileHandle = INVALID_HANDLE_VALUE;
  1729. OBJECT_ATTRIBUTES ObjectAttributes;
  1730. IO_STATUS_BLOCK IoStatusBlock;
  1731. LARGE_INTEGER AllocSz = { 0, 0 }, Offset = { 0, 0 };
  1732. char IniBuffer[8192] = "";
  1733. char IniArgs[8192], * IniArgsP = IniArgs;
  1734. WCHAR LogFileFullPath[1024], LogName[64];
  1735. if (wcslen (pImageName) >= sizeof (ImageName) / sizeof (ImageName[0])) {
  1736. swprintf (ImageName, L"%s", "dummyImage");
  1737. }
  1738. else {
  1739. swprintf (ImageName, L"%s", pImageName);
  1740. }
  1741. // Locate and scan INI file, extract parameters
  1742. if (F_NOT_FOUND != BtlpIniFileExists(CurrentDir, fBTGenericFound, &IniFileHandle)) {
  1743. int ret;
  1744. ret = NtReadFile(IniFileHandle, NULL, NULL, NULL, &IoStatusBlock, (VOID *)IniBuffer, 8192, &Offset, NULL);
  1745. if ( ret == STATUS_END_OF_FILE || ret == STATUS_SUCCESS ) {
  1746. char * CurrentChar;
  1747. static char logparm[] = "log";
  1748. static char logdirparm[] = "logdir";
  1749. #ifdef OVERRIDE_TIA
  1750. static char ovrtiaparm[] = "override_tia=";
  1751. #endif
  1752. #ifndef NODEBUG
  1753. static char PerthreadParm[] = "logfile_per_thread";
  1754. #endif
  1755. static char DebugBtransParm[] = "debug_btrans";
  1756. // Close file (assuming everything has been read in one piece)
  1757. NtClose(IniFileHandle);
  1758. LogDirName[0] = '\0';
  1759. LogDirName[1] = '\0';
  1760. // Mark end of the text
  1761. CurrentChar = IniBuffer;
  1762. CurrentChar[IoStatusBlock.Information] = '\0';
  1763. // Scan until end of file
  1764. while ( *CurrentChar != '\0' ) {
  1765. char *EndOfLineChar;
  1766. // Locate and handle end of line
  1767. if (EndOfLineChar = strchr(CurrentChar+1, '\n')) {
  1768. // Remove \r before, if one present
  1769. if (*(EndOfLineChar-1) == '\r') {
  1770. *(EndOfLineChar-1) = '\0';
  1771. }
  1772. // Replace \n by \0
  1773. *EndOfLineChar++ = '\0';
  1774. }
  1775. #ifndef NODEBUG
  1776. if (_strnicmp(CurrentChar, PerthreadParm, sizeof (PerthreadParm) - 1) == 0) {
  1777. CurrentChar += (sizeof (PerthreadParm) - 1);
  1778. if (BtlpWow64LogFile == INVALID_HANDLE_VALUE) {
  1779. BtlpLogFilePerThread = TRUE;
  1780. swprintf(BtlpLogFileFullPath, L"\\DosDevices\\%s\\%s", CurrentDir, pImageName);
  1781. }
  1782. } else
  1783. #endif
  1784. if (_strnicmp(CurrentChar, DebugBtransParm, sizeof (DebugBtransParm) - 1) == 0) {
  1785. CurrentChar += (sizeof (DebugBtransParm) - 1);
  1786. //ignore application debugging when debugging IA-32 Execution layer
  1787. BeingDebugged = FALSE;
  1788. }
  1789. else if ( _strnicmp(CurrentChar, logdirparm, sizeof (logdirparm) - 1) == 0 ) {
  1790. WCHAR *pl;
  1791. CurrentChar += (sizeof (logdirparm) - 1);
  1792. // log directory specified
  1793. if (*CurrentChar == '=' && *(CurrentChar+1) != '\0') {
  1794. // Name present as well
  1795. CurrentChar++;
  1796. pl = LogDirName;
  1797. while ( (WCHAR)*CurrentChar != (WCHAR)'\0' ) {
  1798. *pl = (WCHAR)*CurrentChar;
  1799. pl++;
  1800. CurrentChar++;
  1801. }
  1802. *pl = (WCHAR)'\0';
  1803. }
  1804. else {
  1805. BtlpPrintf("logdir specified without =<dirname>, IGNORED\n");
  1806. }
  1807. }
  1808. // Process and skip "log" parameter
  1809. else if ( _strnicmp(CurrentChar, logparm, sizeof (logparm) - 1) == 0 ) {
  1810. WCHAR *pl;
  1811. CurrentChar += (sizeof (logparm) - 1);
  1812. // log required - prepare log file name
  1813. if (*CurrentChar == '=' && *(CurrentChar+1) != '\0') {
  1814. // Name present as well
  1815. CurrentChar++;
  1816. pl = LogName;
  1817. while ( (WCHAR)*CurrentChar != (WCHAR)'\0') {
  1818. *pl++ = (WCHAR)*CurrentChar++;
  1819. }
  1820. *pl = (WCHAR)'\0';
  1821. }
  1822. else {
  1823. // No name - use ImageName.log
  1824. swprintf(LogName, L"%s.log", pImageName);
  1825. }
  1826. // Create log file
  1827. if (0==LogDirName[0] && 0==LogDirName[1]) {
  1828. swprintf(LogFileFullPath, L"\\DosDevices\\%s\\%s", CurrentDir, LogName);
  1829. }
  1830. else {
  1831. swprintf(LogFileFullPath, L"\\DosDevices\\%s\\%s", LogDirName, LogName);
  1832. }
  1833. RtlInitUnicodeString(&LogFileName, LogFileFullPath);
  1834. InitializeObjectAttributes(&ObjectAttributes, &LogFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
  1835. ret = NtCreateFile(&BtlpWow64LogFile, FILE_GENERIC_WRITE,
  1836. &ObjectAttributes, &IoStatusBlock,
  1837. &AllocSz, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_SUPERSEDE,
  1838. FILE_NON_DIRECTORY_FILE|FILE_RANDOM_ACCESS|FILE_SYNCHRONOUS_IO_NONALERT,
  1839. NULL, 0);
  1840. if ( ret != STATUS_SUCCESS ) {
  1841. BtlpWow64LogFile = INVALID_HANDLE_VALUE;
  1842. // BtlpPrintf("Can't create LOG file %S: status=%X\n", LogFileFullPath, ret);
  1843. }
  1844. #ifndef NODEBUG
  1845. BtlpLogFilePerThread = FALSE;
  1846. #endif
  1847. }
  1848. #ifdef OVERRIDE_TIA
  1849. // Process and skip "override_tia=..." parameter
  1850. else if ( _strnicmp(CurrentChar, ovrtiaparm, sizeof(ovrtiaparm) - 1) == 0 ) {
  1851. WCHAR * pl;
  1852. WCHAR OvrTiaFileName[64], OvrTiaFileFullPath[1024];
  1853. UNICODE_STRING OvrTiaFile;
  1854. CurrentChar += (sizeof(ovrtiaparm) - 1);
  1855. if ( *CurrentChar == '\0') {
  1856. BtlpPrintf("Name of override TIA file not specfied\n");
  1857. continue;
  1858. }
  1859. // prepare override TIA file name
  1860. pl = OvrTiaFileName;
  1861. while ( (WCHAR)*CurrentChar != (WCHAR)'\0') {
  1862. *pl++ = (WCHAR)*CurrentChar++;
  1863. }
  1864. *pl = (WCHAR)'\0';
  1865. // Open override TIA file; so far - only in current dir
  1866. swprintf(OvrTiaFileFullPath, L"\\DosDevices\\%s\\%s", CurrentDir, OvrTiaFileName);
  1867. RtlInitUnicodeString(&OvrTiaFile, OvrTiaFileFullPath);
  1868. InitializeObjectAttributes(&oa, &OvrTiaFile, OBJ_CASE_INSENSITIVE, NULL, NULL);
  1869. //Do not use synchronized access as it blocks forever in case of thread suspension
  1870. ret = NtCreateFile(&BtlpOverrideTiaFile, FILE_GENERIC_READ, &oa, &iosb, &as,
  1871. FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
  1872. FILE_NON_DIRECTORY_FILE|FILE_RANDOM_ACCESS|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
  1873. if ( ret != STATUS_SUCCESS ) {
  1874. BtlpOverrideTiaFile = INVALID_HANDLE_VALUE;
  1875. DBCODE(TRUE, BtlpPrintf("Can't open override TIA file %S: status=%X\n", OvrTiaFileFullPath, ret));
  1876. } else {
  1877. DBCODE(TRUE, BtlpPrintf("Override TIA will be loaded from file %S\n", OvrTiaFileFullPath));
  1878. }
  1879. }
  1880. #endif /* OVERRIDE_TIA */
  1881. else if ( *CurrentChar != '\0' && *CurrentChar != ';' ) {
  1882. // Add next control directive to the pseudo-argv array
  1883. argv[argc] = IniArgsP;
  1884. *IniArgsP++ = '-';
  1885. strcpy(IniArgsP, CurrentChar);
  1886. IniArgsP += (strlen (IniArgsP) + 1);
  1887. argc++; // We assume there are no extra chars, spaces, etc!!!!
  1888. }
  1889. // Next parameter
  1890. if (EndOfLineChar) {
  1891. CurrentChar = EndOfLineChar;
  1892. }
  1893. else {
  1894. break;
  1895. }
  1896. }
  1897. }
  1898. else {
  1899. BtlpPrintf("Can't read INI file: status=%X\n", ret);
  1900. }
  1901. }
  1902. else {
  1903. DBCODE (TRUE, BtlpPrintf("Can't open INI file\n"));
  1904. }
  1905. }
  1906. #endif /* RELEASE */
  1907. DBCODE(TRUE, BtlpPrintf("\nCpuProcessInit: Unique ProcessId = 0x%I64X\n", BT_CURRENT_PROC_UID()));
  1908. // Locate, load and initialize IA32Exec.bin component
  1909. {
  1910. BT_STATUS_CODE BtStatus;
  1911. NTSTATUS status;
  1912. static char APITableName[] = "BtgAPITable";
  1913. static ANSI_STRING APITableString = { sizeof (APITableName) - 1,
  1914. sizeof (APITableName) - 1,
  1915. APITableName };
  1916. PVOID BtransAPITableStart;
  1917. //DBCODE (TRUE, BtlpPrintf ("\nLOADED: HANDLE=%p\n", BTGenericHandle));
  1918. assert (F_NOT_FOUND != fBTGenericFound);
  1919. assert (INVALID_HANDLE_VALUE != BTGenericHandle);
  1920. // Locate IA32Exec.bin API table
  1921. status = LdrGetProcedureAddress(BTGenericHandle, &APITableString, 0, &BtransAPITableStart);
  1922. if (status != STATUS_SUCCESS) {
  1923. return status;
  1924. }
  1925. //DBCODE (TRUE, BtlpPrintf ("\nTABLE AT: %p, status=%X\n", BtransAPITableStart, status));
  1926. // Perform the API table initialization
  1927. BtlInitializeTables(BtransAPITableStart);
  1928. // initialize IA32Exec.bin placeholder table
  1929. {
  1930. extern PLABEL_PTR_TYPE __imp_setjmp;
  1931. extern PLABEL_PTR_TYPE __imp_longjmp;
  1932. BtlAPITable.APITable[IDX_BTLIB_SETJMP].PLabelPtr = __imp_setjmp;
  1933. BtlAPITable.APITable[IDX_BTLIB_LONGJMP].PLabelPtr = __imp_longjmp;
  1934. // DBCODE (FALSE, BtlpPrintf ("SETJMP: %p [%p %p] = %p [%p %p]",
  1935. // BtlAPITable.APITable[IDX_BTLIB_SETJMP].PLabelPtr,
  1936. // ((VOID **)(BtlAPITable.APITable[IDX_BTLIB_SETJMP].PLabelPtr))[0],
  1937. // ((VOID **)(BtlAPITable.APITable[IDX_BTLIB_SETJMP].PLabelPtr))[1],
  1938. // __imp_setjmp,
  1939. // ((VOID **)__imp_setjmp)[0],
  1940. // ((VOID **)__imp_setjmp)[1]);
  1941. // BtlpPrintf ("LONGJMP: %p [%p %p] = %p [%p %p]",
  1942. // BtlAPITable.APITable[IDX_BTLIB_LONGJMP].PLabelPtr,
  1943. // ((VOID **)(BtlAPITable.APITable[IDX_BTLIB_LONGJMP].PLabelPtr))[0],
  1944. // ((VOID **)(BtlAPITable.APITable[IDX_BTLIB_LONGJMP].PLabelPtr))[1],
  1945. // __imp_longjmp,
  1946. // ((VOID **)__imp_longjmp)[0],
  1947. // ((VOID **)__imp_longjmp)[1]));
  1948. }
  1949. BtStatus = BTGENERIC_START(&BtlAPITable,
  1950. (ULONG_PTR)BTGenericHandle,
  1951. (ULONG_PTR)BTGenericHandle + BtlpExtractNTHeader(BTGenericHandle)->OptionalHeader.SizeOfImage,
  1952. BT_TLS_OFFSET,
  1953. &BtlpInfoOffset,
  1954. &BtlpGenericIA32ContextOffset);
  1955. if (BtStatus != BT_STATUS_SUCCESS) {
  1956. return (BtlpBt2NtStatusCode(BtStatus));
  1957. }
  1958. //DBCODE(TRUE, BtlpPrintf ("BTGENERIC_START returned size 0x%X\n", BtlpInfoOffset));
  1959. //DBCODE(TRUE, BtlpPrintf ("IA32Exec.bin will supply IA32 context on offset 0x%X\n", BtlpGenericIA32ContextOffset));
  1960. BtlpInfoOffset = (BtlpInfoOffset + BTLIB_INFO_ALIGNMENT - 1)&~((U32)(BTLIB_INFO_ALIGNMENT - 1));
  1961. //DBCODE(TRUE, BtlpPrintf ("Offset 0x%X\n", BtlpInfoOffset));
  1962. * pCpuThreadDataSize = BtlpInfoOffset + BTLIB_INFO_SIZE;
  1963. //DBCODE(TRUE, BtlpPrintf ("ProcessInit reports 0x%I64X\n",* pCpuThreadDataSize));
  1964. #ifdef OVERRIDE_TIA
  1965. if ( BtlpOverrideTiaFile != INVALID_HANDLE_VALUE ) {
  1966. unsigned char OvrTiaBuffer[0xffff],
  1967. * OverrideTIAData = (unsigned char *)NULL;
  1968. int ret;
  1969. ret = NtReadFile(BtlpOverrideTiaFile, NULL, NULL, NULL, &iosb, (VOID *)OvrTiaBuffer, 0xffff, &offst, NULL);
  1970. if ( ret == STATUS_SUCCESS || ret == STATUS_END_OF_FILE ) {
  1971. // File size is in iosb.Information
  1972. unsigned int OvrTiaSize = (unsigned int)iosb.Information;
  1973. DBCODE(TRUE, BtlpPrintf("Override TIA loaded successfully\n"));
  1974. OverrideTIAData = (unsigned char *)BtlMemoryAlloc(NULL, OvrTiaSize, MEM_READ|MEM_WRITE);
  1975. assert(OverrideTIAData != (unsigned char *)NULL);
  1976. memcpy(OverrideTIAData, OvrTiaBuffer, OvrTiaSize);
  1977. BTGENERIC_USE_OVERRIDE_TIA(OvrTiaSize, OverrideTIAData);
  1978. NtClose(BtlpOverrideTiaFile);
  1979. } else {
  1980. DBCODE(TRUE, BtlpPrintf("Override TIA data couldn't be loaded - read error!\n"));
  1981. }
  1982. }
  1983. #endif /* OVERRIDE_TIA */
  1984. BtStatus = BTGENERIC_DEBUG_SETTINGS(argc, argv);
  1985. if (BtStatus != BT_STATUS_SUCCESS) {
  1986. return (BtlpBt2NtStatusCode(BtStatus));
  1987. }
  1988. }
  1989. return STATUS_SUCCESS;
  1990. }
  1991. WOW64BT_IMPL NTSTATUS BTAPI(ProcessTerm)(
  1992. HANDLE hProcess
  1993. )
  1994. /*++
  1995. Routine Description:
  1996. Per-process termination code. Note that this routine may not be called,
  1997. especially if the process is terminated by another process.
  1998. Arguments:
  1999. Process ID or 0.
  2000. Return Value:
  2001. NTSTATUS.
  2002. --*/
  2003. {
  2004. // NtTerminateProcess called
  2005. DBCODE (FALSE, BtlpPrintf ("\nCalled NtTerminateProcess (Handle=0x%X, Code=0x%X)\n",
  2006. ((U32 *)UlongToPtr((BTLIB_CONTEXT_IA32_PTR()->Esp)))[1],
  2007. ((U32 *)UlongToPtr((BTLIB_CONTEXT_IA32_PTR()->Esp)))[2]));
  2008. // Consider which call is it
  2009. switch (((U32 *)UlongToPtr((BTLIB_CONTEXT_IA32_PTR()->Esp)))[1]) {
  2010. case 0: // Prepare to terminate
  2011. BTGENERIC_NOTIFY_PREPARE_EXIT ();
  2012. break;
  2013. case NtCurrentProcess(): // Actually terminate
  2014. BTGENERIC_NOTIFY_EXIT ();
  2015. if ( BtlpWow64LogFile != INVALID_HANDLE_VALUE) {
  2016. NtClose(BtlpWow64LogFile);
  2017. }
  2018. break;
  2019. default:
  2020. assert (!"Should not get to here!");
  2021. }
  2022. return STATUS_SUCCESS;
  2023. }
  2024. // IA32 JMPE instruction encoding
  2025. #pragma code_seg(".text")
  2026. static struct JMPECode {
  2027. U32 Align4;
  2028. U8 Align2[2];
  2029. U8 OpCode[2];
  2030. U32 CodeAddress;
  2031. U32 GPAddress;
  2032. } __declspec(allocate(".text")) const BtlpWow64JMPECode = {
  2033. 0,
  2034. {0, 0},
  2035. {0x0f, 0xb8}, // 0F B8
  2036. 0, // "code address"
  2037. 0 // "GP address"
  2038. };
  2039. #define WOW64_JMPE ((VOID *)&(BtlpWow64JMPECode.OpCode)) // start of JMPE instruction
  2040. WOW64BT_IMPL NTSTATUS BTAPI(ThreadInit)(
  2041. PVOID pPerThreadData
  2042. )
  2043. /*++
  2044. Routine Description:
  2045. Per-thread initialization code.
  2046. Arguments:
  2047. pPerThreadData - Pointer to zero-filled per-thread data with the
  2048. size returned from CpuProcessInit.
  2049. Return Value:
  2050. NTSTATUS.
  2051. --*/
  2052. {
  2053. BT_STATUS_CODE BtStatus;
  2054. NTSTATUS status;
  2055. PTEB pTEB;
  2056. PTEB32 pTEB32;
  2057. HANDLE ThreadHandle;
  2058. {
  2059. // Scan the workarea pages from top to bottom, so that higher addresses
  2060. // are accessed first. This enables correct handling of the IA64 stack
  2061. // guard page (workarea is actually allocated from IA64 stack).
  2062. char * ByteP = (char *)pPerThreadData + BtlpInfoOffset + BTLIB_INFO_SIZE;
  2063. *--ByteP = 0;
  2064. while (((ULONG_PTR)ByteP -= BtlMemoryPageSize ()) >= (ULONG_PTR)pPerThreadData) {
  2065. *ByteP = 0;
  2066. }
  2067. *(char *)pPerThreadData = 0;
  2068. }
  2069. pTEB = BT_CURRENT_TEB();
  2070. pTEB32 = BT_TEB32_OF(pTEB);
  2071. pTEB32->WOW32Reserved = (ULONG) ((UINT_PTR) WOW64_JMPE); // Below 4G always!
  2072. BTLIB_INIT_BLOCKED_LOG_FLAG();
  2073. #ifndef NODEBUG
  2074. if ( BtlpLogFilePerThread ) {
  2075. HANDLE hTemp;
  2076. WCHAR LogFileFullName[1024];
  2077. int ret;
  2078. static int SeqNum = 0;
  2079. UNICODE_STRING LogFileName;
  2080. OBJECT_ATTRIBUTES ObjectAttributes;
  2081. IO_STATUS_BLOCK IoStatusBlock;
  2082. LARGE_INTEGER AllocSz = { 0, 0 };
  2083. // Eric: Incrementing SeqNum should be replace with an atomatic operation in the future.
  2084. swprintf(LogFileFullName, L"%s.%x.log", BtlpLogFileFullPath, SeqNum++);
  2085. RtlInitUnicodeString(&LogFileName, LogFileFullName);
  2086. InitializeObjectAttributes(&ObjectAttributes, &LogFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
  2087. ret = NtCreateFile(&hTemp, FILE_GENERIC_WRITE,
  2088. &ObjectAttributes, &IoStatusBlock,
  2089. &AllocSz, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_SUPERSEDE,
  2090. FILE_NON_DIRECTORY_FILE|FILE_RANDOM_ACCESS|FILE_SYNCHRONOUS_IO_NONALERT,
  2091. NULL, 0);
  2092. if ( ret != STATUS_SUCCESS ) {
  2093. BTLIB_SET_LOG_FILE(INVALID_HANDLE_VALUE);
  2094. BtlpPrintf("Can't create LOG file %S: status=%X\n", LogFileFullName, ret);
  2095. } else {
  2096. BTLIB_SET_LOG_FILE(hTemp);
  2097. }
  2098. BTLIB_SET_LOG_OFFSET(0);
  2099. }
  2100. #endif
  2101. status = NtDuplicateObject(NtCurrentProcess(),
  2102. NtCurrentThread(),
  2103. NtCurrentProcess(),
  2104. &ThreadHandle,
  2105. ( THREAD_GET_CONTEXT
  2106. | THREAD_SET_CONTEXT
  2107. | THREAD_QUERY_INFORMATION
  2108. | THREAD_SET_INFORMATION
  2109. | THREAD_SUSPEND_RESUME),
  2110. 0,
  2111. DUPLICATE_SAME_ATTRIBUTES
  2112. );
  2113. if (status == STATUS_SUCCESS) {
  2114. BTLIB_SET_EXTERNAL_HANDLE(ThreadHandle);
  2115. DBCODE(TRUE, BtlpPrintf("\nCpuThreadInit: TEB=%p GLST=%p\n", pTEB, BT_TLS_OF(pTEB)));
  2116. BtStatus = BTGENERIC_THREAD_INIT(pPerThreadData, 0 , pTEB32);
  2117. if (BtStatus != BT_STATUS_SUCCESS) {
  2118. DBCODE(TRUE, BtlpPrintf("\nCpuThreadInit: Failed to initialize, BtStatus=%d\n", BtStatus));
  2119. DBCODE(BtlpLogFilePerThread, NtClose(BTLIB_LOG_FILE()));
  2120. NtClose(BTLIB_EXTERNAL_HANDLE());
  2121. NtTerminateThread(NtCurrentThread(),BtlpBt2NtStatusCode(BtStatus));
  2122. return BtlpBt2NtStatusCode(BtStatus);
  2123. }
  2124. }
  2125. else {
  2126. BTLP_REPORT_NT_FAILURE("NtDuplicateObject", status);
  2127. DBCODE(BtlpLogFilePerThread, NtClose(BTLIB_LOG_FILE()));
  2128. NtTerminateThread(NtCurrentThread(), status);
  2129. return status;
  2130. }
  2131. // Initialize thread context
  2132. BtlpInitIA32Context(BTLIB_CONTEXT_IA32_PTR(), pTEB32);
  2133. //if everithing is Ok, initialize shared info and sign it with BTL_SIGNATURE
  2134. status = BtlpInitSharedInfo();
  2135. return status;
  2136. }
  2137. WOW64BT_IMPL NTSTATUS BTAPI(ThreadTerm)(
  2138. VOID
  2139. )
  2140. /*++
  2141. Routine Description:
  2142. Per-thread termination code. Note that this routine may not be called,
  2143. especially if the thread is terminated abnormally.
  2144. Arguments:
  2145. None.
  2146. Return Value:
  2147. NTSTATUS.
  2148. --*/
  2149. {
  2150. DBCODE(TRUE, BtlpPrintf("\nCpuThreadTerm: TEB=%p GLST=%p)\n", BT_CURRENT_TEB(), BT_CURRENT_TLS()));
  2151. BTGENERIC_THREAD_TERMINATED ();
  2152. DBCODE(BtlpLogFilePerThread, NtClose(BTLIB_LOG_FILE()));
  2153. NtClose(BTLIB_EXTERNAL_HANDLE());
  2154. return STATUS_SUCCESS;
  2155. }
  2156. WOW64BT_IMPL VOID BTAPI(NotifyDllLoad)(
  2157. LPWSTR DllName,
  2158. PVOID DllBase,
  2159. ULONG DllSize
  2160. )
  2161. /*++
  2162. Routine Description:
  2163. This routine get notified when application successfully load a dll.
  2164. Arguments:
  2165. DllName - Name of the Dll the application has loaded.
  2166. DllBase - BaseAddress of the dll.
  2167. DllSize - size of the Dll.
  2168. Return Value:
  2169. None.
  2170. --*/
  2171. {
  2172. DBCODE (TRUE, BtlpPrintf ("\nModule %S loaded, base=0x%p, length=0x%08X\n", DllName, DllBase, DllSize));
  2173. BTGENERIC_REPORT_LOAD(DllBase, DllSize, DllName);
  2174. }
  2175. WOW64BT_IMPL VOID BTAPI(NotifyDllUnload)(
  2176. PVOID DllBase
  2177. )
  2178. /*++
  2179. Routine Description:
  2180. This routine get notified when application unload a dll.
  2181. Arguments:
  2182. DllBase - BaseAddress of the dll.
  2183. Return Value:
  2184. None.
  2185. --*/
  2186. {
  2187. DBCODE (TRUE, BtlpPrintf ("\nModule unloaded, base=0x%p", DllBase));
  2188. BTGENERIC_REPORT_UNLOAD(DllBase, 0 /* ? */, "UNKNOWN" /* ? */);
  2189. }
  2190. WOW64BT_IMPL VOID BTAPI(FlushInstructionCache)(
  2191. #ifndef BUILD_3604
  2192. IN HANDLE ProcessHandle,
  2193. #endif
  2194. IN PVOID BaseAddress,
  2195. IN ULONG Length,
  2196. IN WOW64_FLUSH_REASON Reason
  2197. )
  2198. /*++
  2199. Routine Description:
  2200. Notify IA32Exec.bin that the specified range of addresses has become invalid,
  2201. since some external code has altered whole or part of this range
  2202. Arguments:
  2203. BaseAddress - start of range to flush
  2204. Length - number of bytes to flush
  2205. Reason - reason of the flush
  2206. Return Value:
  2207. None.
  2208. --*/
  2209. {
  2210. BT_FLUSH_REASON BtFlushReason;
  2211. DBCODE (TRUE,
  2212. BtlpPrintf ("\n CpuFlushInstructionCache(BaseAddress=0x%p, Length=0x%X, Reason=%d)\n",
  2213. BaseAddress, (DWORD)Length, Reason));
  2214. #ifndef BUILD_3604
  2215. if (!BtlpIsCurrentProcess(ProcessHandle)) {
  2216. DBCODE (TRUE, BtlpPrintf ("\nDifferent process' handle=0x%p - rejected for now", ProcessHandle));
  2217. return;
  2218. }
  2219. #endif
  2220. BtFlushReason = BtlpWow2BtFlushReason(Reason);
  2221. if ((Reason == WOW64_FLUSH_FREE) && (Length == 0)) {
  2222. //In case of NtFreeVirtualMemory(..., MEM_RELEASE) , the Length parameter is zero.
  2223. //Calculate real region size to be freed.
  2224. SIZE_T RegionSize;
  2225. BOOL IsCommited;
  2226. RegionSize = BtlpGetMemAllocSize(BaseAddress, &IsCommited);
  2227. //Report zero legth for already decommited region - do not need flush in this case
  2228. if (IsCommited) {
  2229. Length = (U32)RegionSize;
  2230. if (RegionSize > (SIZE_T)Length) {
  2231. //region size is too big, return max. U32 value aligned to the page size
  2232. Length = (U32)(-(int)BtlMemoryPageSize());
  2233. }
  2234. }
  2235. }
  2236. BTGENERIC_FLUSH_IA32_INSTRUCTION_CACHE(BaseAddress, Length, BtFlushReason);
  2237. }
  2238. // Suspension handling
  2239. // SUSPENSION SYNCHRONIZATION RULES:
  2240. // a) there are two suspension commands:
  2241. // BtlSuspendThread - internal IA-32 Execution Layer function to suspend in-process threads
  2242. // CpuSuspendThread - called by WOW64 when simulating the system call.
  2243. // b) WOW64 guarantees that call to CpuSuspendThread is protected by a machine-wide mutex
  2244. // c) IA32Exec.bin guarantees that BtlSuspendThread call is protected by a process-wide mutex and
  2245. // suspension in the middle of the call is disabled
  2246. // d) IA32Exec.bin guarantees that target thread can not call to the CpuThreadSuspend function
  2247. // while the BtlSuspendThread(target_thread) function executes. It can be done by
  2248. // closing "simulation gates" before call to BtlSuspendThread.
  2249. //
  2250. // Conclusions:
  2251. // a) while a thread executes suspension command, it can not be suspended by
  2252. // another thread.
  2253. // b) there are at most two concurrent suspension function calls for the same target
  2254. // thread: internal and simulated.
  2255. static NTSTATUS BtlpEnsureSuspensionConsistency (
  2256. IN HANDLE ThreadHandle,
  2257. IN HANDLE ProcessHandle,
  2258. IN PTEB pTEB,
  2259. IN U32 TryCounter,
  2260. IN OUT PULONG PreviousSuspendCountP)
  2261. /*++
  2262. Routine Description:
  2263. Helper function for consistent suspension of the thread
  2264. Called when the thread is suspended, and it is guaranteed that the thread
  2265. is not the current one
  2266. Arguments:
  2267. ThreadHandle - IN thread's handle
  2268. ProcessHandle - IN process' handle
  2269. pTEB - IN pointer to thread's TEB
  2270. TryCounter - IN maximum attempts counter (0 means infinity)
  2271. PreviousSuspendCountP - IN OUT pointer to thread's previous suspend count.
  2272. The referenced value is updated if the function succeeds
  2273. Return Value:
  2274. NTSTATUS
  2275. --*/
  2276. {
  2277. NTSTATUS status;
  2278. U32 NumAttempts = 1;
  2279. ULONG PrevSuspended = *PreviousSuspendCountP;
  2280. PVOID GlstP;
  2281. BOOL IsLocal;
  2282. //Is this a local suspend function?
  2283. IsLocal = BtlpIsCurrentProcess(ProcessHandle);
  2284. // Temporary workaround for IA32 debugging support.
  2285. //When debugger calls SuspendThread, the remote thread is blocked
  2286. //(by kernel???) even after NtResumeThread, so an attempt to establish
  2287. //a handshake protocol with this thread fails.
  2288. //To be removed after MS fix.
  2289. if (!IsLocal) {
  2290. return STATUS_SUCCESS;
  2291. }
  2292. //Get TLS pointer of the target thread
  2293. GlstP = BtlpGetTlsPtr(ProcessHandle, pTEB, IsLocal);
  2294. if (GlstP == NULL) {
  2295. return STATUS_ACCESS_VIOLATION;
  2296. }
  2297. for (;;) { //While target thread is not suspended in a consistent state
  2298. BT_THREAD_SUSPEND_STATE CanonizeResult;
  2299. CONTEXT ContextIA64;
  2300. BTLIB_SHARED_INFO_TYPE SharedInfo;
  2301. // First retrieve ContextIA64 and tnen get the shared info of the target thread.
  2302. // The order is important! It guarantees that either:
  2303. // a) we got ContextIA64 before context change in a concurrent SUSPENSION_REQUEST or
  2304. // b) BTLIB_SI_HAS_SUSPEND_REQUEST(&SharedInfo) == TRUE
  2305. ContextIA64.ContextFlags = CONTEXT_FULL;
  2306. status = NtGetContextThread(ThreadHandle, &ContextIA64);
  2307. if (status != STATUS_SUCCESS) {
  2308. BTLP_REPORT_NT_FAILURE("NtGetContextThread", status);
  2309. break;
  2310. }
  2311. status = BtlpReadSharedInfo(ProcessHandle, GlstP, IsLocal, &SharedInfo);
  2312. if (status != STATUS_SUCCESS) {
  2313. break;
  2314. }
  2315. //Check suspension conditions:
  2316. //a)do not suspend thread if SUSPENSION_DISABLED or in the middle of
  2317. // another SUSPEND_REQUEST
  2318. //b)ask IA32Exec.bin in all other cases
  2319. if (BTLIB_SI_SUSPENSION_DISABLED(&SharedInfo) ||
  2320. (BTLIB_SI_HAS_SUSPEND_REQUEST(&SharedInfo))) {
  2321. // suspension is currently impossible. Resume and try again
  2322. ;
  2323. }
  2324. else {
  2325. //(BTLIB_SI_HAS_SUSPEND_REQUEST(&SharedInfo) == FALSE, so....
  2326. //Although real value of the BTLIB_SI_HAS_SUSPEND_REQUEST can be changed
  2327. //by a concurrent SUSPENSION_REQUEST, ContextIA64 has been taken before
  2328. //start of the SUSPENSION_REQUEST. If this is a case
  2329. //(there is a concurrent SUSPENSION_REQUEST), we will come up with
  2330. //( PrevSuspended > 0) && (CanonizeResult == BAD_SUSPEND_STATE).
  2331. //It means that we will wait for completion of the SUSPENSION_REQUEST,
  2332. //which is Ok.
  2333. // ask IA32Exec.bin to canonize context.Notice, if PrevSuspended>0, IA32Exec.bin
  2334. // only checks possibility of canonization but does not cahange thing
  2335. // in the thread context
  2336. CanonizeResult = (IsLocal ?
  2337. BTGENERIC_CANONIZE_SUSPEND_CONTEXT(GlstP, &ContextIA64, PrevSuspended) :
  2338. BTGENERIC_CANONIZE_SUSPEND_CONTEXT_REMOTE(ProcessHandle, GlstP, &ContextIA64, PrevSuspended));
  2339. // Analyze canonization result
  2340. if (CanonizeResult == SUSPEND_STATE_CONSISTENT) {
  2341. status = STATUS_SUCCESS; //confirm suspension
  2342. break;
  2343. }
  2344. else if (CanonizeResult == SUSPEND_STATE_CANONIZED) {
  2345. //BTGENERIC_CANONIZE_SUSPEND_CONTEXT guarantees that
  2346. //(CanonizeResult == SUSPEND_STATE_CANONIZED) -> ( PrevSuspended == 0)
  2347. assert( PrevSuspended == 0);
  2348. //record updated IA64 state
  2349. status = NtSetContextThread(ThreadHandle, &ContextIA64);
  2350. BTLP_REPORT_NT_FAILURE("NtSetContextThread", status);
  2351. break;
  2352. }
  2353. else if (CanonizeResult == SUSPEND_STATE_READY_FOR_CANONIZATION) {
  2354. //target thread is ready to canonize itself and exit simulation;
  2355. //lets send SUSPEND_REQUEST that will suspend the target thread
  2356. //just on the simulation exit
  2357. //BTGENERIC_CANONIZE_SUSPEND_CONTEXT guarantees that
  2358. //(CanonizeResult == SUSPEND_STATE_READY_FOR_CANONIZATION) -> ( PrevSuspended == 0)
  2359. assert( PrevSuspended == 0);
  2360. //the (PrevSuspended == 0) && !(BTLIB_SI_HAS_SUSPEND_REQUEST)
  2361. //condition guarantees serialization of SUSPEND_REQUESTs
  2362. //targeted to the same thread.
  2363. status = BtlpSendSuspensionRequest(ProcessHandle,
  2364. ThreadHandle,
  2365. GlstP,
  2366. IsLocal,
  2367. &ContextIA64,
  2368. &PrevSuspended);
  2369. break;
  2370. }
  2371. else if (CanonizeResult == SUSPEND_STATE_INACCESIBLE) {
  2372. //fatal error
  2373. status = STATUS_UNSUCCESSFUL;
  2374. break;
  2375. }
  2376. else {
  2377. assert(CanonizeResult == BAD_SUSPEND_STATE);
  2378. // suspension is currently impossible. Resume and try again
  2379. }
  2380. }
  2381. if ((TryCounter != 0) && (NumAttempts >= TryCounter)) {
  2382. // TryCounter reached
  2383. status = STATUS_UNSUCCESSFUL; //reject suspension
  2384. break;
  2385. }
  2386. //Next attempt
  2387. status = NtResumeThread(ThreadHandle, NULL);
  2388. if (status != STATUS_SUCCESS) {
  2389. BTLP_REPORT_NT_FAILURE("NtResumeThread", status);
  2390. break;
  2391. }
  2392. DBCODE(TRUE, BtlpPrintf ("\n%s BtlpEnsureSuspensionConsistency: canonization failed, yield... ,"
  2393. "Target TEB = %p Caller TEB = %p PreviousSuspendCount=0x%I64X NumAttempts = %d\n",
  2394. (IsLocal ? "Local" : "Remote"), pTEB, BT_CURRENT_TEB(), PrevSuspended, NumAttempts));
  2395. NtYieldExecution ();
  2396. /*
  2397. {
  2398. LARGE_INTEGER DelayInterval = { -10000*1000, -1 }; // negative: 1000ms * 10000
  2399. NtDelayExecution (FALSE, &DelayInterval);
  2400. }
  2401. */
  2402. // Stop the thread again
  2403. status = NtSuspendThread(ThreadHandle, &PrevSuspended);
  2404. // While the thread executes this function, it can not be suspended in a consistent
  2405. // state. It is guaranteed by the SUSPENSION SYNCHRONIZATION RULES(see above).
  2406. // It means that target thread, which is now in a non-consistent state,
  2407. // can not be in unintentionally "frozen" by a third thread.
  2408. if (status != STATUS_SUCCESS) {
  2409. BTLP_REPORT_NT_FAILURE("NtSuspendThread", status);
  2410. break;
  2411. }
  2412. ++NumAttempts;
  2413. }
  2414. if (status == STATUS_SUCCESS) {
  2415. *PreviousSuspendCountP = PrevSuspended;
  2416. }
  2417. return status;
  2418. }
  2419. WOW64BT_IMPL NTSTATUS BTAPI(SuspendThread)(
  2420. HANDLE ThreadHandle,
  2421. HANDLE ProcessHandle,
  2422. PTEB pTEB,
  2423. PULONG PreviousSuspendCountP)
  2424. /*++
  2425. Routine Description:
  2426. This routine is entered while the target thread is actually suspended, however, it's
  2427. not known if the target thread is in a consistent IA32 state.
  2428. It attempts to produce consistent IA32 state, and if unsuccessful, tries to
  2429. temporarily resume and then suspend the target thread again.
  2430. In wow64 call to this function is protected by a machine-wide mutex
  2431. Arguments:
  2432. ThreadHandle - Handle of target thread to suspend
  2433. ProcessHandle - Handle of target thread's process
  2434. pTEB - Address of the target thread's TEB
  2435. PreviousSuspendCount - Previous suspend count
  2436. Return Value:
  2437. NTSTATUS.
  2438. --*/
  2439. {
  2440. NTSTATUS status;
  2441. //Do no block logging while the target thread is suspended in a non-consistent state
  2442. //Probably it is suspended in the middle of a logging
  2443. BTLIB_DISABLE_BLOCKED_LOG();
  2444. DBCODE(TRUE, BtlpPrintf ("\n%s CpuSuspendThread started: "
  2445. "Target TEB = %p Caller TEB = %p PreviousSuspendCount = 0x%lX\n",
  2446. (BtlpIsCurrentProcess(ProcessHandle) ? "Local" : "Remote"),
  2447. pTEB, BT_CURRENT_TEB(), *PreviousSuspendCountP));
  2448. status = BtlpEnsureSuspensionConsistency (
  2449. ThreadHandle,
  2450. ProcessHandle,
  2451. pTEB,
  2452. 0, // INFINITE
  2453. PreviousSuspendCountP);
  2454. DBCODE(TRUE, BtlpPrintf ("\n%s CpuSuspendThread %s: "
  2455. "Target TEB = %p Caller TEB = %p PreviousSuspendCount = 0x%lX\n",
  2456. (BtlpIsCurrentProcess(ProcessHandle) ? "Local" : "Remote"),
  2457. ((status == STATUS_SUCCESS) ? "completed successfully" : "failed"),
  2458. pTEB, BT_CURRENT_TEB(), *PreviousSuspendCountP));
  2459. BTLIB_ENABLE_BLOCKED_LOG();
  2460. return status;
  2461. }
  2462. BT_STATUS_CODE BtlSuspendThread(
  2463. IN U64 ThreadId,
  2464. IN U32 TryCounter
  2465. )
  2466. /*++
  2467. Routine Description:
  2468. Suspend IA-32 Execution Layer thread for internal needs.
  2469. Caller of the BtlSuspendThread function must guarantee that target
  2470. thread can not call to the suspension function (CpuThreadSuspend or BtlSuspendThread)
  2471. while this function executes.
  2472. Arguments:
  2473. ThreadId - IN Thread ID
  2474. TryCounter - IN Maximum number of attempts to suspend thread or 0 (INFINITY)
  2475. Return Value:
  2476. BT_STATUS_CODE
  2477. --*/
  2478. {
  2479. NTSTATUS status;
  2480. HANDLE ThreadHandle;
  2481. ULONG PreviousSuspendCount;
  2482. DBCODE(TRUE, BtlpPrintf ("\nBtlSuspendThread started: Target TEB = %p Caller TEB = %p TryCounter=%d\n",
  2483. (PTEB)ThreadId, BT_CURRENT_TEB(), TryCounter));
  2484. // Remember, we use TEB address as a thread ID
  2485. assert (ThreadId != (U64)BT_CURRENT_TEB());
  2486. ThreadHandle = BTLIB_EXTERNAL_HANDLE_OF((PTEB)ThreadId);
  2487. //Do no block logging while the target thread is suspended in a non-consistent state
  2488. //Probably it is suspended in the middle of a logging
  2489. BTLIB_DISABLE_BLOCKED_LOG();
  2490. status = NtSuspendThread(ThreadHandle, &PreviousSuspendCount);
  2491. if (status == STATUS_SUCCESS) {
  2492. status = BtlpEnsureSuspensionConsistency (
  2493. ThreadHandle,
  2494. NtCurrentProcess(),
  2495. (PTEB)ThreadId,
  2496. TryCounter,
  2497. &PreviousSuspendCount);
  2498. if (status != STATUS_SUCCESS) {
  2499. NtResumeThread(ThreadHandle, NULL);
  2500. }
  2501. }
  2502. BTLIB_ENABLE_BLOCKED_LOG();
  2503. DBCODE (TRUE, BtlpPrintf ("\nBtlSuspendThread %s : Target TEB = %p Caller TEB = %p PreviousSuspendCount = 0x%lX\n",
  2504. ((status == STATUS_SUCCESS) ? "completed successfully" : "failed"),
  2505. (PTEB)ThreadId, BT_CURRENT_TEB(), PreviousSuspendCount));
  2506. return ((status == STATUS_SUCCESS) ? BT_STATUS_SUCCESS : BT_STATUS_UNSUCCESSFUL);
  2507. }
  2508. BT_STATUS_CODE BtlResumeThread(
  2509. IN U64 ThreadId
  2510. )
  2511. /*++
  2512. Routine Description:
  2513. Resume IA-32 Execution Layer thread suspended for internal needs
  2514. Arguments:
  2515. ThreadId - IN Thread ID
  2516. Return Value:
  2517. BT_STATUS_CODE
  2518. --*/
  2519. {
  2520. NTSTATUS status;
  2521. HANDLE ThreadHandle;
  2522. ULONG PreviousSuspendCount;
  2523. DBCODE (TRUE, BtlpPrintf ("\nBtlResumeThread started: Target TEB = %p Caller TEB = %p\n",
  2524. (PTEB)ThreadId, BT_CURRENT_TEB()));
  2525. // Remember, we use TEB address as a thread ID
  2526. assert (ThreadId != (U64)BT_CURRENT_TEB());
  2527. ThreadHandle = BTLIB_EXTERNAL_HANDLE_OF((PTEB)ThreadId);
  2528. status = NtResumeThread(ThreadHandle, &PreviousSuspendCount);
  2529. DBCODE (TRUE, BtlpPrintf ("\nBtlResumeThread %s : Target TEB = %p Caller TEB = %p PreviousSuspendCount = 0x%lX\n",
  2530. ((status == STATUS_SUCCESS) ? "completed successfully" : "failed"),
  2531. (PTEB)ThreadId, BT_CURRENT_TEB(), PreviousSuspendCount));
  2532. return ((status == STATUS_SUCCESS) ? BT_STATUS_SUCCESS : BT_STATUS_UNSUCCESSFUL);
  2533. }
  2534. // Exceptions handling
  2535. WOW64BT_IMPL VOID BTAPI(ResetToConsistentState)(
  2536. PEXCEPTION_POINTERS pExceptionPointers
  2537. )
  2538. /*++
  2539. Routine Description:
  2540. After an exception occurs, WOW64 calls this routine to give the CPU
  2541. a chance to clean itself up and recover the CONTEXT32 at the time of
  2542. the fault.
  2543. The function also has to fill in BTLIB_SIM_EXIT_INFO to be eventually
  2544. analyzed/handled by the exception filter/handler of the BTGENERIC_RUN
  2545. function.
  2546. CpuResetToConsistantState() needs to:
  2547. 0) Check if the exception was from ia32 or ia64
  2548. If exception was ia64, do nothing and return
  2549. If exception was ia32, needs to:
  2550. 1) Needs to copy CONTEXT eip to the TLS (WOW64_TLS_EXCEPTIONADDR)
  2551. 2) reset the CONTEXT struction to be a valid ia64 state for unwinding
  2552. this includes:
  2553. 2a) reset CONTEXT ip to a valid ia64 ip (usually
  2554. the destination of the jmpe)
  2555. 2b) reset CONTEXT sp to a valid ia64 sp (TLS
  2556. entry WOW64_TLS_STACKPTR64)
  2557. 2c) reset CONTEXT gp to a valid ia64 gp
  2558. 2d) reset CONTEXT teb to a valid ia64 teb
  2559. 2e) reset CONTEXT psr.is (so exception handler runs as ia64 code)
  2560. Arguments:
  2561. pExceptionPointers - 64-bit exception information
  2562. Return Value:
  2563. None.
  2564. --*/
  2565. {
  2566. BT_EXCEPTION_RECORD BtExceptRecord;
  2567. BT_EXCEPTION_CODE BtExceptCode;
  2568. DBCODE (TRUE,
  2569. BtlpPrintf ("\n CpuResetToConsistentState (pExceptionPointers=0x%016I64X) started\n", pExceptionPointers);
  2570. BtlpPrintf ("\n CpuResetToConsistentState: TEB=0x%I64X", BT_CURRENT_TEB());
  2571. BtlpPrintf ("\n CpuResetToConsistentState: TEB32=0x%I64X", BT_CURRENT_TEB32());
  2572. BtlpPrintf ("\n CpuResetToConsistentState: ExceptionCode=0x%X", pExceptionPointers->ExceptionRecord->ExceptionCode);
  2573. BtlpPrintf ("\n CpuResetToConsistentState: ExceptionAddress=0x%I64X", pExceptionPointers->ExceptionRecord->ExceptionAddress);
  2574. BtlpPrintf ("\n CpuResetToConsistentState: ExceptionFlags=0x%X", pExceptionPointers->ExceptionRecord->ExceptionFlags);
  2575. BtlpPrintf ("\n CpuResetToConsistentState: NumberParameters=0x%X", pExceptionPointers->ExceptionRecord->NumberParameters);
  2576. {
  2577. unsigned int n;
  2578. for (n = 0; n < pExceptionPointers->ExceptionRecord->NumberParameters; ++n) {
  2579. BtlpPrintf ("\n CpuResetToConsistentState: ExceptionInformation[%d]=0x%I64X",
  2580. n, pExceptionPointers->ExceptionRecord->ExceptionInformation[n]);
  2581. }
  2582. }
  2583. BtlpPrintf ("\n\n CpuResetToConsistentState: ContextFlags: 0x%X", pExceptionPointers->ContextRecord->ContextFlags);
  2584. BtlpPrintf ("\n CpuResetToConsistentState: StIIP =0x%I64X", pExceptionPointers->ContextRecord->StIIP);
  2585. BtlpPrintf ("\n CpuResetToConsistentState: StIPSR=0x%I64X", pExceptionPointers->ContextRecord->StIPSR);
  2586. BtlpPrintf ("\n CpuResetToConsistentState: IntSp =0x%I64X", pExceptionPointers->ContextRecord->IntSp);
  2587. BtlpPrintf ("\n *** BRET=0x%016I64X", pExceptionPointers->ContextRecord->BrRp);
  2588. BtlpPrintf ("\n *** GP=0x%016I64X", pExceptionPointers->ContextRecord->IntGp);
  2589. BtlpPrintf ("\n *** SP=0x%016I64X", pExceptionPointers->ContextRecord->IntSp);
  2590. BtlpPrintf ("\n *** PREDS=0x%016I64X", pExceptionPointers->ContextRecord->Preds);
  2591. BtlpPrintf ("\n *** AR.PFS=0x%016I64X", pExceptionPointers->ContextRecord->RsPFS);
  2592. BtlpPrintf ("\n *** AR.BSP=0x%016I64X", pExceptionPointers->ContextRecord->RsBSP);
  2593. BtlpPrintf ("\n *** AR.BSPSTORE=0x%016I64X", pExceptionPointers->ContextRecord->RsBSPSTORE);
  2594. BtlpPrintf ("\n *** AR.RSC=0x%016I64X", pExceptionPointers->ContextRecord->RsRSC);
  2595. );
  2596. //Reconstruct consistent IA32 state
  2597. BtlpNt2BtExceptRecord (pExceptionPointers->ExceptionRecord, &BtExceptRecord);
  2598. BtExceptCode = BTGENERIC_IA32_CANONIZE_CONTEXT(BT_CURRENT_TLS(),
  2599. pExceptionPointers->ContextRecord,
  2600. &BtExceptRecord);
  2601. //BtExceptCode determines appearance of the exception in the simulated application:
  2602. //BT_NO_EXCEPT - ignore exception, otherwise raise exception with the returned code
  2603. //Fill in BTLIB_SIM_EXIT_INFO to be eventually analyzed/handled by the exception
  2604. //filter/handler of the BTGENERIC_RUN function.
  2605. if (BTLIB_INSIDE_CPU_SIMULATION()) {
  2606. // Exception occured during code simulation in the BTGENERIC_RUN function
  2607. if (BtExceptCode == BtExceptRecord.ExceptionCode) {
  2608. //IA32Exec.bin decided to raise exception as is.
  2609. if (BeingDebugged) {
  2610. // External debugger receives exception event before it is
  2611. // locally processed by the CpuResetToConsistentState function.
  2612. // In this case, BTLib silences current exception and re-raises an exact
  2613. // copy of this exception just after state canonization.
  2614. // Copy IA64 exception record to be used to re-raise the exception
  2615. BTLIB_SIM_EXIT_INFO_PTR()->ExitCode = SIM_EXIT_IA64_EXCEPTION_CODE;
  2616. BTLIB_SIM_EXIT_INFO_PTR()->u.IA64Exception.ExceptionRecord =
  2617. *(pExceptionPointers->ExceptionRecord);
  2618. /*
  2619. BTLIB_SIM_EXIT_INFO_PTR()->u.IA64Exception.ExceptionContext =
  2620. *(pExceptionPointers->ContextRecord);
  2621. */
  2622. }
  2623. else {
  2624. //Mark the exception as unhandled and pass it to higher-level exception handler
  2625. BTLIB_SIM_EXIT_INFO_PTR()->ExitCode = SIM_EXIT_UNHANDLED_EXCEPTION_CODE;
  2626. }
  2627. }
  2628. else if (BtExceptCode == BT_NO_EXCEPT) {
  2629. //IA32Exec.bin decided to ignore exception. Restart code simulation.
  2630. BTLIB_SIM_EXIT_INFO_PTR()->ExitCode = SIM_EXIT_RESTART_CODE;
  2631. }
  2632. else {
  2633. //IA32Exec.bin changed exception code, so wowIA32X.dll silences current exception
  2634. //and re-raises the new one.
  2635. BTLIB_SIM_EXIT_INFO_PTR()->ExitCode = SIM_EXIT_EXCEPTION_CODE;
  2636. BTLIB_SIM_EXIT_INFO_PTR()->u.ExceptionRecord.ExceptionCode = BtExceptCode;
  2637. BTLIB_SIM_EXIT_INFO_PTR()->u.ExceptionRecord.ReturnAddr = BTLIB_CONTEXT_IA32_PTR()->Eip;
  2638. }
  2639. }
  2640. // Dump debug info for serious errors
  2641. DBCODE ((pExceptionPointers->ExceptionRecord->ExceptionCode & 0x80000000),
  2642. BTGENERIC_EXCEPTION_DEBUG_PRINT ());
  2643. BT_CURRENT_TEB()->TlsSlots[4] = (VOID *)((UINT_PTR) BTLIB_CONTEXT_IA32_PTR()->Eip);
  2644. DBCODE (TRUE, BtlpPrintf ("\n CpuResetToConsistentState (pExceptionPointers=0x%p) completed\n", pExceptionPointers));
  2645. }
  2646. WOW64BT_IMPL VOID BTAPI(ResetFloatingPoint)(
  2647. VOID
  2648. )
  2649. /*++
  2650. Routine Description:
  2651. This function is called by the wow layer when a floating point exception
  2652. is taken just before returning back to ia32 mode. It is used to reset
  2653. the fp state to a non error condition if needed before running
  2654. the ia32 exception handler.
  2655. For IA-32 Execution Layer, this function is nop, because all handling of FP exceptions
  2656. have already been done in CpuSimulate/CpuResetToConsistentState.
  2657. Arguments:
  2658. None
  2659. Return Value:
  2660. None.
  2661. --*/
  2662. {
  2663. }
  2664. int BtlpMajorFilterException(
  2665. IN LPEXCEPTION_POINTERS pEP
  2666. )
  2667. /*++
  2668. Routine Description:
  2669. Exception filter for IA64 exceptions occured in the BTGENERIC_RUN function while
  2670. simulating the IA32 code.
  2671. The filter decides whether to handle the exception or to continue unwinding.
  2672. Called after the ResetToConsistentState function reconstructed IA32 state and filled
  2673. in BTLIB_SIM_EXIT_INFO.
  2674. Arguments:
  2675. pEP - IN Exception pointers structure
  2676. Return Value:
  2677. Decision: EXCEPTION_EXECUTE_HANDLER or EXCEPTION_CONTINUE_SEARCH.
  2678. --*/
  2679. {
  2680. assert(BTLIB_INSIDE_CPU_SIMULATION());
  2681. //BTLIB_SIM_EXIT_INFO has been filled in by the ResetToConsistentState function.
  2682. //The SIM_EXIT_UNHANDLED_EXCEPTION_CODE code stands for BT-unhandled exception,
  2683. //that should be passed to higher-level handlers.
  2684. DBCODE (TRUE, BtlpPrintf ("\n BtlpMajorFilterException: Exception code = 0x%lx", pEP->ExceptionRecord->ExceptionCode));
  2685. DBCODE (TRUE, BtlpPrintf ("\n BtlpMajorFilterException: Exception address = 0x%p\n", pEP->ExceptionRecord->ExceptionAddress));
  2686. DBCODE (TRUE, BtlpPrintf ("\n BtlpMajorFilterException: %s exception\n",
  2687. ((BTLIB_SIM_EXIT_INFO_PTR()->ExitCode == SIM_EXIT_UNHANDLED_EXCEPTION_CODE) ?
  2688. "Unhandled" : "BT-handled")));
  2689. return ((BTLIB_SIM_EXIT_INFO_PTR()->ExitCode == SIM_EXIT_UNHANDLED_EXCEPTION_CODE) ?
  2690. EXCEPTION_CONTINUE_SEARCH : EXCEPTION_EXECUTE_HANDLER);
  2691. }
  2692. // System service exception filter
  2693. int BtlpSystemServiceFilterException(
  2694. IN LPEXCEPTION_POINTERS pEP
  2695. )
  2696. /*++
  2697. Routine Description:
  2698. Exception filter for exceptions during Wow64 NT system services
  2699. Arguments:
  2700. pEP - IN Exception pointers structure
  2701. Return Value:
  2702. Decision: EXCEPTION_CONTINUE_SEARCH always.
  2703. --*/
  2704. {
  2705. DBCODE (TRUE, BtlpPrintf ("\n BtlpSystemServiceFilterException: Exception code = 0x%lx", pEP->ExceptionRecord->ExceptionCode));
  2706. DBCODE (TRUE, BtlpPrintf ("\n BtlpSystemServiceFilterException: Exception address = 0x%p\n", pEP->ExceptionRecord->ExceptionAddress));
  2707. DBCODE (TRUE, BtlpPrintf ("\n BtlpSystemServiceFilterException: Excepted system service = 0x%X, called from Eip=0x%X with ESP=0x%X\n",
  2708. BTLIB_CONTEXT_IA32_PTR()->Eax, BTLIB_CONTEXT_IA32_PTR()->Eip, BTLIB_CONTEXT_IA32_PTR()->Esp));
  2709. return EXCEPTION_CONTINUE_SEARCH;
  2710. }
  2711. __inline VOID BtlpExitSimulation(
  2712. VOID
  2713. )
  2714. /*++
  2715. Routine Description:
  2716. Exit 32-bit code simulation by performing longjmp to the current
  2717. setjmp addr stored in TLS
  2718. Arguments:
  2719. None.
  2720. Return Value:
  2721. Never returns.
  2722. --*/
  2723. {
  2724. longjmp (BTLIB_SIM_JMPBUF(), 1);
  2725. }
  2726. VOID BtlpMajorExceptionHandler (
  2727. VOID
  2728. )
  2729. /*++
  2730. Routine Description:
  2731. Exception handler for IA64 exceptions occured in the BTGENERIC_RUN function while
  2732. simulating the IA32 code.
  2733. Called after the filter decides to handle the IA64 exception.
  2734. Arguments:
  2735. BtExceptRecordP - IN Pointer to BT exception record
  2736. Return Value:
  2737. None.
  2738. --*/
  2739. {
  2740. assert(BTLIB_INSIDE_CPU_SIMULATION());
  2741. //BTLIB_SIM_EXIT_INFO has been filled in by the ResetToConsistentState function.
  2742. //Just exit simulation to process BTLIB_SIM_EXIT_INFO
  2743. assert((BTLIB_SIM_EXIT_INFO_PTR()->ExitCode == SIM_EXIT_EXCEPTION_CODE) ||
  2744. (BTLIB_SIM_EXIT_INFO_PTR()->ExitCode == SIM_EXIT_RESTART_CODE) ||
  2745. (BTLIB_SIM_EXIT_INFO_PTR()->ExitCode == SIM_EXIT_IA64_EXCEPTION_CODE));
  2746. DBCODE (TRUE, BtlpPrintf ("\n BtlpMajorExceptionHandler: %s exception\n",
  2747. ((BTLIB_SIM_EXIT_INFO_PTR()->ExitCode == SIM_EXIT_RESTART_CODE)? "Ignore" : "Raise")));
  2748. BtlpExitSimulation();
  2749. }
  2750. // IA32 simulation API
  2751. static VOID BtlpSimulate(
  2752. VOID
  2753. )
  2754. /*++
  2755. Routine Description:
  2756. Simulate 32-bit code using the current 32-bit context. On return,
  2757. BTLIB_EXIT_INFO is filled in with an appropriate simulation
  2758. exit code and data.
  2759. Arguments:
  2760. None.
  2761. Return Value:
  2762. None.
  2763. The function does not return normally, but rather longjmps to the current setjmp addr
  2764. stored in TLS .
  2765. --*/
  2766. {
  2767. assert(BTLIB_INSIDE_CPU_SIMULATION());
  2768. BTLIB_SIM_EXIT_INFO_PTR()->ExitCode = SIM_EXIT_RESTART_CODE;
  2769. _try {
  2770. BTGENERIC_RUN ();
  2771. } _except (BtlpMajorFilterException(GetExceptionInformation())) {
  2772. BtlpMajorExceptionHandler ();
  2773. }
  2774. }
  2775. VOID BtlIA32LCall (
  2776. IN OUT BTGENERIC_IA32_CONTEXT * ia32context,
  2777. IN U32 returnAddress,
  2778. IN U32 targetAddress
  2779. )
  2780. /*++
  2781. Routine Description:
  2782. Exit IA32 code simulation to "execute" LCALL instruction (should not happen in NT)
  2783. Arguments:
  2784. ia32context - IA32 context. ia32context->Eip points to the LCALL instruction.
  2785. returnAddress - return address of the LCALL instruction.
  2786. targetAddress - target address of the LCALL instruction.
  2787. Return Value:
  2788. Never returns.
  2789. --*/
  2790. {
  2791. assert(BTLIB_INSIDE_CPU_SIMULATION());
  2792. assert (ia32context == BTLIB_CONTEXT_IA32_PTR());
  2793. //Fill in BTLIB_EXIT_INFO
  2794. BTLIB_SIM_EXIT_INFO_PTR()->ExitCode = SIM_EXIT_LCALL_CODE;
  2795. //Currently LcallRecord is not used
  2796. BtlpExitSimulation();
  2797. }
  2798. static VOID BtlpRaiseException (
  2799. IN BT_EXCEPTION_CODE BtExceptCode,
  2800. IN U32 ReturnAddr
  2801. )
  2802. /*++
  2803. Routine Description:
  2804. This routine either simulates an x86 software interrupt, or generates a
  2805. CPU exception depending on a specified exception code.
  2806. Exception code in the range 0-255 stands for software interrupt number.
  2807. All other BT-exception codes are converted to the corresponding OS-specific
  2808. exception code.
  2809. Arguments:
  2810. BtExceptCode - BT exception/interrupt code
  2811. ReturnAddr - address of the instruction to be executed after return from
  2812. exception handler
  2813. Return Value:
  2814. None.
  2815. --*/
  2816. {
  2817. U32 ExceptionAddr;
  2818. //WOW64 and native Win32 provide different values for context32.Eip and
  2819. //ExceptionRecord.ExceptionAddress in exception handler. Current implementation
  2820. //resembles WOW64 behavior:
  2821. //context32.Eip = ExceptionRecord.ExceptionAddress = ReturnAddr
  2822. ExceptionAddr = ReturnAddr;
  2823. BTLIB_CONTEXT_IA32_PTR()->Eip = ExceptionAddr;
  2824. BT_CURRENT_TEB()->TlsSlots[4] = UlongToPtr(ExceptionAddr);
  2825. if (BtExceptCode > BT_MAX_INTERRUPT_NUMBER) {
  2826. //fill in EXCEPTION_RECORD and simulate exception
  2827. EXCEPTION_RECORD ExceptionRecord;
  2828. ExceptionRecord.ExceptionCode = BtlpBt2NtExceptCode(BtExceptCode);
  2829. ExceptionRecord.ExceptionAddress = UlongToPtr(ExceptionAddr);
  2830. ExceptionRecord.ExceptionFlags = 0;
  2831. ExceptionRecord.ExceptionRecord = NULL;
  2832. if (ExceptionRecord.ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
  2833. //set exception information for the case of inaccessable IA32 code
  2834. ExceptionRecord.NumberParameters = 2;
  2835. ExceptionRecord.ExceptionInformation[0] = 0;
  2836. ExceptionRecord.ExceptionInformation[1] = ExceptionAddr;
  2837. }
  2838. else {
  2839. ExceptionRecord.NumberParameters = 0;
  2840. }
  2841. DBCODE (TRUE, BtlpPrintf ("\nWow64RaiseException simulates exception 0x%X at IP=0x%X ESP=0x%X\n",
  2842. ExceptionRecord.ExceptionCode,
  2843. BTLIB_CONTEXT_IA32_PTR()->Eip,
  2844. BTLIB_CONTEXT_IA32_PTR()->Esp));
  2845. Wow64RaiseException (-1, &ExceptionRecord);
  2846. }
  2847. else {
  2848. //simulate software interrupt
  2849. DBCODE (TRUE, BtlpPrintf ("\nWow64RaiseException simulates interrupt %d at IP=0x%X ESP=0x%X\n",
  2850. BtExceptCode,
  2851. BTLIB_CONTEXT_IA32_PTR()->Eip,
  2852. BTLIB_CONTEXT_IA32_PTR()->Esp));
  2853. Wow64RaiseException (BtExceptCode, NULL);
  2854. }
  2855. DBCODE (TRUE, BtlpPrintf ("\nReturned from Wow64RaiseException IP=0x%X ESP=0x%X",
  2856. BTLIB_CONTEXT_IA32_PTR()->Eip,
  2857. BTLIB_CONTEXT_IA32_PTR()->Esp));
  2858. }
  2859. VOID BtlIA32Interrupt(
  2860. IN OUT BTGENERIC_IA32_CONTEXT * ia32context,
  2861. IN BT_EXCEPTION_CODE exceptionCode,
  2862. IN U32 returnAddress
  2863. )
  2864. /*++
  2865. Routine Description:
  2866. Exit IA32 code simulation to raise exception/interrupt
  2867. Arguments:
  2868. ia32context - IA32 context. The ia32context->Eip register points to the next
  2869. instruction to be simulated
  2870. exceptionCode - exception/interrupt code
  2871. returnAddress - address of the instruction to be executed after return from
  2872. exception handler
  2873. Return Value:
  2874. Never returns.
  2875. Note:
  2876. For CPU faults: ia32context.Eip = returnAddress = fault inst. Eip
  2877. For CPU traps: ia32context.Eip = returnAddress = next Eip to execute
  2878. For software interrupts : ia32context.Eip points
  2879. to instruction caused interruption (not yet executed ) and returnAddress is the
  2880. next Eip.
  2881. --*/
  2882. {
  2883. assert(BTLIB_INSIDE_CPU_SIMULATION());
  2884. assert (ia32context == BTLIB_CONTEXT_IA32_PTR());
  2885. //Fill in BTLIB_EXIT_INFO
  2886. BTLIB_SIM_EXIT_INFO_PTR()->ExitCode = SIM_EXIT_EXCEPTION_CODE;
  2887. BTLIB_SIM_EXIT_INFO_PTR()->u.ExceptionRecord.ExceptionCode = exceptionCode;
  2888. BTLIB_SIM_EXIT_INFO_PTR()->u.ExceptionRecord.ReturnAddr = returnAddress;
  2889. BtlpExitSimulation();
  2890. }
  2891. VOID BtlIA32JmpIA64(
  2892. IN OUT BTGENERIC_IA32_CONTEXT * ia32context,
  2893. IN U32 returnAddress,
  2894. IN U32 targetAddress
  2895. )
  2896. /*++
  2897. Routine Description:
  2898. Exit IA32 code simulation to "execute" JMPE instruction.
  2899. In Wow64, JMPE instruction indicates call to system service. The only JMPE,
  2900. that can be reached during code simulation, is WOW64-provided JMPE,
  2901. since no other JMPE instructions should ever appear in IA32 applications
  2902. Arguments:
  2903. ia32context - IA32 context. ia32context->Eip points to the JMPE instruction.
  2904. returnAddress - Address of the next to JMPE instruction. In Wow64 it points to
  2905. global pointer value
  2906. targetAddress - target address of the JMPE instruction.
  2907. Return Value:
  2908. Never returns.
  2909. --*/
  2910. {
  2911. assert(BTLIB_INSIDE_CPU_SIMULATION());
  2912. assert (ia32context == BTLIB_CONTEXT_IA32_PTR());
  2913. // Only WOW64-provided JMPE is acceptable
  2914. if (((VOID *)((UINT_PTR) ia32context->Eip)) != WOW64_JMPE) {
  2915. BtlpPrintf ("\nJMPE instruction detected in Wow64 application at 0x%X", ia32context->Eip);
  2916. BtlpPrintf ("\nWow64 JMPE is at 0x%p", WOW64_JMPE);
  2917. BTLIB_ABORT ();
  2918. }
  2919. //Fill in BTLIB_EXIT_INFO
  2920. BTLIB_SIM_EXIT_INFO_PTR()->ExitCode = SIM_EXIT_JMPE_CODE;
  2921. //Currently JmpeRecord is not used
  2922. BtlpExitSimulation();
  2923. }
  2924. VOID BtlIA32Reenter(
  2925. IN OUT BTGENERIC_IA32_CONTEXT * ia32context
  2926. )
  2927. /*++
  2928. Routine Description:
  2929. Exit and resume IA32 code simulation.
  2930. Called when IA32 thread has been suspended and then resumed, etc..
  2931. Arguments:
  2932. ia32context - IA32 context to resume code execution with
  2933. Return Value:
  2934. Never returns.
  2935. --*/
  2936. {
  2937. assert(BTLIB_INSIDE_CPU_SIMULATION());
  2938. assert (ia32context == BTLIB_CONTEXT_IA32_PTR());
  2939. BTLIB_SIM_EXIT_INFO_PTR()->ExitCode = SIM_EXIT_RESTART_CODE;
  2940. BtlpExitSimulation();
  2941. }
  2942. WOW64BT_IMPL VOID BTAPI(Simulate)(
  2943. VOID
  2944. )
  2945. /*++
  2946. Routine Description:
  2947. RUn 32-bit code. The CONTEXT32 has already been set up to go.
  2948. Arguments:
  2949. None.
  2950. Return Value:
  2951. None. Never returns.
  2952. --*/
  2953. {
  2954. DBCODE (FALSE, BtlpPrintf ("\nCpuSimulate: TEB=%p, EFLAGS=0x%X", BT_CURRENT_TEB(), BTLIB_CONTEXT_IA32_PTR()->EFlags));
  2955. for (;;) {
  2956. BTLIB_CPU_SIM_DATA CpuSimData;
  2957. BTLIB_ENTER_CPU_SIMULATION(&CpuSimData);
  2958. // If exception happens during code simulation, the IA32 context pointed by
  2959. // BTLIB_CONTEXT_IA32_PTR() may not correspond to the real exception context
  2960. BTLIB_CLEAR_CONSISTENT_EXCEPT_STATE();
  2961. if (setjmp(CpuSimData.Jmpbuf) == 0) {
  2962. BtlpSimulate(); // This function fills in BTLIB_SIM_EXIT_INFO and returns with longjmp
  2963. }
  2964. BTLIB_SET_CONSISTENT_EXCEPT_STATE();
  2965. BTLIB_LEAVE_CPU_SIMULATION();
  2966. //allow thread suspension at this point
  2967. if (BTLIB_HAS_SUSPEND_REQUEST()) {
  2968. BtlpReceiveSuspensionRequest();
  2969. }
  2970. //Take an action as specified in the BTLIB_SIM_EXIT_INFO
  2971. switch (CpuSimData.ExitData.ExitCode) {
  2972. case SIM_EXIT_JMPE_CODE:
  2973. // Call to system service
  2974. DBCODE (FALSE, BtlpPrintf ("\nArrived to JMPE: CONTEXT=%p", BTLIB_CONTEXT_IA32_PTR()));
  2975. DBCODE (FALSE, BtlpPrintf ("\nArrived with: IP=0x%X", BTLIB_CONTEXT_IA32_PTR()->Eip));
  2976. DBCODE (FALSE, BtlpPrintf ("\nArrived with: ESP=0x%X", BTLIB_CONTEXT_IA32_PTR()->Esp));
  2977. // Simulate RET instruction - pop return address
  2978. BTLIB_CONTEXT_IA32_PTR()->Eip = (*((U32 *)((UINT_PTR) BTLIB_CONTEXT_IA32_PTR()->Esp)));
  2979. BTLIB_CONTEXT_IA32_PTR()->Esp += sizeof (U32);
  2980. DBCODE (FALSE, BtlpPrintf ("\n Intend to return with: IP=0x%X ESP=0x%X", BTLIB_CONTEXT_IA32_PTR()->Eip, BTLIB_CONTEXT_IA32_PTR()->Esp));
  2981. DBCODE (FALSE, BtlpPrintf ("\n System Service 0x%X Context32=0x%p\n", BTLIB_CONTEXT_IA32_PTR()->Eax, BTLIB_CONTEXT_IA32_PTR()));
  2982. _try {
  2983. BTLIB_CONTEXT_IA32_PTR()->Eax = Wow64SystemService (BTLIB_CONTEXT_IA32_PTR()->Eax, BTLIB_CONTEXT_IA32_PTR());
  2984. } _except (BtlpSystemServiceFilterException(GetExceptionInformation())) {
  2985. BtlpPrintf ("\nShould never get to here - system service\n");
  2986. }
  2987. DBCODE (FALSE, BtlpPrintf ("\n Returned from System Service: Result=0x%X", BTLIB_CONTEXT_IA32_PTR()->Eax));
  2988. break;
  2989. case SIM_EXIT_RESTART_CODE:
  2990. // Restart code simulation
  2991. DBCODE (TRUE, BtlpPrintf ("\n Resuming thread simulation: TEB=%p EIP=0x%X ESP=0x%X ",
  2992. BT_CURRENT_TEB(), BTLIB_CONTEXT_IA32_PTR()->Eip, BTLIB_CONTEXT_IA32_PTR()->Esp));
  2993. break;
  2994. case SIM_EXIT_LCALL_CODE:
  2995. // Simulate LCALL
  2996. BtlpPrintf ("\n No LCALLs support in NT. Raise exception.");
  2997. BtlpRaiseException(IA32_GEN_PROT_FAULT_INTR, BTLIB_CONTEXT_IA32_PTR()->Eip);
  2998. break;
  2999. case SIM_EXIT_EXCEPTION_CODE:
  3000. // Raise IA32 exception/interrupt
  3001. BtlpRaiseException(CpuSimData.ExitData.u.ExceptionRecord.ExceptionCode,
  3002. CpuSimData.ExitData.u.ExceptionRecord.ReturnAddr);
  3003. break;
  3004. case SIM_EXIT_IA64_EXCEPTION_CODE:
  3005. // Raise IA64 exception
  3006. RtlRaiseException(&CpuSimData.ExitData.u.IA64Exception.ExceptionRecord);
  3007. break;
  3008. default:
  3009. BtlpPrintf ("\n Illegal simulation exit code %d. Aborting...", CpuSimData.ExitData.ExitCode);
  3010. BTLIB_ABORT();
  3011. break;
  3012. }
  3013. }
  3014. }
  3015. // IA32 context manipulation
  3016. WOW64BT_IMPL NTSTATUS BTAPI(GetContext)(
  3017. HANDLE ThreadHandle,
  3018. HANDLE ProcessHandle,
  3019. PTEB pTEB,
  3020. BTGENERIC_IA32_CONTEXT * Context
  3021. )
  3022. /*++
  3023. Routine Description:
  3024. Extracts the cpu context of the specified thread.
  3025. When entered, it is guaranteed that the target thread is suspended at
  3026. a proper CPU state.
  3027. Arguments:
  3028. ThreadHandle - Target thread handle to retreive the context for
  3029. ProcessHandle - Open handle to the process that the thread runs in
  3030. pTEB - Pointer to the target's thread TEB
  3031. Context - Context record to fill
  3032. Return Value:
  3033. NTSTATUS.
  3034. --*/
  3035. {
  3036. BT_STATUS_CODE BtStatus;
  3037. PVOID GlstP;
  3038. BOOL IsLocal;
  3039. if (pTEB == NULL) {
  3040. pTEB = BT_CURRENT_TEB();
  3041. IsLocal = TRUE;
  3042. }
  3043. else {
  3044. IsLocal = BtlpIsCurrentProcess(ProcessHandle);
  3045. }
  3046. DBCODE(FALSE, BtlpPrintf ("\n%s CpuGetContext: "
  3047. "Target TEB = %p Caller TEB = %p \n",
  3048. (IsLocal ? "Local" : "Remote"), pTEB, BT_CURRENT_TEB()));
  3049. GlstP = BtlpGetTlsPtr(ProcessHandle, pTEB, IsLocal);
  3050. if (GlstP == NULL) {
  3051. BtStatus = BT_STATUS_ACCESS_VIOLATION;
  3052. }
  3053. else {
  3054. BtStatus = (IsLocal ? BTGENERIC_IA32_CONTEXT_GET(GlstP, Context) :
  3055. BTGENERIC_IA32_CONTEXT_GET_REMOTE(ProcessHandle, GlstP, Context));
  3056. }
  3057. if (BtStatus != BT_STATUS_SUCCESS) {
  3058. return (BtlpBt2NtStatusCode(BtStatus));
  3059. }
  3060. return STATUS_SUCCESS;
  3061. }
  3062. WOW64BT_IMPL NTSTATUS BTAPI(SetContext)(
  3063. HANDLE ThreadHandle,
  3064. HANDLE ProcessHandle,
  3065. PTEB pTEB,
  3066. BTGENERIC_IA32_CONTEXT * Context
  3067. )
  3068. /*++
  3069. Routine Description:
  3070. Sets the cpu context for the specified thread.
  3071. When entered, if the target thread isn't the currently executing thread, then it is
  3072. guaranteed that the target thread is suspended at a proper CPU state.
  3073. Arguments:
  3074. ThreadHandle - Target thread handle to retreive the context for
  3075. ProcessHandle - Open handle to the process that the thread runs in
  3076. pTEB - Pointer to the target's thread TEB
  3077. Context - Context record to set
  3078. Return Value:
  3079. NTSTATUS.
  3080. --*/
  3081. {
  3082. BT_STATUS_CODE BtStatus;
  3083. PVOID GlstP;
  3084. BOOL IsLocal;
  3085. if (pTEB == NULL) {
  3086. pTEB = BT_CURRENT_TEB();
  3087. IsLocal = TRUE;
  3088. }
  3089. else {
  3090. IsLocal = BtlpIsCurrentProcess(ProcessHandle);
  3091. }
  3092. DBCODE(FALSE, BtlpPrintf ("\n%s CpuSetContext: "
  3093. "Target TEB = %p Caller TEB = %p \n",
  3094. (IsLocal ? "Local" : "Remote"), pTEB, BT_CURRENT_TEB()));
  3095. GlstP = BtlpGetTlsPtr(ProcessHandle, pTEB, IsLocal);
  3096. if (GlstP == NULL) {
  3097. BtStatus = BT_STATUS_ACCESS_VIOLATION;
  3098. }
  3099. else {
  3100. BtStatus = (IsLocal ? BTGENERIC_IA32_CONTEXT_SET(GlstP, Context) :
  3101. BTGENERIC_IA32_CONTEXT_SET_REMOTE(ProcessHandle, GlstP, Context));
  3102. }
  3103. if (BtStatus != BT_STATUS_SUCCESS) {
  3104. return (BtlpBt2NtStatusCode(BtStatus));
  3105. }
  3106. return STATUS_SUCCESS;
  3107. }
  3108. WOW64BT_IMPL ULONG BTAPI(GetStackPointer)(
  3109. VOID
  3110. )
  3111. /*++
  3112. Routine Description:
  3113. Returns the current 32-bit stack pointer value.
  3114. Arguments:
  3115. None.
  3116. Return Value:
  3117. Value of 32-bit stack pointer.
  3118. --*/
  3119. {
  3120. DBCODE (FALSE, BtlpPrintf ("\nBTAPICpuGetStackPointer reports ESP=0x%X TEB=%p\n", BTLIB_CONTEXT_IA32_PTR()->Esp, BT_CURRENT_TEB()));
  3121. return BTLIB_CONTEXT_IA32_PTR()->Esp;
  3122. }
  3123. WOW64BT_IMPL VOID BTAPI(SetStackPointer)(
  3124. ULONG Value
  3125. )
  3126. /*++
  3127. Routine Description:
  3128. Modifies the current 32-bit stack pointer value.
  3129. Arguments:
  3130. Value - new value to use for 32-bit stack pointer.
  3131. Return Value:
  3132. None.
  3133. --*/
  3134. {
  3135. BTLIB_CONTEXT_IA32_PTR()->Esp = Value;
  3136. DBCODE (FALSE, BtlpPrintf ("\nBTCpuSetStackPointer set ESP=0x%X TEB=%p\n", BTLIB_CONTEXT_IA32_PTR()->Esp, BT_CURRENT_TEB()));
  3137. }
  3138. WOW64BT_IMPL VOID BTAPI(SetInstructionPointer)(
  3139. ULONG Value
  3140. )
  3141. /*++
  3142. Routine Description:
  3143. Modifies the current 32-bit instruction pointer value.
  3144. Arguments:
  3145. Value - new value to use for 32-bit instruction pointer.
  3146. Return Value:
  3147. None.
  3148. --*/
  3149. {
  3150. BTLIB_CONTEXT_IA32_PTR()->Eip = Value;
  3151. DBCODE (FALSE, BtlpPrintf ("\nBTCpuSetInstructionPointer set EIP=0x%X TEB=%p\n", BTLIB_CONTEXT_IA32_PTR()->Eip, BT_CURRENT_TEB()));
  3152. }
  3153. WOW64BT_IMPL BOOLEAN BTAPI(ProcessDebugEvent)(
  3154. IN LPDEBUG_EVENT DebugEventP
  3155. )
  3156. /*++
  3157. Routine Description:
  3158. This routine is called whenever a debug event needs to be processed.
  3159. This would indicate that the current thread is acting as a debugger.
  3160. This function gives CPU simulator (IA-32 Execution Layer) a chance to decide whether
  3161. this debug event should be dispatched to 32-bit code or not.
  3162. IA-32 Execution Layer uses this callback to ignore false 64-bit exceptions and
  3163. re-raise real first-chance exceptions that came to debugger before
  3164. restoring consistent state of the debuggee.
  3165. Arguments:
  3166. DebugEventP - Pointer to debug event to be processed
  3167. Return Value:
  3168. This function returns TRUE if it processed the debug event,
  3169. and doesn't wish to dispatch it to 32-bit code. Otherwise, it would
  3170. return FALSE, and it would dispatch the debug event to 32-bit code.
  3171. --*/
  3172. {
  3173. BOOLEAN retval = FALSE;
  3174. DBCODE (TRUE, BtlpPrintf ("\nBTCpuProcessDebugEvent: DebugEventCode = %d", DebugEventP->dwDebugEventCode));
  3175. if ((DebugEventP->dwDebugEventCode == EXCEPTION_DEBUG_EVENT) &&
  3176. DebugEventP->u.Exception.dwFirstChance) {
  3177. NTSTATUS status;
  3178. BOOL IsLocal;
  3179. HANDLE ProcessHandle;
  3180. HANDLE ThreadHandle;
  3181. CLIENT_ID Id;
  3182. static OBJECT_ATTRIBUTES Attributes = {sizeof(OBJECT_ATTRIBUTES), 0, 0, 0, 0, 0};
  3183. DBCODE (TRUE, BtlpPrintf ("\nBTCpuProcessDebugEvent: dwFirstChance= %d, ExceptionCode = 0x%x",
  3184. DebugEventP->u.Exception.dwFirstChance,
  3185. DebugEventP->u.Exception.ExceptionRecord.ExceptionCode));
  3186. //Open handles of the thread&process being debugged
  3187. Id.UniqueProcess = UlongToHandle(DebugEventP->dwProcessId);
  3188. Id.UniqueThread = UlongToHandle(DebugEventP->dwThreadId);
  3189. status = NtOpenProcess(&ProcessHandle,
  3190. PROCESS_VM_READ | PROCESS_VM_WRITE,
  3191. &Attributes,
  3192. &Id);
  3193. if (status != STATUS_SUCCESS) {
  3194. BTLP_REPORT_NT_FAILURE("NtOpenProcess", status);
  3195. }
  3196. else {
  3197. status = NtOpenThread(&ThreadHandle,
  3198. THREAD_QUERY_INFORMATION,
  3199. &Attributes,
  3200. &Id);
  3201. if (status != STATUS_SUCCESS) {
  3202. BTLP_REPORT_NT_FAILURE("NtOpenThread", status);
  3203. }
  3204. else {
  3205. PVOID GlstP;
  3206. BTLIB_SHARED_INFO_TYPE SharedInfo;
  3207. THREAD_BASIC_INFORMATION ThreadInfo;
  3208. //Retreive TEB of the thread being debugged
  3209. status = NtQueryInformationThread(
  3210. ThreadHandle,
  3211. ThreadBasicInformation,
  3212. &ThreadInfo,
  3213. sizeof(ThreadInfo),
  3214. 0);
  3215. if (status != STATUS_SUCCESS) {
  3216. BTLP_REPORT_NT_FAILURE("NtQueryInformationThread", status);
  3217. }
  3218. else {
  3219. //Is this a local notification?
  3220. IsLocal = (DebugEventP->dwProcessId == BT_CURRENT_PROC_UID());
  3221. //Get TLS pointer of the thread being debugged
  3222. GlstP = BtlpGetTlsPtr(ProcessHandle, ThreadInfo.TebBaseAddress, IsLocal);
  3223. if (GlstP != NULL) {
  3224. //Check to see if the exception context is consistent
  3225. //If it is not, ignore current exception
  3226. status = BtlpReadSharedInfo(ProcessHandle, GlstP, IsLocal, &SharedInfo);
  3227. if (status == STATUS_SUCCESS) {
  3228. if (!BTLIB_SI_EXCEPT_STATE_CONSISTENT(&SharedInfo)) {
  3229. retval = TRUE;
  3230. }
  3231. }
  3232. }
  3233. }
  3234. NtClose(ThreadHandle);
  3235. }
  3236. NtClose(ProcessHandle);
  3237. }
  3238. }
  3239. return retval;
  3240. }
  3241. // wowIA32X.dll APIs implementation (called by IA32Exec.bin):
  3242. U64 BtlGetThreadId(
  3243. VOID
  3244. ) {
  3245. /*++
  3246. Routine Description:
  3247. Reports thread handle/id to be recorded in IA32Exec.bin.
  3248. Will be passed to other wowIA32X.dll APIs.
  3249. Arguments:
  3250. None.
  3251. Return Value:
  3252. Handle/Id.
  3253. --*/
  3254. return (U64)(BT_CURRENT_TEB()); // We will use TEB address as a thread ID
  3255. }
  3256. VOID BtlLockSignals(
  3257. VOID
  3258. )
  3259. /*++
  3260. Routine Description:
  3261. "Do not interrupt until furhter notice" (not used in NT).
  3262. Arguments:
  3263. None.
  3264. Return Value:
  3265. None.
  3266. --*/
  3267. {
  3268. // No actions in NT
  3269. }
  3270. VOID BtlUnlockSignals(
  3271. VOID
  3272. )
  3273. /*++
  3274. Routine Description:
  3275. "Can be interrupted" (not used in NT).
  3276. Arguments:
  3277. None.
  3278. Return Value:
  3279. None.
  3280. --*/
  3281. {
  3282. // No actions in NT
  3283. }
  3284. static U64 BtlpConvertPermissionsToBTLib (
  3285. IN DWORD flProtect
  3286. )
  3287. /*++
  3288. Routine Description:
  3289. Convert mempory permissions from NT-specific to wowIA32X.dll/IA32Exec.bin.
  3290. Arguments:
  3291. flProtect - IN NT-specific permissions.
  3292. Return Value:
  3293. wowIA32X.dll/IA32Exec.bin permissions
  3294. --*/
  3295. {
  3296. U64 Permissions = 0;
  3297. //Assuming that the system does not differentiate between read-only
  3298. //access and execute access
  3299. if (flProtect & ( PAGE_READONLY
  3300. | PAGE_READWRITE
  3301. | PAGE_WRITECOPY
  3302. | PAGE_EXECUTE
  3303. | PAGE_EXECUTE_READ
  3304. | PAGE_EXECUTE_READWRITE
  3305. | PAGE_EXECUTE_WRITECOPY )) {
  3306. Permissions |= (MEM_READ | MEM_EXECUTE);
  3307. }
  3308. if (flProtect & ( PAGE_READWRITE
  3309. | PAGE_WRITECOPY
  3310. | PAGE_EXECUTE_READWRITE
  3311. | PAGE_EXECUTE_WRITECOPY )) {
  3312. Permissions |= MEM_WRITE;
  3313. }
  3314. return Permissions;
  3315. }
  3316. static DWORD BtlpConvertPermissionsFromBTLib (
  3317. IN U64 Permissions
  3318. )
  3319. /*++
  3320. Routine Description:
  3321. Convert mempory permissions from wowIA32X.dll/IA32Exec.bin to NT-specific.
  3322. Arguments:
  3323. Permissions - IN wowIA32X.dll/IA32Exec.bin permissions.
  3324. Return Value:
  3325. NT-specific permissions
  3326. --*/
  3327. {
  3328. if (Permissions & MEM_READ) {
  3329. if (Permissions & MEM_WRITE) {
  3330. if (Permissions & MEM_EXECUTE) {
  3331. return PAGE_EXECUTE_READWRITE;
  3332. }
  3333. else {
  3334. return PAGE_READWRITE;
  3335. }
  3336. }
  3337. else {
  3338. if (Permissions & MEM_EXECUTE) {
  3339. return PAGE_EXECUTE_READ;
  3340. }
  3341. else {
  3342. return PAGE_READONLY;
  3343. }
  3344. }
  3345. }
  3346. else {
  3347. return PAGE_NOACCESS;
  3348. }
  3349. }
  3350. VOID * BtlMemoryAlloc(
  3351. IN VOID * startAddress,
  3352. IN U32 size,
  3353. IN U64 prot
  3354. )
  3355. /*++
  3356. Routine Description:
  3357. Allocate memory.
  3358. Arguments:
  3359. startAddress - IN suggested address or NULL, if any address will fit
  3360. size - IN requested memory size
  3361. prot - IN wowIA32X.dll/IA32Exec.bin permissions.
  3362. Return Value:
  3363. Memory address of the allocated block
  3364. --*/
  3365. {
  3366. NTSTATUS status;
  3367. LPVOID lpAddress;
  3368. SIZE_T dwSize = size;
  3369. DWORD permissions = BtlpConvertPermissionsFromBTLib (prot);
  3370. HANDLE processHandle = NtCurrentProcess();
  3371. if (startAddress == INITIAL_DATA_ALLOC) {
  3372. lpAddress = INITIAL_DATA_ADDRESS;
  3373. } else {
  3374. if (startAddress == INITIAL_CODE_ALLOC) {
  3375. lpAddress = INITIAL_CODE_ADDRESS;
  3376. } else {
  3377. lpAddress = startAddress;
  3378. }
  3379. }
  3380. status = NtAllocateVirtualMemory(processHandle,
  3381. &lpAddress,
  3382. 0,
  3383. &dwSize,
  3384. MEM_RESERVE | MEM_COMMIT,
  3385. permissions
  3386. );
  3387. if (status != STATUS_SUCCESS) {
  3388. lpAddress = 0;
  3389. if (startAddress != 0) {
  3390. dwSize = size;
  3391. status = NtAllocateVirtualMemory(processHandle,
  3392. &lpAddress,
  3393. 0,
  3394. &dwSize,
  3395. MEM_RESERVE | MEM_COMMIT,
  3396. permissions
  3397. );
  3398. }
  3399. }
  3400. return lpAddress;
  3401. }
  3402. BT_STATUS_CODE BtlMemoryFree(
  3403. IN VOID * startAddress,
  3404. IN U32 size
  3405. )
  3406. /*++
  3407. Routine Description:
  3408. Free memory.
  3409. Arguments:
  3410. startAddress - IN address of the area allocated by BtlMemoryAlloc
  3411. size - IN memory area size
  3412. Return Value:
  3413. BT_STATUS_CODE
  3414. --*/
  3415. {
  3416. NTSTATUS status;
  3417. LPVOID lpAddress = startAddress;
  3418. SIZE_T dwSize = size;
  3419. status = NtFreeVirtualMemory(NtCurrentProcess (),
  3420. &lpAddress,
  3421. &dwSize,
  3422. MEM_DECOMMIT
  3423. );
  3424. if (status == STATUS_SUCCESS) {
  3425. lpAddress = startAddress;
  3426. dwSize = 0; // No size for release!
  3427. status = NtFreeVirtualMemory(NtCurrentProcess (),
  3428. &lpAddress,
  3429. &dwSize,
  3430. MEM_RELEASE
  3431. );
  3432. }
  3433. return ((status == STATUS_SUCCESS) ? BT_STATUS_SUCCESS : BT_STATUS_UNSUCCESSFUL);
  3434. }
  3435. U32 BtlMemoryPageSize(
  3436. VOID
  3437. )
  3438. /*++
  3439. Routine Description:
  3440. Report memory page size.
  3441. Arguments:
  3442. None.
  3443. Return Value:
  3444. Page size in bytes
  3445. --*/
  3446. {
  3447. //It appears that NT-64 supports 4Kb page size for 32-bit system calls
  3448. //(VirtualAlloc, GetSystemInfo, etc.) and at the same time reports 8Kb page size to
  3449. //IA-32 Execution Layer. This inconsistency has been fixed by enforcing 4Kb page size in IA-32 Execution Layer.
  3450. #define MAX_IA32_APP_PAGE_SIZE 0x1000
  3451. static U32 sysPageSize = 0;
  3452. if (sysPageSize == 0) {
  3453. SYSTEM_BASIC_INFORMATION sysinfo;
  3454. SIZE_T ReturnLength = 0;
  3455. NTSTATUS status;
  3456. status = NtQuerySystemInformation (SystemBasicInformation,
  3457. &sysinfo,
  3458. sizeof(sysinfo),
  3459. (ULONG *)&ReturnLength
  3460. );
  3461. assert (status == STATUS_SUCCESS);
  3462. assert (ReturnLength == sizeof(sysinfo));
  3463. sysPageSize = ((sysinfo.PageSize < MAX_IA32_APP_PAGE_SIZE) ? (U32)sysinfo.PageSize : MAX_IA32_APP_PAGE_SIZE);
  3464. }
  3465. return sysPageSize;
  3466. }
  3467. U64 BtlMemoryChangePermissions(
  3468. IN VOID * startAddress,
  3469. IN U32 size,
  3470. IN U64 prot
  3471. )
  3472. /*++
  3473. Routine Description:
  3474. Change memory area permissions.
  3475. Arguments:
  3476. startAddress - IN memory address
  3477. size - IN memory size
  3478. prot - IN wowIA32X.dll/IA32Exec.bin permissions.
  3479. Return Value:
  3480. Former permissions value
  3481. --*/
  3482. {
  3483. NTSTATUS status;
  3484. LPVOID RegionAddress = startAddress;
  3485. SIZE_T RegionSize = size;
  3486. ULONG flOldProtection;
  3487. status = NtProtectVirtualMemory(NtCurrentProcess(),
  3488. &RegionAddress,
  3489. &RegionSize,
  3490. BtlpConvertPermissionsFromBTLib (prot),
  3491. &flOldProtection
  3492. );
  3493. return ((status == STATUS_SUCCESS) ? BtlpConvertPermissionsToBTLib (flOldProtection) : 0);
  3494. }
  3495. U64 BtlMemoryQueryPermissions(
  3496. IN VOID * address,
  3497. OUT VOID ** pRegionStart,
  3498. OUT U32 * pRegionSize
  3499. )
  3500. /*++
  3501. Routine Description:
  3502. Provide information about a memory region that contains a specified address
  3503. and shares the same access permissions for all pages inside the region.
  3504. Arguments:
  3505. address - IN memory address to be queried
  3506. pRegionStart - OUT pointer to the returned starting address of the region
  3507. pRegionSize - OUT pointer to the returned size of the region in bytes
  3508. Return Value:
  3509. wowIA32X.dll/IA32Exec.bin access permission value shared by all pages in the region
  3510. --*/
  3511. {
  3512. extern int BtQueryRead(VOID * Address);
  3513. NTSTATUS status;
  3514. MEMORY_BASIC_INFORMATION memInfo;
  3515. SIZE_T dwRetSize;
  3516. U64 permissions;
  3517. status = NtQueryVirtualMemory(NtCurrentProcess(),
  3518. address,
  3519. MemoryBasicInformation,
  3520. &memInfo,
  3521. sizeof (memInfo),
  3522. &dwRetSize
  3523. );
  3524. if (status == STATUS_SUCCESS) {
  3525. *pRegionStart = memInfo.BaseAddress;
  3526. *pRegionSize = (U32)(memInfo.RegionSize);
  3527. if (memInfo.RegionSize > (SIZE_T)(*pRegionSize)) {
  3528. //region size is too big, return max. U32 value aligned to the page size
  3529. *pRegionSize = (U32)(-(int)BtlMemoryPageSize());
  3530. }
  3531. if (memInfo.State == MEM_COMMIT) {
  3532. permissions = BtlpConvertPermissionsToBTLib(memInfo.Protect);
  3533. //Check an assumption that executable page is readable
  3534. if ((memInfo.Protect & PAGE_EXECUTE) && !BtQueryRead(address)) {
  3535. //Executable page is not readable - clear MEM_READ permission in order
  3536. //to prevent any attempt by IA32Exec.bin to read this memory
  3537. permissions &= (~((U64)MEM_READ));
  3538. BtlpPrintf("\nAddress %p in IA-32 process is located"
  3539. " in executable but unreadable page.\n",
  3540. address);
  3541. }
  3542. }
  3543. else {
  3544. permissions = 0;
  3545. }
  3546. // Temporary workaround for IA32 debugging support.
  3547. //To be removed after fixing FlushIC(ProcessHandle) by MS.
  3548. if (BeingDebugged && (permissions & MEM_EXECUTE)) {
  3549. permissions |= MEM_WRITE; //Code in the BeingDebugged process can be
  3550. //modified remotely without any notification
  3551. }
  3552. }
  3553. else {
  3554. // error in NtQueryVirtualMemory cosidered as a query of inaccessible memory
  3555. permissions = 0;
  3556. *pRegionStart = (VOID *)((ULONG_PTR)address & ~((ULONG_PTR)BtlMemoryPageSize() - 1));
  3557. *pRegionSize = BtlMemoryPageSize();
  3558. }
  3559. return permissions;
  3560. }
  3561. BT_STATUS_CODE BtlMemoryReadRemote(
  3562. IN BT_HANDLE ProcessHandle,
  3563. IN VOID * BaseAddress,
  3564. OUT VOID * Buffer,
  3565. IN U32 RequestedSize
  3566. )
  3567. /*++
  3568. Routine Description:
  3569. Read virtual memory of another process
  3570. Arguments:
  3571. ProcessHandle - IN Process handle
  3572. BaseAddress - IN Memory region start
  3573. Buffer - OUT Buffer to read data
  3574. RequestedSize - IN Memory region size
  3575. Return Value:
  3576. BT_STATUS
  3577. --*/
  3578. {
  3579. NTSTATUS status;
  3580. status = NtReadVirtualMemory((HANDLE)ProcessHandle,
  3581. (PVOID)BaseAddress,
  3582. (PVOID)Buffer,
  3583. (SIZE_T)RequestedSize,
  3584. NULL);
  3585. if (status != STATUS_SUCCESS) {
  3586. BTLP_REPORT_NT_FAILURE("NtReadVirtualMemory", status);
  3587. return BT_STATUS_ACCESS_VIOLATION;
  3588. }
  3589. return BT_STATUS_SUCCESS;
  3590. }
  3591. BT_STATUS_CODE BtlMemoryWriteRemote(
  3592. IN BT_HANDLE ProcessHandle,
  3593. IN VOID * BaseAddress,
  3594. IN const VOID * Buffer,
  3595. IN U32 RequestedSize
  3596. )
  3597. /*++
  3598. Routine Description:
  3599. Write virtual memory of another process
  3600. Arguments:
  3601. ProcessHandle - IN Process handle
  3602. BaseAddress - IN Memory region start
  3603. Buffer - IN Buffer to write data from
  3604. RequestedSize - IN Memory region size
  3605. Return Value:
  3606. BT_STATUS
  3607. --*/
  3608. {
  3609. NTSTATUS status;
  3610. status = NtWriteVirtualMemory((HANDLE)ProcessHandle,
  3611. (PVOID)BaseAddress,
  3612. (PVOID)Buffer,
  3613. (SIZE_T)RequestedSize,
  3614. NULL);
  3615. if (status != STATUS_SUCCESS) {
  3616. BTLP_REPORT_NT_FAILURE("NtWriteVirtualMemory", status);
  3617. return BT_STATUS_ACCESS_VIOLATION;
  3618. }
  3619. return BT_STATUS_SUCCESS;
  3620. }
  3621. // Locking support (critical sections in NT)
  3622. BT_STATUS_CODE BtlInitAccessLock(
  3623. IN OUT VOID * lock
  3624. )
  3625. /*++
  3626. Routine Description:
  3627. Initialize lock (critical section)
  3628. Arguments:
  3629. lock - IN Pointer to the lock
  3630. Return Value:
  3631. BT_STATUS_CODE.
  3632. --*/
  3633. {
  3634. NTSTATUS status;
  3635. status = RtlInitializeCriticalSection ((PRTL_CRITICAL_SECTION) lock);
  3636. return ((status == STATUS_SUCCESS) ? BT_STATUS_SUCCESS : BT_STATUS_UNSUCCESSFUL);
  3637. }
  3638. BT_STATUS_CODE BtlLockAccess(
  3639. IN OUT VOID * lock,
  3640. IN U64 flag
  3641. )
  3642. /*++
  3643. Routine Description:
  3644. Access lock (enter or try to enter critical section)
  3645. Arguments:
  3646. lock - IN Pointer to the lock
  3647. flag - IN access flag (BLOCK - unconditional, otherwise - if available)
  3648. Return Value:
  3649. BT_STATUS_CODE
  3650. --*/
  3651. {
  3652. if (flag == BLOCK) {
  3653. NTSTATUS status;
  3654. status = RtlEnterCriticalSection ((PRTL_CRITICAL_SECTION) lock);
  3655. return ((status == STATUS_SUCCESS) ? BT_STATUS_SUCCESS : BT_STATUS_UNSUCCESSFUL);
  3656. }
  3657. else if (RtlTryEnterCriticalSection((PRTL_CRITICAL_SECTION) lock)) {
  3658. return BT_STATUS_SUCCESS;
  3659. }
  3660. else {
  3661. return BT_STATUS_UNSUCCESSFUL;
  3662. }
  3663. }
  3664. VOID BtlUnlockAccess(
  3665. IN OUT VOID * lock
  3666. )
  3667. /*++
  3668. Routine Description:
  3669. Release lock (critical section)
  3670. Arguments:
  3671. lock - IN Pointer to the lock
  3672. Return Value:
  3673. None.
  3674. --*/
  3675. {
  3676. NTSTATUS status;
  3677. status = RtlLeaveCriticalSection ((PRTL_CRITICAL_SECTION) lock);
  3678. BTLP_REPORT_NT_FAILURE("RtlLeaveCriticalSection", status);
  3679. }
  3680. VOID BtlInvalidateAccessLock(
  3681. IN OUT VOID * lock
  3682. )
  3683. /*++
  3684. Routine Description:
  3685. Delete lock (critical section)
  3686. Arguments:
  3687. lock - IN Pointer to the lock
  3688. Return Value:
  3689. None.
  3690. --*/
  3691. {
  3692. NTSTATUS status;
  3693. status = RtlDeleteCriticalSection ((PRTL_CRITICAL_SECTION) lock);
  3694. BTLP_REPORT_NT_FAILURE("RtlDeleteCriticalSection", status);
  3695. }
  3696. // Longjmp support.
  3697. // Setjmp and longjmp must be supplied directly,
  3698. // otherwise setjmp does not work!
  3699. // Need only JMP buffer size
  3700. U32 BtlQueryJmpbufSize(
  3701. VOID
  3702. )
  3703. /*++
  3704. Routine Description:
  3705. Report longjmp buffer size
  3706. Arguments:
  3707. None
  3708. Return Value:
  3709. Buffer size in bytes.
  3710. --*/
  3711. {
  3712. return sizeof (_JBTYPE) * _JBLEN;
  3713. }
  3714. VOID BtlYieldThreadExecution(
  3715. VOID
  3716. )
  3717. /*++
  3718. Routine Description:
  3719. Relinquish the remainder of the current thread's time slice
  3720. to any other thread that is ready to run
  3721. Arguments:
  3722. None
  3723. Return Value:
  3724. None
  3725. --*/
  3726. {
  3727. NtYieldExecution();
  3728. }
  3729. VOID BtlFlushIA64InstructionCache(
  3730. IN VOID * Address,
  3731. IN U32 Length
  3732. )
  3733. /*++
  3734. Routine Description:
  3735. Notify kernel about a modification in IA64 code made within the given region
  3736. Arguments:
  3737. Address - IN Pointer to start of the region
  3738. Length - IN Size of the region
  3739. Return Value:
  3740. None
  3741. --*/
  3742. {
  3743. NtFlushInstructionCache (NtCurrentProcess (), Address, (SIZE_T)Length);
  3744. }
  3745. #ifndef NODEBUG
  3746. //support Profiling debug mode
  3747. #define PROF_GEN
  3748. #endif
  3749. #ifdef PROF_GEN
  3750. // Define the method needed by IA-32 execution Layer profiling. They are
  3751. // 1. PGOFileOpen : Open a file for writing the profiling data
  3752. // 2. PGOFileClose : Close the file opened by PGOFileOpen
  3753. // 3. PGOFileWrite : Write profiling data
  3754. // Global handle use for containing the file handle openned by PGOFileOpen.
  3755. // This handle is defined as global instead of thread specific because PGOFileXXX operation
  3756. // is called only once per process.
  3757. HANDLE g_PGOFileHandle;
  3758. // The file offset associated with g_PGOFileHandle
  3759. LARGE_INTEGER g_PGOFileOffset;
  3760. // Function BtlPGOFileOpen
  3761. // Open a file for writing profiling data
  3762. // This is just a pseudo-function for C's fopen
  3763. // It output an (void *) type because the caller need to cast it into (FILE *) type.
  3764. VOID BtlPGOFileOpen(const char * filename,const char * mode,void ** pFileHandle)
  3765. {
  3766. UNICODE_STRING pgoFileName;
  3767. LARGE_INTEGER AllocSz = { 0, 0 };
  3768. OBJECT_ATTRIBUTES ObjectAttributes;
  3769. NTSTATUS ret;
  3770. WCHAR CurDirBuf[512],strInputFileName[64];
  3771. WCHAR CurrentDir[1024];
  3772. IO_STATUS_BLOCK IoStatusBlock;
  3773. int i;
  3774. DBCODE (TRUE,BtlpPrintf("PGO:fopen called: filename=%s, mode=%s\n",filename,mode));
  3775. RtlGetCurrentDirectory_U(512, CurrentDir);
  3776. for (i=0;filename[i] != '\0' && i<sizeof(strInputFileName)/sizeof(WCHAR)-1;i++)
  3777. strInputFileName[i]=(WCHAR)filename[i];
  3778. strInputFileName[i]=(WCHAR)0;
  3779. swprintf(CurDirBuf, L"\\DosDevices\\%s\\%s.%s", CurrentDir, ImageName, strInputFileName);
  3780. RtlInitUnicodeString(&pgoFileName, CurDirBuf);
  3781. InitializeObjectAttributes(&ObjectAttributes, &pgoFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
  3782. if (mode[0] == 'r' || mode[0] == 'R') {
  3783. //Read mode
  3784. ret = NtCreateFile (&g_PGOFileHandle,
  3785. GENERIC_READ,
  3786. &ObjectAttributes,
  3787. &IoStatusBlock,
  3788. &AllocSz,
  3789. FILE_ATTRIBUTE_NORMAL,
  3790. 0,
  3791. FILE_OPEN,//Use FILE_OPEN, if file doesn't exist, return fail
  3792. FILE_NON_DIRECTORY_FILE|FILE_RANDOM_ACCESS,
  3793. NULL, 0);
  3794. if ( ret != STATUS_SUCCESS ) {
  3795. g_PGOFileHandle=NULL;
  3796. *pFileHandle=NULL;
  3797. return;
  3798. }
  3799. else {
  3800. g_PGOFileOffset.LowPart=0;
  3801. g_PGOFileOffset.HighPart=0;
  3802. *pFileHandle=&g_PGOFileHandle;
  3803. return;
  3804. }
  3805. }
  3806. else if (mode[0] == 'w' || mode[0] == 'W') {
  3807. // Write mode
  3808. ret = NtCreateFile (&g_PGOFileHandle,
  3809. FILE_GENERIC_WRITE,//GENERIC_WRITE,
  3810. &ObjectAttributes,
  3811. &IoStatusBlock,
  3812. &AllocSz,
  3813. FILE_ATTRIBUTE_NORMAL,
  3814. 0,
  3815. FILE_SUPERSEDE,
  3816. FILE_NON_DIRECTORY_FILE|FILE_RANDOM_ACCESS|FILE_SYNCHRONOUS_IO_NONALERT,
  3817. NULL, 0);
  3818. if ( ret != STATUS_SUCCESS ) {
  3819. DBCODE (TRUE,BtlpPrintf("Open profile file for write fail, status: %#X\n",ret));
  3820. BTLIB_ABORT();
  3821. pFileHandle=NULL;
  3822. return;
  3823. }
  3824. g_PGOFileOffset.LowPart=0;
  3825. g_PGOFileOffset.HighPart=0;
  3826. *pFileHandle=&g_PGOFileHandle;
  3827. return;
  3828. }
  3829. else {
  3830. *pFileHandle=NULL;
  3831. return;
  3832. }
  3833. }
  3834. // Function BtlPGOFileClose
  3835. // A pseudo function for C's fclose
  3836. VOID BtlPGOFileClose(void * stream)
  3837. {
  3838. DBCODE (TRUE,BtlpPrintf("PGO:fclose called\n"));
  3839. assert(g_PGOFileHandle);
  3840. NtClose(g_PGOFileHandle);
  3841. g_PGOFileHandle=NULL;
  3842. g_PGOFileOffset.LowPart=0;
  3843. g_PGOFileOffset.HighPart=0;
  3844. }
  3845. // Function BtlPGOFileWrite
  3846. // A pseudo function for C's fwrite
  3847. VOID BtlPGOFileWrite(const void *buffer, size_t size, void *stream)
  3848. {
  3849. DBCODE (FALSE,BtlpPrintf("PGO:fwrite called\n"));
  3850. assert(g_PGOFileHandle);
  3851. assert(stream == &g_PGOFileHandle);
  3852. // Write
  3853. {
  3854. NTSTATUS ret;
  3855. IO_STATUS_BLOCK IoStatusBlock;
  3856. LARGE_INTEGER offset;
  3857. offset=g_PGOFileOffset;
  3858. g_PGOFileOffset.LowPart+=size;
  3859. ret = NtWriteFile(g_PGOFileHandle, NULL, NULL, NULL, &IoStatusBlock,
  3860. (void *)buffer, (ULONG)size, &offset, NULL);
  3861. if ( ret != STATUS_SUCCESS ) {
  3862. DBCODE (TRUE,BtlpPrintf("Writing profile file fail, status: %x\n",ret));
  3863. BTLIB_ABORT();
  3864. }
  3865. }
  3866. }
  3867. #else
  3868. // Define dummy function
  3869. VOID BtlPGOFileOpen(void) {}
  3870. VOID BtlPGOFileClose(void) {}
  3871. VOID BtlPGOFileWrite(void) {}
  3872. #endif
  3873. // BtlAPITable
  3874. API_TABLE_TYPE BtlAPITable={
  3875. BTGENERIC_VERSION,
  3876. BTGENERIC_API_STRING,
  3877. NO_OF_APIS,
  3878. API_TABLE_START_OFFSET,
  3879. {L"BTLib First Test Version (API 0.1)"},
  3880. {
  3881. #define BTLIB_RECORD(NAME) { (PLABEL_PTR_TYPE)Btl##NAME }
  3882. BTLIB_RECORD(GetThreadId),
  3883. BTLIB_RECORD(IA32Reenter),
  3884. BTLIB_RECORD(IA32LCall),
  3885. BTLIB_RECORD(IA32Interrupt),
  3886. BTLIB_RECORD(IA32JmpIA64),
  3887. BTLIB_RECORD(LockSignals),
  3888. BTLIB_RECORD(UnlockSignals),
  3889. BTLIB_RECORD(MemoryAlloc),
  3890. BTLIB_RECORD(MemoryFree),
  3891. BTLIB_RECORD(MemoryPageSize),
  3892. BTLIB_RECORD(MemoryChangePermissions),
  3893. BTLIB_RECORD(MemoryQueryPermissions),
  3894. BTLIB_RECORD(MemoryReadRemote),
  3895. BTLIB_RECORD(MemoryWriteRemote),
  3896. { (PLABEL_PTR_TYPE)NULL},//BTLIB_RECORD(Atomic_Misaligned_Load),
  3897. { (PLABEL_PTR_TYPE)NULL},//BTLIB_RECORD(Atomic_Misaligned_Store),
  3898. BTLIB_RECORD(SuspendThread),
  3899. BTLIB_RECORD(ResumeThread),
  3900. BTLIB_RECORD(InitAccessLock),
  3901. BTLIB_RECORD(LockAccess),
  3902. BTLIB_RECORD(UnlockAccess),
  3903. BTLIB_RECORD(InvalidateAccessLock),
  3904. BTLIB_RECORD(QueryJmpbufSize),
  3905. { (PLABEL_PTR_TYPE)NULL},//BTLIB_RECORD(Setjmp),
  3906. { (PLABEL_PTR_TYPE)NULL},//BTLIB_RECORD(Longjmp),
  3907. BTLIB_RECORD(DebugPrint),
  3908. BTLIB_RECORD(Abort),
  3909. BTLIB_RECORD(VtuneCodeCreated),
  3910. BTLIB_RECORD(VtuneCodeDeleted),
  3911. BTLIB_RECORD(VtuneEnteringDynamicCode),
  3912. BTLIB_RECORD(VtuneExitingDynamicCode),
  3913. BTLIB_RECORD(VtuneCodeToTIADmpFile),
  3914. BTLIB_RECORD(SscPerfGetCounter64),
  3915. BTLIB_RECORD(SscPerfSetCounter64),
  3916. BTLIB_RECORD(SscPerfSendEvent),
  3917. BTLIB_RECORD(SscPerfEventHandle),
  3918. BTLIB_RECORD(SscPerfCounterHandle),
  3919. BTLIB_RECORD(YieldThreadExecution),
  3920. BTLIB_RECORD(FlushIA64InstructionCache),
  3921. BTLIB_RECORD(PGOFileOpen), // Indexed by IDX_BTLIB_PSEUDO_OPEN_FILE
  3922. BTLIB_RECORD(PGOFileClose), // Indexed by IDX_BTLIB_PSEUDO_CLOSE_FILE
  3923. BTLIB_RECORD(PGOFileWrite) // Indexed by IDX_BTLIB_PSEUDO_WRITE_FILE
  3924. }
  3925. };
  3926. // wowIA32X.dll placeholder table for IA32Exec.bin plabel pointers
  3927. PLABEL_PTR_TYPE BtlPlaceHolderTable[NO_OF_APIS];
  3928. // WINNT DLL initializer/terminator
  3929. BOOL APIENTRY DllMain(HANDLE hModule,
  3930. DWORD ul_reason_for_call,
  3931. LPVOID lpReserved )
  3932. {
  3933. return TRUE;
  3934. }