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.
1290 lines
33 KiB
1290 lines
33 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
debug.c
|
|
|
|
Abstract:
|
|
|
|
This file contains debugging macros for the webdav client.
|
|
|
|
Author:
|
|
|
|
Andy Herron (andyhe) 30-Mar-1999
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
|
|
#include <stdio.h>
|
|
#include <ntumrefl.h>
|
|
#include <usrmddav.h>
|
|
#include "global.h"
|
|
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
DavOpenDebugFile(
|
|
IN BOOL ReopenFlag
|
|
);
|
|
|
|
HLOCAL
|
|
DebugMemoryAdd(
|
|
HLOCAL hglobal,
|
|
LPCSTR pszFile,
|
|
UINT uLine,
|
|
LPCSTR pszModule,
|
|
UINT uFlags,
|
|
DWORD dwBytes,
|
|
LPCSTR pszComment
|
|
);
|
|
|
|
VOID
|
|
DebugMemoryDelete(
|
|
HLOCAL hlocal
|
|
);
|
|
|
|
#endif // DBG
|
|
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
DebugInitialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the DAV debug environment. Its called by the init
|
|
function ServiveMain().
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwErr;
|
|
HKEY KeyHandle;
|
|
|
|
//
|
|
// We enclose the call to InitializeCriticalSection in a try-except block
|
|
// because its possible for it to raise a STATUS_NO_MEMORY exception.
|
|
//
|
|
try {
|
|
InitializeCriticalSection( &(g_TraceMemoryCS) );
|
|
InitializeCriticalSection( &(DavGlobalDebugFileCritSect) );
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
dwErr = GetExceptionCode();
|
|
DbgPrint("%ld: ERROR: DebugInitialize/InitializeCriticalSection: "
|
|
"Exception Code = %08lx.\n", GetCurrentThreadId(), dwErr);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// These are used in persistent logging. They define the file handle of the
|
|
// file to which the debug o/p is written, the max file size and the path
|
|
// of the file.
|
|
//
|
|
DavGlobalDebugFileHandle = NULL;
|
|
DavGlobalDebugFileMaxSize = DEFAULT_MAXIMUM_DEBUGFILE_SIZE;
|
|
DavGlobalDebugSharePath = NULL;
|
|
|
|
//
|
|
// Read DebugFlags value from the registry. If the entry exists, the global
|
|
// filter "DavGlobalDebugFlag" is set to this value. This value is used in
|
|
// filtering the debug messages.
|
|
//
|
|
dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
DAV_PARAMETERS_KEY,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&(KeyHandle));
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
//
|
|
// Read the value into DavGlobalDebugFlag.
|
|
//
|
|
DavGlobalDebugFlag = ReadDWord(KeyHandle, DAV_DEBUG_KEY, 0);
|
|
RegCloseKey(KeyHandle);
|
|
}
|
|
|
|
//
|
|
// Break in the debugger if we are asked to do so.
|
|
//
|
|
if(DavGlobalDebugFlag & DEBUG_STARTUP_BRK) {
|
|
DavPrint((DEBUG_INIT,
|
|
"DebugInitialize: Stopping at DebugBreak().\n" ));
|
|
DebugBreak();
|
|
}
|
|
|
|
//
|
|
// If we want to do persistent logging, open the debug log file.
|
|
//
|
|
if ( DavGlobalDebugFlag & DEBUG_LOG_IN_FILE ) {
|
|
DavOpenDebugFile( FALSE );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
DebugUninitialize (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine uninitializes the DAV debug environment. It basically frees up
|
|
the resources that were allocated for debugging/logging during debug
|
|
initialization.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
EnterCriticalSection( &(DavGlobalDebugFileCritSect) );
|
|
|
|
if ( DavGlobalDebugFileHandle != NULL ) {
|
|
CloseHandle( DavGlobalDebugFileHandle );
|
|
DavGlobalDebugFileHandle = NULL;
|
|
}
|
|
if( DavGlobalDebugSharePath != NULL ) {
|
|
DavFreeMemory( DavGlobalDebugSharePath );
|
|
DavGlobalDebugSharePath = NULL;
|
|
}
|
|
|
|
LeaveCriticalSection( &(DavGlobalDebugFileCritSect) );
|
|
|
|
DeleteCriticalSection( &(DavGlobalDebugFileCritSect) );
|
|
|
|
DeleteCriticalSection( &(g_TraceMemoryCS) );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
DavOpenDebugFile(
|
|
IN BOOL ReopenFlag
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens or re-opens the debug file. This file is used in persistent logging.
|
|
|
|
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( &(DavGlobalDebugFileCritSect) );
|
|
if ( DavGlobalDebugFileHandle != NULL ) {
|
|
CloseHandle( DavGlobalDebugFileHandle );
|
|
DavGlobalDebugFileHandle = NULL;
|
|
}
|
|
LeaveCriticalSection( &(DavGlobalDebugFileCritSect) );
|
|
|
|
//
|
|
// Create the debug directory path first, if it is not made before.
|
|
//
|
|
if( DavGlobalDebugSharePath == NULL ) {
|
|
|
|
UINT Val, LogFileSize;
|
|
ULONG LogFileNameSizeInBytes;
|
|
|
|
LogFileSize = ( sizeof(LogFileName)/sizeof(WCHAR) );
|
|
Val = GetWindowsDirectoryW(LogFileName, LogFileSize);
|
|
if ( Val == 0 ) {
|
|
DavPrint((DEBUG_ERRORS,
|
|
"DavOpenDebugFile: Window Directory Path can't be "
|
|
"retrieved, %d.\n", GetLastError() ));
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Check debug path length. The filename buffer needs to be of a
|
|
// minimum size.
|
|
//
|
|
PathLength = (wcslen(LogFileName) * sizeof(WCHAR)) + sizeof(DEBUG_DIR)
|
|
+ sizeof(WCHAR);
|
|
|
|
if( ( PathLength + sizeof(DEBUG_FILE) > sizeof(LogFileName) ) ||
|
|
( PathLength + sizeof(DEBUG_BAK_FILE) > sizeof(BakFileName) ) ) {
|
|
DavPrint((DEBUG_ERRORS,
|
|
"DavOpenDebugFile: Debug directory path (%ws) length is "
|
|
"too long.\n", LogFileName));
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
wcscat(LogFileName, DEBUG_DIR);
|
|
|
|
//
|
|
// Copy debug directory name to global var.
|
|
//
|
|
LogFileNameSizeInBytes = ( (wcslen(LogFileName) + 1) * sizeof(WCHAR) );
|
|
|
|
//
|
|
// We need to make the LogFileNameSizeInBytes a multiple of 8. This is
|
|
// because DavAllocateMemory calls DebugAlloc which does some stuff which
|
|
// requires this. The equation below does this.
|
|
//
|
|
LogFileNameSizeInBytes = ( ( ( LogFileNameSizeInBytes + 7 ) / 8 ) * 8 );
|
|
|
|
|
|
DavGlobalDebugSharePath = DavAllocateMemory( LogFileNameSizeInBytes );
|
|
if( DavGlobalDebugSharePath == NULL ) {
|
|
DavPrint((DEBUG_ERRORS,
|
|
"DavOpenDebugFile: Can't allocated memory for debug share"
|
|
"(%ws).\n", LogFileName));
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
wcscpy(DavGlobalDebugSharePath, LogFileName);
|
|
}
|
|
else {
|
|
wcscpy(LogFileName, DavGlobalDebugSharePath);
|
|
}
|
|
|
|
//
|
|
// Check whether this path exists.
|
|
//
|
|
FileAttributes = GetFileAttributesW( LogFileName );
|
|
if( FileAttributes == 0xFFFFFFFF ) {
|
|
WinError = GetLastError();
|
|
if( WinError == ERROR_FILE_NOT_FOUND ) {
|
|
BOOL RetVal;
|
|
//
|
|
// Create debug directory.
|
|
//
|
|
RetVal = CreateDirectoryW( LogFileName, NULL );
|
|
if( !RetVal ) {
|
|
DavPrint((DEBUG_ERRORS,
|
|
"DavOpenDebugFile: Can't create Debug directory (%ws)"
|
|
", %d.\n", LogFileName, GetLastError()));
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
else {
|
|
DavPrint((DEBUG_ERRORS,
|
|
"DavOpenDebugFile: Can't Get File attributes(%ws), %ld.\n",
|
|
LogFileName, WinError));
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// If this is not a directory, then we fail.
|
|
//
|
|
if( !(FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
|
|
DavPrint((DEBUG_ERRORS,
|
|
"DavOpenDebugFile: Debug directory path (%ws) exists "
|
|
"as file.\n", LogFileName));
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create the name of the old and new log file names
|
|
//
|
|
wcscpy( BakFileName, LogFileName );
|
|
wcscat( LogFileName, DEBUG_FILE );
|
|
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 ) {
|
|
DavPrint((DEBUG_ERRORS,
|
|
"DavOpenDebugFile: Cannot delete %ws (%ld)\n",
|
|
BakFileName, WinError));
|
|
DavPrint((DEBUG_ERRORS,
|
|
"DavOpenDebugFile: Try to re-open the file.\n"));
|
|
ReopenFlag = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ReopenFlag ) {
|
|
if ( !MoveFile( LogFileName, BakFileName ) ) {
|
|
DavPrint((DEBUG_ERRORS,
|
|
"DavOpenDebugFile: Cannot rename %ws to %ws (%ld)\n",
|
|
LogFileName, BakFileName, GetLastError()));
|
|
DavPrint((DEBUG_ERRORS,
|
|
"DavopenDebugFile: Try to re-open the file.\n"));
|
|
ReopenFlag = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Open the file.
|
|
//
|
|
EnterCriticalSection( &(DavGlobalDebugFileCritSect) );
|
|
DavGlobalDebugFileHandle = CreateFileW(LogFileName,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
(ReopenFlag ? CREATE_ALWAYS : OPEN_ALWAYS),
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
|
|
if ( DavGlobalDebugFileHandle == INVALID_HANDLE_VALUE ) {
|
|
DavPrint((DEBUG_ERRORS,
|
|
"DavOpenDebugFile: Cannot open (%ws).\n", LogFileName));
|
|
LeaveCriticalSection( &(DavGlobalDebugFileCritSect) );
|
|
goto ErrorReturn;
|
|
} else {
|
|
//
|
|
// Position the log file at the end.
|
|
//
|
|
SetFilePointer( DavGlobalDebugFileHandle, 0, NULL, FILE_END );
|
|
}
|
|
|
|
LeaveCriticalSection( &(DavGlobalDebugFileCritSect) );
|
|
|
|
return;
|
|
|
|
ErrorReturn:
|
|
|
|
DavPrint((DEBUG_ERRORS,
|
|
"DavOpenDebugFile: Debug o/p will be written to terminal.\n"));
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
DavPrintRoutine(
|
|
IN DWORD DebugFlag,
|
|
IN LPSTR Format,
|
|
...
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine prints the string passed in to the debug terminal and/or the
|
|
persistent log file.
|
|
|
|
Arguments:
|
|
|
|
DebugFlag - The debug flag which indicates whether thi string should be
|
|
printed or not.
|
|
|
|
Format - The string to be printed and its format.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
#define MAX_PRINTF_LEN 8192
|
|
|
|
va_list arglist;
|
|
char OutputBuffer[MAX_PRINTF_LEN];
|
|
char OutputBuffer2[MAX_PRINTF_LEN]; // this buffer will remove any % in OutputBuffer
|
|
ULONG length = 0;
|
|
DWORD ThreadId;
|
|
// DWORD BytesWritten, ThreadId;
|
|
// static BeginningOfLine = TRUE;
|
|
// static LineCount = 0;
|
|
// static TruncateLogFileInProgress = FALSE;
|
|
LPSTR Text;
|
|
DWORD PosInBuf1=0,PosInBuf2=0;
|
|
|
|
//
|
|
// If we aren't debugging this functionality, just return.
|
|
//
|
|
if ( DebugFlag == 0 || (DavGlobalDebugFlag & DebugFlag) == 0 ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// vsprintf isn't multithreaded and we don't want to intermingle output
|
|
// from different threads.
|
|
//
|
|
EnterCriticalSection( &(DavGlobalDebugFileCritSect) );
|
|
length = 0;
|
|
|
|
//
|
|
// Print the ThreadId at the start.
|
|
//
|
|
ThreadId = GetCurrentThreadId();
|
|
length += (ULONG) sprintf( &(OutputBuffer[length]), "%ld ", ThreadId );
|
|
|
|
//
|
|
// If this is an error, print the string "ERROR: " next.
|
|
//
|
|
if (DebugFlag & DEBUG_ERRORS) {
|
|
Text = "ERROR: ";
|
|
length += (ULONG) sprintf( &(OutputBuffer[length]), "%s", Text );
|
|
}
|
|
//
|
|
// Finally, print the string.
|
|
//
|
|
va_start(arglist, Format);
|
|
length += (ULONG) vsprintf( &(OutputBuffer[length]), Format, arglist );
|
|
va_end(arglist);
|
|
|
|
DavAssert(length < MAX_PRINTF_LEN); //last one for '\0' char
|
|
|
|
// Remove all % strings from Output buffer as this will be passed as format string
|
|
// to DbgPrint
|
|
PosInBuf1=0; PosInBuf2=0;
|
|
while(PosInBuf1<length) {
|
|
OutputBuffer2[PosInBuf2] = OutputBuffer[PosInBuf1];
|
|
PosInBuf2++;
|
|
if(OutputBuffer2[PosInBuf2-1] == '%') {
|
|
OutputBuffer2[PosInBuf2] = '%';
|
|
PosInBuf2++;
|
|
}
|
|
PosInBuf1++;
|
|
}
|
|
length = PosInBuf2;
|
|
OutputBuffer2[length]='\0';
|
|
|
|
DavAssert(length < MAX_PRINTF_LEN);
|
|
|
|
DbgPrint( (PCH)OutputBuffer2 );
|
|
|
|
LeaveCriticalSection( &(DavGlobalDebugFileCritSect) );
|
|
|
|
return;
|
|
|
|
#if 0
|
|
//
|
|
// If the log file is getting huge, truncate it.
|
|
//
|
|
if ( DavGlobalDebugFileHandle != NULL && !TruncateLogFileInProgress ) {
|
|
//
|
|
// Only check every 50 lines,
|
|
//
|
|
LineCount++;
|
|
if ( LineCount >= 50 ) {
|
|
DWORD FileSize;
|
|
LineCount = 0;
|
|
//
|
|
// Is the log file too big?
|
|
//
|
|
FileSize = GetFileSize( DavGlobalDebugFileHandle, NULL );
|
|
if ( FileSize == 0xFFFFFFFF ) {
|
|
DbgPrint("DavPrintRoutine: Cannot GetFileSize. ErrorVal = %d.\n",
|
|
GetLastError());
|
|
} else if ( FileSize > DavGlobalDebugFileMaxSize ) {
|
|
TruncateLogFileInProgress = TRUE;
|
|
LeaveCriticalSection( &(DavGlobalDebugFileCritSect) );
|
|
DavOpenDebugFile( TRUE );
|
|
DavPrint((DEBUG_MISC,
|
|
"Logfile truncated because it was larger than %ld bytes\n",
|
|
DavGlobalDebugFileMaxSize));
|
|
EnterCriticalSection( &DavGlobalDebugFileCritSect );
|
|
TruncateLogFileInProgress = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Write the debug info to the log file.
|
|
//
|
|
|
|
if ( !WriteFile(DavGlobalDebugFileHandle,
|
|
OutputBuffer,
|
|
lstrlenA( OutputBuffer ),
|
|
&BytesWritten,
|
|
NULL) ) {
|
|
DbgPrint( (PCH) OutputBuffer);
|
|
}
|
|
|
|
|
|
ExitDavPrintRoutine:
|
|
LeaveCriticalSection( &DavGlobalDebugFileCritSect );
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
DavAssertFailed(
|
|
LPSTR FailedAssertion,
|
|
LPSTR FileName,
|
|
DWORD LineNumber,
|
|
LPSTR Message
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called if a DAV assertion failed.
|
|
|
|
Arguments:
|
|
|
|
FailedAssertion : The assertion string that failed.
|
|
|
|
FileName : The file in which this assert was called.
|
|
|
|
LineNumber : The line on which this assert was called.
|
|
|
|
Message : The message to be printed if the assertion failed.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
DavPrint((DEBUG_ERRORS, "DavAssertFailed: Assert: %s.\n", FailedAssertion));
|
|
DavPrint((DEBUG_ERRORS, "DavAssertFailed: Filename: %s.\n", FileName));
|
|
DavPrint((DEBUG_ERRORS, "DavAssertFailed: Line Num: %ld.\n", LineNumber));
|
|
DavPrint((DEBUG_ERRORS, "DavAssertFailed: Message: %s.\n", Message));
|
|
|
|
RtlAssert(FailedAssertion, FileName, (ULONG)LineNumber, (PCHAR)Message);
|
|
|
|
#if DBG
|
|
DebugBreak();
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
LPSTR
|
|
dbgmakefilelinestring(
|
|
LPSTR pszBuf,
|
|
LPCSTR pszFile,
|
|
UINT uLine
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
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.
|
|
|
|
Arguments:
|
|
|
|
pszBuf - The buffer to be written to.
|
|
|
|
pszFile - The filename.
|
|
|
|
uLine - The line in the file.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
LPVOID args[2];
|
|
|
|
args[0] = (LPVOID) pszFile;
|
|
args[1] = (LPVOID) ((ULONG_PTR)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;
|
|
}
|
|
|
|
|
|
HLOCAL
|
|
DebugMemoryAdd(
|
|
HLOCAL hlocal,
|
|
LPCSTR pszFile,
|
|
UINT uLine,
|
|
LPCSTR pszModule,
|
|
UINT uFlags,
|
|
DWORD dwBytes,
|
|
LPCSTR pszComment
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a MEMORYBLOCK to the memory tracking list.
|
|
|
|
Arguments:
|
|
|
|
hlocal - The handle (pointer) to the allocated memroy block.
|
|
|
|
pszFile - The file in which this allocation took place.
|
|
|
|
uLine - The line in which this allocation took place.
|
|
|
|
pszModule - DAV in our case.
|
|
|
|
uFlags - Allocation flags passed to LocalAlloc().
|
|
|
|
dwBytes - Number of bytes to allocate.
|
|
|
|
Comm - The allocation string (i.e argument to DavAllocateMemory).
|
|
|
|
Return Value:
|
|
|
|
Handle (pointer) to the memory block.
|
|
|
|
--*/
|
|
{
|
|
LPMEMORYBLOCK pmb;
|
|
|
|
if ( hlocal ) {
|
|
|
|
pmb = (LPMEMORYBLOCK) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(MEMORYBLOCK));
|
|
if ( !pmb ) {
|
|
LocalFree( hlocal );
|
|
return NULL;
|
|
}
|
|
|
|
pmb->hlocal = hlocal;
|
|
pmb->dwBytes = dwBytes;
|
|
pmb->uFlags = uFlags;
|
|
pmb->pszFile = pszFile;
|
|
pmb->uLine = uLine;
|
|
pmb->pszModule = pszModule;
|
|
pmb->pszComment = pszComment;
|
|
|
|
EnterCriticalSection( &(g_TraceMemoryCS) );
|
|
|
|
//
|
|
// Add this block to the list.
|
|
//
|
|
pmb->pNext = g_TraceMemoryTable;
|
|
g_TraceMemoryTable = pmb;
|
|
|
|
DavPrint((DEBUG_MEMORY,
|
|
"DebugMemoryAdd: Handle = 0x%08lx. Argument: (%s)\n",
|
|
hlocal, pmb->pszComment));
|
|
|
|
LeaveCriticalSection( &(g_TraceMemoryCS) );
|
|
}
|
|
|
|
return hlocal;
|
|
}
|
|
|
|
|
|
HLOCAL
|
|
DebugAlloc(
|
|
LPCSTR File,
|
|
UINT Line,
|
|
LPCSTR Module,
|
|
UINT uFlags,
|
|
DWORD dwBytes,
|
|
LPCSTR Comm
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates memory and adds the MEMORYBLOCK to the memory tracking list.
|
|
|
|
Arguments:
|
|
|
|
File - The file in which this allocation took place.
|
|
|
|
Line - The line in which this allocation took place.
|
|
|
|
Module - DAV in our case.
|
|
|
|
uFlags - Allocation flags passed to LocalAlloc().
|
|
|
|
dwBytes - Number of bytes to allocate.
|
|
|
|
Comm - The allocation string (i.e argument to DavAllocateMemory).
|
|
|
|
Return Value:
|
|
|
|
Handle (pointer) to the memory block.
|
|
|
|
--*/
|
|
{
|
|
HLOCAL hlocal;
|
|
HLOCAL *p;
|
|
ULONG ShouldBeZero;
|
|
|
|
//
|
|
// dwBytes should be a multiple of 8. This is because of the pointer math
|
|
// that is being done below to store the value of hlocal in the memory
|
|
// allocated for it.
|
|
//
|
|
ShouldBeZero = (dwBytes & 0x7);
|
|
|
|
DavPrint((DEBUG_MISC, "DebugAlloc: ShouldBeZero = %d\n", ShouldBeZero));
|
|
|
|
ASSERT(ShouldBeZero == (ULONG)0);
|
|
|
|
hlocal = LocalAlloc( uFlags, dwBytes + sizeof(HLOCAL));
|
|
if (hlocal == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
p = (HLOCAL)((LPBYTE)hlocal + dwBytes);
|
|
|
|
*p = hlocal;
|
|
|
|
return DebugMemoryAdd(hlocal, File, Line, Module, uFlags, dwBytes, Comm);
|
|
}
|
|
|
|
|
|
VOID
|
|
DebugMemoryDelete(
|
|
HLOCAL hlocal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a MEMORYBLOCK to the memory tracking list.
|
|
|
|
Arguments:
|
|
|
|
hlocal - The handle to be removed.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
LPMEMORYBLOCK pmbHead;
|
|
LPMEMORYBLOCK pmbLast = NULL;
|
|
|
|
if ( hlocal ) {
|
|
|
|
EnterCriticalSection( &(g_TraceMemoryCS) );
|
|
|
|
pmbHead = g_TraceMemoryTable;
|
|
|
|
//
|
|
// Search the list for the handle being freed.
|
|
//
|
|
while ( pmbHead && pmbHead->hlocal != hlocal ) {
|
|
pmbLast = pmbHead;
|
|
pmbHead = pmbLast->pNext;
|
|
}
|
|
|
|
if ( pmbHead ) {
|
|
HLOCAL *p;
|
|
|
|
if ( pmbLast ) {
|
|
//
|
|
// Reset the "next" pointer of the previous block.
|
|
//
|
|
pmbLast->pNext = pmbHead->pNext;
|
|
} else {
|
|
//
|
|
// First entry is being freed.
|
|
//
|
|
g_TraceMemoryTable = pmbHead->pNext;
|
|
}
|
|
|
|
DavPrint((DEBUG_MEMORY,
|
|
"DebugMemoryDelete: Handle 0x%08x freed. Comm: (%s)\n",
|
|
hlocal, pmbHead->pszComment ));
|
|
|
|
p = (HLOCAL)((LPBYTE)hlocal + pmbHead->dwBytes);
|
|
if ( *p != hlocal ) {
|
|
DavPrint(((DEBUG_ERRORS | DEBUG_MEMORY),
|
|
"DebugMemoryDelete: Heap check FAILED for %0x08x %u bytes (%s).\n",
|
|
hlocal, pmbHead->dwBytes, pmbHead->pszComment));
|
|
DavPrint(((DEBUG_ERRORS | DEBUG_MEMORY),
|
|
"DebugMemoryDelete: File: %s, Line: %u.\n",
|
|
pmbHead->pszFile, pmbHead->uLine ));
|
|
DavAssert( *p == hlocal );
|
|
}
|
|
|
|
memset( hlocal, 0xFE, pmbHead->dwBytes + sizeof(HLOCAL) );
|
|
memset( pmbHead, 0xFD, sizeof(MEMORYBLOCK) );
|
|
|
|
LocalFree( pmbHead );
|
|
|
|
} else {
|
|
DavPrint(((DEBUG_ERRORS | DEBUG_MEMORY),
|
|
"DebugMemoryDelete: Handle 0x%08x not found in memory "
|
|
"table.\n", hlocal));
|
|
memset( hlocal, 0xFE, (int)LocalSize( hlocal ));
|
|
}
|
|
|
|
LeaveCriticalSection( &(g_TraceMemoryCS) );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
HLOCAL
|
|
DebugFree(
|
|
HLOCAL hlocal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove the MEMORYBLOCK from the memory tracking list, memsets the memory to
|
|
0xFE and then frees the memory.
|
|
|
|
Arguments:
|
|
|
|
hlocal - The handle to be freed.
|
|
|
|
Return Value:
|
|
|
|
Whatever LocalFree returns.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Remove it from the tracking list and free it.
|
|
//
|
|
DebugMemoryDelete( hlocal );
|
|
return LocalFree( hlocal );
|
|
}
|
|
|
|
|
|
VOID
|
|
DebugMemoryCheck(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks the memory tracking list. If it is not empty, it will dump the
|
|
list and break.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
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 ) {
|
|
DavPrintRoutine(DEBUG_MEMORY | DEBUG_ERRORS,
|
|
"************ Memory leak detected ************\n");
|
|
fFoundLeak = TRUE;
|
|
}
|
|
|
|
args[0] = (LPVOID) pmb->hlocal;
|
|
args[1] = (LPVOID) &szFileLine;
|
|
args[2] = (LPVOID) pmb->pszComment;
|
|
args[3] = (LPVOID) ((ULONG_PTR) 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
|
|
(LPSTR) &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
|
|
(LPSTR) &szOutput, // output buffer
|
|
DEBUG_OUTPUT_BUFFER_SIZE, // size of buffer
|
|
(va_list*) &args); // arguments
|
|
}
|
|
|
|
DavPrintRoutine(DEBUG_MEMORY | DEBUG_ERRORS, szOutput);
|
|
|
|
pTemp = pmb;
|
|
|
|
pmb = pmb->pNext;
|
|
|
|
memset( pTemp, 0xFD, sizeof(MEMORYBLOCK) );
|
|
|
|
LocalFree( pTemp );
|
|
}
|
|
|
|
LeaveCriticalSection( &(g_TraceMemoryCS) );
|
|
|
|
return;
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
|
|
DWORD
|
|
DavReportEventW(
|
|
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, SERVICE_DAVCLIENT);
|
|
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
|
|
DavReportEventA(
|
|
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, SERVICE_DAVCLIENT);
|
|
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
|
|
DavClientEventLog(
|
|
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 = DavReportEventA(EventID,
|
|
EventType,
|
|
1,
|
|
sizeof(ErrorCode),
|
|
Strings,
|
|
&ErrorCode);
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DavPrint(( DEBUG_ERRORS, "DavReportEventA failed, %ld.\n", Error ));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
#if 1
|
|
|
|
typedef ULONG (*DBGPRINTEX)(ULONG, ULONG, PCH, va_list);
|
|
|
|
ULONG
|
|
vDbgPrintEx(
|
|
ULONG ComponentId,
|
|
ULONG Level,
|
|
PCH Format,
|
|
va_list arglist
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine has been written to help load the service on Win2K machines.
|
|
The debug version of some libraries call vDbgPrintfEx which has been
|
|
implemented in Whistler and hence does not exist in Win2k's ntdll.dll.
|
|
BryanT added it to help solve this problem.
|
|
|
|
Arguments:
|
|
|
|
ComponentId -
|
|
|
|
Level -
|
|
|
|
Format -
|
|
|
|
arglist -
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS or the Win32 error code.
|
|
|
|
--*/
|
|
{
|
|
|
|
DBGPRINTEX pfnDbgPrintEx = (DBGPRINTEX) GetProcAddress(GetModuleHandle(L"ntdll"), "vDbgPrintEx");
|
|
if (pfnDbgPrintEx) {
|
|
return (*pfnDbgPrintEx)(ComponentId, Level, Format, arglist);
|
|
} else {
|
|
char Buf[2048];
|
|
RtlZeroMemory(Buf, sizeof(Buf));
|
|
_vsnprintf(Buf, sizeof(Buf), Format, arglist);
|
|
Buf[2047] = '\0';
|
|
DbgPrint(Buf);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|