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.

762 lines
20 KiB

  1. /*++
  2. Copyright (c) 1995-1997 Microsoft Corporation
  3. Module Name :
  4. dbgatq.cxx
  5. Abstract:
  6. This module contains the NTSD Debugger extensions for the
  7. Asynchronous Thread Queue DLL
  8. Author:
  9. Murali R. Krishnan ( MuraliK ) 12-May-1997
  10. Environment:
  11. Debugger Mode - inside NT command line debuggers
  12. Project:
  13. Internet Server Debugging DLL
  14. Functions Exported:
  15. Revision History:
  16. --*/
  17. /************************************************************
  18. * Include Headers
  19. ************************************************************/
  20. #include "inetdbgp.h"
  21. /************************************************************
  22. * Definitions of Variables & Macros
  23. ************************************************************/
  24. //
  25. // Text names of ATQ_SOCK_STATE values
  26. //
  27. char * AtqSockState[] = {
  28. "ATQ_SOCK_CLOSED",
  29. "ATQ_SOCK_UNCONNECTED",
  30. "ATQ_SOCK_LISTENING",
  31. "ATQ_SOCK_CONNECTED"
  32. };
  33. char * AtqEndpointState[] = {
  34. "AtqStateInit",
  35. "AtqStateActive",
  36. "AtqStateClosed",
  37. "AtqStateMax",
  38. };
  39. #define LookupSockState( SockState ) \
  40. ((SockState) <= ATQ_SOCK_CONNECTED ? AtqSockState[ (SockState) ] :\
  41. "<Invalid>")
  42. /************************************************************
  43. * Functions
  44. ************************************************************/
  45. VOID
  46. DumpAtqGlobals(
  47. VOID
  48. );
  49. VOID
  50. DumpAtqContextList(
  51. CHAR Level,
  52. CHAR Verbosity,
  53. ATQ_ENDPOINT * pEndpointIn
  54. );
  55. void
  56. DumpEndpointList(
  57. LIST_ENTRY * pAtqClientHead,
  58. CHAR Level,
  59. DWORD * pcContext,
  60. BYTE * pvStart,
  61. BYTE * pvEnd,
  62. ATQ_ENDPOINT * pEndpointIn
  63. );
  64. VOID
  65. PrintAtqContext(
  66. ATQ_CONTEXT * AtqContext
  67. );
  68. void
  69. PrintEndpoint(
  70. ATQ_ENDPOINT * pEp
  71. );
  72. VOID
  73. DumpEndpoint(
  74. CHAR Level
  75. );
  76. DECLARE_API( atq )
  77. /*++
  78. Routine Description:
  79. This function is called as an NTSD extension to format and dump
  80. an object attributes structure.
  81. Arguments:
  82. hCurrentProcess - Supplies a handle to the current process (at the
  83. time the extension was called).
  84. hCurrentThread - Supplies a handle to the current thread (at the
  85. time the extension was called).
  86. CurrentPc - Supplies the current pc at the time the extension is
  87. called.
  88. lpExtensionApis - Supplies the address of the functions callable
  89. by this extension.
  90. lpArgumentString - Supplies the asciiz string that describes the
  91. ansi string to be dumped.
  92. Return Value:
  93. None.
  94. --*/
  95. {
  96. BOOL fRet;
  97. ATQ_CONTEXT AtqContext;
  98. ATQ_CONTEXT * pAtqContext;
  99. INIT_API();
  100. while (*lpArgumentString == ' ')
  101. lpArgumentString++;
  102. if ( !*lpArgumentString )
  103. {
  104. PrintUsage( "atq" );
  105. return;
  106. }
  107. if ( *lpArgumentString == '-' )
  108. {
  109. lpArgumentString++;
  110. switch ( *lpArgumentString ) {
  111. case 'g':
  112. {
  113. DumpAtqGlobals();
  114. break;
  115. }
  116. case 'c':
  117. {
  118. DumpAtqContextList( lpArgumentString[1],
  119. lpArgumentString[2],
  120. NULL );
  121. break;
  122. }
  123. case 'e':
  124. {
  125. ATQ_ENDPOINT * pEndpoint;
  126. // Arguments: -e<Level><Verbosity> <EndpointAddr>
  127. pEndpoint = ((ATQ_ENDPOINT * )
  128. GetExpression( lpArgumentString + 4));
  129. if ( !pEndpoint ) {
  130. dprintf( "inetdbg: Unable to evaluate "
  131. "EndpointAddr \"%s\"\n",
  132. lpArgumentString );
  133. break;
  134. }
  135. DumpAtqContextList( lpArgumentString[1],
  136. lpArgumentString[2],
  137. pEndpoint );
  138. break;
  139. }
  140. case 'l':
  141. {
  142. DumpEndpoint( lpArgumentString[1] );
  143. break;
  144. }
  145. case 'p':
  146. {
  147. //
  148. // Treat the argument as the address of an AtqEndpoint
  149. //
  150. ATQ_ENDPOINT * pEndpoint;
  151. // Arguments: -p <EndpointAddr>
  152. pEndpoint = ((ATQ_ENDPOINT *)
  153. GetExpression( lpArgumentString + 2 )
  154. );
  155. if ( !pEndpoint )
  156. {
  157. dprintf( "inetdbg: Unable to evaluate \"%s\"\n",
  158. lpArgumentString );
  159. break;
  160. }
  161. else
  162. {
  163. ATQ_ENDPOINT Endpoint;
  164. move( Endpoint, pEndpoint );
  165. PrintEndpoint( &Endpoint );
  166. }
  167. break;
  168. }
  169. default:
  170. case 'h':
  171. {
  172. PrintUsage( "atq" );
  173. break;
  174. }
  175. } // switch
  176. return;
  177. }
  178. //
  179. // Treat the argument as the address of an AtqContext
  180. //
  181. pAtqContext = (PATQ_CONT)GetExpression( lpArgumentString );
  182. if ( !pAtqContext )
  183. {
  184. dprintf( "inetdbg: Unable to evaluate \"%s\"\n",
  185. lpArgumentString );
  186. return;
  187. }
  188. move( AtqContext, pAtqContext );
  189. PrintAtqContext( &AtqContext );
  190. } // DECLARE_API( atq )
  191. /************************************************************
  192. * ATQ related functions
  193. ************************************************************/
  194. VOID
  195. DumpAtqGlobals(
  196. VOID
  197. )
  198. {
  199. //
  200. // Dump Atq Globals
  201. //
  202. dprintf("Atq Globals:\n");
  203. DumpDword( "isatq!g_cConcurrency " );
  204. DumpDword( "isatq!g_cThreads " );
  205. DumpDword( "isatq!g_cAvailableThreads " );
  206. DumpDword( "isatq!g_cMaxThreads " );
  207. dprintf("\n");
  208. DumpDword( "isatq!g_fUseAcceptEx " );
  209. DumpDword( "isatq!g_fUseTransmitFile " );
  210. DumpDword( "isatq!g_cbXmitBufferSize " );
  211. DumpDword( "isatq!g_cbMinKbSec " );
  212. DumpDword( "isatq!g_cCPU " );
  213. DumpDword( "isatq!g_fShutdown " );
  214. dprintf("\n");
  215. DumpDword( "isatq!g_msThreadTimeout " );
  216. DumpDword( "isatq!g_dwTimeoutCookie " );
  217. DumpDword( "isatq!g_cListenBacklog " );
  218. DumpDword( "isatq!AtqCurrentTick " );
  219. DumpDword( "isatq!AtqGlobalContextCount" );
  220. dprintf("\tsizeof(ATQ_CONTEXT) = %d\n", sizeof(ATQ_CONTEXT));
  221. return;
  222. } // DumpAtqGlobals()
  223. VOID
  224. DumpAtqContextList(
  225. CHAR Level,
  226. CHAR Verbosity,
  227. ATQ_ENDPOINT * pEndpointIn
  228. )
  229. {
  230. LIST_ENTRY AtqClientHead;
  231. LIST_ENTRY * pAtqClientHead;
  232. ATQ_CONTEXT * pAtqContext;
  233. ATQ_CONTEXT AtqContext;
  234. CHAR Symbol[256];
  235. DWORD cContext = 0;
  236. DWORD cc1;
  237. ATQ_CONTEXT_LISTHEAD * pAtqActiveContextList;
  238. ATQ_CONTEXT_LISTHEAD AtqActiveContextList[ATQ_NUM_CONTEXT_LIST];
  239. DWORD i;
  240. pAtqActiveContextList =
  241. (ATQ_CONTEXT_LISTHEAD *) GetExpression( "&isatq!AtqActiveContextList" );
  242. if ( !pAtqActiveContextList )
  243. {
  244. dprintf("Unable to get AtqActiveContextList symbol\n" );
  245. return;
  246. }
  247. if ( !ReadMemory( (LPVOID) pAtqActiveContextList,
  248. AtqActiveContextList,
  249. sizeof(AtqActiveContextList),
  250. NULL ))
  251. {
  252. dprintf("Unable to read AtqActiveContextList memory\n" );
  253. return;
  254. }
  255. for ( i = 0; i < ATQ_NUM_CONTEXT_LIST; i++ )
  256. {
  257. dprintf("================================================\n");
  258. dprintf("== Context List %d ==\n", i );
  259. dprintf("================================================\n");
  260. dprintf(" Active List ==>\n" );
  261. cc1 = 0;
  262. DumpEndpointList( &(AtqActiveContextList[i].ActiveListHead),
  263. Verbosity,
  264. &cc1,
  265. (BYTE *) pAtqActiveContextList,
  266. (BYTE *) &pAtqActiveContextList[ATQ_NUM_CONTEXT_LIST],
  267. pEndpointIn
  268. );
  269. if ( 0 != cc1) {
  270. dprintf( "\n\t%d Atq contexts traversed\n", cc1 );
  271. cContext += cc1;
  272. }
  273. if ( Level >= '1' )
  274. {
  275. dprintf("================================================\n");
  276. dprintf("Pending AcceptEx List\n");
  277. cc1 = 0;
  278. DumpEndpointList( &(AtqActiveContextList[i].PendingAcceptExListHead),
  279. Verbosity,
  280. &cc1,
  281. (BYTE *) pAtqActiveContextList,
  282. (BYTE *) &pAtqActiveContextList[ATQ_NUM_CONTEXT_LIST],
  283. pEndpointIn
  284. );
  285. if ( 0 != cc1) {
  286. dprintf( "\n\t%d Atq contexts traversed\n", cc1 );
  287. cContext += cc1;
  288. }
  289. }
  290. if ( CheckControlC() )
  291. {
  292. dprintf( "\n^C\n" );
  293. return;
  294. }
  295. }
  296. dprintf( "%d Atq contexts traversed\n",
  297. cContext );
  298. return;
  299. } // DumpAtqContextList()
  300. void
  301. DumpEndpointList(
  302. LIST_ENTRY * pAtqClientHead,
  303. CHAR Verbosity,
  304. DWORD * pcContext,
  305. BYTE * pvStart,
  306. BYTE * pvEnd,
  307. ATQ_ENDPOINT * pEndpointIn
  308. )
  309. {
  310. LIST_ENTRY * pEntry;
  311. ATQ_CONTEXT * pAtqContext;
  312. ATQ_CONTEXT AtqContext;
  313. //
  314. // the list head is embedded in a structure so the exit condition of the
  315. // loop is when the remote memory address ends up in the array memory
  316. //
  317. for ( pEntry = pAtqClientHead->Flink;
  318. !((BYTE *)pEntry >= pvStart && (BYTE *)pEntry <= pvEnd);
  319. )
  320. {
  321. if ( CheckControlC() )
  322. {
  323. return;
  324. }
  325. pAtqContext = CONTAINING_RECORD( pEntry,
  326. ATQ_CONTEXT,
  327. m_leTimeout );
  328. move( AtqContext, pAtqContext );
  329. // selectively print only the contexts that have a matching Endpoint
  330. if ( (pEndpointIn != NULL) &&
  331. (AtqContext.pEndpoint != pEndpointIn)
  332. ) {
  333. move( pEntry, &pEntry->Flink );
  334. continue;
  335. }
  336. (*pcContext)++;
  337. if ( AtqContext.Signature != ATQ_CONTEXT_SIGNATURE )
  338. {
  339. dprintf( "AtqContext(%08lp) signature %08lx doesn't"
  340. " match expected %08lx\n",
  341. pAtqContext,
  342. AtqContext.Signature,
  343. ATQ_CONTEXT_SIGNATURE
  344. );
  345. return;
  346. }
  347. if ( Verbosity >= '1' )
  348. {
  349. //
  350. // Print all
  351. //
  352. dprintf( "\nAtqContext at %08lp\n",
  353. pAtqContext );
  354. PrintAtqContext( &AtqContext );
  355. }
  356. else if ( Verbosity >= '0' )
  357. {
  358. //
  359. // Print all with one line summary info
  360. //
  361. dprintf( "hAsyncIO = %4lp, Flink = %08lp, Blink = %08lp,"
  362. " State = %8lx, Flags =%8lx\n",
  363. AtqContext.hAsyncIO,
  364. AtqContext.m_leTimeout.Blink,
  365. AtqContext.m_leTimeout.Flink,
  366. AtqContext.m_acState,
  367. AtqContext.m_acFlags
  368. );
  369. }
  370. move( pEntry, &pEntry->Flink );
  371. }
  372. } // DumpEndpointList()
  373. VOID
  374. PrintAtqContext(
  375. ATQ_CONTEXT * pContext
  376. )
  377. {
  378. UCHAR szSymFnCallback[MAX_SYMBOL_LEN];
  379. ULONG_PTR offset;
  380. GetSymbol((ULONG_PTR) pContext->pfnCompletion,
  381. szSymFnCallback, &offset);
  382. if (!*szSymFnCallback)
  383. sprintf((char*) szSymFnCallback, "%p()",
  384. pContext->pfnCompletion);
  385. dprintf( "\n" );
  386. dprintf( "\thAsyncIO = %08lp Signature = %08lx\n"
  387. "\tOverlapped.Internal = %08lp Overlapped.Offset= %08lx\n"
  388. "\tLE-Timeout.Flink = %08lp LE-Timeout.Blink = %p\n"
  389. "\tClientContext = %08lp ContextList = %p\n"
  390. "\tpfnIOCompletion = %s\n"
  391. "\tlSyncTimeout = %8d m_nIO = %8d\n"
  392. "\tTimeOut = %08lx NextTimeout = %08lx\n"
  393. "\tBytesSent = %d (0x%08lx)\n"
  394. "\tpvBuff = %08lp pEndPoint = %08lp\n"
  395. "\tState = %8lx Flags = %08lx\n",
  396. pContext->hAsyncIO, pContext->Signature,
  397. pContext->Overlapped.Internal,pContext->Overlapped.Offset,
  398. pContext->m_leTimeout.Flink, pContext->m_leTimeout.Blink,
  399. pContext->ClientContext, pContext->ContextList,
  400. szSymFnCallback,
  401. pContext->lSyncTimeout, pContext->m_nIO,
  402. pContext->TimeOut, pContext->NextTimeout,
  403. pContext->BytesSent, pContext->BytesSent,
  404. pContext->pvBuff, pContext->pEndpoint,
  405. pContext->m_acState, pContext->m_acFlags
  406. );
  407. // identify and print the various properties
  408. dprintf( "\t");
  409. // First print the state bits
  410. if ( pContext->m_acState & ACS_SOCK_CLOSED) {
  411. dprintf( " ACS_SOCK_CLOSED");
  412. }
  413. if ( pContext->m_acState & ACS_SOCK_UNCONNECTED) {
  414. dprintf( " ACS_SOCK_UNCONNECTED");
  415. }
  416. if ( pContext->m_acState & ACS_SOCK_LISTENING) {
  417. dprintf( " ACS_SOCK_LISTENING");
  418. }
  419. if ( pContext->m_acState & ACS_SOCK_CONNECTED) {
  420. dprintf( " ACS_SOCK_CONNECTED");
  421. }
  422. if ( pContext->m_acState & ACS_SOCK_TOBE_FREED) {
  423. dprintf( " ACS_SOCK_TOBE_FREED");
  424. }
  425. // now print the flags associated with this context
  426. if ( pContext->m_acFlags & ACF_ACCEPTEX_ROOT_CONTEXT) {
  427. dprintf( " ACCEPTEX_CONTEXT");
  428. }
  429. if ( pContext->m_acFlags & ACF_CONN_INDICATED) {
  430. dprintf( " CONNECTION_INDICATED");
  431. }
  432. if ( pContext->m_acFlags & ACF_IN_TIMEOUT) {
  433. dprintf( " IN_TIMEOUT");
  434. }
  435. if ( pContext->m_acFlags & ACF_BLOCKED) {
  436. dprintf( " BLOCKED_BY_BWT");
  437. }
  438. if ( pContext->m_acFlags & ACF_REUSE_CONTEXT) {
  439. dprintf( " REUSE_CONTEXT");
  440. }
  441. if ( pContext->m_acFlags & ACF_RECV_ISSUED) {
  442. dprintf( " RECV_ISSUED");
  443. }
  444. if ( pContext->m_acFlags & ACF_ABORTIVE_CLOSE) {
  445. dprintf( " ABORTIVE_CLOSE");
  446. }
  447. dprintf( "\n");
  448. if ( pContext->IsFlag( ACF_ACCEPTEX_ROOT_CONTEXT) && pContext->pvBuff )
  449. {
  450. //
  451. // This size should correspond to the MIN_SOCKADDR_SIZE field in
  452. // atqnew.c. We assume it's two thirty two byte values currently.
  453. //
  454. DWORD AddrInfo[16];
  455. ATQ_ENDPOINT * pEndpoint = pContext->pEndpoint;
  456. ATQ_ENDPOINT Endpoint;
  457. move( Endpoint, pEndpoint );
  458. if ( ReadMemory( (LPVOID) ((BYTE *) pContext->pvBuff +
  459. Endpoint.InitialRecvSize +
  460. 2 * MIN_SOCKADDR_SIZE -
  461. sizeof( AddrInfo )),
  462. AddrInfo,
  463. sizeof(AddrInfo),
  464. NULL ))
  465. {
  466. dprintf( "\tLocal/Remote Addr = %08x %08x %08x %08x\n"
  467. "\t %08x %08x %08x %08x\n"
  468. "\t %08x %08x %08x %08x\n"
  469. "\t %08x %08x %08x %08x\n",
  470. AddrInfo[0],
  471. AddrInfo[1],
  472. AddrInfo[2],
  473. AddrInfo[3],
  474. AddrInfo[4],
  475. AddrInfo[5],
  476. AddrInfo[6],
  477. AddrInfo[7],
  478. AddrInfo[8],
  479. AddrInfo[9],
  480. AddrInfo[10],
  481. AddrInfo[11],
  482. AddrInfo[12],
  483. AddrInfo[13],
  484. AddrInfo[14],
  485. AddrInfo[15] );
  486. }
  487. }
  488. } // PrintAtqContext()
  489. VOID
  490. DumpEndpoint(
  491. CHAR Verbosity
  492. )
  493. {
  494. LIST_ENTRY AtqEndpointList;
  495. LIST_ENTRY * pAtqEndpointList;
  496. LIST_ENTRY * pEntry;
  497. ATQ_CONTEXT * pAtqContext;
  498. ATQ_CONTEXT AtqContext;
  499. CHAR Symbol[256];
  500. DWORD cEndp = 0;
  501. DWORD i;
  502. ATQ_ENDPOINT * pEndpoint;
  503. ATQ_ENDPOINT Endpoint;
  504. pAtqEndpointList = (LIST_ENTRY *) GetExpression( "&isatq!AtqEndpointList" );
  505. if ( !pAtqEndpointList )
  506. {
  507. dprintf("Unable to get AtqEndpointList symbol\n" );
  508. return;
  509. }
  510. move( AtqEndpointList, pAtqEndpointList );
  511. for ( pEntry = AtqEndpointList.Flink;
  512. pEntry != pAtqEndpointList;
  513. cEndp++
  514. )
  515. {
  516. if ( CheckControlC() )
  517. {
  518. return;
  519. }
  520. pEndpoint = CONTAINING_RECORD( pEntry,
  521. ATQ_ENDPOINT,
  522. ListEntry );
  523. move( Endpoint, pEndpoint );
  524. if ( Endpoint.Signature != ATQ_ENDPOINT_SIGNATURE )
  525. {
  526. dprintf( "Endpoint(%08p) signature %08lx doesn't match expected %08lx\n",
  527. pEndpoint,
  528. Endpoint.Signature,
  529. ATQ_ENDPOINT_SIGNATURE
  530. );
  531. break;
  532. }
  533. if ( Verbosity >= '1' )
  534. {
  535. //
  536. // Print all
  537. //
  538. dprintf( "\nEndpoint at %08lp\n",
  539. pEndpoint );
  540. PrintEndpoint( &Endpoint );
  541. }
  542. else if ( Verbosity >= '0' )
  543. {
  544. //
  545. // Print all with one line summary info
  546. //
  547. dprintf( "sListenSocket = %4lp, cRef = %d, cSocketsAvail = %d\n",
  548. Endpoint.ListenSocket,
  549. Endpoint.m_refCount,
  550. Endpoint.nSocketsAvail );
  551. }
  552. move( pEntry, &pEntry->Flink );
  553. }
  554. dprintf( "%d Atq Endpoints traversed\n",
  555. cEndp );
  556. return;
  557. } // DumpEndpoint()
  558. void
  559. PrintEndpoint(
  560. ATQ_ENDPOINT * pEp
  561. )
  562. {
  563. dprintf( "\tcRef = %8d State = %s\n"
  564. "\tIP Address = %s Port = %04x\n"
  565. "\tsListenSocket = %8p InitRecvSize = %04x\n"
  566. "\tnSocketsAvail = %8d nAvailAtTimeout = %d\n"
  567. "\tnAcceptExOutstdg =%8d\n"
  568. "\tUseAcceptEx = %8s AcceptExTimeout = %8d\n"
  569. "\tEnableBw Throttle= %s\n"
  570. "\tListEntry.Flink = %08lp ListEntry.Blink = %08lp\n"
  571. "\tClient Context = %08lp pfnCompletion = %08lp()\n"
  572. "\tpfnConnComp = %08lp() pfnConnExComp = %08lp()\n"
  573. "\tShutDownCallback = %08lp() ShutDown Context = %08lp\n"
  574. ,
  575. pEp->m_refCount,
  576. AtqEndpointState[pEp->State],
  577. pEp->IpAddress,
  578. pEp->Port,
  579. pEp->ListenSocket,
  580. pEp->InitialRecvSize,
  581. pEp->nSocketsAvail,
  582. pEp->nAvailDuringTimeOut,
  583. pEp->nAcceptExOutstanding,
  584. BoolValue( pEp->UseAcceptEx),
  585. pEp->AcceptExTimeout,
  586. BoolValue( pEp->EnableBw),
  587. pEp->ListEntry.Flink,
  588. pEp->ListEntry.Blink,
  589. pEp->Context,
  590. pEp->IoCompletion,
  591. pEp->ConnectCompletion,
  592. pEp->ConnectExCompletion,
  593. pEp->ShutdownCallback,
  594. pEp->ShutdownCallbackContext
  595. );
  596. return;
  597. } // PrintEndpoint()
  598. /************************ End of File ***********************/
  599.