windows-nt/Source/XPSP1/NT/net/tcpip/services/lpd/debug.c

563 lines
14 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*************************************************************************
* Microsoft Windows NT *
* *
* Copyright(c) Microsoft Corp., 1994 *
* *
* Revision History: *
* *
* Jan. 24,94 Koti Created *
* *
* Description: *
* *
* This file contains debug support routines for the LPD Service. *
* This file is based on (in fact, borrowed and then modified) on the *
* debug.c in the ftpsvc module. *
* *
*************************************************************************/
#include <stdio.h>
#include "lpd.h"
#if DBG
//
// Private constants.
//
#define LPD_OUT_FILE "lpdout.log"
#define LPD_ERR_FILE "lpderr.log"
#define MAX_PRINTF_OUTPUT 1024 // characters
#define LPD_OUTPUT_LABEL "LPDSVC"
#define DEBUG_HEAP 0 // enable/disable heap debugging
//
// Private globals.
//
FILE * pErrFile; // Debug output log file.
FILE * pOutFile; // Debug output log file.
BOOL fFirstTimeErr=TRUE;
BOOL fFirstTimeOut=TRUE;
//
// every LocalAlloc gets linked to this list and LocalFree gets unlinked
// (so that we can catch any memory leaks!)
//
LIST_ENTRY DbgMemList;
//
// synchronization for DbgMemList
//
CRITICAL_SECTION CS;
//
// Public functions.
//
/*******************************************************************
NAME: DbgInit
SYNOPSIS: Peforms initialization for debug memory allocator
ENTRY: void
HISTORY:
Frankbee 05-Jun-1996 Created.
********************************************************************/
VOID
DbgInit()
{
InitializeCriticalSection( &CS );
}
/*******************************************************************
NAME: DbgUninit
SYNOPSIS: Peforms cleanup for debug memory allocator
ENTRY: void
HISTORY:
Frankbee 05-Jun-1996 Created.
********************************************************************/
VOID
DbgUninit()
{
DeleteCriticalSection( &CS );
}
//
// Public functions.
//
/*******************************************************************
NAME: LpdAssert
SYNOPSIS: Called if an assertion fails. Displays the failed
assertion, file name, and line number. Gives the
user the opportunity to ignore the assertion or
break into the debugger.
ENTRY: pAssertion - The text of the failed expression.
pFileName - The containing source file.
nLineNumber - The guilty line number.
HISTORY:
KeithMo 07-Mar-1993 Created.
********************************************************************/
VOID
LpdAssert( VOID * pAssertion,
VOID * pFileName,
ULONG nLineNumber
)
{
RtlAssert( pAssertion, pFileName, nLineNumber, NULL );
} // LpdAssert
/*******************************************************************
NAME: LpdPrintf
SYNOPSIS: Customized debug output routine.
ENTRY: Usual printf-style parameters.
HISTORY:
KeithMo 07-Mar-1993 Created.
********************************************************************/
VOID
LpdPrintf(
CHAR * pszFormat,
...
)
{
CHAR szOutput[MAX_PRINTF_OUTPUT];
DWORD dwErrcode;
va_list ArgList;
DWORD cchOutputLength;
PSTR pszErrorBuffer;
dwErrcode = GetLastError();
sprintf( szOutput,
"%s (%lu): ",
LPD_OUTPUT_LABEL,
GetCurrentThreadId() );
va_start( ArgList, pszFormat );
vsprintf( szOutput + strlen(szOutput), pszFormat, ArgList );
va_end( ArgList );
cchOutputLength = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM + FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL,
dwErrcode,
0,
(LPTSTR)&pszErrorBuffer,
1,
NULL
);
if ( cchOutputLength == 0 )
{
sprintf( szOutput + strlen(szOutput), " Error = %ld\n",dwErrcode);
pszErrorBuffer = NULL;
}
else
{
pszErrorBuffer[ cchOutputLength - 1 ] = '\0';
sprintf( szOutput + strlen(szOutput),
" Error = %ld (%s)\n",
dwErrcode,
pszErrorBuffer );
}
if ( pszErrorBuffer != NULL )
{
//
// Why is "LocalFree" in parentheses? Because LocalFree might be #define'd
// to a debugging function, but pszErrorBuffer was LocalAlloc()'d with the
// normal function. The parens prevent macro expansion and guarantee that
// we call the real LocalFree() function.
//
(LocalFree)( pszErrorBuffer );
}
if( pErrFile == NULL )
{
if ( fFirstTimeErr )
{
pErrFile = fopen( LPD_ERR_FILE, "w+" );
fFirstTimeErr = FALSE;
}
else
pErrFile = fopen( LPD_ERR_FILE, "a+" );
}
if( pErrFile != NULL )
{
fputs( szOutput, pErrFile );
fflush( pErrFile );
}
} // LpdPrintf
/*******************************************************************
NAME: StripPath
SYNOPSIS: Given a fully qualified filename, returns the filename
sans path
ENTRY: char *szPath - filename, possibly including path
RETURNS: filename
HISTORY:
Frankbee 6/18/96 Created.
********************************************************************/
char *
StripPath( char *szPath )
{
char *p;
p = szPath + strlen( szPath );
while( p != szPath && *p != '\\' )
p--;
if ( *p == '\\' )
++p;
return p;
}
/*******************************************************************
NAME: DbgDumpLeaks
SYNOPSIS: Checks DbgMemList for memory that wasn't deallocated.
For each leaked block, the following is written to
the error log:
- Filename
- Line #
- Requested Size
ENTRY: VOID
RETURNS: VOID
HISTORY:
Frankbee 6/18/96 Created
********************************************************************/
void
DbgDumpLeaks()
{
LIST_ENTRY *p = DbgMemList.Flink;
if ( IsListEmpty( &DbgMemList ) )
return; // no leaks
LPD_DEBUG("DbgDumpLeaks: memory leaks detected:\n");
while ( p != &DbgMemList )
{
DbgMemBlkHdr *pHdr = (DbgMemBlkHdr*) p;
LpdPrintf( "%s, line %d: %d byte block\n", pHdr->szFile, pHdr->dwLine,
pHdr->ReqSize );
p = p->Flink;
}
LPD_ASSERT(0);
}
/*******************************************************************
NAME: DbgAllocMem
SYNOPSIS: Keep track of all allocated memory so we can catch
memory leak when we unload
This is only on debug builds. On non-debug builds
this function doesn't exist: calls directly go to
LocalAlloc
ENTRY: pscConn - connection which is requesting memory
flag - whatever flags are passed in
ReqSize - how much memory is needed
RETURNS: PVOID - pointer to the memory block that client will
use directly.
HISTORY:
Koti 3-Dec-1994 Created.
********************************************************************/
//
// IMPORTANT: we are undef'ing LocalAlloc because we need to make a
// call to the actual function here!. That's why
// this function and this undef are at the end of the file.
//
#undef LocalAlloc
PVOID
DbgAllocMem( PSOCKCONN pscConn,
DWORD flag,
DWORD ReqSize,
DWORD dwLine,
char *szFile
)
{
DWORD ActualSize;
PVOID pBuffer;
DbgMemBlkHdr *pMemHdr;
PVOID pRetAddr;
ActualSize = ReqSize + sizeof(DbgMemBlkHdr);
pBuffer = LocalAlloc( flag, ActualSize );
if ( !pBuffer )
{
LPD_DEBUG("DbgAllocMem: couldn't allocate memory: returning!\n");
return( NULL );
}
pMemHdr = (DbgMemBlkHdr *)pBuffer;
pMemHdr->Verify = DBG_MEMALLOC_VERIFY;
pMemHdr->ReqSize = ReqSize;
pMemHdr->dwLine = dwLine;
strncpy( pMemHdr->szFile, StripPath( szFile ), DBG_MAXFILENAME );
pMemHdr->szFile[ DBG_MAXFILENAME - 1 ] = '\0';
pMemHdr->Owner[0] = (DWORD_PTR)pscConn;
//
// for private builds on x86 machines, remove the #if 0
// (this code saves stack trace as to exactly who allocated memory)
//
#if 0
pRetAddr = &pMemHdr->Owner[0];
_asm
{
push ebx
push ecx
push edx
mov ebx, pRetAddr
mov eax, ebp
mov edx, dword ptr [eax+4] ; return address
mov dword ptr [ebx], edx
mov eax, dword ptr [eax] ; previous frame pointer
pop edx
pop ecx
pop ebx
}
#endif
InitializeListHead(&pMemHdr->Linkage);
EnterCriticalSection( &CS );
InsertTailList(&DbgMemList, &pMemHdr->Linkage);
LeaveCriticalSection( &CS );
return( (PCHAR)pBuffer + sizeof(DbgMemBlkHdr) );
}
/*******************************************************************
NAME: DbgReAllocMem
SYNOPSIS: Keep track of all allocated memory so we can catch
memory leak when we unload
This is only on debug builds. On non-debug builds
this function doesn't exist: calls directly go to
LocalReAlloc
ENTRY: pscConn - connection which is requesting memory
pPartBuf - the originally allocated buffer
ReqSize - how much memory is needed
flag - whatever flags are passed in
RETURNS: PVOID - pointer to the memory block that client will
use directly.
HISTORY:
Koti 3-Dec-1994 Created.
********************************************************************/
//
// IMPORTANT: we are undef'ing LocalReAlloc because we need to make a
// call to the actual function here!. That's why
// this function and this undef are at the end of the file.
//
#undef LocalReAlloc
PVOID
DbgReAllocMem(
PSOCKCONN pscConn,
PVOID pPartBuf,
DWORD ReqSize,
DWORD flag,
DWORD dwLine,
char *szFile
)
{
DbgMemBlkHdr *pMemHdr;
PVOID pRetAddr;
if ( !pPartBuf )
{
LPD_DEBUG("DbgReAllocMem: invalid memory: returning!\n");
return( NULL );
}
pMemHdr = (DbgMemBlkHdr *)((PCHAR)pPartBuf - sizeof(DbgMemBlkHdr));
if( pMemHdr->Verify != DBG_MEMALLOC_VERIFY )
{
LPD_DEBUG("DbgReAllocMem: invalid memory being realloced: returning!\n");
return( NULL );
}
EnterCriticalSection( &CS );
RemoveEntryList(&pMemHdr->Linkage);
LeaveCriticalSection( &CS );
pMemHdr = LocalReAlloc((PCHAR)pMemHdr, ReqSize+sizeof(DbgMemBlkHdr), flag);
if ( !pMemHdr )
{
LPD_DEBUG("DbgReAllocMem: LocalReAlloc failed: returning!\n");
return( NULL );
}
pMemHdr->Verify = DBG_MEMALLOC_VERIFY;
pMemHdr->ReqSize = ReqSize;
pMemHdr->dwLine = dwLine;
strncpy( pMemHdr->szFile, StripPath( szFile ), DBG_MAXFILENAME );
pMemHdr->szFile[ DBG_MAXFILENAME - 1 ] = '\0';
pMemHdr->Owner[0] = (DWORD_PTR)pscConn;
//
// for private builds on x86 machines, remove the #if 0
// (this code saves stack trace as to exactly who allocated memory)
//
#if 0
pRetAddr = &pMemHdr->Owner[0];
_asm
{
push ebx
push ecx
push edx
mov ebx, pRetAddr
mov eax, ebp
mov edx, dword ptr [eax+4] ; return address
mov dword ptr [ebx], edx
mov eax, dword ptr [eax] ; previous frame pointer
pop edx
pop ecx
pop ebx
}
#endif
InitializeListHead(&pMemHdr->Linkage);
EnterCriticalSection( &CS );
InsertTailList(&DbgMemList, &pMemHdr->Linkage);
LeaveCriticalSection( &CS );
return( (PCHAR)pMemHdr + sizeof(DbgMemBlkHdr) );
}
/*******************************************************************
NAME: DbgFreeMem
SYNOPSIS: This routine removes the memory block from our list and
frees the memory by calling the CTE function CTEFreeMem
ENTRY: pBufferToFree - memory to free (caller's buffer)
RETURNS: nothing
HISTORY:
Koti 11-Nov-1994 Created.
********************************************************************/
//
// IMPORTANT: we are undef'ing CTEFreeMem because we need to make a
// call to the actual CTE function CTEFreeMem. That's why
// this function and this undef are at the end of the file.
//
#undef LocalFree
VOID
DbgFreeMem( PVOID pBufferToFree )
{
DbgMemBlkHdr *pMemHdr;
if ( !pBufferToFree )
{
return;
}
pMemHdr = (DbgMemBlkHdr *)((PCHAR)pBufferToFree - sizeof(DbgMemBlkHdr));
if( pMemHdr->Verify != DBG_MEMALLOC_VERIFY )
{
LPD_DEBUG("DbgFreeMem: attempt to free invalid memory: returning!\n");
LPD_ASSERT(0);
return;
}
//
// change our signature: if we are freeing some memory twice, we'll know!
//
pMemHdr->Verify -= 1;
EnterCriticalSection( &CS );
RemoveEntryList(&pMemHdr->Linkage);
LeaveCriticalSection( &CS );
LocalFree( (PVOID)pMemHdr );
}
#endif // DBG