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.

815 lines
20 KiB

  1. /*++
  2. Copyright (c) 1998-1999 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 "inetdbgp.h"
  12. #ifdef LOCK_INSTRUMENTATION
  13. LONG CLKRLinearHashTable::CBucket::sm_cBuckets = 0;
  14. LONG CLKRLinearHashTable::sm_cTables = 0;
  15. #endif // LOCK_INSTRUMENTATION
  16. // #define SAMPLE_LKRHASH_TESTCLASS
  17. // #include <lkrhash.h>
  18. // There are several different DLLs in the IISRTL family. This is to
  19. // allow us to set the name of the DLL on the fly.
  20. // TODO: add a command to set this name dynamically.
  21. CHAR g_szIisRtlName[MAX_PATH] = IISRTL_NAME;
  22. // sprintf-formatted string, e.g., "&%s!CLKRHashTable__sm_llGlobalList"
  23. // Has to return LPSTR, not LPCSTR, because GetExpression is not const-correct
  24. LPSTR
  25. IisRtlVar(
  26. LPCSTR pszFormat)
  27. {
  28. // we can get away with a static CHAR[] because debugger extensions
  29. // are single-threaded
  30. static CHAR szSymbol[MAX_SYMBOL_LEN];
  31. sprintf(szSymbol, pszFormat, g_szIisRtlName);
  32. return szSymbol;
  33. }
  34. class CTest
  35. {
  36. public:
  37. enum {BUFFSIZE=20};
  38. int m_n; // This will also be a key
  39. char m_sz[BUFFSIZE]; // This will be the primary key
  40. bool m_fWhatever;
  41. mutable LONG m_cRefs; // Reference count for lifetime management.
  42. // Must be mutable to use 'const CTest*' in
  43. // hashtables
  44. CTest(int n, const char* psz, bool f)
  45. : m_n(n), m_fWhatever(f), m_cRefs(0)
  46. {
  47. strncpy(m_sz, psz, BUFFSIZE-1);
  48. m_sz[BUFFSIZE-1] = '\0';
  49. }
  50. ~CTest()
  51. {
  52. IRTLASSERT(m_cRefs == 0);
  53. }
  54. };
  55. BOOL
  56. TestEnum(
  57. IN const void* pvParam,
  58. IN DWORD dwSignature,
  59. IN INT nVerbose)
  60. {
  61. CTest* pTest = (CTest*) pvParam;
  62. CTest tst(0, "", 0);
  63. ReadMemory(pTest, &tst, sizeof(tst), NULL);
  64. dprintf("%8p: %d %s %d %d \n",
  65. pTest, tst.m_n, tst.m_sz, tst.m_fWhatever, tst.m_cRefs);
  66. return TRUE;
  67. }
  68. // Dummy implementations so that we can link
  69. CLKRLinearHashTable::CLKRLinearHashTable(
  70. LPCSTR pszName, // An identifier for debugging
  71. PFnExtractKey pfnExtractKey, // Extract key from record
  72. PFnCalcKeyHash pfnCalcKeyHash, // Calculate hash signature of key
  73. PFnEqualKeys pfnEqualKeys, // Compare two keys
  74. PFnAddRefRecord pfnAddRefRecord,// AddRef in FindKey, etc
  75. double maxload, // Upperbound on average chain length
  76. DWORD initsize, // Initial size of hash table.
  77. DWORD num_subtbls // for signature compatiblity
  78. // with CLKRHashTable
  79. )
  80. #ifdef LKR_NEWCODE
  81. : m_nTableLockType(TableLock::LockType()),
  82. m_nBucketLockType(BucketLock::LockType()),
  83. m_phtParent(NULL)
  84. #endif // LKR_NEWCODE
  85. {}
  86. #ifdef LKR_NEWCODE
  87. CLKRLinearHashTable::CLKRLinearHashTable(
  88. LPCSTR pszName, // An identifier for debugging
  89. PFnExtractKey pfnExtractKey, // Extract key from record
  90. PFnCalcKeyHash pfnCalcKeyHash, // Calculate hash signature of key
  91. PFnEqualKeys pfnEqualKeys, // Compare two keys
  92. PFnAddRefRecord pfnAddRefRecord,// AddRef in FindKey, etc
  93. double maxload, // Upperbound on average chain length
  94. DWORD initsize, // Initial size of hash table.
  95. CLKRHashTable* phtParent // Owning table.
  96. )
  97. : m_nTableLockType(TableLock::LockType()),
  98. m_nBucketLockType(BucketLock::LockType()),
  99. m_phtParent(NULL)
  100. {}
  101. #endif // LKR_NEWCODE
  102. CLKRLinearHashTable::~CLKRLinearHashTable()
  103. {}
  104. CLKRHashTable::CLKRHashTable(
  105. LPCSTR pszName, // An identifier for debugging
  106. PFnExtractKey pfnExtractKey, // Extract key from record
  107. PFnCalcKeyHash pfnCalcKeyHash, // Calculate hash signature of key
  108. PFnEqualKeys pfnEqualKeys, // Compare two keys
  109. PFnAddRefRecord pfnAddRefRecord,// AddRef in FindKey, etc
  110. double maxload, // Upperbound on average chain length
  111. DWORD initsize, // Initial size of hash table.
  112. DWORD num_subtbls // #subordinate hash tables
  113. )
  114. {}
  115. CLKRHashTable::~CLKRHashTable()
  116. {}
  117. /************************************************************
  118. * Dump LKRhash tables
  119. ************************************************************/
  120. const char*
  121. LKRC2String(
  122. LK_RETCODE lkrc)
  123. {
  124. const char* psz = NULL;
  125. switch (lkrc)
  126. {
  127. case LK_UNUSABLE:
  128. psz = "LK_UNUSABLE";
  129. break;
  130. case LK_ALLOC_FAIL:
  131. psz = "LK_ALLOC_FAIL";
  132. break;
  133. case LK_BAD_ITERATOR:
  134. psz = "LK_BAD_ITERATOR";
  135. break;
  136. case LK_BAD_RECORD:
  137. psz = "LK_BAD_RECORD";
  138. break;
  139. case LK_BAD_PARAMETERS:
  140. psz = "LK_BAD_PARAMETERS";
  141. break;
  142. case LK_NOT_INITIALIZED:
  143. psz = "LK_NOT_INITIALIZED";
  144. break;
  145. case LK_SUCCESS:
  146. psz = "LK_SUCCESS";
  147. break;
  148. case LK_KEY_EXISTS:
  149. psz = "LK_KEY_EXISTS";
  150. break;
  151. case LK_NO_SUCH_KEY:
  152. psz = "LK_NO_SUCH_KEY";
  153. break;
  154. case LK_NO_MORE_ELEMENTS:
  155. psz = "LK_NO_MORE_ELEMENTS";
  156. break;
  157. default:
  158. psz = "Unknown LK_RETCODE";
  159. break;
  160. }
  161. return psz;
  162. }
  163. BOOL
  164. DefaultLKRhashEnum(
  165. IN const void* pvParam,
  166. IN DWORD dwSignature,
  167. IN INT nVerbose)
  168. {
  169. dprintf("%8p (%08x)\n", pvParam, dwSignature);
  170. return TRUE;
  171. }
  172. typedef CLKRLinearHashTable::CBucket CBucket;
  173. typedef CLKRLinearHashTable::CNodeClump CNodeClump;
  174. typedef CLKRLinearHashTable::CSegment CSegment;
  175. typedef CLKRLinearHashTable::CSmallSegment CSmallSegment;
  176. typedef CLKRLinearHashTable::CMediumSegment CMediumSegment;
  177. typedef CLKRLinearHashTable::CLargeSegment CLargeSegment;
  178. typedef CLKRLinearHashTable::CDirEntry CDirEntry;
  179. enum {
  180. NODES_PER_CLUMP = CNodeClump::NODES_PER_CLUMP,
  181. HASH_INVALID_SIGNATURE = CLKRLinearHashTable::HASH_INVALID_SIGNATURE,
  182. };
  183. BOOL
  184. EnumerateBucketChain(
  185. IN PFN_ENUM_LKRHASH pfnEnum,
  186. IN LOCK_LOCKTYPE ltBucketLockType,
  187. IN CBucket* pbkt,
  188. IN INT nVerbose)
  189. {
  190. PSTR cmdName = "lkrhash";
  191. CBucket bkt;
  192. CNodeClump nc;
  193. CNodeClump* pncCurr;
  194. CNodeClump* pncPrev = NULL;
  195. DWORD cNodes = 0;
  196. ReadMemory(pbkt, &bkt, sizeof(bkt), NULL);
  197. PrintLock(ltBucketLockType, &pbkt->m_Lock, nVerbose);
  198. for (pncCurr = (CNodeClump*) ((PBYTE) pbkt + LockSize(ltBucketLockType));
  199. pncCurr != NULL;
  200. pncPrev = pncCurr, pncCurr = nc.m_pncNext)
  201. {
  202. DWORD i, c;
  203. ReadMemory(pncCurr, &nc, sizeof(nc), NULL);
  204. for (i = c = 0; i < NODES_PER_CLUMP; i++)
  205. {
  206. if (nc.m_dwKeySigs[i] == HASH_INVALID_SIGNATURE)
  207. c++;
  208. }
  209. if (c == NODES_PER_CLUMP)
  210. {
  211. dprintf(" 0-%d: -- empty\n", NODES_PER_CLUMP);
  212. }
  213. else
  214. {
  215. for (i = 0; i < NODES_PER_CLUMP; i++)
  216. {
  217. if (nc.m_dwKeySigs[i] == HASH_INVALID_SIGNATURE)
  218. {
  219. dprintf(" %d: --\n", i);
  220. }
  221. else
  222. {
  223. (*pfnEnum)(nc.m_pvNode[i], nc.m_dwKeySigs[i], nVerbose);
  224. }
  225. }
  226. }
  227. if (CheckControlC())
  228. {
  229. dprintf("\n^C\n");
  230. return FALSE;
  231. }
  232. const DWORD MAX_NODES = 20;
  233. if (++cNodes > MAX_NODES)
  234. {
  235. dprintf("inetdbg.%s: Bucket chain contains more than %d nodes! "
  236. "Corrupted?\n", cmdName, MAX_NODES);
  237. return TRUE;
  238. }
  239. }
  240. return TRUE;
  241. }
  242. BOOL
  243. EnumerateLKRLinearHashTable(
  244. IN PFN_ENUM_LKRHASH pfnEnum,
  245. IN CLKRLinearHashTable* plht,
  246. IN INT nVerbose)
  247. {
  248. PSTR cmdName = "lkrhash";
  249. CLKRLinearHashTable lht(NULL, NULL, NULL, NULL, NULL);
  250. INT i;
  251. BOOL fRet = FALSE;
  252. LOCK_LOCKTYPE ltTableLockType = LOCK_SPINLOCK;
  253. LOCK_LOCKTYPE ltBucketLockType = LOCK_SPINLOCK;
  254. CDirEntry* paDirSegs = NULL;
  255. //
  256. // Read the header, perform some sanity checks.
  257. //
  258. if (!ReadMemory(plht, &lht, sizeof(lht), NULL) )
  259. {
  260. dprintf("inetdbg.%s: cannot read memory @ %p\n",
  261. cmdName, (PVOID)plht);
  262. goto cleanup;
  263. }
  264. dprintf(
  265. "\ninetdbg.%s: @ %p:\n"
  266. " CLKRLinearHashTable Signature = %08lx '%c%c%c%c' (%s), \"%s\",\n"
  267. " State = %d (%s)\n",
  268. cmdName,
  269. plht,
  270. lht.m_dwSignature,
  271. DECODE_SIGNATURE(lht.m_dwSignature),
  272. lht.m_dwSignature == CLKRLinearHashTable::SIGNATURE
  273. ? "OK" : (lht.m_dwSignature == CLKRLinearHashTable::SIGNATURE_FREE
  274. ? "FREED" : "INVALID"),
  275. lht.m_szName,
  276. lht.m_lkrcState, LKRC2String(lht.m_lkrcState));
  277. if (nVerbose == 0)
  278. goto done;
  279. #ifdef LKR_NEWCODE
  280. ltTableLockType = (LOCK_LOCKTYPE) lht.m_nTableLockType;
  281. ltBucketLockType = (LOCK_LOCKTYPE) lht.m_nBucketLockType;
  282. dprintf(
  283. " TableLock = %s, BucketLock = %s, Parent CLKRHashTable = %p\n",
  284. LockName(ltTableLockType),
  285. LockName(ltBucketLockType),
  286. lht.m_phtParent);
  287. #endif // LKR_NEWCODE
  288. dprintf(
  289. " Size = %d, SegBits = %d, SegSize = %d, SegMask = %x\n",
  290. lht.m_lkts, lht.m_dwSegBits, lht.m_dwSegSize, lht.m_dwSegMask);
  291. dprintf(
  292. " MaxLoad = %3.1f, paDirSegs = %p, cDirSegs = %d\n",
  293. lht.m_MaxLoad, lht.m_paDirSegs, lht.m_cDirSegs);
  294. dprintf(
  295. " cRecords = %d, cActiveBuckets = %d, BucketSpins = %hd\n",
  296. lht.m_cRecords, lht.m_cActiveBuckets, lht.m_wBucketLockSpins);
  297. dprintf(
  298. " nLevel = %d, dwBktAddrMask = %x, iExpansionIdx = %d\n",
  299. lht.m_nLevel, lht.m_dwBktAddrMask, lht.m_iExpansionIdx);
  300. PrintLock(ltTableLockType, &plht->m_Lock, nVerbose);
  301. if (nVerbose == 1)
  302. goto done;
  303. paDirSegs = (CDirEntry*) calloc(lht.m_cDirSegs, sizeof(CDirEntry));
  304. if (paDirSegs == NULL) {
  305. dprintf("Out of memory\n");
  306. goto cleanup;
  307. }
  308. ReadMemory(lht.m_paDirSegs, paDirSegs,
  309. sizeof(CDirEntry) * lht.m_cDirSegs, NULL);
  310. for (i = 0; i < (INT) (lht.m_cDirSegs * lht.m_dwSegSize); i++)
  311. {
  312. const DWORD iSeg = i >> lht.m_dwSegBits;
  313. CLargeSegment* pseg =
  314. static_cast<CLargeSegment*>(paDirSegs[iSeg].m_pseg);
  315. if ((i & lht.m_dwSegMask) == 0)
  316. dprintf("Segment %d: %p\n", iSeg, pseg);
  317. if (pseg == NULL)
  318. continue;
  319. if (nVerbose >= 2)
  320. {
  321. CBucket* const pbkt = pseg->m_bktSlots + (i & lht.m_dwSegMask);
  322. dprintf("Bucket %4d: ", i);
  323. if (!EnumerateBucketChain(pfnEnum, ltBucketLockType,
  324. pbkt, nVerbose))
  325. goto cleanup;
  326. }
  327. if (CheckControlC())
  328. {
  329. dprintf("\n^C\n");
  330. goto cleanup;
  331. }
  332. }
  333. done:
  334. fRet = TRUE;
  335. cleanup:
  336. if (paDirSegs)
  337. free(paDirSegs);
  338. return fRet;
  339. }
  340. BOOL
  341. EnumerateLKRhashTable(
  342. IN PFN_ENUM_LKRHASH pfnEnum,
  343. IN CLKRHashTable* pht,
  344. IN INT nVerbose)
  345. {
  346. CLKRHashTable ht(NULL, NULL, NULL, NULL, NULL);
  347. PSTR cmdName = "lkrhash";
  348. CLKRLinearHashTable** palhtDir = NULL;
  349. UINT i;
  350. BOOL fRet = FALSE;
  351. //
  352. // Read the header, perform some sanity checks.
  353. //
  354. if (!ReadMemory(pht, &ht, sizeof(ht), NULL) )
  355. {
  356. dprintf("inetdbg.%s: cannot read memory @ %p\n",
  357. cmdName, (PVOID)pht);
  358. goto cleanup;
  359. }
  360. dprintf(
  361. "inetdbg.%s: @ %p:\n"
  362. " CLKRHashTable Signature = %08lx '%c%c%c%c' (%s), \"%s\",\n"
  363. " %d subtables, State = %d (%s)\n",
  364. cmdName,
  365. pht,
  366. ht.m_dwSignature,
  367. DECODE_SIGNATURE(ht.m_dwSignature),
  368. ht.m_dwSignature == CLKRHashTable::SIGNATURE
  369. ? "OK"
  370. : ht.m_dwSignature == CLKRHashTable::SIGNATURE_FREE
  371. ? "FREED"
  372. : "INVALID",
  373. ht.m_szName,
  374. ht.m_cSubTables,
  375. ht.m_lkrcState, LKRC2String(ht.m_lkrcState)
  376. );
  377. if (nVerbose == 0)
  378. goto done;
  379. palhtDir = (CLKRLinearHashTable**) calloc(ht.m_cSubTables,
  380. sizeof(CLKRLinearHashTable*));
  381. if (!palhtDir)
  382. goto cleanup;
  383. if (!ReadMemory(ht.m_palhtDir, palhtDir,
  384. ht.m_cSubTables * sizeof(CLKRLinearHashTable*), NULL))
  385. goto cleanup;
  386. for (i = 0; i < ht.m_cSubTables; ++i)
  387. {
  388. dprintf("%d : ", i);
  389. if (!EnumerateLKRLinearHashTable(pfnEnum, palhtDir[i], nVerbose))
  390. break;
  391. if (CheckControlC())
  392. {
  393. dprintf("\n^C\n");
  394. goto cleanup;
  395. }
  396. }
  397. done:
  398. fRet = TRUE;
  399. cleanup:
  400. free(palhtDir);
  401. return fRet;
  402. }
  403. VOID
  404. PrintLKRLinearHashTableThunk(
  405. PVOID psdDebuggee,
  406. PVOID psdDebugger,
  407. CHAR chVerbosity,
  408. DWORD iThunk)
  409. {
  410. DWORD dwSig = ((CLKRLinearHashTable*) psdDebugger)->m_dwSignature;
  411. if (dwSig != CLKRLinearHashTable::SIGNATURE)
  412. {
  413. dprintf( "CLKRLinearHashTable(%08p) signature %08lx '%c%c%c%c' doesn't"
  414. " match expected: %08lx\n",
  415. psdDebuggee, dwSig, DECODE_SIGNATURE(dwSig),
  416. CLKRLinearHashTable::SIGNATURE
  417. );
  418. return;
  419. }
  420. EnumerateLKRLinearHashTable(DefaultLKRhashEnum,
  421. (CLKRLinearHashTable*) psdDebuggee,
  422. chVerbosity);
  423. }
  424. VOID
  425. PrintLKRHashTableThunk(
  426. PVOID psdDebuggee,
  427. PVOID psdDebugger,
  428. CHAR chVerbosity,
  429. DWORD iThunk)
  430. {
  431. DWORD dwSig = ((CLKRHashTable*) psdDebugger)->m_dwSignature;
  432. if (dwSig != CLKRHashTable::SIGNATURE)
  433. {
  434. dprintf( "CLKRHashTable(%08p) signature %08lx '%c%c%c%c' doesn't"
  435. " match expected: %08lx\n",
  436. psdDebuggee,
  437. dwSig, DECODE_SIGNATURE(dwSig),
  438. CLKRHashTable::SIGNATURE
  439. );
  440. return;
  441. }
  442. EnumerateLKRhashTable(DefaultLKRhashEnum, (CLKRHashTable*) psdDebuggee,
  443. chVerbosity);
  444. }
  445. VOID
  446. DumpLKRsList(
  447. IN INT nVerbose)
  448. {
  449. CLockedDoubleList* plstHashTables = (CLockedDoubleList*) GetExpression(
  450. IisRtlVar("&%s!CLKRHashTable__sm_llGlobalList"));
  451. if (NULL == plstHashTables)
  452. {
  453. dprintf("Unable to get %s\n",
  454. IisRtlVar("%s!CLKRHashTable__sm_llGlobalList"));
  455. return;
  456. }
  457. dprintf("\nGlobal List of CLKRHashTables\n");
  458. EnumLinkedList( (LIST_ENTRY*) &plstHashTables->m_list.m_leHead,
  459. PrintLKRHashTableThunk,
  460. (CHAR) nVerbose,
  461. sizeof(CLKRHashTable),
  462. FIELD_OFFSET( CLKRHashTable, m_leGlobalList)
  463. );
  464. plstHashTables = (CLockedDoubleList*) GetExpression(
  465. IisRtlVar( "&%s!CLKRLinearHashTable__sm_llGlobalList"));
  466. if (NULL == plstHashTables)
  467. {
  468. dprintf("Unable to get %s\n",
  469. IisRtlVar("!CLKRLinearHashTable__sm_llGlobalList"));
  470. return;
  471. }
  472. dprintf("\nGlobal List of CLKRLinearHashTables\n");
  473. EnumLinkedList( (LIST_ENTRY*) &plstHashTables->m_list.m_leHead,
  474. PrintLKRLinearHashTableThunk,
  475. (CHAR) nVerbose,
  476. sizeof(CLKRLinearHashTable),
  477. FIELD_OFFSET( CLKRLinearHashTable, m_leGlobalList)
  478. );
  479. return;
  480. } // DumpLKRsList()
  481. DECLARE_API( lkrhash )
  482. /*++
  483. Routine Description:
  484. This function is called as an NTSD extension to format and dump
  485. an LKRhash table.
  486. Arguments:
  487. hCurrentProcess - Supplies a handle to the current process (at the
  488. time the extension was called).
  489. hCurrentThread - Supplies a handle to the current thread (at the
  490. time the extension was called).
  491. CurrentPc - Supplies the current pc at the time the extension is
  492. called.
  493. lpExtensionApis - Supplies the address of the functions callable
  494. by this extension.
  495. lpArgumentString - Supplies the asciiz string that describes the
  496. ansi string to be dumped.
  497. Return Value:
  498. None.
  499. --*/
  500. {
  501. INIT_API();
  502. ULONG_PTR lkrAddress = 0;
  503. INT nVerbose = 0;
  504. PSTR cmdName = "lkrhash";
  505. //
  506. // Skip leading blanks.
  507. //
  508. while( *lpArgumentString == ' ' ||
  509. *lpArgumentString == '\t' ) {
  510. lpArgumentString++;
  511. }
  512. if( *lpArgumentString == '\0' ) {
  513. PrintUsage( cmdName );
  514. return;
  515. }
  516. if ( *lpArgumentString == '-' )
  517. {
  518. lpArgumentString++;
  519. if ( *lpArgumentString == 'h' )
  520. {
  521. PrintUsage( cmdName );
  522. return;
  523. }
  524. if ( *lpArgumentString == 'l' ) {
  525. lpArgumentString++;
  526. if ('0' <= *lpArgumentString && *lpArgumentString <= '9' ) {
  527. nVerbose = *lpArgumentString++ - '0';
  528. }
  529. }
  530. if ( *lpArgumentString == 'v' )
  531. {
  532. lpArgumentString++;
  533. nVerbose = 99;
  534. }
  535. if ( *lpArgumentString == 'g' )
  536. {
  537. lpArgumentString++;
  538. DumpLKRsList(nVerbose);
  539. return;
  540. }
  541. }
  542. while( *lpArgumentString == ' ' ||
  543. *lpArgumentString == '\t' ) {
  544. lpArgumentString++;
  545. }
  546. lkrAddress = (ULONG_PTR) GetExpression( lpArgumentString );
  547. if (lkrAddress == 0) {
  548. dprintf(
  549. "inetdbg.%s: cannot evaluate \"%s\"\n",
  550. cmdName,
  551. lpArgumentString
  552. );
  553. return;
  554. }
  555. //
  556. // Skip to end of expression, then skip any blanks.
  557. //
  558. while( *lpArgumentString != ' ' &&
  559. *lpArgumentString != '\t' &&
  560. *lpArgumentString != '\0' ) {
  561. lpArgumentString++;
  562. }
  563. DWORD dwSig;
  564. if (!ReadMemory(lkrAddress, &dwSig, sizeof(dwSig), NULL) )
  565. {
  566. dprintf("inetdbg.%s: cannot read memory @ %p\n",
  567. cmdName, (PVOID)lkrAddress);
  568. goto cleanup;
  569. }
  570. if (dwSig == CLKRHashTable::SIGNATURE ||
  571. dwSig == CLKRHashTable::SIGNATURE_FREE)
  572. {
  573. EnumerateLKRhashTable(DefaultLKRhashEnum,
  574. (CLKRHashTable*) lkrAddress,
  575. nVerbose);
  576. }
  577. else if (dwSig == CLKRLinearHashTable::SIGNATURE ||
  578. dwSig == CLKRLinearHashTable::SIGNATURE_FREE)
  579. {
  580. EnumerateLKRLinearHashTable(DefaultLKRhashEnum,
  581. (CLKRLinearHashTable*) lkrAddress,
  582. nVerbose);
  583. }
  584. else
  585. {
  586. dprintf("inetdbg.%s: %p does not contain a valid LKRhash table\n",
  587. cmdName, (PVOID)lkrAddress);
  588. }
  589. cleanup:
  590. return;
  591. } // DECLARE_API( lkrhash )
  592. DECLARE_API( testhash )
  593. {
  594. INIT_API();
  595. ULONG_PTR lkrAddress = 0;
  596. INT nVerbose = 0;
  597. PSTR cmdName = "testhash";
  598. //
  599. // Skip leading blanks.
  600. //
  601. while( *lpArgumentString == ' ' ||
  602. *lpArgumentString == '\t' ) {
  603. lpArgumentString++;
  604. }
  605. if( *lpArgumentString == '\0' ) {
  606. PrintUsage( cmdName );
  607. return;
  608. }
  609. if ( *lpArgumentString == '-' )
  610. {
  611. lpArgumentString++;
  612. if ( *lpArgumentString == 'h' )
  613. {
  614. PrintUsage( cmdName );
  615. return;
  616. }
  617. if ( *lpArgumentString == 'l' ) {
  618. lpArgumentString++;
  619. if ('0' <= *lpArgumentString && *lpArgumentString <= '9' ) {
  620. nVerbose = *lpArgumentString++ - '0';
  621. }
  622. }
  623. }
  624. while( *lpArgumentString == ' ' ||
  625. *lpArgumentString == '\t' ) {
  626. lpArgumentString++;
  627. }
  628. lkrAddress = (ULONG_PTR)GetExpression( lpArgumentString );
  629. if( lkrAddress == 0 ) {
  630. dprintf(
  631. "inetdbg.%s: cannot evaluate \"%s\"\n",
  632. cmdName,
  633. lpArgumentString
  634. );
  635. return;
  636. }
  637. //
  638. // Skip to end of expression, then skip any blanks.
  639. //
  640. while( *lpArgumentString != ' ' &&
  641. *lpArgumentString != '\t' &&
  642. *lpArgumentString != '\0' ) {
  643. lpArgumentString++;
  644. }
  645. EnumerateLKRhashTable(TestEnum,
  646. (CLKRHashTable*) lkrAddress,
  647. nVerbose);
  648. } // DECLARE_API( testhash )