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.

781 lines
16 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Debug.c
  5. Abstract:
  6. This module declares the Debug only code used by the NetWare redirector
  7. file system.
  8. Author:
  9. Colin Watson [ColinW] 05-Jan-1993
  10. Revision History:
  11. --*/
  12. #include "procs.h"
  13. #include <stdio.h>
  14. #include <stdarg.h>
  15. #define LINE_SIZE 511
  16. #define BUFFER_LINES 50
  17. #ifdef NWDBG
  18. #include <stdlib.h> // rand()
  19. int FailAllocateMdl = 0;
  20. ULONG MaxDump = 256;
  21. CHAR DBuffer[BUFFER_LINES*LINE_SIZE+1];
  22. PCHAR DBufferPtr = DBuffer;
  23. //
  24. // The reference count debug buffer.
  25. //
  26. CHAR RBuffer[BUFFER_LINES*LINE_SIZE+1];
  27. PCHAR RBufferPtr = RBuffer;
  28. LIST_ENTRY MdlList;
  29. VOID
  30. HexDumpLine (
  31. PCHAR pch,
  32. ULONG len,
  33. PCHAR s,
  34. PCHAR t,
  35. USHORT flag
  36. );
  37. ULONG
  38. NwMemDbg (
  39. IN PCH Format,
  40. ...
  41. )
  42. //++
  43. //
  44. // Routine Description:
  45. //
  46. // Effectively DbgPrint to the debugging console.
  47. //
  48. // Arguments:
  49. //
  50. // Same as for DbgPrint
  51. //
  52. //--
  53. {
  54. va_list arglist;
  55. int Length;
  56. //
  57. // Format the output into a buffer and then print it.
  58. //
  59. va_start(arglist, Format);
  60. Length = _vsnprintf(DBufferPtr, LINE_SIZE, Format, arglist);
  61. if (Length < 0) {
  62. DbgPrint( "NwRdr: Message is too long for NwMemDbg\n");
  63. return 0;
  64. }
  65. va_end(arglist);
  66. ASSERT( Length <= LINE_SIZE );
  67. ASSERT( Length != 0 );
  68. ASSERT( DBufferPtr < &DBuffer[BUFFER_LINES*LINE_SIZE+1]);
  69. ASSERT( DBufferPtr >= DBuffer);
  70. DBufferPtr += Length;
  71. DBufferPtr[0] = '\0';
  72. // Avoid running off the end of the buffer and exit
  73. if (DBufferPtr >= (DBuffer+((BUFFER_LINES-1) * LINE_SIZE))) {
  74. DBufferPtr = DBuffer;
  75. }
  76. return 0;
  77. }
  78. VOID
  79. RefDbgTrace (
  80. PVOID Resource,
  81. DWORD Count,
  82. BOOLEAN Reference,
  83. PBYTE FileName,
  84. UINT Line
  85. )
  86. /**
  87. Routine Description:
  88. NwRefDebug logs reference count operations to expose
  89. reference count errors or leaks in the redirector.
  90. Arguments:
  91. Resource - The object we're adjusting the reference count on.
  92. Count - The current count on the object.
  93. Reference - If TRUE we are doing a REFERENCE.
  94. Otherwise, we are doing a DEREFERENCE.
  95. FileName - The callers file name.
  96. Line - The callers line number.
  97. **/
  98. {
  99. int Length;
  100. int NextCount;
  101. //
  102. // Format the output into a buffer and then print it.
  103. //
  104. if ( Reference )
  105. NextCount = Count + 1;
  106. else
  107. NextCount = Count - 1;
  108. Length = sprintf( RBufferPtr,
  109. "%p: R=%p, %lu -> %lu (%s, line %d)\n",
  110. (PVOID)PsGetCurrentThread(),
  111. Resource,
  112. Count,
  113. NextCount,
  114. FileName,
  115. Line );
  116. if (Length < 0) {
  117. DbgPrint( "NwRdr: Message is too long for NwRefDbg\n");
  118. return;
  119. }
  120. ASSERT( Length <= LINE_SIZE );
  121. ASSERT( Length != 0 );
  122. ASSERT( RBufferPtr < &RBuffer[BUFFER_LINES*LINE_SIZE+1]);
  123. ASSERT( RBufferPtr >= RBuffer);
  124. RBufferPtr += Length;
  125. RBufferPtr[0] = '\0';
  126. // Avoid running off the end of the buffer and exit
  127. if (RBufferPtr >= (RBuffer+((BUFFER_LINES-1) * LINE_SIZE))) {
  128. RBufferPtr = RBuffer;
  129. }
  130. return;
  131. }
  132. VOID
  133. RealDebugTrace(
  134. LONG Indent,
  135. ULONG Level,
  136. PCH Message,
  137. PVOID Parameter
  138. )
  139. /*++
  140. Routine Description:
  141. Arguments:
  142. Return Value:
  143. None.
  144. --*/
  145. {
  146. if ( (Level == 0) || (NwMemDebug & Level )) {
  147. NwMemDbg( Message, PsGetCurrentThread(), 1, "", Parameter );
  148. }
  149. if ( (Level == 0) || (NwDebug & Level )) {
  150. if ( Indent < 0) {
  151. NwDebugTraceIndent += Indent;
  152. }
  153. DbgPrint( Message, PsGetCurrentThread(), NwDebugTraceIndent, "", Parameter );
  154. if ( Indent > 0) {
  155. NwDebugTraceIndent += Indent;
  156. }
  157. if (NwDebugTraceIndent < 0) {
  158. NwDebugTraceIndent = 0;
  159. }
  160. }
  161. }
  162. VOID
  163. dump(
  164. IN ULONG Level,
  165. IN PVOID far_p,
  166. IN ULONG len
  167. )
  168. /*++
  169. Routine Description:
  170. Dump Min(len, MaxDump) bytes in classic hex dump style if debug
  171. output is turned on for this level.
  172. Arguments:
  173. IN Level - 0 if always display. Otherwise only display if a
  174. corresponding bit is set in NwDebug.
  175. IN far_p - address of buffer to start dumping from.
  176. IN len - length in bytes of buffer.
  177. Return Value:
  178. None.
  179. --*/
  180. {
  181. ULONG l;
  182. char s[80], t[80];
  183. PCHAR far_pchar = (PCHAR)far_p;
  184. if ( (Level == 0) || (NwDebug & Level )) {
  185. if (len > MaxDump)
  186. len = MaxDump;
  187. while (len) {
  188. l = len < 16 ? len : 16;
  189. DbgPrint("\n%lx ", far_pchar);
  190. HexDumpLine (far_pchar, l, s, t, 0);
  191. DbgPrint("%s%.*s%s", s, 1 + ((16 - l) * 3), "", t);
  192. NwMemDbg ( "%lx: %s%.*s%s\n",
  193. far_pchar, s, 1 + ((16 - l) * 3), "", t);
  194. len -= l;
  195. far_pchar += l;
  196. }
  197. DbgPrint("\n");
  198. }
  199. }
  200. VOID
  201. dumpMdl(
  202. IN ULONG Level,
  203. IN PMDL Mdl
  204. )
  205. /*++
  206. Routine Description:
  207. Dump the memory described by each part of a chained Mdl.
  208. Arguments:
  209. IN Level - 0 if always display. Otherwise only display if a
  210. corresponding bit is set in NwDebug.
  211. Mdl - Supplies the addresses of the memory to be dumped.
  212. Return Value:
  213. None.
  214. --*/
  215. {
  216. PMDL Next;
  217. ULONG len;
  218. if ( (Level == 0) || (NwDebug & Level )) {
  219. Next = Mdl; len = 0;
  220. do {
  221. dump(Level, MmGetSystemAddressForMdlSafe(Next, LowPagePriority), MIN(MmGetMdlByteCount(Next), MaxDump-len));
  222. len += MmGetMdlByteCount(Next);
  223. } while ( (Next = Next->Next) != NULL &&
  224. len <= MaxDump);
  225. }
  226. }
  227. VOID
  228. HexDumpLine (
  229. PCHAR pch,
  230. ULONG len,
  231. PCHAR s,
  232. PCHAR t,
  233. USHORT flag
  234. )
  235. {
  236. static UCHAR rghex[] = "0123456789ABCDEF";
  237. UCHAR c;
  238. UCHAR *hex, *asc;
  239. hex = s;
  240. asc = t;
  241. *(asc++) = '*';
  242. while (len--) {
  243. c = *(pch++);
  244. *(hex++) = rghex [c >> 4] ;
  245. *(hex++) = rghex [c & 0x0F];
  246. *(hex++) = ' ';
  247. *(asc++) = (c < ' ' || c > '~') ? (CHAR )'.' : c;
  248. }
  249. *(asc++) = '*';
  250. *asc = 0;
  251. *hex = 0;
  252. flag;
  253. }
  254. typedef struct _NW_POOL_HEADER {
  255. ULONG Signature;
  256. ULONG BufferSize;
  257. ULONG BufferType;
  258. LIST_ENTRY ListEntry;
  259. ULONG Pad; // Pad to Q-word align
  260. } NW_POOL_HEADER, *PNW_POOL_HEADER;
  261. typedef struct _NW_POOL_TRAILER {
  262. ULONG Signature;
  263. } NW_POOL_TRAILER;
  264. typedef NW_POOL_TRAILER UNALIGNED *PNW_POOL_TRAILER;
  265. PVOID
  266. NwAllocatePool(
  267. ULONG Type,
  268. ULONG Size,
  269. BOOLEAN RaiseStatus
  270. )
  271. {
  272. PCHAR Buffer;
  273. PNW_POOL_HEADER PoolHeader;
  274. PNW_POOL_TRAILER PoolTrailer;
  275. if ( RaiseStatus ) {
  276. Buffer = FsRtlAllocatePoolWithTag(
  277. Type,
  278. sizeof( NW_POOL_HEADER ) + sizeof( NW_POOL_TRAILER ) + Size,
  279. 'scwn' );
  280. } else {
  281. #ifndef QFE_BUILD
  282. Buffer = ExAllocatePoolWithTag(
  283. Type,
  284. sizeof( NW_POOL_HEADER )+sizeof( NW_POOL_TRAILER )+Size,
  285. 'scwn' );
  286. #else
  287. Buffer = ExAllocatePool(
  288. Type,
  289. sizeof( NW_POOL_HEADER )+sizeof( NW_POOL_TRAILER )+Size );
  290. #endif
  291. if ( Buffer == NULL ) {
  292. return( NULL );
  293. }
  294. }
  295. PoolHeader = (PNW_POOL_HEADER)Buffer;
  296. PoolTrailer = (PNW_POOL_TRAILER)(Buffer + sizeof( NW_POOL_HEADER ) + Size);
  297. PoolHeader->Signature = 0x11111111;
  298. PoolHeader->BufferSize = Size;
  299. PoolHeader->BufferType = Type;
  300. PoolTrailer->Signature = 0x99999999;
  301. if ( Type == PagedPool ) {
  302. ExAcquireResourceExclusive( &NwDebugResource, TRUE );
  303. InsertTailList( &NwPagedPoolList, &PoolHeader->ListEntry );
  304. ExReleaseResource( &NwDebugResource );
  305. } else if ( Type == NonPagedPool ) {
  306. ExInterlockedInsertTailList( &NwNonpagedPoolList, &PoolHeader->ListEntry, &NwDebugInterlock );
  307. } else {
  308. KeBugCheck( RDR_FILE_SYSTEM );
  309. }
  310. return( Buffer + sizeof( NW_POOL_HEADER ) );
  311. }
  312. VOID
  313. NwFreePool(
  314. PVOID Buffer
  315. )
  316. {
  317. PNW_POOL_HEADER PoolHeader;
  318. PNW_POOL_TRAILER PoolTrailer;
  319. KIRQL OldIrql;
  320. PoolHeader = (PNW_POOL_HEADER)((PCHAR)Buffer - sizeof( NW_POOL_HEADER ));
  321. ASSERT( PoolHeader->Signature == 0x11111111 );
  322. ASSERT( PoolHeader->BufferType == PagedPool ||
  323. PoolHeader->BufferType == NonPagedPool );
  324. PoolTrailer = (PNW_POOL_TRAILER)((PCHAR)Buffer + PoolHeader->BufferSize );
  325. ASSERT( PoolTrailer->Signature == 0x99999999 );
  326. if ( PoolHeader->BufferType == PagedPool ) {
  327. ExAcquireResourceExclusive( &NwDebugResource, TRUE );
  328. RemoveEntryList( &PoolHeader->ListEntry );
  329. ExReleaseResource( &NwDebugResource );
  330. } else {
  331. KeAcquireSpinLock( &NwDebugInterlock, &OldIrql );
  332. RemoveEntryList( &PoolHeader->ListEntry );
  333. KeReleaseSpinLock( &NwDebugInterlock, OldIrql );
  334. }
  335. ExFreePool( PoolHeader );
  336. }
  337. //
  338. // Debug functions for allocating and deallocating IRPs and MDLs
  339. //
  340. PIRP
  341. NwAllocateIrp(
  342. CCHAR Size,
  343. BOOLEAN ChargeQuota
  344. )
  345. {
  346. ExInterlockedIncrementLong( &IrpCount, &NwDebugInterlock );
  347. return IoAllocateIrp( Size, ChargeQuota );
  348. }
  349. VOID
  350. NwFreeIrp(
  351. PIRP Irp
  352. )
  353. {
  354. ExInterlockedDecrementLong( &IrpCount, &NwDebugInterlock );
  355. IoFreeIrp( Irp );
  356. }
  357. typedef struct _NW_MDL {
  358. LIST_ENTRY Next;
  359. PUCHAR File;
  360. int Line;
  361. PMDL pMdl;
  362. } NW_MDL, *PNW_MDL;
  363. //int DebugLine = 2461;
  364. PMDL
  365. NwAllocateMdl(
  366. PVOID Va,
  367. ULONG Length,
  368. BOOLEAN Secondary,
  369. BOOLEAN ChargeQuota,
  370. PIRP Irp,
  371. PUCHAR FileName,
  372. int Line
  373. )
  374. {
  375. PNW_MDL Buffer;
  376. static BOOLEAN MdlSetup = FALSE;
  377. if (MdlSetup == FALSE) {
  378. InitializeListHead( &MdlList );
  379. MdlSetup = TRUE;
  380. }
  381. if ( FailAllocateMdl != 0 ) {
  382. if ( ( rand() % FailAllocateMdl ) == 0 ) {
  383. return(NULL);
  384. }
  385. }
  386. #ifndef QFE_BUILD
  387. Buffer = ExAllocatePoolWithTag(
  388. NonPagedPool,
  389. sizeof( NW_MDL),
  390. 'scwn' );
  391. #else
  392. Buffer = ExAllocatePool(
  393. NonPagedPool,
  394. sizeof( NW_MDL));
  395. #endif
  396. if ( Buffer == NULL ) {
  397. return( NULL );
  398. }
  399. ExInterlockedIncrementLong( &MdlCount, &NwDebugInterlock );
  400. Buffer->File = FileName;
  401. Buffer->Line = Line;
  402. Buffer->pMdl = IoAllocateMdl( Va, Length, Secondary, ChargeQuota, Irp );
  403. ExInterlockedInsertTailList( &MdlList, &Buffer->Next, &NwDebugInterlock );
  404. /*
  405. if (DebugLine == Line) {
  406. DebugTrace( 0, DEBUG_TRACE_MDL, "AllocateMdl -> %08lx\n", Buffer->pMdl );
  407. DebugTrace( 0, DEBUG_TRACE_MDL, "AllocateMdl -> %08lx\n", Line );
  408. }
  409. */
  410. return(Buffer->pMdl);
  411. }
  412. VOID
  413. NwFreeMdl(
  414. PMDL Mdl
  415. )
  416. {
  417. PLIST_ENTRY MdlEntry;
  418. PNW_MDL Buffer;
  419. KIRQL OldIrql;
  420. ExInterlockedDecrementLong( &MdlCount, &NwDebugInterlock );
  421. KeAcquireSpinLock( &NwDebugInterlock, &OldIrql );
  422. // Find the Mdl in the list and remove it.
  423. for (MdlEntry = MdlList.Flink ;
  424. MdlEntry != &MdlList ;
  425. MdlEntry = MdlEntry->Flink ) {
  426. Buffer = CONTAINING_RECORD( MdlEntry, NW_MDL, Next );
  427. if (Buffer->pMdl == Mdl) {
  428. RemoveEntryList( &Buffer->Next );
  429. KeReleaseSpinLock( &NwDebugInterlock, OldIrql );
  430. IoFreeMdl( Mdl );
  431. DebugTrace( 0, DEBUG_TRACE_MDL, "FreeMDL - %08lx\n", Mdl );
  432. /*
  433. if (DebugLine == Buffer->Line) {
  434. DebugTrace( 0, DEBUG_TRACE_MDL, "FreeMdl -> %08lx\n", Mdl );
  435. DebugTrace( 0, DEBUG_TRACE_MDL, "FreeMdl -> %08lx\n", Buffer->Line );
  436. }
  437. */
  438. ExFreePool(Buffer);
  439. return;
  440. }
  441. }
  442. ASSERT( FALSE );
  443. KeReleaseSpinLock( &NwDebugInterlock, OldIrql );
  444. }
  445. /*
  446. VOID
  447. NwLookForMdl(
  448. )
  449. {
  450. PLIST_ENTRY MdlEntry;
  451. PNW_MDL Buffer;
  452. KIRQL OldIrql;
  453. KeAcquireSpinLock( &NwDebugInterlock, &OldIrql );
  454. // Find the Mdl in the list and remove it.
  455. for (MdlEntry = MdlList.Flink ;
  456. MdlEntry != &MdlList ;
  457. MdlEntry = MdlEntry->Flink ) {
  458. Buffer = CONTAINING_RECORD( MdlEntry, NW_MDL, Next );
  459. if (Buffer->Line == DebugLine) {
  460. DebugTrace( 0, DEBUG_TRACE_MDL, "LookForMdl -> %08lx\n", Buffer );
  461. DbgBreakPoint();
  462. }
  463. }
  464. KeReleaseSpinLock( &NwDebugInterlock, OldIrql );
  465. }
  466. */
  467. //
  468. // Function version of resource macro, to make debugging easier.
  469. //
  470. VOID
  471. NwAcquireExclusiveRcb(
  472. PRCB Rcb,
  473. BOOLEAN Wait )
  474. {
  475. ExAcquireResourceExclusive( &((Rcb)->Resource), Wait );
  476. }
  477. VOID
  478. NwAcquireSharedRcb(
  479. PRCB Rcb,
  480. BOOLEAN Wait )
  481. {
  482. ExAcquireResourceShared( &((Rcb)->Resource), Wait );
  483. }
  484. VOID
  485. NwReleaseRcb(
  486. PRCB Rcb )
  487. {
  488. ExReleaseResource( &((Rcb)->Resource) );
  489. }
  490. VOID
  491. NwAcquireExclusiveFcb(
  492. PNONPAGED_FCB pFcb,
  493. BOOLEAN Wait )
  494. {
  495. ExAcquireResourceExclusive( &((pFcb)->Resource), Wait );
  496. }
  497. VOID
  498. NwAcquireSharedFcb(
  499. PNONPAGED_FCB pFcb,
  500. BOOLEAN Wait )
  501. {
  502. ExAcquireResourceShared( &((pFcb)->Resource), Wait );
  503. }
  504. VOID
  505. NwReleaseFcb(
  506. PNONPAGED_FCB pFcb )
  507. {
  508. ExReleaseResource( &((pFcb)->Resource) );
  509. }
  510. VOID
  511. NwAcquireOpenLock(
  512. VOID
  513. )
  514. {
  515. ExAcquireResourceExclusive( &NwOpenResource, TRUE );
  516. }
  517. VOID
  518. NwReleaseOpenLock(
  519. VOID
  520. )
  521. {
  522. ExReleaseResource( &NwOpenResource );
  523. }
  524. //
  525. // code to dump ICBs
  526. //
  527. VOID DumpIcbs(VOID)
  528. {
  529. PVCB Vcb;
  530. PFCB Fcb;
  531. PICB Icb;
  532. PLIST_ENTRY VcbListEntry;
  533. PLIST_ENTRY FcbListEntry;
  534. PLIST_ENTRY IcbListEntry;
  535. KIRQL OldIrql;
  536. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  537. KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
  538. DbgPrint("\nICB Pid State Scb/Fcb Name\n", 0);
  539. for ( VcbListEntry = GlobalVcbList.Flink;
  540. VcbListEntry != &GlobalVcbList ;
  541. VcbListEntry = VcbListEntry->Flink ) {
  542. Vcb = CONTAINING_RECORD( VcbListEntry, VCB, GlobalVcbListEntry );
  543. for ( FcbListEntry = Vcb->FcbList.Flink;
  544. FcbListEntry != &(Vcb->FcbList) ;
  545. FcbListEntry = FcbListEntry->Flink ) {
  546. Fcb = CONTAINING_RECORD( FcbListEntry, FCB, FcbListEntry );
  547. for ( IcbListEntry = Fcb->IcbList.Flink;
  548. IcbListEntry != &(Fcb->IcbList) ;
  549. IcbListEntry = IcbListEntry->Flink ) {
  550. Icb = CONTAINING_RECORD( IcbListEntry, ICB, ListEntry );
  551. DbgPrint("%08lx", Icb);
  552. DbgPrint(" %08lx",(DWORD)Icb->Pid);
  553. DbgPrint(" %08lx",Icb->State);
  554. DbgPrint(" %08lx",Icb->SuperType.Scb);
  555. DbgPrint(" %wZ\n",
  556. &(Icb->FileObject->FileName) );
  557. }
  558. }
  559. }
  560. KeReleaseSpinLock( &ScbSpinLock, OldIrql );
  561. NwReleaseRcb( &NwRcb );
  562. }
  563. #endif // ifdef NWDBG
  564. //
  565. // Ref counting debug routines.
  566. //
  567. #ifdef NWDBG
  568. VOID
  569. ChkNwReferenceScb(
  570. PNONPAGED_SCB pNpScb,
  571. PBYTE FileName,
  572. UINT Line,
  573. BOOLEAN Silent
  574. ) {
  575. if ( (pNpScb)->NodeTypeCode != NW_NTC_SCBNP ) {
  576. DbgBreakPoint();
  577. }
  578. if ( !Silent) {
  579. RefDbgTrace( pNpScb, pNpScb->Reference, TRUE, FileName, Line );
  580. }
  581. ExInterlockedIncrementLong( &(pNpScb)->Reference, &(pNpScb)->NpScbInterLock );
  582. }
  583. VOID
  584. ChkNwDereferenceScb(
  585. PNONPAGED_SCB pNpScb,
  586. PBYTE FileName,
  587. UINT Line,
  588. BOOLEAN Silent
  589. ) {
  590. if ( (pNpScb)->Reference == 0 ) {
  591. DbgBreakPoint();
  592. }
  593. if ( (pNpScb)->NodeTypeCode != NW_NTC_SCBNP ) {
  594. DbgBreakPoint();
  595. }
  596. if ( !Silent ) {
  597. RefDbgTrace( pNpScb, pNpScb->Reference, FALSE, FileName, Line );
  598. }
  599. ExInterlockedDecrementLong( &(pNpScb)->Reference, &(pNpScb)->NpScbInterLock );
  600. }
  601. #endif