mirror of https://github.com/lianthony/NT4.0
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.
577 lines
14 KiB
577 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name :
|
|
pudebug.c
|
|
|
|
Abstract:
|
|
|
|
This module defines functions required for
|
|
Debugging and logging messages for a dynamic program.
|
|
|
|
Author:
|
|
Murali R. Krishnan ( MuraliK ) 10-Sept-1994
|
|
Modified to be moved to common dll in 22-Dec-1994.
|
|
|
|
Revisions:
|
|
MuraliK 16-May-1995 Code to load and save debug flags from registry
|
|
MuraliK 16-Nov-1995 Remove DbgPrint (undoc api)
|
|
--*/
|
|
|
|
|
|
/************************************************************
|
|
* Include Headers
|
|
************************************************************/
|
|
|
|
# include <nt.h>
|
|
# include <ntrtl.h>
|
|
# include <nturtl.h>
|
|
# include <windows.h>
|
|
# include <stdio.h>
|
|
# include <stdlib.h>
|
|
# include <stdarg.h>
|
|
# include <string.h>
|
|
|
|
# include "pudebug.h"
|
|
|
|
|
|
/*************************************************************
|
|
* Global Variables and Default Values
|
|
*************************************************************/
|
|
|
|
# define MAX_PRINTF_OUTPUT ( 1024)
|
|
|
|
# define DEFAULT_DEBUG_FLAGS_VALUE ( 0)
|
|
# define DEBUG_FLAGS_REGISTRY_LOCATION_W L"DebugFlags"
|
|
|
|
|
|
/*************************************************************
|
|
* Functions
|
|
*************************************************************/
|
|
|
|
LPDEBUG_PRINTS
|
|
PuCreateDebugPrintsObject(
|
|
IN char * pszPrintLabel,
|
|
IN DWORD dwOutputFlags)
|
|
/*++
|
|
This function creates a new DEBUG_PRINTS object for the required
|
|
program.
|
|
|
|
Arguments:
|
|
pszPrintLabel pointer to null-terminated string containing
|
|
the label for program's debugging output
|
|
dwOutputFlags DWORD containing the output flags to be used.
|
|
|
|
Returns:
|
|
pointer to a new DEBUG_PRINTS object on success.
|
|
Returns NULL on failure.
|
|
--*/
|
|
{
|
|
|
|
LPDEBUG_PRINTS pDebugPrints;
|
|
|
|
pDebugPrints = GlobalAlloc( GPTR, sizeof( DEBUG_PRINTS));
|
|
|
|
if ( pDebugPrints != NULL) {
|
|
|
|
if ( strlen( pszPrintLabel) < MAX_LABEL_LENGTH) {
|
|
|
|
strcpy( pDebugPrints->m_rgchLabel, pszPrintLabel);
|
|
} else {
|
|
strncpy( pDebugPrints->m_rgchLabel,
|
|
pszPrintLabel, MAX_LABEL_LENGTH - 1);
|
|
pDebugPrints->m_rgchLabel[MAX_LABEL_LENGTH-1] = '\0';
|
|
// terminate string
|
|
}
|
|
|
|
memset( pDebugPrints->m_rgchLogFilePath, 0, MAX_PATH);
|
|
memset( pDebugPrints->m_rgchLogFileName, 0, MAX_PATH);
|
|
|
|
pDebugPrints->m_LogFileHandle = INVALID_HANDLE_VALUE;
|
|
|
|
pDebugPrints->m_dwOutputFlags = dwOutputFlags;
|
|
pDebugPrints->m_StdErrHandle = GetStdHandle( STD_ERROR_HANDLE);
|
|
pDebugPrints->m_fInitialized = TRUE;
|
|
}
|
|
|
|
|
|
return ( pDebugPrints);
|
|
} // PuCreateDebugPrintsObject()
|
|
|
|
|
|
|
|
|
|
LPDEBUG_PRINTS
|
|
PuDeleteDebugPrintsObject(
|
|
IN OUT LPDEBUG_PRINTS pDebugPrints)
|
|
/*++
|
|
This function cleans up the pDebugPrints object and
|
|
frees the allocated memory.
|
|
|
|
Arguments:
|
|
pDebugPrints poitner to the DEBUG_PRINTS object.
|
|
|
|
Returns:
|
|
NULL on success.
|
|
pDebugPrints() if the deallocation failed.
|
|
|
|
--*/
|
|
{
|
|
if ( pDebugPrints != NULL) {
|
|
|
|
DWORD dwError = PuCloseDbgPrintFile( pDebugPrints);
|
|
|
|
if ( dwError != NO_ERROR) {
|
|
|
|
SetLastError( dwError);
|
|
} else {
|
|
|
|
pDebugPrints = GlobalFree( pDebugPrints);
|
|
}
|
|
}
|
|
|
|
return ( pDebugPrints);
|
|
|
|
} // PuDeleteDebugPrintsObject()
|
|
|
|
|
|
|
|
|
|
VOID
|
|
PuSetDbgOutputFlags(
|
|
IN OUT LPDEBUG_PRINTS pDebugPrints,
|
|
IN DWORD dwFlags)
|
|
{
|
|
|
|
if ( pDebugPrints == NULL) {
|
|
|
|
SetLastError( ERROR_INVALID_PARAMETER);
|
|
} else {
|
|
|
|
pDebugPrints->m_dwOutputFlags = dwFlags;
|
|
}
|
|
|
|
return;
|
|
} // PuSetDbgOutputFlags()
|
|
|
|
|
|
|
|
DWORD
|
|
PuGetDbgOutputFlags(
|
|
IN const LPDEBUG_PRINTS pDebugPrints)
|
|
{
|
|
return ( pDebugPrints != NULL) ? pDebugPrints->m_dwOutputFlags : 0;
|
|
|
|
} // PuGetDbgOutputFlags()
|
|
|
|
|
|
static DWORD
|
|
PuOpenDbgFileLocal(
|
|
IN OUT LPDEBUG_PRINTS pDebugPrints)
|
|
{
|
|
|
|
if ( pDebugPrints->m_LogFileHandle != INVALID_HANDLE_VALUE) {
|
|
|
|
//
|
|
// Silently return as a file handle exists.
|
|
//
|
|
return ( NO_ERROR);
|
|
}
|
|
|
|
pDebugPrints->m_LogFileHandle =
|
|
CreateFile( pDebugPrints->m_rgchLogFileName,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if ( pDebugPrints->m_LogFileHandle == INVALID_HANDLE_VALUE) {
|
|
|
|
CHAR pchBuffer[1024];
|
|
DWORD dwError = GetLastError();
|
|
|
|
wsprintfA( pchBuffer,
|
|
" Critical Error: Unable to Open File %s. Error = %d\n",
|
|
pDebugPrints->m_rgchLogFileName, dwError);
|
|
OutputDebugString( pchBuffer);
|
|
|
|
return ( dwError);
|
|
}
|
|
|
|
return ( NO_ERROR);
|
|
} // PuOpenDbgFileLocal()
|
|
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
PuOpenDbgPrintFile(
|
|
IN OUT LPDEBUG_PRINTS pDebugPrints,
|
|
IN char * pszFileName,
|
|
IN char * pszPathForFile)
|
|
/*++
|
|
|
|
Opens a Debugging log file. This function can be called to set path
|
|
and name of the debugging file.
|
|
|
|
Arguments:
|
|
pszFileName pointer to null-terminated string containing
|
|
the name of the file.
|
|
|
|
pszPathForFile pointer to null-terminated string containing the
|
|
path for the given file.
|
|
If NULL, then the old place where dbg files were
|
|
stored is used or if none,
|
|
default windows directory will be used.
|
|
|
|
Returns:
|
|
Win32 error codes. NO_ERROR on success.
|
|
|
|
--*/
|
|
{
|
|
|
|
if ( pszFileName == NULL || pDebugPrints == NULL) {
|
|
|
|
return ( ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// Setup the Path information. if necessary.
|
|
//
|
|
|
|
if ( pszPathForFile != NULL) {
|
|
|
|
// Path is being changed.
|
|
|
|
if ( strlen( pszPathForFile) < MAX_PATH) {
|
|
|
|
strcpy( pDebugPrints->m_rgchLogFilePath, pszPathForFile);
|
|
} else {
|
|
|
|
return ( ERROR_INVALID_PARAMETER);
|
|
}
|
|
} else {
|
|
|
|
if ( pDebugPrints->m_rgchLogFilePath[0] == '\0' && // no old path
|
|
!GetWindowsDirectory( pDebugPrints->m_rgchLogFilePath, MAX_PATH)) {
|
|
|
|
//
|
|
// Unable to get the windows default directory. Use current dir
|
|
//
|
|
|
|
strcpy( pDebugPrints->m_rgchLogFilePath, ".");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Should need be, we need to create this directory for storing file
|
|
//
|
|
|
|
|
|
//
|
|
// Form the complete Log File name and open the file.
|
|
//
|
|
if ( (strlen( pszFileName) + strlen( pDebugPrints->m_rgchLogFilePath))
|
|
>= MAX_PATH) {
|
|
|
|
return ( ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
// form the complete path
|
|
strcpy( pDebugPrints->m_rgchLogFileName, pDebugPrints->m_rgchLogFilePath);
|
|
|
|
if ( pDebugPrints->m_rgchLogFileName[ strlen(pDebugPrints->m_rgchLogFileName) - 1]
|
|
!= '\\') {
|
|
// Append a \ if necessary
|
|
strcat( pDebugPrints->m_rgchLogFileName, "\\");
|
|
};
|
|
strcat( pDebugPrints->m_rgchLogFileName, pszFileName);
|
|
|
|
return PuOpenDbgFileLocal( pDebugPrints);
|
|
|
|
} // PuOpenDbgPrintFile()
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
PuReOpenDbgPrintFile(
|
|
IN OUT LPDEBUG_PRINTS pDebugPrints)
|
|
/*++
|
|
|
|
This function closes any open log file and reopens a new copy.
|
|
If necessary. It makes a backup copy of the file.
|
|
|
|
--*/
|
|
{
|
|
|
|
PuCloseDbgPrintFile( pDebugPrints); // close any existing file.
|
|
|
|
if ( pDebugPrints->m_dwOutputFlags & DbgOutputBackup) {
|
|
|
|
// MakeBkupCopy();
|
|
|
|
OutputDebugString( " Error: MakeBkupCopy() Not Yet Implemented\n");
|
|
}
|
|
|
|
return PuOpenDbgFileLocal( pDebugPrints);
|
|
|
|
} // PuReOpenDbgPrintFile()
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
PuCloseDbgPrintFile(
|
|
IN OUT LPDEBUG_PRINTS pDebugPrints)
|
|
{
|
|
DWORD dwError = NO_ERROR;
|
|
|
|
if ( pDebugPrints == NULL ) {
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
} else {
|
|
|
|
if ( pDebugPrints->m_LogFileHandle != INVALID_HANDLE_VALUE) {
|
|
|
|
FlushFileBuffers( pDebugPrints->m_LogFileHandle);
|
|
|
|
if ( !CloseHandle( pDebugPrints->m_LogFileHandle)) {
|
|
|
|
CHAR pchBuffer[1024];
|
|
|
|
dwError = GetLastError();
|
|
|
|
wsprintf( pchBuffer,
|
|
"CloseDbgPrintFile() : CloseHandle( %d) failed."
|
|
" Error = %d\n",
|
|
pDebugPrints->m_LogFileHandle,
|
|
dwError);
|
|
OutputDebugString( pchBuffer);
|
|
}
|
|
|
|
pDebugPrints->m_LogFileHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
return ( dwError);
|
|
} // DEBUG_PRINTS::CloseDbgPrintFile()
|
|
|
|
|
|
VOID
|
|
PuDbgPrint(
|
|
IN OUT LPDEBUG_PRINTS pDebugPrints,
|
|
IN const char * pszFilePath,
|
|
IN int nLineNum,
|
|
IN const char * pszFormat,
|
|
...)
|
|
/*++
|
|
|
|
Main function that examines the incoming message and prints out a header
|
|
and the message.
|
|
|
|
--*/
|
|
{
|
|
LPCSTR pszFileName = strrchr( pszFilePath, '\\');
|
|
char pszOutput[ MAX_PRINTF_OUTPUT];
|
|
LPCSTR pszMsg = "";
|
|
va_list argsList;
|
|
DWORD dwErr;
|
|
|
|
|
|
//
|
|
// Skip the complete path name and retain file name in pszName
|
|
//
|
|
|
|
if ( pszFileName== NULL) {
|
|
|
|
pszFileName = pszFilePath; // if skipping \\ yields nothing use whole path.
|
|
}
|
|
|
|
# ifdef _PRINT_REASONS_INCLUDED_
|
|
|
|
switch (pr) {
|
|
|
|
case PrintError:
|
|
pszMsg = "ERROR: ";
|
|
break;
|
|
|
|
case PrintWarning:
|
|
pszMsg = "WARNING: ";
|
|
break;
|
|
|
|
case PrintCritical:
|
|
pszMsg = "FATAL ERROR ";
|
|
break;
|
|
|
|
case PrintAssertion:
|
|
pszMsg = "ASSERTION Failed ";
|
|
break;
|
|
|
|
case PrintLog:
|
|
pfnPrintFunction = &DEBUG_PRINTS::DebugPrintNone;
|
|
default:
|
|
break;
|
|
|
|
} /* switch */
|
|
|
|
# endif // _PRINT_REASONS_INClUDED_
|
|
|
|
dwErr = GetLastError();
|
|
|
|
// Format the message header
|
|
|
|
wsprintf( pszOutput, "%s (%lu)[ %12s : %05d]",
|
|
pDebugPrints->m_rgchLabel,
|
|
GetCurrentThreadId(),
|
|
pszFileName, nLineNum);
|
|
|
|
// Format the incoming message
|
|
|
|
va_start( argsList, pszFormat);
|
|
vsprintf( pszOutput + strlen( pszOutput), pszFormat, argsList);
|
|
va_end( argsList);
|
|
|
|
//
|
|
// Send the outputs to respective files.
|
|
//
|
|
|
|
if ( pDebugPrints->m_dwOutputFlags & DbgOutputStderr) {
|
|
|
|
DWORD nBytesWritten;
|
|
|
|
( VOID) WriteFile( pDebugPrints->m_StdErrHandle,
|
|
pszOutput,
|
|
strlen( pszOutput),
|
|
&nBytesWritten,
|
|
NULL);
|
|
}
|
|
|
|
if ( pDebugPrints->m_dwOutputFlags & DbgOutputLogFile &&
|
|
pDebugPrints->m_LogFileHandle != INVALID_HANDLE_VALUE) {
|
|
|
|
DWORD nBytesWritten;
|
|
|
|
//
|
|
// Truncation of log files. Not yet implemented.
|
|
|
|
( VOID) WriteFile( pDebugPrints->m_LogFileHandle,
|
|
pszOutput,
|
|
strlen( pszOutput),
|
|
&nBytesWritten,
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
if ( pDebugPrints->m_dwOutputFlags & DbgOutputKdb) {
|
|
|
|
OutputDebugString( pszOutput);
|
|
}
|
|
|
|
SetLastError( dwErr );
|
|
|
|
|
|
return;
|
|
|
|
} // PuDbgPrint()
|
|
|
|
|
|
|
|
VOID
|
|
PuDbgAssertFailed(
|
|
IN OUT LPDEBUG_PRINTS pDebugPrints,
|
|
IN const char * pszFilePath,
|
|
IN int nLineNum,
|
|
IN const char * pszExpression,
|
|
IN const char * pszMessage)
|
|
/*++
|
|
This function calls assertion failure and records assertion failure
|
|
in log file.
|
|
|
|
--*/
|
|
{
|
|
PuDbgPrint( pDebugPrints, pszFilePath, nLineNum,
|
|
" Assertion (%s) Failed: %s\n",
|
|
pszExpression,
|
|
pszMessage);
|
|
|
|
DebugBreak();
|
|
|
|
return;
|
|
} // PuDbgAssertFailed()
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
PuLoadDebugFlagsFromReg(IN HKEY hkey, IN DWORD dwDefault)
|
|
/*++
|
|
This function reads the debug flags assumed to be stored in
|
|
the location "DebugFlags" under given key.
|
|
If there is any error the default value is returned.
|
|
--*/
|
|
{
|
|
DWORD err;
|
|
DWORD dwDebug = dwDefault;
|
|
DWORD dwBuffer;
|
|
DWORD cbBuffer = sizeof(dwBuffer);
|
|
DWORD dwType;
|
|
|
|
if( hkey != NULL )
|
|
{
|
|
err = RegQueryValueExW( hkey,
|
|
DEBUG_FLAGS_REGISTRY_LOCATION_W,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwBuffer,
|
|
&cbBuffer );
|
|
|
|
if( ( err == NO_ERROR ) && ( dwType == REG_DWORD ) )
|
|
{
|
|
dwDebug = dwBuffer;
|
|
}
|
|
}
|
|
|
|
return dwDebug;
|
|
} // PuLoadDebugFlagsFromReg()
|
|
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
PuSaveDebugFlagsInReg(IN HKEY hkey, IN DWORD dwDbg)
|
|
/*++
|
|
Saves the debug flags in registry. On failure returns the error code for
|
|
the operation that failed.
|
|
|
|
--*/
|
|
{
|
|
DWORD err;
|
|
|
|
if( hkey == NULL ) {
|
|
|
|
err = ERROR_INVALID_PARAMETER;
|
|
} else {
|
|
|
|
err = RegSetValueExW(hkey,
|
|
DEBUG_FLAGS_REGISTRY_LOCATION_W,
|
|
0,
|
|
REG_DWORD,
|
|
(LPBYTE)&dwDbg,
|
|
sizeof(dwDbg) );
|
|
}
|
|
|
|
return (err);
|
|
} // PuSaveDebugFlagsInReg()
|
|
|
|
|
|
/****************************** End of File ******************************/
|
|
|
|
|
|
|
|
|