windows-nt/Source/XPSP1/NT/com/svcdlls/trksvcs/common/debug.cxx
2020-09-26 16:20:57 +08:00

435 lines
11 KiB
C++

// Copyright (c) 1996-1999 Microsoft Corporation
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// File: debug.cxx
//
// Contents: Debug support.
//
// Classes:
//
// Functions:
//
//
//
// History: 18-Nov-96 BillMo Created.
//
// Notes:
//
// Codework:
//
//--------------------------------------------------------------------------
#include "pch.cxx"
#pragma hdrstop
#include "trklib.hxx"
#include <stdio.h> // vsprintf
#if DBG == 1
//CFailPoint * CFailPoint::g_pList = NULL;
#define TRKSVC_LOG_FILE TEXT("%SystemRoot%\\debug\\trksvcs.log")
CHAR TrkGlobalDebugBuffer[ 1024]; // arbitrary
DWORD TrkGlobalDebug;
HANDLE g_LogFile = INVALID_HANDLE_VALUE;
// This critical section is used to serialize simultaneous dbgout calls.
CRITICAL_SECTION g_csDebugOut;
LONG g_cCritSecInit = 0;
CHAR g_szDebugBuffer[ 1024]; // arbitrary
TCHAR g_tszDebugBuffer[ 1024 ];
ULONG g_grfDebugFlags = 0;
ULONG g_grfLogFlags = 0;
CHAR g_szModuleName[ MAX_PATH ] = { "" };
LONG g_cInitializations = 0;
VOID TrkDebugDelete( VOID)
{
// This isn't thread safe, so we won't ever delete it.
// It just means there's a one-time leak in the chk build
// when the service gets stopped.
//if( 0 == InterlockedDecrement( &g_cCritSecInit ))
// DeleteCriticalSection( &g_csDebugOut);
InterlockedDecrement(&g_cInitializations);
if( INVALID_HANDLE_VALUE != g_LogFile )
{
CloseHandle( g_LogFile );
g_LogFile = INVALID_HANDLE_VALUE;
}
}
VOID TrkDebugCreate( ULONG grfLogFlags, CHAR *pszModuleName )
{
TCHAR Buffer[ MAX_PATH];
DWORD Length;
if( 1 < InterlockedIncrement(&g_cInitializations) ) return;
strncpy( g_szModuleName, pszModuleName, sizeof(g_szModuleName) );
g_szModuleName[ sizeof(g_szModuleName) - 1 ] = TEXT('\0');
if( 1 == InterlockedIncrement( &g_cCritSecInit ))
InitializeCriticalSection( &g_csDebugOut );
if( (TRK_DBG_FLAGS_WRITE_TO_FILE | TRK_DBG_FLAGS_APPEND_TO_FILE) & grfLogFlags )
{
//
// Length returned by ExpandEnvironmentalStrings includes terminating
// NULL byte.
//
Length = ExpandEnvironmentStrings( TRKSVC_LOG_FILE, Buffer, sizeof( Buffer));
if ( Length == 0) {
TrkLog(( TRKDBG_ERROR, TEXT("Error=%d"), GetLastError()));
return;
}
if ( Length > sizeof( Buffer) || Length != _tcslen(Buffer) + 1) {
Beep(2000,2000);
TrkLog(( TRKDBG_ERROR, TEXT("Buffer=%x, Length = %d"), Buffer, Length));
return;
}
g_LogFile = CreateFile( Buffer,
GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
NULL,
(TRK_DBG_FLAGS_APPEND_TO_FILE & grfLogFlags)
? OPEN_ALWAYS
: CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL );
if ( g_LogFile == INVALID_HANDLE_VALUE ) {
TCHAR tsz[ 2 * MAX_PATH ];
_stprintf( tsz, TEXT("Cannot open %s (%lu)\n"),
Buffer, GetLastError() );
OutputDebugString( tsz );
return;
}
if( TRK_DBG_FLAGS_APPEND_TO_FILE & grfLogFlags )
{
//
// Position the log file at the end
//
(VOID) SetFilePointer( g_LogFile,
0,
NULL,
FILE_END );
}
else
{
//
// Truncate the file
//
SetFilePointer( g_LogFile, 0, NULL, FILE_BEGIN );
SetEndOfFile( g_LogFile );
}
}
g_grfLogFlags = grfLogFlags;
}
VOID TrkLogRoutine(
IN DWORD DebugFlag,
IN LPTSTR Format,
...
)
{
LONG l = GetLastError();
va_list Arguments;
va_start( Arguments, Format );
TrkLogErrorRoutineInternal( DebugFlag, NULL, Format, Arguments );
SetLastError(l);
}
VOID TrkLogErrorRoutine(
IN DWORD DebugFlag,
IN HRESULT hr,
IN LPTSTR Format,
...
)
{
CHAR szHR[8];
va_list Arguments;
va_start( Arguments, Format );
sprintf( szHR, "%08X", hr );
TrkLogErrorRoutineInternal( DebugFlag, szHR, Format, Arguments );
}
VOID TrkLogErrorRoutineInternal(
IN DWORD DebugFlag,
IN LPSTR pszHR,
IN LPTSTR Format,
IN va_list Arguments
)
{
// va_list arglist;
ULONG length = 0;
DWORD BytesWritten;
ULONG iFormatStart = 0;
// Skip if TrkDebugCreate hasn't been called yet.
if( 0 == g_grfLogFlags )
return;
//
// If we aren't debugging this type of message and it's not an
// error, then we're done.
//
if( !( (g_grfDebugFlags | TRKDBG_ERROR ) & DebugFlag ) )
return;
//
// vsprintf isn't multithreaded + we don't want to intermingle output
// from different threads. Therefore we can use just a single output
// debug buffer.
//
EnterCriticalSection( &g_csDebugOut );
//
// Prefix the line with any newlines
//
for( iFormatStart = 0; TEXT('\n') == Format[iFormatStart]; iFormatStart++ )
g_szDebugBuffer[length++] = '\n';
//
// Put our name/time at the beginning of the line.
//
CFILETIME cftLocal(0);
cftLocal.SetToLocal();
SYSTEMTIME st = static_cast<SYSTEMTIME>( cftLocal );
length += (ULONG) sprintf( &g_szDebugBuffer[length],
"[%s/%02d%02d%02d.%03d:%03x] ",
g_szModuleName,
st.wHour, st.wMinute, st.wSecond, st.wMilliseconds,
GetCurrentThreadId() );
//
// Put the information requested by the caller onto the line
//
_vstprintf( g_tszDebugBuffer, &Format[iFormatStart], Arguments );
tcstombs( &g_szDebugBuffer[length], g_tszDebugBuffer );
length = strlen( g_szDebugBuffer );
if( NULL != pszHR )
length += (ULONG) sprintf( &g_szDebugBuffer[length], " %s", pszHR );
length += (ULONG) sprintf( &g_szDebugBuffer[length], "\n" );
TrkAssert(length <= sizeof(g_szDebugBuffer));
if( TRK_DBG_FLAGS_WRITE_TO_DBG & g_grfLogFlags )
(void) OutputDebugStringA( (PCH) g_szDebugBuffer);
if( TRK_DBG_FLAGS_WRITE_TO_STDOUT & g_grfLogFlags )
printf( (PCH) g_szDebugBuffer );
if( (TRK_DBG_FLAGS_WRITE_TO_FILE | TRK_DBG_FLAGS_APPEND_TO_FILE) & g_grfLogFlags )
{
if ( INVALID_HANDLE_VALUE == g_LogFile
||
!WriteFile( g_LogFile,
g_szDebugBuffer,
length,
&BytesWritten,
NULL ) )
{
(void) OutputDebugStringA( (PCH) g_szDebugBuffer);
}
}
LeaveCriticalSection( &g_csDebugOut );
}
VOID TrkAssertFailed(
IN PVOID FailedAssertion,
IN PVOID FileName,
IN ULONG LineNumber,
IN PCHAR Message OPTIONAL
)
/*++
Have my own version of RtlAssert so debug versions of netlogon really assert on
free builds.
--*/
{
char Response[ 2 ];
for ( ; ; ) {
DbgPrint( "\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n",
Message ? Message : "",
FailedAssertion,
FileName,
LineNumber
);
DbgPrompt( "Break, Ignore, terminate Process, Sleep 30 seconds, or terminate Thread (bipst)? ",
Response, sizeof( Response));
switch ( toupper(Response[0])) {
case 'B':
DbgBreakPoint();
break;
case 'I':
return;
break;
case 'P':
NtTerminateProcess( NtCurrentProcess(), STATUS_UNSUCCESSFUL );
break;
case 'S':
Sleep( 30000L);
break;
case 'T':
NtTerminateThread( NtCurrentThread(), STATUS_UNSUCCESSFUL );
break;
}
}
DbgBreakPoint();
NtTerminateProcess( NtCurrentProcess(), STATUS_UNSUCCESSFUL );
}
typedef void (*PFNWin4AssertEx)( char const *pszFile, int iLine, char const *pszMsg);
VOID TrkAssertFailedDlg(
IN PVOID FailedAssertion,
IN PVOID FileName,
IN ULONG LineNumber,
IN PCHAR Message OPTIONAL
)
{
static HINSTANCE hinstOLE32 = NULL;
static PFNWin4AssertEx pfnWin4AssertEx = NULL;
if( NULL == hinstOLE32 )
{
hinstOLE32 = LoadLibraryEx( TEXT("ole32.dll"), NULL, 0 );
if( NULL == hinstOLE32 )
{
TrkLog(( TRKDBG_ERROR, TEXT("Couldn't load ole32.dll for Win4AssertEx (%#08x)"),
GetLastError() ));
return;
}
}
if( NULL == pfnWin4AssertEx )
{
pfnWin4AssertEx = (PFNWin4AssertEx) GetProcAddress( hinstOLE32, "Win4AssertEx" );
if( NULL == pfnWin4AssertEx )
{
TrkLog(( TRKDBG_ERROR, TEXT("Couldn't get Win4AssertEx from ole32.dll (%#08x)"),
GetLastError() ));
return;
}
}
pfnWin4AssertEx( (char*) FileName, (int) LineNumber, (char*) FailedAssertion );
return;
}
VOID TrkLogRuntimeList( IN PCHAR Comment)
{
PLIST_ENTRY pListEntry;
TrkLog(( TRKDBG_ERROR, TEXT("%s\n"), Comment));
}
HANDLE hTestThread = NULL;
/*
DWORD WINAPI _TestWorkManagerThread(LPVOID pParam)
{
__try
{
((CWorkManager*) pParam)->WorkManagerThread();
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
TrkAssert(GetExceptionCode() != STATUS_ACCESS_VIOLATION);
}
return(0);
}
void
StartTestWorkerThread(CWorkManager * pwm)
{
DWORD dwThreadId;
hTestThread = CreateThread( NULL,
0,
_TestWorkManagerThread,
pwm,
0,
&dwThreadId );
TrkAssert(hTestThread != NULL);
// Hack: make sure the work manager has a chance to init
Sleep( 500 );
}
void
WaitTestThreadExit()
{
if (hTestThread != NULL)
{
WaitForSingleObject(hTestThread, INFINITE);
CloseHandle(hTestThread);
}
}
*/
#endif // #if DBG == 1