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.

582 lines
13 KiB

4 years ago
  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. HANDLE hCurrentProcess;
  14. WINDBG_EXTENSION_APIS ExtensionApis;
  15. PWINDBG_OUTPUT_ROUTINE Print;
  16. PWINDBG_GET_EXPRESSION EvalExpression;
  17. PWINDBG_GET_SYMBOL GetSymbolRtn;
  18. PWINDBG_CHECK_CONTROL_C CheckControlCRtn;
  19. USHORT SavedMajorVersion;
  20. USHORT SavedMinorVersion;
  21. BOOL bWindbg = FALSE;
  22. VOID
  23. WinDbgExtensionDllInit(
  24. PWINDBG_EXTENSION_APIS lpExtensionApis,
  25. USHORT MajorVersion,
  26. USHORT MinorVersion
  27. )
  28. {
  29. ::ExtensionApis = *lpExtensionApis;
  30. SavedMajorVersion = MajorVersion;
  31. SavedMinorVersion = MinorVersion;
  32. bWindbg = TRUE;
  33. return;
  34. }
  35. VOID
  36. TDebugExt::
  37. vDumpPDL(
  38. PDLINK pDLink
  39. )
  40. {
  41. Print( "%x %x", pDLink->FLink, pDLink->BLink );
  42. if( pDLink->FLink == pDLink->BLink ){
  43. Print( " <empty>\n" );
  44. } else {
  45. Print( "\n" );
  46. }
  47. }
  48. VOID
  49. TDebugExt::
  50. vDumpStr(
  51. LPCWSTR pszString
  52. )
  53. {
  54. WCHAR szString[MAX_PATH];
  55. if( (LPCWSTR)pszString == NULL ){
  56. Print( "(NULL)\n" );
  57. return;
  58. }
  59. szString[0] = 0;
  60. move( szString, pszString );
  61. if( szString[0] == 0 ){
  62. Print( "\"\"\n" );
  63. } else {
  64. Print( "%ws\n", szString );
  65. }
  66. }
  67. VOID
  68. TDebugExt::
  69. vDumpStrA(
  70. LPCSTR pszString
  71. )
  72. {
  73. CHAR szString[MAX_PATH];
  74. if( (LPCSTR)pszString == NULL ){
  75. Print( "(NULL)\n" );
  76. return;
  77. }
  78. szString[0] = 0;
  79. move( szString, pszString );
  80. if( szString[0] == 0 ){
  81. Print( "\"\"\n" );
  82. } else {
  83. Print( "%hs\n", szString );
  84. }
  85. }
  86. VOID
  87. TDebugExt::
  88. vDumpTime(
  89. const SYSTEMTIME& st
  90. )
  91. {
  92. Print( "%d/%d/%d %d %d:%d:%d.%d\n",
  93. st.wMonth,
  94. st.wDay,
  95. st.wYear,
  96. st.wDayOfWeek,
  97. st.wHour,
  98. st.wMinute,
  99. st.wSecond,
  100. st.wMilliseconds );
  101. }
  102. VOID
  103. TDebugExt::
  104. vDumpFlags(
  105. DWORD dwFlags,
  106. PDEBUG_FLAGS pDebugFlags
  107. )
  108. {
  109. DWORD dwFound = 0;
  110. Print( "%x [ ", dwFlags );
  111. for( ; pDebugFlags->dwFlag; ++pDebugFlags ){
  112. if( dwFlags & pDebugFlags->dwFlag ){
  113. Print( "%s ", pDebugFlags->pszFlag );
  114. dwFound |= pDebugFlags->dwFlag;
  115. }
  116. }
  117. Print( "]" );
  118. //
  119. // Check if there are extra bits set that we don't understand.
  120. //
  121. if( dwFound != dwFlags ){
  122. Print( "<ExtraBits: %x>", dwFlags & ~dwFound );
  123. }
  124. Print( "\n" );
  125. }
  126. VOID
  127. TDebugExt::
  128. vDumpValue(
  129. DWORD dwValue,
  130. PDEBUG_VALUES pDebugValues
  131. )
  132. {
  133. Print( "%x ", dwValue );
  134. for( ; pDebugValues->dwValue; ++pDebugValues ){
  135. if( dwValue == pDebugValues->dwValue ){
  136. Print( "%s ", pDebugValues->pszValue );
  137. }
  138. }
  139. Print( "\n" );
  140. }
  141. VOID
  142. TDebugExt::
  143. vDumpTrace(
  144. PVOID apvBackTrace[]
  145. )
  146. {
  147. INT i;
  148. UCHAR szSymbol[64];
  149. DWORD dwDisplacement;
  150. for( i=0; i < VBackTrace::kMaxDepth; i++ ){
  151. if( !apvBackTrace[i] ){
  152. break;
  153. }
  154. GetSymbolRtn( apvBackTrace[i],
  155. szSymbol,
  156. &dwDisplacement );
  157. Print( "%08x %s+%x\n",
  158. apvBackTrace[i], szSymbol,
  159. dwDisplacement );
  160. }
  161. if( i > 0 ){
  162. Print( "\n" );
  163. }
  164. }
  165. DWORD
  166. TDebugExt::
  167. dwEval(
  168. LPSTR& lpArgumentString,
  169. BOOL bParam
  170. )
  171. {
  172. DWORD dwReturn;
  173. LPSTR pSpace = NULL;
  174. while( *lpArgumentString == ' ' ){
  175. lpArgumentString++;
  176. }
  177. //
  178. // If it's a parameter, scan to next space and delimit.
  179. //
  180. if( bParam ){
  181. for( pSpace = lpArgumentString; *pSpace && *pSpace != ' '; ++pSpace )
  182. ;
  183. if( *pSpace == ' ' ){
  184. *pSpace = 0;
  185. }
  186. }
  187. dwReturn = (DWORD)EvalExpression( lpArgumentString );
  188. while( *lpArgumentString != ' ' && *lpArgumentString ){
  189. lpArgumentString++;
  190. }
  191. if( pSpace ){
  192. *pSpace = ' ';
  193. }
  194. return dwReturn;
  195. }
  196. /********************************************************************
  197. Generic extensions
  198. ********************************************************************/
  199. VOID
  200. TDebugExt::
  201. vLookCalls(
  202. HANDLE hProcess,
  203. DWORD dwStartAddr,
  204. DWORD dwLength,
  205. DWORD dwFlags
  206. )
  207. {
  208. #if i386
  209. struct OPCODES {
  210. BYTE op;
  211. UINT uLen;
  212. };
  213. OPCODES Opcodes[] = {
  214. 0xe8, 5, // rel16
  215. 0xff, 6, // r/m16
  216. 0x0, 0
  217. };
  218. dwStartAddr = DWordAlign( dwStartAddr );
  219. dwLength = DWordAlign( dwLength );
  220. DWORD dwAddr;
  221. for( dwAddr = dwStartAddr;
  222. dwAddr < dwStartAddr + dwLength;
  223. ++dwAddr ){
  224. if( CheckControlCRtn()){
  225. Print( "Aborted.\n" );
  226. return;
  227. }
  228. //
  229. // Get a value on the stack and see if it looks like an ebp on
  230. // the stack. It should be close to the current address, but
  231. // be greater.
  232. //
  233. DWORD dwNextFrame = 0;
  234. move( dwNextFrame, dwAddr );
  235. BOOL bLooksLikeEbp = dwNextFrame > dwAddr &&
  236. dwNextFrame - dwAddr < kMaxCallFrame;
  237. //
  238. // If we are dumping all, or it looks like an ebp, dump it.
  239. //
  240. if(( dwFlags & kLCFlagAll ) || bLooksLikeEbp ){
  241. //
  242. // Check if next address looks like a valid call request.
  243. //
  244. DWORD dwRetAddr = 0;
  245. //
  246. // Get return address.
  247. //
  248. move( dwRetAddr, dwAddr + sizeof( DWORD ));
  249. //
  250. // Get 16 bytes before return address.
  251. //
  252. BYTE abyBuffer[16];
  253. ZeroMemory( abyBuffer, sizeof( abyBuffer ));
  254. move( abyBuffer, dwRetAddr - sizeof( abyBuffer ));
  255. //
  256. // Check if previous bytes look like a call instruction.
  257. //
  258. UINT i;
  259. for( i = 0; Opcodes[i].op; ++i ){
  260. if( abyBuffer[sizeof( abyBuffer )-Opcodes[i].uLen] ==
  261. Opcodes[i].op ){
  262. UCHAR szSymbol[64];
  263. DWORD dwDisplacement;
  264. LPCSTR pszNull = "";
  265. LPCSTR pszStar = "*** ";
  266. LPCSTR pszPrefix = pszNull;
  267. if(( dwFlags & kLCFlagAll ) && bLooksLikeEbp ){
  268. pszPrefix = pszStar;
  269. }
  270. GetSymbolRtn( (PVOID)(dwRetAddr - Opcodes[i].uLen),
  271. szSymbol,
  272. &dwDisplacement );
  273. Print( "%s%x %s + 0x%x\n",
  274. pszPrefix,
  275. dwRetAddr - Opcodes[i].uLen,
  276. szSymbol,
  277. dwDisplacement );
  278. //
  279. // Found what could be a match: dump it out.
  280. //
  281. DWORD dwArg[4];
  282. move( dwArg, dwAddr + 2*sizeof( DWORD ));
  283. Print( "%s%08x: %08x %08x %08x %08x %08x %08x\n",
  284. pszPrefix,
  285. dwAddr,
  286. dwNextFrame, dwRetAddr,
  287. dwArg[0], dwArg[1], dwArg[2], dwArg[3] );
  288. DWORD adwNextFrame[2];
  289. ZeroMemory( adwNextFrame, sizeof( adwNextFrame ));
  290. move( adwNextFrame, dwNextFrame );
  291. Print( "%s%08x: %08x %08x\n\n",
  292. pszPrefix,
  293. dwNextFrame, adwNextFrame[0], adwNextFrame[1] );
  294. }
  295. }
  296. }
  297. }
  298. #else
  299. Print( "Only supported on x86\n" );
  300. #endif
  301. }
  302. VOID
  303. TDebugExt::
  304. vFindPointer(
  305. HANDLE hProcess,
  306. DWORD dwStartAddr,
  307. DWORD dwEndAddr,
  308. DWORD dwStartPtr,
  309. DWORD dwEndPtr
  310. )
  311. {
  312. BYTE abyBuf[kFPGranularity];
  313. //
  314. // Read each granularity chunk then scan the buffer.
  315. // (Start by rounding down.)
  316. //
  317. DWORD dwCur;
  318. for( dwCur = dwStartAddr & ~( kFPGranularity - 1 );
  319. dwCur < dwEndAddr;
  320. dwCur += kFPGranularity ){
  321. ZeroMemory( abyBuf, sizeof( abyBuf ));
  322. move( abyBuf, dwCur );
  323. DWORD i;
  324. for( i=0; i< kFPGranularity; i += sizeof( DWORD ) ){
  325. DWORD dwVal = *((PDWORD)(abyBuf+i));
  326. if( dwVal >= dwStartPtr &&
  327. dwVal <= dwEndPtr &&
  328. dwCur + i >= dwStartAddr &&
  329. dwCur + i <= dwEndAddr ){
  330. Print( "%08x : %08x\n", dwCur + i, dwVal );
  331. }
  332. }
  333. if( CheckControlCRtn()){
  334. Print( "Aborted at %08x.\n", dwCur+i );
  335. return;
  336. }
  337. }
  338. }
  339. VOID
  340. TDebugExt::
  341. vCreateRemoteThread(
  342. HANDLE hProcess,
  343. DWORD dwAddr,
  344. DWORD dwParm
  345. )
  346. {
  347. DWORD dwThreadId = 0;
  348. if( !CreateRemoteThread( hProcess,
  349. NULL,
  350. 4*4096,
  351. (LPTHREAD_START_ROUTINE)dwAddr,
  352. (LPVOID)dwParm,
  353. 0,
  354. &dwThreadId )){
  355. Print( "<Error: Unable to ct %x( %x ) %d.>\n",
  356. dwAddr, dwParm, GetLastError( ));
  357. return;
  358. }
  359. Print( "<ct %x( %x ) threadid=<%d>>\n", dwAddr, dwParm, dwThreadId );
  360. }
  361. /********************************************************************
  362. Extension entrypoints.
  363. ********************************************************************/
  364. DEBUG_EXT_HEAD( help )
  365. {
  366. DEBUG_EXT_SETUP_VARS();
  367. Print( "Spllib Extensions\n" );
  368. Print( "---------------------------------------------------------\n" );
  369. Print( "d dump spooler structure based on signature\n" );
  370. Print( "ds dump pIniSpooler\n" );
  371. Print( "dlcs dump localspl's critical section (debug builds only)\n" );
  372. Print( "lastlog dump localspl's debug tracing (uses ddt flags)\n" );
  373. Print( "ddev dump Unicode devmode\n" );
  374. Print( "ddeva dump Ansi devmode\n" );
  375. Print( "---------------------------------------------------------\n" );
  376. Print( "dcs dump spllib critical section\n" );
  377. Print( "ddt dump spllib debug trace buffer\n" );
  378. Print( " ** Recent lines printed first! **\n" );
  379. Print( " -c Count (number of recent lines to print)\n" );
  380. Print( " -l Level (DBG_*) to print\n" );
  381. Print( " -b Dump backtrace (x86 only)\n" );
  382. Print( " -d Print debug message (default if -x not specified)\n" );
  383. Print( " -x Print hex information\n" );
  384. Print( " -r Dump raw buffer: specify pointer to lines\n" );
  385. Print( " -t tid: Dump specific thread $1\n" );
  386. Print( " -s Skip $1 lines that would otherwise print.\n" );
  387. Print( " -m Search for $1 in memory block (gpbtAlloc/gpbtFree only)\n" );
  388. Print( "dbt dump raw backtrace\n" );
  389. Print( "ddp dump debug pointers\n" );
  390. Print( "---------------------------------------------------------\n" );
  391. Print( "duntfy dump printui notify\n" );
  392. Print( "dup dump printui printer\n" );
  393. Print( " -t[e] types MExecWork base classes\n" );
  394. Print( "---------------------------------------------------------\n" );
  395. Print( "fl free library $1 (hLibrary)\n" );
  396. Print( "ct create thread at $1 with arg $2\n" );
  397. Print( "fp find pointer from $1 to $2 range, ptr $3 to $4 range\n" );
  398. Print( "lc look for calls at $1 for $2 bytes (x86 only)\n" );
  399. Print( " -a Check all for return addresses\n" );
  400. }
  401. DEBUG_EXT_HEAD( fl )
  402. {
  403. DEBUG_EXT_SETUP_VARS();
  404. //
  405. // Relies on the fact that kernel32 won't be relocated.
  406. //
  407. TDebugExt::vCreateRemoteThread( hCurrentProcess,
  408. (DWORD)&FreeLibrary,
  409. TDebugExt::dwEval( lpArgumentString, FALSE ));
  410. }
  411. DEBUG_EXT_HEAD( fp )
  412. {
  413. DEBUG_EXT_SETUP_VARS();
  414. DWORD dwStartAddr = TDebugExt::dwEval( lpArgumentString, TRUE );
  415. DWORD dwEndAddr = TDebugExt::dwEval( lpArgumentString, TRUE );
  416. DWORD dwStartPtr = TDebugExt::dwEval( lpArgumentString, TRUE );
  417. DWORD dwEndPtr = TDebugExt::dwEval( lpArgumentString, TRUE );
  418. TDebugExt::vFindPointer( hCurrentProcess,
  419. dwStartAddr,
  420. dwEndAddr,
  421. dwStartPtr,
  422. dwEndPtr );
  423. }
  424. DEBUG_EXT_HEAD( ct )
  425. {
  426. DEBUG_EXT_SETUP_VARS();
  427. DWORD dwStartAddr = TDebugExt::dwEval( lpArgumentString, TRUE );
  428. DWORD dwParm = TDebugExt::dwEval( lpArgumentString, FALSE );
  429. TDebugExt::vCreateRemoteThread( hCurrentProcess,
  430. dwStartAddr,
  431. dwParm );
  432. }
  433. DEBUG_EXT_HEAD( lc )
  434. {
  435. DEBUG_EXT_SETUP_VARS();
  436. DWORD dwFlags = 0;
  437. for( ; *lpArgumentString; ++lpArgumentString ){
  438. while( *lpArgumentString == ' ' ){
  439. ++lpArgumentString;
  440. }
  441. if (*lpArgumentString != '-') {
  442. break;
  443. }
  444. ++lpArgumentString;
  445. switch( *lpArgumentString++ ){
  446. case 'A':
  447. case 'a':
  448. dwFlags |= TDebugExt::kLCFlagAll;
  449. break;
  450. default:
  451. Print( "Unknown option %c.\n", lpArgumentString[-1] );
  452. return;
  453. }
  454. }
  455. DWORD dwStartAddr = TDebugExt::dwEval( lpArgumentString, TRUE );
  456. DWORD dwLength = TDebugExt::dwEval( lpArgumentString, FALSE );
  457. TDebugExt::vLookCalls( hCurrentProcess,
  458. dwStartAddr,
  459. dwLength,
  460. dwFlags );
  461. }