Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

679 lines
16 KiB

  1. /*++
  2. * Main module of DBG DLL.
  3. *
  4. * Copyright (c) 1997, Microsoft Corporation
  5. *
  6. * This code runs in the debuggee's process.
  7. *
  8. --*/
  9. #include <precomp.h>
  10. #pragma hdrstop
  11. BOOL InVdmDebugger = FALSE;
  12. BOOL bWantsNtsdPrompt = FALSE;
  13. ULONG ulTHHOOK = 0L; // Address registered from 16-bit world
  14. LPVOID lpRemoteAddress = NULL; // Address registered from WOW32
  15. DWORD lpRemoteBlock = 0; // Address registered from WOW32
  16. BOOL f386;
  17. DWORD VdmDbgEFLAGS;
  18. WORD DbgWowhExeHead = 0;
  19. WORD DbgWowhGlobalHeap = 0;
  20. PDWORD lpVdmState = NULL;
  21. PBYTE lpNtCpuInfo = NULL;
  22. UCHAR DbgTimerMode = VDMTI_TIMER_TICK;
  23. BOOL DbgTimerInitialized = FALSE;
  24. VOID VdmDbgAttach(VOID);
  25. BOOLEAN
  26. DbgDllInitialize(
  27. IN PVOID DllHandle,
  28. IN ULONG Reason,
  29. IN PCONTEXT Context OPTIONAL
  30. )
  31. /*
  32. * DBGDllInitialize - DBG Initialiazation routine.
  33. *
  34. */
  35. {
  36. HANDLE MyDebugPort;
  37. DWORD st;
  38. BOOL fAlreadyDebugged;
  39. UNREFERENCED_PARAMETER(Context);
  40. switch ( Reason ) {
  41. case DLL_PROCESS_ATTACH:
  42. #ifdef i386
  43. // X86 Only, get pointer to Register Context Block
  44. px86 = getIntelRegistersPointer();
  45. #endif
  46. st = NtQueryInformationProcess(
  47. NtCurrentProcess(),
  48. ProcessDebugPort,
  49. (PVOID)&MyDebugPort,
  50. sizeof(MyDebugPort),
  51. NULL );
  52. if ( NT_SUCCESS(st) ) {
  53. fDebugged = (MyDebugPort != NULL);
  54. } else {
  55. fDebugged = FALSE;
  56. }
  57. if (fDebugged) {
  58. DbgAttach();
  59. }
  60. break;
  61. case DLL_THREAD_ATTACH:
  62. //
  63. // See if the debugger is attaching. If it is, then turn on the
  64. // default of breaking into the debugger.
  65. //
  66. fAlreadyDebugged = fDebugged;
  67. st = NtQueryInformationProcess(
  68. NtCurrentProcess(),
  69. ProcessDebugPort,
  70. (PVOID)&MyDebugPort,
  71. sizeof(MyDebugPort),
  72. NULL );
  73. if ( NT_SUCCESS(st) ) {
  74. fDebugged = (MyDebugPort != NULL);
  75. } else {
  76. fDebugged = FALSE;
  77. }
  78. if (fDebugged && !fAlreadyDebugged) {
  79. DbgAttach();
  80. }
  81. break;
  82. case DLL_THREAD_DETACH:
  83. break;
  84. case DLL_PROCESS_DETACH:
  85. break;
  86. default:
  87. break;
  88. }
  89. return( TRUE );
  90. }
  91. void
  92. DbgAttach(
  93. void
  94. )
  95. /*
  96. * DbgAttach
  97. *
  98. * Called to initiate the communication with a debugger
  99. *
  100. */
  101. {
  102. //
  103. // Send DBG_ATTACH notification
  104. //
  105. DbgGetContext();
  106. SendVDMEvent(DBG_ATTACH);
  107. //
  108. // This call tells ntvdm to resync with us
  109. //
  110. VdmDbgAttach();
  111. }
  112. BOOL
  113. WINAPI
  114. xxxDbgInit(
  115. PVOID pState,
  116. ULONG InitialVdmDbgFlags,
  117. PVOID pCpuInfo
  118. )
  119. /*
  120. * DbgInit
  121. *
  122. * Called once ntvdm has completed it's initialization. Now it
  123. * is possible to compute for example the IntelMemoryBase.
  124. *
  125. */
  126. {
  127. VdmDbgTraceFlags = InitialVdmDbgFlags;
  128. lpVdmState = pState;
  129. IntelMemoryBase = (ULONG)VdmMapFlat(0, 0, VDM_V86);
  130. lpNtCpuInfo = pCpuInfo;
  131. //
  132. // turn on default debugging bits in ntvdmstate
  133. //
  134. *lpVdmState |= VDM_BREAK_DEBUGGER;
  135. #if DBG
  136. *lpVdmState |= VDM_TRACE_HISTORY;
  137. #endif
  138. if (fDebugged) {
  139. DbgGetContext();
  140. SendVDMEvent(DBG_INIT);
  141. }
  142. return TRUE;
  143. }
  144. BOOL
  145. WINAPI
  146. xxxDbgIsDebuggee(
  147. void
  148. )
  149. /*
  150. * DbgIsDebuggee
  151. *
  152. * Determines if we are being debugged
  153. *
  154. * Entry: void
  155. *
  156. * Exit: BOOL bRet - TRUE we are being debugged
  157. *
  158. */
  159. {
  160. return fDebugged;
  161. }
  162. BOOL
  163. SendVDMEvent(
  164. WORD wEventType
  165. )
  166. /* SendVDMEvent
  167. *
  168. * Sends a VDM event notification to the debugger
  169. *
  170. * Entry:
  171. *
  172. * Exit: BOOL bRet
  173. * Returns TRUE if exception was handled, FALSE otherwise
  174. *
  175. */
  176. {
  177. BOOL fResult;
  178. EventParams[0] = MAKELONG( wEventType, EventFlags );
  179. EventParams[3] = (DWORD)&viInfo;
  180. InVdmDebugger = TRUE;
  181. do {
  182. bWantsNtsdPrompt = FALSE;
  183. // Slimyness to determine whether the exception was handled or not.
  184. try {
  185. RaiseException( STATUS_VDM_EVENT,
  186. 0,
  187. 4,
  188. EventParams );
  189. fResult = TRUE;
  190. } except(EXCEPTION_EXECUTE_HANDLER) {
  191. fResult = FALSE;
  192. }
  193. //
  194. // bWantsNtsdPrompt may be changed by vdmexts
  195. //
  196. if (bWantsNtsdPrompt) {
  197. DbgBreakPoint();
  198. }
  199. } while (bWantsNtsdPrompt);
  200. InVdmDebugger = FALSE;
  201. FlushVdmBreakPoints();
  202. return( fResult );
  203. }
  204. VOID
  205. DbgGetContext(
  206. VOID
  207. )
  208. /* DbgGetContext() - Get the VDM's current context
  209. *
  210. * Most of the routines that send VDMEvents need to have a context record
  211. * associated with them. This routine is a quick way to get most of the
  212. * general registers. Redundant work is being done because AX for example
  213. * is often on the stack and as such must really be pulled from the frame.
  214. * Hopefully this is OK because it is fast.
  215. */
  216. {
  217. //
  218. // Everything defaults to 0.
  219. //
  220. RtlFillMemory( &vcContext, sizeof(VDMCONTEXT), (UCHAR)0 );
  221. RtlFillMemory( &viInfo, sizeof(VDMINTERNALINFO), (UCHAR)0 );
  222. //
  223. // Fill in the internal info structure
  224. //
  225. viInfo.dwLdtBase = (DWORD)ExpLdt;
  226. viInfo.dwIntelBase = IntelMemoryBase;
  227. viInfo.wKernelSeg = HIWORD(ulTHHOOK);
  228. viInfo.dwOffsetTHHOOK = (DWORD)(LOWORD(ulTHHOOK));
  229. viInfo.vdmContext = &vcContext;
  230. viInfo.lpRemoteAddress = lpRemoteAddress;
  231. viInfo.lpRemoteBlock = lpRemoteBlock;
  232. viInfo.f386 = f386;
  233. viInfo.lpNtvdmState = lpVdmState;
  234. viInfo.lpVdmDbgFlags = &VdmDbgTraceFlags;
  235. viInfo.lpNtCpuInfo = lpNtCpuInfo;
  236. viInfo.lpVdmBreakPoints= &VdmBreakPoints;
  237. //
  238. // Fill in the context structure
  239. //
  240. vcContext.SegEs = (ULONG)getES();
  241. vcContext.SegDs = (ULONG)getDS();
  242. vcContext.SegCs = (ULONG)getCS();
  243. vcContext.SegSs = (ULONG)getSS();
  244. vcContext.SegFs = (ULONG)getFS();
  245. vcContext.SegGs = (ULONG)getGS();
  246. vcContext.EFlags = getEFLAGS();
  247. VdmDbgEFLAGS = vcContext.EFlags; // save for vdmexts
  248. vcContext.Edi = getEDI();
  249. vcContext.Esi = getESI();
  250. vcContext.Ebx = getEBX();
  251. vcContext.Edx = getEDX();
  252. vcContext.Ecx = getECX();
  253. vcContext.Eax = getEAX();
  254. vcContext.Ebp = getEBP();
  255. vcContext.Eip = getEIP();
  256. vcContext.Esp = getESP();
  257. //
  258. // Put in special flags in event field
  259. //
  260. EventFlags = 0;
  261. if (!(getMSW() & MSW_PE) || (getEFLAGS() & V86FLAGS_V86)) {
  262. EventFlags |= VDMEVENT_V86; // emulator is in real or v86 mode
  263. } else {
  264. EventFlags |= VDMEVENT_PE;
  265. if ((getMSW() & MSW_PE) && !SEGMENT_IS_BIG(vcContext.SegCs)) {
  266. EventFlags |= VDMEVENT_PM16; // emulator is in real or v86 mode
  267. }
  268. }
  269. }
  270. void
  271. WINAPI
  272. xxxDbgDispatch()
  273. {
  274. UNALIGNED WORD *stack;
  275. WORD mode;
  276. WORD selector;
  277. WORD segment;
  278. WORD new_selector;
  279. BOOL fBPRelease;
  280. BOOL fData;
  281. LPSTR lpModuleName;
  282. LPSTR lpPathName;
  283. UCHAR fPE;
  284. PFFRAME16 pFFrame;
  285. PTFRAME16 pTFrame;
  286. PNDFRAME16 pNDFrame;
  287. PSTFRAME16 pSTFrame;
  288. WORD wFrame;
  289. fPE = ISPESET;
  290. stack = (UNALIGNED WORD *)Sim32GetVDMPointer(
  291. ((ULONG)getSS() << 16) + (ULONG)getSP(),
  292. MAX_DBG_FRAME, fPE );
  293. mode = *stack++;
  294. //
  295. // If there is no debugger, then only handle DBG_WOWINIT
  296. //
  297. if (!fDebugged && (mode != DBG_WOWINIT)) {
  298. return;
  299. }
  300. switch( mode ) {
  301. case DBG_SEGLOAD:
  302. selector = *stack++;
  303. segment = *stack++;
  304. lpModuleName = (LPSTR)Sim32GetVDMPointer(
  305. (ULONG)*stack + ((ULONG)(*(stack+1)) << 16),
  306. 0, fPE );
  307. stack += 2;
  308. lpPathName = (LPSTR)Sim32GetVDMPointer(
  309. (ULONG)*stack + ((ULONG)(*(stack+1)) << 16),
  310. 0, fPE );
  311. if ( lpPathName == NULL ) {
  312. lpPathName = "";
  313. }
  314. stack += 2;
  315. fData = (BOOL)(*stack++);
  316. SegmentLoad( lpModuleName, lpPathName, selector, segment, fData );
  317. break;
  318. case DBG_SEGMOVE:
  319. selector = *stack++;
  320. new_selector = *stack++;
  321. SegmentMove( selector, new_selector );
  322. break;
  323. case DBG_SEGFREE:
  324. fBPRelease = (BOOL)*stack++;
  325. selector = *stack++;
  326. SegmentFree( selector, fBPRelease );
  327. break;
  328. case DBG_MODFREE:
  329. lpModuleName = (LPSTR)Sim32GetVDMPointer(
  330. (ULONG)*stack + ((ULONG)(*(stack+1)) << 16),
  331. 0, fPE );
  332. stack += 2;
  333. lpPathName = (LPSTR)Sim32GetVDMPointer(
  334. (ULONG)*stack + ((ULONG)(*(stack+1)) << 16),
  335. 0, fPE );
  336. if ( lpPathName == NULL ) {
  337. lpPathName = "";
  338. }
  339. ModuleFree( lpModuleName, lpPathName );
  340. break;
  341. case DBG_GPFAULT2:
  342. wFrame = getBP() - (WORD)(FIELD_OFFSET(FFRAME16,wBP));
  343. pFFrame = (PFFRAME16)Sim32GetVDMPointer(
  344. ((ULONG)getSS() << 16) + (ULONG)wFrame,
  345. MAX_DBG_FRAME, fPE );
  346. fData = DbgGPFault2( pFFrame );
  347. setAX((WORD)fData);
  348. break;
  349. case DBG_DIVOVERFLOW:
  350. pTFrame = (PTFRAME16)Sim32GetVDMPointer(
  351. (ULONG)((ULONG)getSS() << 16) + (ULONG)getSP(),
  352. MAX_DBG_FRAME, fPE );
  353. fData = DbgDivOverflow2( pTFrame );
  354. setAX((WORD)fData);
  355. break;
  356. case DBG_DLLSTART:
  357. pNDFrame = (PNDFRAME16)Sim32GetVDMPointer(
  358. (ULONG)((ULONG)getSS() << 16) + (ULONG)getSP(),
  359. MAX_DBG_FRAME, fPE );
  360. fData = DbgDllStart( pNDFrame );
  361. setAX((WORD)fData);
  362. break;
  363. case DBG_TASKSTOP:
  364. pSTFrame = (PSTFRAME16)Sim32GetVDMPointer(
  365. (ULONG)((ULONG)getSS() << 16) + (ULONG)getSP(),
  366. MAX_DBG_FRAME, fPE );
  367. fData = DbgTaskStop( pSTFrame );
  368. break;
  369. case DBG_ATTACH:
  370. break;
  371. case DBG_TOOLHELP:
  372. ulTHHOOK = (ULONG)*stack + ((ULONG)(*(stack+1)) << 16);
  373. stack += 2;
  374. f386 = (BOOL)*stack;
  375. break;
  376. case DBG_WOWINIT:
  377. //
  378. // Pass in some data from KRNL386 so that VDMEXTS can get a
  379. // hold of them.
  380. //
  381. DbgWowhExeHead = getDX();
  382. DbgWowhGlobalHeap = getCX();
  383. break;
  384. default:
  385. setAX(0); // Event not handled
  386. break;
  387. }
  388. }
  389. VOID
  390. xxxDbgNotifyRemoteThreadAddress(
  391. LPVOID lpAddress,
  392. DWORD lpBlock
  393. ) {
  394. lpRemoteAddress = lpAddress;
  395. lpRemoteBlock = lpBlock;
  396. }
  397. VOID
  398. xxxDbgNotifyDebugged(
  399. BOOL fNewDebugged
  400. ) {
  401. fDebugged = fNewDebugged;
  402. }
  403. VOID
  404. RestoreVDMContext(
  405. VDMCONTEXT *vcContext
  406. )
  407. {
  408. setEAX(vcContext->Eax);
  409. setEBX(vcContext->Ebx);
  410. setECX(vcContext->Ecx);
  411. setEDX(vcContext->Edx);
  412. setEIP(vcContext->Eip);
  413. setESP(vcContext->Esp);
  414. setEBP(vcContext->Ebp);
  415. setEFLAGS(vcContext->EFlags);
  416. }
  417. ULONG
  418. DbgEventTime(
  419. PVDM_TRACEINFO pVdmTraceInfo
  420. )
  421. {
  422. ULONG TickCount = 0;
  423. USHORT id;
  424. ULONG CurTick;
  425. LARGE_INTEGER CurTime;
  426. LARGE_INTEGER DiffTime;
  427. #ifdef _X86_
  428. ULONG CurHigh, CurLow;
  429. #endif
  430. if (!DbgTimerInitialized) {
  431. #ifdef _X86_
  432. ULONG CpuidHigh;
  433. _asm pushad
  434. _asm mov eax, 1
  435. _asm _emit 0fh
  436. _asm _emit 0a2h // CPUID
  437. _asm mov CpuidHigh, edx
  438. _asm popad
  439. if (CpuidHigh & 0x10) {
  440. // cpu has time stamp counter
  441. DbgTimerMode = VDMTI_TIMER_PENTIUM;
  442. }
  443. #endif
  444. switch(DbgTimerMode & VDMTI_TIMER_MODE) {
  445. case VDMTI_TIMER_TICK:
  446. pVdmTraceInfo->TimeStamp.LowPart = GetTickCount();
  447. DbgTimerInitialized = TRUE;
  448. break;
  449. #ifdef _X86_
  450. case VDMTI_TIMER_PENTIUM:
  451. _asm push eax
  452. _asm push edx
  453. _asm _emit 0fh
  454. _asm _emit 031h // RDTSC
  455. _asm mov CurLow, eax
  456. _asm mov CurHigh, edx
  457. _asm pop edx
  458. _asm pop eax
  459. pVdmTraceInfo->TimeStamp.LowPart = CurLow;
  460. pVdmTraceInfo->TimeStamp.HighPart = CurHigh;
  461. DbgTimerInitialized = TRUE;
  462. break;
  463. #endif
  464. }
  465. }
  466. if (DbgTimerInitialized) {
  467. pVdmTraceInfo->Flags = (pVdmTraceInfo->Flags & ~VDMTI_TIMER_MODE) +
  468. (DbgTimerMode & VDMTI_TIMER_MODE);
  469. switch(pVdmTraceInfo->Flags & VDMTI_TIMER_MODE) {
  470. case VDMTI_TIMER_TICK:
  471. CurTick = GetTickCount();
  472. if (CurTick > pVdmTraceInfo->TimeStamp.LowPart) {
  473. TickCount = CurTick - pVdmTraceInfo->TimeStamp.LowPart;
  474. pVdmTraceInfo->TimeStamp.LowPart = CurTick;
  475. } else {
  476. TickCount = 0;
  477. }
  478. break;
  479. #ifdef _X86_
  480. case VDMTI_TIMER_PENTIUM: {
  481. _asm push eax
  482. _asm push edx
  483. _asm _emit 0fh
  484. _asm _emit 031h // RDTSC
  485. _asm mov CurLow, eax
  486. _asm mov CurHigh, edx
  487. _asm pop edx
  488. _asm pop eax
  489. CurTime.LowPart = CurLow;
  490. CurTime.HighPart = CurHigh;
  491. DiffTime.QuadPart = CurTime.QuadPart - pVdmTraceInfo->TimeStamp.QuadPart;
  492. pVdmTraceInfo->TimeStamp.QuadPart = CurTime.QuadPart;
  493. TickCount = DiffTime.LowPart;
  494. //if (DiffTime.HighPart) {
  495. // TickCount = 0xffffffff;
  496. //}
  497. break;
  498. }
  499. #endif
  500. }
  501. }
  502. return (TickCount);
  503. }
  504. #define NUM_VDM_TRACE_PAGES 8
  505. VOID
  506. WINAPI
  507. xxxDbgTraceEvent(
  508. PVDM_TRACEINFO pVdmTraceInfo,
  509. USHORT Type,
  510. USHORT wData,
  511. ULONG lData
  512. )
  513. {
  514. PVDM_TRACEENTRY pEntry;
  515. if (!(*(ULONG *)(IntelMemoryBase+FIXED_NTVDMSTATE_LINEAR) & VDM_TRACE_HISTORY)) {
  516. return;
  517. }
  518. if (!pVdmTraceInfo->pTraceTable) {
  519. pVdmTraceInfo->pTraceTable = (PVDM_TRACEENTRY) VirtualAlloc(NULL,
  520. 4096*NUM_VDM_TRACE_PAGES,
  521. MEM_COMMIT,
  522. PAGE_READWRITE);
  523. if (!pVdmTraceInfo->pTraceTable) {
  524. // couldn't allocate memory
  525. return;
  526. }
  527. pVdmTraceInfo->CurrentEntry = 0;
  528. pVdmTraceInfo->NumPages = NUM_VDM_TRACE_PAGES;
  529. pVdmTraceInfo->Flags = 0;
  530. }
  531. pEntry = &pVdmTraceInfo->pTraceTable[pVdmTraceInfo->CurrentEntry];
  532. pEntry->Type = Type;
  533. pEntry->wData = wData;
  534. pEntry->lData = lData;
  535. pEntry->Time = DbgEventTime(pVdmTraceInfo);
  536. pEntry->eax = getEAX();
  537. pEntry->ebx = getEBX();
  538. pEntry->ecx = getECX();
  539. pEntry->edx = getEDX();
  540. pEntry->esi = getESI();
  541. pEntry->edi = getEDI();
  542. pEntry->ebp = getEBP();
  543. pEntry->esp = getESP();
  544. pEntry->eip = getEIP();
  545. pEntry->eflags = getEFLAGS();
  546. pEntry->cs = getCS();
  547. pEntry->ds = getDS();
  548. pEntry->es = getES();
  549. pEntry->fs = getFS();
  550. pEntry->gs = getGS();
  551. pEntry->ss = getSS();
  552. if (++pVdmTraceInfo->CurrentEntry >=
  553. (pVdmTraceInfo->NumPages*4096/sizeof(VDM_TRACEENTRY))) {
  554. pVdmTraceInfo->CurrentEntry = 0;
  555. }
  556. }