Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

659 lines
15 KiB

/**********************************************************************/
/** Microsoft Windows NT **/
/** Copyright(c) Microsoft Corp., 1993 **/
/**********************************************************************/
/*
debug.c
This module contains debug support routines.
FILE HISTORY:
KeithMo 20-Sep-1993 Created.
*/
#include <nbtprocs.h>
#include <vxddebug.h>
#ifdef DEBUG
//
// Private constants.
//
#define MAX_PRINTF_OUTPUT 1024 // characters
#define MAX_SUBSTRING_LEN 256
#define OUTPUT_LABEL "VNBT"
#define IS_DIGIT(ch) (((ch) >= '0') && ((ch) <= '9'))
//
// Private types.
//
//
// Private globals.
//
//
// Private prototypes.
//
int VxdVsprintf( char * pszStr,
char * pszFmt,
char * ArgPtr );
void VxdCopyToDBOut( void );
//
// Public functions.
//
/*******************************************************************
NAME: VxdAssert
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 20-Sep-1993 Created.
********************************************************************/
void VxdAssert( void * pAssertion,
void * pFileName,
unsigned long nLineNumber )
{
VxdPrintf( "\n"
"*** Assertion failed: %s\n"
"*** Source file %s, line %lu\n\n",
pAssertion,
pFileName,
nLineNumber );
DEBUG_BREAK;
} // VxdAssert
/*******************************************************************
NAME: VxdPrintf
SYNOPSIS: Customized debug output routine.
ENTRY: Usual printf-style parameters.
HISTORY:
KeithMo 20-Sep-1993 Created.
********************************************************************/
char szOutput[MAX_PRINTF_OUTPUT];
void VxdPrintf( char * pszFormat,
... )
{
va_list ArgList;
int cch;
cch = VxdSprintf( szOutput,
"%s: ",
OUTPUT_LABEL );
va_start( ArgList, pszFormat );
VxdVsprintf( szOutput + cch, pszFormat, ArgList );
va_end( ArgList );
VxdSprintf( szOutput, "%s\r\n", szOutput ) ;
VxdCopyToDBOut() ;
NbtDebugOut( DBOut+iCurPos ) ;
} // VxdPrintf
//
// Private functions.
//
/*******************************************************************
NAME: VxdCopyToDBOut
SYNOPSIS: Copies everything from szOutput into DBOut
First checks to see if DBOut has enough room to hold what we
have temporarily put in szOutput. If not, resets the iCurPos
to point to beginning of DBOut.
RETURNS: Nothing
*******************************************************************/
void VxdCopyToDBOut( void )
{
int bytesTowrite;
int spaceAvailable;
int i;
spaceAvailable = sizeof(DBOut) - iCurPos;
bytesTowrite = strlen( szOutput ) + 1;
// if not enough room, start at the beginning
if ( spaceAvailable <= bytesTowrite )
{
for ( i=iCurPos; i<sizeof(DBOut); i++ )
DBOut[i] = '+'; // so that strings don't mix
iCurPos = 0;
if ( bytesTowrite > sizeof(szOutput) )
{
bytesTowrite = sizeof(szOutput);
szOutput[bytesTowrite-1] = '\0';
}
}
CTEMemCopy( DBOut+iCurPos, szOutput, bytesTowrite ) ;
}
/*******************************************************************
NAME: VxdVsprintf
SYNOPSIS: Half-baked vsprintf() clone for VxD environment.
ENTRY: pszStr - Will receive the formatted string.
pszFmt - The format, with field specifiers.
ArgPtr - Points to the actual printf() arguments.
RETURNS: int - Number of characters stored in *pszStr.
HISTORY:
KeithMo 20-Sep-1993 Created.
********************************************************************/
int VxdVsprintf( char * pszStr,
char * pszFmt,
char * ArgPtr )
{
char ch;
char * pszStrStart;
int fZeroPad;
int cchWidth;
int ccMaxToCopy;
//
// Remember start of output, so we can calc length.
//
pszStrStart = pszStr;
while( ( ch = *pszFmt++ ) != '\0' )
{
//
// Scan for format specifiers.
//
if( ch != '%' )
{
*pszStr++ = ch;
continue;
}
//
// Got one.
//
ch = *pszFmt++;
//
// Initialize attributes for this item.
//
fZeroPad = 0;
cchWidth = 0;
ccMaxToCopy = MAX_SUBSTRING_LEN;
//
// Interpret the field specifiers.
//
if( ch == '-' )
{
//
// Left justification not supported.
//
ch = *pszFmt++;
}
if( ch == '0' )
{
//
// Zero padding.
//
fZeroPad = 1;
ch = *pszFmt++;
}
if( ch == '*' )
{
//
// Retrieve width from next argument.
//
cchWidth = va_arg( ArgPtr, int );
ch = *pszFmt++;
}
else
{
//
// Calculate width.
//
while( IS_DIGIT(ch) )
{
cchWidth = ( cchWidth * 10 ) + ( ch - '0' );
ch = *pszFmt++;
}
}
if( ch == '.' )
{
ch = *pszFmt++;
if( ch == '*' )
{
ccMaxToCopy = va_arg( ArgPtr, int );
ch = *pszFmt++;
}
else
{
ccMaxToCopy = 0;
while( IS_DIGIT(ch) )
{
ccMaxToCopy = ( ccMaxToCopy * 10 ) + ( ch - '0' );
ch = *pszFmt++;
}
}
}
//
// All numbers are longs.
//
if( ch == 'l' )
{
ch = *pszFmt++;
}
//
// Decipher the format specifier.
//
if( ( ch == 'd' ) || ( ch == 'u' ) || ( ch == 'x' ) || ( ch == 'X' ) )
{
unsigned long ul;
unsigned long radix;
char xbase;
char * pszTmp;
char * pszEnd;
int cchNum;
int fNegative;
//
// Numeric. Retrieve the value.
//
ul = va_arg( ArgPtr, unsigned long );
//
// If this is a negative number, remember and negate.
//
if( ( ch == 'd' ) && ( (long)ul < 0 ) )
{
fNegative = 1;
ul = (unsigned long)(-(long)ul);
}
else
{
fNegative = 0;
}
//
// Remember start of digits.
//
pszTmp = pszStr;
cchNum = 0;
//
// Special goodies for hex conversion.
//
radix = ( ( ch == 'x' ) || ( ch == 'X' ) ) ? 16 : 10;
xbase = ( ch == 'x' ) ? 'a' : 'A';
//
// Loop until we're out of digits.
//
do
{
unsigned int digit;
digit = (unsigned int)( ul % radix );
ul /= radix;
if( digit > 9 )
{
*pszTmp++ = (char)( digit - 10 + xbase );
}
else
{
*pszTmp++ = (char)( digit + '0' );
}
cchNum++;
} while( ul > 0 );
//
// Add the negative sign if necessary.
//
if( fNegative )
{
*pszTmp++ = '-';
cchNum++;
}
//
// Add any necessary padding.
//
while( cchNum < cchWidth )
{
*pszTmp++ = fZeroPad ? '0' : ' ';
cchNum++;
}
//
// Now reverse the digits.
//
pszEnd = pszTmp--;
do
{
char tmp;
tmp = *pszTmp;
*pszTmp = *pszStr;
*pszStr = tmp;
pszTmp--;
pszStr++;
} while( pszTmp > pszStr );
pszStr = pszEnd;
}
else
if( ch == 's' )
{
char * pszTmp;
int count;
//
// Copy the string.
//
pszTmp = va_arg( ArgPtr, char * );
count = 0;
while( *pszTmp )
{
*pszStr++ = *pszTmp++;
count++;
//
// if we get passed a weird pointer, don't go on writing! That
// overwrites other things (like tdidispatch table!) and very
// bad things happen....
//
if (count >= ccMaxToCopy)
break;
}
}
else
if( ch == 'c' )
{
//
// A single character.
//
*pszStr++ = (char)va_arg( ArgPtr, int );
}
else
{
//
// Unknown. Ideally we should copy the entire
// format specifier, including any width & precision
// values, but who really cares?
//
*pszStr++ = ch;
}
}
//
// Terminate it properly.
//
*pszStr = '\0';
//
// Return the length of the generated string.
//
return pszStr - pszStrStart;
} // VxdVsprintf
/*******************************************************************
NAME: VxdSprintf
SYNOPSIS: Half-baked sprintf() clone for VxD environment.
ENTRY: pszStr - Will receive the formatted string.
pszFmt - The format, with field specifiers.
... - Usual printf()-like parameters.
RETURNS: int - Number of characters stored in *pszStr.
HISTORY:
KeithMo 20-Sep-1993 Created.
********************************************************************/
int VxdSprintf( char * pszStr,
char * pszFmt,
... )
{
int cch;
va_list ArgPtr;
va_start( ArgPtr, pszFmt );
cch = VxdVsprintf( pszStr, pszFmt, ArgPtr );
va_end( ArgPtr );
return( cch );
} // VxdSprintf
/*******************************************************************
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
CTEAllocMem.
ENTRY: ReqSize - how much memory is needed
RETURNS: PVOID - pointer to the memory block that client will
use directly.
HISTORY:
Koti 11-Nov-1994 Created.
********************************************************************/
//
// IMPORTANT: we are undef'ing CTEAllocMem because we need to make a
// call to the actual CTE function CTEAllocMem. That's why
// this function and this undef are at the end of the file.
//
#undef CTEAllocMem
PVOID DbgAllocMem( DWORD ReqSize )
{
DWORD ActualSize;
PVOID pBuffer;
DbgMemBlkHdr *pMemHdr;
PVOID pRetAddr;
ActualSize = ReqSize + sizeof(DbgMemBlkHdr);
pBuffer = CTEAllocMem( ActualSize );
if ( !pBuffer )
{
return( NULL );
}
pMemHdr = (DbgMemBlkHdr *)pBuffer;
pMemHdr->Verify = DBG_MEMALLOC_VERIFY;
pMemHdr->ReqSize = ReqSize;
pRetAddr = &pMemHdr->Owner[0];
//
// now memory is allocated from NCBHandler, too where stack trace isn't more
// than 2 deep! unifdef when memory leaks becomes an issue...
//
#if 0
_asm
{
push ebx
push ecx
push edx
mov ebx, pRetAddr
mov eax, ebp
mov ecx, 4
again:
mov edx, dword ptr [eax+4] ; return address
mov dword ptr [ebx], edx
mov eax, dword ptr [eax] ; previous frame pointer
add ebx, 4
dec ecx
cmp ecx, 0
je done
jmp again
done:
pop edx
pop ecx
pop ebx
}
#endif
//
// BUGBUG: if ever ported to NT (or if chicago needs MP support),
// put spinlocks. (we will need a spinlock field in DbgMemBlkHdr struct).
//
InsertTailList(&DbgMemList, &pMemHdr->Linkage);
return( (PCHAR)pBuffer + 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 CTEMemFree
#undef CTEFreeMem
VOID DbgFreeMem( PVOID pBufferToFree )
{
DbgMemBlkHdr *pMemHdr;
if ( !pBufferToFree )
{
return;
}
pMemHdr = (DbgMemBlkHdr *)((PCHAR)pBufferToFree - sizeof(DbgMemBlkHdr));
ASSERT( pMemHdr->Verify == DBG_MEMALLOC_VERIFY );
//
// change our signature: if we are freeing some memory twice, we'll know!
//
pMemHdr->Verify -= 1;
//
// BUGBUG: if ever ported to NT (or if chicago needs MP support),
// put spinlocks. (we will need a spinlock field in DbgMemBlkHdr struct).
//
RemoveEntryList(&pMemHdr->Linkage);
CTEFreeMem( (PVOID)pMemHdr );
}
#endif // DEBUG