Windows NT 4.0 source code leak
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.

1617 lines
40 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. mach.c
  5. Abstract:
  6. This file contains the x86 specific code for dealing with
  7. machine dependent issues that invlove registers, instruction
  8. disassembly, function calling and other interesting things.
  9. Author:
  10. Jim Schaad (jimsch)
  11. Environment:
  12. Win32 - User
  13. Notes:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. extern CRITICAL_SECTION csContinueQueue;
  18. /**********************************************************************/
  19. extern LPDM_MSG LpDmMsg;
  20. /**********************************************************************/
  21. #ifdef WIN32S
  22. extern BOOL fCanGetThreadContext;
  23. typedef struct tagWin32sSystemDll {
  24. struct tagWin32sSystemDll * pNext;
  25. DWORD dwStart;
  26. DWORD dwEnd;
  27. } WIN32S_SYSTEM_DLL, * LPWIN32S_SYSTEM_DLL;
  28. // sorted list of win32s system dll names. NULL terminated.
  29. UCHAR * szWin32sSystemDllTable[] = {
  30. "advapi32.dll",
  31. "comdlg32.dll",
  32. "gdi32.dll",
  33. "kernel32.dll",
  34. "lz32.dll",
  35. "ntdll.dll",
  36. "olecli32.dll",
  37. "olesrv32.dll",
  38. "shell32.dll",
  39. "user32.dll",
  40. "version.dll",
  41. "w32skrnl.dll",
  42. NULL
  43. };
  44. #define WIN32S_LOAD_EPSILON 15 // 15 bytes min between sections
  45. DWORD Win32sSystemDllFirst = 0xFFFFFFFF;
  46. DWORD Win32sSystemDllLast = 0;
  47. LPWIN32S_SYSTEM_DLL pWin32sSystemDlls = NULL; // start list empty
  48. FARPROC Win32sBackTo32 = NULL; // BackTo32 thunk return address
  49. #endif // WIN32S
  50. #if DBG
  51. static char * rgszTrace[] = {
  52. "Trace", "BreakPoint", "Cannot Trace", "Soft Int", "Call"
  53. };
  54. #endif // DBG
  55. #define MAXL 20L
  56. #define BIT20(b) (b & 0x07)
  57. #define BIT53(b) (b >> 3 & 0x07)
  58. #define BIT76(b) (b >> 6 & 0x03)
  59. static int mod; /* mod of mod/rm byte */
  60. //
  61. // Stuff for debug registers
  62. //
  63. typedef struct _DR7 *PDR7;
  64. typedef struct _DR7 {
  65. DWORD L0 : 1;
  66. DWORD G0 : 1;
  67. DWORD L1 : 1;
  68. DWORD G1 : 1;
  69. DWORD L2 : 1;
  70. DWORD G2 : 1;
  71. DWORD L3 : 1;
  72. DWORD G3 : 1;
  73. DWORD LE : 1;
  74. DWORD GE : 1;
  75. DWORD Pad1 : 3;
  76. DWORD GD : 1;
  77. DWORD Pad2 : 1;
  78. DWORD Pad3 : 1;
  79. DWORD Rwe0 : 2;
  80. DWORD Len0 : 2;
  81. DWORD Rwe1 : 2;
  82. DWORD Len1 : 2;
  83. DWORD Rwe2 : 2;
  84. DWORD Len2 : 2;
  85. DWORD Rwe3 : 2;
  86. DWORD Len3 : 2;
  87. } DR7;
  88. #define RWE_EXEC 0x00
  89. #define RWE_WRITE 0x01
  90. #define RWE_RESERVED 0x02
  91. #define RWE_READWRITE 0x03
  92. DWORD LenMask[ MAX_DEBUG_REG_DATA_SIZE + 1 ] = DEBUG_REG_LENGTH_MASKS;
  93. BOOL
  94. IsRet(
  95. HTHDX hthd,
  96. LPADDR addr
  97. )
  98. {
  99. BYTE instr;
  100. DWORD cBytes;
  101. if (!AddrReadMemory( hthd->hprc, hthd, addr, &instr, 1, &cBytes )) {
  102. return FALSE;
  103. }
  104. return ((instr == 0xc2) || (instr == 0xc3) || (instr == 0xca) || (instr == 0xcb));
  105. }
  106. void
  107. IsCall(
  108. HTHDX hthd,
  109. LPADDR lpaddr,
  110. LPINT lpf,
  111. BOOL fStepOver
  112. )
  113. /*++
  114. Routine Description:
  115. This function checks to see if the specified instruction is
  116. a call instruction.
  117. Arguments:
  118. hthd - Supplies the handle to the current thread
  119. lpaddr - Supplies the address to check for the call instruction at
  120. lpf - Returns TRUE if is a call instruction
  121. fStepOver - Supplies TRUE if doing a step over
  122. Return Value:
  123. None.
  124. --*/
  125. {
  126. int mode_32;
  127. int opsize_32;
  128. DWORD cBytes;
  129. DWORD cb;
  130. char membuf [ MAXL ];
  131. char *pMem;
  132. UCHAR opcode;
  133. int fPrefix;
  134. int fRepPrefix;
  135. int ttt;
  136. int mode;
  137. int rm;
  138. BOOL fAddrSet;
  139. ULONG rgul[2];
  140. USHORT rgus[2];
  141. ADDR addrSp;
  142. /*
  143. * If we have already done this work and cached the answer then
  144. * pick up the answer from the cache. The cache marker is cleared
  145. * at the start of ProcessDebugEvent.
  146. */
  147. if (hthd->fIsCallDone) {
  148. *lpaddr = hthd->addrIsCall;
  149. *lpf = hthd->iInstrIsCall;
  150. return;
  151. }
  152. /*
  153. * local addressing mode
  154. */
  155. mode_32 = opsize_32 = hthd->fAddrOff32;
  156. /*
  157. * Read enough bytes to get the longest possible instruction
  158. */
  159. if (!AddrReadMemory( hthd->hprc,
  160. hthd,
  161. lpaddr,
  162. membuf,
  163. MAXL,
  164. &cBytes) ||
  165. (cBytes == 0)) {
  166. *lpf = INSTR_CANNOT_TRACE;
  167. goto done;
  168. }
  169. DPRINT(1, ("(IsCall?) EIP=%08x Type=", *lpaddr));
  170. /*
  171. * point to begin of instruction
  172. */
  173. pMem = membuf;
  174. /*
  175. * read and process any prefixes first
  176. */
  177. fPrefix = TRUE;
  178. fRepPrefix = FALSE;
  179. do {
  180. opcode = (UCHAR) *pMem++; /* get opcode */
  181. /*
  182. * Operand size prefix
  183. */
  184. if (opcode == 0x66) {
  185. opsize_32 = !opsize_32;
  186. }
  187. /*
  188. * Address size prefix
  189. */
  190. else if (opcode == 0x67) {
  191. mode_32 = !mode_32;
  192. }
  193. /*
  194. * REP and REPNE prefix
  195. */
  196. else if ((opcode & ~1) == 0xf2) {
  197. fRepPrefix = TRUE;
  198. }
  199. /*
  200. * LOCK prefix (0xf0)
  201. * Segment Override (0x26, 0x36, 0x2e, 0x3e, 0x64, 0x65)
  202. */
  203. else if ( opcode != 0xf0 &&
  204. (opcode & ~0x18) != 0x26 &&
  205. (opcode & ~1) != 0x64 ) {
  206. fPrefix = FALSE;
  207. }
  208. } while ( fPrefix );
  209. /*
  210. * Now start checking for the instructions which must be treated
  211. * in a special manner. Any instruction which does not respect
  212. * the trace bit (either due to flag munging or faulting) needs
  213. * to be treated specially. Also all call ops need to be treated
  214. * specially (step in vs step over). Finally interupts need to
  215. * be treated specially since they could cause faults in 16-bit mode
  216. */
  217. fAddrSet = FALSE;
  218. /*
  219. * Break point instruction
  220. */
  221. if (opcode == 0xcc) {
  222. *lpf = INSTR_BREAKPOINT;
  223. }
  224. // NOTENOTE -- missing the INTO instruction
  225. /*
  226. * all other interrrupt instructions
  227. */
  228. else if (opcode == 0xcd) {
  229. opcode = (UCHAR) *pMem++;
  230. /*
  231. * Is this really a 2-byte version of INT 3 ?
  232. */
  233. if (opcode == 0x3) {
  234. *lpf = INSTR_BREAKPOINT;
  235. }
  236. /*
  237. * Is this a funky 16-bit floating point instruction? if so then
  238. * we need to make sure and step over it
  239. */
  240. else if (!ADDR_IS_FLAT(*lpaddr) &&
  241. (0x34 <= opcode) && (opcode <= 0x3c)) {
  242. if (opcode == 0x3C) {
  243. pMem++;
  244. }
  245. opcode = *pMem++;
  246. mode = opcode & 0xc0;
  247. rm = opcode & 0x03;
  248. switch ( mode) {
  249. case 0:
  250. if (rm == 0x6) {
  251. pMem += 2;
  252. }
  253. break;
  254. case 1:
  255. pMem += 1;
  256. break;
  257. case 2:
  258. pMem += 2;
  259. break;
  260. }
  261. *lpf = INSTR_CANNOT_TRACE;
  262. GetAddrOff(*lpaddr) += pMem - membuf;
  263. fAddrSet = TRUE;
  264. }
  265. /*
  266. * This is an FWAIT instr -- 2 bytes long
  267. */
  268. else if (!ADDR_IS_FLAT(*lpaddr) && opcode == 0x3d) {
  269. *lpf = INSTR_CANNOT_TRACE;
  270. GetAddrOff(*lpaddr) += 2;
  271. fAddrSet = TRUE;
  272. }
  273. /*
  274. * This is a 0x3f interrupt -- I think this is for
  275. * overlays in dos
  276. */
  277. else if (!ADDR_IS_FLAT(*lpaddr) && (opcode == 0x3f)) {
  278. if (fStepOver) {
  279. *lpf = INSTR_CANNOT_TRACE;
  280. AddrInit(&addrSp, 0, SsSegOfHthdx(hthd), STACK_POINTER(hthd),
  281. FALSE, FALSE, FALSE, hthd->fAddrIsReal);
  282. if (!AddrReadMemory(hthd->hprc,
  283. hthd,
  284. &addrSp,
  285. rgus,
  286. 4,
  287. &cb) ||
  288. (cb != 4) ) {
  289. goto done;
  290. }
  291. AddrInit(lpaddr, 0, rgus[1], (UOFF32) rgus[0], FALSE, FALSE,
  292. FALSE, hthd->fAddrIsReal);
  293. fAddrSet = TRUE;
  294. }
  295. }
  296. /*
  297. * OK its really an interrupt --- deal with it
  298. */
  299. else {
  300. if (!fStepOver && hthd->fAddrIsReal) {
  301. *lpf = INSTR_CANNOT_TRACE;
  302. AddrInit(&addrSp, 0, 0, opcode*4, FALSE, FALSE, FALSE, TRUE);
  303. if (!AddrReadMemory(hthd->hprc,
  304. hthd,
  305. &addrSp,
  306. rgus,
  307. 4,
  308. &cb) ||
  309. (cb != 4) ) {
  310. goto done;
  311. }
  312. AddrInit(lpaddr, 0, rgus[1], (UOFF32) rgus[0], FALSE, FALSE,
  313. FALSE, TRUE);
  314. fAddrSet = TRUE;
  315. }
  316. }
  317. }
  318. /*
  319. * Now check for various call instructions
  320. */
  321. else if (opcode == 0xe8) { /* near direct call */
  322. *lpf = INSTR_IS_CALL;
  323. pMem += (1 + opsize_32)*2;
  324. } else if (opcode == 0x9a) { /* far direct call */
  325. *lpf = INSTR_IS_CALL;
  326. pMem += (2 + opsize_32)*2;
  327. } else if (opcode == 0xff) {
  328. opcode = *pMem++; /* compute the modRM bits for instruction */
  329. ttt = BIT53(opcode);
  330. if ((ttt & ~1) == 2) { /* indirect call */
  331. *lpf = INSTR_IS_CALL;
  332. mod = BIT76(opcode);
  333. if (mod != 3) { /* non-register operand */
  334. rm = BIT20( opcode );
  335. if (mode_32) {
  336. if (rm == 4) {
  337. rm = BIT20(*pMem++); /* get base from SIB */
  338. }
  339. if (mod == 0) {
  340. if (rm == 5) {
  341. pMem += 4; /* long direct address */
  342. }
  343. } else if (mod == 1) {
  344. pMem++; /* register with byte offset */
  345. } else {
  346. pMem += 4; /* register with long offset */
  347. }
  348. } else { /* 16-bit mode */
  349. if (mod == 0) {
  350. if (rm == 6) {
  351. pMem += 2; /* short direct address */
  352. }
  353. } else {
  354. pMem += mod; /* reg, byte, word offset */
  355. }
  356. }
  357. }
  358. }
  359. }
  360. /*
  361. * Now catch all of the repeated instructions
  362. *
  363. * INSB (0x6c) INSW (0x6d) OUTSB (0x6e) OUTSW (0x6f)
  364. * MOVSB (0xa4) MOVSW (0xa5) CMPSB (0xa6) CMPSW (0xa7)
  365. * STOSB (0xaa) STOSW (0xab)
  366. * LODSB (0xac) LODSW (0xad) SCASB (0xae) SCASW (0xaf)
  367. */
  368. else if (fRepPrefix && (((opcode & ~3) == 0x6c) ||
  369. ((opcode & ~3) == 0xa4) ||
  370. ((opcode & ~1) == 0xaa) ||
  371. ((opcode & ~3) == 0xac))) {
  372. if (fStepOver) {
  373. *lpf = INSTR_CANNOT_TRACE;
  374. } else {
  375. /*
  376. * Cannot trace the ins/outs instructions
  377. */
  378. if ((opcode & ~3) == 0x6c) {
  379. *lpf = INSTR_CANNOT_TRACE;
  380. }
  381. }
  382. }
  383. /*
  384. * Now catch IO instructions -- these will generally fault and
  385. * be interpreted.
  386. */
  387. else if ((opcode & ~3) == 0x6c) {
  388. *lpf = INSTR_CANNOT_TRACE;
  389. }
  390. /*
  391. * Now catch other instructions which change registers
  392. */
  393. else if ((opcode == 0xfa) || (opcode == 0xfb) ||
  394. (opcode == 0x9d) || (opcode == 0x9c)) {
  395. *lpf = INSTR_CANNOT_TRACE;
  396. }
  397. /*
  398. * Now catch irets
  399. */
  400. else if (opcode == 0xcf) {
  401. *lpf = INSTR_CANNOT_TRACE;
  402. AddrInit(&addrSp, 0, SsSegOfHthdx(hthd), STACK_POINTER(hthd),
  403. hthd->fAddrIsFlat, hthd->fAddrOff32, FALSE,
  404. hthd->fAddrIsReal);
  405. if (opsize_32) {
  406. if (!AddrReadMemory(hthd->hprc,
  407. hthd,
  408. &addrSp,
  409. rgul,
  410. 8,
  411. &cb) ||
  412. (cb != 8) ) {
  413. goto done;
  414. }
  415. AddrInit(lpaddr, 0, (SEGMENT) rgul[1], rgul[0],
  416. hthd->fAddrIsFlat, TRUE, FALSE, FALSE);
  417. } else {
  418. if (!AddrReadMemory(hthd->hprc,
  419. hthd,
  420. &addrSp,
  421. rgus,
  422. 4,
  423. &cb) ||
  424. (cb != 4) ) {
  425. goto done;
  426. }
  427. AddrInit(lpaddr, 0, rgus[1], (UOFF32) rgus[0], FALSE, FALSE,
  428. FALSE, hthd->fAddrIsReal);
  429. }
  430. fAddrSet = TRUE;
  431. }
  432. /*
  433. * Assume that we want to just trace the instruction
  434. */
  435. else {
  436. *lpf = INSTR_TRACE_BIT;
  437. goto done;
  438. }
  439. /*
  440. *
  441. */
  442. DPRINT(1, ("%s", rgszTrace[*lpf]));
  443. /*
  444. * Have read enough bytes? no -- expect somebody else to blow up
  445. */
  446. if (cBytes < (DWORD)(pMem - membuf)) {
  447. *lpf = INSTR_TRACE_BIT;
  448. goto done;
  449. }
  450. if (!fAddrSet) {
  451. GetAddrOff(*lpaddr) += pMem - membuf;
  452. }
  453. /*
  454. * Dump out the bytes for later checking
  455. */
  456. #if DBG
  457. if (FVerbose) {
  458. DWORD i;
  459. DPRINT(1, ("length = %d bytes=", cBytes & 0xff));
  460. for (i=0; i<cBytes; i++) {
  461. DPRINT(1, (" %02x", membuf[i]));
  462. }
  463. }
  464. #endif
  465. done:
  466. hthd->fIsCallDone = TRUE;
  467. hthd->addrIsCall = *lpaddr;
  468. hthd->iInstrIsCall = *lpf;
  469. return;
  470. } /* IsCall() */
  471. XOSD
  472. SetupFunctionCall(
  473. LPEXECUTE_OBJECT_DM lpeo,
  474. LPEXECUTE_STRUCT lpes
  475. )
  476. /*++
  477. Routine Description:
  478. This function contains the machine dependent code for initializing
  479. the function call system.
  480. Arguments:
  481. lpeo - Supplies a pointer to the Execute Object for the Function call
  482. lpes - Supplies a pointer to the Execute Struct from the DM
  483. Return Value:
  484. XOSD error code
  485. --*/
  486. {
  487. CONTEXT context;
  488. OFFSET off;
  489. int cb;
  490. ULONG ul;
  491. HPRCX hprc = lpeo->hthd->hprc;
  492. ADDR addr;
  493. /*
  494. * Can only execute functions on the current stopped thread. Therefore
  495. * assert that the current thread is stopped.
  496. */
  497. assert(lpeo->hthd->tstate & ts_stopped);
  498. if (!(lpeo->hthd->tstate & ts_stopped)) {
  499. return xosdInvalidThread;
  500. }
  501. /*
  502. * Can copy the context from the cached context in the thread structure
  503. */
  504. context = lpeo->hthd->context;
  505. /*
  506. * Now get the current stack offset
  507. */
  508. lpeo->addrStack.addr.off = context.Esp;
  509. lpeo->addrStack.addr.seg = (SEGMENT) context.SegSs;
  510. if (!lpeo->hthd->fAddrOff32) {
  511. lpeo->addrStack.addr.off &= 0xffff;
  512. }
  513. /*
  514. * Put the return address onto the stack. If this is a far address
  515. * then it needs to be a far return address. Else it must be a
  516. * near return address.
  517. */
  518. if (lpeo->hthd->fAddrOff32) {
  519. if (lpes->fFar) {
  520. assert(FALSE); /* Not used for Win32 */
  521. }
  522. off = context.Esp - 4;
  523. if (DbgWriteMemory(hprc, (char *) off, &lpeo->addrStart.addr.off,
  524. 4, &cb) == 0 ||
  525. (cb != 4)) {
  526. return xosdUnknown;
  527. }
  528. } else {
  529. if (lpes->fFar) {
  530. off = context.Esp - 4;
  531. ul = (lpeo->addrStart.addr.seg << 16) | lpeo->addrStart.addr.off;
  532. addr = lpeo->addrStack;
  533. GetAddrOff(addr) -= 4;
  534. TranslateAddress(hprc, lpeo->hthd, &addr, TRUE);
  535. if ((DbgWriteMemory(hprc, (char *) GetAddrOff(addr),
  536. &ul, 4, &cb) == 0) ||
  537. (cb != 4)) {
  538. return xosdUnknown;
  539. }
  540. } else {
  541. off = context.Esp & 0xffff - 2;
  542. addr = lpeo->addrStack;
  543. GetAddrOff(addr) -= 2;
  544. TranslateAddress(hprc, lpeo->hthd, &addr, TRUE);
  545. if ((DbgWriteMemory(hprc, (char *) GetAddrOff(addr),
  546. &lpeo->addrStart.addr.off, 2, &cb) == 0) ||
  547. (cb != 2)) {
  548. return xosdUnknown;
  549. }
  550. }
  551. }
  552. /*
  553. * Set the new stack pointer and starting address in the context and
  554. * write them back to the thread.
  555. */
  556. lpeo->hthd->context.Esp = off;
  557. lpeo->hthd->context.Eip = lpeo->addrStart.addr.off;
  558. lpeo->hthd->fContextDirty = TRUE;
  559. return xosdNone;
  560. } /* SetupFunctionCall() */
  561. BOOL
  562. CompareStacks(
  563. LPEXECUTE_OBJECT_DM lpeo
  564. )
  565. /*++
  566. Routine Description:
  567. This routine is used to determine if the stack pointers are currect
  568. for terminating function evaluation.
  569. Arguments:
  570. lpeo - Supplies the pointer to the DM Execute Object description
  571. Return Value:
  572. TRUE if the evaluation is to be terminated and FALSE otherwise
  573. --*/
  574. {
  575. if (lpeo->hthd->fAddrOff32) {
  576. if (lpeo->addrStack.addr.off <= lpeo->hthd->context.Esp) {
  577. return TRUE;
  578. }
  579. } else if ((lpeo->addrStack.addr.off <= (lpeo->hthd->context.Esp & 0xffff)) &&
  580. (lpeo->addrStack.addr.seg == (SEGMENT) lpeo->hthd->context.SegSs)) {
  581. return TRUE;
  582. }
  583. return FALSE;
  584. } /* CompareStacks() */
  585. #ifdef WIN32S
  586. /*
  587. * IsWin32sSystemDll
  588. *
  589. * INPUTS szImageName = asciiz name of dll (may include path)
  590. * OUTPUTS returns TRUE if the dll name is in the set of Win32s system dlls.
  591. * SUMMARY Simple table search. The table of names is sorted and NULL
  592. * terminated.
  593. */
  594. BOOL IsWin32sSystemDll(UCHAR * szImageName) {
  595. USHORT i = 0;
  596. int cmp;
  597. UCHAR * pTemp;
  598. if (! szImageName) {
  599. return(FALSE);
  600. }
  601. // break off path
  602. pTemp = szImageName + strlen(szImageName) - 1; // point to end of string
  603. while ((pTemp > szImageName) && (*pTemp != ':') && (*pTemp != '\\')) {
  604. pTemp--;
  605. }
  606. if (*pTemp == ':' || *pTemp == '\\') {
  607. pTemp++;
  608. }
  609. // linear search in sorted table (NULL terminated)
  610. while (szWin32sSystemDllTable[i] &&
  611. ((cmp = _stricmp(szWin32sSystemDllTable[i], pTemp)) < 0)) {
  612. i++;
  613. }
  614. return(cmp == 0); // _stricmp --> 0 on match
  615. }
  616. /*
  617. * IsWin32sSystemDllAddr
  618. *
  619. * INPUTS dwOffset
  620. * OUTPUTS TRUE if dwOffset fits into a range found in the system dll table.
  621. * SUMMARY Search the ranges in the table until the Start value is > dwOffset.
  622. */
  623. BOOL
  624. IsWin32sSystemDllAddr(
  625. DWORD dwOffset
  626. )
  627. {
  628. LPWIN32S_SYSTEM_DLL pNode = pWin32sSystemDlls;
  629. if (dwOffset < Win32sSystemDllFirst || dwOffset > Win32sSystemDllLast) {
  630. return(FALSE); // quick check
  631. }
  632. // otherwise, do the search
  633. while (pNode && (pNode->dwStart <= dwOffset)) {
  634. if (dwOffset <= pNode->dwEnd && dwOffset >= pNode->dwStart) {
  635. return(TRUE); // in range
  636. }
  637. pNode = pNode->pNext;
  638. }
  639. return(FALSE);
  640. }
  641. /*
  642. * AddWin32sSystemDllAddr
  643. *
  644. * INPUTS dwOffset = start address for object
  645. * cbObject = size of object
  646. * OUTPUTS none
  647. * SUMMARY Add the addresses in between {offset, offset+cbObject} to the
  648. * Win32s System Dlls list. If the offset is within
  649. * WIN32S_LOAD_EPSILON of another entry, tack them together. (The
  650. * idea is that the loader won't load any of the user's code in
  651. * there anyway and we want to speed up list searches.) The list
  652. * will be maintained in sorted order. We will also maintain the
  653. * Win32sSystemDllFirst and Win32sSystemDllLast offsets for a quick
  654. * elimination of most list searches.
  655. */
  656. void
  657. AddWin32sSystemDllAddr(
  658. DWORD dwOffset,
  659. DWORD cbObject
  660. )
  661. {
  662. DWORD dwEnd = dwOffset + cbObject - 1; // ending offset
  663. LPWIN32S_SYSTEM_DLL pNode, pPrev, pNew;
  664. assert(dwOffset < dwEnd);
  665. // Update Win32sSystemDllFirst/Last
  666. Win32sSystemDllFirst = min(Win32sSystemDllFirst, dwOffset);
  667. Win32sSystemDllLast = max(Win32sSystemDllLast, dwEnd);
  668. // find insert point and insert new node for section
  669. pPrev = NULL;
  670. pNode = pWin32sSystemDlls; // head of list
  671. while (pNode && pNode->dwStart < dwOffset) {
  672. pPrev = pNode;
  673. pNode = pNode->pNext;
  674. }
  675. if ((pNew = malloc(sizeof(WIN32S_SYSTEM_DLL))) == NULL) {
  676. assert(FALSE);
  677. return; //error, no memory
  678. }
  679. if (pPrev) { // insert point is middle or end, not head
  680. pPrev->pNext = pNew;
  681. } else { // insert at head, update global head pointer
  682. pWin32sSystemDlls = pNew;
  683. }
  684. // fill in new node
  685. pNew->dwStart = dwOffset;
  686. pNew->dwEnd = dwEnd;
  687. pNew->pNext = pNode;
  688. // Remove overlap. It can only happen near the new node.
  689. // merge with prev
  690. if (pPrev && pPrev->dwEnd + WIN32S_LOAD_EPSILON >= pNew->dwStart) {
  691. pPrev->dwEnd = max(pNew->dwEnd, pPrev->dwEnd);
  692. pPrev->pNext = pNew->pNext;
  693. free(pNew);
  694. pNew = pPrev;
  695. }
  696. // merge with next (may be more than one if we have large dwEnd)
  697. while (pNode && pNode->dwStart <= pNew->dwEnd + WIN32S_LOAD_EPSILON) {
  698. pNew->dwEnd = max(pNode->dwEnd, pNew->dwEnd);
  699. pNew->pNext = pNode->pNext;
  700. free(pNode);
  701. pNode = pNew->pNext;
  702. }
  703. }
  704. /*
  705. * FreeWin32sDllList
  706. *
  707. * INPUTS none
  708. * OUTPUTS none
  709. * SUMMARY free all the memory in the win32s system dll list and set the
  710. * global head pointer to null.
  711. */
  712. void
  713. FreeWin32sDllList(
  714. void
  715. )
  716. {
  717. LPWIN32S_SYSTEM_DLL pNode, pNext;
  718. pNode = pWin32sSystemDlls;
  719. pWin32sSystemDlls = NULL;
  720. while (pNode) {
  721. pNext = pNode->pNext;
  722. free(pNode);
  723. pNode = pNext;
  724. }
  725. }
  726. WIN32S_TRACE_CHECK
  727. IsWin32sSystemThunk(
  728. HPRCX hprc,
  729. HTHDX hthd,
  730. DWORD currAddr,
  731. DWORD stackPtr
  732. )
  733. /*
  734. * IsWin32sSystemThunk
  735. *
  736. * INPUTS rwHand = handle to the process
  737. * currAddr = EIP to check for a thunk call
  738. * stackPtr = current ESP
  739. * OUTPUT WIN32S_TRACE_OK: not a jump or call to win32s code
  740. * WIN32S_THUNK_CALL: the instr is a call to win32s code
  741. * WIN32S_THUNK_JUMP: the instr is a jump or ret to win32s code
  742. * SUMMARY This is kinda twisted: Thunks look like this:
  743. *
  744. * ApiCall(p1, p2, etc);
  745. * push
  746. * push
  747. * etc.
  748. * call _ApiCall@8
  749. * e8 {offset} where offset is the distance from the start
  750. * of the next instruction. The destination of
  751. * the call is eip+5+offset.
  752. *
  753. * _ApiCall@8:
  754. * jmp dword ptr [system call address]
  755. * ff 25 {address} where address is the address to read the
  756. * destination from.
  757. *
  758. * Anyway, we want to recognize this situation and check the final
  759. * destination against the known address space of the system dlls.
  760. * For this, we will look in the table compiled during dll loads.
  761. *
  762. * WARNWARN This code is very i386 specific, but that should be ok since it is
  763. * only intended to run on Win32s machines.
  764. *
  765. */
  766. {
  767. WIN32S_TRACE_CHECK wtcReturn = WIN32S_TRACE_OK;
  768. BYTE InstructionBuffer[6] = {0};
  769. DWORD dwDestination;
  770. DWORD * pdwDestination;
  771. DWORD dwIndirect;
  772. DWORD * pdwIndirect;
  773. DWORD dwBytesRead;
  774. ADDR addr;
  775. DEBUG_PRINT_1("\r\nIsWin32sSystemThunk(0x%x)\r\n", currAddr);
  776. try { // in case instruction would generate gp-fault
  777. // read the current instruction
  778. AddrInit(&addr, 0, 0, (OFFSET)currAddr, TRUE, TRUE, FALSE, FALSE);
  779. if (AddrReadMemory(hprc, hthd, &addr, InstructionBuffer, 5,
  780. &dwBytesRead)) {
  781. // got the current instruction. What is it?
  782. switch (InstructionBuffer[0]) {
  783. case (BYTE)0xe8: // Near call
  784. // call to where?
  785. pdwDestination = (DWORD *)(&InstructionBuffer[1]);
  786. dwDestination = *pdwDestination + currAddr + 5;
  787. DEBUG_PRINT_1("Found a call to 0x%x\r\n", dwDestination);
  788. AddrInit(&addr, 0, 0, (OFFSET)dwDestination, TRUE, TRUE, FALSE, FALSE);
  789. if (AddrReadMemory(hprc, hthd, &addr, InstructionBuffer, 6,
  790. &dwBytesRead)) {
  791. // Got the destination instruction, is it a jmp
  792. // indirect?
  793. if (InstructionBuffer[0] == (BYTE)0xff &&
  794. InstructionBuffer[1] == (BYTE)0x25) {
  795. // Jump indirect to where?
  796. pdwIndirect = (DWORD *)(&InstructionBuffer[2]);
  797. dwIndirect = *pdwIndirect;
  798. DEBUG_PRINT_1(
  799. "Found a call -> jump indirect to 0x%x\r\n",
  800. dwIndirect);
  801. AddrInit(&addr, 0, 0, (OFFSET)dwIndirect, TRUE, TRUE, FALSE, FALSE);
  802. if (AddrReadMemory(hprc, hthd, &addr,
  803. InstructionBuffer, 4, &dwBytesRead)) {
  804. pdwDestination = (DWORD *)InstructionBuffer;
  805. if (IsWin32sSystemDllAddr(*pdwDestination)) {
  806. wtcReturn = WIN32S_THUNK_CALL;
  807. }
  808. }
  809. }
  810. }
  811. break;
  812. case (BYTE)0xc2: // retn N
  813. case (BYTE)0xc3: // retn
  814. // check if we are about to return to win32s system code...
  815. // look at [esp]. If it is in system dll, do a Go
  816. // Special case: If the current address is Win32sBackTo32+4
  817. // don't do the check, we want to allow the trace back to
  818. // User32.dll.
  819. if (currAddr == (DWORD)Win32sBackTo32) {
  820. break;
  821. }
  822. // read return address from stack
  823. AddrInit(&addr, 0, 0, (OFFSET)stackPtr, TRUE, TRUE, FALSE, FALSE);
  824. if (AddrReadMemory(hprc, hthd, &addr, InstructionBuffer, 4,
  825. &dwBytesRead)) {
  826. pdwDestination = (DWORD *)InstructionBuffer;
  827. if (IsWin32sSystemDllAddr(*pdwDestination)) {
  828. wtcReturn = WIN32S_THUNK_JUMP;
  829. }
  830. }
  831. break;
  832. // BRUCEK: should also check for JUMP FAR to 16-bit. What does
  833. // that look like?
  834. default:
  835. break;
  836. }
  837. }
  838. } except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  839. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
  840. }
  841. switch (wtcReturn) {
  842. case WIN32S_THUNK_CALL:
  843. DEBUG_PRINT("IsWin32sSystemThunk --> WIN32S_THUNK_CALL\r\n");
  844. break;
  845. case WIN32S_THUNK_JUMP:
  846. DEBUG_PRINT("IsWin32sSystemThunk --> WIN32S_THUNK_JUMP\r\n");
  847. break;
  848. case WIN32S_TRACE_OK:
  849. DEBUG_PRINT("IsWin32sSystemThunk --> WIN32S_TRACE_OK\r\n");
  850. break;
  851. default:
  852. DEBUG_PRINT_1("ERROR: IsWin32sSystemThunk --> UNKNOWN %u\r\n",
  853. wtcReturn);
  854. }
  855. return(wtcReturn);
  856. }
  857. #endif // WIN32S
  858. #ifndef KERNEL
  859. void
  860. ProcessGetDRegsCmd(
  861. HPRCX hprc,
  862. HTHDX hthd,
  863. LPDBB lpdbb
  864. )
  865. {
  866. LPDWORD lpdw = (LPDWORD)LpDmMsg->rgb;
  867. CONTEXT cxt;
  868. int rs = 0;
  869. DEBUG_PRINT( "ProcessGetDRegsCmd :\n");
  870. #ifdef WIN32S
  871. // Can't yet get thread context within a non-exception event.
  872. if (hthd == 0 || ! fCanGetThreadContext) {
  873. DEBUG_PRINT("\r\nProcessGetDRegsCmd\r\n");
  874. // DebugBreak();
  875. #else
  876. if (hthd == 0) {
  877. #endif
  878. rs = 0;
  879. } else {
  880. cxt.ContextFlags = CONTEXT_DEBUG_REGISTERS;
  881. if (!GetThreadContext(hthd->rwHand, &cxt)) {
  882. LpDmMsg->xosdRet = xosdUnknown;
  883. rs = 0;
  884. } else {
  885. lpdw[0] = hthd->context.Dr0;
  886. lpdw[1] = hthd->context.Dr1;
  887. lpdw[2] = hthd->context.Dr2;
  888. lpdw[3] = hthd->context.Dr3;
  889. lpdw[4] = hthd->context.Dr6;
  890. lpdw[5] = hthd->context.Dr7;
  891. LpDmMsg->xosdRet = xosdNone;
  892. rs = sizeof(CONTEXT);
  893. }
  894. }
  895. Reply( rs, LpDmMsg, lpdbb->hpid );
  896. return;
  897. } /* ProcessGetDRegsCmd() */
  898. void
  899. ProcessSetDRegsCmd(
  900. HPRCX hprc,
  901. HTHDX hthd,
  902. LPDBB lpdbb
  903. )
  904. {
  905. LPDWORD lpdw = (LPDWORD)(lpdbb->rgbVar);
  906. XOSD_ xosd = xosdNone;
  907. Unreferenced(hprc);
  908. DPRINT(5, ("ProcessSetDRegsCmd : "));
  909. hthd->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
  910. hthd->context.Dr0 = lpdw[0];
  911. hthd->context.Dr1 = lpdw[1];
  912. hthd->context.Dr2 = lpdw[2];
  913. hthd->context.Dr3 = lpdw[3];
  914. hthd->context.Dr6 = lpdw[4];
  915. hthd->context.Dr7 = lpdw[5];
  916. if (hthd->fWowEvent) {
  917. WOWSetThreadContext(hthd, &hthd->context);
  918. } else {
  919. SetThreadContext(hthd->rwHand, &hthd->context);
  920. }
  921. Reply(0, &xosd, lpdbb->hpid);
  922. return;
  923. } /* ProcessSetDRegsCmd() */
  924. VOID
  925. MakeThreadSuspendItselfHelper(
  926. HTHDX hthd,
  927. FARPROC lpSuspendThread
  928. )
  929. {
  930. HANDLE h;
  931. DWORD dw;
  932. //
  933. // set up the args to SuspendThread
  934. //
  935. hthd->context.Esp -= 4;
  936. h = GetCurrentThread();
  937. WriteProcessMemory(hthd->hprc->rwHand,
  938. (PVOID)hthd->context.Esp,
  939. &h,
  940. sizeof(h),
  941. &dw);
  942. hthd->context.Esp -= 4;
  943. WriteProcessMemory(hthd->hprc->rwHand,
  944. (PVOID)hthd->context.Esp,
  945. &(PC(hthd)),
  946. sizeof(DWORD),
  947. &dw);
  948. PC(hthd) = (DWORD)lpSuspendThread;
  949. hthd->fContextDirty = TRUE;
  950. }
  951. #endif // !KERNEL
  952. BOOL
  953. ProcessFrameStackWalkNextCmd(HPRCX hprc,
  954. HTHDX hthd,
  955. PCONTEXT context,
  956. LPVOID pctxPtrs)
  957. {
  958. return FALSE;
  959. }
  960. XOSD disasm ( LPSDI lpsdi, void*Memory, int Size );
  961. BOOL ParseAddr ( char*, ADDR* );
  962. BOOL ParseNumber( char*, DWORD*, int );
  963. typedef struct _BTNODE {
  964. char *Name;
  965. BOOL IsCall;
  966. BOOL TargetAvail;
  967. } BTNODE;
  968. BTNODE BranchTable[] = {
  969. { "call" , TRUE , TRUE },
  970. { "ja" , FALSE , TRUE },
  971. { "jae" , FALSE , TRUE },
  972. { "jb" , FALSE , TRUE },
  973. { "jbe" , FALSE , TRUE },
  974. { "jcxz" , FALSE , TRUE },
  975. { "je" , FALSE , TRUE },
  976. { "jecxz" , FALSE , TRUE },
  977. { "jg" , FALSE , TRUE },
  978. { "jge" , FALSE , TRUE },
  979. { "jl" , FALSE , TRUE },
  980. { "jle" , FALSE , TRUE },
  981. { "jmp" , FALSE , TRUE },
  982. { "jne" , FALSE , TRUE },
  983. { "jno" , FALSE , TRUE },
  984. { "jnp" , FALSE , TRUE },
  985. { "jns" , FALSE , TRUE },
  986. { "jo" , FALSE , TRUE },
  987. { "jp" , FALSE , TRUE },
  988. { "js" , FALSE , TRUE },
  989. { "loop" , FALSE , FALSE },
  990. { "loope" , FALSE , FALSE },
  991. { "loopne" , FALSE , FALSE },
  992. { "loopnz" , FALSE , FALSE },
  993. { "loopz" , FALSE , FALSE },
  994. { "ret" , FALSE , FALSE },
  995. { "retf" , FALSE , FALSE },
  996. { "retn" , FALSE , FALSE },
  997. { NULL , FALSE , FALSE }
  998. };
  999. DWORD
  1000. BranchUnassemble(
  1001. void *Memory,
  1002. ADDR *Addr,
  1003. BOOL *IsBranch,
  1004. BOOL *TargetKnown,
  1005. BOOL *IsCall,
  1006. BOOL *IsTable,
  1007. ADDR *Target
  1008. )
  1009. {
  1010. XOSD xosd;
  1011. SDI Sdi;
  1012. DWORD Consumed = 0;
  1013. DWORD i;
  1014. int s;
  1015. char *p;
  1016. ADDR Trgt;
  1017. AddrInit( &Trgt, 0, 0, 0, TRUE, TRUE, FALSE, FALSE );
  1018. *IsBranch = FALSE;
  1019. *IsTable = FALSE;
  1020. Sdi.dop = dopOpcode| dopOperands | dopEA;
  1021. Sdi.addr = *Addr;
  1022. xosd = disasm( &Sdi, Memory, 16 );
  1023. if ( xosd == xosdNone ) {
  1024. *IsTable = Sdi.fJumpTable;
  1025. for ( i=0; BranchTable[i].Name != NULL; i++ ) {
  1026. s = strcmp( Sdi.lpch, BranchTable[i].Name );
  1027. if ( s == 0 ) {
  1028. *IsBranch = TRUE;
  1029. *IsCall = BranchTable[i].IsCall;
  1030. if (*IsTable) {
  1031. *Target = Sdi.addrEA0;
  1032. //
  1033. // We might know the target, but for this
  1034. // purpose, we don't want to deal with it.
  1035. //
  1036. *TargetKnown = FALSE;
  1037. }
  1038. else if (BranchTable[i].TargetAvail &&
  1039. (p = Sdi.lpch) &&
  1040. *(p += (strlen(p)+1)) ) {
  1041. Trgt = *Addr;
  1042. if ( ParseAddr( p, &Trgt ) ) {
  1043. *TargetKnown = TRUE;
  1044. } else {
  1045. AddrInit( &Trgt, 0, 0, 0, TRUE, TRUE, FALSE, FALSE );
  1046. *TargetKnown = FALSE;
  1047. }
  1048. *Target = Trgt;
  1049. }
  1050. else {
  1051. *Target = Trgt;
  1052. *TargetKnown = FALSE;
  1053. }
  1054. break;
  1055. } else if ( s < 0 ) {
  1056. break;
  1057. }
  1058. }
  1059. Consumed = GetAddrOff( Sdi.addr ) - GetAddrOff(*Addr);
  1060. }
  1061. return Consumed;
  1062. }
  1063. BOOL
  1064. ParseAddr (
  1065. char *szAddr,
  1066. ADDR *Addr
  1067. )
  1068. {
  1069. char *p;
  1070. BOOL fParsed;
  1071. SEGMENT Segment;
  1072. UOFF16 Off16;
  1073. UOFF32 Off32;
  1074. DWORD Dword;
  1075. assert( szAddr );
  1076. assert( Addr );
  1077. fParsed = FALSE;
  1078. p = strchr( szAddr, ':' );
  1079. if ( p ) {
  1080. *p = '\0';
  1081. p++;
  1082. if ( ParseNumber( szAddr, &Dword, 16 ) ) {
  1083. Segment = (SEGMENT)Dword;
  1084. if ( ParseNumber( p, &Dword, 16 ) ) {
  1085. Off16 = (UOFF16)Dword;
  1086. fParsed = TRUE;
  1087. GetAddrSeg(*Addr) = Segment;
  1088. GetAddrOff(*Addr) = Off16;
  1089. }
  1090. }
  1091. } else {
  1092. if ( ParseNumber( szAddr, &Dword, 16 ) ) {
  1093. Off32 = (UOFF32)Dword;
  1094. fParsed = TRUE;
  1095. GetAddrOff(*Addr) = Off32;
  1096. }
  1097. }
  1098. return fParsed;
  1099. }
  1100. BOOL
  1101. ParseNumber (
  1102. char *szNumber,
  1103. DWORD *Number,
  1104. int Radix
  1105. )
  1106. {
  1107. BOOL fParsed = FALSE;
  1108. char *p = szNumber;
  1109. char *q;
  1110. assert( szNumber );
  1111. assert( Number );
  1112. if ( strlen(p) > 2 &&
  1113. p[0]=='0' &&
  1114. (p[1]=='x' || p[1]=='X') ) {
  1115. p+=2;
  1116. assert( Radix == 16 );
  1117. }
  1118. q = p;
  1119. while ( *q && isxdigit(*q) ) {
  1120. q++;
  1121. }
  1122. if ( !*q ) {
  1123. *Number = strtoul( p, NULL, Radix );
  1124. fParsed = TRUE;
  1125. }
  1126. return fParsed;
  1127. }
  1128. BOOL
  1129. SetupDebugRegister(
  1130. HTHDX hthd,
  1131. int Register,
  1132. int DataSize,
  1133. DWORD DataAddr,
  1134. DWORD BpType
  1135. )
  1136. {
  1137. DWORD Len;
  1138. DWORD rwMask;
  1139. #ifdef KERNEL
  1140. KSPECIAL_REGISTERS ksr;
  1141. PDWORD Dr0 = &ksr.KernelDr0;
  1142. PDWORD Dr1 = &ksr.KernelDr1;
  1143. PDWORD Dr2 = &ksr.KernelDr2;
  1144. PDWORD Dr3 = &ksr.KernelDr3;
  1145. PDR7 Dr7 = (PDR7)&(ksr.KernelDr7);
  1146. #else
  1147. CONTEXT Context;
  1148. PDWORD Dr0 = &Context.Dr0;
  1149. PDWORD Dr1 = &Context.Dr1;
  1150. PDWORD Dr2 = &Context.Dr2;
  1151. PDWORD Dr3 = &Context.Dr3;
  1152. PDR7 Dr7 = (PDR7)&(Context.Dr7);
  1153. #endif
  1154. #ifdef KERNEL
  1155. if (!GetExtendedContext(hthd, &ksr))
  1156. #else
  1157. Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
  1158. if (!GetThreadContext(hthd->rwHand, &Context))
  1159. #endif
  1160. {
  1161. return FALSE;
  1162. }
  1163. Len = LenMask[ DataSize ];
  1164. switch ( BpType ) {
  1165. case bptpDataR:
  1166. rwMask = RWE_READWRITE;
  1167. break;
  1168. case bptpDataW:
  1169. case bptpDataC:
  1170. rwMask = RWE_WRITE;
  1171. break;
  1172. case bptpDataExec:
  1173. rwMask = RWE_EXEC;
  1174. //
  1175. // length must be 0 for exec bp
  1176. //
  1177. Len = 0;
  1178. break;
  1179. default:
  1180. assert(!"Invalid BpType!!");
  1181. break;
  1182. }
  1183. switch( Register ) {
  1184. case 0:
  1185. *Dr0 = DataAddr;
  1186. Dr7->Len0 = Len;
  1187. Dr7->Rwe0 = rwMask;
  1188. Dr7->L0 = 0x01;
  1189. break;
  1190. case 1:
  1191. *Dr1 = DataAddr;
  1192. Dr7->Len1 = Len;
  1193. Dr7->Rwe1 = rwMask;
  1194. Dr7->L1 = 0x01;
  1195. break;
  1196. case 2:
  1197. *Dr2 = DataAddr;
  1198. Dr7->Len2 = Len;
  1199. Dr7->Rwe2 = rwMask;
  1200. Dr7->L2 = 0x01;
  1201. break;
  1202. case 3:
  1203. *Dr3 = DataAddr;
  1204. Dr7->Len3 = Len;
  1205. Dr7->Rwe3 = rwMask;
  1206. Dr7->L3 = 0x01;
  1207. break;
  1208. }
  1209. #ifdef KERNEL
  1210. ksr.KernelDr6 = 0;
  1211. return SetExtendedContext(hthd, &ksr);
  1212. #else
  1213. Context.Dr6 = 0;
  1214. return SetThreadContext(hthd->rwHand, &Context);
  1215. #endif
  1216. }
  1217. VOID
  1218. ClearDebugRegister(
  1219. HTHDX hthd,
  1220. int Register
  1221. )
  1222. {
  1223. #ifdef KERNEL
  1224. KSPECIAL_REGISTERS ksr;
  1225. PDWORD Dr0 = &ksr.KernelDr0;
  1226. PDWORD Dr1 = &ksr.KernelDr1;
  1227. PDWORD Dr2 = &ksr.KernelDr2;
  1228. PDWORD Dr3 = &ksr.KernelDr3;
  1229. PDR7 Dr7 = (PDR7)&(ksr.KernelDr7);
  1230. #else
  1231. CONTEXT Context;
  1232. PDWORD Dr0 = &Context.Dr0;
  1233. PDWORD Dr1 = &Context.Dr1;
  1234. PDWORD Dr2 = &Context.Dr2;
  1235. PDWORD Dr3 = &Context.Dr3;
  1236. PDR7 Dr7 = (PDR7)&(Context.Dr7);
  1237. #endif
  1238. #ifdef KERNEL
  1239. if (GetExtendedContext(hthd, &ksr))
  1240. #else
  1241. Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
  1242. if (GetThreadContext(hthd->rwHand, &Context))
  1243. #endif
  1244. {
  1245. switch( Register ) {
  1246. case 0:
  1247. *Dr0 = 0;
  1248. Dr7->Len0 = 0;
  1249. Dr7->Rwe0 = 0;
  1250. Dr7->L0 = 0;
  1251. break;
  1252. case 1:
  1253. *Dr1 = 0;
  1254. Dr7->Len1 = 0;
  1255. Dr7->Rwe1 = 0;
  1256. Dr7->L1 = 0;
  1257. break;
  1258. case 2:
  1259. *Dr2 = 0;
  1260. Dr7->Len2 = 0;
  1261. Dr7->Rwe2 = 0;
  1262. Dr7->L2 = 0;
  1263. break;
  1264. case 3:
  1265. *Dr3 = 0;
  1266. Dr7->Len3 = 0;
  1267. Dr7->Rwe3 = 0;
  1268. Dr7->L3 = 0;
  1269. break;
  1270. }
  1271. #ifdef KERNEL
  1272. ksr.KernelDr6 = 0;
  1273. SetExtendedContext(hthd, &ksr);
  1274. #else
  1275. Context.Dr6 = 0;
  1276. SetThreadContext( hthd->rwHand, &Context );
  1277. #endif
  1278. }
  1279. }
  1280. BOOL
  1281. DecodeSingleStepEvent(
  1282. HTHDX hthd,
  1283. DEBUG_EVENT *de,
  1284. PDWORD eventCode,
  1285. PDWORD subClass
  1286. )
  1287. /*++
  1288. Routine Description:
  1289. Arguments:
  1290. hthd - Supplies thread that has a single step exception pending
  1291. de - Supplies the DEBUG_EVENT structure for the exception
  1292. eventCode - Returns the remapped debug event id
  1293. subClass - Returns the remapped subClass id
  1294. Return Value:
  1295. TRUE if event was a real single step or was successfully mapped
  1296. to a breakpoint. FALSE if a register breakpoint occurred which was
  1297. not expected.
  1298. --*/
  1299. {
  1300. DWORD dr6;
  1301. PBREAKPOINT bp;
  1302. #ifdef KERNEL
  1303. KSPECIAL_REGISTERS ksr;
  1304. GetExtendedContext( hthd, &ksr);
  1305. dr6 = ksr.KernelDr6;
  1306. #else
  1307. CONTEXT Context;
  1308. Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
  1309. DbgGetThreadContext( hthd, &Context);
  1310. dr6 = Context.Dr6;
  1311. #endif
  1312. //
  1313. // if it was a single step, look no further:
  1314. //
  1315. if ((dr6 & 0x4000) != 0) {
  1316. return TRUE;
  1317. }
  1318. //
  1319. // Search for a matching walk...
  1320. //
  1321. bp = GetWalkBPFromBits(hthd, (dr6 & 0xf));
  1322. if (bp) {
  1323. de->dwDebugEventCode = *eventCode = BREAKPOINT_DEBUG_EVENT;
  1324. de->u.Exception.ExceptionRecord.ExceptionCode = *subClass = (DWORD)bp;
  1325. return TRUE;
  1326. } else {
  1327. return FALSE;
  1328. }
  1329. }