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.

711 lines
16 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. verifier.c
  5. Abstract:
  6. Application verifier debugger extension for both ntsd and kd.
  7. Author:
  8. Silviu Calinoiu (SilviuC) 4-Mar-2001
  9. Environment:
  10. User Mode.
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. ULONG
  16. VrfGetArguments (
  17. PCHAR ArgsString,
  18. PCHAR Args[],
  19. ULONG NoOfArgs
  20. );
  21. VOID
  22. VrfHelp (
  23. );
  24. BOOLEAN
  25. VrfTraceInitialize (
  26. );
  27. ULONG64
  28. VrfTraceAddress (
  29. ULONG TraceIndex
  30. );
  31. VOID
  32. VrfTraceDump (
  33. ULONG TraceIndex
  34. );
  35. VOID
  36. VrfDumpSettings (
  37. );
  38. VOID
  39. VrfDumpVspaceLog (
  40. ULONG NoOfEntries,
  41. ULONG64 Address
  42. );
  43. VOID
  44. VrfDumpHeapLog (
  45. ULONG NoOfEntries,
  46. ULONG64 Address
  47. );
  48. DECLARE_API( avrf )
  49. /*++
  50. Routine Description:
  51. Application verifier debugger extension.
  52. Arguments:
  53. args -
  54. Return Value:
  55. None
  56. --*/
  57. {
  58. PCHAR Args[16];
  59. ULONG NoOfArgs, I;
  60. INIT_API();
  61. //
  62. // Parse arguments.
  63. //
  64. NoOfArgs = VrfGetArguments ((PCHAR)args,
  65. Args,
  66. 16);
  67. #if 0
  68. for (I = 0; I < NoOfArgs; I += 1) {
  69. dprintf ("%02u: %s\n", I, Args[I]);
  70. }
  71. #endif
  72. //
  73. // Check if help needed
  74. //
  75. if (NoOfArgs > 0 && strstr (Args[0], "?") != NULL) {
  76. VrfHelp ();
  77. goto Exit;
  78. }
  79. if (VrfTraceInitialize() == FALSE) {
  80. goto Exit;
  81. }
  82. if (NoOfArgs > 1 && _stricmp (Args[0], "-trace") == 0) {
  83. VrfTraceDump (atoi(Args[1]));
  84. goto Exit;
  85. }
  86. if (NoOfArgs > 1 && _stricmp (Args[0], "-vs") == 0) {
  87. if (NoOfArgs > 2 && _stricmp (Args[1], "-a") == 0) {
  88. ULONG64 Address;
  89. BOOL Result;
  90. PCSTR Remainder;
  91. Result = GetExpressionEx (Args[2], &Address, &Remainder);
  92. if (Result == FALSE) {
  93. dprintf ("\nFailed to convert `%s' to an address.\n", Args[2]);
  94. goto Exit;
  95. }
  96. // sscanf (Args[2], "%I64X", &Address);
  97. dprintf ("Searching in vspace log for address %I64X ...\n\n", Address);
  98. VrfDumpVspaceLog (0, Address);
  99. goto Exit;
  100. }
  101. else {
  102. VrfDumpVspaceLog (atoi(Args[1]), 0);
  103. goto Exit;
  104. }
  105. }
  106. if (NoOfArgs > 1 && _stricmp (Args[0], "-hp") == 0) {
  107. if (NoOfArgs > 2 && _stricmp (Args[1], "-a") == 0) {
  108. ULONG64 Address;
  109. BOOL Result;
  110. PCSTR Remainder;
  111. Result = GetExpressionEx (Args[2], &Address, &Remainder);
  112. if (Result == FALSE) {
  113. dprintf ("\nFailed to convert `%s' to an address.\n", Args[2]);
  114. goto Exit;
  115. }
  116. // sscanf (Args[2], "%I64X", &Address);
  117. dprintf ("Searching in vspace log for address %I64X ...\n\n", Address);
  118. VrfDumpHeapLog (0, Address);
  119. goto Exit;
  120. }
  121. else {
  122. VrfDumpHeapLog (atoi(Args[1]), 0);
  123. goto Exit;
  124. }
  125. }
  126. //
  127. // If no option specified then we just print current settings.
  128. //
  129. VrfDumpSettings ();
  130. Exit:
  131. EXIT_API();
  132. return S_OK;
  133. }
  134. VOID
  135. VrfHelp (
  136. )
  137. {
  138. dprintf ("Application verifier debugger extension \n"
  139. " \n"
  140. "!avrf displays current settings and stop \n"
  141. " data if a verifier stop happened. \n"
  142. "!avrf -vs N dumps last N entries from vspace log. \n"
  143. "!avrf -vs -a ADDR searches ADDR in the vspace log. \n"
  144. "!avrf -hp N dumps last N entries from heap log. \n"
  145. "!avrf -hp -a ADDR searches ADDR in the heap log. \n"
  146. " \n");
  147. }
  148. /////////////////////////////////////////////////////////////////////
  149. /////////////////////////////////////////// Argument parsing routines
  150. /////////////////////////////////////////////////////////////////////
  151. PCHAR
  152. VrfGetArgument (
  153. PCHAR Args,
  154. PCHAR * Next
  155. )
  156. {
  157. PCHAR Start;
  158. if (Args == NULL) {
  159. return NULL;
  160. }
  161. while (*Args == ' ' || *Args == '\t') {
  162. Args += 1;
  163. }
  164. if (*Args == '\0') {
  165. return NULL;
  166. }
  167. Start = Args;
  168. while (*Args != ' ' && *Args != '\t' && *Args != '\0') {
  169. Args += 1;
  170. }
  171. if (*Args == '\0') {
  172. *Next = NULL;
  173. }
  174. else {
  175. *Args = '\0';
  176. *Next = Args + 1;
  177. }
  178. return Start;
  179. }
  180. ULONG
  181. VrfGetArguments (
  182. PCHAR ArgsString,
  183. PCHAR Args[],
  184. ULONG NoOfArgs
  185. )
  186. {
  187. PCHAR Arg = ArgsString;
  188. PCHAR Next;
  189. ULONG Index;
  190. for (Index = 0; Index < NoOfArgs; Index += 1) {
  191. Arg = VrfGetArgument (Arg, &Next);
  192. if (Arg) {
  193. Args[Index] = Arg;
  194. }
  195. else {
  196. break;
  197. }
  198. Arg = Next;
  199. }
  200. return Index;
  201. }
  202. /////////////////////////////////////////////////////////////////////
  203. /////////////////////////////////////////////////// Dump stack traces
  204. /////////////////////////////////////////////////////////////////////
  205. ULONG64 TraceDbArrayEnd;
  206. ULONG PvoidSize;
  207. BOOLEAN
  208. VrfTraceInitialize (
  209. )
  210. {
  211. ULONG64 TraceDatabaseAddress;
  212. ULONG64 TraceDatabase;
  213. //
  214. // Stack trace database address
  215. //
  216. TraceDatabaseAddress = GetExpression("ntdll!RtlpStackTraceDataBase");
  217. if ( TraceDatabaseAddress == 0 ) {
  218. dprintf( "Unable to resolve ntdll!RtlpStackTraceDataBase symbolic name.\n");
  219. return FALSE;
  220. }
  221. if (ReadPtr (TraceDatabaseAddress, &TraceDatabase ) != S_OK) {
  222. dprintf( "Cannot read pointer at ntdll!RtlpStackTraceDataBase\n" );
  223. return FALSE;
  224. }
  225. if (TraceDatabase == 0) {
  226. dprintf( "Stack traces not enabled (ntdll!RtlpStackTraceDataBase is null).\n" );
  227. return FALSE;
  228. }
  229. //
  230. // Find the array of stack traces
  231. //
  232. if (InitTypeRead(TraceDatabase, ntdll!_STACK_TRACE_DATABASE)) {
  233. dprintf("Unable to read type ntdll!_STACK_TRACE_DATABASE @ %p\n", TraceDatabase);
  234. return FALSE;
  235. }
  236. TraceDbArrayEnd = ReadField (EntryIndexArray);
  237. PvoidSize = GetTypeSize ("ntdll!PVOID");
  238. return TRUE;
  239. }
  240. ULONG64
  241. VrfTraceAddress (
  242. ULONG TraceIndex
  243. )
  244. {
  245. ULONG64 TracePointerAddress;
  246. ULONG64 TracePointer;
  247. TracePointerAddress = TraceDbArrayEnd - TraceIndex * PvoidSize;
  248. if (ReadPtr (TracePointerAddress, &TracePointer) != S_OK) {
  249. dprintf ("Cannot read stack trace address @ %p\n", TracePointerAddress);
  250. return 0;
  251. }
  252. return TracePointer;
  253. }
  254. VOID
  255. VrfTraceDump (
  256. ULONG TraceIndex
  257. )
  258. {
  259. ULONG64 TraceAddress;
  260. ULONG64 TraceArray;
  261. ULONG TraceDepth;
  262. ULONG Offset;
  263. ULONG Index;
  264. ULONG64 ReturnAddress;
  265. CHAR Symbol[ 1024 ];
  266. ULONG64 Displacement;
  267. //
  268. // Get real address of the trace.
  269. //
  270. TraceAddress = VrfTraceAddress (TraceIndex);
  271. if (TraceAddress == 0) {
  272. return;
  273. }
  274. //
  275. // Read the stack trace depth
  276. //
  277. if (InitTypeRead(TraceAddress, ntdll!_RTL_STACK_TRACE_ENTRY)) {
  278. dprintf("Unable to read type ntdll!_RTL_STACK_TRACE_ENTRY @ %p\n", TraceAddress);
  279. return;
  280. }
  281. TraceDepth = (ULONG)ReadField (Depth);
  282. //
  283. // Limit the depth to 20 to protect ourselves from corrupted data
  284. //
  285. TraceDepth = __min (TraceDepth, 16);
  286. //
  287. // Get a pointer to the BackTrace array
  288. //
  289. GetFieldOffset ("ntdll!_RTL_STACK_TRACE_ENTRY", "BackTrace", &Offset);
  290. TraceArray = TraceAddress + Offset;
  291. //
  292. // Dump this stack trace. Skip first two entries.
  293. //
  294. TraceArray += 2 * PvoidSize;
  295. for (Index = 2; Index < TraceDepth; Index += 1) {
  296. if (ReadPtr (TraceArray, &ReturnAddress) != S_OK) {
  297. dprintf ("Cannot read address @ %p\n", TraceArray);
  298. return;
  299. }
  300. GetSymbol (ReturnAddress, Symbol, &Displacement);
  301. dprintf ("\t%p: %s+0x%I64X\n",
  302. ReturnAddress,
  303. Symbol,
  304. Displacement );
  305. TraceArray += PvoidSize;
  306. }
  307. }
  308. /////////////////////////////////////////////////////////////////////
  309. /////////////////////////////////////////////////////// Dump settings
  310. /////////////////////////////////////////////////////////////////////
  311. VOID
  312. VrfDumpSettings (
  313. )
  314. {
  315. ULONG64 FlagsAddress;
  316. ULONG Flags;
  317. ULONG BytesRead;
  318. ULONG64 StopAddress;
  319. ULONG64 StopData[5];
  320. ULONG I;
  321. ULONG UlongPtrSize;
  322. UlongPtrSize = GetTypeSize ("ntdll!ULONG_PTR");
  323. FlagsAddress = GetExpression("ntdll!AVrfpVerifierFlags");
  324. if (FlagsAddress == 0) {
  325. dprintf( "Unable to resolve ntdll!AVrfpVerifierFlags symbolic name.\n");
  326. return;
  327. }
  328. if (ReadMemory (FlagsAddress, &Flags, sizeof Flags, &BytesRead) == FALSE) {
  329. dprintf ("Cannot read value @ %p (ntdll!AVrfpVerifierFlags) \n", FlagsAddress);
  330. return;
  331. }
  332. dprintf ("Application verifier settings (%08X): \n\n", Flags);
  333. if (Flags & RTL_VRF_FLG_FULL_PAGE_HEAP) {
  334. dprintf (" - full page heap\n");
  335. }
  336. else {
  337. dprintf (" - light page heap\n");
  338. }
  339. if (Flags & RTL_VRF_FLG_LOCK_CHECKS) {
  340. dprintf (" - lock checks (critical section verifier)\n");
  341. }
  342. if (Flags & RTL_VRF_FLG_HANDLE_CHECKS) {
  343. dprintf (" - handle checks\n");
  344. }
  345. if (Flags & RTL_VRF_FLG_STACK_CHECKS) {
  346. dprintf (" - stack checks (disable automatic stack extensions)\n");
  347. }
  348. dprintf ("\n");
  349. //
  350. // Check if a verifier stop has been encountered.
  351. //
  352. StopAddress = GetExpression("ntdll!AVrfpStopData");
  353. if (StopAddress == 0) {
  354. dprintf( "Unable to resolve ntdll!AVrfpStopData symbolic name.\n");
  355. return;
  356. }
  357. for (I = 0; I < 5; I += 1) {
  358. if (ReadPtr (StopAddress + I * UlongPtrSize, &(StopData[I])) != S_OK) {
  359. dprintf ("Cannot read value @ %p \n", StopAddress + I * UlongPtrSize);
  360. }
  361. }
  362. if (StopData[0] != 0) {
  363. dprintf ("Stop %p: %p %p %p %p \n",
  364. StopData[0],
  365. StopData[1],
  366. StopData[2],
  367. StopData[3],
  368. StopData[4]);
  369. // silviuc: dump more text info about the verifier_stop
  370. }
  371. }
  372. /////////////////////////////////////////////////////////////////////
  373. ///////////////////////////////////////////////////// Dump vspace log
  374. /////////////////////////////////////////////////////////////////////
  375. VOID
  376. VrfDumpVspaceLog (
  377. ULONG NoOfEntries,
  378. ULONG64 Address
  379. )
  380. {
  381. ULONG64 IndexAddress;
  382. ULONG Index;
  383. ULONG64 LogAddress;
  384. ULONG EntrySize;
  385. ULONG MaxIndex = 8192; // silviuc: should not be hard coded
  386. ULONG BytesRead;
  387. ULONG64 EntryAddress;
  388. ULONG TraceIndex;
  389. ULONG I;
  390. PCHAR OpName;
  391. BOOLEAN Found = FALSE;
  392. if (Address) {
  393. NoOfEntries = MaxIndex;
  394. }
  395. else {
  396. if (NoOfEntries == 0) {
  397. NoOfEntries = 8;
  398. }
  399. }
  400. EntrySize = GetTypeSize ("verifier!_VS_CALL");
  401. IndexAddress = GetExpression("verifier!VsCallsIndex");
  402. LogAddress = GetExpression("verifier!VsCalls");
  403. if (IndexAddress == 0 || LogAddress == 0 || EntrySize == 0) {
  404. dprintf( "Incorrect symbols for verifier.dll.\n");
  405. return;
  406. }
  407. if (ReadMemory (IndexAddress, &Index, sizeof Index, &BytesRead) == FALSE) {
  408. dprintf ("Cannot read value @ %p (verifier!VsCallsIndex) \n", IndexAddress);
  409. return;
  410. }
  411. for (I = 0; I < NoOfEntries; I += 1) {
  412. ULONG64 VsAddress;
  413. ULONG64 VsSize;
  414. BOOLEAN PrintTrace;
  415. EntryAddress = LogAddress + EntrySize * ((Index - I) % MaxIndex);
  416. if (InitTypeRead (EntryAddress, verifier!_VS_CALL)) {
  417. dprintf("Unable to read type verifier!_VS_CALL @ %p\n", EntryAddress);
  418. return;
  419. }
  420. switch ((ULONG)ReadField(Type)) {
  421. case 0: OpName = "VirtualAlloc"; break;
  422. case 1: OpName = "VirtualFree"; break;
  423. case 2: OpName = "MapView"; break;
  424. case 3: OpName = "UnmapView"; break;
  425. default:OpName = "Unknown?"; break;
  426. }
  427. VsAddress = ReadField(Address);
  428. VsSize = ReadField (Size);
  429. if (Address) {
  430. if (VsAddress <= Address && Address < VsAddress + VsSize) {
  431. PrintTrace = TRUE;
  432. }
  433. else {
  434. PrintTrace = FALSE;
  435. }
  436. }
  437. else {
  438. PrintTrace = TRUE;
  439. }
  440. if (PrintTrace) {
  441. Found = TRUE;
  442. dprintf ("%s (tid: 0x%X): \n"
  443. "address: %p \n"
  444. "size: %p\n"
  445. "operation: %X\n"
  446. "protection: %X\n",
  447. OpName,
  448. (ULONG)ReadField(Thread),
  449. VsAddress,
  450. VsSize,
  451. (ULONG)ReadField(Operation),
  452. (ULONG)ReadField(Protection));
  453. TraceIndex = (ULONG) ReadField (Trace);
  454. VrfTraceDump (TraceIndex);
  455. dprintf ("\n");
  456. }
  457. }
  458. if (! Found) {
  459. dprintf ("No entries found. \n");
  460. }
  461. }
  462. /////////////////////////////////////////////////////////////////////
  463. /////////////////////////////////////////////////////// Dump heap log
  464. /////////////////////////////////////////////////////////////////////
  465. VOID
  466. VrfDumpHeapLog (
  467. ULONG NoOfEntries,
  468. ULONG64 Address
  469. )
  470. {
  471. ULONG64 IndexAddress;
  472. ULONG Index;
  473. ULONG64 LogAddress;
  474. ULONG EntrySize;
  475. ULONG MaxIndex = 8192; // silviuc: should not be hard coded
  476. ULONG BytesRead;
  477. ULONG64 EntryAddress;
  478. ULONG TraceIndex;
  479. ULONG I;
  480. PCHAR OpName;
  481. BOOLEAN Found = FALSE;
  482. if (Address) {
  483. NoOfEntries = MaxIndex;
  484. }
  485. else {
  486. if (NoOfEntries == 0) {
  487. NoOfEntries = 8;
  488. }
  489. }
  490. EntrySize = GetTypeSize ("verifier!_HEAP_CALL");
  491. IndexAddress = GetExpression("verifier!HeapCallsIndex");
  492. LogAddress = GetExpression("verifier!HeapCalls");
  493. if (IndexAddress == 0 || LogAddress == 0 || EntrySize == 0) {
  494. dprintf( "Incorrect symbols for verifier.dll.\n");
  495. return;
  496. }
  497. if (ReadMemory (IndexAddress, &Index, sizeof Index, &BytesRead) == FALSE) {
  498. dprintf ("Cannot read value @ %p (verifier!HeapCallsIndex) \n", IndexAddress);
  499. return;
  500. }
  501. for (I = 0; I < NoOfEntries; I += 1) {
  502. ULONG64 VsAddress;
  503. ULONG64 VsSize;
  504. BOOLEAN PrintTrace;
  505. EntryAddress = LogAddress + EntrySize * ((Index - I) % MaxIndex);
  506. if (InitTypeRead (EntryAddress, verifier!_HEAP_CALL)) {
  507. dprintf("Unable to read type verifier!_HEAP_CALL @ %p\n", EntryAddress);
  508. return;
  509. }
  510. VsAddress = ReadField(Address);
  511. VsSize = ReadField (Size);
  512. if (VsSize == 0) {
  513. OpName = "free";
  514. }
  515. else {
  516. OpName = "alloc";
  517. }
  518. if (Address) {
  519. if (VsAddress <= Address && Address <= VsAddress + VsSize) {
  520. PrintTrace = TRUE;
  521. }
  522. else {
  523. PrintTrace = FALSE;
  524. }
  525. }
  526. else {
  527. PrintTrace = TRUE;
  528. }
  529. if (PrintTrace) {
  530. Found = TRUE;
  531. dprintf ("%s (tid: 0x%X): \n"
  532. "address: %p \n"
  533. "size: %p\n",
  534. OpName,
  535. (ULONG)ReadField(Thread),
  536. VsAddress,
  537. VsSize);
  538. TraceIndex = (ULONG) ReadField (Trace);
  539. VrfTraceDump (TraceIndex);
  540. dprintf ("\n");
  541. }
  542. }
  543. if (! Found) {
  544. dprintf ("No entries found. \n");
  545. }
  546. }