Leaked source code of windows server 2003
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.

681 lines
18 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 PBucket pbkt,
  110. IN INT nVerbose)
  111. {
  112. PSTR cmdName = CMDNAME;
  113. BYTE abBkt[BUCKET_BYTE_SIZE];
  114. DEFINE_CPP_VAR(CNodeClump, nc);
  115. PNodeClump pnc = GET_CPP_VAR_PTR(CNodeClump, nc);
  116. PNodeClump 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 = (PNodeClump) ((PBYTE) pbkt + LockSize(ltBucketLockType));
  124. pncCurr != NULL;
  125. pncCurr = pnc->m_pncNext)
  126. {
  127. DWORD i, c;
  128. ReadMemory(pncCurr, pnc, 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. #ifdef LKR_USE_BUCKET_LOCKS
  142. if (cnc++ == 0)
  143. PrintLock(ltBucketLockType, &pbkt->m_Lock, nVerbose);
  144. #endif
  145. dprintf("Bucket %4d, %d:\n", iBkt, cnc);
  146. for (i = 0; i < NODES_PER_CLUMP; i++)
  147. {
  148. if (pnc->m_dwKeySigs[i] == HASH_INVALID_SIGNATURE)
  149. {
  150. if (nVerbose >= 3)
  151. dprintf(" %d: --\n", i);
  152. else
  153. break;
  154. }
  155. else if (plce != NULL)
  156. {
  157. if (!(*plce->m_pfn_Record_Dump)(pnc->m_pvNode[i],
  158. pnc->m_dwKeySigs[i],
  159. nVerbose))
  160. return FALSE;
  161. }
  162. }
  163. }
  164. if (CheckControlC())
  165. {
  166. dprintf("\n^C\n");
  167. return FALSE;
  168. }
  169. const DWORD MAX_NODES = 20;
  170. if (++cNodes > MAX_NODES)
  171. {
  172. dprintf(DBGEXT ".%s: Bucket chain contains more than %d nodes! "
  173. "Corrupted?\n", cmdName, MAX_NODES);
  174. return TRUE;
  175. }
  176. }
  177. return TRUE;
  178. }
  179. BOOL
  180. EnumerateLKRLinearHashTable(
  181. LKR_CUST_EXTN* plce,
  182. IN CLinearHashTable* plht,
  183. IN INT nVerbose)
  184. {
  185. PSTR cmdName = CMDNAME;
  186. DEFINE_CPP_VAR(CLinearHashTable, lht);
  187. CLinearHashTable* plht2 = GET_CPP_VAR_PTR(CLinearHashTable, lht);
  188. INT i;
  189. BOOL fRet = FALSE;
  190. LOCK_LOCKTYPE ltTableLockType = LOCK_SPINLOCK;
  191. LOCK_LOCKTYPE ltBucketLockType = LOCK_SPINLOCK;
  192. PSegment* paDirSegs = NULL;
  193. //
  194. // Read the header, perform some sanity checks.
  195. //
  196. if (!ReadMemory(plht, plht2, sizeof(lht), NULL) )
  197. {
  198. dprintf(DBGEXT ".%s: cannot read memory @ %p\n",
  199. cmdName, (PVOID)plht);
  200. goto cleanup;
  201. }
  202. dprintf(
  203. "\n" DBGEXT ".%s: @ %p:\n"
  204. " CLKRLinearHashTable Signature = %08lx '%c%c%c%c' (%s), \"%s\",\n"
  205. " State = %d (%s)\n",
  206. cmdName,
  207. plht,
  208. plht2->m_dwSignature,
  209. DECODE_SIGNATURE(plht2->m_dwSignature),
  210. plht2->m_dwSignature == LKLH_SIGNATURE
  211. ? "OK" : (plht2->m_dwSignature == LKLH_SIGNATURE_FREE
  212. ? "FREED" : "INVALID"),
  213. plht2->m_szName,
  214. plht2->m_lkrcState, LKRC2String(plht2->m_lkrcState));
  215. if (nVerbose == 0)
  216. goto done;
  217. ltTableLockType = (LOCK_LOCKTYPE) plht2->m_nTableLockType;
  218. ltBucketLockType = (LOCK_LOCKTYPE) plht2->m_nBucketLockType;
  219. dprintf(
  220. " TableLock = %s, BucketLock = %s, Parent CLKRHashTable = %p\n",
  221. LockName(ltTableLockType),
  222. LockName(ltBucketLockType),
  223. plht2->m_phtParent);
  224. dprintf(
  225. " Size = %d, SegBits = %d, SegSize = %d, SegMask = %x\n",
  226. plht2->m_lkts, plht2->m_nSegBits,
  227. plht2->m_nSegSize, plht2->m_nSegMask);
  228. dprintf(
  229. " MaxLoad = %3.1f, paDirSegs = %p, cDirSegs = %d\n",
  230. plht2->m_MaxLoad, plht2->m_paDirSegs, plht2->m_cDirSegs);
  231. dprintf(
  232. " cRecords = %d, cActiveBuckets = %d, BucketSpins = %hd\n",
  233. plht2->m_cRecords, plht2->m_cActiveBuckets, plht2->m_wBucketLockSpins);
  234. dprintf(
  235. " nLevel = %d, dwBktAddrMask0 = %x, iExpansionIdx = %d\n",
  236. plht2->m_nLevel, plht2->m_dwBktAddrMask0, plht2->m_iExpansionIdx);
  237. PrintLock(ltTableLockType, &plht->m_Lock, nVerbose);
  238. if (plce != NULL && !(*plce->m_pfn_LKLH_Dump)(plht, nVerbose))
  239. goto done;
  240. if (nVerbose == 1)
  241. goto done;
  242. paDirSegs = (PSegment*) calloc(plht2->m_cDirSegs, sizeof(PSegment));
  243. if (paDirSegs == NULL)
  244. {
  245. dprintf("Couldn't allocate %d bytes for directory segment\n",
  246. plht2->m_cDirSegs * sizeof(PSegment));
  247. return fRet;
  248. }
  249. if (!ReadMemory(plht2->m_paDirSegs, paDirSegs,
  250. sizeof(PSegment) * plht2->m_cDirSegs, NULL))
  251. goto cleanup;
  252. for (i = 0; i < (INT) (plht2->m_cDirSegs * plht2->m_nSegSize); i++)
  253. {
  254. const DWORD iSeg = i >> plht2->m_nSegBits;
  255. CLargeSegment* pseg = static_cast<CLargeSegment*>(paDirSegs[iSeg]);
  256. if ((i & plht2->m_nSegMask) == 0)
  257. dprintf("Segment %d: %p\n", iSeg, pseg);
  258. if (pseg == NULL)
  259. continue;
  260. if (nVerbose >= 2)
  261. {
  262. PBucket pbkt = pseg->m_bktSlots + (i & plht2->m_nSegMask);
  263. if (!EnumerateBucketChain(plce, ltBucketLockType,
  264. i, pbkt, nVerbose))
  265. goto cleanup;
  266. }
  267. if (CheckControlC())
  268. {
  269. dprintf("\n^C\n");
  270. goto cleanup;
  271. }
  272. }
  273. done:
  274. fRet = TRUE;
  275. cleanup:
  276. memset(plht2, 0, sizeof(lht));
  277. free(paDirSegs);
  278. return fRet;
  279. }
  280. BOOL
  281. EnumerateLKRhashTable(
  282. LKR_CUST_EXTN* plce,
  283. IN CHashTable* pht,
  284. IN INT nVerbose)
  285. {
  286. DEFINE_CPP_VAR(CHashTable, ht);
  287. CHashTable* pht2 = GET_CPP_VAR_PTR(CHashTable, ht);
  288. PSTR cmdName = CMDNAME;
  289. CLinearHashTable** palhtDir = NULL;
  290. UINT i;
  291. BOOL fRet = FALSE;
  292. //
  293. // Read the header, perform some sanity checks.
  294. //
  295. if (!ReadMemory(pht, pht2, sizeof(ht), NULL) )
  296. {
  297. dprintf(DBGEXT ".%s: cannot read memory @ %p\n",
  298. cmdName, (PVOID)pht);
  299. goto cleanup;
  300. }
  301. dprintf(
  302. DBGEXT ".%s: @ %p:\n"
  303. " CLKRHashTable Signature = %08lx '%c%c%c%c' (%s), \"%s\",\n"
  304. " %d subtables, State = %d (%s)\n",
  305. cmdName,
  306. pht,
  307. pht2->m_dwSignature,
  308. DECODE_SIGNATURE(pht2->m_dwSignature),
  309. pht2->m_dwSignature == LKHT_SIGNATURE
  310. ? "OK"
  311. : pht2->m_dwSignature == LKHT_SIGNATURE_FREE
  312. ? "FREED"
  313. : "INVALID",
  314. pht2->m_szName,
  315. pht2->m_cSubTables,
  316. pht2->m_lkrcState, LKRC2String(pht2->m_lkrcState)
  317. );
  318. if (plce != NULL && !(*plce->m_pfn_LKHT_Dump)(pht, nVerbose))
  319. goto done;
  320. if (nVerbose == 0)
  321. goto done;
  322. palhtDir = (CLinearHashTable**) calloc(pht2->m_cSubTables,
  323. sizeof(CLinearHashTable*));
  324. if (!palhtDir)
  325. goto cleanup;
  326. if (!ReadMemory(pht2->m_palhtDir, palhtDir,
  327. pht2->m_cSubTables * sizeof(CLinearHashTable*), NULL))
  328. goto cleanup;
  329. for (i = 0; i < pht2->m_cSubTables; ++i)
  330. {
  331. dprintf("\n%d : ", i);
  332. if (!EnumerateLKRLinearHashTable(plce, palhtDir[i], nVerbose))
  333. break;
  334. if (CheckControlC())
  335. {
  336. dprintf("\n^C\n");
  337. goto cleanup;
  338. }
  339. }
  340. done:
  341. fRet = TRUE;
  342. cleanup:
  343. free(palhtDir);
  344. return fRet;
  345. }
  346. VOID
  347. PrintLKRLinearHashTableThunk(
  348. PVOID psdDebuggee,
  349. PVOID psdDebugger,
  350. CHAR chVerbosity,
  351. DWORD iThunk)
  352. {
  353. DWORD dwSig = ((CLinearHashTable*) psdDebugger)->m_dwSignature;
  354. if (dwSig != LKLH_SIGNATURE)
  355. {
  356. dprintf( "CLKRLinearHashTable(%08p) signature %08lx '%c%c%c%c' doesn't"
  357. " match expected: %08lx '%c%c%c%c'\n",
  358. psdDebuggee, dwSig, DECODE_SIGNATURE(dwSig),
  359. LKLH_SIGNATURE, DECODE_SIGNATURE(LKLH_SIGNATURE)
  360. );
  361. return;
  362. }
  363. LKR_CUST_EXTN* plce = FindLkrCustExtn(CMDNAME, psdDebuggee, dwSig);
  364. if (plce != NULL)
  365. EnumerateLKRLinearHashTable(plce,
  366. (CLinearHashTable*) psdDebuggee,
  367. chVerbosity);
  368. }
  369. VOID
  370. PrintLKRHashTableThunk(
  371. PVOID psdDebuggee,
  372. PVOID psdDebugger,
  373. CHAR chVerbosity,
  374. DWORD iThunk)
  375. {
  376. DWORD dwSig = ((CHashTable*) psdDebugger)->m_dwSignature;
  377. if (dwSig != LKHT_SIGNATURE)
  378. {
  379. dprintf( "CLKRHashTable(%08p) signature %08lx '%c%c%c%c' doesn't"
  380. " match expected: %08lx '%c%c%c%c'\n",
  381. psdDebuggee,
  382. dwSig, DECODE_SIGNATURE(dwSig),
  383. LKHT_SIGNATURE, DECODE_SIGNATURE(LKHT_SIGNATURE)
  384. );
  385. return;
  386. }
  387. LKR_CUST_EXTN* plce = FindLkrCustExtn(CMDNAME, psdDebuggee, dwSig);
  388. if (plce != NULL)
  389. EnumerateLKRhashTable(plce, (CHashTable*) psdDebuggee,
  390. chVerbosity);
  391. }
  392. VOID
  393. DumpLKRsList(
  394. IN INT nVerbose)
  395. {
  396. #ifndef LKR_NO_GLOBAL_LIST
  397. CLockedDoubleList* plstHashTables = (CLockedDoubleList*) GetExpression(
  398. LKRhashDllVar("&%s!" STR_LKRHASH_NS
  399. "CLKRHashTable__sm_llGlobalList"));
  400. if (NULL == plstHashTables)
  401. {
  402. dprintf("Unable to get %s\n",
  403. LKRhashDllVar("%s!" STR_LKRHASH_NS
  404. "CLKRHashTable__sm_llGlobalList"));
  405. return;
  406. }
  407. dprintf("\nGlobal List of CLKRHashTables\n");
  408. EnumLinkedList( (LIST_ENTRY*) &plstHashTables->m_list.m_leHead,
  409. PrintLKRHashTableThunk,
  410. (CHAR) nVerbose,
  411. sizeof(CHashTable),
  412. FIELD_OFFSET( CHashTable, m_leGlobalList));
  413. plstHashTables = (CLockedDoubleList*) GetExpression(
  414. LKRhashDllVar("&%s!" STR_LKRHASH_NS
  415. "CLKRLinearHashTable__sm_llGlobalList"));
  416. if (NULL == plstHashTables)
  417. {
  418. dprintf("Unable to get %s\n",
  419. LKRhashDllVar("!" STR_LKRHASH_NS
  420. "CLKRLinearHashTable__sm_llGlobalList"));
  421. return;
  422. }
  423. dprintf("\nGlobal List of CLKRLinearHashTables\n");
  424. EnumLinkedList( (LIST_ENTRY*) &plstHashTables->m_list.m_leHead,
  425. PrintLKRLinearHashTableThunk,
  426. (CHAR) nVerbose,
  427. sizeof(CLinearHashTable),
  428. FIELD_OFFSET( CLinearHashTable, m_leGlobalList));
  429. #endif // !LKR_NO_GLOBAL_LIST
  430. return;
  431. } // DumpLKRsList()
  432. DECLARE_API( lkrhash )
  433. /*++
  434. Routine Description:
  435. This function is called as an NTSD extension to format and dump
  436. an LKRhash table.
  437. Arguments:
  438. hCurrentProcess - Supplies a handle to the current process (at the
  439. time the extension was called).
  440. hCurrentThread - Supplies a handle to the current thread (at the
  441. time the extension was called).
  442. CurrentPc - Supplies the current pc at the time the extension is
  443. called.
  444. lpExtensionApis - Supplies the address of the functions callable
  445. by this extension.
  446. lpArgumentString - Supplies the asciiz string that describes the
  447. ansi string to be dumped.
  448. Return Value:
  449. None.
  450. --*/
  451. {
  452. INIT_API();
  453. ULONG_PTR lkrAddress = 0;
  454. INT nVerbose = 0;
  455. PSTR cmdName = CMDNAME;
  456. //
  457. // Skip leading blanks.
  458. //
  459. while( *lpArgumentString == ' ' ||
  460. *lpArgumentString == '\t' ) {
  461. lpArgumentString++;
  462. }
  463. if( *lpArgumentString == '\0' ) {
  464. PrintUsage( cmdName );
  465. return;
  466. }
  467. if ( *lpArgumentString == '-' )
  468. {
  469. lpArgumentString++;
  470. if ( *lpArgumentString == 'h' )
  471. {
  472. PrintUsage( cmdName );
  473. return;
  474. }
  475. if ( *lpArgumentString == 'l' ) {
  476. lpArgumentString++;
  477. if ('0' <= *lpArgumentString && *lpArgumentString <= '9' ) {
  478. nVerbose = *lpArgumentString++ - '0';
  479. }
  480. }
  481. if ( *lpArgumentString == 'v' )
  482. {
  483. lpArgumentString++;
  484. nVerbose = 99;
  485. }
  486. if ( *lpArgumentString == 'g' )
  487. {
  488. lpArgumentString++;
  489. if ('0' <= *lpArgumentString && *lpArgumentString <= '9' ) {
  490. nVerbose = *lpArgumentString++ - '0';
  491. }
  492. DumpLKRsList(nVerbose);
  493. return;
  494. }
  495. }
  496. while( *lpArgumentString == ' ' ||
  497. *lpArgumentString == '\t' ) {
  498. lpArgumentString++;
  499. }
  500. lkrAddress = (ULONG_PTR) GetExpression( lpArgumentString );
  501. if (lkrAddress == 0) {
  502. dprintf(
  503. DBGEXT ".%s: cannot evaluate \"%s\"\n",
  504. cmdName,
  505. lpArgumentString
  506. );
  507. return;
  508. }
  509. //
  510. // Skip to end of expression, then skip any blanks.
  511. //
  512. while( *lpArgumentString != ' ' &&
  513. *lpArgumentString != '\t' &&
  514. *lpArgumentString != '\0' ) {
  515. lpArgumentString++;
  516. }
  517. DWORD dwSig;
  518. LKR_CUST_EXTN* plce = FindLkrCustExtn(CMDNAME, (VOID*) lkrAddress, dwSig);
  519. if (plce == NULL)
  520. goto cleanup;
  521. if (dwSig == LKHT_SIGNATURE || dwSig == LKHT_SIGNATURE_FREE)
  522. {
  523. EnumerateLKRhashTable(plce,
  524. (CHashTable*) lkrAddress,
  525. nVerbose);
  526. }
  527. else if (dwSig == LKLH_SIGNATURE || dwSig == LKLH_SIGNATURE_FREE)
  528. {
  529. EnumerateLKRLinearHashTable(plce,
  530. (CLinearHashTable*) lkrAddress,
  531. nVerbose);
  532. }
  533. else
  534. {
  535. dprintf(DBGEXT ".%s: %p does not contain a valid LKRhash table\n",
  536. cmdName, (PVOID)lkrAddress);
  537. }
  538. cleanup:
  539. return;
  540. } // DECLARE_API( lkrhash )