NT4/private/windows/spooler/spllib/debug.cxx
2020-09-30 17:12:29 +02:00

562 lines
11 KiB
C++

/*++
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