|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: debug.c
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 3-14-95 RichardW Created
//
//----------------------------------------------------------------------------
#include "debuglib.h"
PDebugHeader DbgpHeader = NULL;
DebugModule * * DbgpFixupModules[] = { &__pAssertModule, &__pExceptionModule, NULL };
CHAR szDebugSection[] = "DSysDebug"; CHAR szDebugFlags[] = "DebugFlags";
DEBUG_KEY DbgpKeys[] = { {DEBUG_NO_DEBUGIO, "NoDebugger"}, {DEBUG_TIMESTAMP, "TimeStamp"}, {DEBUG_DEBUGGER_OK, "DebuggerOk"}, {DEBUG_LOGFILE, "Logfile"}, {DEBUG_AUTO_DEBUG, "AutoDebug"}, {DEBUG_USE_KDEBUG, "UseKD"}, {DEBUG_HEAP_CHECK, "HeapCheck"}, {DEBUG_MULTI_THREAD, "MultiThread"}, {DEBUG_DISABLE_ASRT, "DisableAssert"}, {DEBUG_PROMPTS, "AssertPrompts"}, {DEBUG_BREAK_ON_ERROR,"BreakOnError"}, {0, NULL } };
#define DEBUG_NUMBER_OF_KEYS ((sizeof(DbgpKeys) / sizeof(DEBUG_KEY)) - 1)
#define _ALIGN(x,a) ((x) & ((a)-1) ? ((x) + (a)) & ~((a) - 1) : (x));
#define ALIGN_8(x) _ALIGN(x, 8)
#define ALIGN_16(x) _ALIGN(x, 16)
#ifdef WIN64
#define DBG_ALIGN ALIGN_16
#else
#define DBG_ALIGN ALIGN_8
#endif
#define DEBUGMEM_ALLOCATED 0x00000001
typedef struct _DebugMemory { struct _DebugMemory * pNext; DWORD Size; DWORD Flags; } DebugMemory, * PDebugMemory;
#ifdef DEBUG_DEBUG
#define LockDebugHeader(p) EnterCriticalSection(&((p)->csDebug)); OutputDebugStringA("Lock")
#define UnlockDebugHeader(p) LeaveCriticalSection(&((p)->csDebug)); OutputDebugStringA("Unlock")
#else
#define LockDebugHeader(p) EnterCriticalSection(&((p)->csDebug))
#define UnlockDebugHeader(p) LeaveCriticalSection(&((p)->csDebug))
#endif
//+---------------------------------------------------------------------------
//
// Function: DbgpComputeMappingName
//
// Synopsis: Computes the mapping object name
//
// Arguments: [pszName] -- place to stick the name (no more than 32 wchars)
//
// History: 3-22-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
void DbgpComputeMappingName( IN PWSTR pszName, IN SIZE_T NameLen ) { _snwprintf(pszName, NameLen, TEXT("Debug.Memory.%x"), GetCurrentProcessId()); }
//+---------------------------------------------------------------------------
//
// Function: DbgpInitializeMM
//
// Synopsis: Initializes our simple memory manager within the shared mem
// section.
//
// Arguments: [pHeader] -- Header to initialize
//
// History: 3-22-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID DbgpInitializeMM(PDebugHeader pHeader) { PDebugMemory pMem;
pMem = (PDebugMemory) (pHeader + 1); pMem->pNext = NULL; pMem->Size = pHeader->CommitRange - (sizeof(DebugHeader) + sizeof(DebugMemory)); pHeader->pFreeList = pMem; }
//+---------------------------------------------------------------------------
//
// Function: DbgpAlloc
//
// Synopsis: Very, very simple allocator
//
// Arguments: [pHeader] -- Header from which to allocate
// [cSize] -- size to allocate
//
// History: 3-22-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PVOID DbgpAlloc( PDebugHeader pHeader, DWORD cSize) { PDebugMemory pSearch; PDebugMemory pLargest = NULL; PDebugMemory pNew; DWORD cLargest;
cLargest = 0; cSize = DBG_ALIGN(cSize);
//
// Very, very simple allocator. Search free list for an exact match,
//
pSearch = (PDebugMemory) pHeader->pFreeList; while (pSearch) { if ( ( pSearch->Flags & DEBUGMEM_ALLOCATED ) == 0 ) { if ( pSearch->Size == cSize ) { break; }
if (pSearch->Size > cLargest) { pLargest = pSearch; cLargest = pSearch->Size; } }
pSearch = pSearch->pNext; }
//
// If no match yet
//
if (!pSearch) { //
// If the largest free block is still too small,
//
if (cLargest < (cSize + sizeof(DebugMemory) * 2)) { //
// Extend the mapped range
//
if (pHeader->CommitRange < pHeader->ReserveRange) { if ( VirtualAlloc( (PUCHAR) pHeader + pHeader->CommitRange, pHeader->PageSize, MEM_COMMIT, PAGE_READWRITE ) ) { pNew = (PDebugMemory) ((PUCHAR) pHeader + pHeader->CommitRange ); pHeader->CommitRange += pHeader->PageSize ; pNew->Size = pHeader->PageSize - sizeof( DebugMemory ); pNew->pNext = pHeader->pFreeList ; pHeader->pFreeList = pNew ;
return DbgpAlloc( pHeader, cSize ); } else { return NULL ; } }
return(NULL); }
//
// Otherwise, split the largest block into something better...
//
pNew = (PDebugMemory) ((PUCHAR) pLargest + (cSize + sizeof(DebugMemory)) );
pNew->Size = pLargest->Size - (cSize + sizeof(DebugMemory) * 2); pNew->pNext = pLargest->pNext ; pNew->Flags = 0;
pLargest->Size = cSize; pLargest->Flags |= DEBUGMEM_ALLOCATED; pLargest->pNext = pNew;
return((PVOID) (pLargest + 1) ); } else { pSearch->Flags |= DEBUGMEM_ALLOCATED ;
return((PVOID) (pSearch + 1) ); }
return(NULL); }
//+---------------------------------------------------------------------------
//
// Function: DbgpFree
//
// Synopsis: Returns memory to the shared mem segment
//
// Arguments: [pHeader] -- Shared memory header
// [pMemory] -- Memory to free
//
// History: 3-22-95 RichardW Created
//
// Notes: No compaction.
//
//----------------------------------------------------------------------------
VOID DbgpFree( PDebugHeader pHeader, PVOID pMemory) { PDebugMemory pMem;
pMem = (PDebugMemory) ((PUCHAR) pMemory - sizeof(DebugMemory)); pMem->Flags &= ~DEBUGMEM_ALLOCATED; ZeroMemory( pMemory, pMem->Size ); }
//+---------------------------------------------------------------------------
//
// Function: DbgpFindModule
//
// Synopsis: Locates a module based on a name
//
// Arguments: [pHeader] -- Header to search
// [pszName] -- module to find
//
// History: 3-22-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PDebugModule DbgpFindModule( PDebugHeader pHeader, CHAR * pszName) { PDebugModule pSearch;
pSearch = pHeader->pModules; while (pSearch) { if (_strcmpi(pSearch->pModuleName, pszName) == 0) { return(pSearch); } pSearch = pSearch->pNext; }
return(NULL); }
//+---------------------------------------------------------------------------
//
// Function: DbgpCopyModule
//
// Synopsis: Copies a module into a new module. Used for the builtins.
// note, no references to the code module that the builtin lived
// in is kept. This way, the module can unload.
//
// Arguments: [pHeader] --
// [pSource] --
// [ppDest] --
//
// Requires: Header must be locked.
//
// Returns: 0 for failure, non-zero for success
//
// History: 7-19-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD DbgpCopyModule( PDebugHeader pHeader, PDebugModule pSource, PDebugModule * ppDest) { PDebugModule pModule; DWORD i; DWORD cStringSpace; PCHAR pStrings;
*ppDest = NULL;
cStringSpace = strlen(pSource->pModuleName) + 1;
for (i = 0; i < 32 ; i++ ) { if (pSource->TagLevels[i]) { cStringSpace += (strlen(pSource->TagLevels[i]) + 1); } }
//
// Allocate an extra DWORD to store the infolevel.
//
pModule = DbgpAlloc(pHeader, sizeof(DebugModule) + sizeof( DWORD ) ); if (!pModule) { return(0); }
pStrings = DbgpAlloc(pHeader, cStringSpace);
if ( !pStrings ) { DbgpFree( pHeader, pModule );
return 0 ; }
pModule->pModuleName = pStrings;
cStringSpace = strlen(pSource->pModuleName) + 1;
strcpy(pModule->pModuleName, pSource->pModuleName);
pStrings += cStringSpace;
for (i = 0; i < 32 ; i++ ) { if (pSource->TagLevels[i]) { pModule->TagLevels[i] = pStrings; cStringSpace = strlen(pSource->TagLevels[i]) + 1; strcpy(pStrings, pSource->TagLevels[i]); pStrings += cStringSpace; } else { pSource->TagLevels[i] = NULL; } }
//
// Add this in to the global list
//
pModule->pNext = pHeader->pModules; pHeader->pModules = pModule;
//
// Do not increment module count - this is a builtin
//
//
// Copy the rest of the interesting stuff
//
pModule->pInfoLevel = (PDWORD) (pModule + 1); *pModule->pInfoLevel = *pSource->pInfoLevel;
pModule->InfoLevel = pSource->InfoLevel; pModule->fModule = pSource->fModule | DEBUGMOD_BUILTIN_MODULE ; pModule->pHeader = pHeader; pModule->TotalOutput = pSource->TotalOutput; pModule->Reserved = 0;
*ppDest = pModule;
return(1); }
//+---------------------------------------------------------------------------
//
// Function: DbgpAttachBuiltinModules
//
// Synopsis: Attaches the builtin library modules to the global shared
// list
//
// Arguments: [pHeader] --
//
// History: 7-19-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL DbgpAttachBuiltinModules( PDebugHeader pHeader) { PDebugModule pModule; PDebugModule pFixup; DWORD i; BOOL Success = FALSE;
i = 0; while (DbgpFixupModules[i]) { pFixup = *DbgpFixupModules[i];
pModule = DbgpFindModule(pHeader, pFixup->pModuleName); if (pModule) { *DbgpFixupModules[i] = pModule; Success = TRUE; } else { if (DbgpCopyModule(pHeader, pFixup, &pModule)) { *DbgpFixupModules[i] = pModule; Success = TRUE; } }
i++; }
return(Success); }
//+---------------------------------------------------------------------------
//
// Function: DbgpBuildModule
//
// Synopsis: Initializes a Module, builds the string table
//
// Arguments: [pModule] -- Module pointer
// [pHeader] -- Header
// [pKeys] -- Key table
// [pszName] -- Name
// [pInfoLevel] -- Pointer to info level
//
// History: 4-03-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD DbgpBuildModule( PDebugModule pModule, PDebugHeader pHeader, PDEBUG_KEY pKeys, PCHAR pszName, PDWORD pInfoLevel) { PCHAR pStringData; DWORD cStringData; DWORD cKeys; DWORD i; DWORD KeyIndex; DWORD BitScan;
//
// Easy stuff to start..
//
pModule->pInfoLevel = pInfoLevel; pModule->pHeader = pHeader;
cStringData = strlen(pszName) + 1;
//
// Search through the list of masks and string tags, computing
// the size needed for containing them all. If a tag has more
// than one bit set, reject it.
//
for (i = 0; i < 32 ; i++ ) { if (pKeys[i].Mask) { if (pKeys[i].Mask & (pKeys[i].Mask - 1)) { continue; } } if (pKeys[i].Tag) { cStringData += strlen(pKeys[i].Tag) + 1; } else { break; } }
//
// We know how many keys there are, and how big a space they need.
//
cKeys = i;
pStringData = DbgpAlloc(pHeader, cStringData);
if ( !pStringData ) { return 0 ; }
pModule->pModuleName = pStringData; strcpy(pStringData, pszName); pStringData += strlen(pStringData) + 1;
for (i = 0, KeyIndex = 0; i < cKeys ; i++ ) { if (pKeys[i].Mask & (pKeys[i].Mask - 1)) { continue; }
if (!(pKeys[i].Mask & (1 << KeyIndex))) { //
// Grr, out of order. Do a bit-wise scan.
//
KeyIndex = 0; BitScan = 1; while ((pKeys[i].Mask & BitScan) == 0) { BitScan <<= 1; KeyIndex ++; } }
pModule->TagLevels[KeyIndex] = pStringData; strcpy(pStringData, pKeys[i].Tag); pStringData += strlen(pKeys[i].Tag) + 1;
KeyIndex++; }
return(cKeys); }
//+---------------------------------------------------------------------------
//
// Function: DbgpGetBitmask
//
// Synopsis: Based on a parameter line and a key table, builds the bitmask
//
// Arguments: [pKeys] --
// [cKeys] --
// [pszLine] --
// [ParameterIndex] --
// [ParameterValue] --
//
// History: 4-03-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD DbgpGetBitmask( DEBUG_KEY * pKeys, DWORD cKeys, PCHAR pszLine, DWORD ParameterIndex, PCHAR ParameterValue) { PCHAR pszSearch; PCHAR pszParam; PCHAR pszScan; DWORD i; DWORD Mask; DWORD cbParameter = 0; DWORD Compare; CHAR Saved;
if (ParameterIndex < cKeys) { cbParameter = strlen(pKeys[ParameterIndex].Tag); }
Mask = 0;
pszSearch = pszLine;
//
// Scan through the line, searching for flags. Note: do NOT use strtok,
// since that is not exported by ntdll, and we would not be able to make
// security.dll
//
while (*pszSearch) { pszScan = pszSearch; while ((*pszScan) && (*pszScan != ',')) { pszScan++; } Saved = *pszScan; *pszScan = '\0';
for (i = 0; i < cKeys ; i++ ) { if (i == ParameterIndex) { if (_strnicmp(pKeys[i].Tag, pszSearch, cbParameter) == 0) { pszParam = strchr(pszSearch, ':'); if (pszParam) { strcpy(ParameterValue, pszParam + 1); } Mask |= pKeys[i].Mask; } } else { if (_strcmpi(pKeys[i].Tag, pszSearch) == 0) { Mask |= pKeys[i].Mask; }
} }
*pszScan = Saved; if (Saved) { while ((*pszScan) && ((*pszScan == ',') || (*pszScan == ' '))) { pszScan++; } } pszSearch = pszScan; }
return(Mask); }
//+---------------------------------------------------------------------------
//
// Function: DbgpInitializeDebug
//
// Synopsis: Initialize the base memory
//
// Arguments: [pHeader] --
//
// History: 4-03-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID DbgpInitializeDebug( PDebugHeader pHeader) { CHAR szExeName[MAX_PATH] = {0}; PCHAR pszExeName; PCHAR dot; DWORD cbExeName; CHAR LogFile[MAX_PATH + 4] = {0}; // add 4 for ".log"
CHAR Line[MAX_PATH] = {0}; PDebugModule pModule; HANDLE Token; TOKEN_STATISTICS TokenStat; ULONG Size; LUID LocalSys = SYSTEM_LUID;
//
// Plug the debug section in first
//
pModule = DbgpAlloc(pHeader, sizeof(DebugModule)); if (!pModule) { return; }
DbgpBuildModule(pModule, pHeader, DbgpKeys, DEBUG_MODULE_NAME, &pHeader->fDebug);
GetModuleFileNameA(NULL, szExeName, RTL_NUMBER_OF(szExeName) - 1); pszExeName = strrchr(szExeName, '\\'); if (pszExeName) { pszExeName++; } else { pszExeName = szExeName; }
dot = strrchr(pszExeName, '.'); if (dot) { *dot = '\0'; }
cbExeName = (DWORD) (dot - pszExeName); pHeader->pszExeName = DbgpAlloc(pHeader, cbExeName + 1); if (pHeader->pszExeName) { strcpy(pHeader->pszExeName, pszExeName); }
LogFile[0] = '\0';
if (GetProfileStringA( szDebugSection, pszExeName, "", Line, RTL_NUMBER_OF(Line) - 1)) { pHeader->fDebug = DbgpGetBitmask( DbgpKeys, DEBUG_NUMBER_OF_KEYS, Line, 3, LogFile);
}
//
// If running as local system, turn on the kd flag. That
// way,
if ( OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &Token ) ) { if ( GetTokenInformation( Token, TokenStatistics, &TokenStat, sizeof( TokenStat ), &Size ) ) { if ( (TokenStat.AuthenticationId.LowPart == LocalSys.LowPart ) && (TokenStat.AuthenticationId.HighPart == LocalSys.HighPart ) ) { pHeader->fDebug |= DEBUG_USE_KDEBUG ; } }
CloseHandle( Token ); }
if (GetProfileStringA( szDebugSection, szDebugFlags, "", Line, RTL_NUMBER_OF(Line) - 1)) { pHeader->fDebug |= DbgpGetBitmask( DbgpKeys, DEBUG_NUMBER_OF_KEYS, Line, 3, LogFile);
}
if ( pHeader->fDebug & DEBUG_USE_KDEBUG ) { //
// Verify that there is a kernel debugger
//
SYSTEM_KERNEL_DEBUGGER_INFORMATION KdInfo ; NTSTATUS Status ;
Status = NtQuerySystemInformation( SystemKernelDebuggerInformation, &KdInfo, sizeof( KdInfo ), NULL );
if ( NT_SUCCESS( Status ) ) { if ( !KdInfo.KernelDebuggerEnabled ) { pHeader->fDebug &= ~(DEBUG_USE_KDEBUG) ; } }
}
if (pHeader->fDebug & DEBUG_LOGFILE) { if (LogFile[0] == '\0') { strcpy(LogFile, szExeName); strcat(LogFile, ".log"); } pHeader->hLogFile = CreateFileA(LogFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, //&sa,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL); }
pHeader->pModules = pModule; pHeader->pGlobalModule = pModule; pModule->pInfoLevel = &pHeader->fDebug; pModule->InfoLevel = pHeader->fDebug;
DbgpAttachBuiltinModules(pHeader); }
//+---------------------------------------------------------------------------
//
// Function: DbgpOpenLogFileRandom
//
// Synopsis: Opens the logfile dynamically
//
// Arguments: [pHeader] --
//
// History: 4-27-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL DbgpOpenLogFileRandom( PDebugHeader pHeader) { WCHAR szLogPath[MAX_PATH + 4] = {0}; // add 4 for ".log"
DWORD dwPath; PWSTR pszDot;
dwPath = GetModuleFileName(NULL, szLogPath, RTL_NUMBER_OF(szLogPath) - 4 - 1);
pszDot = wcsrchr(szLogPath, L'.'); if (!pszDot) { pszDot = &szLogPath[dwPath]; }
wcscpy(pszDot, L".log");
LockDebugHeader(pHeader);
pHeader->hLogFile = CreateFileW(szLogPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, //&sa,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL);
if (pHeader->hLogFile == INVALID_HANDLE_VALUE) { pHeader->fDebug &= ~(DEBUG_LOGFILE); UnlockDebugHeader(pHeader); return(FALSE); }
UnlockDebugHeader(pHeader); return(TRUE); }
//+---------------------------------------------------------------------------
//
// Function: _DbgSetLoggingFile
//
// Synopsis: Sets the passed in file handle as the logging file handle.
// This function should be called in combination with
// _DbgSetLoggingOption since this function actually enables/disables
// file logging. Note that if _DbgSetLoggingOption is called
// with the On parameter as FALSE then the file handle will be
// closed.
//
// Arguments: [pHeader] --
// [hLogFile] --
//
// History: 7-16-02 jeffspel Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID _DbgSetLoggingFile( PVOID pControl, HANDLE hLogFile ) { PDebugModule pModule;
pModule = (PDebugModule)pControl;
if ( pModule ) { LockDebugHeader(pModule->pHeader);
pModule->pHeader->hLogFile = hLogFile;
UnlockDebugHeader(pModule->pHeader); } }
//+---------------------------------------------------------------------------
//
// Function: DbgpOpenOrCreateSharedMem
//
// Synopsis: Returns a pointer to the shared memory segment,
// creating it if necessary. Header is LOCKED on return
//
// Arguments: (none)
//
// History: 3-22-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PVOID DbgpOpenOrCreateSharedMem(DWORD Flags) { HANDLE hMapping; WCHAR szMappingName[32] = {0}; PDebugHeader pHeader; SYSTEM_INFO SysInfo;
if (DbgpHeader) { LockDebugHeader(DbgpHeader); return(DbgpHeader); }
GetSystemInfo(&SysInfo);
DbgpComputeMappingName(szMappingName, RTL_NUMBER_OF( szMappingName ) - 1); hMapping = OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, szMappingName);
if (hMapping) { //
// Ok, someone else has created the section. So, we just need to map
// it.
//
pHeader = MapViewOfFileEx( hMapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, SysInfo.dwPageSize, NULL);
if ( pHeader ) { if (pHeader != pHeader->pvSection) { DbgpHeader = pHeader->pvSection; } else { DbgpHeader = pHeader; }
UnmapViewOfFile(pHeader); } else { DbgpHeader = NULL ; }
//
// Now that we have the other guy's address, we can throw away this
// one.
//
CloseHandle(hMapping);
if ( DbgpHeader ) { LockDebugHeader(DbgpHeader);
DbgpAttachBuiltinModules(DbgpHeader); }
return(DbgpHeader); }
if (Flags & DSYSDBG_OPEN_ONLY) { return(NULL); }
hMapping = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, //&sa,
PAGE_READWRITE | SEC_RESERVE, 0, SysInfo.dwAllocationGranularity, szMappingName); if (hMapping) { PDebugHeader pMappedHeader;
pMappedHeader = MapViewOfFileEx(hMapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, SysInfo.dwAllocationGranularity, NULL);
if (!pMappedHeader) { return NULL; }
//
// Commit the view, so we can initialize the header
//
pHeader = (PDebugHeader) VirtualAlloc(pMappedHeader, SysInfo.dwPageSize, MEM_COMMIT, PAGE_READWRITE);
if (pHeader == NULL) { UnmapViewOfFile(pMappedHeader); return NULL; }
pHeader->Tag = DEBUG_TAG; pHeader->pvSection = pHeader; pHeader->hMapping = hMapping; pHeader->hLogFile = INVALID_HANDLE_VALUE; pHeader->CommitRange = SysInfo.dwPageSize; pHeader->ReserveRange = SysInfo.dwAllocationGranularity; pHeader->PageSize = SysInfo.dwPageSize; pHeader->pModules = NULL; pHeader->pFreeList = NULL; pHeader->pBufferList = &pHeader->DefaultBuffer ; pHeader->DefaultBuffer.Next = NULL ;
InitializeCriticalSection(&pHeader->csDebug);
LockDebugHeader(pHeader);
DbgpInitializeMM(pHeader); DbgpInitializeDebug(pHeader);
DbgpHeader = pHeader;
return(pHeader); }
return(NULL); }
//+---------------------------------------------------------------------------
//
// Function: DbgpLoadValidateRoutine
//
// Synopsis: Loads RtlValidateProcessHeaps() from ntdll
//
// Arguments: [pHeader] --
//
// History: 5-02-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID DbgpLoadValidateRoutine(PDebugHeader pHeader) { HMODULE hNtDll;
hNtDll = LoadLibrary(TEXT("ntdll.dll")); if (hNtDll) { pHeader->pfnValidate = (HEAPVALIDATE) GetProcAddress(hNtDll, "RtlValidateProcessHeaps"); if (!pHeader->pfnValidate) { pHeader->fDebug &= ~(DEBUG_HEAP_CHECK); }
//
// We can safely free this handle, since kernel32 and advapi32 DLLs
// both use ntdll, so the refcount won't go to zero.
//
FreeLibrary(hNtDll); } }
//+---------------------------------------------------------------------------
//
// Function: _InitDebug
//
// Synopsis: Workhorse of the initializers
//
// Arguments: [pInfoLevel] -- Pointer to module specific infolevel
// [ppControlBlock] -- Pointer to module specific control pointer
// [szName] -- Name
// [pKeys] -- Key data
//
// History: 3-22-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID _InitDebug( DWORD Flags, DWORD * pInfoLevel, PVOID * ppControlBlock, CHAR * szName, PDEBUG_KEY pKeys) { PDebugHeader pHeader; PDebugModule pModule; CHAR Line[MAX_PATH] = {0}; DWORD cKeys; DWORD i;
if ( (*ppControlBlock) && (*ppControlBlock != INVALID_HANDLE_VALUE) ) { //
// Already Initialized
//
return ; }
*ppControlBlock = NULL;
//
// Find the shared section.
//
pHeader = DbgpOpenOrCreateSharedMem(Flags);
if (!pHeader) { if (Flags & DSYSDBG_DEMAND_OPEN) { *ppControlBlock = (PVOID) INVALID_HANDLE_VALUE; } return; }
//
// See if we have already registered (dll being loaded several times)
// if not, allocate a new module.
//
pModule = DbgpFindModule(pHeader, szName); if (!pModule) { pModule = DbgpAlloc(pHeader, sizeof(DebugModule) ); if (!pModule) { UnlockDebugHeader(pHeader); return; } } else { //
// Found module already loaded. Check to see that everything
// lines up:
//
if ( pModule->pInfoLevel != pInfoLevel ) { //
// Uh oh, there's a module with our name already loaded,
// but the pointers don't match. So, let's create our
// own now.
//
pModule = DbgpAlloc( pHeader, sizeof( DebugModule ) );
if ( !pModule ) { UnlockDebugHeader( pHeader ); return; } } else { *ppControlBlock = pModule; UnlockDebugHeader(pHeader); return; } }
//
// Initialize module
//
cKeys = DbgpBuildModule(pModule, pHeader, pKeys, szName, pInfoLevel);
//
// Now, load up info levels from ini or registry
// First, try a module specific entry.
//
if (GetProfileStringA(szName, szDebugFlags, "", Line, RTL_NUMBER_OF(Line) - 1)) { pModule->InfoLevel = DbgpGetBitmask(pKeys, cKeys, Line, 0xFFFFFFFF, NULL ); }
if (pHeader->pszExeName) { if (GetProfileStringA(szName, pHeader->pszExeName, "", Line, RTL_NUMBER_OF(Line) - 1)) { pModule->InfoLevel = DbgpGetBitmask(pKeys, cKeys, Line, 0xFFFFFFFF, NULL );
} }
// HACK - Make Default DBG / DEBUG_SUPPORT dependent. See dsysdbg.h
if (GetProfileStringA(szDebugSection, szName, SZ_DEFAULT_PROFILE_STRING, Line, RTL_NUMBER_OF(Line) - 1)) { pModule->InfoLevel |= DbgpGetBitmask( pKeys, cKeys, Line, 0xFFFFFFFF, NULL ); }
*pModule->pInfoLevel = pModule->InfoLevel;
pModule->pNext = pHeader->pModules; pHeader->pModules = pModule; pHeader->ModuleCount++ ; *ppControlBlock = pModule;
UnlockDebugHeader(pHeader); }
VOID _UnloadDebug( PVOID pControlBlock ) { PDebugHeader pHeader; PDebugModule pModule; PDebugModule pScan ; BOOL FreeIt = FALSE ;
pModule = (PDebugModule) pControlBlock ;
if ( !pModule ) { return ; }
if ( pModule->pInfoLevel == NULL ) { return ; }
pHeader = pModule->pHeader ;
LockDebugHeader( pHeader );
pScan = pHeader->pModules ;
if ( pScan == pModule ) { pHeader->pModules = pModule->pNext ; } else { while ( pScan && ( pScan->pNext != pModule ) ) { pScan = pScan->pNext ; }
if ( pScan ) { pScan->pNext = pModule->pNext ; }
pModule->pNext = NULL ; }
DbgpFree( pHeader, pModule->pModuleName );
DbgpFree( pHeader, pModule );
pHeader->ModuleCount-- ;
if ( pHeader->ModuleCount == 0 ) { FreeIt = TRUE ; }
UnlockDebugHeader( pHeader );
if ( FreeIt ) { if ( pHeader->hLogFile != INVALID_HANDLE_VALUE ) { CloseHandle( pHeader->hLogFile ); }
if ( pHeader->hMapping ) { CloseHandle( pHeader->hMapping ); }
DeleteCriticalSection( &pHeader->csDebug );
UnmapViewOfFile( pHeader ); } }
//+---------------------------------------------------------------------------
//
// Function: DbgpGetTextBuffer
//
// Synopsis: Gets a text buffer from the header, allocating if necessary
//
// Arguments: [pHeader] --
//
// History: 3-19-98 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PDEBUG_TEXT_BUFFER DbgpGetTextBuffer( PDebugHeader pHeader ) { PDEBUG_TEXT_BUFFER pBuffer ;
LockDebugHeader( pHeader );
if ( pHeader->pBufferList ) { pBuffer = pHeader->pBufferList ;
pHeader->pBufferList = pBuffer->Next ;
} else { pBuffer = DbgpAlloc( pHeader, sizeof( DEBUG_TEXT_BUFFER ) ); }
UnlockDebugHeader( pHeader );
if ( pBuffer ) { pBuffer->Next = NULL ; }
return pBuffer ; }
//+---------------------------------------------------------------------------
//
// Function: DbgpReleaseTextBuffer
//
// Synopsis: Releases a text buffer back to the pool of buffers
//
// Arguments: [pHeader] --
// [pBuffer] --
//
// History: 3-19-98 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID DbgpReleaseTextBuffer( PDebugHeader pHeader, PDEBUG_TEXT_BUFFER pBuffer ) { LockDebugHeader( pHeader );
pBuffer->Next = pHeader->pBufferList ;
pHeader->pBufferList = pBuffer ;
UnlockDebugHeader( pHeader ); }
//+---------------------------------------------------------------------------
//
// Function: _DebugOut
//
// Synopsis: Workhorse for the debug out functions
//
// Arguments: [pControl] -- Control pointer
// [Mask] -- Event mask
// [Format] -- format string
// [ArgList] -- va_list...
//
// History: 3-22-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID _DebugOut( PVOID pControl, ULONG Mask, CHAR * Format, va_list ArgList) { PDebugModule pModule; int Level = 0; int PrefixSize = 0; int TotalSize; BOOL fLocked; BOOL fClean; PCHAR Tag; BOOL Break = FALSE ; PDEBUG_TEXT_BUFFER pBuffer ;
if ( pControl == NULL ) { return ; }
pModule = (PDebugModule) pControl;
if ( pModule->pInfoLevel == NULL ) { return ; }
if (!pModule || (pModule == INVALID_HANDLE_VALUE)) { if (Mask & DSYSDBG_FORCE) { NOTHING ; } else return; }
if (pModule->fModule & DEBUGMOD_CHANGE_INFOLEVEL) { *pModule->pInfoLevel = pModule->InfoLevel; pModule->fModule &= ~(DEBUGMOD_CHANGE_INFOLEVEL); }
if (pModule->pHeader->pGlobalModule->fModule & DEBUGMOD_CHANGE_INFOLEVEL) { pModule->pHeader->fDebug = pModule->pHeader->pGlobalModule->InfoLevel; pModule->pHeader->pGlobalModule->fModule &= ~(DEBUGMOD_CHANGE_INFOLEVEL); }
pModule->InfoLevel = *pModule->pInfoLevel;
if (pModule->pHeader->fDebug & DEBUG_MULTI_THREAD) { LockDebugHeader(pModule->pHeader); fLocked = TRUE; } else fLocked = FALSE;
if (pModule->pHeader->fDebug & DEBUG_HEAP_CHECK) { if (!pModule->pHeader->pfnValidate) { DbgpLoadValidateRoutine(pModule->pHeader); } if (pModule->pHeader->pfnValidate) { pModule->pHeader->pfnValidate(); } }
fClean = ((Mask & DSYSDBG_CLEAN) != 0);
if ( ( Mask & DEB_ERROR ) && ( pModule->pHeader->fDebug & DEBUG_BREAK_ON_ERROR ) ) { Break = TRUE ; }
pBuffer = DbgpGetTextBuffer( pModule->pHeader );
if ( !pBuffer ) { OutputDebugStringA( "_DebugOut : Out of memory\n" ); if ( fLocked ) { UnlockDebugHeader( pModule->pHeader );
} return; }
if (Mask & (pModule->InfoLevel | DSYSDBG_FORCE)) {
if (Mask & DSYSDBG_FORCE) { Tag = "FORCE"; } else { while (!(Mask & 1)) { Level++; Mask >>= 1; } Tag = pModule->TagLevels[Level]; }
//
// Make the prefix first: "Process.Thread> Module-Tag:
//
if (!fClean) { if (pModule->pHeader->fDebug & DEBUG_TIMESTAMP) { SYSTEMTIME stTime;
GetLocalTime(&stTime);
PrefixSize = _snprintf(pBuffer->TextBuffer, RTL_NUMBER_OF(pBuffer->TextBuffer) - 1, "[%2d/%2d %02d:%02d:%02d] %d.%d> %s-%s: ", stTime.wMonth, stTime.wDay, stTime.wHour, stTime.wMinute, stTime.wSecond, GetCurrentProcessId(), GetCurrentThreadId(), pModule->pModuleName, Tag); } else { PrefixSize = _snprintf(pBuffer->TextBuffer, RTL_NUMBER_OF(pBuffer->TextBuffer) - 1, "%d.%d> %s-%s: ", GetCurrentProcessId(), GetCurrentThreadId(), pModule->pModuleName, Tag); }
if (PrefixSize < 0) { PrefixSize = 0; // chop off the prefix
} }
if ((TotalSize = _vsnprintf(&pBuffer->TextBuffer[PrefixSize], DEBUG_TEXT_BUFFER_SIZE - PrefixSize - 1, Format, ArgList)) < 0) { //
// Less than zero indicates that the string could not be
// fitted into the buffer. Output a special message indicating
// that:
//
OutputDebugStringA("dsysdbg: Could not pack string into 512 bytes\n"); } else { TotalSize += PrefixSize;
if ((pModule->pHeader->fDebug & DEBUG_NO_DEBUGIO) == 0 ) { OutputDebugStringA( pBuffer->TextBuffer ); }
if ((pModule->pHeader->fDebug & DEBUG_LOGFILE)) { if (pModule->pHeader->hLogFile == INVALID_HANDLE_VALUE) { DbgpOpenLogFileRandom(pModule->pHeader); }
if (!WriteFile( pModule->pHeader->hLogFile, pBuffer->TextBuffer, (DWORD) TotalSize, (PDWORD) &PrefixSize, NULL )) { CHAR szOutput[MAX_PATH] = {0}; _snprintf(szOutput, RTL_NUMBER_OF(szOutput) - 1, "_DebugOut: WriteFile failed with %#x\n", GetLastError()); OutputDebugStringA(szOutput); } }
pModule->pHeader->TotalWritten += TotalSize; pModule->TotalOutput += TotalSize; } } if (fLocked) { UnlockDebugHeader(pModule->pHeader); }
DbgpReleaseTextBuffer( pModule->pHeader, pBuffer );
if ( Break ) { OutputDebugStringA( "BreakOnError\n" ); DebugBreak(); } }
VOID _DbgSetOption( PVOID pControl, DWORD Option, BOOL On, BOOL Global ) { PDebugModule pModule;
pModule = (PDebugModule) pControl ;
if ( pModule ) { if ( Global ) { pModule = pModule->pHeader->pGlobalModule ; }
if ( On ) { pModule->InfoLevel |= Option ; *pModule->pInfoLevel |= Option ; } else { pModule->InfoLevel &= (~Option) ; *pModule->pInfoLevel &= (~Option) ; } } }
VOID _DbgSetLoggingOption( PVOID pControl, BOOL On ) { PDebugModule pModule;
pModule = (PDebugModule)pControl;
if ( pModule ) { if (((pModule->pHeader->fDebug & DEBUG_LOGFILE) == 0) && On )// off, turn it on
{ pModule->pHeader->fDebug |= DEBUG_LOGFILE; } else if ((pModule->pHeader->fDebug & DEBUG_LOGFILE) && !On) // on, turn it off
{ pModule->pHeader->fDebug &= (~DEBUG_LOGFILE); if ( pModule->pHeader->hLogFile != INVALID_HANDLE_VALUE ) { CloseHandle( pModule->pHeader->hLogFile ); pModule->pHeader->hLogFile = INVALID_HANDLE_VALUE; } } } }
|