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.
1724 lines
44 KiB
1724 lines
44 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|