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.
395 lines
14 KiB
395 lines
14 KiB
//==========================================================================; |
|
// |
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY |
|
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR |
|
// PURPOSE. |
|
// |
|
// Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved. |
|
// |
|
//--------------------------------------------------------------------------; |
|
|
|
|
|
// For every module and executable we store a debugging level and flags |
|
// for the types of output that are desired. Constants for the types are |
|
// defined in WXDEBUG.H and more can be added. |
|
// The keys are stored in the registry under the |
|
// HKEY_LOCAL_MACHINE\SOFTWARE\Debug\<Module Name>\Type and |
|
// HKEY_LOCAL_MACHINE\SOFTWARE\Debug\<Module Name>\Level key values |
|
// |
|
// There are also global values under SOFTWARE\Debug\Global which are loaded |
|
// after the module-specific values. The Types specified there are OR'ed with |
|
// the module specific types and m_dwLevel is set to the greater of the global |
|
// and the module specific settings. |
|
|
|
#include <stdarg.h> |
|
#include <stdio.h> |
|
|
|
#include "extdll.h" |
|
#include "util.h" |
|
#include "wxdebug.h" |
|
|
|
#include <tchar.h> |
|
|
|
#ifdef _DEBUG |
|
|
|
void WINAPI DbgInitModuleName(void); |
|
void WINAPI DbgInitModuleSettings(void); |
|
void WINAPI DbgInitGlobalSettings(void); |
|
void WINAPI DbgInitLogTo(HKEY hKey); |
|
void WINAPI DbgInitKeyLevels(HKEY hKey, DWORD *pdwTypes, DWORD *pdwLevel); |
|
|
|
|
|
|
|
const INT iDEBUGINFO = 512; // Used to format strings |
|
|
|
HINSTANCE m_hInst; // Module instance handle |
|
TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name |
|
//CRITICAL_SECTION m_CSDebug; // Controls access to list |
|
BOOL m_bInit = FALSE; // Have we been initialised |
|
HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here |
|
DWORD m_dwTypes = 0; |
|
DWORD m_dwLevel = 0; |
|
|
|
const TCHAR *m_pBaseKey = TEXT("SOFTWARE\\Debug"); |
|
const TCHAR *m_pGlobalKey = TEXT("GLOBAL"); |
|
TCHAR *pKeyNames[] = |
|
{ |
|
TEXT("Types"), |
|
TEXT("Level") |
|
}; |
|
|
|
|
|
// DbgInitialize |
|
// This sets the instance handle that the debug library uses to find |
|
// the module's file name from the Win32 GetModuleFileName function |
|
void WINAPI DbgInitialise(HINSTANCE hInst) |
|
{ |
|
if (!m_bInit) |
|
{ |
|
//InitializeCriticalSection(&m_CSDebug); |
|
m_bInit = TRUE; |
|
m_hInst = hInst; |
|
DbgInitModuleName(); |
|
DbgInitModuleSettings(); |
|
DbgInitGlobalSettings(); |
|
} |
|
} |
|
|
|
|
|
// DbgTerminate |
|
// This is called to clear up any resources the debug library uses - at the |
|
// moment we delete our critical section and the handle of the output file. |
|
void WINAPI DbgTerminate() |
|
{ |
|
if (m_bInit) |
|
{ |
|
if (m_hOutput != INVALID_HANDLE_VALUE) |
|
{ |
|
DBGASSERTEXECUTE(CloseHandle(m_hOutput)); |
|
m_hOutput = INVALID_HANDLE_VALUE; |
|
} |
|
//DeleteCriticalSection(&m_CSDebug); |
|
m_bInit = FALSE; |
|
} |
|
} |
|
|
|
|
|
// DbgInitModuleName |
|
// Initialise the module file name |
|
void WINAPI DbgInitModuleName() |
|
{ |
|
TCHAR FullName[iDEBUGINFO]; // Load the full path and module name |
|
TCHAR *pName; // Searches from the end for a backslash |
|
|
|
GetModuleFileName(m_hInst,FullName,iDEBUGINFO); |
|
pName = _tcsrchr(FullName,'\\'); |
|
if (pName == NULL) |
|
{ |
|
pName = FullName; |
|
} |
|
else |
|
{ |
|
pName++; |
|
} |
|
lstrcpy(m_ModuleName,pName); |
|
} |
|
|
|
|
|
// DbgInitModuleSettings |
|
// Retrieve the module-specific settings |
|
void WINAPI DbgInitModuleSettings() |
|
{ |
|
LONG lReturn; // Create key return value |
|
TCHAR szInfo[iDEBUGINFO]; // Constructs key names |
|
HKEY hModuleKey; // Module key handle |
|
|
|
// Construct the base key name |
|
wsprintf(szInfo,TEXT("%s\\%s"),m_pBaseKey,m_ModuleName); |
|
|
|
// Create or open the key for this module |
|
lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key |
|
szInfo, // Address of subkey name |
|
(DWORD)0, // Reserved value |
|
NULL, // Address of class name |
|
(DWORD)0, // Special options flags |
|
KEY_ALL_ACCESS, // Desired security access |
|
NULL, // Key security descriptor |
|
&hModuleKey, // Opened handle buffer |
|
NULL); // What really happened |
|
|
|
if (lReturn != ERROR_SUCCESS) |
|
{ |
|
DbgLogInfo(LOG_ERROR, 0, TEXT("Could not access module key")); |
|
return; |
|
} |
|
|
|
DbgInitLogTo(hModuleKey); |
|
DbgInitKeyLevels(hModuleKey, &m_dwTypes, &m_dwLevel); |
|
RegCloseKey(hModuleKey); |
|
} |
|
|
|
|
|
// DbgInitGlobalSettings |
|
// This is called by DbgInitialize to read the global debug settings for |
|
// Level and Type from the registry. The Types are OR'ed together and m_dwLevel |
|
// is set to the greater of the global and module-specific values. |
|
void WINAPI DbgInitGlobalSettings() |
|
{ |
|
LONG lReturn; // Create key return value |
|
TCHAR szInfo[iDEBUGINFO]; // Constructs key names |
|
HKEY hGlobalKey; // Global override key |
|
DWORD dwTypes = 0; |
|
DWORD dwLevel = 0; |
|
|
|
// Construct the global base key name |
|
wsprintf(szInfo,TEXT("%s\\%s"),m_pBaseKey,m_pGlobalKey); |
|
|
|
// Create or open the key for this module |
|
lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key |
|
szInfo, // Address of subkey name |
|
(DWORD)0, // Reserved value |
|
NULL, // Address of class name |
|
(DWORD)0, // Special options flags |
|
KEY_ALL_ACCESS, // Desired security access |
|
NULL, // Key security descriptor |
|
&hGlobalKey, // Opened handle buffer |
|
NULL); // What really happened |
|
|
|
if (lReturn != ERROR_SUCCESS) |
|
{ |
|
DbgLogInfo(LOG_ERROR, 0, TEXT("Could not access GLOBAL module key")); |
|
return; |
|
} |
|
|
|
DbgInitKeyLevels(hGlobalKey, &dwTypes, &dwLevel); |
|
RegCloseKey(hGlobalKey); |
|
|
|
m_dwTypes |= dwTypes; |
|
if (dwLevel > m_dwLevel) |
|
m_dwLevel = dwLevel; |
|
} |
|
|
|
|
|
// DbgInitLogTo |
|
// Called by DbgInitModuleSettings to setup alternate logging destinations |
|
void WINAPI DbgInitLogTo(HKEY hKey) |
|
{ |
|
LONG lReturn; |
|
DWORD dwKeyType; |
|
DWORD dwKeySize; |
|
TCHAR szFile[MAX_PATH] = {0}; |
|
static const TCHAR cszKey[] = TEXT("LogToFile"); |
|
|
|
dwKeySize = MAX_PATH; |
|
lReturn = RegQueryValueEx( |
|
hKey, // Handle to an open key |
|
cszKey, // Subkey name derivation |
|
NULL, // Reserved field |
|
&dwKeyType, // Returns the field type |
|
(LPBYTE) szFile, // Returns the field's value |
|
&dwKeySize); // Number of bytes transferred |
|
|
|
// create an empty key if it does not already exist |
|
if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ) |
|
{ |
|
dwKeySize = 1; |
|
lReturn = RegSetValueEx( |
|
hKey, // Handle of an open key |
|
cszKey, // Address of subkey name |
|
(DWORD) 0, // Reserved field |
|
REG_SZ, // Type of the key field |
|
(PBYTE)szFile, // Value for the field |
|
dwKeySize); // Size of the field buffer |
|
} |
|
|
|
// if an output-to was specified. try to open it. |
|
if (m_hOutput != INVALID_HANDLE_VALUE) |
|
{ |
|
DBGASSERTEXECUTE(CloseHandle(m_hOutput)); |
|
m_hOutput = INVALID_HANDLE_VALUE; |
|
} |
|
if (szFile[0] != 0) |
|
{ |
|
if (!lstrcmpi(szFile, TEXT("Console"))) |
|
{ |
|
m_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); |
|
if (m_hOutput == INVALID_HANDLE_VALUE) |
|
{ |
|
AllocConsole(); |
|
m_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); |
|
} |
|
SetConsoleTitle (TEXT("Valve Debug Output")); |
|
} else if (szFile[0] && |
|
lstrcmpi(szFile, TEXT("Debug")) && |
|
lstrcmpi(szFile, TEXT("Debugger")) && |
|
lstrcmpi(szFile, TEXT("Deb"))) |
|
{ |
|
m_hOutput = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
|
if (INVALID_HANDLE_VALUE != m_hOutput) |
|
{ |
|
static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n"); |
|
SetFilePointer (m_hOutput, 0, NULL, FILE_END); |
|
DbgOutString (cszBar); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
// DbgInitKeyLevels |
|
// This is called by DbgInitModuleSettings and DbgInitGlobalSettings to read |
|
// settings for Types and Level from the registry |
|
void WINAPI DbgInitKeyLevels(HKEY hKey, DWORD *pdwTypes, DWORD *pdwLevel) |
|
{ |
|
LONG lReturn; // Create key return value |
|
DWORD dwKeySize; // Size of the key value |
|
DWORD dwKeyType; // Receives it's type |
|
|
|
// Get the Types value |
|
dwKeySize = sizeof(DWORD); |
|
lReturn = RegQueryValueEx( |
|
hKey, // Handle to an open key |
|
pKeyNames[0], // Subkey name derivation |
|
NULL, // Reserved field |
|
&dwKeyType, // Returns the field type |
|
(LPBYTE)pdwTypes, // Returns the field's value |
|
&dwKeySize ); // Number of bytes transferred |
|
|
|
// If either the key was not available or it was not a DWORD value |
|
// then we ensure only the high priority debug logging is output |
|
// but we try and update the field to a zero filled DWORD value |
|
|
|
if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) |
|
{ |
|
*pdwTypes = 0; |
|
lReturn = RegSetValueEx( |
|
hKey, // Handle of an open key |
|
pKeyNames[0], // Address of subkey name |
|
(DWORD)0, // Reserved field |
|
REG_DWORD, // Type of the key field |
|
(PBYTE)pdwTypes, // Value for the field |
|
sizeof(DWORD)); // Size of the field buffer |
|
|
|
if (lReturn != ERROR_SUCCESS) |
|
{ |
|
DbgLogInfo(LOG_ERROR, 0, TEXT("Could not create subkey %s"),pKeyNames[0]); |
|
*pdwTypes = 0; |
|
} |
|
} |
|
|
|
// Get the Level value |
|
dwKeySize = sizeof(DWORD); |
|
lReturn = RegQueryValueEx( |
|
hKey, // Handle to an open key |
|
pKeyNames[1], // Subkey name derivation |
|
NULL, // Reserved field |
|
&dwKeyType, // Returns the field type |
|
(LPBYTE)pdwLevel, // Returns the field's value |
|
&dwKeySize ); // Number of bytes transferred |
|
|
|
// If either the key was not available or it was not a DWORD value |
|
// then we ensure only the high priority debug logging is output |
|
// but we try and update the field to a zero filled DWORD value |
|
|
|
if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) |
|
{ |
|
*pdwLevel = 0; |
|
lReturn = RegSetValueEx( |
|
hKey, // Handle of an open key |
|
pKeyNames[1], // Address of subkey name |
|
(DWORD)0, // Reserved field |
|
REG_DWORD, // Type of the key field |
|
(PBYTE)pdwLevel, // Value for the field |
|
sizeof(DWORD)); // Size of the field buffer |
|
|
|
if (lReturn != ERROR_SUCCESS) |
|
{ |
|
DbgLogInfo(LOG_ERROR, 0, TEXT("Could not create subkey %s"),pKeyNames[1]); |
|
*pdwLevel = 0; |
|
} |
|
} |
|
} |
|
|
|
|
|
// DbgOutString |
|
void WINAPI DbgOutString(LPCTSTR psz) |
|
{ |
|
if (!m_bInit) |
|
return; |
|
if (m_hOutput != INVALID_HANDLE_VALUE) { |
|
UINT cb = lstrlen(psz); |
|
DWORD dw; |
|
WriteFile (m_hOutput, psz, cb, &dw, NULL); |
|
} else { |
|
OutputDebugString (psz); |
|
} |
|
} |
|
|
|
|
|
// DbgLogInfo |
|
// Print a formatted string to the debugger prefixed with this module's name |
|
// Because the debug code is linked statically every module loaded will |
|
// have its own copy of this code. It therefore helps if the module name is |
|
// included on the output so that the offending code can be easily found |
|
void WINAPI DbgLogInfo(DWORD Type, DWORD Level, const TCHAR *pFormat,...) |
|
{ |
|
if (!m_bInit) |
|
return; |
|
// Check the current level for this type combination */ |
|
if (((Type & m_dwTypes) == 0) || (m_dwLevel < Level)) |
|
return; |
|
|
|
TCHAR szInfo[2000]; |
|
|
|
// Format the variable length parameter list |
|
|
|
va_list va; |
|
va_start(va, pFormat); |
|
|
|
//lstrcpy(szInfo, m_ModuleName); |
|
//lstrcat(szInfo, TEXT(": ")); |
|
wvsprintf(szInfo /* + lstrlen(szInfo) */, pFormat, va); |
|
//lstrcat(szInfo, TEXT("\r\n")); |
|
DbgOutString(szInfo); |
|
|
|
va_end(va); |
|
} |
|
|
|
|
|
// DbgKernelAssert |
|
// If we are executing as a pure kernel filter we cannot display message |
|
// boxes to the user, this provides an alternative which puts the error |
|
// condition on the debugger output with a suitable eye catching message |
|
void WINAPI DbgKernelAssert(const TCHAR *pCondition, const TCHAR *pFileName, INT iLine) |
|
{ |
|
if (!m_bInit) |
|
return; |
|
DbgLogInfo(LOG_ERROR, 0, TEXT(m_ModuleName)); |
|
DbgLogInfo(LOG_ERROR, 0, TEXT(": Assertion FAILED (%s) at line %d in file %s\r\n"), pCondition, iLine, pFileName); |
|
DebugBreak(); |
|
} |
|
|
|
#endif // _DEBUG |
|
|
|
|
|
|