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.

634 lines
14 KiB

  1. /*++
  2. Copyright (c) 2001-2001 Microsoft Corporation
  3. Module Name:
  4. ownref.c
  5. Abstract:
  6. Implements the ownref command.
  7. Author:
  8. George V. Reilly (GeorgeRe) 23-Jan-2001
  9. Environment:
  10. User Mode.
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. typedef struct _REF_OWNER_GLOBAL_CALLBACK_CONTEXT
  15. {
  16. ULONG Signature;
  17. LONG Index;
  18. BOOLEAN Verbose;
  19. PSTR Prefix;
  20. } REF_OWNER_GLOBAL_CALLBACK_CONTEXT, *PREF_OWNER_GLOBAL_CALLBACK_CONTEXT;
  21. #define REF_OWNER_GLOBAL_CALLBACK_CONTEXT_SIGNATURE ((ULONG) 'xGOR')
  22. BOOLEAN
  23. DumpOwnerRefTraceLog(
  24. IN PLIST_ENTRY RemoteListEntry,
  25. IN PVOID Context
  26. )
  27. {
  28. ULONG_PTR address;
  29. ULONG result;
  30. OWNER_REF_TRACELOG logHeader;
  31. PREF_OWNER_GLOBAL_CALLBACK_CONTEXT pCtxt
  32. = (PREF_OWNER_GLOBAL_CALLBACK_CONTEXT) Context;
  33. ASSERT(pCtxt->Signature == REF_OWNER_GLOBAL_CALLBACK_CONTEXT_SIGNATURE);
  34. address = (ULONG_PTR) CONTAINING_RECORD(
  35. RemoteListEntry,
  36. OWNER_REF_TRACELOG,
  37. OwnerHeader.GlobalListEntry
  38. );
  39. if (!ReadMemory(
  40. address,
  41. &logHeader,
  42. sizeof(logHeader),
  43. &result
  44. ))
  45. {
  46. return FALSE;
  47. }
  48. dprintf("OWNER_REF_TRACELOG[%d] @ %p\n", ++pCtxt->Index, address);
  49. return TRUE;
  50. } // DumpOwnerRefTraceLog
  51. #if 0
  52. VOID
  53. DumpOwnerRefTraceLogGlobalList(
  54. IN BOOLEAN Verbose
  55. )
  56. {
  57. REF_OWNER_GLOBAL_CALLBACK_CONTEXT Context;
  58. Context.Signature = REF_OWNER_GLOBAL_CALLBACK_CONTEXT_SIGNATURE ;
  59. Context.Verbose = Verbose;
  60. Context.Prefix = "";
  61. Context.Index = 0;
  62. "&http!g_OwnerRefTraceLogGlobalListHead"
  63. dprintf(
  64. "\n"
  65. " OWNER_REF_TRACELOG @ %p: %d owners\n",
  66. RemoteAddress,
  67. plogHeader->OwnerHeader.OwnersCount
  68. );
  69. EnumLinkedList(
  70. (PLIST_ENTRY)REMOTE_OFFSET(
  71. RemoteAddress,
  72. OWNER_REF_TRACELOG,
  73. OwnerHeader.ListHead
  74. ),
  75. &DumpOwnerRefTraceLogOwnerCallback,
  76. &Context
  77. );
  78. } // DumpOwnerRefTraceLogGlobalList
  79. #endif
  80. typedef struct _REF_OWNER_CALLBACK_CONTEXT
  81. {
  82. ULONG Signature;
  83. LONG Index;
  84. BOOLEAN Verbose;
  85. PSTR Prefix;
  86. LONG TotalRefs;
  87. } REF_OWNER_CALLBACK_CONTEXT, *PREF_OWNER_CALLBACK_CONTEXT;
  88. #define REF_OWNER_CALLBACK_CONTEXT_SIGNATURE ((ULONG) 'xCOR')
  89. BOOLEAN
  90. DumpOwnerRefTraceLogOwner(
  91. IN ULONG_PTR address,
  92. IN PREF_OWNER_CALLBACK_CONTEXT pCtxt
  93. )
  94. {
  95. ULONG result;
  96. REF_OWNER RefOwner;
  97. LONG index;
  98. ULONG index2;
  99. ASSERT(pCtxt->Signature == REF_OWNER_CALLBACK_CONTEXT_SIGNATURE);
  100. if (!ReadMemory(
  101. address,
  102. &RefOwner,
  103. sizeof(RefOwner),
  104. &result
  105. ))
  106. {
  107. return FALSE;
  108. }
  109. if (RefOwner.Signature != OWNER_REF_SIGNATURE)
  110. {
  111. dprintf(
  112. "Invalid REF_OWNER @ %p: signature = '%c%c%c%c'\n",
  113. address,
  114. DECODE_SIGNATURE(RefOwner.Signature)
  115. );
  116. return FALSE;
  117. }
  118. pCtxt->TotalRefs += RefOwner.RelativeRefCount;
  119. dprintf(
  120. "%s\tREF_OWNER[%3d] @ %p:"
  121. " pOwner=%p '%c%c%c%c',"
  122. " RelativeRefCount=%d,"
  123. " OwnedNextEntry=%d.\n"
  124. ,
  125. pCtxt->Verbose ? "\n" : "",
  126. pCtxt->Index++,
  127. address,
  128. RefOwner.pOwner,
  129. DECODE_SIGNATURE(RefOwner.OwnerSignature),
  130. RefOwner.RelativeRefCount,
  131. RefOwner.OwnedNextEntry
  132. );
  133. if (RefOwner.OwnedNextEntry == -1 || !pCtxt->Verbose)
  134. return TRUE;
  135. index = max( 0, (RefOwner.OwnedNextEntry + 1) - OWNED_REF_NUM_ENTRIES );
  136. index2 = index % OWNED_REF_NUM_ENTRIES;
  137. for ( ;
  138. index <= RefOwner.OwnedNextEntry;
  139. index++, index2++
  140. )
  141. {
  142. if (CheckControlC())
  143. {
  144. break;
  145. }
  146. if (index2 >= OWNED_REF_NUM_ENTRIES)
  147. index2 = 0;
  148. dprintf(
  149. "\t\t%8ld: RefIndex=%6I64d, MonotonicId=%ld, Act=%s\n",
  150. index,
  151. RefOwner.RecentEntries[index2].RefIndex,
  152. RefOwner.RecentEntries[index2].MonotonicId,
  153. Action2Name(RefOwner.RecentEntries[index2].Action)
  154. );
  155. }
  156. return TRUE;
  157. } // DumpOwnerRefTraceLogOwner
  158. BOOLEAN
  159. DumpOwnerRefTraceLogOwnerCallback(
  160. IN PLIST_ENTRY RemoteListEntry,
  161. IN PVOID Context
  162. )
  163. {
  164. ULONG_PTR address = (ULONG_PTR) CONTAINING_RECORD(
  165. RemoteListEntry,
  166. REF_OWNER,
  167. ListEntry
  168. );
  169. PREF_OWNER_CALLBACK_CONTEXT pCtxt = (PREF_OWNER_CALLBACK_CONTEXT) Context;
  170. return DumpOwnerRefTraceLogOwner(address, pCtxt);
  171. } // DumpOwnerRefTraceLogOwnerCallback
  172. VOID
  173. DumpOwnerRefTraceLogOwnersList(
  174. IN POWNER_REF_TRACELOG plogHeader,
  175. IN ULONG_PTR RemoteAddress,
  176. IN BOOLEAN Verbose
  177. )
  178. {
  179. REF_OWNER_CALLBACK_CONTEXT Context;
  180. Context.Signature = REF_OWNER_CALLBACK_CONTEXT_SIGNATURE ;
  181. Context.Verbose = Verbose;
  182. Context.Prefix = "";
  183. Context.Index = 0;
  184. Context.TotalRefs = 0;
  185. dprintf(
  186. "\n"
  187. " OWNER_REF_TRACELOG @ %p: %d owners\n",
  188. RemoteAddress,
  189. plogHeader->OwnerHeader.OwnersCount
  190. );
  191. EnumLinkedList(
  192. (PLIST_ENTRY) REMOTE_OFFSET(
  193. RemoteAddress,
  194. OWNER_REF_TRACELOG,
  195. OwnerHeader.ListHead
  196. ),
  197. &DumpOwnerRefTraceLogOwnerCallback,
  198. &Context
  199. );
  200. dprintf("\nTotal RefCount = %d\n\n", Context.TotalRefs);
  201. } // DumpOwnerRefTraceLogOwnersList
  202. VOID
  203. DumpOwnerRefTraceLogData(
  204. IN POWNER_REF_TRACELOG plogHeader,
  205. IN ULONG_PTR RemoteAddress,
  206. IN BOOLEAN Verbose,
  207. IN ULONG_PTR context
  208. )
  209. {
  210. OWNER_REF_TRACE_LOG_ENTRY logEntry;
  211. ULONG_PTR entryAddress;
  212. CHAR filePath[MAX_PATH];
  213. PSTR fileName;
  214. PVOID pPrevFilePath;
  215. CHAR symbol1[MAX_SYMBOL_LENGTH];
  216. CHAR symbol2[MAX_SYMBOL_LENGTH];
  217. ULONG result;
  218. ULONG Dumped = 0;
  219. ULONG NonMatch = 0;
  220. ULONG NumToDump = plogHeader->TraceLog.LogSize;
  221. LONGLONG index = max( 0, ((plogHeader->TraceLog.NextEntry + 1)
  222. - NumToDump) );
  223. ULONGLONG index2 = index % plogHeader->TraceLog.LogSize;
  224. ULONGLONG index1000 = index % 1000;
  225. entryAddress = (ULONG_PTR) plogHeader->TraceLog.pLogBuffer +
  226. (ULONG_PTR)( index2 * sizeof(logEntry) );
  227. pPrevFilePath = NULL;
  228. *filePath = '\0';
  229. //
  230. // Dump the log.
  231. //
  232. dprintf(
  233. "\n"
  234. " OWNER_REF_TRACELOG @ %p: dumping entries[%I64d-%I64d]",
  235. RemoteAddress,
  236. index,
  237. plogHeader->TraceLog.NextEntry
  238. );
  239. if (context != 0)
  240. dprintf(", filtering on owner=%p", context);
  241. dprintf("\n");
  242. for ( ;
  243. index <= plogHeader->TraceLog.NextEntry;
  244. index++,
  245. index2++,
  246. index1000++,
  247. entryAddress += sizeof(logEntry)
  248. )
  249. {
  250. if (CheckControlC())
  251. {
  252. break;
  253. }
  254. if (index2 >= (ULONG)(plogHeader->TraceLog.LogSize))
  255. {
  256. index2 = 0;
  257. entryAddress = (ULONG_PTR) plogHeader->TraceLog.pLogBuffer;
  258. }
  259. if (index1000 >= 1000)
  260. index1000 = 0;
  261. if (!ReadMemory(
  262. entryAddress,
  263. &logEntry,
  264. sizeof(logEntry),
  265. NULL
  266. ))
  267. {
  268. dprintf(
  269. "ownref: cannot read memory @ %p\n",
  270. entryAddress
  271. );
  272. return;
  273. }
  274. if (context == 0 || context == (ULONG_PTR)logEntry.pOwner)
  275. {
  276. if (logEntry.pFileName != pPrevFilePath)
  277. {
  278. if (ReadMemory(
  279. (ULONG_PTR)logEntry.pFileName,
  280. filePath,
  281. sizeof(filePath),
  282. &result
  283. ))
  284. {
  285. fileName = strrchr( filePath, '\\' );
  286. if (fileName != NULL)
  287. {
  288. fileName++;
  289. }
  290. else
  291. {
  292. fileName = filePath;
  293. }
  294. pPrevFilePath = logEntry.pFileName;
  295. }
  296. else
  297. {
  298. sprintf(
  299. filePath,
  300. "%p",
  301. logEntry.pFileName
  302. );
  303. fileName = filePath;
  304. }
  305. }
  306. dprintf(
  307. "%s%4I64d: Own=%p Act=%2lu %-30s Ref=%4d Src=%s:%lu\n",
  308. (NonMatch > 0) ? "\n" : "",
  309. index,
  310. logEntry.pOwner,
  311. (ULONG)logEntry.Action,
  312. Action2Name(logEntry.Action),
  313. logEntry.NewRefCount,
  314. fileName,
  315. (ULONG)logEntry.LineNumber
  316. );
  317. ++Dumped;
  318. NonMatch = 0;
  319. }
  320. else
  321. {
  322. if (index1000 == 0)
  323. dprintf("%d", index);
  324. if ((++NonMatch & 127) == 127)
  325. dprintf(".");
  326. }
  327. }
  328. if (context != 0)
  329. dprintf("%d entries dumped\n\n", Dumped);
  330. } // DumpOwnerRefTraceLogData
  331. //
  332. // Public functions.
  333. //
  334. DECLARE_API( ownref )
  335. /*++
  336. Routine Description:
  337. Dumps the owner reference trace log at the specified address.
  338. Arguments:
  339. None.
  340. Return Value:
  341. None.
  342. --*/
  343. {
  344. ULONG_PTR address = 0;
  345. ULONG_PTR context = 0;
  346. ULONG64 address64 = 0, context64 = 0;
  347. ULONG result;
  348. OWNER_REF_TRACELOG logHeader;
  349. CHAR strSignature[MAX_SIGNATURE_LENGTH];
  350. BOOLEAN ListGlobal = FALSE; // CODEWORK
  351. BOOLEAN ListAllOwners = FALSE;
  352. BOOLEAN ListOneOwner = FALSE;
  353. BOOLEAN ListRefs = FALSE;
  354. BOOLEAN Verbose = FALSE;
  355. SNAPSHOT_EXTENSION_DATA();
  356. // Parse any leading flags
  357. while (*args == ' ' || *args == '\t')
  358. {
  359. args++;
  360. }
  361. if (*args == '-')
  362. {
  363. args++;
  364. switch (*args)
  365. {
  366. case 'g' :
  367. ListGlobal = TRUE;
  368. args++;
  369. break;
  370. case 'O' :
  371. ListAllOwners = TRUE;
  372. args++;
  373. break;
  374. case 'o' :
  375. ListOneOwner = TRUE;
  376. args++;
  377. break;
  378. case 'r' :
  379. ListRefs = TRUE;
  380. args++;
  381. break;
  382. case 'v' :
  383. Verbose = TRUE;
  384. args++;
  385. break;
  386. default :
  387. PrintUsage( "ownref" );
  388. return;
  389. }
  390. }
  391. while (*args == ' ' || *args == '\t')
  392. {
  393. args++;
  394. }
  395. //
  396. // Snag the address and optional context from the command line.
  397. //
  398. if (! GetExpressionEx(args, &address64, &args))
  399. {
  400. PrintUsage( "ownref" );
  401. return;
  402. }
  403. GetExpressionEx(args, &context64, &args);
  404. address = (ULONG_PTR) address64;
  405. context = (ULONG_PTR) context64;
  406. //
  407. // Read the log header.
  408. //
  409. if (!ReadMemory(
  410. address,
  411. &logHeader,
  412. sizeof(logHeader),
  413. &result
  414. ))
  415. {
  416. dprintf(
  417. "ownref: cannot read OWNER_REF_TRACELOG @ %p\n",
  418. address
  419. );
  420. return;
  421. }
  422. if (ListGlobal)
  423. {
  424. dprintf("Sorry, -g option not yet implemented.\n"
  425. "Use: dl http!g_OwnerRefTraceLogGlobalListHead\n");
  426. }
  427. if (ListOneOwner)
  428. {
  429. REF_OWNER_CALLBACK_CONTEXT Context;
  430. Context.Signature = REF_OWNER_CALLBACK_CONTEXT_SIGNATURE ;
  431. Context.Verbose = TRUE;
  432. Context.Prefix = "";
  433. Context.Index = -1;
  434. Context.TotalRefs = 0;
  435. DumpOwnerRefTraceLogOwner(address, &Context);
  436. return;
  437. }
  438. dprintf(
  439. "ownref: log @ %p\n"
  440. " Signature = %08lx '%c%c%c%c' (%s)\n"
  441. " TypeSignature = %08lx (%s)\n"
  442. " LogSize = %lu\n"
  443. " NextEntry = %I64d\n"
  444. " EntrySize = %lu\n"
  445. " LogBuffer = %p\n"
  446. " OwnersCount = %d\n"
  447. " MonotonicId = %d\n",
  448. address,
  449. logHeader.TraceLog.Signature,
  450. DECODE_SIGNATURE(logHeader.TraceLog.Signature),
  451. logHeader.TraceLog.Signature == TRACE_LOG_SIGNATURE
  452. ? "OK"
  453. : logHeader.TraceLog.Signature == TRACE_LOG_SIGNATURE_X
  454. ? "FREED"
  455. : "INVALID",
  456. logHeader.TraceLog.TypeSignature,
  457. SignatureToString(
  458. logHeader.TraceLog.TypeSignature,
  459. OWNER_REF_TRACELOG_SIGNATURE,
  460. 0,
  461. strSignature
  462. ),
  463. logHeader.TraceLog.LogSize,
  464. logHeader.TraceLog.NextEntry,
  465. logHeader.TraceLog.EntrySize,
  466. logHeader.TraceLog.pLogBuffer,
  467. logHeader.OwnerHeader.OwnersCount,
  468. logHeader.OwnerHeader.MonotonicId
  469. );
  470. if (logHeader.TraceLog.pLogBuffer > ( (PUCHAR)address + sizeof(logHeader)))
  471. {
  472. dprintf(
  473. " ExtraData @ %p\n",
  474. address + sizeof(logHeader)
  475. );
  476. }
  477. if (logHeader.TraceLog.TypeSignature != OWNER_REF_TRACELOG_SIGNATURE)
  478. {
  479. dprintf(
  480. "ownref: log @ %p has invalid signature %08lx, '%c%c%c%c':\n",
  481. address,
  482. logHeader.TraceLog.TypeSignature,
  483. DECODE_SIGNATURE(logHeader.TraceLog.TypeSignature)
  484. );
  485. return;
  486. }
  487. if (logHeader.TraceLog.EntrySize != sizeof(OWNER_REF_TRACE_LOG_ENTRY)
  488. || logHeader.TraceLog.TypeSignature != OWNER_REF_TRACELOG_SIGNATURE)
  489. {
  490. dprintf(
  491. "ownref: log @ %p is not an owner ref count log\n",
  492. address
  493. );
  494. return;
  495. }
  496. if (logHeader.TraceLog.NextEntry == -1)
  497. {
  498. dprintf(
  499. "ownref: empty log @ %p\n",
  500. address
  501. );
  502. return;
  503. }
  504. if (Verbose || ListAllOwners)
  505. DumpOwnerRefTraceLogOwnersList(&logHeader, address, Verbose);
  506. if (Verbose || ListRefs)
  507. DumpOwnerRefTraceLogData(&logHeader, address, Verbose, context);
  508. } // ownref