2241 lines
70 KiB
C
2241 lines
70 KiB
C
|
/*++
|
|||
|
|
|||
|
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)
|
|||
|
JasAndre Jan-1998 Replaced tracing mechanism with WMI Tracing
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
/************************************************************
|
|||
|
* 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"
|
|||
|
# include <winbase.h>
|
|||
|
# include <coguid.h>
|
|||
|
# include <objbase.h>
|
|||
|
|
|||
|
#ifndef _NO_TRACING_
|
|||
|
DEFINE_GUID(IisRtlGuid,
|
|||
|
0x784d8900, 0xaa8c, 0x11d2, 0x92, 0x5e, 0x00, 0xc0, 0x4f, 0x72, 0xd9, 0x0e);
|
|||
|
#endif
|
|||
|
|
|||
|
/*************************************************************
|
|||
|
* Global Variables and Default Values
|
|||
|
*************************************************************/
|
|||
|
|
|||
|
# define MAX_PRINTF_OUTPUT ( 10240)
|
|||
|
|
|||
|
# define DEFAULT_DEBUG_FLAGS_VALUE ( 0)
|
|||
|
# define DEBUG_FLAGS_REGISTRY_LOCATION_A "DebugFlags"
|
|||
|
# define DEBUG_BREAK_ENABLED_REGKEYNAME_A "BreakOnAssert"
|
|||
|
|
|||
|
|
|||
|
/*************************************************************
|
|||
|
* Functions
|
|||
|
*************************************************************/
|
|||
|
|
|||
|
# ifndef _NO_TRACING_
|
|||
|
|
|||
|
// Critical section used to control access to the list of known guids used for
|
|||
|
// WMI tracing
|
|||
|
CRITICAL_SECTION g_csGuidList;
|
|||
|
// The list of known guids which are used with WMI Tracing
|
|||
|
LIST_ENTRY g_pGuidList;
|
|||
|
// The sequence number of the trace message we are about to log
|
|||
|
LONG g_dwSequenceNumber = 0;
|
|||
|
// This flag tells us whether or not to do any WMI handling
|
|||
|
BOOL g_bTracingEnabled = FALSE;
|
|||
|
// This flag tells us if we had to start WMI tracing
|
|||
|
BOOL g_bStartedTracing = FALSE;
|
|||
|
TRACEHANDLE g_hLoggerHandle = 0;
|
|||
|
// This flag tells us whether to enable the guids as they are defined or to
|
|||
|
// wait for an enable command from WMI
|
|||
|
BOOL g_bTracingActive = FALSE;
|
|||
|
// This flag tells us whether or not to log info to OutputDebugString, this is
|
|||
|
// SLOW. It is on by default for CHK builds and off by default for FRE builds
|
|||
|
//#ifdef DBG
|
|||
|
//BOOL g_ODSEnabled = TRUE;
|
|||
|
//#else
|
|||
|
BOOL g_ODSEnabled = FALSE;
|
|||
|
//#endif
|
|||
|
// The filename and session name to use for the WMI Tracing file
|
|||
|
char g_szLogFileName[MAX_PATH] = "";
|
|||
|
char g_szLogSessionName[MAX_PATH] = "";
|
|||
|
// The WMI Tracing buffer size, in KB, and the min and max number of buffers
|
|||
|
// that are permitted, and max file size, 0 means use default
|
|||
|
// If max file size is set then circular buffers are used
|
|||
|
ULONG g_ulBufferSize = 0;
|
|||
|
ULONG g_ulMinBuffers = 0;
|
|||
|
ULONG g_ulMaxBuffers = 0;
|
|||
|
ULONG g_ulMaxFileSize = 0;
|
|||
|
// Three special modes that it is possible to start the logger in
|
|||
|
BOOL g_bRealTimeMode = FALSE;
|
|||
|
BOOL g_bInMemoryMode = FALSE;
|
|||
|
BOOL g_bUserMode = FALSE;
|
|||
|
// The default values used for control flags and the error level. These
|
|||
|
// settings are only used for modules that have their active flags set
|
|||
|
DWORD g_dwDefaultControlFlag = 0;
|
|||
|
DWORD g_dwDefaultErrorLevel = 0;
|
|||
|
// This flag tells us if we have done the registry initialization, we can't
|
|||
|
// register with WMI until this has been done
|
|||
|
BOOL g_bHaveDoneInit = FALSE;
|
|||
|
// This flag tells us whether we have registered with WMI or not
|
|||
|
BOOL g_bHadARegister = FALSE;
|
|||
|
|
|||
|
void SetLevel(int iDefaultErrorLevel, int *piErrorFlags)
|
|||
|
/*++
|
|||
|
Support function used by all and sundry to convert the level, ie. 1, 2 or 3
|
|||
|
into the bitmapped format used in the error flags variable
|
|||
|
|
|||
|
Arguments:
|
|||
|
iDefaultErrorLevel new value to decode for the error level
|
|||
|
*piErrorFlags pointer to the variable to set the error level in
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if (piErrorFlags) {
|
|||
|
|
|||
|
// Mask out all but the ODS flag
|
|||
|
// Note: Why do we do this? There is a problem that if this module is
|
|||
|
// compiled as FRE but the caller is CHK then this function would
|
|||
|
// erase the callers ODS setting, so by masking out all but the ODS
|
|||
|
// flag here we can maintain the callers ODS setting
|
|||
|
*piErrorFlags &= DEBUG_FLAG_ODS;
|
|||
|
|
|||
|
// Then or in the appropriate bit
|
|||
|
switch (iDefaultErrorLevel) {
|
|||
|
case DEBUG_LEVEL_ERROR:
|
|||
|
*piErrorFlags |= DEBUG_FLAG_ERROR;
|
|||
|
break;
|
|||
|
|
|||
|
case DEBUG_LEVEL_WARN:
|
|||
|
*piErrorFlags |= DEBUG_FLAG_WARN;
|
|||
|
break;
|
|||
|
|
|||
|
case DEBUG_LEVEL_INFO:
|
|||
|
*piErrorFlags |= DEBUG_FLAG_INFO;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
break;
|
|||
|
};
|
|||
|
|
|||
|
if (g_ODSEnabled)
|
|||
|
*piErrorFlags |= DEBUG_FLAG_ODS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
SGuidList *FindGuid(
|
|||
|
IN GUID *ControlGuid
|
|||
|
)
|
|||
|
/*++
|
|||
|
Support function used by all and sundry to find a guid in the guid list.
|
|||
|
NOTE: It is the responsibility of the caller to enter the guid list
|
|||
|
critical section before calling this function
|
|||
|
|
|||
|
Arguments:
|
|||
|
*ControlGuid pointer to the guid that we are looking for
|
|||
|
|
|||
|
Returns:
|
|||
|
NULL if the guid is not in the list
|
|||
|
*DEBUG_PRINTS the data relating to the guid if it is in the list
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LIST_ENTRY *pEntry;
|
|||
|
SGuidList *pGE = NULL;
|
|||
|
BOOL bFound = FALSE;
|
|||
|
|
|||
|
for (pEntry = g_pGuidList.Flink;
|
|||
|
pEntry != &g_pGuidList;
|
|||
|
pEntry = pEntry->Flink)
|
|||
|
{
|
|||
|
pGE = CONTAINING_RECORD(pEntry,
|
|||
|
SGuidList,
|
|||
|
m_leEntry);
|
|||
|
|
|||
|
DBG_ASSERT(TRACESIG == pGE->dwSig);
|
|||
|
|
|||
|
if (IsEqualGUID(ControlGuid, &pGE->m_dpData.m_guidControl)) {
|
|||
|
|
|||
|
bFound = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return bFound ? pGE : NULL;
|
|||
|
}
|
|||
|
|
|||
|
dllexp ULONG IISTraceControlCallback(
|
|||
|
IN WMIDPREQUESTCODE RequestCode,
|
|||
|
IN PVOID RequestContext,
|
|||
|
IN OUT ULONG *InOutBufferSize,
|
|||
|
IN OUT PVOID Buffer
|
|||
|
)
|
|||
|
/*++
|
|||
|
Callback function supplied to WMI so that it can notify me when the user
|
|||
|
requests a change to the level or control flags for logging
|
|||
|
|
|||
|
Arguments:
|
|||
|
RequestCode control code used to determine what function to perform
|
|||
|
RequestContext not used
|
|||
|
InOutBufferSize size of the buffer supplied by WMI, set to 0 as we don't
|
|||
|
send any data back to WMI through this mechanism
|
|||
|
Buffer contains EVENT_TRACE_HEADER needed to identify whom a
|
|||
|
request is for
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PEVENT_TRACE_HEADER pHeader = (PEVENT_TRACE_HEADER) Buffer;
|
|||
|
TRACEHANDLE hTrace = GetTraceLoggerHandle(Buffer);
|
|||
|
LPGUID pGuid = &pHeader->Guid;
|
|||
|
ULONG Status = ERROR_SUCCESS;
|
|||
|
SGuidList *pGE = NULL;
|
|||
|
|
|||
|
switch (RequestCode)
|
|||
|
{
|
|||
|
case WMI_ENABLE_EVENTS:
|
|||
|
{
|
|||
|
EnterCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
DBG_ASSERT(pGuid);
|
|||
|
DBG_REQUIRE(pGE = FindGuid(pGuid));
|
|||
|
|
|||
|
if (pGuid && pGE) {
|
|||
|
|
|||
|
DEBUG_PRINTS *pGEData = &pGE->m_dpData;
|
|||
|
|
|||
|
pGEData->m_iControlFlag = GetTraceEnableFlags(hTrace);
|
|||
|
pGEData->m_hLogger = hTrace;
|
|||
|
|
|||
|
if (pGEData->m_piErrorFlags) {
|
|||
|
|
|||
|
SetLevel(GetTraceEnableLevel(hTrace), pGEData->m_piErrorFlags);
|
|||
|
|
|||
|
// Flag us as no longer needing an initialize, important step
|
|||
|
// to prevent re-initialization attempts in PuInitiateDebug
|
|||
|
pGE->m_iInitializeFlags &= ~DEBUG_FLAG_INITIALIZE;
|
|||
|
pGE->m_iDefaultErrorLevel = GetTraceEnableLevel(hTrace);
|
|||
|
}
|
|||
|
else {
|
|||
|
pGE->m_iInitializeFlags = DEBUG_FLAG_DEFERRED_START;
|
|||
|
pGE->m_iDefaultErrorLevel = GetTraceEnableLevel(hTrace);
|
|||
|
}
|
|||
|
}
|
|||
|
LeaveCriticalSection(&g_csGuidList);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case WMI_DISABLE_EVENTS:
|
|||
|
{
|
|||
|
EnterCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
if (pGuid && (NULL != (pGE = FindGuid(pGuid)))) {
|
|||
|
|
|||
|
DEBUG_PRINTS *pGEData = &pGE->m_dpData;
|
|||
|
|
|||
|
pGEData->m_iControlFlag = 0;
|
|||
|
pGEData->m_hLogger = hTrace;
|
|||
|
|
|||
|
if (pGEData->m_piErrorFlags) {
|
|||
|
SetLevel(0, pGEData->m_piErrorFlags);
|
|||
|
pGE->m_iDefaultErrorLevel = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
LeaveCriticalSection(&g_csGuidList);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
default:
|
|||
|
{
|
|||
|
char szTemp[MAX_PATH];
|
|||
|
|
|||
|
_snprintf(szTemp, sizeof(szTemp),
|
|||
|
"IISTRACE:\t%s(%d), IISTraceControlCallback: Invalid parameter\n",
|
|||
|
__FILE__, __LINE__);
|
|||
|
OutputDebugString(szTemp);
|
|||
|
Status = ERROR_INVALID_PARAMETER;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
*InOutBufferSize = 0;
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void LoadGuidFromRegistry(char *pszModuleName)
|
|||
|
/*++
|
|||
|
This function is used to load all the information stored in the registry
|
|||
|
about a module and to allocate an entry in the guid list for it
|
|||
|
NOTE: It is the responsibility of the caller to enter the guid list
|
|||
|
critical section before calling this function
|
|||
|
|
|||
|
Arguments:
|
|||
|
pszModuleName pointer to the name of the module we are about to process
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
char KeyName[MAX_PATH * 2] = REG_TRACE_IIS "\\";
|
|||
|
HKEY hk = 0;
|
|||
|
|
|||
|
// Create the name of the key for this GUID using the english name
|
|||
|
strcat(KeyName, pszModuleName);
|
|||
|
// Open the GUIDs key
|
|||
|
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, KeyName, &hk)) {
|
|||
|
WCHAR szwTemp[MAX_PATH];
|
|||
|
DWORD dwReadSize;
|
|||
|
|
|||
|
// 1. Load the guid number from the registry, we can only continue
|
|||
|
// processing this module if we find a guid for it
|
|||
|
dwReadSize = sizeof(szwTemp);
|
|||
|
if (ERROR_SUCCESS == RegQueryValueExW(hk, REG_TRACE_IIS_GUID,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) szwTemp,
|
|||
|
&dwReadSize)) {
|
|||
|
CLSID ControlGuid;
|
|||
|
|
|||
|
// 2. Convert the guid string into a guid
|
|||
|
if (SUCCEEDED(CLSIDFromString(szwTemp, &ControlGuid))) {
|
|||
|
|
|||
|
// 3. Ensure it is not already in the guid list
|
|||
|
if (!FindGuid(&ControlGuid)) {
|
|||
|
DEBUG_PRINTS *pGEData = NULL;
|
|||
|
BOOL bGuidEnabled;
|
|||
|
int iTemp;
|
|||
|
|
|||
|
// 4. Try and insert it into the guid list
|
|||
|
SGuidList *pGE = (SGuidList *) LocalAlloc(LPTR, sizeof(SGuidList));
|
|||
|
|
|||
|
if (pGE) {
|
|||
|
|
|||
|
pGEData = &pGE->m_dpData;
|
|||
|
|
|||
|
// Set the GuidList signature
|
|||
|
pGE->dwSig = TRACESIG;
|
|||
|
|
|||
|
// Set the SGuidList.m_dpData member variables
|
|||
|
strncpy(pGEData->m_rgchLabel,
|
|||
|
pszModuleName, MAX_LABEL_LENGTH - 1);
|
|||
|
pGEData->m_guidControl = ControlGuid;
|
|||
|
pGEData->m_bBreakOnAssert = TRUE; // Default - Break if Assert Fails
|
|||
|
|
|||
|
// Add it to the head of the list. Put it at the head in case this
|
|||
|
// is an object which is being loaded and unloaded continuosly.
|
|||
|
InsertHeadList(&g_pGuidList, &pGE->m_leEntry);
|
|||
|
|
|||
|
// 5. Try to load any previous control settings from the registry
|
|||
|
// 5.1 See if the guid is enabled, if so flag us as needing
|
|||
|
// to start this guid when we initialize with WMI
|
|||
|
dwReadSize = sizeof(bGuidEnabled);
|
|||
|
if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_ACTIVE,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) &bGuidEnabled,
|
|||
|
&dwReadSize)) {
|
|||
|
if (bGuidEnabled)
|
|||
|
pGE->m_iInitializeFlags = DEBUG_FLAG_INITIALIZE;
|
|||
|
}
|
|||
|
// Otherwise use the global setting to determine this
|
|||
|
else if (g_bTracingActive)
|
|||
|
pGE->m_iInitializeFlags = DEBUG_FLAG_INITIALIZE;
|
|||
|
|
|||
|
// If it is enabled then load the remaining flags
|
|||
|
if (pGE->m_iInitializeFlags & DEBUG_FLAG_INITIALIZE) {
|
|||
|
|
|||
|
// 5.2 So next load the ControlFlags, the flags default
|
|||
|
// to the global setting
|
|||
|
dwReadSize = sizeof(&iTemp);
|
|||
|
if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_CONTROL,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) &iTemp,
|
|||
|
&dwReadSize))
|
|||
|
pGEData->m_iControlFlag = iTemp;
|
|||
|
else
|
|||
|
pGEData->m_iControlFlag = g_dwDefaultControlFlag;
|
|||
|
|
|||
|
// 5.3 Then load the Level, it also defaults to the global
|
|||
|
// setting
|
|||
|
if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LEVEL,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) &iTemp,
|
|||
|
&dwReadSize)) {
|
|||
|
pGE->m_iDefaultErrorLevel = iTemp;
|
|||
|
}
|
|||
|
else
|
|||
|
pGE->m_iDefaultErrorLevel = g_dwDefaultErrorLevel;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
RegCloseKey(hk);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
dllexp void
|
|||
|
AddToRegistry(
|
|||
|
IN SGuidList *pGE
|
|||
|
)
|
|||
|
/*++
|
|||
|
This function creates new registry entries for this module so that it will
|
|||
|
be correctly loaded next time IIS is started
|
|||
|
NOTE: It is the responsibility of the caller to enter the guid list
|
|||
|
critical section before calling this function
|
|||
|
|
|||
|
Arguments:
|
|||
|
*pGE pointer to the SGuidList entry which has all the
|
|||
|
information about the guid to add
|
|||
|
|
|||
|
Returns:
|
|||
|
This returns void as it does not matter to the running program whether
|
|||
|
this works or not, it just improves restart performance if it does.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
HKEY hk = 0;
|
|||
|
HKEY hkNew = 0;
|
|||
|
|
|||
|
// Open the IIS Trace registry key
|
|||
|
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, REG_TRACE_IIS, &hk)) {
|
|||
|
|
|||
|
DEBUG_PRINTS *pGEData = &pGE->m_dpData;
|
|||
|
BOOL bCreatedGuid = FALSE;
|
|||
|
DWORD dwDisposition;
|
|||
|
|
|||
|
// 1. Create a new key for the module
|
|||
|
if (ERROR_SUCCESS == RegCreateKeyEx(hk, pGEData->m_rgchLabel,
|
|||
|
0, NULL,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
NULL, &hkNew, &dwDisposition))
|
|||
|
{
|
|||
|
WCHAR szwTemp[MAX_PATH];
|
|||
|
|
|||
|
// 2. Convert the guid to a string so that we can add it to the
|
|||
|
// registry, the format is E.g.
|
|||
|
// {37EABAF0-7FB6-11D0-8817-00A0C903B83C}
|
|||
|
if (StringFromGUID2(&pGEData->m_guidControl,
|
|||
|
(WCHAR *) szwTemp,
|
|||
|
MAX_PATH)) {
|
|||
|
|
|||
|
// 3. Add the guid string to the module information
|
|||
|
if (ERROR_SUCCESS == RegSetValueExW(hkNew,
|
|||
|
REG_TRACE_IIS_GUID,
|
|||
|
0,
|
|||
|
REG_SZ,
|
|||
|
(BYTE *) szwTemp,
|
|||
|
wcslen(szwTemp) * sizeof(WCHAR))) {
|
|||
|
bCreatedGuid = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RegCloseKey(hkNew);
|
|||
|
|
|||
|
if (!bCreatedGuid && (REG_CREATED_NEW_KEY == dwDisposition)) {
|
|||
|
|
|||
|
RegDeleteKey(hk, pGEData->m_rgchLabel);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RegCloseKey(hk);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
TRACEHANDLE
|
|||
|
GetTraceFileHandle(
|
|||
|
VOID)
|
|||
|
/*++
|
|||
|
This function create the tracing file for the current log file. It only does
|
|||
|
this if a module that has the DEBUG_FLAG_INITIALIZE bit is successfully
|
|||
|
registered with WMI.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Returns:
|
|||
|
--*/
|
|||
|
{
|
|||
|
TRACEHANDLE hLogger = 0;
|
|||
|
|
|||
|
// There must be a valid log file name and session name in order to create
|
|||
|
// the trace file
|
|||
|
if (g_szLogFileName[0] && g_szLogSessionName[0]) {
|
|||
|
|
|||
|
struct {
|
|||
|
EVENT_TRACE_PROPERTIES Header;
|
|||
|
char LoggerName[MAX_PATH];
|
|||
|
char LogFileName[MAX_PATH];
|
|||
|
} Properties;
|
|||
|
|
|||
|
PEVENT_TRACE_PROPERTIES LoggerInfo;
|
|||
|
PCHAR Offset;
|
|||
|
|
|||
|
ULONG Status = ERROR_SUCCESS;
|
|||
|
|
|||
|
LoggerInfo = (PEVENT_TRACE_PROPERTIES)&Properties.Header;
|
|||
|
|
|||
|
// Set up the request structure
|
|||
|
RtlZeroMemory(&Properties, sizeof(Properties));
|
|||
|
LoggerInfo->Wnode.BufferSize = sizeof(Properties);
|
|||
|
LoggerInfo->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
|
|||
|
if (0 == g_ulMaxFileSize)
|
|||
|
LoggerInfo->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;
|
|||
|
else {
|
|||
|
LoggerInfo->LogFileMode = EVENT_TRACE_FILE_MODE_CIRCULAR;
|
|||
|
LoggerInfo->MaximumFileSize = g_ulMaxFileSize;
|
|||
|
}
|
|||
|
if (g_bRealTimeMode)
|
|||
|
LoggerInfo->LogFileMode |= EVENT_TRACE_REAL_TIME_MODE;
|
|||
|
else if (g_bInMemoryMode)
|
|||
|
LoggerInfo->LogFileMode |= EVENT_TRACE_BUFFERING_MODE;
|
|||
|
else if (g_bUserMode)
|
|||
|
LoggerInfo->LogFileMode |= EVENT_TRACE_PRIVATE_LOGGER_MODE;
|
|||
|
|
|||
|
strcpy(&Properties.LoggerName[0], g_szLogSessionName);
|
|||
|
strcpy(&Properties.LogFileName[0], g_szLogFileName);
|
|||
|
LoggerInfo->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
|
|||
|
LoggerInfo->LogFileNameOffset = LoggerInfo->LoggerNameOffset +
|
|||
|
MAX_PATH;
|
|||
|
|
|||
|
LoggerInfo->BufferSize = g_ulBufferSize;
|
|||
|
|
|||
|
LoggerInfo->MinimumBuffers = g_ulMinBuffers;
|
|||
|
LoggerInfo->MaximumBuffers = g_ulMaxBuffers;
|
|||
|
|
|||
|
Status = QueryTrace(0,
|
|||
|
g_szLogSessionName,
|
|||
|
(PEVENT_TRACE_PROPERTIES) LoggerInfo);
|
|||
|
if (ERROR_SUCCESS == Status)
|
|||
|
hLogger = LoggerInfo->Wnode.HistoricalContext;
|
|||
|
else if (ERROR_WMI_INSTANCE_NOT_FOUND == Status) {
|
|||
|
// The logger is not already started so try to start it now
|
|||
|
Status = StartTrace(&hLogger,
|
|||
|
g_szLogSessionName,
|
|||
|
LoggerInfo);
|
|||
|
}
|
|||
|
if (ERROR_SUCCESS == Status) {
|
|||
|
g_bStartedTracing = TRUE;
|
|||
|
strcpy(g_szLogSessionName, &Properties.LoggerName[0]);
|
|||
|
strcpy(g_szLogFileName, &Properties.LogFileName[0]);
|
|||
|
}
|
|||
|
else {
|
|||
|
char szTemp[MAX_PATH];
|
|||
|
|
|||
|
_snprintf(szTemp, sizeof(szTemp),
|
|||
|
"IISRTL:\t%s(%d), Unable to get the Logger Handle, return code = %d\n",
|
|||
|
__FILE__, __LINE__,
|
|||
|
Status);
|
|||
|
OutputDebugString(szTemp);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return hLogger;
|
|||
|
}
|
|||
|
|
|||
|
dllexp VOID
|
|||
|
PuUninitiateDebug(
|
|||
|
VOID)
|
|||
|
/*++
|
|||
|
This function stops tracing for the current log file but only if we started
|
|||
|
the tracing in the initiate debug
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Returns:
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOL bStartedTracing = FALSE;
|
|||
|
DWORD dwError;
|
|||
|
|
|||
|
EnterCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
bStartedTracing = g_bStartedTracing;
|
|||
|
g_bStartedTracing = FALSE;
|
|||
|
|
|||
|
LeaveCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
if (bStartedTracing) {
|
|||
|
|
|||
|
struct {
|
|||
|
EVENT_TRACE_PROPERTIES Header;
|
|||
|
char LoggerName[MAX_PATH];
|
|||
|
char LogFileName[MAX_PATH];
|
|||
|
} Properties;
|
|||
|
PEVENT_TRACE_PROPERTIES LoggerInfo;
|
|||
|
|
|||
|
LoggerInfo = (PEVENT_TRACE_PROPERTIES) &Properties.Header;
|
|||
|
RtlZeroMemory(&Properties, sizeof(Properties));
|
|||
|
LoggerInfo->Wnode.BufferSize = sizeof(Properties);
|
|||
|
LoggerInfo->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
|
|||
|
LoggerInfo->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
|
|||
|
LoggerInfo->LogFileNameOffset = LoggerInfo->LoggerNameOffset + MAX_PATH;
|
|||
|
|
|||
|
// Stop tracing to the log file
|
|||
|
dwError = StopTrace(g_hLoggerHandle, g_szLogSessionName, LoggerInfo);
|
|||
|
if (dwError == ERROR_SUCCESS) {
|
|||
|
strcpy(g_szLogFileName, &Properties.LogFileName[0]);
|
|||
|
strcpy(g_szLogSessionName, &Properties.LoggerName[0]);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
dllexp VOID
|
|||
|
PuInitiateDebug(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
This function iterates through the list of modules in the guid list
|
|||
|
registering all of them and starting up logging if that is the state that
|
|||
|
was stored in the registry
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Returns:
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOL bStartedLogger = FALSE;
|
|||
|
|
|||
|
EnterCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
if (!g_bHadARegister) {
|
|||
|
|
|||
|
LIST_ENTRY pRegList;
|
|||
|
SGuidList *pGEReg = NULL;
|
|||
|
LIST_ENTRY *pEntry;
|
|||
|
SGuidList *pGE = NULL;
|
|||
|
char szTemp[MAX_PATH];
|
|||
|
|
|||
|
// Flag us as having done this so that we can later leave this
|
|||
|
// critical section
|
|||
|
g_bHadARegister = TRUE;
|
|||
|
|
|||
|
// Only do the WMI registration if tracing is enabled
|
|||
|
if (g_bTracingEnabled) {
|
|||
|
|
|||
|
// Initialize the list of guids which need to be registered with WMI
|
|||
|
InitializeListHead(&pRegList);
|
|||
|
|
|||
|
// Iterate through the guid list
|
|||
|
for (pEntry = g_pGuidList.Flink;
|
|||
|
pEntry != &g_pGuidList;
|
|||
|
pEntry = pEntry->Flink)
|
|||
|
{
|
|||
|
|
|||
|
pGE = CONTAINING_RECORD(pEntry,
|
|||
|
SGuidList,
|
|||
|
m_leEntry);
|
|||
|
|
|||
|
DBG_ASSERT(TRACESIG == pGE->dwSig);
|
|||
|
|
|||
|
// Allocate memory for a local copy of the entry so that we can
|
|||
|
// add it to our local list
|
|||
|
pGEReg = (SGuidList *) _alloca(sizeof(SGuidList));
|
|||
|
|
|||
|
if (NULL != pGEReg) {
|
|||
|
|
|||
|
// Copy the entry and add it to the local list
|
|||
|
memcpy(pGEReg, pGE, sizeof(SGuidList));
|
|||
|
InsertHeadList(&pRegList, &pGEReg->m_leEntry);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LeaveCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
// Now iterate through our local copy of the list and register all the
|
|||
|
// guids with WMI
|
|||
|
for (pEntry = pRegList.Flink;
|
|||
|
pEntry != &pRegList;
|
|||
|
pEntry = pEntry->Flink)
|
|||
|
{
|
|||
|
TRACE_GUID_REGISTRATION RegGuids;
|
|||
|
ULONG Status = ERROR_SUCCESS;
|
|||
|
|
|||
|
pGEReg = CONTAINING_RECORD(pEntry,
|
|||
|
SGuidList,
|
|||
|
m_leEntry);
|
|||
|
|
|||
|
DBG_ASSERT(TRACESIG == pGEReg->dwSig);
|
|||
|
|
|||
|
// Initialise the GUID registration structure
|
|||
|
memset(&RegGuids, 0x00, sizeof(RegGuids));
|
|||
|
RegGuids.Guid = (LPGUID) &pGEReg->m_dpData.m_guidControl;
|
|||
|
|
|||
|
// And then register the guid
|
|||
|
Status = RegisterTraceGuidsW(IISTraceControlCallback,
|
|||
|
NULL,
|
|||
|
(LPGUID) &pGEReg->m_dpData.m_guidControl,
|
|||
|
1,
|
|||
|
&RegGuids,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
&pGEReg->m_dpData.m_hRegistration);
|
|||
|
|
|||
|
if (ERROR_SUCCESS != Status)
|
|||
|
{
|
|||
|
_snprintf(szTemp, sizeof(szTemp),
|
|||
|
"%16s:\t%s(%d), RegisterTraceGuids returned %d, main ID = %08X\n",
|
|||
|
pGEReg->m_dpData.m_rgchLabel,
|
|||
|
__FILE__, __LINE__,
|
|||
|
Status,
|
|||
|
pGEReg->m_dpData.m_guidControl.Data1);
|
|||
|
OutputDebugString(szTemp);
|
|||
|
}
|
|||
|
else if (pGEReg->m_iInitializeFlags & DEBUG_FLAG_INITIALIZE) {
|
|||
|
|
|||
|
// Turn off the initialize flag
|
|||
|
pGEReg->m_iInitializeFlags &= ~DEBUG_FLAG_INITIALIZE;
|
|||
|
|
|||
|
// Get the trace file handle if necessary
|
|||
|
if (!bStartedLogger) {
|
|||
|
|
|||
|
bStartedLogger = TRUE;
|
|||
|
g_hLoggerHandle = GetTraceFileHandle();
|
|||
|
}
|
|||
|
|
|||
|
// And enable tracing for the module. If this is successful
|
|||
|
// then WMI will call the IISTraceControlCallback
|
|||
|
Status = EnableTrace(TRUE,
|
|||
|
pGEReg->m_dpData.m_iControlFlag,
|
|||
|
pGEReg->m_iDefaultErrorLevel,
|
|||
|
(LPGUID) &pGEReg->m_dpData.m_guidControl,
|
|||
|
g_hLoggerHandle);
|
|||
|
if ((ERROR_SUCCESS != Status) && (ERROR_WMI_ALREADY_ENABLED != Status)) {
|
|||
|
_snprintf(szTemp, sizeof(szTemp),
|
|||
|
"%16s:\t%s(%d), Unable to EnableTrace, return code = %d\n",
|
|||
|
pGEReg->m_dpData.m_rgchLabel,
|
|||
|
__FILE__, __LINE__,
|
|||
|
Status);
|
|||
|
OutputDebugString(szTemp);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Now re-enter the critical section so that we can save the results
|
|||
|
// back to our global data structure
|
|||
|
EnterCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
for (pEntry = pRegList.Flink;
|
|||
|
pEntry != &pRegList;
|
|||
|
pEntry = pEntry->Flink)
|
|||
|
{
|
|||
|
pGEReg = CONTAINING_RECORD(pEntry,
|
|||
|
SGuidList,
|
|||
|
m_leEntry);
|
|||
|
|
|||
|
DBG_ASSERT(TRACESIG == pGEReg->dwSig);
|
|||
|
|
|||
|
// Find the guid in our original guid list
|
|||
|
pGE = FindGuid(&pGEReg->m_dpData.m_guidControl);
|
|||
|
|
|||
|
if (pGE) {
|
|||
|
|
|||
|
// Save the only two things that could have changed
|
|||
|
pGE->m_iInitializeFlags = pGEReg->m_iInitializeFlags;
|
|||
|
pGE->m_dpData.m_hRegistration = pGEReg->m_dpData.m_hRegistration;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LeaveCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
} // PuInitiateDebug()
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PuLoadRegistryInfo(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
This function loads all the registry settings for the project and adds all
|
|||
|
the known modules to the Guid list
|
|||
|
NOTE: It is the responsibility of the caller to enter the guid list
|
|||
|
critical section before calling this function
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
HKEY hk = 0;
|
|||
|
|
|||
|
// Get the global settings which need only be read once, and only for
|
|||
|
// the master
|
|||
|
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, REG_TRACE_IIS, &hk)) {
|
|||
|
|
|||
|
DWORD dwIndex = 0;
|
|||
|
ULONG ulTemp = 0;
|
|||
|
LONG iRegRes = 0;
|
|||
|
char szTemp[MAX_PATH];
|
|||
|
char szModuleName[MAX_PATH];
|
|||
|
DWORD dwReadSize = sizeof(ulTemp);
|
|||
|
DWORD dwSizeOfModuleName = sizeof(szModuleName);
|
|||
|
|
|||
|
// 1. Get the enabled flag, if this is false we do not do any WMI
|
|||
|
// processing, by default this is FALSE
|
|||
|
if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_ENABLED,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) &ulTemp, &dwReadSize))
|
|||
|
g_bTracingEnabled = ulTemp;
|
|||
|
|
|||
|
// 2. Get the AlwaysODS flag, if this is true we will always write
|
|||
|
// trace out with OutputDebugString, effectively CHK build
|
|||
|
// compatability mode
|
|||
|
if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_ODS,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) &ulTemp, &dwReadSize))
|
|||
|
g_ODSEnabled = ulTemp;
|
|||
|
|
|||
|
// 3. Determine if the active flag is set, if it was then it means
|
|||
|
// that something was active at shut down, so for each module load
|
|||
|
// read the appropriate registry entries at start up
|
|||
|
dwReadSize = sizeof(ulTemp);
|
|||
|
if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_ACTIVE,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) &ulTemp, &dwReadSize))
|
|||
|
g_bTracingActive = ulTemp;
|
|||
|
|
|||
|
// 4. Get the trace configuration information, log file name,
|
|||
|
// logging session name, min/max number of buffers, buffer size & mode
|
|||
|
dwReadSize = sizeof(szTemp);
|
|||
|
if (ERROR_SUCCESS == (iRegRes = RegQueryValueEx(hk,
|
|||
|
REG_TRACE_IIS_LOG_FILE_NAME,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
(BYTE *) &szTemp,
|
|||
|
&dwReadSize)))
|
|||
|
strcpy(g_szLogFileName, szTemp);
|
|||
|
else if (ERROR_MORE_DATA == iRegRes) {
|
|||
|
DBGERROR((DBG_CONTEXT,
|
|||
|
"Unable to load tracing logfile name, name too long.\n"));
|
|||
|
}
|
|||
|
else
|
|||
|
DBGWARN((DBG_CONTEXT,
|
|||
|
"Unable to load tracing logfile name, Windows error %d\n",
|
|||
|
iRegRes));
|
|||
|
dwReadSize = sizeof(szTemp);
|
|||
|
if (ERROR_SUCCESS == (iRegRes = RegQueryValueEx(hk,
|
|||
|
REG_TRACE_IIS_LOG_SESSION_NAME,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
(BYTE *) &szTemp,
|
|||
|
&dwReadSize)))
|
|||
|
strcpy(g_szLogSessionName, szTemp);
|
|||
|
else if (ERROR_MORE_DATA == iRegRes) {
|
|||
|
DBGERROR((DBG_CONTEXT,
|
|||
|
"Unable to load tracing log session name, name too long.\n"));
|
|||
|
}
|
|||
|
else
|
|||
|
DBGWARN((DBG_CONTEXT,
|
|||
|
"Unable to load tracing log session name, Windows error %d\n",
|
|||
|
iRegRes));
|
|||
|
dwReadSize = sizeof(ulTemp);
|
|||
|
if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LOG_BUFFER_SIZE,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) &ulTemp, &dwReadSize))
|
|||
|
g_ulBufferSize = ulTemp;
|
|||
|
dwReadSize = sizeof(ulTemp);
|
|||
|
if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LOG_MIN_BUFFERS,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) &ulTemp, &dwReadSize))
|
|||
|
g_ulMinBuffers = ulTemp;
|
|||
|
dwReadSize = sizeof(ulTemp);
|
|||
|
if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LOG_MAX_BUFFERS,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) &ulTemp, &dwReadSize))
|
|||
|
g_ulMaxBuffers = ulTemp;
|
|||
|
dwReadSize = sizeof(ulTemp);
|
|||
|
if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LOG_MAX_FILESIZE,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) &ulTemp, &dwReadSize))
|
|||
|
g_ulMaxFileSize = ulTemp;
|
|||
|
dwReadSize = sizeof(ulTemp);
|
|||
|
if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LOG_MAX_FILESIZE,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) &ulTemp, &dwReadSize))
|
|||
|
g_bRealTimeMode = ulTemp;
|
|||
|
dwReadSize = sizeof(ulTemp);
|
|||
|
if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LOG_MAX_FILESIZE,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) &ulTemp, &dwReadSize))
|
|||
|
g_bInMemoryMode = ulTemp;
|
|||
|
dwReadSize = sizeof(ulTemp);
|
|||
|
if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LOG_MAX_FILESIZE,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) &ulTemp, &dwReadSize))
|
|||
|
g_bUserMode = ulTemp;
|
|||
|
|
|||
|
// 5. Load the ControlFlags and Level. Both default to 0, off
|
|||
|
dwReadSize = sizeof(ulTemp);
|
|||
|
if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_CONTROL,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) &ulTemp, &dwReadSize))
|
|||
|
g_dwDefaultControlFlag = ulTemp;
|
|||
|
dwReadSize = sizeof(ulTemp);
|
|||
|
if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LEVEL,
|
|||
|
NULL, NULL,
|
|||
|
(BYTE *) &ulTemp,
|
|||
|
&dwReadSize)) {
|
|||
|
g_dwDefaultErrorLevel = ulTemp;
|
|||
|
}
|
|||
|
|
|||
|
DBGPRINTF((DBG_CONTEXT, "Enumerating module for : %s\n", REG_TRACE_IIS));
|
|||
|
// Enumerate all the modules listed in the registry for IIS
|
|||
|
while (ERROR_NO_MORE_ITEMS != RegEnumKeyEx(hk, dwIndex,
|
|||
|
szModuleName,
|
|||
|
&dwSizeOfModuleName,
|
|||
|
NULL, NULL, NULL, NULL))
|
|||
|
{
|
|||
|
// Then load the setting for this guid from the registry and
|
|||
|
// set up any defaults that are needed
|
|||
|
LoadGuidFromRegistry(szModuleName);
|
|||
|
|
|||
|
dwSizeOfModuleName = sizeof(szModuleName);
|
|||
|
++dwIndex;
|
|||
|
}
|
|||
|
RegCloseKey(hk);
|
|||
|
}
|
|||
|
#ifdef DBG
|
|||
|
else
|
|||
|
if (g_ODSEnabled)
|
|||
|
OutputDebugString("IISTRACE: Warning, could not find IIS trace entry in "
|
|||
|
"the registry.\n\t Unable to initialize WMI tracing.\n");
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
} // PuLoadRegistryInfo()
|
|||
|
|
|||
|
|
|||
|
LPDEBUG_PRINTS
|
|||
|
PuCreateDebugPrintsObject(
|
|||
|
IN const char * pszPrintLabel,
|
|||
|
IN GUID * ControlGuid,
|
|||
|
IN int * ErrorFlags,
|
|||
|
IN int DefaultControlFlags
|
|||
|
)
|
|||
|
/*++
|
|||
|
This function looks for and if necessary creates a new DEBUG_PRINTS object
|
|||
|
for the required module
|
|||
|
|
|||
|
Arguments:
|
|||
|
*pszPrintLabel pointer to null-terminated string containing the
|
|||
|
label for program's debugging output
|
|||
|
*ControlGuid the unique GUID used to identify this module
|
|||
|
*ErrorFlags pointer to the error flags variable used by the
|
|||
|
module to determine whether or not to log something
|
|||
|
DefaultControlFlags default flags used by IF_DEBUG
|
|||
|
|
|||
|
Returns:
|
|||
|
pointer to a new DEBUG_PRINTS object on success.
|
|||
|
Returns NULL on failure.
|
|||
|
--*/
|
|||
|
{
|
|||
|
DEBUG_PRINTS *pGEData = NULL;
|
|||
|
LIST_ENTRY *pEntry;
|
|||
|
SGuidList *pGE = NULL;
|
|||
|
|
|||
|
DBG_ASSERT(NULL != ErrorFlags);
|
|||
|
DBG_ASSERT(0 != pszPrintLabel[0]);
|
|||
|
|
|||
|
// Look through the guid list for this module
|
|||
|
EnterCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
// See if we have done the registry initialization stuff, if we have then
|
|||
|
// we should have the guid list. The initialization need only be done once
|
|||
|
if (!g_bHaveDoneInit) {
|
|||
|
g_bHaveDoneInit = TRUE;
|
|||
|
PuLoadRegistryInfo();
|
|||
|
}
|
|||
|
|
|||
|
pGE = FindGuid(ControlGuid);
|
|||
|
|
|||
|
// If we don't have a pointer to the data member it means we could not
|
|||
|
// find the guid, so add it to the list
|
|||
|
if (NULL == pGE) {
|
|||
|
|
|||
|
pGE = (SGuidList *) LocalAlloc(LPTR, sizeof(SGuidList));
|
|||
|
if (pGE) {
|
|||
|
|
|||
|
pGEData = &pGE->m_dpData;
|
|||
|
|
|||
|
// Set the SGuidList member variables
|
|||
|
pGE->dwSig = TRACESIG;
|
|||
|
pGE->m_iDefaultErrorLevel = g_dwDefaultErrorLevel;
|
|||
|
|
|||
|
// Set the SGuidList.m_dpData member variables
|
|||
|
strncpy(pGEData->m_rgchLabel,
|
|||
|
pszPrintLabel, MAX_LABEL_LENGTH - 1);
|
|||
|
pGEData->m_rgchLabel[MAX_LABEL_LENGTH-1] = '\0';
|
|||
|
pGEData->m_guidControl = *ControlGuid;
|
|||
|
pGEData->m_bBreakOnAssert = TRUE; // Default - Break if Assert Fails
|
|||
|
pGEData->m_iControlFlag = g_dwDefaultControlFlag;
|
|||
|
|
|||
|
// Add it to the head of the list. Put it at the head in case this
|
|||
|
// is an object which is being loaded and unloaded continuosly.
|
|||
|
InsertHeadList(&g_pGuidList, &pGE->m_leEntry);
|
|||
|
|
|||
|
// And now update the registry with the information about the guid
|
|||
|
// so that we don't have to do this again. While we have already
|
|||
|
// done a DBG_ASSERT above we should still verify that the module
|
|||
|
// has a name before calling this in case of new components
|
|||
|
if (pGEData->m_rgchLabel[0])
|
|||
|
AddToRegistry(pGE);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
pGEData = &pGE->m_dpData;
|
|||
|
|
|||
|
// And then if we have the member initialize its data members with the
|
|||
|
// parameters supplied by the caller
|
|||
|
if (NULL != pGEData) {
|
|||
|
|
|||
|
DBG_ASSERT(!strncmp(pGEData->m_rgchLabel,
|
|||
|
pszPrintLabel,
|
|||
|
MAX_LABEL_LENGTH - 1));
|
|||
|
|
|||
|
// Check to see if we had a deferred start waiting, this would happen
|
|||
|
// if we received a WMI initialize during the main phase but we had not
|
|||
|
// yet loaded this module
|
|||
|
if (pGE->m_iInitializeFlags & DEBUG_FLAG_DEFERRED_START) {
|
|||
|
|
|||
|
pGE->m_iInitializeFlags &= ~(DEBUG_FLAG_DEFERRED_START | DEBUG_FLAG_INITIALIZE);
|
|||
|
}
|
|||
|
// Otherwise load the default control flags, but only if we are not
|
|||
|
// waiting for initialization. When we are waiting, the registry
|
|||
|
// entries we have already loaded are to take precedence
|
|||
|
else if (!(pGE->m_iInitializeFlags & DEBUG_FLAG_INITIALIZE)) {
|
|||
|
|
|||
|
// Set the SGuidList.m_dpData member variables
|
|||
|
pGEData->m_iControlFlag = DefaultControlFlags;
|
|||
|
}
|
|||
|
|
|||
|
// Save the pointer to the error flags and set the level
|
|||
|
pGEData->m_piErrorFlags = ErrorFlags;
|
|||
|
SetLevel(pGE->m_iDefaultErrorLevel, pGEData->m_piErrorFlags);
|
|||
|
}
|
|||
|
|
|||
|
if (NULL == pGEData) {
|
|||
|
char szTemp[MAX_PATH];
|
|||
|
|
|||
|
_snprintf(szTemp, sizeof(szTemp),
|
|||
|
"%16s:\t%s(%d), Unable to find in or add a Guid to the trace list, return code = %d\n",
|
|||
|
pszPrintLabel, __FILE__, __LINE__,
|
|||
|
GetLastError());
|
|||
|
OutputDebugString(szTemp);
|
|||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
// And finally ALWAYS or in the ODS flag if enabled
|
|||
|
if (g_ODSEnabled && ErrorFlags)
|
|||
|
*ErrorFlags |= DEBUG_FLAG_ODS;
|
|||
|
|
|||
|
LeaveCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
return pGEData;
|
|||
|
|
|||
|
} // PuCreateDebugPrintsObject()
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PuDeleteDebugPrintsObject(
|
|||
|
IN OUT LPDEBUG_PRINTS pDebugPrints
|
|||
|
)
|
|||
|
/*++
|
|||
|
This function cleans up the pDebugPrints object and does an frees of
|
|||
|
allocated memory that may be required.
|
|||
|
|
|||
|
Arguments:
|
|||
|
pDebugPrints pointer to the DEBUG_PRINTS object.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
SGuidList *pGE = NULL;
|
|||
|
|
|||
|
EnterCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
if (NULL != pDebugPrints) {
|
|||
|
|
|||
|
// Since we no longer delete anything or bother to shut it down all we
|
|||
|
// need to do here is clear the pointer to the error flag
|
|||
|
pDebugPrints->m_piErrorFlags = NULL;
|
|||
|
|
|||
|
// we allocated an SGuidList that contained the DEBUG_PRINTS struct
|
|||
|
pGE = CONTAINING_RECORD(pDebugPrints, SGuidList, m_dpData);
|
|||
|
DBG_ASSERT(TRACESIG == pGE->dwSig);
|
|||
|
if (pGE)
|
|||
|
{
|
|||
|
RemoveEntryList(&pGE->m_leEntry);
|
|||
|
pGE->dwSig = 0;
|
|||
|
LocalFree(pGE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LeaveCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
} // PuDeleteDebugPrintsObject()
|
|||
|
|
|||
|
VOID
|
|||
|
PuDbgPrintMain(
|
|||
|
IN OUT LPDEBUG_PRINTS pDebugPrints,
|
|||
|
IN const BOOL bUnicodeRequest,
|
|||
|
IN const char * pszFilePath,
|
|||
|
IN int nLineNum,
|
|||
|
IN const char * pszFormat,
|
|||
|
IN va_list argptr
|
|||
|
)
|
|||
|
/*++
|
|||
|
Main function that examines the incoming message and works out what to do
|
|||
|
with the header and the message.
|
|||
|
|
|||
|
Arguments:
|
|||
|
pDebugPrints pointer to the DEBUG_PRINTS object.
|
|||
|
pszFilePath null terminated string which is the file name
|
|||
|
nLineNum the number of the line where the tracing is coming from
|
|||
|
pszFormat & ... the format and arguments to be written out
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LPCSTR pszFileName = strrchr( pszFilePath, '\\');
|
|||
|
WCHAR szwOutput[ MAX_PRINTF_OUTPUT + 2];
|
|||
|
char *pszOutput = (char *) szwOutput;
|
|||
|
char rgchLabel[MAX_LABEL_LENGTH] = "";
|
|||
|
TRACEHANDLE hLogger = 0;
|
|||
|
TRACE_INFO tiTraceInfo;
|
|||
|
DWORD dwSequenceNumber;
|
|||
|
BOOL bUseODS = FALSE;
|
|||
|
int cchOutput;
|
|||
|
int nLength;
|
|||
|
|
|||
|
// Save the current error state so that we don't disrupt it
|
|||
|
DWORD dwErr = GetLastError();
|
|||
|
|
|||
|
// Skip the '\' and retain only the file name in pszFileName
|
|||
|
if (pszFileName)
|
|||
|
++pszFileName;
|
|||
|
else
|
|||
|
pszFileName = pszFilePath;
|
|||
|
|
|||
|
EnterCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
// Determine if we are to do an OutputDebugString
|
|||
|
if (g_ODSEnabled &&
|
|||
|
(pDebugPrints &&
|
|||
|
pDebugPrints->m_piErrorFlags &&
|
|||
|
(*pDebugPrints->m_piErrorFlags & DEBUG_FLAG_ODS)))
|
|||
|
{
|
|||
|
bUseODS = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if (NULL != pDebugPrints) {
|
|||
|
// Save local copies of the data needed for the ODS case
|
|||
|
if (bUseODS) {
|
|||
|
strncpy(rgchLabel, pDebugPrints->m_rgchLabel, sizeof(rgchLabel));
|
|||
|
}
|
|||
|
|
|||
|
// Save local copies of the data needed for the WMI Tracing case
|
|||
|
if (pDebugPrints->m_hLogger) {
|
|||
|
|
|||
|
dwSequenceNumber = ++g_dwSequenceNumber;
|
|||
|
hLogger = pDebugPrints->m_hLogger;
|
|||
|
|
|||
|
// Initialize our traceinfo structure
|
|||
|
memset(&tiTraceInfo, 0x00, sizeof(tiTraceInfo));
|
|||
|
tiTraceInfo.TraceHeader.Guid = pDebugPrints->m_guidControl;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// All data is now local so we can leave the critical section
|
|||
|
LeaveCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
if (hLogger) {
|
|||
|
|
|||
|
int pid = GetCurrentProcessId();
|
|||
|
ULONG Status = ERROR_SUCCESS;
|
|||
|
// Format the incoming message using vsnprintf() so that we don't exceed
|
|||
|
// the buffer length
|
|||
|
if (bUnicodeRequest) {
|
|||
|
cchOutput = _vsnwprintf(szwOutput, MAX_PRINTF_OUTPUT, (WCHAR *) pszFormat, argptr);
|
|||
|
// If the string is too long, we get back a length of -1, so just use the
|
|||
|
// partial data that fits in the string
|
|||
|
if (cchOutput == -1) {
|
|||
|
// Terminate the string properly since _vsnprintf() does not terminate
|
|||
|
// properly on failure.
|
|||
|
cchOutput = MAX_PRINTF_OUTPUT;
|
|||
|
szwOutput[ cchOutput] = '\0';
|
|||
|
}
|
|||
|
++cchOutput;
|
|||
|
cchOutput *= sizeof(WCHAR);
|
|||
|
}
|
|||
|
else {
|
|||
|
cchOutput = _vsnprintf(pszOutput, sizeof(szwOutput), pszFormat, argptr);
|
|||
|
// If the string is too long, we get back a length of -1, so just use the
|
|||
|
// partial data that fits in the string
|
|||
|
if (cchOutput == -1) {
|
|||
|
// Terminate the string properly since _vsnprintf() does not terminate
|
|||
|
// properly on failure.
|
|||
|
cchOutput = sizeof(szwOutput) - 1;
|
|||
|
pszOutput[cchOutput] = '\0';
|
|||
|
}
|
|||
|
++cchOutput;
|
|||
|
}
|
|||
|
// Fill out the Tracing structure
|
|||
|
tiTraceInfo.TraceHeader.Size = sizeof(TRACE_INFO);
|
|||
|
tiTraceInfo.TraceHeader.Class.Type = EVENT_TRACE_TYPE_INFO;
|
|||
|
tiTraceInfo.TraceHeader.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
|
|||
|
tiTraceInfo.TraceHeader.ThreadId = GetCurrentThreadId();
|
|||
|
tiTraceInfo.MofFields[0].DataPtr = (ULONGLONG) &dwSequenceNumber;
|
|||
|
tiTraceInfo.MofFields[0].Length = sizeof(int);
|
|||
|
tiTraceInfo.MofFields[1].DataPtr = (ULONGLONG) &pid;
|
|||
|
tiTraceInfo.MofFields[1].Length = sizeof(int);
|
|||
|
tiTraceInfo.MofFields[2].DataPtr = (ULONGLONG) &nLineNum;
|
|||
|
tiTraceInfo.MofFields[2].Length = sizeof(int);
|
|||
|
tiTraceInfo.MofFields[3].DataPtr = (ULONGLONG) pszFileName;
|
|||
|
tiTraceInfo.MofFields[3].Length = strlen(pszFileName) + 1;
|
|||
|
tiTraceInfo.MofFields[4].DataPtr = (ULONGLONG) szwOutput;
|
|||
|
tiTraceInfo.MofFields[4].Length = cchOutput;
|
|||
|
// Send the trace information to the trace class
|
|||
|
TraceEvent(hLogger, (PEVENT_TRACE_HEADER) &tiTraceInfo);
|
|||
|
}
|
|||
|
|
|||
|
if (bUseODS) {
|
|||
|
|
|||
|
int cchPrologue;
|
|||
|
// Create the prologue
|
|||
|
if (bUnicodeRequest) {
|
|||
|
WCHAR wszLabel[MAX_PRINTF_OUTPUT];
|
|||
|
WCHAR wszFileName[MAX_PRINTF_OUTPUT];
|
|||
|
int iLength = MAX_PRINTF_OUTPUT;
|
|||
|
|
|||
|
if (MultiByteToWideChar(CP_ACP, 0, rgchLabel, -1, wszLabel, iLength) &&
|
|||
|
MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, wszFileName, iLength))
|
|||
|
{
|
|||
|
cchOutput = _snwprintf(szwOutput,
|
|||
|
MAX_PRINTF_OUTPUT,
|
|||
|
L"IISTRACE\t%s\t(%lu)\t[ %12s : %5d]\t",
|
|||
|
wszLabel,
|
|||
|
GetCurrentThreadId(),
|
|||
|
wszFileName,
|
|||
|
nLineNum);
|
|||
|
cchOutput = _vsnwprintf(szwOutput + cchOutput,
|
|||
|
MAX_PRINTF_OUTPUT - cchOutput - 1,
|
|||
|
(WCHAR *) pszFormat,
|
|||
|
argptr);
|
|||
|
// If the string is too long, we get back -1. So we get the string
|
|||
|
// length for partial data.
|
|||
|
if (cchOutput == -1) {
|
|||
|
// Terminate the string properly, since _vsnprintf() does not
|
|||
|
// terminate properly on failure.
|
|||
|
cchOutput = MAX_PRINTF_OUTPUT;
|
|||
|
szwOutput[ cchOutput] = '\0';
|
|||
|
}
|
|||
|
OutputDebugStringW(szwOutput);
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
int cchPrologue;
|
|||
|
// Create the prologue
|
|||
|
cchPrologue = _snprintf(pszOutput,
|
|||
|
sizeof(szwOutput),
|
|||
|
"IISTRACE\t%s\t(%lu)\t[ %12s : %5d]\t",
|
|||
|
rgchLabel,
|
|||
|
GetCurrentThreadId(),
|
|||
|
pszFileName,
|
|||
|
nLineNum);
|
|||
|
// Format the incoming message using vsnprintf() so that the overflows are
|
|||
|
// captured
|
|||
|
cchOutput = _vsnprintf(pszOutput + cchPrologue,
|
|||
|
sizeof(szwOutput) - cchPrologue - 1,
|
|||
|
pszFormat,
|
|||
|
argptr);
|
|||
|
// If the string is too long, we get back -1. So we get the string
|
|||
|
// length for partial data.
|
|||
|
if (cchOutput == -1) {
|
|||
|
// Terminate the string properly, since _vsnprintf() does not
|
|||
|
// terminate properly on failure.
|
|||
|
cchOutput = sizeof(szwOutput) - 1;
|
|||
|
pszOutput[cchOutput] = '\0';
|
|||
|
}
|
|||
|
OutputDebugStringA(pszOutput);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Restore the error state
|
|||
|
SetLastError( dwErr );
|
|||
|
} // PuDbgPrintMain()
|
|||
|
|
|||
|
VOID
|
|||
|
PuDbgPrint(
|
|||
|
IN OUT LPDEBUG_PRINTS pDebugPrints,
|
|||
|
IN const char * pszFilePath,
|
|||
|
IN int nLineNum,
|
|||
|
IN const char * pszFormat,
|
|||
|
...)
|
|||
|
{
|
|||
|
va_list argsList;
|
|||
|
|
|||
|
va_start(argsList, pszFormat);
|
|||
|
PuDbgPrintMain(pDebugPrints, FALSE, pszFilePath, nLineNum, pszFormat, argsList);
|
|||
|
va_end(argsList);
|
|||
|
}
|
|||
|
|
|||
|
dllexp VOID
|
|||
|
PuDbgPrintW(
|
|||
|
IN OUT LPDEBUG_PRINTS pDebugPrints,
|
|||
|
IN const char * pszFilePath,
|
|||
|
IN int nLineNum,
|
|||
|
IN const WCHAR * pszFormat,
|
|||
|
...)
|
|||
|
{
|
|||
|
va_list argsList;
|
|||
|
|
|||
|
va_start(argsList, pszFormat);
|
|||
|
PuDbgPrintMain(pDebugPrints, TRUE, pszFilePath, nLineNum, (char *) pszFormat, argsList);
|
|||
|
va_end(argsList);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PuDbgDumpMain(
|
|||
|
IN OUT LPDEBUG_PRINTS pDebugPrints,
|
|||
|
IN BOOL bUnicodeRequest,
|
|||
|
IN const char * pszFilePath,
|
|||
|
IN int nLineNum,
|
|||
|
IN const char * pszDump
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function that write a dump of a buffer out to the trace file.
|
|||
|
|
|||
|
Arguments:
|
|||
|
pDebugPrints pointer to the DEBUG_PRINTS object.
|
|||
|
pszFilePath null terminated string which is the file name
|
|||
|
nLineNum the number of the line where the tracing is coming from
|
|||
|
pszDump the dump to be written out
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LPCSTR pszFileName = strrchr( pszFilePath, '\\');
|
|||
|
TRACEHANDLE hLogger = 0;
|
|||
|
TRACE_INFO tiTraceInfo;
|
|||
|
DWORD dwSequenceNumber;
|
|||
|
BOOL bUseODS = FALSE;
|
|||
|
DWORD cbDump;
|
|||
|
|
|||
|
// Save the current error state so that we don't disrupt it
|
|||
|
DWORD dwErr = GetLastError();
|
|||
|
|
|||
|
// Skip the complete path name and retain only the file name in pszFileName
|
|||
|
if ( pszFileName)
|
|||
|
++pszFileName;
|
|||
|
else
|
|||
|
pszFileName = pszFilePath;
|
|||
|
|
|||
|
EnterCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
// Determine if we are to do an OutputDebugString
|
|||
|
if (g_ODSEnabled ||
|
|||
|
(pDebugPrints &&
|
|||
|
pDebugPrints->m_piErrorFlags &&
|
|||
|
(*pDebugPrints->m_piErrorFlags & DEBUG_FLAG_ODS)))
|
|||
|
{
|
|||
|
bUseODS = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
// Save local copies of the data needed for the WMI Tracing case
|
|||
|
if ((NULL != pDebugPrints) && pDebugPrints->m_hLogger) {
|
|||
|
|
|||
|
dwSequenceNumber = ++g_dwSequenceNumber;
|
|||
|
hLogger = pDebugPrints->m_hLogger;
|
|||
|
|
|||
|
if (bUnicodeRequest)
|
|||
|
cbDump = (wcslen((WCHAR *) pszDump) + 1) * sizeof(WCHAR);
|
|||
|
else
|
|||
|
cbDump = strlen( pszDump) + 1;
|
|||
|
|
|||
|
// Initialize our traceinfo structure
|
|||
|
memset(&tiTraceInfo, 0x00, sizeof(tiTraceInfo));
|
|||
|
tiTraceInfo.TraceHeader.Guid = pDebugPrints->m_guidControl;
|
|||
|
}
|
|||
|
|
|||
|
// All data is now local so we can leave the critical section
|
|||
|
LeaveCriticalSection(&g_csGuidList);
|
|||
|
|
|||
|
// Send the outputs to respective files.
|
|||
|
if (hLogger) {
|
|||
|
int pid = GetCurrentProcessId();
|
|||
|
// Fill out the Tracing structure
|
|||
|
tiTraceInfo.TraceHeader.Size = sizeof(TRACE_INFO);
|
|||
|
tiTraceInfo.TraceHeader.Class.Type = EVENT_TRACE_TYPE_INFO;
|
|||
|
tiTraceInfo.TraceHeader.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
|
|||
|
tiTraceInfo.TraceHeader.ThreadId = GetCurrentThreadId();
|
|||
|
tiTraceInfo.MofFields[0].DataPtr = (ULONGLONG) &dwSequenceNumber;
|
|||
|
tiTraceInfo.MofFields[0].Length = sizeof(int);
|
|||
|
tiTraceInfo.MofFields[1].DataPtr = (ULONGLONG) &pid;
|
|||
|
tiTraceInfo.MofFields[1].Length = sizeof(int);
|
|||
|
tiTraceInfo.MofFields[2].DataPtr = (ULONGLONG) &nLineNum;
|
|||
|
tiTraceInfo.MofFields[2].Length = sizeof(int);
|
|||
|
tiTraceInfo.MofFields[3].DataPtr = (ULONGLONG) pszFileName;
|
|||
|
tiTraceInfo.MofFields[3].Length = strlen(pszFileName) + 1;
|
|||
|
tiTraceInfo.MofFields[4].DataPtr = (ULONGLONG) pszDump;
|
|||
|
tiTraceInfo.MofFields[4].Length = cbDump;
|
|||
|
// Send the trace information to the trace class
|
|||
|
TraceEvent(hLogger, (PEVENT_TRACE_HEADER) &tiTraceInfo);
|
|||
|
}
|
|||
|
|
|||
|
if (bUseODS) {
|
|||
|
if (bUnicodeRequest)
|
|||
|
OutputDebugStringW((WCHAR *) pszDump);
|
|||
|
else
|
|||
|
OutputDebugString(pszDump);
|
|||
|
}
|
|||
|
|
|||
|
// Restore the error state
|
|||
|
SetLastError( dwErr );
|
|||
|
} // PuDbgDumpMain()
|
|||
|
|
|||
|
VOID
|
|||
|
PuDbgDump(
|
|||
|
IN OUT LPDEBUG_PRINTS pDebugPrints,
|
|||
|
IN const char * pszFilePath,
|
|||
|
IN int nLineNum,
|
|||
|
IN const char * pszDump
|
|||
|
)
|
|||
|
{
|
|||
|
PuDbgDumpMain(pDebugPrints, FALSE, pszFilePath, nLineNum, pszDump);
|
|||
|
}
|
|||
|
|
|||
|
dllexp VOID
|
|||
|
PuDbgDumpW(
|
|||
|
IN OUT LPDEBUG_PRINTS pDebugPrints,
|
|||
|
IN const char * pszFilePath,
|
|||
|
IN int nLineNum,
|
|||
|
IN const WCHAR * pszDump
|
|||
|
)
|
|||
|
{
|
|||
|
PuDbgDumpMain(pDebugPrints, TRUE, pszFilePath, nLineNum, (char *) pszDump);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// N.B. For PuDbgCaptureContext() to work properly, the calling function
|
|||
|
// *must* be __cdecl, and must have a "normal" stack frame. So, we decorate
|
|||
|
// PuDbgAssertFailed() with the __cdecl modifier and disable the frame pointer
|
|||
|
// omission (FPO) optimization.
|
|||
|
//
|
|||
|
|
|||
|
#pragma optimize( "y", off ) // disable frame pointer omission (FPO)
|
|||
|
|
|||
|
VOID
|
|||
|
__cdecl
|
|||
|
PuDbgAssertFailed(
|
|||
|
IN OUT LPDEBUG_PRINTS pDebugPrints,
|
|||
|
IN const char * pszFilePath,
|
|||
|
IN int nLineNum,
|
|||
|
IN const char * pszExpression)
|
|||
|
/*++
|
|||
|
This function calls assertion failure and records assertion failure
|
|||
|
in log file.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
CONTEXT context;
|
|||
|
|
|||
|
PuDbgCaptureContext( &context );
|
|||
|
|
|||
|
PuDbgPrint(pDebugPrints, pszFilePath, nLineNum,
|
|||
|
" Assertion (%s) Failed\n"
|
|||
|
" use !cxr %p to dump context\n",
|
|||
|
pszExpression,
|
|||
|
&context);
|
|||
|
|
|||
|
if (( NULL == pDebugPrints) || (TRUE == pDebugPrints->m_bBreakOnAssert))
|
|||
|
{
|
|||
|
DebugBreak();
|
|||
|
}
|
|||
|
} // PuDbgAssertFailed()
|
|||
|
|
|||
|
#pragma optimize( "", on ) // restore frame pointer omission (FPO)
|
|||
|
|
|||
|
# else // !_NO_TRACING_
|
|||
|
|
|||
|
LPDEBUG_PRINTS
|
|||
|
PuCreateDebugPrintsObject(
|
|||
|
IN const 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;
|
|||
|
pDebugPrints->m_fBreakOnAssert= TRUE; // Default - Break if Assert Fails
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
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); // returns NULL on success
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return ( pDebugPrints);
|
|||
|
|
|||
|
} // PuDeleteDebugPrintsObject()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
dllexp VOID
|
|||
|
PuSetDbgOutputFlags(
|
|||
|
IN OUT LPDEBUG_PRINTS pDebugPrints,
|
|||
|
IN DWORD dwFlags)
|
|||
|
{
|
|||
|
|
|||
|
if ( pDebugPrints == NULL) {
|
|||
|
|
|||
|
SetLastError( ERROR_INVALID_PARAMETER);
|
|||
|
} else {
|
|||
|
|
|||
|
pDebugPrints->m_dwOutputFlags = dwFlags;
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
} // PuSetDbgOutputFlags()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
dllexp DWORD
|
|||
|
PuGetDbgOutputFlags(
|
|||
|
IN const LPDEBUG_PRINTS pDebugPrints)
|
|||
|
{
|
|||
|
return ( pDebugPrints != NULL) ? pDebugPrints->m_dwOutputFlags : 0;
|
|||
|
|
|||
|
} // PuGetDbgOutputFlags()
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
PuOpenDbgFileLocal(
|
|||
|
IN OUT LPDEBUG_PRINTS pDebugPrints)
|
|||
|
{
|
|||
|
if ( pDebugPrints == NULL)
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
|
|||
|
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()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
dllexp DWORD
|
|||
|
PuOpenDbgPrintFile(
|
|||
|
IN OUT LPDEBUG_PRINTS pDebugPrints,
|
|||
|
IN const char * pszFileName,
|
|||
|
IN const 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()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
dllexp 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.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if ( pDebugPrints == NULL) {
|
|||
|
return ( ERROR_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
PuCloseDbgPrintFile( pDebugPrints); // close any existing file.
|
|||
|
|
|||
|
if ( pDebugPrints->m_dwOutputFlags & DbgOutputBackup) {
|
|||
|
|
|||
|
// MakeBkupCopy();
|
|||
|
|
|||
|
OutputDebugString( " Error: MakeBkupCopy() Not Yet Implemented\n");
|
|||
|
}
|
|||
|
|
|||
|
return PuOpenDbgFileLocal( pDebugPrints);
|
|||
|
|
|||
|
} // PuReOpenDbgPrintFile()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
dllexp 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 + 2];
|
|||
|
LPCSTR pszMsg = "";
|
|||
|
INT cchOutput;
|
|||
|
INT cchPrologue;
|
|||
|
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
|
|||
|
|
|||
|
cchPrologue = wsprintf( pszOutput, "IISTRACE\t%s\t(%lu)\t[ %12s : %05d]\t",
|
|||
|
pDebugPrints ? pDebugPrints->m_rgchLabel : "??",
|
|||
|
GetCurrentThreadId(),
|
|||
|
pszFileName, nLineNum);
|
|||
|
|
|||
|
// Format the incoming message using vsnprintf() so that the overflows are
|
|||
|
// captured
|
|||
|
|
|||
|
va_start( argsList, pszFormat);
|
|||
|
|
|||
|
cchOutput = _vsnprintf( pszOutput + cchPrologue,
|
|||
|
MAX_PRINTF_OUTPUT - cchPrologue - 1,
|
|||
|
pszFormat, argsList);
|
|||
|
va_end( argsList);
|
|||
|
|
|||
|
//
|
|||
|
// The string length is long, we get back -1.
|
|||
|
// so we get the string length for partial data.
|
|||
|
//
|
|||
|
|
|||
|
if ( cchOutput == -1 ) {
|
|||
|
|
|||
|
//
|
|||
|
// terminate the string properly,
|
|||
|
// since _vsnprintf() does not terminate properly on failure.
|
|||
|
//
|
|||
|
cchOutput = MAX_PRINTF_OUTPUT;
|
|||
|
pszOutput[ cchOutput] = '\0';
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Send the outputs to respective files.
|
|||
|
//
|
|||
|
|
|||
|
if ( pDebugPrints != NULL)
|
|||
|
{
|
|||
|
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 == NULL ||
|
|||
|
pDebugPrints->m_dwOutputFlags & DbgOutputKdb)
|
|||
|
{
|
|||
|
OutputDebugString( pszOutput);
|
|||
|
}
|
|||
|
|
|||
|
SetLastError( dwErr );
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // PuDbgPrint()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PuDbgDump(
|
|||
|
IN OUT LPDEBUG_PRINTS pDebugPrints,
|
|||
|
IN const char * pszFilePath,
|
|||
|
IN int nLineNum,
|
|||
|
IN const char * pszDump
|
|||
|
)
|
|||
|
{
|
|||
|
LPCSTR pszFileName = strrchr( pszFilePath, '\\');
|
|||
|
LPCSTR pszMsg = "";
|
|||
|
DWORD dwErr;
|
|||
|
DWORD cbDump;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Skip the complete path name and retain file name in pszName
|
|||
|
//
|
|||
|
|
|||
|
if ( pszFileName== NULL) {
|
|||
|
|
|||
|
pszFileName = pszFilePath;
|
|||
|
}
|
|||
|
|
|||
|
dwErr = GetLastError();
|
|||
|
|
|||
|
// No message header for this dump
|
|||
|
cbDump = strlen( pszDump);
|
|||
|
|
|||
|
//
|
|||
|
// Send the outputs to respective files.
|
|||
|
//
|
|||
|
|
|||
|
if ( pDebugPrints != NULL)
|
|||
|
{
|
|||
|
if ( pDebugPrints->m_dwOutputFlags & DbgOutputStderr) {
|
|||
|
|
|||
|
DWORD nBytesWritten;
|
|||
|
|
|||
|
( VOID) WriteFile( pDebugPrints->m_StdErrHandle,
|
|||
|
pszDump,
|
|||
|
cbDump,
|
|||
|
&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,
|
|||
|
pszDump,
|
|||
|
cbDump,
|
|||
|
&nBytesWritten,
|
|||
|
NULL);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( pDebugPrints == NULL
|
|||
|
|| pDebugPrints->m_dwOutputFlags & DbgOutputKdb)
|
|||
|
{
|
|||
|
OutputDebugString( pszDump);
|
|||
|
}
|
|||
|
|
|||
|
SetLastError( dwErr );
|
|||
|
|
|||
|
return;
|
|||
|
} // PuDbgDump()
|
|||
|
|
|||
|
//
|
|||
|
// N.B. For PuDbgCaptureContext() to work properly, the calling function
|
|||
|
// *must* be __cdecl, and must have a "normal" stack frame. So, we decorate
|
|||
|
// PuDbgAssertFailed() with the __cdecl modifier and disable the frame pointer
|
|||
|
// omission (FPO) optimization.
|
|||
|
//
|
|||
|
|
|||
|
#pragma optimize( "y", off ) // disable frame pointer omission (FPO)
|
|||
|
|
|||
|
VOID
|
|||
|
__cdecl
|
|||
|
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.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
CONTEXT context;
|
|||
|
|
|||
|
PuDbgCaptureContext( &context );
|
|||
|
|
|||
|
PuDbgPrint( pDebugPrints, pszFilePath, nLineNum,
|
|||
|
" Assertion (%s) Failed: %s\n"
|
|||
|
" use !cxr %p to dump context\n",
|
|||
|
pszExpression,
|
|||
|
pszMessage,
|
|||
|
&context);
|
|||
|
|
|||
|
if (( NULL == pDebugPrints) || (TRUE == pDebugPrints->m_fBreakOnAssert))
|
|||
|
{
|
|||
|
DebugBreak();
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
} // PuDbgAssertFailed()
|
|||
|
|
|||
|
#pragma optimize( "", on ) // restore frame pointer omission (FPO)
|
|||
|
|
|||
|
|
|||
|
|
|||
|
dllexp VOID
|
|||
|
PuDbgPrintCurrentTime(
|
|||
|
IN OUT LPDEBUG_PRINTS pDebugPrints,
|
|||
|
IN const char * pszFilePath,
|
|||
|
IN int nLineNum
|
|||
|
)
|
|||
|
/*++
|
|||
|
This function generates the current time and prints it out to debugger
|
|||
|
for tracing out the path traversed, if need be.
|
|||
|
|
|||
|
Arguments:
|
|||
|
pszFile pointer to string containing the name of the file
|
|||
|
lineNum line number within the file where this function is called.
|
|||
|
|
|||
|
Returns:
|
|||
|
NO_ERROR always.
|
|||
|
--*/
|
|||
|
{
|
|||
|
PuDbgPrint( pDebugPrints, pszFilePath, nLineNum,
|
|||
|
" TickCount = %u\n",
|
|||
|
GetTickCount()
|
|||
|
);
|
|||
|
|
|||
|
return;
|
|||
|
} // PrintOutCurrentTime()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
dllexp DWORD
|
|||
|
PuLoadDebugFlagsFromReg(IN HKEY hkey, IN DWORD dwDefault, IN LPDEBUG_PRINTS pDebugPrints)
|
|||
|
/*++
|
|||
|
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 = RegQueryValueExA( hkey,
|
|||
|
DEBUG_FLAGS_REGISTRY_LOCATION_A,
|
|||
|
NULL,
|
|||
|
&dwType,
|
|||
|
(LPBYTE)&dwBuffer,
|
|||
|
&cbBuffer );
|
|||
|
|
|||
|
if( ( err == NO_ERROR ) && ( dwType == REG_DWORD ) )
|
|||
|
{
|
|||
|
dwDebug = dwBuffer;
|
|||
|
}
|
|||
|
|
|||
|
cbBuffer = sizeof(DWORD);
|
|||
|
|
|||
|
if (pDebugPrints)
|
|||
|
{
|
|||
|
err = RegQueryValueExA( hkey,
|
|||
|
DEBUG_BREAK_ENABLED_REGKEYNAME_A,
|
|||
|
NULL,
|
|||
|
&dwType,
|
|||
|
(LPBYTE)&dwBuffer,
|
|||
|
&cbBuffer );
|
|||
|
|
|||
|
if( ( err == NO_ERROR ) && ( dwType == REG_DWORD ) )
|
|||
|
{
|
|||
|
pDebugPrints->m_fBreakOnAssert = dwBuffer;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return dwDebug;
|
|||
|
} // PuLoadDebugFlagsFromReg()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
dllexp DWORD
|
|||
|
PuLoadDebugFlagsFromRegStr(IN LPCSTR pszRegKey, IN DWORD dwDefault, IN LPDEBUG_PRINTS pDebugPrints)
|
|||
|
/*++
|
|||
|
Description:
|
|||
|
This function reads the debug flags assumed to be stored in
|
|||
|
the location "DebugFlags" under given key location in registry.
|
|||
|
If there is any error the default value is returned.
|
|||
|
|
|||
|
Arguments:
|
|||
|
pszRegKey - pointer to registry key location from where to read the key from
|
|||
|
dwDefault - default values in case the read from registry fails
|
|||
|
|
|||
|
Returns:
|
|||
|
Newly read value on success
|
|||
|
If there is any error the dwDefault is returned.
|
|||
|
--*/
|
|||
|
{
|
|||
|
HKEY hkey = NULL;
|
|||
|
|
|||
|
DWORD dwVal = dwDefault;
|
|||
|
|
|||
|
DWORD dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|||
|
pszRegKey,
|
|||
|
0,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
&hkey);
|
|||
|
if ( dwError == NO_ERROR) {
|
|||
|
dwVal = PuLoadDebugFlagsFromReg( hkey, dwDefault, pDebugPrints);
|
|||
|
RegCloseKey( hkey);
|
|||
|
hkey = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return ( dwVal);
|
|||
|
} // PuLoadDebugFlagsFromRegStr()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
dllexp 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 = RegSetValueExA(hkey,
|
|||
|
DEBUG_FLAGS_REGISTRY_LOCATION_A,
|
|||
|
0,
|
|||
|
REG_DWORD,
|
|||
|
(LPBYTE)&dwDbg,
|
|||
|
sizeof(dwDbg) );
|
|||
|
}
|
|||
|
|
|||
|
return (err);
|
|||
|
} // PuSaveDebugFlagsInReg()
|
|||
|
|
|||
|
#endif // !_NO_TRACING_
|
|||
|
|
|||
|
VOID
|
|||
|
PuDbgCaptureContext (
|
|||
|
OUT PCONTEXT ContextRecord
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
RtlCaptureContext(ContextRecord);
|
|||
|
return;
|
|||
|
|
|||
|
} // PuDbgCaptureContext
|
|||
|
|
|||
|
/****************************** End of File ******************************/
|
|||
|
|