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.
461 lines
11 KiB
461 lines
11 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
spllib.cxx
|
|
|
|
Abstract:
|
|
|
|
Extensions for spllib
|
|
|
|
Author:
|
|
|
|
Albert Ting (AlbertT) 20-Feb-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
/********************************************************************
|
|
|
|
Helper routines
|
|
|
|
********************************************************************/
|
|
|
|
#if !DBG
|
|
#error "Only the debug version should be built."
|
|
#endif
|
|
|
|
BOOL
|
|
TDebugExt::
|
|
bDumpCritSec(
|
|
PVOID pCritSec_,
|
|
ULONG_PTR dwAddr
|
|
)
|
|
{
|
|
MCritSec* pCritSec = (MCritSec*)pCritSec_;
|
|
|
|
if( !pCritSec->bSigCheck( )){
|
|
return FALSE;
|
|
}
|
|
|
|
Print( "MCritSec*\n" );
|
|
|
|
Print( " CriticalSection @ %x\n", dwAddr + OFFSETOF( MCritSec, _CritSec ));
|
|
Print( " dwThreadOwner %x\n", pCritSec->_dwThreadOwner );
|
|
Print( " dwEntryCount <%d> ", pCritSec->_dwEntryCount );
|
|
|
|
if( pCritSec->_dwEntryCount ){
|
|
Print( "Owned\n" );
|
|
} else {
|
|
Print( "Not Owned\n" );
|
|
}
|
|
Print( "dwTickCountEntered <%d>\n", pCritSec->_dwTickCountEntered );
|
|
|
|
Print( "==== Statistics\n" );
|
|
|
|
Print( " dwTickCountBlockedTotal <%d>\n", pCritSec->_dwTickCountBlockedTotal );
|
|
Print( " dwTickCountInsideTotal <%d>\n", pCritSec->_dwTickCountInsideTotal );
|
|
Print( " dwEntryCountTotal <%d>\n", pCritSec->_dwEntryCountTotal );
|
|
|
|
Print( " CritSecHardLock_base " ); vDumpPDL( pCritSec->CritSecHardLock_pdlBase( ));
|
|
|
|
ULONG_PTR dwAddrBt = dwAddr + OFFSETOF( MCritSec, _BackTrace )
|
|
- OFFSETOF_BASE( TBackTraceMem, VBackTrace );
|
|
|
|
Print( " VBackTrace @ %x !splx.ddt -x %x\n",
|
|
dwAddrBt, dwAddrBt );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
TDebugExt::
|
|
bDumpBackTrace(
|
|
ULONG_PTR dwAddr,
|
|
COUNT Count,
|
|
PDWORD pdwSkip,
|
|
DWORD DebugTrace,
|
|
DWORD DebugLevel,
|
|
DWORD dwThreadId,
|
|
ULONG_PTR dwMem
|
|
)
|
|
{
|
|
#ifdef TRACE_ENABLED
|
|
|
|
BYTE abyBackTraceBuffer[sizeof(TBackTraceMem)];
|
|
TBackTraceMem* pBackTraceMem = (TBackTraceMem*)abyBackTraceBuffer;
|
|
|
|
move2( pBackTraceMem, dwAddr, sizeof( TBackTraceMem ));
|
|
|
|
if( !pBackTraceMem->bSigCheck( )){
|
|
return FALSE;
|
|
}
|
|
|
|
INT iLineStart = pBackTraceMem->_uNextFree;
|
|
INT iLine;
|
|
|
|
if( iLineStart < 0 ){
|
|
iLineStart = TBackTraceMem::kMaxCall - 1;
|
|
}
|
|
|
|
for( iLine = iLineStart - 1; Count; --iLine, --Count ){
|
|
|
|
if( CheckControlCRtn()){
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Handle wrap around case.
|
|
//
|
|
if( iLine < 0 ){
|
|
iLine = TBackTraceMem::kMaxCall - 1;
|
|
}
|
|
|
|
if( iLine == iLineStart ||
|
|
!TDebugExt::bDumpDebugTrace( (ULONG_PTR)&pBackTraceMem->_pLines[iLine],
|
|
1,
|
|
pdwSkip,
|
|
DebugTrace,
|
|
DebugLevel,
|
|
dwThreadId,
|
|
dwMem )){
|
|
//
|
|
// Wrapped around yet didn't find enough.
|
|
//
|
|
Print( "Out of lines\n" );
|
|
return TRUE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
#else // #ifdef TRACE_ENABLED
|
|
|
|
return FALSE;
|
|
|
|
#endif // #ifdef TRACE_ENABLED
|
|
}
|
|
|
|
|
|
BOOL
|
|
TDebugExt::
|
|
bDumpDebugTrace(
|
|
ULONG_PTR dwLineAddr,
|
|
COUNT Count,
|
|
PDWORD pdwSkip,
|
|
DWORD DebugTrace,
|
|
DWORD DebugLevel,
|
|
DWORD dwThreadId,
|
|
ULONG_PTR dwMem
|
|
)
|
|
{
|
|
//
|
|
// TLine is a simple class, and can be treated as a "C" struct.
|
|
//
|
|
COUNTB cbTotalLine = sizeof( TBackTraceMem::TLine ) * Count;
|
|
TBackTraceMem::TLine* pLineBase =
|
|
(TBackTraceMem::TLine*) LocalAlloc( LPTR, cbTotalLine );
|
|
BOOL bValidLines = TRUE;
|
|
|
|
TBackTraceMem::TLine* pLine;
|
|
|
|
if( !pLineBase ){
|
|
|
|
Print( "Cannot alloc 0x%x bytes.\n", cbTotalLine );
|
|
return FALSE;
|
|
}
|
|
|
|
move2( pLineBase, dwLineAddr, cbTotalLine );
|
|
|
|
//
|
|
// Dump out the lines.
|
|
//
|
|
for( pLine = pLineBase ; Count; Count--, pLine++ ){
|
|
|
|
if( CheckControlCRtn()){
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// If we are out of lines, quit.
|
|
//
|
|
if( !pLine->_TickCount ){
|
|
bValidLines = FALSE;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// If we are processing DBGMSG, skip levels we don't want.
|
|
//
|
|
if( DebugTrace & DEBUG_TRACE_DBGMSG ){
|
|
if( !( DebugLevel & ( pLine->_Info2 >> DBG_BREAK_SHIFT ))){
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Skip thread Ids we don't want.
|
|
//
|
|
if( dwThreadId && dwThreadId != pLine->_ThreadId ){
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Skip mem we don't want.
|
|
// This is used when we are dumping the memory functions in
|
|
// spllib (gpbtAlloc and gpbtFree).
|
|
//
|
|
if( dwMem &&
|
|
( dwMem < pLine->_Info1 ||
|
|
dwMem > pLine->_Info1 + pLine->_Info2 )){
|
|
|
|
continue;
|
|
}
|
|
|
|
if( *pdwSkip ){
|
|
--*pdwSkip;
|
|
continue;
|
|
}
|
|
|
|
if( DebugTrace & DEBUG_TRACE_DBGMSG ){
|
|
|
|
CHAR szMsg[kStringDefaultMax];
|
|
|
|
szMsg[0] = 0;
|
|
|
|
if( pLine->_Info1 ){
|
|
|
|
move( szMsg, pLine->_Info1 );
|
|
|
|
//
|
|
// PageHeap forces all allocated blocks to be placed
|
|
// at the end of a page, with the next page marked
|
|
// as unreadable. If we don't get a string here,
|
|
// then read up chunk.
|
|
//
|
|
if( !szMsg[0] ){
|
|
|
|
move2( szMsg,
|
|
pLine->_Info1,
|
|
kStringChunk -
|
|
( (DWORD)pLine->_Info1 & ( kStringChunk - 1 )));
|
|
}
|
|
|
|
Print( "* %s", szMsg );
|
|
|
|
UINT cchLen = lstrlenA( szMsg );
|
|
|
|
if( !cchLen || szMsg[cchLen-1] != '\n' ){
|
|
|
|
Print( "\n" );
|
|
}
|
|
} else {
|
|
Print( "\n" );
|
|
}
|
|
}
|
|
|
|
if( DebugTrace & DEBUG_TRACE_HEX ){
|
|
Print( "%08x %08x %08x bt=%x threadid=%x tc=%x [%x]\n",
|
|
pLine->_Info1,
|
|
pLine->_Info2,
|
|
pLine->_Info3,
|
|
pLine->_hTrace,
|
|
pLine->_ThreadId,
|
|
pLine->_TickCount,
|
|
pLine->_Info1 + pLine->_Info2 );
|
|
}
|
|
|
|
if( DebugTrace & DEBUG_TRACE_BT ){
|
|
vDumpTrace( (ULONG_PTR)pLine->_hTrace );
|
|
}
|
|
}
|
|
|
|
Done:
|
|
|
|
LocalFree( pLineBase );
|
|
return bValidLines;
|
|
}
|
|
|
|
BOOL
|
|
TDebugExt::
|
|
bDumpDbgPointers(
|
|
PVOID pDbgPointers_,
|
|
ULONG_PTR dwAddress
|
|
)
|
|
{
|
|
PDBG_POINTERS pDbgPointers = (PDBG_POINTERS)pDbgPointers_;
|
|
|
|
Print( "DBG_POINTERS*\n" );
|
|
|
|
Print( "hMemHeap !heap -a %x\n", pDbgPointers->hMemHeap );
|
|
Print( "hDbgMemHeap !heap -a %x\n", pDbgPointers->hDbgMemHeap );
|
|
Print( "pbtAlloc !splx.ddt -x %x\n", pDbgPointers->pbtAlloc );
|
|
Print( "pbtFree !splx.ddt -x %x\n", pDbgPointers->pbtFree );
|
|
Print( "pbtErrLog !splx.ddt %x\n", pDbgPointers->pbtErrLog );
|
|
Print( "pbtTraceLog !splx.ddt %x\n", pDbgPointers->pbtTraceLog );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/********************************************************************
|
|
|
|
Extension entrypoints.
|
|
|
|
********************************************************************/
|
|
|
|
DEBUG_EXT_ENTRY( dthdm, TThreadM, bDumpThreadM, NULL, FALSE )
|
|
DEBUG_EXT_ENTRY( dcs, MCritSec, bDumpCritSec, NULL, FALSE )
|
|
|
|
DEBUG_EXT_ENTRY( ddp, DBG_POINTERS, bDumpDbgPointers, "&gpDbgPointers", FALSE )
|
|
|
|
DEBUG_EXT_HEAD(dbt)
|
|
{
|
|
DEBUG_EXT_SETUP_VARS();
|
|
TDebugExt::vDumpTrace( TDebugExt::dwEval( lpArgumentString, FALSE ));
|
|
}
|
|
|
|
DEBUG_EXT_HEAD(ddt)
|
|
{
|
|
DEBUG_EXT_SETUP_VARS();
|
|
|
|
vDumpTraceWithFlags( lpArgumentString, 0 );
|
|
}
|
|
|
|
DEBUG_EXT_HEAD(dmem)
|
|
{
|
|
DEBUG_EXT_SETUP_VARS();
|
|
TDebugExt::vDumpMem( lpArgumentString );
|
|
}
|
|
|
|
|
|
/********************************************************************
|
|
|
|
Helper funcs.
|
|
|
|
********************************************************************/
|
|
|
|
VOID
|
|
vDumpTraceWithFlags(
|
|
LPSTR lpArgumentString,
|
|
ULONG_PTR dwAddress
|
|
)
|
|
{
|
|
COUNT Count = 10;
|
|
BOOL bRaw = FALSE;
|
|
DWORD DebugTrace = DEBUG_TRACE_NONE;
|
|
DWORD DebugLevel = (DWORD)-1;
|
|
DWORD dwThreadId = 0;
|
|
DWORD dwSkip = 0;
|
|
ULONG_PTR dwMem = 0;
|
|
|
|
for( ; *lpArgumentString; ++lpArgumentString ){
|
|
|
|
while( *lpArgumentString == ' ' ){
|
|
++lpArgumentString;
|
|
}
|
|
|
|
if (*lpArgumentString != '-') {
|
|
break;
|
|
}
|
|
|
|
++lpArgumentString;
|
|
|
|
switch( *lpArgumentString++ ){
|
|
case 'T':
|
|
case 't':
|
|
|
|
dwThreadId = (DWORD)TDebugExt::dwEvalParam( lpArgumentString );
|
|
break;
|
|
|
|
case 'L':
|
|
case 'l':
|
|
|
|
DebugLevel = (DWORD)TDebugExt::dwEvalParam( lpArgumentString );
|
|
break;
|
|
|
|
case 'C':
|
|
case 'c':
|
|
|
|
Count = (COUNT)TDebugExt::dwEvalParam( lpArgumentString );
|
|
break;
|
|
|
|
case 'M':
|
|
case 'm':
|
|
|
|
dwMem = TDebugExt::dwEvalParam( lpArgumentString );
|
|
break;
|
|
|
|
case 'R':
|
|
case 'r':
|
|
|
|
bRaw = TRUE;
|
|
break;
|
|
|
|
case 'b':
|
|
case 'B':
|
|
|
|
DebugTrace |= DEBUG_TRACE_BT;
|
|
break;
|
|
|
|
case 'X':
|
|
case 'x':
|
|
|
|
DebugTrace |= DEBUG_TRACE_HEX;
|
|
break;
|
|
|
|
case 'd':
|
|
case 'D':
|
|
|
|
DebugTrace |= DEBUG_TRACE_DBGMSG;
|
|
break;
|
|
|
|
case 's':
|
|
case 'S':
|
|
|
|
dwSkip = (DWORD)TDebugExt::dwEvalParam( lpArgumentString );
|
|
break;
|
|
|
|
default:
|
|
Print( "Unknown option %c.\n", lpArgumentString[-1] );
|
|
return;
|
|
}
|
|
}
|
|
|
|
if( !dwAddress ){
|
|
dwAddress = TDebugExt::dwEval( lpArgumentString );
|
|
}
|
|
|
|
if( bRaw ){
|
|
TDebugExt::bDumpDebugTrace( dwAddress,
|
|
Count,
|
|
&dwSkip,
|
|
DebugTrace,
|
|
DebugLevel,
|
|
dwThreadId,
|
|
dwMem );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If nothing is set, default to dbg msgs.
|
|
//
|
|
if( !DebugTrace ){
|
|
DebugTrace |= DEBUG_TRACE_DBGMSG;
|
|
}
|
|
|
|
if( !TDebugExt::bDumpBackTrace( dwAddress,
|
|
Count,
|
|
&dwSkip,
|
|
DebugTrace,
|
|
DebugLevel,
|
|
dwThreadId,
|
|
dwMem )){
|
|
Print( "Unknown Signature\n" );
|
|
}
|
|
}
|
|
|