Leaked source code of windows server 2003
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.
 
 
 
 
 
 

554 lines
12 KiB

/*
* debug.c - Debug functions module.
*/
/* Headers
**********/
#include "project.h"
#include <shlwapi.h>
#pragma hdrstop
/* Constants
************/
#ifdef DEBUG
#define LOG_FILE_NAME TEXT("debug.log")
#endif
/* Types
********/
#ifdef DEBUG
/* debug flags */
typedef enum _debugdebugflags
{
DEBUG_DFL_ENABLE_TRACE_MESSAGES = 0x0001,
DEBUG_DFL_LOG_TRACE_MESSAGES = 0x0002,
DEBUG_DFL_DUMP_THREAD_ID = 0x0004,
DEBUG_DFL_DUMP_LAST_ERROR = 0x0008,
ALL_DEBUG_DFLAGS = (DEBUG_DFL_ENABLE_TRACE_MESSAGES |
DEBUG_DFL_LOG_TRACE_MESSAGES |
DEBUG_DFL_DUMP_THREAD_ID |
DEBUG_DFL_DUMP_LAST_ERROR)
}
DEBUGDEBUGFLAGS;
#endif
/* Global Variables
*******************/
#ifdef DEBUG
/* parameters used by SpewOut() */
PUBLIC_DATA DWORD GdwSpewFlags = 0;
PUBLIC_DATA UINT GuSpewSev = 0;
PUBLIC_DATA UINT GuSpewLine = 0;
PUBLIC_DATA LPCTSTR GpcszSpewFile = NULL;
#endif /* DEBUG */
/* Module Variables
*******************/
#ifdef DEBUG
/* TLS slot used to store stack depth for SpewOut() indentation */
PRIVATE_DATA DWORD MdwStackDepthSlot = TLS_OUT_OF_INDEXES;
/* hack stack depth counter used until MdwStackDepthSlot is not available */
PRIVATE_DATA ULONG MulcHackStackDepth = 0;
/* debug flags */
PRIVATE_DATA DWORD MdwDebugModuleFlags = 0;
/* .ini file switch descriptions */
PRIVATE_DATA CBOOLINISWITCH cbisEnableTraceMessages =
{
IST_BOOL,
TEXT("EnableTraceMessages"),
&MdwDebugModuleFlags,
DEBUG_DFL_ENABLE_TRACE_MESSAGES
};
PRIVATE_DATA CBOOLINISWITCH cbisLogTraceMessages =
{
IST_BOOL,
TEXT("LogTraceMessages"),
&MdwDebugModuleFlags,
DEBUG_DFL_LOG_TRACE_MESSAGES
};
PRIVATE_DATA CBOOLINISWITCH cbisDumpThreadID =
{
IST_BOOL,
TEXT("DumpThreadID"),
&MdwDebugModuleFlags,
DEBUG_DFL_DUMP_THREAD_ID
};
PRIVATE_DATA CBOOLINISWITCH cbisDumpLastError =
{
IST_BOOL,
TEXT("DumpLastError"),
&MdwDebugModuleFlags,
DEBUG_DFL_DUMP_LAST_ERROR
};
PRIVATE_DATA const PCVOID MrgcpcvisDebugModule[] =
{
&cbisLogTraceMessages,
&cbisEnableTraceMessages,
&cbisDumpThreadID,
&cbisDumpLastError
};
#endif /* DEBUG */
/***************************** Private Functions *****************************/
/* Module Prototypes
********************/
#ifdef DEBUG
PRIVATE_CODE BOOL LogOutputDebugString(LPCTSTR);
PRIVATE_CODE BOOL IsValidSpewSev(UINT);
#endif /* DEBUG */
#ifdef DEBUG
/*
** LogOutputDebugString()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL LogOutputDebugString(LPCTSTR pcsz)
{
BOOL bResult = FALSE;
UINT ucb;
TCHAR rgchLogFile[MAX_PATH_LEN];
ASSERT(IS_VALID_STRING_PTR(pcsz, CSTR));
ucb = GetWindowsDirectory(rgchLogFile, ARRAYSIZE(rgchLogFile));
if (ucb > 0 && ucb < ARRAYSIZE(rgchLogFile))
{
HANDLE hfLog;
StrCatBuff(rgchLogFile, TEXT("\\"), ARRAYSIZE(rgchLogFile));
StrCatBuff(rgchLogFile, LOG_FILE_NAME, ARRAYSIZE(rgchLogFile));
hfLog = CreateFile(rgchLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
FILE_FLAG_WRITE_THROUGH, NULL);
if (hfLog != INVALID_HANDLE_VALUE)
{
if (SetFilePointer(hfLog, 0, NULL, FILE_END) != INVALID_SEEK_POSITION)
{
DWORD dwcbWritten;
bResult = WriteFile(hfLog, pcsz, lstrlen(pcsz)*SIZEOF(TCHAR), &dwcbWritten, NULL);
if (! CloseHandle(hfLog) && bResult)
bResult = FALSE;
}
}
}
return(bResult);
}
/*
** IsValidSpewSev()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL IsValidSpewSev(UINT uSpewSev)
{
BOOL bResult;
switch (uSpewSev)
{
case SPEW_TRACE:
case SPEW_WARNING:
case SPEW_ERROR:
case SPEW_FATAL:
bResult = TRUE;
break;
default:
ERROR_OUT((TEXT("IsValidSpewSev(): Invalid debug spew severity %u."),
uSpewSev));
bResult = FALSE;
break;
}
return(bResult);
}
#endif /* DEBUG */
/****************************** Public Functions *****************************/
#ifdef DEBUG
/*
** SetDebugModuleIniSwitches()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL SetDebugModuleIniSwitches(void)
{
BOOL bResult;
bResult = SetIniSwitches(MrgcpcvisDebugModule,
ARRAY_ELEMENTS(MrgcpcvisDebugModule));
ASSERT(FLAGS_ARE_VALID(MdwDebugModuleFlags, ALL_DEBUG_DFLAGS));
return(bResult);
}
/*
** InitDebugModule()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL InitDebugModule(void)
{
ASSERT(MdwStackDepthSlot == TLS_OUT_OF_INDEXES);
MdwStackDepthSlot = TlsAlloc();
if (MdwStackDepthSlot != TLS_OUT_OF_INDEXES)
{
EVAL(TlsSetValue(MdwStackDepthSlot, IntToPtr(MulcHackStackDepth)));
TRACE_OUT((TEXT("InitDebugModule(): Using thread local storage slot %lu for debug stack depth counter."),
MdwStackDepthSlot));
}
else
WARNING_OUT((TEXT("InitDebugModule(): TlsAlloc() failed to allocate thread local storage for debug stack depth counter.")));
return(TRUE);
}
/*
** ExitDebugModule()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE void ExitDebugModule(void)
{
if (MdwStackDepthSlot != TLS_OUT_OF_INDEXES)
{
MulcHackStackDepth = PtrToUlong(TlsGetValue(MdwStackDepthSlot));
/* Leave MulcHackStackDepth == 0 if TlsGetValue() fails. */
EVAL(TlsFree(MdwStackDepthSlot));
MdwStackDepthSlot = TLS_OUT_OF_INDEXES;
}
return;
}
/*
** StackEnter()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE void StackEnter(void)
{
if (MdwStackDepthSlot != TLS_OUT_OF_INDEXES)
{
ULONG ulcDepth;
ulcDepth = PtrToUlong(TlsGetValue(MdwStackDepthSlot));
ASSERT(ulcDepth < ULONG_MAX);
EVAL(TlsSetValue(MdwStackDepthSlot, IntToPtr(ulcDepth + 1)));
}
else
{
ASSERT(MulcHackStackDepth < ULONG_MAX);
InterlockedIncrement(&MulcHackStackDepth);
}
return;
}
/*
** StackLeave()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE void StackLeave(void)
{
if (MdwStackDepthSlot != TLS_OUT_OF_INDEXES)
{
ULONG ulcDepth;
ulcDepth = PtrToUlong(TlsGetValue(MdwStackDepthSlot));
if (EVAL(ulcDepth > 0))
EVAL(TlsSetValue(MdwStackDepthSlot, IntToPtr(ulcDepth - 1)));
}
else
{
if (EVAL(MulcHackStackDepth > 0))
InterlockedDecrement(&MulcHackStackDepth);
}
return;
}
/*
** GetStackDepth()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE ULONG GetStackDepth(void)
{
ULONG ulcDepth;
if (MdwStackDepthSlot != TLS_OUT_OF_INDEXES)
ulcDepth = PtrToUlong(TlsGetValue(MdwStackDepthSlot));
else
ulcDepth = MulcHackStackDepth;
return(ulcDepth);
}
/*
** SpewOut()
**
** Spews out a formatted message to the debug terminal.
**
** Arguments: pcszFormat - pointer to wvnsprintf() format string
** ... - formatting arguments ala wvnsprintf()
**
** Returns: void
**
** Side Effects: none
**
** N.b., this function assumes the global variables GdwSpewFlags, GuSpewSev,
** GpcszSpewModule, GpcszSpewFile, and GpcszSpewLine are filled in.
**
** SpewOut() uses global variables to set the message parameters in order to
** permit printf()-style macro expansion.
*/
PUBLIC_CODE void __cdecl SpewOut(LPCTSTR pcszFormat, ...)
{
va_list arglist;
ASSERT(IS_VALID_STRING_PTR(pcszFormat, CSTR));
ASSERT(FLAGS_ARE_VALID(GdwSpewFlags, ALL_SPEW_FLAGS));
ASSERT(IsValidSpewSev(GuSpewSev));
ASSERT(IS_FLAG_CLEAR(GdwSpewFlags, SPEW_FL_SPEW_LOCATION) ||
(IS_VALID_STRING_PTR(GpcszSpewFile, CSTR) &&
IS_VALID_STRING_PTR(GpcszSpewModule, CSTR)));
if (GuSpewSev != SPEW_TRACE || IS_FLAG_SET(MdwDebugModuleFlags, DEBUG_DFL_ENABLE_TRACE_MESSAGES))
{
int nMsgLen;
TCHAR rgchMsg[1024];
if (IS_FLAG_SET(GdwSpewFlags, SPEW_FL_SPEW_PREFIX))
{
static TCHAR SrgchSpewLeader[] = TEXT(" ");
ULONG ulcStackDepth;
TCHAR chReplaced;
LPTSTR pszSpewLeaderEnd;
LPCTSTR pcszSpewPrefix;
/* Build spew message space leader string. */
ulcStackDepth = GetStackDepth();
if (ulcStackDepth < ARRAYSIZE(SrgchSpewLeader))
pszSpewLeaderEnd = SrgchSpewLeader + ulcStackDepth;
else
pszSpewLeaderEnd = SrgchSpewLeader + ARRAYSIZE(SrgchSpewLeader) - 1;
chReplaced = *pszSpewLeaderEnd;
*pszSpewLeaderEnd = TEXT('\0');
/* Determine spew prefix. */
switch (GuSpewSev)
{
case SPEW_TRACE:
pcszSpewPrefix = TEXT("t");
break;
case SPEW_WARNING:
pcszSpewPrefix = TEXT("w");
break;
case SPEW_ERROR:
pcszSpewPrefix = TEXT("e");
break;
case SPEW_FATAL:
pcszSpewPrefix = TEXT("f");
break;
default:
pcszSpewPrefix = TEXT("u");
ERROR_OUT((TEXT("SpewOut(): Invalid GuSpewSev %u."),
GuSpewSev));
break;
}
nMsgLen = wnsprintf(rgchMsg, ARRAYSIZE(rgchMsg), TEXT("%s%s %s "), SrgchSpewLeader, pcszSpewPrefix, GpcszSpewModule);
/* Restore spew leader. */
*pszSpewLeaderEnd = chReplaced;
ASSERT(nMsgLen < ARRAYSIZE(rgchMsg));
}
else
nMsgLen = 0;
/* Append thread ID. */
if (IS_FLAG_SET(MdwDebugModuleFlags, DEBUG_DFL_DUMP_THREAD_ID))
{
nMsgLen += wnsprintf(rgchMsg + nMsgLen, ARRAYSIZE(rgchMsg) - nMsgLen, TEXT("%#lx "), GetCurrentThreadId());
ASSERT(nMsgLen < ARRAYSIZE(rgchMsg));
}
/* Build position string. */
if (IS_FLAG_SET(GdwSpewFlags, SPEW_FL_SPEW_LOCATION))
{
nMsgLen += wnsprintf(rgchMsg + nMsgLen, ARRAYSIZE(rgchMsg) - nMsgLen, TEXT("(%s line %u): "), GpcszSpewFile, GuSpewLine);
ASSERT(nMsgLen < ARRAYSIZE(rgchMsg));
}
/* Append message string. */
va_start(arglist,pcszFormat);
nMsgLen += wvnsprintf(rgchMsg + nMsgLen, ARRAYSIZE(rgchMsg) - nMsgLen, pcszFormat, arglist);
va_end(arglist);
ASSERT(nMsgLen < ARRAYSIZE(rgchMsg));
if (IS_FLAG_SET(GdwSpewFlags, DEBUG_DFL_DUMP_THREAD_ID))
{
if (GuSpewSev == SPEW_ERROR ||
GuSpewSev == SPEW_FATAL)
{
nMsgLen += wnsprintf(rgchMsg + nMsgLen, ARRAYSIZE(rgchMsg) - nMsgLen, TEXT(" (GetLastError() == %lu)"), GetLastError());
ASSERT(nMsgLen < ARRAYSIZE(rgchMsg));
}
}
nMsgLen += wnsprintf(rgchMsg + nMsgLen, ARRAYSIZE(rgchMsg) - nMsgLen, TEXT("\r\n"));
ASSERT(nMsgLen < ARRAYSIZE(rgchMsg));
OutputDebugString(rgchMsg);
if (IS_FLAG_SET(MdwDebugModuleFlags, DEBUG_DFL_LOG_TRACE_MESSAGES))
{
LogOutputDebugString(rgchMsg);
LogOutputDebugString(TEXT("\r\n"));
}
}
/* Break here on errors and fatal errors. */
if (GuSpewSev == SPEW_ERROR || GuSpewSev == SPEW_FATAL)
DebugBreak();
return;
}
#endif /* DEBUG */