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.

447 lines
9.5 KiB

  1. /*++
  2. Copyright (c) 1998-2001 Microsoft Corporation
  3. Module Name:
  4. ref.c
  5. Abstract:
  6. Implements the ref command.
  7. Author:
  8. Keith Moore (keithmo) 17-Jun-1998
  9. Environment:
  10. User Mode.
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #undef BEGIN_REF_ACTION
  15. #undef END_REF_ACTION
  16. #undef REF_ACTION
  17. #define BEGIN_REF_ACTION() NAMED_REFTRACE_ACTION g_RefTraceActions[] = {
  18. #define END_REF_ACTION() };
  19. #define REF_ACTION(x) { REF_ACTION_##x, #x },
  20. #include "..\drv\refaction.h"
  21. #define NUM_REFTRACE_ACTIONS \
  22. (sizeof(g_RefTraceActions) / sizeof(g_RefTraceActions[0]))
  23. const CHAR*
  24. Action2Name(
  25. ULONG Action)
  26. {
  27. if (Action < NUM_REFTRACE_ACTIONS)
  28. {
  29. ASSERT(g_RefTraceActions[Action].Action == Action);
  30. return g_RefTraceActions[Action].Name;
  31. }
  32. else
  33. return "????";
  34. }
  35. typedef
  36. BOOLEAN
  37. (*FN_MATCH_CONTEXT)(
  38. IN ULONG_PTR context,
  39. IN PREF_TRACE_LOG_ENTRY plogEntry
  40. );
  41. BOOLEAN
  42. RefMatchContext(
  43. IN ULONG_PTR context,
  44. IN PREF_TRACE_LOG_ENTRY plogEntry)
  45. {
  46. return (context == 0 || context == (ULONG_PTR) plogEntry->pContext);
  47. }
  48. BOOLEAN
  49. ThreadMatchContext(
  50. IN ULONG_PTR context,
  51. IN PREF_TRACE_LOG_ENTRY plogEntry)
  52. {
  53. return (context == 0 || context == (ULONG_PTR) plogEntry->pThread);
  54. }
  55. // Do all the real
  56. VOID
  57. DumpRefTrace(
  58. PCSTR args,
  59. FN_MATCH_CONTEXT pfnMatchContext,
  60. PCSTR cmd)
  61. {
  62. ULONG_PTR address = 0;
  63. ULONG_PTR context = 0;
  64. ULONG_PTR flags = 0;
  65. ULONG_PTR entryAddress;
  66. ULONG result;
  67. TRACE_LOG logHeader;
  68. REF_TRACE_LOG_ENTRY logEntry;
  69. PSTR fileName;
  70. LONGLONG index;
  71. ULONGLONG index2;
  72. ULONGLONG index1000;
  73. ULONG_PTR offset1;
  74. ULONG_PTR offset2;
  75. CHAR filePath[MAX_PATH];
  76. PVOID pPrevFilePath;
  77. CHAR symbol1[MAX_SYMBOL_LENGTH];
  78. CHAR symbol2[MAX_SYMBOL_LENGTH];
  79. ULONG Dumped = 0;
  80. ULONG NonMatch = 0;
  81. ULONG64 address64 = 0;
  82. ULONG64 context64 = 0;
  83. ULONG64 flags64 = 0;
  84. ULONG NumToDump = 0;
  85. while (*args == ' ' || *args == '\t')
  86. {
  87. args++;
  88. }
  89. if (*args == '-')
  90. {
  91. args++;
  92. switch (*args)
  93. {
  94. case 'l' :
  95. for (index = 0; index < NUM_REFTRACE_ACTIONS; ++index)
  96. {
  97. dprintf(
  98. "%4u: REF_ACTION_%s\n",
  99. g_RefTraceActions[index].Action,
  100. g_RefTraceActions[index].Name);
  101. }
  102. return;
  103. default :
  104. PrintUsage( cmd );
  105. return;
  106. }
  107. }
  108. //
  109. // Snag the address and optional context and flags from the command line.
  110. //
  111. if (! GetExpressionEx(args, &address64, &args))
  112. {
  113. PrintUsage( cmd );
  114. return;
  115. }
  116. if (GetExpressionEx(args, &context64, &args))
  117. GetExpressionEx(args, &flags64, &args);
  118. address = (ULONG_PTR) address64;
  119. context = (ULONG_PTR) context64;
  120. flags = (ULONG_PTR) flags64;
  121. //
  122. // Read the log header.
  123. //
  124. if (!ReadMemory(
  125. address,
  126. &logHeader,
  127. sizeof(logHeader),
  128. &result
  129. ))
  130. {
  131. dprintf(
  132. "%s: cannot read TRACE_LOG @ %p\n",
  133. cmd,
  134. address
  135. );
  136. return;
  137. }
  138. dprintf(
  139. "%s: log @ %p\n"
  140. " Signature = %08lx '%c%c%c%c' (%s)\n"
  141. " TypeSignature = %08lx '%c%c%c%c'\n"
  142. " LogSize = %lu\n"
  143. " NextEntry = %I64d\n"
  144. " EntrySize = %lu\n"
  145. " LogBuffer = %p\n",
  146. cmd,
  147. address,
  148. logHeader.Signature,
  149. DECODE_SIGNATURE(logHeader.Signature),
  150. logHeader.Signature == TRACE_LOG_SIGNATURE
  151. ? "OK"
  152. : logHeader.Signature == TRACE_LOG_SIGNATURE_X
  153. ? "FREED"
  154. : "INVALID",
  155. logHeader.TypeSignature,
  156. DECODE_SIGNATURE(logHeader.TypeSignature),
  157. logHeader.LogSize,
  158. logHeader.NextEntry,
  159. logHeader.EntrySize,
  160. logHeader.pLogBuffer
  161. );
  162. if (logHeader.pLogBuffer > ( (PUCHAR)address + sizeof(logHeader) ))
  163. {
  164. dprintf(
  165. " ExtraData @ %p\n",
  166. address + sizeof(logHeader)
  167. );
  168. }
  169. if (logHeader.Signature != TRACE_LOG_SIGNATURE &&
  170. logHeader.Signature != TRACE_LOG_SIGNATURE_X)
  171. {
  172. dprintf(
  173. "%s: log @ %p has invalid signature %08lx:\n",
  174. cmd,
  175. address,
  176. logHeader.Signature
  177. );
  178. return;
  179. }
  180. if (logHeader.EntrySize != sizeof(logEntry)
  181. || logHeader.TypeSignature != REF_TRACELOG_SIGNATURE
  182. )
  183. {
  184. dprintf(
  185. "%s: log @ %p is not a ref count log\n",
  186. cmd,
  187. address
  188. );
  189. return;
  190. }
  191. if (logHeader.NextEntry == -1)
  192. {
  193. dprintf(
  194. "%s: empty log @ %p\n",
  195. cmd,
  196. address
  197. );
  198. return;
  199. }
  200. //
  201. // Calculate the log size to dump.
  202. //
  203. NumToDump = logHeader.LogSize;
  204. index = max( 0, (logHeader.NextEntry + 1) - NumToDump );
  205. index2 = index % logHeader.LogSize;
  206. index1000 = index % 1000;
  207. pPrevFilePath = NULL;
  208. *filePath = '\0';
  209. entryAddress = (ULONG_PTR) logHeader.pLogBuffer +
  210. (ULONG_PTR)( index2 * sizeof(logEntry) );
  211. //
  212. // Dump the log.
  213. //
  214. for ( ;
  215. index <= logHeader.NextEntry;
  216. index++,
  217. index2++,
  218. index1000++,
  219. entryAddress += sizeof(logEntry)
  220. )
  221. {
  222. if (CheckControlC())
  223. {
  224. break;
  225. }
  226. if (index2 >= (ULONG)(logHeader.LogSize))
  227. {
  228. index2 = 0;
  229. entryAddress = (ULONG_PTR) logHeader.pLogBuffer;
  230. }
  231. if (index1000 >= 1000)
  232. index1000 = 0;
  233. if (!ReadMemory(
  234. entryAddress,
  235. &logEntry,
  236. sizeof(logEntry),
  237. NULL
  238. ))
  239. {
  240. dprintf(
  241. "%s: cannot read memory @ %p\n",
  242. cmd,
  243. entryAddress
  244. );
  245. return;
  246. }
  247. if ((*pfnMatchContext)(context, &logEntry))
  248. {
  249. if (logEntry.pFileName != pPrevFilePath)
  250. {
  251. if (ReadMemory(
  252. (ULONG_PTR)logEntry.pFileName,
  253. filePath,
  254. sizeof(filePath),
  255. &result
  256. ))
  257. {
  258. fileName = strrchr( filePath, '\\' );
  259. if (fileName != NULL)
  260. {
  261. fileName++;
  262. }
  263. else
  264. {
  265. fileName = filePath;
  266. }
  267. pPrevFilePath = logEntry.pFileName;
  268. }
  269. else
  270. {
  271. sprintf(
  272. filePath,
  273. "%p",
  274. logEntry.pFileName
  275. );
  276. fileName = filePath;
  277. }
  278. }
  279. dprintf(
  280. "%s%4I64d: CPU=%lu Ctx=%p Act=%2lu %-30s Ref=%4d Src=%s:%lu\n",
  281. (NonMatch > 0) ? "\n" : "",
  282. index,
  283. (ULONG)logEntry.Processor,
  284. logEntry.pContext,
  285. (ULONG)logEntry.Action,
  286. Action2Name(logEntry.Action),
  287. logEntry.NewRefCount,
  288. fileName,
  289. (ULONG)logEntry.LineNumber
  290. );
  291. if (flags & 1)
  292. {
  293. GetSymbol(
  294. logEntry.pCaller,
  295. symbol1,
  296. &offset1
  297. );
  298. GetSymbol(
  299. logEntry.pCallersCaller,
  300. symbol2,
  301. &offset2
  302. );
  303. dprintf(
  304. " Process=%p Thread=%p\n"
  305. " Caller1=%p (%s+0x%p)\n"
  306. " Caller2=%p (%s+0x%p)\n",
  307. logEntry.pProcess,
  308. logEntry.pThread,
  309. logEntry.pCaller,
  310. symbol1,
  311. offset1,
  312. logEntry.pCallersCaller,
  313. symbol2,
  314. offset2
  315. );
  316. }
  317. ++Dumped;
  318. NonMatch = 0;
  319. }
  320. else
  321. {
  322. if (index1000 == 0)
  323. dprintf("%I64d", index);
  324. if ((++NonMatch & 127) == 127)
  325. dprintf(".");
  326. }
  327. }
  328. if (context != 0)
  329. dprintf("%d entries dumped\n\n", Dumped);
  330. } // DumpRefTrace
  331. //
  332. // Public functions.
  333. //
  334. DECLARE_API( ref )
  335. /*++
  336. Routine Description:
  337. Dumps the reference trace log at the specified address.
  338. Arguments:
  339. None.
  340. Return Value:
  341. None.
  342. --*/
  343. {
  344. SNAPSHOT_EXTENSION_DATA();
  345. DumpRefTrace(args, RefMatchContext, "ref");
  346. } // ref
  347. DECLARE_API( tref )
  348. /*++
  349. Routine Description:
  350. Dumps the trace log at the specified address.
  351. Filtering done by thread instead of context.
  352. Arguments:
  353. None.
  354. Return Value:
  355. None.
  356. --*/
  357. {
  358. SNAPSHOT_EXTENSION_DATA();
  359. DumpRefTrace(args, ThreadMatchContext, "tref");
  360. } // ref