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.

680 lines
17 KiB

  1. /*++
  2. Copyright (c) 1998-2000 Microsoft Corporation
  3. Module Name:
  4. dbglkrh.cxx
  5. Abstract:
  6. LKRhash support
  7. Author:
  8. George V. Reilly (GeorgeRe) 22-Feb-1999
  9. Revision History:
  10. --*/
  11. #include "precomp.hxx"
  12. #include "lkrcust.h"
  13. #define LKR_CUST_DECLARE_TABLE
  14. #include "lkrcust.h"
  15. #include <i-lkrhash.h>
  16. #ifdef LOCK_INSTRUMENTATION
  17. LONG CLKRLinearHashTable::CBucket::sm_cBuckets = 0;
  18. LONG CLKRLinearHashTable::sm_cTables = 0;
  19. #endif // LOCK_INSTRUMENTATION
  20. #define CMDNAME "lkrhash"
  21. // There are several different DLLs in the IISRTL family. This is to
  22. // allow us to set the name of the DLL on the fly.
  23. // TODO: add a command to set this name dynamically.
  24. #ifndef LKRHASH_NAME
  25. # define LKRHASH_NAME "LKRhash"
  26. #endif // LKRHASH_NAME
  27. CHAR g_szLKRhashDllName[MAX_PATH] = LKRHASH_NAME;
  28. // sprintf-formatted string, e.g., "&%s!CLKRHashTable__sm_llGlobalList"
  29. // Has to return LPSTR, not LPCSTR, because GetExpression is not const-correct
  30. LPSTR
  31. LKRhashDllVar(
  32. LPCSTR pszFormat)
  33. {
  34. // we can get away with a static CHAR[] because debugger extensions
  35. // are single-threaded
  36. static CHAR szSymbol[MAX_SYMBOL_LEN];
  37. sprintf(szSymbol, pszFormat, g_szLKRhashDllName);
  38. return szSymbol;
  39. }
  40. #ifndef __LKRHASH_NO_NAMESPACE__
  41. #define STR_LKRHASH_NS "LKRhash__"
  42. #else
  43. #define STR_LKRHASH_NS ""
  44. #endif // !__LKRHASH_NO_NAMESPACE__
  45. /************************************************************
  46. * Dump LKRhash tables
  47. ************************************************************/
  48. const char*
  49. LKRC2String(
  50. LK_RETCODE lkrc)
  51. {
  52. const char* psz = NULL;
  53. switch (lkrc)
  54. {
  55. case LK_UNUSABLE:
  56. psz = "LK_UNUSABLE";
  57. break;
  58. case LK_ALLOC_FAIL:
  59. psz = "LK_ALLOC_FAIL";
  60. break;
  61. case LK_BAD_ITERATOR:
  62. psz = "LK_BAD_ITERATOR";
  63. break;
  64. case LK_BAD_RECORD:
  65. psz = "LK_BAD_RECORD";
  66. break;
  67. case LK_BAD_PARAMETERS:
  68. psz = "LK_BAD_PARAMETERS";
  69. break;
  70. case LK_NOT_INITIALIZED:
  71. psz = "LK_NOT_INITIALIZED";
  72. break;
  73. case LK_BAD_TABLE:
  74. psz = "LK_BAD_TABLE";
  75. break;
  76. case LK_SUCCESS:
  77. psz = "LK_SUCCESS";
  78. break;
  79. case LK_KEY_EXISTS:
  80. psz = "LK_KEY_EXISTS";
  81. break;
  82. case LK_NO_SUCH_KEY:
  83. psz = "LK_NO_SUCH_KEY";
  84. break;
  85. case LK_NO_MORE_ELEMENTS:
  86. psz = "LK_NO_MORE_ELEMENTS";
  87. break;
  88. default:
  89. psz = "Unknown LK_RETCODE";
  90. break;
  91. }
  92. return psz;
  93. }
  94. enum {
  95. NODES_PER_CLUMP = CNodeClump::NODES_PER_CLUMP,
  96. BUCKET_BYTE_SIZE = CNodeClump::BUCKET_BYTE_SIZE,
  97. HASH_INVALID_SIGNATURE =
  98. LKRHASH_NS::CLKRLinearHashTable::HASH_INVALID_SIGNATURE,
  99. LKLH_SIGNATURE = LKRHASH_NS::CLKRLinearHashTable::SIGNATURE,
  100. LKLH_SIGNATURE_FREE = LKRHASH_NS::CLKRLinearHashTable::SIGNATURE_FREE,
  101. LKHT_SIGNATURE = LKRHASH_NS::CLKRHashTable::SIGNATURE,
  102. LKHT_SIGNATURE_FREE = LKRHASH_NS::CLKRHashTable::SIGNATURE_FREE,
  103. };
  104. BOOL
  105. EnumerateBucketChain(
  106. LKR_CUST_EXTN* plce,
  107. IN LOCK_LOCKTYPE ltBucketLockType,
  108. IN INT iBkt,
  109. IN CBucket* pbkt,
  110. IN INT nVerbose)
  111. {
  112. PSTR cmdName = CMDNAME;
  113. BYTE abBkt[BUCKET_BYTE_SIZE];
  114. DEFINE_CPP_VAR(CNodeClump, nc);
  115. CNodeClump* pnc = GET_CPP_VAR_PTR(CNodeClump, nc);
  116. CNodeClump* pncCurr;
  117. DWORD cNodes = 0, cnc = 0;
  118. BOOL fLockPrinted = FALSE;
  119. ReadMemory(pbkt, abBkt, sizeof(abBkt), NULL);
  120. // Just in case lkrdbg.dll and lkrhash.dll were built with different
  121. // definitions for BucketLock, we make no assumptions about the size
  122. // of BucketLock
  123. for (pncCurr = (CNodeClump*) ((PBYTE) pbkt + LockSize(ltBucketLockType));
  124. pncCurr != NULL;
  125. pncCurr = pnc->m_pncNext)
  126. {
  127. DWORD i, c;
  128. ReadMemory(pncCurr, &nc, sizeof(nc), NULL);
  129. for (i = c = 0; i < NODES_PER_CLUMP; i++)
  130. {
  131. if (pnc->m_dwKeySigs[i] == HASH_INVALID_SIGNATURE)
  132. c++;
  133. }
  134. if (c == NODES_PER_CLUMP)
  135. {
  136. if (nVerbose >= 3)
  137. dprintf(" 0-%d: -- empty\n", NODES_PER_CLUMP);
  138. }
  139. else
  140. {
  141. if (cnc++ == 0)
  142. PrintLock(ltBucketLockType, &pbkt->m_Lock, nVerbose);
  143. dprintf("Bucket %4d, %d:\n", iBkt, cnc);
  144. for (i = 0; i < NODES_PER_CLUMP; i++)
  145. {
  146. if (pnc->m_dwKeySigs[i] == HASH_INVALID_SIGNATURE)
  147. {
  148. if (nVerbose >= 3)
  149. dprintf(" %d: --\n", i);
  150. else
  151. break;
  152. }
  153. else if (plce != NULL)
  154. {
  155. if (!(*plce->m_pfn_Record_Dump)(pnc->m_pvNode[i],
  156. pnc->m_dwKeySigs[i],
  157. nVerbose))
  158. return FALSE;
  159. }
  160. }
  161. }
  162. if (CheckControlC())
  163. {
  164. dprintf("\n^C\n");
  165. return FALSE;
  166. }
  167. const DWORD MAX_NODES = 20;
  168. if (++cNodes > MAX_NODES)
  169. {
  170. dprintf(DBGEXT ".%s: Bucket chain contains more than %d nodes! "
  171. "Corrupted?\n", cmdName, MAX_NODES);
  172. return TRUE;
  173. }
  174. }
  175. return TRUE;
  176. }
  177. BOOL
  178. EnumerateLKRLinearHashTable(
  179. LKR_CUST_EXTN* plce,
  180. IN CLinearHashTable* plht,
  181. IN INT nVerbose)
  182. {
  183. PSTR cmdName = CMDNAME;
  184. DEFINE_CPP_VAR(CLinearHashTable, lht);
  185. CLinearHashTable* plht2 = GET_CPP_VAR_PTR(CLinearHashTable, lht);
  186. INT i;
  187. BOOL fRet = FALSE;
  188. LOCK_LOCKTYPE ltTableLockType = LOCK_SPINLOCK;
  189. LOCK_LOCKTYPE ltBucketLockType = LOCK_SPINLOCK;
  190. CDirEntry* paDirSegs = NULL;
  191. //
  192. // Read the header, perform some sanity checks.
  193. //
  194. if (!ReadMemory(plht, &lht, sizeof(lht), NULL) )
  195. {
  196. dprintf(DBGEXT ".%s: cannot read memory @ %p\n",
  197. cmdName, (PVOID)plht);
  198. goto cleanup;
  199. }
  200. dprintf(
  201. "\n" DBGEXT ".%s: @ %p:\n"
  202. " CLKRLinearHashTable Signature = %08lx '%c%c%c%c' (%s), \"%s\",\n"
  203. " State = %d (%s)\n",
  204. cmdName,
  205. plht,
  206. plht2->m_dwSignature,
  207. DECODE_SIGNATURE(plht2->m_dwSignature),
  208. plht2->m_dwSignature == LKLH_SIGNATURE
  209. ? "OK" : (plht2->m_dwSignature == LKLH_SIGNATURE_FREE
  210. ? "FREED" : "INVALID"),
  211. plht2->m_szName,
  212. plht2->m_lkrcState, LKRC2String(plht2->m_lkrcState));
  213. if (nVerbose == 0)
  214. goto done;
  215. ltTableLockType = (LOCK_LOCKTYPE) plht2->m_nTableLockType;
  216. ltBucketLockType = (LOCK_LOCKTYPE) plht2->m_nBucketLockType;
  217. dprintf(
  218. " TableLock = %s, BucketLock = %s, Parent CLKRHashTable = %p\n",
  219. LockName(ltTableLockType),
  220. LockName(ltBucketLockType),
  221. plht2->m_phtParent);
  222. dprintf(
  223. " Size = %d, SegBits = %d, SegSize = %d, SegMask = %x\n",
  224. plht2->m_lkts, plht2->m_dwSegBits,
  225. plht2->m_dwSegSize, plht2->m_dwSegMask);
  226. dprintf(
  227. " MaxLoad = %3.1f, paDirSegs = %p, cDirSegs = %d\n",
  228. plht2->m_MaxLoad, plht2->m_paDirSegs, plht2->m_cDirSegs);
  229. dprintf(
  230. " cRecords = %d, cActiveBuckets = %d, BucketSpins = %hd\n",
  231. plht2->m_cRecords, plht2->m_cActiveBuckets, plht2->m_wBucketLockSpins);
  232. dprintf(
  233. " nLevel = %d, dwBktAddrMask0 = %x, iExpansionIdx = %d\n",
  234. plht2->m_nLevel, plht2->m_dwBktAddrMask0, plht2->m_iExpansionIdx);
  235. PrintLock(ltTableLockType, &plht->m_Lock, nVerbose);
  236. if (plce != NULL && !(*plce->m_pfn_LKLH_Dump)(plht, nVerbose))
  237. goto done;
  238. if (nVerbose == 1)
  239. goto done;
  240. paDirSegs = (CDirEntry*) calloc(plht2->m_cDirSegs, sizeof(CDirEntry));
  241. if (paDirSegs == NULL)
  242. {
  243. dprintf("Couldn't allocate %d bytes for directory segment\n",
  244. plht2->m_cDirSegs * sizeof(CDirEntry));
  245. return fRet;
  246. }
  247. if (!ReadMemory(plht2->m_paDirSegs, paDirSegs,
  248. sizeof(CDirEntry) * plht2->m_cDirSegs, NULL))
  249. goto cleanup;
  250. for (i = 0; i < (INT) (plht2->m_cDirSegs * plht2->m_dwSegSize); i++)
  251. {
  252. const DWORD iSeg = i >> plht2->m_dwSegBits;
  253. CLargeSegment* pseg =
  254. static_cast<CLargeSegment*>(paDirSegs[iSeg].m_pseg);
  255. if ((i & plht2->m_dwSegMask) == 0)
  256. dprintf("Segment %d: %p\n", iSeg, pseg);
  257. if (pseg == NULL)
  258. continue;
  259. if (nVerbose >= 2)
  260. {
  261. CBucket* pbkt = pseg->m_bktSlots + (i & plht2->m_dwSegMask);
  262. if (!EnumerateBucketChain(plce, ltBucketLockType,
  263. i, pbkt, nVerbose))
  264. goto cleanup;
  265. }
  266. if (CheckControlC())
  267. {
  268. dprintf("\n^C\n");
  269. goto cleanup;
  270. }
  271. }
  272. done:
  273. fRet = TRUE;
  274. cleanup:
  275. memset(&lht, 0, sizeof(lht));
  276. free(paDirSegs);
  277. return fRet;
  278. }
  279. BOOL
  280. EnumerateLKRhashTable(
  281. LKR_CUST_EXTN* plce,
  282. IN CHashTable* pht,
  283. IN INT nVerbose)
  284. {
  285. DEFINE_CPP_VAR(CHashTable, ht);
  286. CHashTable* pht2 = GET_CPP_VAR_PTR(CHashTable, ht);
  287. PSTR cmdName = CMDNAME;
  288. CLinearHashTable** palhtDir = NULL;
  289. UINT i;
  290. BOOL fRet = FALSE;
  291. //
  292. // Read the header, perform some sanity checks.
  293. //
  294. if (!ReadMemory(pht, &ht, sizeof(ht), NULL) )
  295. {
  296. dprintf(DBGEXT ".%s: cannot read memory @ %p\n",
  297. cmdName, (PVOID)pht);
  298. goto cleanup;
  299. }
  300. dprintf(
  301. DBGEXT ".%s: @ %p:\n"
  302. " CLKRHashTable Signature = %08lx '%c%c%c%c' (%s), \"%s\",\n"
  303. " %d subtables, State = %d (%s)\n",
  304. cmdName,
  305. pht,
  306. pht2->m_dwSignature,
  307. DECODE_SIGNATURE(pht2->m_dwSignature),
  308. pht2->m_dwSignature == LKHT_SIGNATURE
  309. ? "OK"
  310. : pht2->m_dwSignature == LKHT_SIGNATURE_FREE
  311. ? "FREED"
  312. : "INVALID",
  313. pht2->m_szName,
  314. pht2->m_cSubTables,
  315. pht2->m_lkrcState, LKRC2String(pht2->m_lkrcState)
  316. );
  317. if (plce != NULL && !(*plce->m_pfn_LKHT_Dump)(pht, nVerbose))
  318. goto done;
  319. if (nVerbose == 0)
  320. goto done;
  321. palhtDir = (CLinearHashTable**) calloc(pht2->m_cSubTables,
  322. sizeof(CLinearHashTable*));
  323. if (!palhtDir)
  324. goto cleanup;
  325. if (!ReadMemory(pht2->m_palhtDir, palhtDir,
  326. pht2->m_cSubTables * sizeof(CLinearHashTable*), NULL))
  327. goto cleanup;
  328. for (i = 0; i < pht2->m_cSubTables; ++i)
  329. {
  330. dprintf("\n%d : ", i);
  331. if (!EnumerateLKRLinearHashTable(plce, palhtDir[i], nVerbose))
  332. break;
  333. if (CheckControlC())
  334. {
  335. dprintf("\n^C\n");
  336. goto cleanup;
  337. }
  338. }
  339. done:
  340. fRet = TRUE;
  341. cleanup:
  342. free(palhtDir);
  343. return fRet;
  344. }
  345. VOID
  346. PrintLKRLinearHashTableThunk(
  347. PVOID psdDebuggee,
  348. PVOID psdDebugger,
  349. CHAR chVerbosity,
  350. DWORD iThunk)
  351. {
  352. DWORD dwSig = ((CLinearHashTable*) psdDebugger)->m_dwSignature;
  353. if (dwSig != LKLH_SIGNATURE)
  354. {
  355. dprintf( "CLKRLinearHashTable(%08p) signature %08lx '%c%c%c%c' doesn't"
  356. " match expected: %08lx '%c%c%c%c'\n",
  357. psdDebuggee, dwSig, DECODE_SIGNATURE(dwSig),
  358. LKLH_SIGNATURE, DECODE_SIGNATURE(LKLH_SIGNATURE)
  359. );
  360. return;
  361. }
  362. LKR_CUST_EXTN* plce = FindLkrCustExtn(CMDNAME, psdDebuggee, dwSig);
  363. if (plce != NULL)
  364. EnumerateLKRLinearHashTable(plce,
  365. (CLinearHashTable*) psdDebuggee,
  366. chVerbosity);
  367. }
  368. VOID
  369. PrintLKRHashTableThunk(
  370. PVOID psdDebuggee,
  371. PVOID psdDebugger,
  372. CHAR chVerbosity,
  373. DWORD iThunk)
  374. {
  375. DWORD dwSig = ((CHashTable*) psdDebugger)->m_dwSignature;
  376. if (dwSig != LKHT_SIGNATURE)
  377. {
  378. dprintf( "CLKRHashTable(%08p) signature %08lx '%c%c%c%c' doesn't"
  379. " match expected: %08lx '%c%c%c%c'\n",
  380. psdDebuggee,
  381. dwSig, DECODE_SIGNATURE(dwSig),
  382. LKHT_SIGNATURE, DECODE_SIGNATURE(LKHT_SIGNATURE)
  383. );
  384. return;
  385. }
  386. LKR_CUST_EXTN* plce = FindLkrCustExtn(CMDNAME, psdDebuggee, dwSig);
  387. if (plce != NULL)
  388. EnumerateLKRhashTable(plce, (CHashTable*) psdDebuggee,
  389. chVerbosity);
  390. }
  391. VOID
  392. DumpLKRsList(
  393. IN INT nVerbose)
  394. {
  395. #ifndef LKR_NO_GLOBAL_LIST
  396. CLockedDoubleList* plstHashTables = (CLockedDoubleList*) GetExpression(
  397. LKRhashDllVar("&%s!" STR_LKRHASH_NS
  398. "CLKRHashTable__sm_llGlobalList"));
  399. if (NULL == plstHashTables)
  400. {
  401. dprintf("Unable to get %s\n",
  402. LKRhashDllVar("%s!" STR_LKRHASH_NS
  403. "CLKRHashTable__sm_llGlobalList"));
  404. return;
  405. }
  406. dprintf("\nGlobal List of CLKRHashTables\n");
  407. EnumLinkedList( (LIST_ENTRY*) &plstHashTables->m_list.m_leHead,
  408. PrintLKRHashTableThunk,
  409. (CHAR) nVerbose,
  410. sizeof(CHashTable),
  411. FIELD_OFFSET( CHashTable, m_leGlobalList));
  412. plstHashTables = (CLockedDoubleList*) GetExpression(
  413. LKRhashDllVar("&%s!" STR_LKRHASH_NS
  414. "CLKRLinearHashTable__sm_llGlobalList"));
  415. if (NULL == plstHashTables)
  416. {
  417. dprintf("Unable to get %s\n",
  418. LKRhashDllVar("!" STR_LKRHASH_NS
  419. "CLKRLinearHashTable__sm_llGlobalList"));
  420. return;
  421. }
  422. dprintf("\nGlobal List of CLKRLinearHashTables\n");
  423. EnumLinkedList( (LIST_ENTRY*) &plstHashTables->m_list.m_leHead,
  424. PrintLKRLinearHashTableThunk,
  425. (CHAR) nVerbose,
  426. sizeof(CLinearHashTable),
  427. FIELD_OFFSET( CLinearHashTable, m_leGlobalList));
  428. #endif // !LKR_NO_GLOBAL_LIST
  429. return;
  430. } // DumpLKRsList()
  431. DECLARE_API( lkrhash )
  432. /*++
  433. Routine Description:
  434. This function is called as an NTSD extension to format and dump
  435. an LKRhash table.
  436. Arguments:
  437. hCurrentProcess - Supplies a handle to the current process (at the
  438. time the extension was called).
  439. hCurrentThread - Supplies a handle to the current thread (at the
  440. time the extension was called).
  441. CurrentPc - Supplies the current pc at the time the extension is
  442. called.
  443. lpExtensionApis - Supplies the address of the functions callable
  444. by this extension.
  445. lpArgumentString - Supplies the asciiz string that describes the
  446. ansi string to be dumped.
  447. Return Value:
  448. None.
  449. --*/
  450. {
  451. INIT_API();
  452. ULONG_PTR lkrAddress = 0;
  453. INT nVerbose = 0;
  454. PSTR cmdName = CMDNAME;
  455. //
  456. // Skip leading blanks.
  457. //
  458. while( *lpArgumentString == ' ' ||
  459. *lpArgumentString == '\t' ) {
  460. lpArgumentString++;
  461. }
  462. if( *lpArgumentString == '\0' ) {
  463. PrintUsage( cmdName );
  464. return;
  465. }
  466. if ( *lpArgumentString == '-' )
  467. {
  468. lpArgumentString++;
  469. if ( *lpArgumentString == 'h' )
  470. {
  471. PrintUsage( cmdName );
  472. return;
  473. }
  474. if ( *lpArgumentString == 'l' ) {
  475. lpArgumentString++;
  476. if ('0' <= *lpArgumentString && *lpArgumentString <= '9' ) {
  477. nVerbose = *lpArgumentString++ - '0';
  478. }
  479. }
  480. if ( *lpArgumentString == 'v' )
  481. {
  482. lpArgumentString++;
  483. nVerbose = 99;
  484. }
  485. if ( *lpArgumentString == 'g' )
  486. {
  487. lpArgumentString++;
  488. if ('0' <= *lpArgumentString && *lpArgumentString <= '9' ) {
  489. nVerbose = *lpArgumentString++ - '0';
  490. }
  491. DumpLKRsList(nVerbose);
  492. return;
  493. }
  494. }
  495. while( *lpArgumentString == ' ' ||
  496. *lpArgumentString == '\t' ) {
  497. lpArgumentString++;
  498. }
  499. lkrAddress = (ULONG_PTR) GetExpression( lpArgumentString );
  500. if (lkrAddress == 0) {
  501. dprintf(
  502. DBGEXT ".%s: cannot evaluate \"%s\"\n",
  503. cmdName,
  504. lpArgumentString
  505. );
  506. return;
  507. }
  508. //
  509. // Skip to end of expression, then skip any blanks.
  510. //
  511. while( *lpArgumentString != ' ' &&
  512. *lpArgumentString != '\t' &&
  513. *lpArgumentString != '\0' ) {
  514. lpArgumentString++;
  515. }
  516. DWORD dwSig;
  517. LKR_CUST_EXTN* plce = FindLkrCustExtn(CMDNAME, (VOID*) lkrAddress, dwSig);
  518. if (plce == NULL)
  519. goto cleanup;
  520. if (dwSig == LKHT_SIGNATURE || dwSig == LKHT_SIGNATURE_FREE)
  521. {
  522. EnumerateLKRhashTable(plce,
  523. (CHashTable*) lkrAddress,
  524. nVerbose);
  525. }
  526. else if (dwSig == LKLH_SIGNATURE || dwSig == LKLH_SIGNATURE_FREE)
  527. {
  528. EnumerateLKRLinearHashTable(plce,
  529. (CLinearHashTable*) lkrAddress,
  530. nVerbose);
  531. }
  532. else
  533. {
  534. dprintf(DBGEXT ".%s: %p does not contain a valid LKRhash table\n",
  535. cmdName, (PVOID)lkrAddress);
  536. }
  537. cleanup:
  538. return;
  539. } // DECLARE_API( lkrhash )