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.

834 lines
19 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. debug.cxx
  6. Abstract:
  7. Generic debug extensions.
  8. Author:
  9. Albert Ting (AlbertT) 19-Feb-1995
  10. Revision History:
  11. --*/
  12. #include "precomp.hxx"
  13. #pragma hdrstop
  14. HANDLE hCurrentProcess;
  15. WINDBG_EXTENSION_APIS ExtensionApis;
  16. PWINDBG_OUTPUT_ROUTINE Print;
  17. PWINDBG_GET_EXPRESSION EvalExpression;
  18. PWINDBG_GET_SYMBOL GetSymbolRtn;
  19. PWINDBG_CHECK_CONTROL_C CheckControlCRtn;
  20. USHORT SavedMajorVersion;
  21. USHORT SavedMinorVersion;
  22. BOOL bWindbg = FALSE;
  23. VOID
  24. WinDbgExtensionDllInit(
  25. PWINDBG_EXTENSION_APIS lpExtensionApis,
  26. USHORT MajorVersion,
  27. USHORT MinorVersion
  28. )
  29. {
  30. ::ExtensionApis = *lpExtensionApis;
  31. SavedMajorVersion = MajorVersion;
  32. SavedMinorVersion = MinorVersion;
  33. bWindbg = TRUE;
  34. return;
  35. }
  36. /*++
  37. Routine Name:
  38. ExtensionApiVersion
  39. Routine Description:
  40. Windbg calls this function to match between the
  41. version of windbg and the extension. If the versions
  42. doesn't match, windbg will not load the extension.
  43. Arguments:
  44. None.
  45. Return Value:
  46. None.
  47. --*/
  48. extern "C"
  49. LPEXT_API_VERSION
  50. ExtensionApiVersion(
  51. VOID
  52. )
  53. {
  54. static EXT_API_VERSION ApiVersion = { 3, 5, EXT_API_VERSION_NUMBER, 0 };
  55. return &ApiVersion;
  56. }
  57. /*++
  58. Routine Name:
  59. CheckVersion
  60. Routine Description:
  61. This function is called before every command. It gives
  62. the extension a chance to compare between the versions
  63. of the target and the extension.
  64. Arguments:
  65. None
  66. Return Value:
  67. None.
  68. --*/
  69. extern "C"
  70. VOID
  71. CheckVersion(
  72. VOID
  73. )
  74. {
  75. }
  76. VOID
  77. TDebugExt::
  78. vDumpPDL(
  79. PDLINK pDLink
  80. )
  81. {
  82. Print( "%x %x", pDLink->FLink, pDLink->BLink );
  83. if( pDLink->FLink == pDLink->BLink ){
  84. Print( " <empty>\n" );
  85. } else {
  86. Print( "\n" );
  87. }
  88. }
  89. VOID
  90. TDebugExt::
  91. vDumpStr(
  92. LPCWSTR pszString
  93. )
  94. {
  95. WCHAR szString[MAX_PATH];
  96. if( (LPCWSTR)pszString == NULL ){
  97. Print( "(NULL)\n" );
  98. return;
  99. }
  100. szString[0] = 0;
  101. //
  102. // First try reading to the end of 1k (pages are 4k on x86, but
  103. // most strings are < 1k ).
  104. //
  105. UINT cbShort = (UINT)(0x400 - ( (ULONG_PTR)pszString & 0x3ff ));
  106. BOOL bFound = FALSE;
  107. if( cbShort < sizeof( szString )){
  108. UINT i;
  109. move2( szString, pszString, cbShort );
  110. //
  111. // Look for a NULL.
  112. //
  113. for( i=0; i< cbShort/sizeof( pszString[0] ); ++i )
  114. {
  115. if( !szString[i] ){
  116. bFound = TRUE;
  117. }
  118. }
  119. }
  120. if( !bFound ){
  121. move( szString, pszString );
  122. }
  123. if( szString[0] == 0 ){
  124. Print( "\"\"\n" );
  125. } else {
  126. Print( "%ws\n", szString );
  127. }
  128. }
  129. VOID
  130. TDebugExt::
  131. vDumpStrA(
  132. LPCSTR pszString
  133. )
  134. {
  135. CHAR szString[MAX_PATH];
  136. if( (LPCSTR)pszString == NULL ){
  137. Print( "(NULL)\n" );
  138. return;
  139. }
  140. szString[0] = 0;
  141. //
  142. // First try reading to the end of 1k (pages are 4k on x86, but
  143. // most strings are < 1k ).
  144. //
  145. UINT cbShort = 0x400 - (UINT)( (ULONG_PTR)pszString & 0x3ff );
  146. BOOL bFound = FALSE;
  147. if( cbShort < sizeof( szString )){
  148. UINT i;
  149. move2( szString, pszString, cbShort );
  150. //
  151. // Look for a NULL.
  152. //
  153. for( i=0; i< cbShort/sizeof( pszString[0] ); ++i )
  154. {
  155. if( !szString[i] ){
  156. bFound = TRUE;
  157. }
  158. }
  159. }
  160. if( !bFound ){
  161. move( szString, pszString );
  162. }
  163. if( szString[0] == 0 ){
  164. Print( "\"\"\n" );
  165. } else {
  166. Print( "%hs\n", szString );
  167. }
  168. }
  169. VOID
  170. TDebugExt::
  171. vDumpTime(
  172. const SYSTEMTIME& st
  173. )
  174. {
  175. Print( "%d/%d/%d %d %d:%d:%d.%d\n",
  176. st.wMonth,
  177. st.wDay,
  178. st.wYear,
  179. st.wDayOfWeek,
  180. st.wHour,
  181. st.wMinute,
  182. st.wSecond,
  183. st.wMilliseconds );
  184. }
  185. VOID
  186. TDebugExt::
  187. vDumpFlags(
  188. ULONG_PTR dwFlags,
  189. PDEBUG_FLAGS pDebugFlags
  190. )
  191. {
  192. ULONG_PTR dwFound = 0;
  193. Print( "%x [ ", dwFlags );
  194. for( ; pDebugFlags->dwFlag; ++pDebugFlags ){
  195. if( dwFlags & pDebugFlags->dwFlag ){
  196. Print( "%s ", pDebugFlags->pszFlag );
  197. dwFound |= pDebugFlags->dwFlag;
  198. }
  199. }
  200. Print( "]" );
  201. //
  202. // Check if there are extra bits set that we don't understand.
  203. //
  204. if( dwFound != dwFlags ){
  205. Print( "<ExtraBits: %x>", dwFlags & ~dwFound );
  206. }
  207. Print( "\n" );
  208. }
  209. VOID
  210. TDebugExt::
  211. vDumpValue(
  212. ULONG_PTR dwValue,
  213. PDEBUG_VALUES pDebugValues
  214. )
  215. {
  216. Print( "%x ", dwValue );
  217. for( ; pDebugValues->dwValue; ++pDebugValues ){
  218. if( dwValue == pDebugValues->dwValue ){
  219. Print( "%s ", pDebugValues->pszValue );
  220. }
  221. }
  222. Print( "\n" );
  223. }
  224. VOID
  225. TDebugExt::
  226. vDumpTrace(
  227. ULONG_PTR dwAddress
  228. )
  229. {
  230. #ifdef TRACE_ENABLED
  231. INT i;
  232. CHAR szSymbol[64];
  233. ULONG_PTR dwDisplacement;
  234. ULONG_PTR adwTrace[ ( OFFSETOF( TBackTraceDB::TTrace, apvBackTrace ) +
  235. sizeof( PVOID ) * VBackTrace::kMaxDepth )
  236. / sizeof( ULONG_PTR )];
  237. if( !dwAddress ){
  238. return;
  239. }
  240. move( adwTrace, dwAddress );
  241. TBackTraceDB::TTrace *pTrace = (TBackTraceDB::TTrace*)adwTrace;
  242. printf( "Trace %x Hash = %x Count = %x\n",
  243. dwAddress,
  244. pTrace->_ulHash,
  245. pTrace->_lCount );
  246. for( i=0; i < VBackTrace::kMaxDepth; i++ ){
  247. if( !pTrace->apvBackTrace[i] ){
  248. break;
  249. }
  250. GetSymbolRtn( (PVOID)pTrace->apvBackTrace[i],
  251. szSymbol,
  252. &dwDisplacement );
  253. Print( "%08x %s+%x\n",
  254. pTrace->apvBackTrace[i], szSymbol,
  255. dwDisplacement );
  256. }
  257. if( i > 0 ){
  258. Print( "\n" );
  259. }
  260. #endif
  261. }
  262. ULONG_PTR
  263. TDebugExt::
  264. dwEval(
  265. LPSTR& lpArgumentString,
  266. BOOL bParam
  267. )
  268. {
  269. ULONG_PTR dwReturn;
  270. LPSTR pSpace = NULL;
  271. while( *lpArgumentString == ' ' ){
  272. lpArgumentString++;
  273. }
  274. //
  275. // If it's a parameter, scan to next space and delimit.
  276. //
  277. if( bParam ){
  278. for( pSpace = lpArgumentString; *pSpace && *pSpace != ' '; ++pSpace )
  279. ;
  280. if( *pSpace == ' ' ){
  281. *pSpace = 0;
  282. } else {
  283. pSpace = NULL;
  284. }
  285. }
  286. dwReturn = (ULONG_PTR)EvalExpression( lpArgumentString );
  287. while( *lpArgumentString != ' ' && *lpArgumentString ){
  288. lpArgumentString++;
  289. }
  290. if( pSpace ){
  291. *pSpace = ' ';
  292. }
  293. return dwReturn;
  294. }
  295. /********************************************************************
  296. Generic extensions
  297. ********************************************************************/
  298. VOID
  299. TDebugExt::
  300. vLookCalls(
  301. HANDLE hProcess,
  302. HANDLE hThread,
  303. ULONG_PTR dwStartAddr,
  304. ULONG_PTR dwLength,
  305. ULONG_PTR dwFlags
  306. )
  307. {
  308. #if i386
  309. struct OPCODES {
  310. BYTE op;
  311. UINT uLen;
  312. };
  313. OPCODES Opcodes[] = {
  314. 0xe8, 5, // rel16
  315. 0xff, 6, // r/m16
  316. 0x0, 0
  317. };
  318. dwStartAddr = DWordAlign( dwStartAddr );
  319. dwLength = DWordAlign( dwLength );
  320. if( !dwStartAddr ){
  321. //
  322. // No address specified; use esp.
  323. //
  324. dwStartAddr = DWordAlign( (ULONG_PTR)EvalExpression( "ebp" ));
  325. }
  326. if( !dwLength ){
  327. DWORD Status;
  328. THREAD_BASIC_INFORMATION ThreadInformation;
  329. Status = NtQueryInformationThread( hThread,
  330. ThreadBasicInformation,
  331. &ThreadInformation,
  332. sizeof( ThreadInformation ),
  333. NULL
  334. );
  335. if( NT_SUCCESS( Status )){
  336. TEB Teb;
  337. ULONG_PTR dwBase;
  338. move( Teb, ThreadInformation.TebBaseAddress );
  339. dwBase = DWordAlign( (ULONG_PTR)Teb.NtTib.StackBase );
  340. if( dwBase > dwStartAddr ){
  341. dwLength = dwBase - dwStartAddr;
  342. }
  343. } else {
  344. Print( "Unable to get Teb %d\n", Status );
  345. return;
  346. }
  347. }
  348. Print( "Start %x End %x (Length %x)\n",
  349. dwStartAddr, dwStartAddr + dwLength, dwLength );
  350. if( !( dwFlags & (kLCFlagAll|kLCVerbose )))
  351. {
  352. Print( "FramePtr Arguments "
  353. "Next call (move one line up)\n" );
  354. }
  355. ULONG_PTR dwAddr;
  356. for( dwAddr = dwStartAddr;
  357. dwAddr < dwStartAddr + dwLength;
  358. ++dwAddr ){
  359. if( CheckControlCRtn()){
  360. Print( "Aborted.\n" );
  361. return;
  362. }
  363. //
  364. // Get a value on the stack and see if it looks like an ebp on
  365. // the stack. It should be close to the current address, but
  366. // be greater.
  367. //
  368. ULONG_PTR dwNextFrame = 0;
  369. move( dwNextFrame, dwAddr );
  370. BOOL bLooksLikeEbp = dwNextFrame > dwAddr &&
  371. dwNextFrame - dwAddr < kMaxCallFrame;
  372. //
  373. // If we are dumping all, or it looks like an ebp, dump it.
  374. //
  375. if(( dwFlags & kLCFlagAll ) || bLooksLikeEbp ){
  376. //
  377. // Check if next address looks like a valid call request.
  378. //
  379. ULONG_PTR dwRetAddr = 0;
  380. //
  381. // Get return address.
  382. //
  383. move( dwRetAddr, dwAddr + sizeof( DWORD ));
  384. //
  385. // Get 16 bytes before return address.
  386. //
  387. BYTE abyBuffer[16];
  388. ZeroMemory( abyBuffer, sizeof( abyBuffer ));
  389. move( abyBuffer, dwRetAddr - sizeof( abyBuffer ));
  390. //
  391. // Check if previous bytes look like a call instruction.
  392. //
  393. UINT i;
  394. for( i = 0; Opcodes[i].op; ++i ){
  395. if( abyBuffer[sizeof( abyBuffer )-Opcodes[i].uLen] ==
  396. Opcodes[i].op ){
  397. CHAR szSymbol[64];
  398. ULONG_PTR dwDisplacement;
  399. LPCSTR pszNull = "";
  400. LPCSTR pszStar = "*** ";
  401. LPCSTR pszPrefix = pszNull;
  402. if(( dwFlags & kLCFlagAll ) && bLooksLikeEbp ){
  403. pszPrefix = pszStar;
  404. }
  405. GetSymbolRtn( (PVOID)dwRetAddr,
  406. szSymbol,
  407. &dwDisplacement );
  408. //
  409. // Found what could be a match: dump it out.
  410. //
  411. DWORD dwArg[4];
  412. move( dwArg, dwAddr + 2*sizeof( DWORD ));
  413. if( dwFlags & kLCVerbose ){
  414. Print( "%s%x %s+0x%x\n",
  415. pszPrefix,
  416. dwRetAddr,
  417. szSymbol,
  418. dwDisplacement );
  419. Print( "%s%08x: %08x %08x %08x %08x %08x %08x\n",
  420. pszPrefix,
  421. dwAddr,
  422. dwNextFrame, dwRetAddr,
  423. dwArg[0], dwArg[1], dwArg[2], dwArg[3] );
  424. DWORD adwNextFrame[2];
  425. ZeroMemory( adwNextFrame, sizeof( adwNextFrame ));
  426. move( adwNextFrame, dwNextFrame );
  427. Print( "%s%08x: %08x %08x\n\n",
  428. pszPrefix,
  429. dwNextFrame, adwNextFrame[0], adwNextFrame[1] );
  430. } else {
  431. Print( "%08x %08x %08x %08x %08x-%s+0x%x\n",
  432. dwAddr,
  433. dwArg[0], dwArg[1], dwArg[2],
  434. dwRetAddr, szSymbol, dwDisplacement );
  435. }
  436. }
  437. }
  438. }
  439. }
  440. #else
  441. Print( "Only supported on x86\n" );
  442. #endif
  443. }
  444. VOID
  445. TDebugExt::
  446. vFindPointer(
  447. HANDLE hProcess,
  448. ULONG_PTR dwStartAddr,
  449. ULONG_PTR dwEndAddr,
  450. ULONG_PTR dwStartPtr,
  451. ULONG_PTR dwEndPtr
  452. )
  453. {
  454. BYTE abyBuf[kFPGranularity];
  455. //
  456. // Read each granularity chunk then scan the buffer.
  457. // (Start by rounding down.)
  458. //
  459. ULONG_PTR dwCur;
  460. for( dwCur = dwStartAddr & ~( kFPGranularity - 1 );
  461. dwCur < dwEndAddr;
  462. dwCur += kFPGranularity ){
  463. ZeroMemory( abyBuf, sizeof( abyBuf ));
  464. move( abyBuf, dwCur );
  465. ULONG_PTR i;
  466. for( i=0; i< kFPGranularity; i += sizeof( DWORD ) ){
  467. ULONG_PTR dwVal = *((PDWORD)(abyBuf+i));
  468. if( dwVal >= dwStartPtr &&
  469. dwVal <= dwEndPtr &&
  470. dwCur + i >= dwStartAddr &&
  471. dwCur + i <= dwEndAddr ){
  472. Print( "%08x : %08x\n", dwCur + i, dwVal );
  473. }
  474. }
  475. if( CheckControlCRtn()){
  476. Print( "Aborted at %08x.\n", dwCur+i );
  477. return;
  478. }
  479. }
  480. }
  481. VOID
  482. TDebugExt::
  483. vCreateRemoteThread(
  484. HANDLE hProcess,
  485. ULONG_PTR dwAddr,
  486. ULONG_PTR dwParm
  487. )
  488. {
  489. DWORD dwThreadId = 0;
  490. if( !CreateRemoteThread( hProcess,
  491. NULL,
  492. 4*4096,
  493. (LPTHREAD_START_ROUTINE)dwAddr,
  494. (LPVOID)dwParm,
  495. 0,
  496. &dwThreadId )){
  497. Print( "<Error: Unable to ct %x( %x ) %d.>\n",
  498. dwAddr, dwParm, GetLastError( ));
  499. return;
  500. }
  501. Print( "<ct %x( %x ) threadid=<%d>>\n", dwAddr, dwParm, dwThreadId );
  502. }
  503. /********************************************************************
  504. Extension entrypoints.
  505. ********************************************************************/
  506. DEBUG_EXT_HEAD( help )
  507. {
  508. DEBUG_EXT_SETUP_VARS();
  509. Print( "Spllib Extensions\n" );
  510. Print( "---------------------------------------------------------\n" );
  511. Print( "d dump spooler structure based on signature\n" );
  512. Print( "ds dump pIniSpooler\n" );
  513. Print( "dlcs dump localspl's critical section (debug builds only)\n" );
  514. Print( "lastlog dump localspl's debug tracing (uses ddt flags)\n" );
  515. Print( "ddev dump Unicode devmode\n" );
  516. Print( "ddeva dump Ansi devmode\n" );
  517. Print( "dmem dump spllib heap blocks\n" );
  518. Print( "---------------------------------------------------------\n" );
  519. Print( "dcs dump spllib critical section\n" );
  520. Print( "ddt dump spllib debug trace buffer\n" );
  521. Print( " ** Recent lines printed first! **\n" );
  522. Print( " -c Count (number of recent lines to print)\n" );
  523. Print( " -l Level (DBG_*) to print\n" );
  524. Print( " -b Dump backtrace (x86 only)\n" );
  525. Print( " -d Print debug message (default if -x not specified)\n" );
  526. Print( " -x Print hex information\n" );
  527. Print( " -r Dump raw buffer: specify pointer to lines\n" );
  528. Print( " -t tid: Dump specific thread $1\n" );
  529. Print( " -s Skip $1 lines that would otherwise print.\n" );
  530. Print( " -m Search for $1 in memory block (gpbtAlloc/gpbtFree only)\n" );
  531. Print( "dbt dump raw backtrace\n" );
  532. Print( "dtbt dump text backtrace\n" );
  533. Print( "ddp dump debug pointers\n" );
  534. Print( "---------------------------------------------------------\n" );
  535. Print( "fl free library $1 (hLibrary)\n" );
  536. Print( "ct create thread at $1 with arg $2\n" );
  537. Print( "fp find pointer from $1 to $2 range, ptr $3 to $4 range\n" );
  538. Print( "lc look for calls at $1 for $2 bytes (x86 only)\n" );
  539. Print( " -a Check all for return addresses\n" );
  540. Print( " -v Verbose\n" );
  541. Print( "sleep Sleep for $1 ms\n" );
  542. Print( "dbti Dump KM backtrace index\n");
  543. }
  544. DEBUG_EXT_HEAD( dtbt )
  545. {
  546. DEBUG_EXT_SETUP_VARS();
  547. for( ; *lpArgumentString; )
  548. {
  549. ULONG_PTR p;
  550. CHAR szSymbol[64];
  551. p = TDebugExt::dwEval( lpArgumentString, FALSE );
  552. if( !p )
  553. {
  554. break;
  555. }
  556. ULONG_PTR dwDisplacement;
  557. GetSymbolRtn( (PVOID)p,
  558. szSymbol,
  559. &dwDisplacement );
  560. Print( "%08x %s+%x\n", p, szSymbol, dwDisplacement );
  561. }
  562. }
  563. DEBUG_EXT_HEAD( fl )
  564. {
  565. DEBUG_EXT_SETUP_VARS();
  566. //
  567. // Relies on the fact that kernel32 won't be relocated.
  568. //
  569. TDebugExt::vCreateRemoteThread( hCurrentProcess,
  570. (ULONG_PTR)&FreeLibrary,
  571. TDebugExt::dwEval( lpArgumentString, FALSE ));
  572. }
  573. DEBUG_EXT_HEAD( fp )
  574. {
  575. DEBUG_EXT_SETUP_VARS();
  576. ULONG_PTR dwStartAddr = TDebugExt::dwEval( lpArgumentString, TRUE );
  577. ULONG_PTR dwEndAddr = TDebugExt::dwEval( lpArgumentString, TRUE );
  578. ULONG_PTR dwStartPtr = TDebugExt::dwEval( lpArgumentString, TRUE );
  579. ULONG_PTR dwEndPtr = TDebugExt::dwEval( lpArgumentString, TRUE );
  580. TDebugExt::vFindPointer( hCurrentProcess,
  581. dwStartAddr,
  582. dwEndAddr,
  583. dwStartPtr,
  584. dwEndPtr );
  585. }
  586. DEBUG_EXT_HEAD( ct )
  587. {
  588. DEBUG_EXT_SETUP_VARS();
  589. ULONG_PTR dwStartAddr = TDebugExt::dwEval( lpArgumentString, TRUE );
  590. ULONG_PTR dwParm = TDebugExt::dwEval( lpArgumentString, FALSE );
  591. TDebugExt::vCreateRemoteThread( hCurrentProcess,
  592. dwStartAddr,
  593. dwParm );
  594. }
  595. DEBUG_EXT_HEAD( sleep )
  596. {
  597. DEBUG_EXT_SETUP_VARS();
  598. const UINT_PTR kSleepInterval = 500;
  599. ULONG_PTR SleepMS = atoi(lpArgumentString);
  600. UINT_PTR i = SleepMS / kSleepInterval;
  601. Sleep((DWORD)(SleepMS % kSleepInterval));
  602. for (i = SleepMS / kSleepInterval; i; --i)
  603. {
  604. if (CheckControlCRtn())
  605. {
  606. break;
  607. }
  608. Sleep(kSleepInterval);
  609. }
  610. }
  611. DEBUG_EXT_HEAD( lc )
  612. {
  613. DEBUG_EXT_SETUP_VARS();
  614. ULONG_PTR dwFlags = 0;
  615. for( ; *lpArgumentString; ++lpArgumentString ){
  616. while( *lpArgumentString == ' ' ){
  617. ++lpArgumentString;
  618. }
  619. if (*lpArgumentString != '-') {
  620. break;
  621. }
  622. ++lpArgumentString;
  623. switch( *lpArgumentString ){
  624. case 'A':
  625. case 'a':
  626. dwFlags |= TDebugExt::kLCFlagAll;
  627. break;
  628. case 'V':
  629. case 'v':
  630. dwFlags |= TDebugExt::kLCVerbose;
  631. break;
  632. default:
  633. Print( "Unknown option %c.\n", lpArgumentString[0] );
  634. return;
  635. }
  636. }
  637. ULONG_PTR dwStartAddr = TDebugExt::dwEval( lpArgumentString, TRUE );
  638. ULONG_PTR dwLength = TDebugExt::dwEval( lpArgumentString, FALSE );
  639. TDebugExt::vLookCalls( hCurrentProcess,
  640. hCurrentThread,
  641. dwStartAddr,
  642. dwLength,
  643. dwFlags );
  644. }