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.

668 lines
14 KiB

  1. /*++
  2. Copyright (c) 1995-1997 Microsoft Corporation
  3. Module Name:
  4. ref.cxx
  5. Abstract:
  6. This module contains the default ntsd debugger extensions for
  7. Internet Information Server.
  8. Author:
  9. Keith Moore (keithmo) 27-Aug-1997
  10. Revision History:
  11. --*/
  12. #include "inetdbgp.h"
  13. //
  14. // The maximum number of contexts that may be passed to the "ref"
  15. // extension command on the command line.
  16. //
  17. #define MAX_REF_CONTEXT 64
  18. /************************************************************
  19. * Dump Reference Traces
  20. ************************************************************/
  21. BOOL
  22. IsContextInList(
  23. IN PVOID Context,
  24. IN PVOID * ContextList,
  25. IN LONG NumContextsInList
  26. )
  27. /*++
  28. Routine Description:
  29. Scans the given context list looking for the specified context value.
  30. Arguments:
  31. Context - The context value to look for.
  32. ContextList - The context list to scan.
  33. NumContextsInList - The number of contexts in the context list.
  34. Return Value:
  35. BOOL - TRUE if the context value is in the list, FALSE if not.
  36. --*/
  37. {
  38. while( NumContextsInList > 0 ) {
  39. if( *ContextList == Context ) {
  40. return TRUE;
  41. }
  42. ContextList++;
  43. NumContextsInList--;
  44. }
  45. return FALSE;
  46. }
  47. VOID
  48. DumpReferenceLog(
  49. IN PSTR lpArgumentString,
  50. IN BOOLEAN fReverse
  51. )
  52. /*++
  53. Routine Description:
  54. Dumps the specified reference log either forwards (fReverse == FALSE)
  55. or backwards (fReverse == TRUE).
  56. Arguments:
  57. lpArgumentString - An expression specifying the reference log to
  58. dump.
  59. fReverse - The dump direction.
  60. Return Value:
  61. None.
  62. --*/
  63. {
  64. ULONG_PTR refLogAddress = 0;
  65. ULONG_PTR entryAddress;
  66. LONG numEntries;
  67. TRACE_LOG logHeader;
  68. REF_TRACE_LOG_ENTRY logEntry;
  69. LONG i;
  70. DWORD_PTR offset;
  71. PCHAR format;
  72. PVOID specificContexts[MAX_REF_CONTEXT];
  73. LONG numSpecificContexts = 0;
  74. LONG index;
  75. LONG direction;
  76. PSTR cmdName;
  77. UCHAR symbol[MAX_SYMBOL_LEN];
  78. direction = fReverse ? -1 : 1;
  79. cmdName = fReverse ? "rref" : "ref";
  80. //
  81. // Skip leading blanks.
  82. //
  83. while( *lpArgumentString == ' ' ||
  84. *lpArgumentString == '\t' ) {
  85. lpArgumentString++;
  86. }
  87. if( *lpArgumentString == '\0' ) {
  88. PrintUsage( cmdName );
  89. return;
  90. }
  91. refLogAddress = (ULONG_PTR)GetExpression( lpArgumentString );
  92. if( refLogAddress == 0 ) {
  93. dprintf(
  94. "inetdbg.%s: cannot evaluate \"%s\"\n",
  95. cmdName,
  96. lpArgumentString
  97. );
  98. return;
  99. }
  100. //
  101. // Skip to end of expression, then skip any blanks.
  102. //
  103. while( *lpArgumentString != ' ' &&
  104. *lpArgumentString != '\t' &&
  105. *lpArgumentString != '\0' ) {
  106. lpArgumentString++;
  107. }
  108. while( *lpArgumentString == ' ' ||
  109. *lpArgumentString == '\t' ) {
  110. lpArgumentString++;
  111. }
  112. //
  113. // If we have context values, use them.
  114. //
  115. while( *lpArgumentString != '\0' && numSpecificContexts < MAX_REF_CONTEXT ) {
  116. specificContexts[numSpecificContexts++] =
  117. (PVOID)GetExpression( lpArgumentString );
  118. while( *lpArgumentString != ' ' &&
  119. *lpArgumentString != '\t' &&
  120. *lpArgumentString != '\0' ) {
  121. lpArgumentString++;
  122. }
  123. while( *lpArgumentString == ' ' ||
  124. *lpArgumentString == '\t' ) {
  125. lpArgumentString++;
  126. }
  127. }
  128. //
  129. // Read the log header, perform some sanity checks.
  130. //
  131. if( !ReadMemory(
  132. refLogAddress,
  133. &logHeader,
  134. sizeof(logHeader),
  135. NULL
  136. ) ) {
  137. dprintf(
  138. "inetdbg.%s: cannot read memory @ %p\n",
  139. cmdName,
  140. (PVOID)refLogAddress
  141. );
  142. return;
  143. }
  144. dprintf(
  145. "inetdbg.%s: log @ %p:\n"
  146. " Signature = %08lx (%s)\n"
  147. " LogSize = %lu\n"
  148. " NextEntry = %lu\n"
  149. " EntrySize = %lu\n"
  150. " LogBuffer = %p\n",
  151. cmdName,
  152. (PVOID)refLogAddress,
  153. logHeader.Signature,
  154. logHeader.Signature == TRACE_LOG_SIGNATURE
  155. ? "OK"
  156. : logHeader.Signature == TRACE_LOG_SIGNATURE_X
  157. ? "FREED"
  158. : "INVALID",
  159. logHeader.LogSize,
  160. logHeader.NextEntry,
  161. logHeader.EntrySize,
  162. logHeader.LogBuffer
  163. );
  164. if( logHeader.LogBuffer > ( (PUCHAR)refLogAddress + sizeof(logHeader) ) ) {
  165. dprintf(
  166. " Extra Data @ %p\n",
  167. (PVOID)( refLogAddress + sizeof(logHeader) )
  168. );
  169. }
  170. if( logHeader.Signature != TRACE_LOG_SIGNATURE &&
  171. logHeader.Signature != TRACE_LOG_SIGNATURE_X ) {
  172. dprintf(
  173. "inetdbg.%s: log @ %p has invalid signature %08lx:\n",
  174. cmdName,
  175. (PVOID)refLogAddress,
  176. logHeader.Signature
  177. );
  178. return;
  179. }
  180. if( logHeader.EntrySize != sizeof(logEntry) ) {
  181. dprintf(
  182. "inetdbg.%s: log @ %p is not a ref count log\n",
  183. cmdName,
  184. (PVOID)refLogAddress
  185. );
  186. return;
  187. }
  188. if( logHeader.NextEntry == -1 ) {
  189. dprintf(
  190. "inetdbg.%s: empty log @ %p\n",
  191. cmdName,
  192. (PVOID)refLogAddress
  193. );
  194. return;
  195. }
  196. //
  197. // Calculate the starting address and number of entries.
  198. //
  199. if( fReverse ) {
  200. if( logHeader.NextEntry < logHeader.LogSize ) {
  201. numEntries = logHeader.NextEntry + 1;
  202. index = logHeader.NextEntry;
  203. } else {
  204. numEntries = logHeader.LogSize;
  205. index = logHeader.NextEntry % logHeader.LogSize;
  206. }
  207. } else {
  208. if( logHeader.NextEntry < logHeader.LogSize ) {
  209. numEntries = logHeader.NextEntry + 1;
  210. index = 0;
  211. } else {
  212. numEntries = logHeader.LogSize;
  213. index = ( logHeader.NextEntry + 1 ) % logHeader.LogSize;
  214. }
  215. }
  216. entryAddress = (ULONG_PTR)logHeader.LogBuffer + (ULONG_PTR)( index * sizeof(logEntry) );
  217. if( entryAddress >=
  218. ( (ULONG_PTR)logHeader.LogBuffer + (ULONG_PTR)( numEntries * sizeof(logEntry) ) ) ) {
  219. dprintf(
  220. "inetdbg.%s: log @ %p has invalid data\n",
  221. cmdName,
  222. (PVOID)refLogAddress
  223. );
  224. return;
  225. }
  226. //
  227. // Dump the log.
  228. //
  229. for( ;
  230. numEntries > 0 ;
  231. index += direction,
  232. numEntries--,
  233. entryAddress += ( direction * sizeof(logEntry) ) ) {
  234. if( CheckControlC() ) {
  235. break;
  236. }
  237. if( index >= logHeader.LogSize ) {
  238. index = 0;
  239. entryAddress = (ULONG_PTR)logHeader.LogBuffer;
  240. } else if( index < 0 ) {
  241. index = logHeader.LogSize - 1;
  242. entryAddress = (ULONG_PTR)logHeader.LogBuffer + (ULONG_PTR)( index * sizeof(logEntry) );
  243. }
  244. if( !ReadMemory(
  245. entryAddress,
  246. &logEntry,
  247. sizeof(logEntry),
  248. NULL
  249. ) ) {
  250. dprintf(
  251. "inetdbg.%s: cannot read memory @ %p\n",
  252. cmdName,
  253. (ULONG_PTR)entryAddress
  254. );
  255. return;
  256. }
  257. if( ( numSpecificContexts == 0 ) ||
  258. IsContextInList(
  259. logEntry.Context,
  260. specificContexts,
  261. numSpecificContexts
  262. ) ) {
  263. dprintf(
  264. "\nThread = %08p, Context = %08p, NewRefCount = %-10ld : %ld\n",
  265. logEntry.Thread,
  266. logEntry.Context,
  267. logEntry.NewRefCount,
  268. index
  269. );
  270. if ( logEntry.Context1 != REF_TRACE_EMPTY_CONTEXT
  271. || logEntry.Context2 != REF_TRACE_EMPTY_CONTEXT
  272. || logEntry.Context3 != REF_TRACE_EMPTY_CONTEXT
  273. ) {
  274. //
  275. // if the caller passed extended context values,
  276. // write them to the log
  277. //
  278. // NOTE we use REF_TRACE_EMPTY_CONTEXT in all extended
  279. // contexts as the signal that a caller does not use
  280. // extended context - avoids spew for callers who don't care.
  281. //
  282. dprintf(
  283. "Context1 = %08p, Context2 = %08p, Context3 = %08p\n",
  284. logEntry.Context1,
  285. logEntry.Context2,
  286. logEntry.Context3
  287. );
  288. }
  289. for( i = 0 ; i < REF_TRACE_LOG_STACK_DEPTH ; i++ ) {
  290. if( logEntry.Stack[i] == NULL ) {
  291. break;
  292. }
  293. GetSymbol(
  294. (ULONG_PTR) logEntry.Stack[i],
  295. symbol,
  296. &offset
  297. );
  298. if( symbol[0] == '\0' ) {
  299. format = " %08p\n";
  300. } else
  301. if( offset == 0 ) {
  302. format = " %08p : %s\n";
  303. } else {
  304. format = " %08p : %s+0x%lx\n";
  305. }
  306. dprintf(
  307. format,
  308. logEntry.Stack[i],
  309. symbol,
  310. offset
  311. );
  312. }
  313. }
  314. }
  315. } // DumpReferenceLog
  316. DECLARE_API( ref )
  317. /*++
  318. Routine Description:
  319. This function is called as an NTSD extension to format and dump
  320. a reference trace log.
  321. Arguments:
  322. hCurrentProcess - Supplies a handle to the current process (at the
  323. time the extension was called).
  324. hCurrentThread - Supplies a handle to the current thread (at the
  325. time the extension was called).
  326. CurrentPc - Supplies the current pc at the time the extension is
  327. called.
  328. lpExtensionApis - Supplies the address of the functions callable
  329. by this extension.
  330. lpArgumentString - Supplies the asciiz string that describes the
  331. ansi string to be dumped.
  332. Return Value:
  333. None.
  334. --*/
  335. {
  336. INIT_API();
  337. DumpReferenceLog( lpArgumentString, FALSE );
  338. } // DECLARE_API( ref )
  339. DECLARE_API( rref )
  340. /*++
  341. Routine Description:
  342. This function is called as an NTSD extension to format and dump
  343. a reference trace log backwards.
  344. Arguments:
  345. hCurrentProcess - Supplies a handle to the current process (at the
  346. time the extension was called).
  347. hCurrentThread - Supplies a handle to the current thread (at the
  348. time the extension was called).
  349. CurrentPc - Supplies the current pc at the time the extension is
  350. called.
  351. lpExtensionApis - Supplies the address of the functions callable
  352. by this extension.
  353. lpArgumentString - Supplies the asciiz string that describes the
  354. ansi string to be dumped.
  355. Return Value:
  356. None.
  357. --*/
  358. {
  359. INIT_API();
  360. DumpReferenceLog( lpArgumentString, TRUE );
  361. } // DECLARE_API( rref )
  362. DECLARE_API( resetref )
  363. /*++
  364. Routine Description:
  365. This function is called as an NTSD extension to reset a reference
  366. trace log back to its initial state.
  367. Arguments:
  368. hCurrentProcess - Supplies a handle to the current process (at the
  369. time the extension was called).
  370. hCurrentThread - Supplies a handle to the current thread (at the
  371. time the extension was called).
  372. CurrentPc - Supplies the current pc at the time the extension is
  373. called.
  374. lpExtensionApis - Supplies the address of the functions callable
  375. by this extension.
  376. lpArgumentString - Supplies the asciiz string that describes the
  377. ansi string to be dumped.
  378. Return Value:
  379. None.
  380. --*/
  381. {
  382. ULONG_PTR refLogAddress = 0;
  383. TRACE_LOG logHeader;
  384. INIT_API();
  385. //
  386. // Skip leading blanks.
  387. //
  388. while( *lpArgumentString == ' ' ||
  389. *lpArgumentString == '\t' ) {
  390. lpArgumentString++;
  391. }
  392. if( *lpArgumentString == '\0' ) {
  393. PrintUsage( "resetref" );
  394. return;
  395. }
  396. refLogAddress = GetExpression( lpArgumentString );
  397. if( refLogAddress == 0 ) {
  398. dprintf(
  399. "inetdbg.resetref: cannot evaluate \"%s\"\n",
  400. lpArgumentString
  401. );
  402. return;
  403. }
  404. //
  405. // Read the log header, perform some sanity checks.
  406. //
  407. if( !ReadMemory(
  408. refLogAddress,
  409. &logHeader,
  410. sizeof(logHeader),
  411. NULL
  412. ) ) {
  413. dprintf(
  414. "inetdbg.resetref: cannot read memory @ %p\n",
  415. refLogAddress
  416. );
  417. return;
  418. }
  419. dprintf(
  420. "inetdbg.resetref: log @ %p:\n"
  421. " Signature = %08lx (%s)\n"
  422. " LogSize = %lu\n"
  423. " NextEntry = %lu\n"
  424. " EntrySize = %lu\n"
  425. " LogBuffer = %08lp\n",
  426. (PVOID) refLogAddress,
  427. logHeader.Signature,
  428. logHeader.Signature == TRACE_LOG_SIGNATURE
  429. ? "OK"
  430. : logHeader.Signature == TRACE_LOG_SIGNATURE_X
  431. ? "FREED"
  432. : "INVALID",
  433. logHeader.LogSize,
  434. logHeader.NextEntry,
  435. logHeader.EntrySize,
  436. logHeader.LogBuffer
  437. );
  438. if( logHeader.LogBuffer > ( (PUCHAR)refLogAddress + sizeof(logHeader) ) ) {
  439. dprintf(
  440. " Extra Data @ %08p\n",
  441. (PVOID) (refLogAddress + sizeof(logHeader))
  442. );
  443. }
  444. if( logHeader.Signature != TRACE_LOG_SIGNATURE &&
  445. logHeader.Signature != TRACE_LOG_SIGNATURE_X ) {
  446. dprintf(
  447. "inetdbg.resetref: log @ %p has invalid signature %08lx:\n",
  448. (PVOID) refLogAddress,
  449. logHeader.Signature
  450. );
  451. return;
  452. }
  453. if( logHeader.EntrySize != sizeof(REF_TRACE_LOG_ENTRY) ) {
  454. dprintf(
  455. "inetdbg.resetref: log @ %p is not a ref count log\n",
  456. (PVOID) refLogAddress
  457. );
  458. return;
  459. }
  460. //
  461. // Reset it.
  462. //
  463. logHeader.NextEntry = -1;
  464. if( !WriteMemory(
  465. refLogAddress,
  466. &logHeader,
  467. sizeof(logHeader),
  468. NULL
  469. ) ) {
  470. dprintf(
  471. "inetdbg.resetref: cannot write memory @ %p\n",
  472. (PVOID) refLogAddress
  473. );
  474. return;
  475. }
  476. dprintf(
  477. "inetdbg.resetref: log @ %p reset\n",
  478. (PVOID) refLogAddress
  479. );
  480. } // DECLARE_API( resetref )