Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

722 lines
14 KiB

/*++
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"
#define DEFAULT_TRACE_TYPE TBackTraceMem
//#define DEFAULT_TRACE_TYPE TBackTraceFile // For tracing to file.
#define DEFAULT_MEM_TRACE_TYPE TBackTraceMem
extern HANDLE ghMemHeap;
extern HANDLE ghDbgMemHeap;
extern pfCreateThread gpfSafeCreateThread;
#if DBG
UINT gLogFilter = (UINT)-1;
VBackTrace* gpbtErrLog;
VBackTrace* gpbtTraceLog;
MODULE_DEBUG_INIT( DBG_ERROR, DBG_ERROR );
DBG_POINTERS gDbgPointers;
PDBG_POINTERS gpDbgPointers;
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 HRESULTs.
********************************************************************/
TStatusHBase&
TStatusHBase::
pNoChk(
VOID
)
{
_pszFileA = NULL;
return (TStatusH&)*this;
}
TStatusHBase&
TStatusHBase::
pSetInfo(
UINT uDbg,
UINT uLine,
LPCSTR pszFileA,
LPCSTR pszModuleA
)
{
_uDbg = uDbg;
_uLine = uLine;
_pszFileA = pszFileA;
SPLASSERT( pszFileA );
_pszModuleA = pszModuleA;
return (TStatusH&)*this;
}
HRESULT
TStatusHBase::
operator=(
HRESULT hrStatus
)
{
//
// 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 &&
FAILED(hrStatus) &&
hrStatus != _hrStatusSafe1 &&
hrStatus != _hrStatusSafe2 &&
hrStatus != _hrStatusSafe3 ){
#ifdef DBGLOG
//
// An unexpected error occured. Log an error and continue.
//
vDbgLogError( _uDbg,
_uDbgLevel,
_uLine,
_pszFileA,
_pszModuleA,
pszDbgAllocMsgA( "TStatusH set to %x\nLine %d, %hs\n",
hrStatus,
_uLine,
_pszFileA ));
#else
DBGMSG( DBG_WARN,
( "TStatusH set to %x\nLine %d, %hs\n",
hrStatus,
_uLine,
_pszFileA ));
#endif
}
return _hrStatus = hrStatus;
}
HRESULT
TStatusH::
hrGetStatus(
VOID
)
{
//
// For now, return error code. Later it will return the actual
// error code.
//
return _hrStatus;
}
/********************************************************************
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",
(ULONG_PTR)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();
}
if( gLogFilter & uDbgLevel )
{
//
// Log the failure.
//
//
// Capture significant errors in separate error log.
//
if( uDbgLevel & DBG_ERRLOG_CAPTURE ){
pBackTrace = gpbtErrLog;
}
if (pBackTrace)
{
pBackTrace->hCapture( (ULONG_PTR)pszMsgA,
uLine | ( uDbgLevel << DBG_BREAK_SHIFT ),
(ULONG_PTR)pszFileA );
}
else
{
//
// Backtracing is not enabled, free the message string that is
// passed in.
//
if(pszMsgA)
{
DbgFreeMem((PVOID)pszMsgA);
}
}
}
else
{
//
// Just free up the memory if this line is not captured
// actually this happens when uDbgLevel == DBG_NONE (0)
//
if( pszMsgA )
{
DbgFreeMem( (PVOID)pszMsgA );
}
}
SetLastError( dwLastError );
}
#endif // def DBGLOG
#endif // DBG
/********************************************************************
Initialization
********************************************************************/
#if DBG
BOOL
bSplLibInit(
pfCreateThread pfSafeCreateThread
)
{
BOOL bValid;
bValid = (ghMemHeap = HeapCreate( 0, 1024*4, 0 )) &&
(ghDbgMemHeap = HeapCreate( 0, 1024*4, 0 )) &&
(VBackTrace::bInit( )) &&
#ifdef TRACE_ENABLED
(gpbtAlloc = new DEFAULT_MEM_TRACE_TYPE) &&
(gpbtFree = new DEFAULT_MEM_TRACE_TYPE) &&
(gpbtErrLog = new DEFAULT_TRACE_TYPE( VBackTrace::kString )) &&
(gpbtTraceLog = new DEFAULT_TRACE_TYPE( VBackTrace::kString )) &&
#endif
(MRefCom::gpcsCom = new MCritSec) &&
MRefCom::gpcsCom->bValid();
gpfSafeCreateThread = ( pfSafeCreateThread ) ? pfSafeCreateThread : CreateThread;
if( bValid ){
gDbgPointers.pfnAllocBackTrace = &DbgAllocBackTrace;
gDbgPointers.pfnAllocBackTraceMem = &DbgAllocBackTraceMem;
gDbgPointers.pfnAllocBackTraceFile = &DbgAllocBackTraceFile;
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.pfnSetAllocFail = &DbgSetAllocFail;
gDbgPointers.hMemHeap = ghMemHeap;
gDbgPointers.hDbgMemHeap = ghDbgMemHeap;
gDbgPointers.pbtAlloc = gpbtAlloc;
gDbgPointers.pbtFree = gpbtFree;
gDbgPointers.pbtErrLog = gpbtErrLog;
gDbgPointers.pbtTraceLog = gpbtTraceLog;
gpDbgPointers = &gDbgPointers;
}
return bValid;
}
VOID
vSplLibFree(
VOID
)
{
SPLASSERT( MRefCom::gpcsCom->bOutside( ));
delete MRefCom::gpcsCom;
VBackTrace::vDone();
if (ghMemHeap)
{
HeapDestroy( ghMemHeap );
ghMemHeap = NULL;
}
if (ghDbgMemHeap)
{
HeapDestroy( ghDbgMemHeap );
ghDbgMemHeap = NULL;
}
}
#else
BOOL
bSplLibInit(
pfCreateThread pfSafeCreateThread
)
{
gpfSafeCreateThread = ( pfSafeCreateThread ) ? pfSafeCreateThread : CreateThread;
return ( ghMemHeap = HeapCreate( 0, 1024*4, 0 )) ?
TRUE : FALSE;
}
VOID
vSplLibFree(
VOID
)
{
if (ghMemHeap)
{
HeapDestroy( ghMemHeap );
ghMemHeap = NULL;
}
}
#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