435 lines
11 KiB
C++
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
|
||
|
|