|
|
/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
debug.c
Abstract:
This file contains debugging macros for the BINL server.
Author:
Madan Appiah (madana) 10-Sep-1993
Environment:
User Mode - Win32
Revision History:
--*/
#include "binl.h"
#pragma hdrstop
const char g_szTrue[] = "True"; const char g_szFalse[] = "False";
DWORD DebugRefCount = 0;
VOID DebugInitialize ( VOID ) { DWORD dwErr; HKEY KeyHandle;
//
// only initialize debugging once.
//
InterlockedIncrement(&DebugRefCount); if (DebugRefCount > 1) { return; }
InitializeCriticalSection(&BinlGlobalDebugFileCritSect); BinlGlobalDebugFileHandle = NULL;
BinlGlobalDebugFileMaxSize = DEFAULT_MAXIMUM_DEBUGFILE_SIZE; BinlGlobalDebugSharePath = NULL;
// Read DebugFlags value
dwErr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, BINL_PARAMETERS_KEY, 0, KEY_QUERY_VALUE, &KeyHandle ); if ( dwErr == ERROR_SUCCESS ) { BinlGlobalDebugFlag = ReadDWord( KeyHandle, BINL_DEBUG_KEY, 0 ); BinlPrintDbg(( DEBUG_OPTIONS, "Debug Flags = 0x%08x.\n", BinlGlobalDebugFlag )); RegCloseKey( KeyHandle ); }
#if DBG
// break in the debugger if we are asked to do so.
if(BinlGlobalDebugFlag & DEBUG_STARTUP_BRK) { BinlPrintDbg(( 0, "Stopping at DebugInitialize()'s DebugBreak( ).\n" )); DebugBreak(); } #endif
//
// Open debug log file.
//
if ( BinlGlobalDebugFlag & DEBUG_LOG_IN_FILE ) { BinlOpenDebugFile( FALSE ); // not a reopen.
}
} // DebugInitialize
VOID DebugUninitialize ( VOID ) { //
// Make sure debugging has been initialized before we go
// uninitializing it.
//
if( DebugRefCount == 0 ) { // do nothing.
return; }
//
// Don't uninitialize if there are other's depending on
// our debugging engine.
//
InterlockedDecrement(&DebugRefCount); if (DebugRefCount > 0) { return; } EnterCriticalSection( &BinlGlobalDebugFileCritSect ); if ( BinlGlobalDebugFileHandle != NULL ) { CloseHandle( BinlGlobalDebugFileHandle ); BinlGlobalDebugFileHandle = NULL; }
if( BinlGlobalDebugSharePath != NULL ) { BinlFreeMemory( BinlGlobalDebugSharePath ); BinlGlobalDebugSharePath = NULL; }
LeaveCriticalSection( &BinlGlobalDebugFileCritSect );
DeleteCriticalSection( &BinlGlobalDebugFileCritSect );
} // DebugUninitialize
VOID BinlOpenDebugFile( IN BOOL ReopenFlag ) /*++
Routine Description:
Opens or re-opens the debug file
Arguments:
ReopenFlag - TRUE to indicate the debug file is to be closed, renamed, and recreated.
Return Value:
None
--*/
{ WCHAR LogFileName[500]; WCHAR BakFileName[500]; DWORD FileAttributes; DWORD PathLength; DWORD WinError;
//
// Close the handle to the debug file, if it is currently open
//
EnterCriticalSection( &BinlGlobalDebugFileCritSect ); if ( BinlGlobalDebugFileHandle != NULL ) { CloseHandle( BinlGlobalDebugFileHandle ); BinlGlobalDebugFileHandle = NULL; } LeaveCriticalSection( &BinlGlobalDebugFileCritSect );
//
// make debug directory path first, if it is not made before.
//
if( BinlGlobalDebugSharePath == NULL ) {
if ( !GetWindowsDirectoryW( LogFileName, sizeof(LogFileName)/sizeof(WCHAR) ) ) { BinlPrintDbg((DEBUG_ERRORS, "Window Directory Path can't be " "retrieved, %lu.\n", GetLastError() )); return; }
//
// check debug path length.
//
PathLength = wcslen(LogFileName) * sizeof(WCHAR) + sizeof(DEBUG_DIR) + sizeof(WCHAR);
if( (PathLength + sizeof(DEBUG_FILE) > sizeof(LogFileName) ) || (PathLength + sizeof(DEBUG_BAK_FILE) > sizeof(BakFileName) ) ) {
BinlPrintDbg((DEBUG_ERRORS, "Debug directory path (%ws) length is too long.\n", LogFileName)); goto ErrorReturn; }
wcscat(LogFileName, DEBUG_DIR);
//
// copy debug directory name to global var.
//
BinlGlobalDebugSharePath = BinlAllocateMemory( (wcslen(LogFileName) + 1) * sizeof(WCHAR) );
if( BinlGlobalDebugSharePath == NULL ) { BinlPrintDbg((DEBUG_ERRORS, "Can't allocate memory for debug share " "(%ws).\n", LogFileName)); goto ErrorReturn; }
wcscpy(BinlGlobalDebugSharePath, LogFileName); } else { wcscpy(LogFileName, BinlGlobalDebugSharePath); }
//
// Check this path exists.
//
FileAttributes = GetFileAttributesW( LogFileName );
if( FileAttributes == 0xFFFFFFFF ) {
WinError = GetLastError(); if( WinError == ERROR_FILE_NOT_FOUND ) {
//
// Create debug directory.
//
if( !CreateDirectoryW( LogFileName, NULL) ) { BinlPrintDbg((DEBUG_ERRORS, "Can't create Debug directory (%ws), " "%lu.\n", LogFileName, GetLastError() )); goto ErrorReturn; }
} else { BinlPrintDbg((DEBUG_ERRORS, "Can't Get File attributes(%ws), " "%lu.\n", LogFileName, WinError )); goto ErrorReturn; } } else {
//
// if this is not a directory.
//
if(!(FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
BinlPrintDbg((DEBUG_ERRORS, "Debug directory path (%ws) exists " "as file.\n", LogFileName)); goto ErrorReturn; } }
//
// Create the name of the old and new log file names
//
(VOID) wcscpy( BakFileName, LogFileName ); (VOID) wcscat( LogFileName, DEBUG_FILE ); (VOID) wcscat( BakFileName, DEBUG_BAK_FILE );
//
// If this is a re-open,
// delete the backup file,
// rename the current file to the backup file.
//
if ( ReopenFlag ) {
if ( !DeleteFile( BakFileName ) ) { WinError = GetLastError(); if ( WinError != ERROR_FILE_NOT_FOUND ) { BinlPrintDbg((DEBUG_ERRORS, "Cannot delete %ws (%ld)\n", BakFileName, WinError )); BinlPrintDbg((DEBUG_ERRORS, " Try to re-open the file.\n")); ReopenFlag = FALSE; // Don't truncate the file
} } }
if ( ReopenFlag ) { if ( !MoveFile( LogFileName, BakFileName ) ) { BinlPrintDbg((DEBUG_ERRORS, "Cannot rename %ws to %ws (%ld)\n", LogFileName, BakFileName, GetLastError() )); BinlPrintDbg((DEBUG_ERRORS, " Try to re-open the file.\n")); ReopenFlag = FALSE; // Don't truncate the file
} }
//
// Open the file.
//
EnterCriticalSection( &BinlGlobalDebugFileCritSect ); BinlGlobalDebugFileHandle = CreateFileW( LogFileName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, ReopenFlag ? CREATE_ALWAYS : OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if ( BinlGlobalDebugFileHandle == INVALID_HANDLE_VALUE ) { BinlPrintDbg((DEBUG_ERRORS, "cannot open %ws ,\n", LogFileName )); LeaveCriticalSection( &BinlGlobalDebugFileCritSect ); goto ErrorReturn; } else { // Position the log file at the end
(VOID) SetFilePointer( BinlGlobalDebugFileHandle, 0, NULL, FILE_END ); }
LeaveCriticalSection( &BinlGlobalDebugFileCritSect ); return;
ErrorReturn: BinlPrintDbg((DEBUG_ERRORS, " Debug output will be written to debug terminal.\n")); return; }
#define MAX_PRINTF_LEN 1024 // Arbitrary.
char OutputBuffer[MAX_PRINTF_LEN]; // protected by BinlGlobalDebugFileCritSect
VOID BinlPrintRoutine( IN DWORD DebugFlag, IN LPSTR Format, ... )
{ va_list arglist; ULONG length; DWORD BytesWritten; static BeginningOfLine = TRUE; static LineCount = 0; static TruncateLogFileInProgress = FALSE; LPSTR Text;
//
// If we aren't debugging this functionality, just return.
//
if ( DebugFlag != 0 && (BinlGlobalDebugFlag & DebugFlag) == 0 ) { return; }
//
// vsprintf isn't multithreaded + we don't want to intermingle output
// from different threads.
//
EnterCriticalSection( &BinlGlobalDebugFileCritSect ); length = 0;
//
// Handle the beginning of a new line.
//
//
if ( BeginningOfLine ) {
//
// If the log file is getting huge,
// truncate it.
//
if ( BinlGlobalDebugFileHandle != NULL && !TruncateLogFileInProgress ) {
//
// Only check every 50 lines,
//
LineCount++; if ( LineCount >= 50 ) { DWORD FileSize; LineCount = 0;
//
// Is the log file too big?
//
FileSize = GetFileSize( BinlGlobalDebugFileHandle, NULL ); if ( FileSize == 0xFFFFFFFF ) { (void) DbgPrint( "[BinlServer] Cannot GetFileSize %ld\n", GetLastError() ); } else if ( FileSize > BinlGlobalDebugFileMaxSize ) { TruncateLogFileInProgress = TRUE; LeaveCriticalSection( &BinlGlobalDebugFileCritSect ); BinlOpenDebugFile( TRUE ); BinlPrint(( DEBUG_MISC, "Logfile truncated because it was larger than %ld bytes\n", BinlGlobalDebugFileMaxSize )); EnterCriticalSection( &BinlGlobalDebugFileCritSect ); TruncateLogFileInProgress = FALSE; }
} }
// Indicate this is a BINL server's message.
length += (ULONG) sprintf( &OutputBuffer[length], "[BinlServer] " );
//
// Put the thread id at the begining of the line.
//
if (BinlGlobalDebugFlag & DEBUG_THREAD) { DWORD threadId = GetCurrentThreadId(); length += (ULONG) sprintf( &OutputBuffer[length], "%08x ", threadId ); }
//
// Put the timestamp at the begining of the line.
//
if (BinlGlobalDebugFlag & DEBUG_TIMESTAMP) { SYSTEMTIME SystemTime; GetLocalTime( &SystemTime ); length += (ULONG) sprintf( &OutputBuffer[length], "%02u/%02u %02u:%02u:%02u ", SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond ); }
//
// Indicate the type of message on the line
//
switch (DebugFlag) { case DEBUG_OPTIONS: Text = "OPTIONS"; break;
case DEBUG_ERRORS: Text = "ERRORS"; break;
case DEBUG_STOC: Text = "STOC"; break;
case DEBUG_INIT: Text = "INIT"; break;
case DEBUG_SCAVENGER: Text = "SCAVENGER"; break;
case DEBUG_REGISTRY: Text = "REGISTRY"; break;
case DEBUG_NETINF: Text = "NETINF"; break;
case DEBUG_MISC: Text = "MISC"; break;
case DEBUG_MESSAGE: Text = "MESSAGE"; break;
case DEBUG_LOG_IN_FILE: Text = "LOG_IN_FILE"; break;
default: Text = NULL; break; }
if ( Text != NULL ) { length += (ULONG) sprintf( &OutputBuffer[length], "[%s] ", Text ); } }
//
// Put a the information requested by the caller onto the line
//
va_start(arglist, Format);
length += (ULONG) vsprintf(&OutputBuffer[length], Format, arglist); BeginningOfLine = (length > 0 && OutputBuffer[length-1] == '\n' );
va_end(arglist);
// Add in the fix for notepad users and fixing the assert
BinlAssert(length < MAX_PRINTF_LEN - 1); if(BeginningOfLine){ OutputBuffer[length-1] = '\r'; OutputBuffer[length] = '\n'; length++; OutputBuffer[length] = '\0'; }
//
// Output to the debug terminal,
// if the log file isn't open or we are asked to do so.
//
if ( (BinlGlobalDebugFileHandle == NULL) || !(BinlGlobalDebugFlag & DEBUG_LOG_IN_FILE) ) {
//
// Don't use DbgPrint(OutputBuffer) here because the buffer
// might contain strings that printf will try to interpret
// (e.g., NewMachineNamingPolicy = %1Fist%Last%#).
//
(void) DbgPrint( "%s", (PCH)OutputBuffer);
//
// Write the debug info to the log file.
//
} else { if ( !WriteFile( BinlGlobalDebugFileHandle, OutputBuffer, strlen( OutputBuffer ), &BytesWritten, NULL ) ) { (void) DbgPrint( "%s", (PCH) OutputBuffer); }
}
LeaveCriticalSection( &BinlGlobalDebugFileCritSect );
}
#if DBG
VOID BinlAssertFailed( LPSTR FailedAssertion, LPSTR FileName, DWORD LineNumber, LPSTR Message ) /*++
Routine Description:
Assertion failed.
Arguments:
FailedAssertion :
FileName :
LineNumber :
Message :
Return Value:
none.
--*/ { RtlAssert( FailedAssertion, FileName, (ULONG) LineNumber, (PCHAR) Message);
BinlPrintDbg(( 0, "Assert @ %s \n", FailedAssertion )); BinlPrintDbg(( 0, "Assert Filename, %s \n", FileName )); BinlPrintDbg(( 0, "Line Num. = %ld.\n", LineNumber )); BinlPrintDbg(( 0, "Message is %s\n", Message )); #if DBG
DebugBreak( ); #endif
}
VOID BinlDumpMessage( DWORD BinlDebugFlag, LPDHCP_MESSAGE BinlMessage ) /*++
Routine Description:
This function dumps a DHCP packet in human readable form.
Arguments:
BinlDebugFlag - debug flag that indicates what we are debugging.
BinlMessage - A pointer to a DHCP message.
Return Value:
None.
--*/ { LPOPTION option; BYTE i;
BinlPrintDbg(( BinlDebugFlag, "Binl message: \n\n"));
BinlPrintDbg(( BinlDebugFlag, "Operation :")); if ( BinlMessage->Operation == BOOT_REQUEST ) { BinlPrintDbg(( BinlDebugFlag, "BootRequest\n")); } else if ( BinlMessage->Operation == BOOT_REPLY ) { BinlPrintDbg(( BinlDebugFlag, "BootReply\n")); } else { BinlPrintDbg(( BinlDebugFlag, "Unknown %x\n", BinlMessage->Operation)); return; }
BinlPrintDbg(( BinlDebugFlag, "Hardware Address type : %d\n", BinlMessage->HardwareAddressType)); BinlPrintDbg(( BinlDebugFlag, "Hardware Address Length: %d\n", BinlMessage->HardwareAddressLength)); BinlPrintDbg(( BinlDebugFlag, "Hop Count : %d\n", BinlMessage->HopCount )); BinlPrintDbg(( BinlDebugFlag, "Transaction ID : %lx\n", BinlMessage->TransactionID )); BinlPrintDbg(( BinlDebugFlag, "Seconds Since Boot : %d\n", BinlMessage->SecondsSinceBoot )); BinlPrintDbg(( BinlDebugFlag, "Client IP Address : " )); BinlPrintDbg(( BinlDebugFlag, "%s\n", inet_ntoa(*(struct in_addr *)&BinlMessage->ClientIpAddress ) ));
BinlPrintDbg(( BinlDebugFlag, "Your IP Address : " )); BinlPrintDbg(( BinlDebugFlag, "%s\n", inet_ntoa(*(struct in_addr *)&BinlMessage->YourIpAddress ) ));
BinlPrintDbg(( BinlDebugFlag, "Server IP Address : " )); BinlPrintDbg(( BinlDebugFlag, "%s\n", inet_ntoa(*(struct in_addr *)&BinlMessage->BootstrapServerAddress ) ));
BinlPrintDbg(( BinlDebugFlag, "Relay Agent IP Address : " )); BinlPrintDbg(( BinlDebugFlag, "%s\n", inet_ntoa(*(struct in_addr *)&BinlMessage->RelayAgentIpAddress ) ));
BinlPrintDbg(( BinlDebugFlag, "Hardware Address : ")); for ( i = 0; i < BinlMessage->HardwareAddressLength; i++ ) { BinlPrintDbg(( BinlDebugFlag, "%2.2x", BinlMessage->HardwareAddress[i] )); }
option = &BinlMessage->Option;
BinlPrintDbg(( BinlDebugFlag, "\n\n")); BinlPrintDbg(( BinlDebugFlag, "Magic Cookie: ")); for ( i = 0; i < 4; i++ ) { BinlPrintDbg(( BinlDebugFlag, "%d ", *((LPBYTE)option)++ )); } BinlPrintDbg(( BinlDebugFlag, "\n\n"));
BinlPrintDbg(( BinlDebugFlag, "Options:\n")); while ( option->OptionType != 255 ) { BinlPrintDbg(( BinlDebugFlag, "\tType = %d ", option->OptionType )); for ( i = 0; i < option->OptionLength; i++ ) { BinlPrintDbg(( BinlDebugFlag, "%2.2x", option->OptionValue[i] )); } BinlPrintDbg(( BinlDebugFlag, "\n"));
if ( option->OptionType == OPTION_PAD || option->OptionType == OPTION_END ) {
option = (LPOPTION)( (LPBYTE)(option) + 1);
} else {
option = (LPOPTION)( (LPBYTE)(option) + option->OptionLength + 2);
}
if ( (LPBYTE)option - (LPBYTE)BinlMessage > DHCP_MESSAGE_SIZE ) { BinlPrintDbg(( BinlDebugFlag, "End of message, but no trailer found!\n")); break; } } } #endif // DBG
DWORD BinlReportEventW( DWORD EventID, DWORD EventType, DWORD NumStrings, DWORD DataLength, LPWSTR *Strings, LPVOID Data ) /*++
Routine Description:
This function writes the specified (EventID) log at the end of the eventlog.
Arguments:
EventID - The specific event identifier. This identifies the message that goes with this event.
EventType - Specifies the type of event being logged. This parameter can have one of the following
values:
Value Meaning
EVENTLOG_ERROR_TYPE Error event EVENTLOG_WARNING_TYPE Warning event EVENTLOG_INFORMATION_TYPE Information event
NumStrings - Specifies the number of strings that are in the array at 'Strings'. A value of zero indicates no strings are present.
DataLength - Specifies the number of bytes of event-specific raw (binary) data to write to the log. If cbData is zero, no event-specific data is present.
Strings - Points to a buffer containing an array of null-terminated strings that are merged into the message before displaying to the user. This parameter must be a valid pointer (or NULL), even if cStrings is zero.
Data - Buffer containing the raw data. This parameter must be a valid pointer (or NULL), even if cbData is zero.
Return Value:
Returns the WIN32 extended error obtained by GetLastError().
NOTE : This function works slow since it calls the open and close eventlog source everytime.
--*/ { HANDLE EventlogHandle; DWORD ReturnCode;
//
// open eventlog section.
//
EventlogHandle = RegisterEventSourceW(NULL, BINL_SERVER);
if (EventlogHandle == NULL) {
ReturnCode = GetLastError(); goto Cleanup; }
//
// Log the error code specified
//
if( !ReportEventW( EventlogHandle, (WORD)EventType, 0, // event category
EventID, NULL, (WORD)NumStrings, DataLength, Strings, Data ) ) {
ReturnCode = GetLastError(); goto Cleanup; }
ReturnCode = NO_ERROR;
Cleanup:
if( EventlogHandle != NULL ) {
DeregisterEventSource(EventlogHandle); }
return ReturnCode; }
DWORD BinlReportEventA( DWORD EventID, DWORD EventType, DWORD NumStrings, DWORD DataLength, LPSTR *Strings, LPVOID Data ) /*++
Routine Description:
This function writes the specified (EventID) log at the end of the eventlog.
Arguments:
Source - Points to a null-terminated string that specifies the name of the module referenced. The node must exist in the registration database, and the module name has the following format:
\EventLog\System\Lanmanworkstation
EventID - The specific event identifier. This identifies the message that goes with this event.
EventType - Specifies the type of event being logged. This parameter can have one of the following
values:
Value Meaning
EVENTLOG_ERROR_TYPE Error event EVENTLOG_WARNING_TYPE Warning event EVENTLOG_INFORMATION_TYPE Information event
NumStrings - Specifies the number of strings that are in the array at 'Strings'. A value of zero indicates no strings are present.
DataLength - Specifies the number of bytes of event-specific raw (binary) data to write to the log. If cbData is zero, no event-specific data is present.
Strings - Points to a buffer containing an array of null-terminated strings that are merged into the message before displaying to the user. This parameter must be a valid pointer (or NULL), even if cStrings is zero.
Data - Buffer containing the raw data. This parameter must be a valid pointer (or NULL), even if cbData is zero.
Return Value:
Returns the WIN32 extended error obtained by GetLastError().
NOTE : This function works slow since it calls the open and close eventlog source everytime.
--*/ { HANDLE EventlogHandle; DWORD ReturnCode;
//
// open eventlog section.
//
EventlogHandle = RegisterEventSourceW( NULL, BINL_SERVER );
if (EventlogHandle == NULL) {
ReturnCode = GetLastError(); goto Cleanup; }
//
// Log the error code specified
//
if( !ReportEventA( EventlogHandle, (WORD)EventType, 0, // event category
EventID, NULL, (WORD)NumStrings, DataLength, Strings, Data ) ) {
ReturnCode = GetLastError(); goto Cleanup; }
ReturnCode = NO_ERROR;
Cleanup:
if( EventlogHandle != NULL ) {
DeregisterEventSource(EventlogHandle); }
return ReturnCode; }
VOID BinlServerEventLog( DWORD EventID, DWORD EventType, DWORD ErrorCode ) /*++
Routine Description:
Logs an event in EventLog.
Arguments:
EventID - The specific event identifier. This identifies the message that goes with this event.
EventType - Specifies the type of event being logged. This parameter can have one of the following
values:
Value Meaning
EVENTLOG_ERROR_TYPE Error event EVENTLOG_WARNING_TYPE Warning event EVENTLOG_INFORMATION_TYPE Information event
ErrorCode - Error Code to be Logged.
Return Value:
None.
--*/
{ DWORD Error; LPSTR Strings[1]; CHAR ErrorCodeOemString[32 + 1];
wsprintfA( ErrorCodeOemString, "%lu", ErrorCode );
Strings[0] = ErrorCodeOemString;
Error = BinlReportEventA( EventID, EventType, 1, sizeof(ErrorCode), Strings, &ErrorCode );
if( Error != ERROR_SUCCESS ) { BinlPrintDbg(( DEBUG_ERRORS, "BinlReportEventW failed, %ld.\n", Error )); }
return; }
#if DBG==1
//
// Memory allocation and tracking
//
LPVOID g_TraceMemoryTable = NULL; CRITICAL_SECTION g_TraceMemoryCS;
#define DEBUG_OUTPUT_BUFFER_SIZE 1024
typedef struct _MEMORYBLOCK { HGLOBAL hglobal; struct _MEMORYBLOCK *pNext; LPCSTR pszModule; LPCSTR pszComment; LPCSTR pszFile; DWORD dwBytes; UINT uFlags; UINT uLine; } MEMORYBLOCK, *LPMEMORYBLOCK;
//
// Takes the filename and line number and put them into a string buffer.
//
// NOTE: the buffer is assumed to be of size DEBUG_OUTPUT_BUFFER_SIZE.
//
LPSTR dbgmakefilelinestring( LPSTR pszBuf, LPCSTR pszFile, UINT uLine ) { LPVOID args[2];
args[0] = (LPVOID) pszFile; args[1] = (LPVOID) UintToPtr( uLine );
FormatMessageA( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, "%1(%2!u!):", 0, // error code
0, // default language
(LPSTR) pszBuf, // output buffer
DEBUG_OUTPUT_BUFFER_SIZE, // size of buffer
(va_list*) args ); // arguments
return pszBuf; }
//
// Adds a MEMORYBLOCK to the memory tracking list.
//
HGLOBAL DebugMemoryAdd( HGLOBAL hglobal, LPCSTR pszFile, UINT uLine, LPCSTR pszModule, UINT uFlags, DWORD dwBytes, LPCSTR pszComment ) { if ( hglobal ) { LPMEMORYBLOCK pmb = (LPMEMORYBLOCK) GlobalAlloc( GMEM_FIXED, sizeof(MEMORYBLOCK) );
if ( !pmb ) { GlobalFree( hglobal ); return NULL; }
pmb->hglobal = hglobal; pmb->dwBytes = dwBytes; pmb->uFlags = uFlags; pmb->pszFile = pszFile; pmb->uLine = uLine; pmb->pszModule = pszModule; pmb->pszComment = pszComment;
EnterCriticalSection( &g_TraceMemoryCS );
pmb->pNext = g_TraceMemoryTable; g_TraceMemoryTable = pmb;
BinlPrintDbg((DEBUG_MEMORY, "DebugAlloc: 0x%08x alloced (%s)\n", hglobal, pmb->pszComment ));
LeaveCriticalSection( &g_TraceMemoryCS ); }
return hglobal; }
//
// Removes a MEMORYBLOCK to the memory tracking list.
//
void DebugMemoryDelete( HGLOBAL hglobal ) { if ( hglobal ) { LPMEMORYBLOCK pmbHead; LPMEMORYBLOCK pmbLast = NULL;
EnterCriticalSection( &g_TraceMemoryCS ); pmbHead = g_TraceMemoryTable;
while ( pmbHead && pmbHead->hglobal != hglobal ) { pmbLast = pmbHead; pmbHead = pmbLast->pNext; }
if ( pmbHead ) { HGLOBAL *p; if ( pmbLast ) { pmbLast->pNext = pmbHead->pNext; } else { g_TraceMemoryTable = pmbHead->pNext; }
BinlPrintDbg((DEBUG_MEMORY, "DebugFree: 0x%08x freed (%s)\n", hglobal, pmbHead->pszComment ));
p = (HGLOBAL)((LPBYTE)hglobal + pmbHead->dwBytes - sizeof(HGLOBAL)); if ( *p != hglobal ) { BinlPrintDbg(((DEBUG_ERRORS|DEBUG_MEMORY), "DebugFree: Heap check FAILED for %0x08x %u bytes (%s).\n", hglobal, pmbHead->dwBytes, pmbHead->pszComment)); BinlPrintDbg(((DEBUG_ERRORS|DEBUG_MEMORY), "DebugFree: %s, Line: %u\n", pmbHead->pszFile, pmbHead->uLine )); BinlAssert( *p == hglobal ); }
memset( hglobal, 0xFE, pmbHead->dwBytes ); memset( pmbHead, 0xFD, sizeof(sizeof(MEMORYBLOCK)) );
LocalFree( pmbHead ); } else { HGLOBAL *p;
BinlPrintDbg(((DEBUG_ERRORS|DEBUG_MEMORY), "DebugFree: 0x%08x not found in memory table\n", hglobal )); memset( hglobal, 0xFE, (int)LocalSize( hglobal )); }
LeaveCriticalSection( &g_TraceMemoryCS );
} }
//
// Allocates memory and adds the MEMORYBLOCK to the memory tracking list.
//
HGLOBAL DebugAlloc( LPCSTR pszFile, UINT uLine, LPCSTR pszModule, UINT uFlags, DWORD dwBytes, LPCSTR pszComment ) { HGLOBAL hglobal; DWORD dwBytesToAlloc = ROUND_UP_COUNT( dwBytes + sizeof(HGLOBAL), ALIGN_WORST);
HGLOBAL *p; hglobal = GlobalAlloc( uFlags, dwBytesToAlloc ); if (hglobal == NULL) { return NULL; } p = (HGLOBAL)((LPBYTE)hglobal + dwBytesToAlloc - sizeof(HGLOBAL)); *p = hglobal;
return DebugMemoryAdd( hglobal, pszFile, uLine, pszModule, uFlags, dwBytesToAlloc, pszComment ); }
//
// Remove the MEMORYBLOCK to the memory tracking list, memsets the
// memory to 0xFE and then frees the memory.
//
HGLOBAL DebugFree( HGLOBAL hglobal ) { DebugMemoryDelete( hglobal );
return GlobalFree( hglobal ); }
//
// Checks the memory tracking list. If it is not empty, it will dump the
// list and break.
//
void DebugMemoryCheck( ) { BOOL fFoundLeak = FALSE; LPMEMORYBLOCK pmb;
EnterCriticalSection( &g_TraceMemoryCS );
pmb = g_TraceMemoryTable; while ( pmb ) { LPMEMORYBLOCK pTemp; LPVOID args[ 5 ]; CHAR szOutput[ DEBUG_OUTPUT_BUFFER_SIZE ]; CHAR szFileLine[ DEBUG_OUTPUT_BUFFER_SIZE ];
if ( fFoundLeak == FALSE ) { BinlPrintRoutine( 0, "\n***************************** Memory leak detected *****************************\n\n"); //BinlPrintRoutine( 0, "1234567890123456789012345678901234567890 1234567890 X 0x12345678 12345 1...");
BinlPrintRoutine( 0, "Filename(Line Number): Module Addr/HGLOBAL Size String\n"); fFoundLeak = TRUE; }
args[0] = (LPVOID) pmb->hglobal; args[1] = (LPVOID) szFileLine; args[2] = (LPVOID) pmb->pszComment; args[3] = (LPVOID) ULongToPtr( pmb->dwBytes ); args[4] = (LPVOID) pmb->pszModule;
dbgmakefilelinestring( szFileLine, pmb->pszFile, pmb->uLine );
if ( !!(pmb->uFlags & GMEM_MOVEABLE) ) { FormatMessageA( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, "%2!-40s! %5!-10s! H 0x%1!08x! %4!-5u! \"%3\"\n", 0, // error code
0, // default language
szOutput, // output buffer
DEBUG_OUTPUT_BUFFER_SIZE, // size of buffer
(va_list*) args ); // arguments
} else { FormatMessageA( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, "%2!-40s! %5!-10s! A 0x%1!08x! %4!-5u! \"%3\"\n", 0, // error code
0, // default language
szOutput, // output buffer
DEBUG_OUTPUT_BUFFER_SIZE, // size of buffer
(va_list*) args ); // arguments
}
BinlPrintRoutine( 0, szOutput );
pTemp = pmb; pmb = pmb->pNext; memset( pTemp, 0xFD, sizeof(MEMORYBLOCK) ); LocalFree( pTemp ); }
if ( fFoundLeak == TRUE ) { BinlPrintRoutine( 0, "\n***************************** Memory leak detected *****************************\n\n"); }
LeaveCriticalSection( &g_TraceMemoryCS );
//BinlAssert( !fFoundLeak );
}
VOID DumpBuffer( PVOID Buffer, ULONG BufferSize ) /*++
Routine Description:
Dumps the buffer content on to the debugger output.
Arguments:
Buffer: buffer pointer.
BufferSize: size of the buffer.
Return Value:
none
--*/ { #define NUM_CHARS 16
ULONG i, limit; CHAR TextBuffer[NUM_CHARS + 1]; PUCHAR BufferPtr = Buffer;
DbgPrint("------------------------------------\n");
//
// Hex dump of the bytes
//
limit = ((BufferSize - 1) / NUM_CHARS + 1) * NUM_CHARS;
for (i = 0; i < limit; i++) {
if (i < BufferSize) {
DbgPrint("%02x ", (UCHAR)BufferPtr[i]);
if (BufferPtr[i] < 31 ) { TextBuffer[i % NUM_CHARS] = '.'; } else if (BufferPtr[i] == '\0') { TextBuffer[i % NUM_CHARS] = ' '; } else { TextBuffer[i % NUM_CHARS] = (CHAR) BufferPtr[i]; }
} else {
DbgPrint(" "); TextBuffer[i % NUM_CHARS] = ' ';
}
if ((i + 1) % NUM_CHARS == 0) { TextBuffer[NUM_CHARS] = 0; DbgPrint(" %s\n", TextBuffer); }
}
DbgPrint("------------------------------------\n"); }
#endif // DBG==1
|