|
|
/*++
Copyright (c) 1994 Microsoft Corporation All rights reserved.
Module Name:
Debug.cxx
Abstract:
Debug support
Author:
Albert Ting (AlbertT) 28-May-1994
Revision History:
--*/
#include "spllibp.hxx"
#pragma hdrstop
#include "trace.hxx"
extern HANDLE ghMemHeap; extern HANDLE ghDbgMemHeap;
VBackTrace* gpbtErrLog; VBackTrace* gpbtTraceLog;
#if DBG
MODULE_DEBUG_INIT( DBG_ERROR|DBG_WARN|DBG_TRACE, DBG_ERROR ); DBG_POINTERS gDbgPointers;
extern VBackTrace* gpbtAlloc; extern VBackTrace* gpbtFree;
/********************************************************************
Single thread checking.
This is used to verify that a set of functions are called from only one thread. This is for debugging purposes only.
********************************************************************/
VOID vDbgSingleThread( PDWORD pdwThreadId ) { EnterCriticalSection( &gcsBackTrace );
if (!*pdwThreadId) { *pdwThreadId = (DWORD)GetCurrentThreadId(); } SPLASSERT( *pdwThreadId == (DWORD)GetCurrentThreadId() );
LeaveCriticalSection( &gcsBackTrace ); }
VOID vDbgSingleThreadReset( PDWORD pdwThreadId ) { *pdwThreadId = 0; }
VOID vDbgSingleThreadNot( PDWORD pdwThreadId ) { SPLASSERT( *pdwThreadId != (DWORD)GetCurrentThreadId() ); }
/********************************************************************
TStatus automated error logging and codepath testing.
********************************************************************/
TStatusBase& TStatusBase:: pNoChk( VOID ) { _pszFileA = NULL; return (TStatusBase&)*this; }
TStatusBase& TStatusBase:: pSetInfo( UINT uDbg, UINT uLine, LPCSTR pszFileA, LPCSTR pszModuleA ) { _uDbg = uDbg; _uLine = uLine; _pszFileA = pszFileA; SPLASSERT( pszFileA );
_pszModuleA = pszModuleA;
return (TStatusBase&)*this; }
DWORD TStatus:: dwGetStatus( VOID ) { //
// For now, return error code. Later it will return the actual
// error code.
//
return _dwStatus; }
DWORD TStatusBase:: operator=( DWORD dwStatus ) { //
// Check if we have an error, and it's not one of the two
// accepted "safe" errors.
//
// If pszFileA is not set, then we can safely ignore the
// error as one the client intended.
//
if( _pszFileA && dwStatus != ERROR_SUCCESS && dwStatus != _dwStatusSafe1 && dwStatus != _dwStatusSafe2 && dwStatus != _dwStatusSafe3 ){
#ifdef DBGLOG
//
// An unexpected error occured. Log an error and continue.
//
vDbgLogError( _uDbg, _uDbgLevel, _uLine, _pszFileA, _pszModuleA, pszDbgAllocMsgA( "TStatus set to %d\nLine %d, %hs\n", dwStatus, _uLine, _pszFileA )); #else
DBGMSG( DBG_WARN, ( "TStatus set to %d\nLine %d, %hs\n", dwStatus, _uLine, _pszFileA )); #endif
}
return _dwStatus = dwStatus; }
/********************************************************************
Same, but for BOOLs.
********************************************************************/
TStatusBBase& TStatusBBase:: pNoChk( VOID ) { _pszFileA = NULL; return (TStatusBBase&)*this; }
TStatusBBase& TStatusBBase:: pSetInfo( UINT uDbg, UINT uLine, LPCSTR pszFileA, LPCSTR pszModuleA ) { _uDbg = uDbg; _uLine = uLine; _pszFileA = pszFileA; SPLASSERT( pszFileA );
_pszModuleA = pszModuleA;
return (TStatusBBase&)*this; }
BOOL TStatusB:: bGetStatus( VOID ) { //
// For now, return error code. Later it will return the actual
// error code.
//
return _bStatus; }
BOOL TStatusBBase:: operator=( BOOL bStatus ) { //
// Check if we have an error, and it's not one of the two
// accepted "safe" errors.
//
// If pszFileA is not set, then we can safely ignore the
// error as one the client intended.
//
if( _pszFileA && !bStatus ){
DWORD dwLastError = GetLastError();
if( dwLastError != _dwStatusSafe1 && dwLastError != _dwStatusSafe2 && dwLastError != _dwStatusSafe3 ){
#ifdef DBGLOG
//
// An unexpected error occured. Log an error and continue.
//
vDbgLogError( _uDbg, _uDbgLevel, _uLine, _pszFileA, _pszModuleA, pszDbgAllocMsgA( "TStatusB set to FALSE, LastError = %d\nLine %d, %hs\n", GetLastError(), _uLine, _pszFileA )); #else
DBGMSG( DBG_WARN, ( "TStatusB set to FALSE, LastError = %d\nLine %d, %hs\n", GetLastError(), _uLine, _pszFileA )); #endif
} }
return _bStatus = bStatus; }
VOID vWarnInvalid( PVOID pvObject, UINT uDbg, UINT uLine, LPCSTR pszFileA, LPCSTR pszModuleA )
/*++
Routine Description:
Warns that an object is invalid.
Arguments:
Return Value:
--*/
{ #if DBGLOG
vDbgLogError( uDbg, DBG_WARN, uLine, pszFileA, pszModuleA, pszDbgAllocMsgA( "Invalid Object %x LastError = %d\nLine %d, %hs\n", (DWORD)pvObject, GetLastError(), uLine, pszFileA )); #else
DBGMSG( DBG_WARN, ( "Invalid Object %x LastError = %d\nLine %d, %hs\n", (DWORD)pvObject, GetLastError(), uLine, pszFileA )); #endif
}
/********************************************************************
Generic Error logging package.
********************************************************************/
VOID DbgMsg( LPCSTR pszMsgFormat, ... ) { CHAR szMsgText[1024]; va_list vargs;
va_start( vargs, pszMsgFormat ); wvsprintfA( szMsgText, pszMsgFormat, vargs ); va_end( vargs );
#ifndef DBGLOG
//
// Prefix the string if the first character isn't a space:
//
if( szMsgText[0] && szMsgText[0] != ' ' ){ OutputDebugStringA( MODULE ); } #endif
OutputDebugStringA( szMsgText ); }
#ifdef DBGLOG
LPSTR pszDbgAllocMsgA( LPCSTR pszMsgFormatA, ... ) { CHAR szMsgTextA[1024]; UINT cbStr; LPSTR pszMsgA; va_list vargs;
va_start( vargs, pszMsgFormatA );
__try { wvsprintfA( szMsgTextA, pszMsgFormatA, vargs ); } __except(( GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION || GetExceptionCode() == EXCEPTION_DATATYPE_MISALIGNMENT) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ){
OutputDebugStringA( "SPL: <Bad DbgMsg !!> " ); OutputDebugStringA( pszMsgFormatA ); }
va_end( vargs );
cbStr = ( lstrlenA( szMsgTextA ) + 1 ) * sizeof( szMsgTextA[0] );
pszMsgA = (LPSTR)DbgAllocMem( cbStr );
if( pszMsgA ){ CopyMemory( pszMsgA, szMsgTextA, cbStr ); } return pszMsgA; }
VOID vDbgLogError( UINT uDbg, UINT uDbgLevel, UINT uLine, LPCSTR pszFileA, LPCSTR pszModuleA, LPCSTR pszMsgA ) { DWORD dwLastError = GetLastError(); VBackTrace* pBackTrace = gpbtTraceLog;
if(( uDbgLevel & DBG_PRINT_MASK & uDbg ) && pszMsgA ){
if( !( uDbgLevel & DBG_NOHEAD )){
OutputDebugStringA( pszModuleA ); } OutputDebugStringA( pszMsgA ); }
if(( uDbgLevel << DBG_BREAK_SHIFT ) & uDbg ){
DebugBreak(); }
//
// Log the failure.
//
//
// Capture significant errors in separate error log.
//
if( uDbgLevel & DBG_ERRLOG_CAPTURE ){ pBackTrace = gpbtErrLog; }
pBackTrace->pvCapture( (DWORD)pszMsgA, uLine | ( uDbgLevel << DBG_BREAK_SHIFT ), (DWORD)pszFileA );
SetLastError( dwLastError ); }
#endif // def DBGLOG
#endif // DBG
/********************************************************************
Initialization
********************************************************************/
#if DBG
BOOL bSplLibInit( VOID ) { BOOL bValid;
bValid = (ghMemHeap = HeapCreate( 0, 1024*4, 0 )) && (ghDbgMemHeap = HeapCreate( 0, 1024*4, 0 )) && (VBackTrace::bInit( )) && (gpbtAlloc = new TBackTraceMem) && (gpbtFree = new TBackTraceMem) && (gpbtErrLog = new TBackTraceMem( VBackTrace::kString )) && (gpbtTraceLog = new TBackTraceMem( VBackTrace::kString )) && (MRefCom::gpcsCom = new MCritSec) && MRefCom::gpcsCom->bValid();
if( bValid ){ gDbgPointers.pfnAllocBackTrace = &DbgAllocBackTrace; gDbgPointers.pfnAllocBackTraceMem = &DbgAllocBackTraceMem; gDbgPointers.pfnFreeBackTrace = &DbgFreeBackTrace; gDbgPointers.pfnCaptureBackTrace = &DbgCaptureBackTrace; gDbgPointers.pfnAllocCritSec = &DbgAllocCritSec; gDbgPointers.pfnFreeCritSec = &DbgFreeCritSec; gDbgPointers.pfnInsideCritSec = &DbgInsideCritSec; gDbgPointers.pfnOutsideCritSec = &DbgOutsideCritSec; gDbgPointers.pfnEnterCritSec = &DbgEnterCritSec; gDbgPointers.pfnLeaveCritSec = &DbgLeaveCritSec;
gDbgPointers.hMemHeap = ghMemHeap; gDbgPointers.hDbgMemHeap = ghDbgMemHeap; gDbgPointers.pbtAlloc = gpbtAlloc; gDbgPointers.pbtFree = gpbtFree; gDbgPointers.pbtErrLog = gpbtErrLog; gDbgPointers.pbtTraceLog = gpbtTraceLog; } return bValid; }
VOID vSplLibFree( VOID ) { SPLASSERT( MRefCom::gpcsCom->bOutside( )); delete MRefCom::gpcsCom;
HeapDestroy( ghMemHeap ); HeapDestroy( ghDbgMemHeap ); }
#else
BOOL bSplLibInit( VOID ) { return ( ghMemHeap = HeapCreate( 0, 1024*4, 0 )) ? TRUE : FALSE; }
VOID vSplLibFree( VOID ) { HeapDestroy( ghMemHeap ); }
#endif
/********************************************************************
Stub these out so non-debug builds will find them.
********************************************************************/
#if !DBG
#ifdef DBGLOG
LPSTR pszDbgAllocMsgA( LPCSTR pszMsgFormatA, ... ) { return NULL; }
VOID vDbgLogError( UINT uDbg, UINT uDbgLevel, UINT uLine, LPCSTR pszFileA, LPCSTR pszModuleA, LPCSTR pszMsgA ) { }
#else
VOID vDbgMsg2( LPCTSTR pszMsgFormat, ... ) { }
#endif // ndef DBGLOG
#endif // !DBG
|