summaryrefslogtreecommitdiffstats
path: root/private/nw/rdr/debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/rdr/debug.c')
-rw-r--r--private/nw/rdr/debug.c780
1 files changed, 780 insertions, 0 deletions
diff --git a/private/nw/rdr/debug.c b/private/nw/rdr/debug.c
new file mode 100644
index 000000000..52e356300
--- /dev/null
+++ b/private/nw/rdr/debug.c
@@ -0,0 +1,780 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ Debug.c
+
+Abstract:
+
+ This module declares the Debug only code used by the NetWare redirector
+ file system.
+
+Author:
+
+ Colin Watson [ColinW] 05-Jan-1993
+
+Revision History:
+
+--*/
+#include "procs.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+#define LINE_SIZE 511
+#define BUFFER_LINES 50
+
+
+#ifdef NWDBG
+
+#include <stdlib.h> // rand()
+int FailAllocateMdl = 0;
+
+ULONG MaxDump = 256;
+CHAR DBuffer[BUFFER_LINES*LINE_SIZE+1];
+PCHAR DBufferPtr = DBuffer;
+
+//
+// The reference count debug buffer.
+//
+
+CHAR RBuffer[BUFFER_LINES*LINE_SIZE+1];
+PCHAR RBufferPtr = RBuffer;
+
+LIST_ENTRY MdlList;
+
+VOID
+HexDumpLine (
+ PCHAR pch,
+ ULONG len,
+ PCHAR s,
+ PCHAR t,
+ USHORT flag
+ );
+
+ULONG
+NwMemDbg (
+ IN PCH Format,
+ ...
+ )
+
+//++
+//
+// Routine Description:
+//
+// Effectively DbgPrint to the debugging console.
+//
+// Arguments:
+//
+// Same as for DbgPrint
+//
+//--
+
+{
+ va_list arglist;
+ int Length;
+
+ //
+ // Format the output into a buffer and then print it.
+ //
+
+ va_start(arglist, Format);
+
+ Length = _vsnprintf(DBufferPtr, LINE_SIZE, Format, arglist);
+
+ if (Length < 0) {
+ DbgPrint( "NwRdr: Message is too long for NwMemDbg\n");
+ return 0;
+ }
+
+ va_end(arglist);
+
+ ASSERT( Length <= LINE_SIZE );
+ ASSERT( Length != 0 );
+ ASSERT( DBufferPtr < &DBuffer[BUFFER_LINES*LINE_SIZE+1]);
+ ASSERT( DBufferPtr >= DBuffer);
+
+ DBufferPtr += Length;
+ DBufferPtr[0] = '\0';
+
+ // Avoid running off the end of the buffer and exit
+
+ if (DBufferPtr >= (DBuffer+((BUFFER_LINES-1) * LINE_SIZE))) {
+ DBufferPtr = DBuffer;
+
+ }
+
+ return 0;
+}
+
+VOID
+RefDbgTrace (
+ PVOID Resource,
+ DWORD Count,
+ BOOLEAN Reference,
+ PBYTE FileName,
+ UINT Line
+)
+/**
+
+ Routine Description:
+
+ NwRefDebug logs reference count operations to expose
+ reference count errors or leaks in the redirector.
+
+ Arguments:
+
+ Resource - The object we're adjusting the reference count on.
+ Count - The current count on the object.
+ Reference - If TRUE we are doing a REFERENCE.
+ Otherwise, we are doing a DEREFERENCE.
+ FileName - The callers file name.
+ Line - The callers line number.
+
+**/
+{
+ int Length;
+ int NextCount;
+
+ //
+ // Format the output into a buffer and then print it.
+ //
+
+ if ( Reference )
+ NextCount = Count + 1;
+ else
+ NextCount = Count - 1;
+
+ Length = sprintf( RBufferPtr,
+ "%08lx: R=%08lx, %lu -> %lu (%s, line %d)\n",
+ (PVOID)PsGetCurrentThread(),
+ Resource,
+ Count,
+ NextCount,
+ FileName,
+ Line );
+
+ if (Length < 0) {
+ DbgPrint( "NwRdr: Message is too long for NwRefDbg\n");
+ return;
+ }
+
+ ASSERT( Length <= LINE_SIZE );
+ ASSERT( Length != 0 );
+ ASSERT( RBufferPtr < &RBuffer[BUFFER_LINES*LINE_SIZE+1]);
+ ASSERT( RBufferPtr >= RBuffer);
+
+ RBufferPtr += Length;
+ RBufferPtr[0] = '\0';
+
+ // Avoid running off the end of the buffer and exit
+
+ if (RBufferPtr >= (RBuffer+((BUFFER_LINES-1) * LINE_SIZE))) {
+ RBufferPtr = RBuffer;
+ }
+
+ return;
+}
+
+VOID
+RealDebugTrace(
+ LONG Indent,
+ ULONG Level,
+ PCH Message,
+ PVOID Parameter
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if ( (Level == 0) || (NwMemDebug & Level )) {
+ NwMemDbg( Message, PsGetCurrentThread(), 1, "", Parameter );
+ }
+
+ if ( (Level == 0) || (NwDebug & Level )) {
+
+ if ( Indent < 0) {
+ NwDebugTraceIndent += Indent;
+ }
+
+ DbgPrint( Message, PsGetCurrentThread(), NwDebugTraceIndent, "", Parameter );
+
+ if ( Indent > 0) {
+ NwDebugTraceIndent += Indent;
+ }
+
+ if (NwDebugTraceIndent < 0) {
+ NwDebugTraceIndent = 0;
+ }
+ }
+}
+
+VOID
+dump(
+ IN ULONG Level,
+ IN PVOID far_p,
+ IN ULONG len
+ )
+/*++
+
+Routine Description:
+ Dump Min(len, MaxDump) bytes in classic hex dump style if debug
+ output is turned on for this level.
+
+Arguments:
+
+ IN Level - 0 if always display. Otherwise only display if a
+ corresponding bit is set in NwDebug.
+
+ IN far_p - address of buffer to start dumping from.
+
+ IN len - length in bytes of buffer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG l;
+ char s[80], t[80];
+ PCHAR far_pchar = (PCHAR)far_p;
+
+ if ( (Level == 0) || (NwDebug & Level )) {
+ if (len > MaxDump)
+ len = MaxDump;
+
+ while (len) {
+ l = len < 16 ? len : 16;
+
+ DbgPrint("\n%lx ", far_pchar);
+ HexDumpLine (far_pchar, l, s, t, 0);
+ DbgPrint("%s%.*s%s", s, 1 + ((16 - l) * 3), "", t);
+ NwMemDbg ( "%lx: %s%.*s%s\n",
+ far_pchar, s, 1 + ((16 - l) * 3), "", t);
+
+ len -= l;
+ far_pchar += l;
+ }
+ DbgPrint("\n");
+
+ }
+}
+
+VOID
+dumpMdl(
+ IN ULONG Level,
+ IN PMDL Mdl
+ )
+/*++
+
+Routine Description:
+ Dump the memory described by each part of a chained Mdl.
+
+Arguments:
+
+ IN Level - 0 if always display. Otherwise only display if a
+ corresponding bit is set in NwDebug.
+
+ Mdl - Supplies the addresses of the memory to be dumped.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMDL Next;
+ ULONG len;
+
+
+ if ( (Level == 0) || (NwDebug & Level )) {
+ Next = Mdl; len = 0;
+ do {
+
+ dump(Level, MmGetSystemAddressForMdl(Next), MIN(MmGetMdlByteCount(Next), MaxDump-len));
+
+ len += MmGetMdlByteCount(Next);
+ } while ( (Next = Next->Next) != NULL &&
+ len <= MaxDump);
+ }
+}
+
+VOID
+HexDumpLine (
+ PCHAR pch,
+ ULONG len,
+ PCHAR s,
+ PCHAR t,
+ USHORT flag
+ )
+{
+ static UCHAR rghex[] = "0123456789ABCDEF";
+
+ UCHAR c;
+ UCHAR *hex, *asc;
+
+
+ hex = s;
+ asc = t;
+
+ *(asc++) = '*';
+ while (len--) {
+ c = *(pch++);
+ *(hex++) = rghex [c >> 4] ;
+ *(hex++) = rghex [c & 0x0F];
+ *(hex++) = ' ';
+ *(asc++) = (c < ' ' || c > '~') ? (CHAR )'.' : c;
+ }
+ *(asc++) = '*';
+ *asc = 0;
+ *hex = 0;
+
+ flag;
+}
+
+typedef struct _NW_POOL_HEADER {
+ ULONG Signature;
+ ULONG BufferSize;
+ ULONG BufferType;
+ LIST_ENTRY ListEntry;
+ ULONG Pad; // Pad to Q-word align
+} NW_POOL_HEADER, *PNW_POOL_HEADER;
+
+typedef struct _NW_POOL_TRAILER {
+ ULONG Signature;
+} NW_POOL_TRAILER;
+
+typedef NW_POOL_TRAILER UNALIGNED *PNW_POOL_TRAILER;
+
+PVOID
+NwAllocatePool(
+ ULONG Type,
+ ULONG Size,
+ BOOLEAN RaiseStatus
+ )
+{
+ PCHAR Buffer;
+ PNW_POOL_HEADER PoolHeader;
+ PNW_POOL_TRAILER PoolTrailer;
+
+ if ( RaiseStatus ) {
+ Buffer = FsRtlAllocatePool(
+ Type,
+ sizeof( NW_POOL_HEADER ) + sizeof( NW_POOL_TRAILER ) + Size );
+ } else {
+#ifndef QFE_BUILD
+ Buffer = ExAllocatePoolWithTag(
+ Type,
+ sizeof( NW_POOL_HEADER )+sizeof( NW_POOL_TRAILER )+Size,
+ 'scwn' );
+#else
+ Buffer = ExAllocatePool(
+ Type,
+ sizeof( NW_POOL_HEADER )+sizeof( NW_POOL_TRAILER )+Size );
+#endif
+
+ if ( Buffer == NULL ) {
+ return( NULL );
+ }
+ }
+
+ PoolHeader = (PNW_POOL_HEADER)Buffer;
+ PoolTrailer = (PNW_POOL_TRAILER)(Buffer + sizeof( NW_POOL_HEADER ) + Size);
+
+ PoolHeader->Signature = 0x11111111;
+ PoolHeader->BufferSize = Size;
+ PoolHeader->BufferType = Type;
+
+ PoolTrailer->Signature = 0x99999999;
+
+ if ( Type == PagedPool ) {
+ ExAcquireResourceExclusive( &NwDebugResource, TRUE );
+ InsertTailList( &NwPagedPoolList, &PoolHeader->ListEntry );
+ ExReleaseResource( &NwDebugResource );
+ } else if ( Type == NonPagedPool ) {
+ ExInterlockedInsertTailList( &NwNonpagedPoolList, &PoolHeader->ListEntry, &NwDebugInterlock );
+ } else {
+ KeBugCheck( RDR_FILE_SYSTEM );
+ }
+
+ return( Buffer + sizeof( NW_POOL_HEADER ) );
+}
+
+VOID
+NwFreePool(
+ PVOID Buffer
+ )
+{
+ PNW_POOL_HEADER PoolHeader;
+ PNW_POOL_TRAILER PoolTrailer;
+ KIRQL OldIrql;
+
+ PoolHeader = (PNW_POOL_HEADER)((PCHAR)Buffer - sizeof( NW_POOL_HEADER ));
+ ASSERT( PoolHeader->Signature == 0x11111111 );
+ ASSERT( PoolHeader->BufferType == PagedPool ||
+ PoolHeader->BufferType == NonPagedPool );
+
+ PoolTrailer = (PNW_POOL_TRAILER)((PCHAR)Buffer + PoolHeader->BufferSize );
+ ASSERT( PoolTrailer->Signature == 0x99999999 );
+
+ if ( PoolHeader->BufferType == PagedPool ) {
+ ExAcquireResourceExclusive( &NwDebugResource, TRUE );
+ RemoveEntryList( &PoolHeader->ListEntry );
+ ExReleaseResource( &NwDebugResource );
+ } else {
+ KeAcquireSpinLock( &NwDebugInterlock, &OldIrql );
+ RemoveEntryList( &PoolHeader->ListEntry );
+ KeReleaseSpinLock( &NwDebugInterlock, OldIrql );
+ }
+
+ ExFreePool( PoolHeader );
+}
+
+//
+// Debug functions for allocating and deallocating IRPs and MDLs
+//
+
+PIRP
+NwAllocateIrp(
+ CCHAR Size,
+ BOOLEAN ChargeQuota
+ )
+{
+ ExInterlockedIncrementLong( &IrpCount, &NwDebugInterlock );
+ return IoAllocateIrp( Size, ChargeQuota );
+}
+
+VOID
+NwFreeIrp(
+ PIRP Irp
+ )
+{
+ ExInterlockedDecrementLong( &IrpCount, &NwDebugInterlock );
+ IoFreeIrp( Irp );
+}
+
+typedef struct _NW_MDL {
+ LIST_ENTRY Next;
+ PUCHAR File;
+ int Line;
+ PMDL pMdl;
+} NW_MDL, *PNW_MDL;
+
+//int DebugLine = 2461;
+
+PMDL
+NwAllocateMdl(
+ PVOID Va,
+ ULONG Length,
+ BOOLEAN Secondary,
+ BOOLEAN ChargeQuota,
+ PIRP Irp,
+ PUCHAR FileName,
+ int Line
+ )
+{
+ PNW_MDL Buffer;
+
+ static BOOLEAN MdlSetup = FALSE;
+
+ if (MdlSetup == FALSE) {
+
+ InitializeListHead( &MdlList );
+
+ MdlSetup = TRUE;
+ }
+
+ if ( FailAllocateMdl != 0 ) {
+ if ( ( rand() % FailAllocateMdl ) == 0 ) {
+ return(NULL);
+ }
+ }
+
+#ifndef QFE_BUILD
+ Buffer = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof( NW_MDL),
+ 'scwn' );
+#else
+ Buffer = ExAllocatePool(
+ NonPagedPool,
+ sizeof( NW_MDL));
+#endif
+
+ if ( Buffer == NULL ) {
+ return( NULL );
+ }
+
+ ExInterlockedIncrementLong( &MdlCount, &NwDebugInterlock );
+
+ Buffer->File = FileName;
+ Buffer->Line = Line;
+ Buffer->pMdl = IoAllocateMdl( Va, Length, Secondary, ChargeQuota, Irp );
+
+ ExInterlockedInsertTailList( &MdlList, &Buffer->Next, &NwDebugInterlock );
+
+/*
+ if (DebugLine == Line) {
+ DebugTrace( 0, DEBUG_TRACE_MDL, "AllocateMdl -> %08lx\n", Buffer->pMdl );
+ DebugTrace( 0, DEBUG_TRACE_MDL, "AllocateMdl -> %08lx\n", Line );
+ }
+*/
+ return(Buffer->pMdl);
+}
+
+VOID
+NwFreeMdl(
+ PMDL Mdl
+ )
+{
+ PLIST_ENTRY MdlEntry;
+ PNW_MDL Buffer;
+ KIRQL OldIrql;
+
+ ExInterlockedDecrementLong( &MdlCount, &NwDebugInterlock );
+
+ KeAcquireSpinLock( &NwDebugInterlock, &OldIrql );
+ // Find the Mdl in the list and remove it.
+
+ for (MdlEntry = MdlList.Flink ;
+ MdlEntry != &MdlList ;
+ MdlEntry = MdlEntry->Flink ) {
+
+ Buffer = CONTAINING_RECORD( MdlEntry, NW_MDL, Next );
+
+ if (Buffer->pMdl == Mdl) {
+
+ RemoveEntryList( &Buffer->Next );
+
+ KeReleaseSpinLock( &NwDebugInterlock, OldIrql );
+
+ IoFreeMdl( Mdl );
+ DebugTrace( 0, DEBUG_TRACE_MDL, "FreeMDL - %08lx\n", Mdl );
+/*
+ if (DebugLine == Buffer->Line) {
+ DebugTrace( 0, DEBUG_TRACE_MDL, "FreeMdl -> %08lx\n", Mdl );
+ DebugTrace( 0, DEBUG_TRACE_MDL, "FreeMdl -> %08lx\n", Buffer->Line );
+ }
+*/
+ ExFreePool(Buffer);
+
+ return;
+ }
+ }
+ ASSERT( FALSE );
+
+ KeReleaseSpinLock( &NwDebugInterlock, OldIrql );
+}
+
+/*
+VOID
+NwLookForMdl(
+ )
+{
+ PLIST_ENTRY MdlEntry;
+ PNW_MDL Buffer;
+ KIRQL OldIrql;
+
+ KeAcquireSpinLock( &NwDebugInterlock, &OldIrql );
+ // Find the Mdl in the list and remove it.
+
+ for (MdlEntry = MdlList.Flink ;
+ MdlEntry != &MdlList ;
+ MdlEntry = MdlEntry->Flink ) {
+
+ Buffer = CONTAINING_RECORD( MdlEntry, NW_MDL, Next );
+
+ if (Buffer->Line == DebugLine) {
+
+ DebugTrace( 0, DEBUG_TRACE_MDL, "LookForMdl -> %08lx\n", Buffer );
+ DbgBreakPoint();
+
+ }
+ }
+
+ KeReleaseSpinLock( &NwDebugInterlock, OldIrql );
+}
+*/
+
+//
+// Function version of resource macro, to make debugging easier.
+//
+
+VOID
+NwAcquireExclusiveRcb(
+ PRCB Rcb,
+ BOOLEAN Wait )
+{
+ ExAcquireResourceExclusive( &((Rcb)->Resource), Wait );
+}
+
+VOID
+NwAcquireSharedRcb(
+ PRCB Rcb,
+ BOOLEAN Wait )
+{
+ ExAcquireResourceShared( &((Rcb)->Resource), Wait );
+}
+
+VOID
+NwReleaseRcb(
+ PRCB Rcb )
+{
+ ExReleaseResource( &((Rcb)->Resource) );
+}
+
+VOID
+NwAcquireExclusiveFcb(
+ PNONPAGED_FCB pFcb,
+ BOOLEAN Wait )
+{
+ ExAcquireResourceExclusive( &((pFcb)->Resource), Wait );
+}
+
+VOID
+NwAcquireSharedFcb(
+ PNONPAGED_FCB pFcb,
+ BOOLEAN Wait )
+{
+ ExAcquireResourceShared( &((pFcb)->Resource), Wait );
+}
+
+VOID
+NwReleaseFcb(
+ PNONPAGED_FCB pFcb )
+{
+ ExReleaseResource( &((pFcb)->Resource) );
+}
+
+VOID
+NwAcquireOpenLock(
+ VOID
+ )
+{
+ ExAcquireResourceExclusive( &NwOpenResource, TRUE );
+}
+
+VOID
+NwReleaseOpenLock(
+ VOID
+ )
+{
+ ExReleaseResource( &NwOpenResource );
+}
+
+
+//
+// code to dump ICBs
+//
+
+VOID DumpIcbs(VOID)
+{
+ PVCB Vcb;
+ PFCB Fcb;
+ PICB Icb;
+ PLIST_ENTRY VcbListEntry;
+ PLIST_ENTRY FcbListEntry;
+ PLIST_ENTRY IcbListEntry;
+ KIRQL OldIrql;
+
+ NwAcquireExclusiveRcb( &NwRcb, TRUE );
+ KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
+
+ DbgPrint("\nICB Pid State Scb/Fcb Name\n", 0);
+ for ( VcbListEntry = GlobalVcbList.Flink;
+ VcbListEntry != &GlobalVcbList ;
+ VcbListEntry = VcbListEntry->Flink ) {
+
+ Vcb = CONTAINING_RECORD( VcbListEntry, VCB, GlobalVcbListEntry );
+
+ for ( FcbListEntry = Vcb->FcbList.Flink;
+ FcbListEntry != &(Vcb->FcbList) ;
+ FcbListEntry = FcbListEntry->Flink ) {
+
+ Fcb = CONTAINING_RECORD( FcbListEntry, FCB, FcbListEntry );
+
+ for ( IcbListEntry = Fcb->IcbList.Flink;
+ IcbListEntry != &(Fcb->IcbList) ;
+ IcbListEntry = IcbListEntry->Flink ) {
+
+ Icb = CONTAINING_RECORD( IcbListEntry, ICB, ListEntry );
+
+ DbgPrint("%08lx", Icb);
+ DbgPrint(" %08lx",(DWORD)Icb->Pid);
+ DbgPrint(" %08lx",Icb->State);
+ DbgPrint(" %08lx",Icb->SuperType.Scb);
+ DbgPrint(" %wZ\n",
+ &(Icb->FileObject->FileName) );
+ }
+ }
+ }
+
+ KeReleaseSpinLock( &ScbSpinLock, OldIrql );
+ NwReleaseRcb( &NwRcb );
+}
+
+#endif // ifdef NWDBG
+
+//
+// Ref counting debug routines.
+//
+
+#ifdef NWDBG
+
+VOID
+ChkNwReferenceScb(
+ PNONPAGED_SCB pNpScb,
+ PBYTE FileName,
+ UINT Line,
+ BOOLEAN Silent
+) {
+
+ if ( (pNpScb)->NodeTypeCode != NW_NTC_SCBNP ) {
+ DbgBreakPoint();
+ }
+
+ if ( !Silent) {
+ RefDbgTrace( pNpScb, pNpScb->Reference, TRUE, FileName, Line );
+ }
+
+ ExInterlockedIncrementLong( &(pNpScb)->Reference, &(pNpScb)->NpScbInterLock );
+}
+
+VOID
+ChkNwDereferenceScb(
+ PNONPAGED_SCB pNpScb,
+ PBYTE FileName,
+ UINT Line,
+ BOOLEAN Silent
+) {
+
+ if ( (pNpScb)->Reference == 0 ) {
+ DbgBreakPoint();
+ }
+
+ if ( (pNpScb)->NodeTypeCode != NW_NTC_SCBNP ) {
+ DbgBreakPoint();
+ }
+
+ if ( !Silent ) {
+ RefDbgTrace( pNpScb, pNpScb->Reference, FALSE, FileName, Line );
+ }
+
+ ExInterlockedDecrementLong( &(pNpScb)->Reference, &(pNpScb)->NpScbInterLock );
+}
+
+#endif
+