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.

589 lines
13 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. util.c
  5. Abstract:
  6. This module contains the debugging support needed to debug
  7. 16-bit VDM applications
  8. Author:
  9. Bob Day (bobday) 16-Sep-1992 Wrote it
  10. Revision History:
  11. Neil Sandlin (neilsa) 1-Mar-1997 Enhanced it
  12. --*/
  13. #include <precomp.h>
  14. #pragma hdrstop
  15. WORD wKernelSeg = 0;
  16. DWORD dwOffsetTHHOOK = 0L;
  17. LPVOID lpRemoteAddress = NULL;
  18. DWORD lpRemoteBlock = 0;
  19. BOOL fKernel386 = FALSE;
  20. DWORD dwLdtBase = 0;
  21. DWORD dwIntelBase = 0;
  22. LPVOID lpNtvdmState = NULL;
  23. LPVOID lpVdmDbgFlags = NULL;
  24. LPVOID lpVdmContext = NULL;
  25. LPVOID lpNtCpuInfo = NULL;
  26. LPVOID lpVdmBreakPoints = NULL;
  27. //----------------------------------------------------------------------------
  28. // InternalGetThreadSelectorEntry()
  29. //
  30. // Routine to return a LDT_ENTRY structure for the passed in selector number.
  31. // Its is assumed that we are talking about protect mode selectors.
  32. // For x86 systems, take the easy way and just call the system. For non-x86
  33. // systems, we get some information from softpc and index into them as the
  34. // LDT and GDT tables.
  35. //
  36. //----------------------------------------------------------------------------
  37. BOOL
  38. InternalGetThreadSelectorEntry(
  39. HANDLE hProcess,
  40. WORD wSelector,
  41. LPVDMLDT_ENTRY lpSelectorEntry
  42. )
  43. {
  44. BOOL bResult = FALSE;
  45. DWORD lpNumberOfBytesRead;
  46. // For non-intel systems, query the information from the LDT
  47. // that we have a pointer to from the VDMINTERNALINFO that we
  48. // got passed.
  49. if (!dwLdtBase) {
  50. RtlFillMemory( lpSelectorEntry, sizeof(VDMLDT_ENTRY), (UCHAR)0 );
  51. } else {
  52. bResult = ReadProcessMemory(
  53. hProcess,
  54. (LPVOID)(dwLdtBase+((wSelector&~7))),
  55. lpSelectorEntry,
  56. sizeof(VDMLDT_ENTRY),
  57. &lpNumberOfBytesRead
  58. );
  59. }
  60. return( bResult );
  61. }
  62. //----------------------------------------------------------------------------
  63. // InternalGetPointer()
  64. //
  65. // Routine to convert a 16-bit address into a 32-bit address. If fProtMode
  66. // is TRUE, then the selector table lookup is performed. Otherwise, simple
  67. // real mode address calculations are performed. On non-x86 systems, the
  68. // base of real memory is added into the
  69. //
  70. //----------------------------------------------------------------------------
  71. ULONG
  72. InternalGetPointer(
  73. HANDLE hProcess,
  74. WORD wSelector,
  75. DWORD dwOffset,
  76. BOOL fProtMode
  77. )
  78. {
  79. VDMLDT_ENTRY le;
  80. ULONG ulResult;
  81. ULONG base;
  82. ULONG limit;
  83. BOOL b;
  84. if ( fProtMode ) {
  85. b = InternalGetThreadSelectorEntry( hProcess,
  86. wSelector,
  87. &le );
  88. if ( !b ) {
  89. return( 0 );
  90. }
  91. base = ((ULONG)le.HighWord.Bytes.BaseHi << 24)
  92. + ((ULONG)le.HighWord.Bytes.BaseMid << 16)
  93. + ((ULONG)le.BaseLow);
  94. limit = (ULONG)le.LimitLow
  95. + ((ULONG)le.HighWord.Bits.LimitHi << 16);
  96. if ( le.HighWord.Bits.Granularity ) {
  97. limit <<= 12;
  98. limit += 0xFFF;
  99. }
  100. } else {
  101. base = wSelector << 4;
  102. limit = 0xFFFF;
  103. }
  104. if ( dwOffset > limit ) {
  105. ulResult = 0;
  106. } else {
  107. ulResult = base + dwOffset;
  108. #ifndef i386
  109. ulResult += dwIntelBase;
  110. #endif
  111. }
  112. return( ulResult );
  113. }
  114. //----------------------------------------------------------------------------
  115. // ReadItem
  116. //
  117. // Internal routine used to read items out of the debugee's address space.
  118. // The routine returns TRUE for failure. This allows easy failure testing.
  119. //
  120. //----------------------------------------------------------------------------
  121. BOOL
  122. ReadItem(
  123. HANDLE hProcess,
  124. WORD wSeg,
  125. DWORD dwOffset,
  126. LPVOID lpitem,
  127. UINT nSize
  128. )
  129. {
  130. LPVOID lp;
  131. BOOL b;
  132. DWORD dwBytes;
  133. if ( nSize == 0 ) {
  134. return( FALSE );
  135. }
  136. lp = (LPVOID)InternalGetPointer(
  137. hProcess,
  138. (WORD)(wSeg | 1),
  139. dwOffset,
  140. TRUE );
  141. if ( lp == NULL ) return( TRUE );
  142. b = ReadProcessMemory(
  143. hProcess,
  144. lp,
  145. lpitem,
  146. nSize,
  147. &dwBytes );
  148. if ( !b || dwBytes != nSize ) return( TRUE );
  149. return( FALSE );
  150. }
  151. //----------------------------------------------------------------------------
  152. // WriteItem
  153. //
  154. // Internal routine used to write items into the debugee's address space.
  155. // The routine returns TRUE for failure. This allows easy failure testing.
  156. //
  157. //----------------------------------------------------------------------------
  158. BOOL
  159. WriteItem(
  160. HANDLE hProcess,
  161. WORD wSeg,
  162. DWORD dwOffset,
  163. LPVOID lpitem,
  164. UINT nSize
  165. )
  166. {
  167. LPVOID lp;
  168. BOOL b;
  169. DWORD dwBytes;
  170. if ( nSize == 0 ) {
  171. return( FALSE );
  172. }
  173. lp = (LPVOID)InternalGetPointer(
  174. hProcess,
  175. (WORD)(wSeg | 1),
  176. dwOffset,
  177. TRUE );
  178. if ( lp == NULL ) return( TRUE );
  179. b = WriteProcessMemory(
  180. hProcess,
  181. lp,
  182. lpitem,
  183. nSize,
  184. &dwBytes );
  185. if ( !b || dwBytes != nSize ) return( TRUE );
  186. return( FALSE );
  187. }
  188. BOOL
  189. CallRemote16(
  190. HANDLE hProcess,
  191. LPSTR lpModuleName,
  192. LPSTR lpEntryName,
  193. LPBYTE lpArgs,
  194. WORD wArgsPassed,
  195. WORD wArgsSize,
  196. LPDWORD lpdwReturnValue,
  197. DEBUGEVENTPROC lpEventProc,
  198. LPVOID lpData
  199. )
  200. {
  201. HANDLE hRemoteThread;
  202. DWORD dwThreadId;
  203. DWORD dwContinueCode;
  204. DEBUG_EVENT de;
  205. BOOL b;
  206. BOOL fContinue;
  207. COM_HEADER comhead;
  208. WORD wRemoteSeg;
  209. WORD wRemoteOff;
  210. WORD wOff;
  211. UINT uModuleLength;
  212. UINT uEntryLength;
  213. if ( lpRemoteAddress == NULL || lpRemoteBlock == 0 ) {
  214. #ifdef DEBUG
  215. OutputDebugString("Remote address or remote block not initialized\n");
  216. #endif
  217. return( FALSE );
  218. }
  219. wRemoteSeg = HIWORD(lpRemoteBlock);
  220. wRemoteOff = LOWORD(lpRemoteBlock);
  221. wOff = wRemoteOff;
  222. // Fill in the communications buffer header
  223. READ_FIXED_ITEM( wRemoteSeg, wOff, comhead );
  224. comhead.wArgsPassed = wArgsPassed;
  225. comhead.wArgsSize = wArgsSize;
  226. uModuleLength = strlen(lpModuleName) + 1;
  227. uEntryLength = strlen(lpEntryName) + 1;
  228. //
  229. // If this call won't fit into the buffer, then fail.
  230. //
  231. if ( (UINT)comhead.wBlockLength < sizeof(comhead) + wArgsSize + uModuleLength + uEntryLength ) {
  232. #ifdef DEBUG
  233. OutputDebugString("Block won't fit\n");
  234. #endif
  235. return( FALSE );
  236. }
  237. WRITE_FIXED_ITEM( wRemoteSeg, wOff, comhead );
  238. wOff += sizeof(comhead);
  239. // Fill in the communications buffer arguments
  240. WRITE_SIZED_ITEM( wRemoteSeg, wOff, lpArgs, wArgsSize );
  241. wOff += wArgsSize;
  242. // Fill in the communications buffer module name and entry name
  243. WRITE_SIZED_ITEM( wRemoteSeg, wOff, lpModuleName, uModuleLength );
  244. wOff += (WORD) uModuleLength;
  245. WRITE_SIZED_ITEM( wRemoteSeg, wOff, lpEntryName, uEntryLength );
  246. wOff += (WORD) uEntryLength;
  247. hRemoteThread = CreateRemoteThread(
  248. hProcess,
  249. NULL,
  250. (DWORD)0,
  251. lpRemoteAddress,
  252. NULL,
  253. 0,
  254. &dwThreadId );
  255. if ( hRemoteThread == (HANDLE)0 ) { // Fail if we couldn't creaet thrd
  256. #ifdef DEBUG
  257. OutputDebugString("CreateRemoteThread failed\n");
  258. #endif
  259. return( FALSE );
  260. }
  261. //
  262. // Wait for the EXIT_THREAD_DEBUG_EVENT.
  263. //
  264. fContinue = TRUE;
  265. while ( fContinue ) {
  266. b = WaitForDebugEvent( &de, LONG_TIMEOUT );
  267. if (!b) {
  268. TerminateThread( hRemoteThread, 0 );
  269. CloseHandle( hRemoteThread );
  270. return( FALSE );
  271. }
  272. if ( de.dwThreadId == dwThreadId &&
  273. de.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT ) {
  274. fContinue = FALSE;
  275. }
  276. if ( lpEventProc ) {
  277. dwContinueCode = (* lpEventProc)( &de, lpData );
  278. } else {
  279. dwContinueCode = DBG_CONTINUE;
  280. }
  281. ContinueDebugEvent( de.dwProcessId, de.dwThreadId, dwContinueCode );
  282. }
  283. b = WaitForSingleObject( hRemoteThread, LONG_TIMEOUT );
  284. CloseHandle( hRemoteThread );
  285. if (b) {
  286. #ifdef DEBUG
  287. OutputDebugString("Wait for remote thread failed\n");
  288. #endif
  289. return( FALSE );
  290. }
  291. //
  292. // Get the return value and returned arguments
  293. //
  294. wOff = wRemoteOff;
  295. READ_FIXED_ITEM( wRemoteSeg, wOff, comhead );
  296. wOff += sizeof(comhead);
  297. *lpdwReturnValue = comhead.dwReturnValue;
  298. // Read back the communications buffer arguments
  299. READ_SIZED_ITEM( wRemoteSeg, wOff, lpArgs, wArgsSize );
  300. return( comhead.wSuccess );
  301. punt:
  302. return( FALSE );
  303. }
  304. DWORD
  305. GetRemoteBlock16(
  306. VOID
  307. )
  308. {
  309. if ( lpRemoteBlock == 0 ) {
  310. return( 0 );
  311. }
  312. return( ((DWORD)lpRemoteBlock) + sizeof(COM_HEADER) );
  313. }
  314. VOID
  315. ProcessInitNotification(
  316. LPDEBUG_EVENT lpDebugEvent
  317. )
  318. {
  319. VDMINTERNALINFO viInfo;
  320. DWORD lpNumberOfBytesRead;
  321. HANDLE hProcess;
  322. BOOL b;
  323. LPDWORD lpdw;
  324. lpdw = &(lpDebugEvent->u.Exception.ExceptionRecord.ExceptionInformation[0]);
  325. hProcess = OpenProcess( PROCESS_VM_READ, FALSE, lpDebugEvent->dwProcessId );
  326. if ( hProcess == HANDLE_NULL ) {
  327. return;
  328. }
  329. b = ReadProcessMemory(hProcess,
  330. (LPVOID)lpdw[3],
  331. &viInfo,
  332. sizeof(viInfo),
  333. &lpNumberOfBytesRead
  334. );
  335. if ( !b || lpNumberOfBytesRead != sizeof(viInfo) ) {
  336. return;
  337. }
  338. if ( wKernelSeg == 0 ) {
  339. wKernelSeg = viInfo.wKernelSeg;
  340. dwOffsetTHHOOK = viInfo.dwOffsetTHHOOK;
  341. }
  342. if ( lpRemoteAddress == NULL ) {
  343. lpRemoteAddress = viInfo.lpRemoteAddress;
  344. }
  345. if ( lpRemoteBlock == 0 ) {
  346. lpRemoteBlock = viInfo.lpRemoteBlock;
  347. }
  348. dwLdtBase = viInfo.dwLdtBase;
  349. dwIntelBase = viInfo.dwIntelBase;
  350. fKernel386 = viInfo.f386;
  351. lpNtvdmState = viInfo.lpNtvdmState;
  352. lpVdmDbgFlags = viInfo.lpVdmDbgFlags;
  353. lpVdmContext = viInfo.vdmContext;
  354. lpNtCpuInfo = viInfo.lpNtCpuInfo;
  355. lpVdmBreakPoints = viInfo.lpVdmBreakPoints;
  356. CloseHandle( hProcess );
  357. }
  358. VOID
  359. ParseModuleName(
  360. LPSTR szName,
  361. LPSTR szPath
  362. )
  363. /*++
  364. Routine Description:
  365. This routine strips off the 8 character file name from a path
  366. Arguments:
  367. szName - pointer to buffer of 8 characters (plus null)
  368. szPath - full path of file
  369. Return Value
  370. None.
  371. --*/
  372. {
  373. LPSTR lPtr = szPath;
  374. LPSTR lDest = szName;
  375. int BufferSize = 9;
  376. while(*lPtr) lPtr++; // scan to end
  377. while( ((DWORD)lPtr > (DWORD)szPath) &&
  378. ((*lPtr != '\\') && (*lPtr != '/'))) lPtr--;
  379. if (*lPtr) lPtr++;
  380. while((*lPtr) && (*lPtr!='.')) {
  381. if (!--BufferSize) break;
  382. *lDest++ = *lPtr++;
  383. }
  384. *lDest = 0;
  385. }
  386. #ifndef i386
  387. WORD
  388. ReadWord(
  389. HANDLE hProcess,
  390. PVOID lpAddress
  391. )
  392. {
  393. NTSTATUS bResult;
  394. WORD value;
  395. ULONG NumberOfBytesRead;
  396. bResult = ReadProcessMemory(
  397. hProcess,
  398. lpAddress,
  399. &value,
  400. sizeof(WORD),
  401. &NumberOfBytesRead
  402. );
  403. return value;
  404. }
  405. DWORD
  406. ReadDword(
  407. HANDLE hProcess,
  408. PVOID lpAddress
  409. )
  410. {
  411. NTSTATUS bResult;
  412. DWORD value;
  413. ULONG NumberOfBytesRead;
  414. bResult = ReadProcessMemory(
  415. hProcess,
  416. lpAddress,
  417. &value,
  418. sizeof(DWORD),
  419. &NumberOfBytesRead
  420. );
  421. return value;
  422. }
  423. //
  424. // The following two routines implement the very funky way that we
  425. // have to get register values on the 486 emulator.
  426. //
  427. ULONG
  428. GetRegValue(
  429. HANDLE hProcess,
  430. NT_CPU_REG reg,
  431. BOOL bInNano,
  432. ULONG UMask
  433. )
  434. {
  435. if (bInNano) {
  436. return(ReadDword(hProcess, reg.nano_reg));
  437. } else if (UMask & reg.universe_8bit_mask) {
  438. return (ReadDword(hProcess, reg.saved_reg) & 0xFFFFFF00 |
  439. ReadDword(hProcess, reg.reg) & 0xFF);
  440. } else if (UMask & reg.universe_16bit_mask) {
  441. return (ReadDword(hProcess, reg.saved_reg) & 0xFFFF0000 |
  442. ReadDword(hProcess, reg.reg) & 0xFFFF);
  443. } else {
  444. return (ReadDword(hProcess, reg.reg));
  445. }
  446. }
  447. ULONG
  448. GetEspValue(
  449. HANDLE hProcess,
  450. NT_CPU_INFO nt_cpu_info,
  451. BOOL bInNano
  452. )
  453. {
  454. if (bInNano) {
  455. return (ReadDword(hProcess, nt_cpu_info.nano_esp));
  456. } else {
  457. if (ReadDword(hProcess, nt_cpu_info.stack_is_big)) {
  458. return (ReadDword(hProcess, nt_cpu_info.host_sp) -
  459. ReadDword(hProcess, nt_cpu_info.ss_base));
  460. } else {
  461. return (ReadDword(hProcess, nt_cpu_info.esp_sanctuary) & 0xFFFF0000 |
  462. (ReadDword(hProcess, nt_cpu_info.host_sp) -
  463. ReadDword(hProcess, nt_cpu_info.ss_base) & 0xFFFF));
  464. }
  465. }
  466. }
  467. #endif