363 lines
7.8 KiB
C++
363 lines
7.8 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1998-1999 Microsoft Corporation
|
||
|
All rights reserved.
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
dbgback.cxx
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Debug Backtrace Device
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Steve Kiraly (SteveKi) 16-May-1998
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
#include "precomp.hxx"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include "dbgloadl.hxx"
|
||
|
#include "dbgimage.hxx"
|
||
|
#include "dbgback.hxx"
|
||
|
#include "dbgreg.hxx"
|
||
|
|
||
|
//
|
||
|
// Construct the backtrace device.
|
||
|
//
|
||
|
TDebugDeviceBacktrace::
|
||
|
TDebugDeviceBacktrace(
|
||
|
IN LPCTSTR pszConfiguration,
|
||
|
IN EDebugType eDebugType
|
||
|
) : TDebugDevice( pszConfiguration, eDebugType ),
|
||
|
_pDbgImagehlp( NULL ),
|
||
|
_bValid( FALSE ),
|
||
|
_pDbgDevice( NULL ),
|
||
|
_bDisplaySymbols( FALSE )
|
||
|
{
|
||
|
//
|
||
|
// Collect andy device arguments.
|
||
|
//
|
||
|
CollectDeviceArguments();
|
||
|
|
||
|
//
|
||
|
// Create the debug imagehlp object.
|
||
|
//
|
||
|
_pDbgImagehlp = INTERNAL_NEW TDebugImagehlp;
|
||
|
|
||
|
//
|
||
|
// Set the valid flag.
|
||
|
//
|
||
|
_bValid = _pDbgImagehlp && _pDbgImagehlp->bValid();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Close the backtrace device.
|
||
|
//
|
||
|
TDebugDeviceBacktrace::
|
||
|
~TDebugDeviceBacktrace(
|
||
|
)
|
||
|
{
|
||
|
INTERNAL_DELETE _pDbgImagehlp;
|
||
|
INTERNAL_DELETE _pDbgDevice;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Indicates the deveice object is valid.
|
||
|
//
|
||
|
BOOL
|
||
|
TDebugDeviceBacktrace::
|
||
|
bValid(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
return _bValid;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Output the string to the backtrace device
|
||
|
//
|
||
|
BOOL
|
||
|
TDebugDeviceBacktrace::
|
||
|
bOutput(
|
||
|
IN UINT uSize,
|
||
|
IN LPBYTE pBuffer
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// Is the class in a good state and we have an output device.
|
||
|
//
|
||
|
BOOL bRetval = bValid() && _pDbgDevice;
|
||
|
|
||
|
if( bRetval )
|
||
|
{
|
||
|
//
|
||
|
// Send the string to the output device.
|
||
|
//
|
||
|
bRetval = _pDbgDevice->bOutput( uSize, pBuffer );
|
||
|
|
||
|
if( bRetval )
|
||
|
{
|
||
|
PVOID apvBacktrace[kMaxDepth];
|
||
|
ULONG uCount = 0;
|
||
|
|
||
|
memset( apvBacktrace, 0, sizeof( apvBacktrace ) );
|
||
|
|
||
|
//
|
||
|
// Capture the current backtrace skiping the call stack of this class
|
||
|
//
|
||
|
bRetval = _pDbgImagehlp->bCaptureBacktrace( 3, kMaxDepth, apvBacktrace, &uCount );
|
||
|
|
||
|
if( bRetval )
|
||
|
{
|
||
|
//
|
||
|
// Send the backtrace to the output device.
|
||
|
//
|
||
|
bRetval = OutputBacktrace( uCount, apvBacktrace );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return bRetval;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Send the backtrace to the output device.
|
||
|
//
|
||
|
BOOL
|
||
|
TDebugDeviceBacktrace::
|
||
|
OutputBacktrace(
|
||
|
IN UINT uCount,
|
||
|
IN PVOID *apvBacktrace
|
||
|
)
|
||
|
{
|
||
|
TCHAR szBuffer [kMaxSymbolName];
|
||
|
BOOL bRetval = FALSE;
|
||
|
LPCTSTR pszFmt = NULL;
|
||
|
|
||
|
for( UINT i = 0; i < uCount && apvBacktrace[i]; i++ )
|
||
|
{
|
||
|
if( _bDisplaySymbols )
|
||
|
{
|
||
|
bRetval = _pDbgImagehlp->ResolveAddressToSymbol( apvBacktrace[i],
|
||
|
szBuffer,
|
||
|
COUNTOF( szBuffer ),
|
||
|
TDebugImagehlp::kUnDecorateName );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( i == 0 )
|
||
|
{
|
||
|
pszFmt = kstrBacktraceStart;
|
||
|
}
|
||
|
else if( !apvBacktrace[i+1] )
|
||
|
{
|
||
|
pszFmt = kstrBacktraceEnd;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pszFmt = kstrBacktraceMiddle;
|
||
|
}
|
||
|
|
||
|
bRetval = _sntprintf( szBuffer, COUNTOF(szBuffer), pszFmt, apvBacktrace[i] ) > 0;
|
||
|
}
|
||
|
|
||
|
if( bRetval )
|
||
|
{
|
||
|
bRetval = _pDbgDevice->bOutput( _tcslen( szBuffer ) * sizeof(TCHAR),
|
||
|
reinterpret_cast<LPBYTE>( szBuffer ) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bRetval;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Initialize the specified symbol path.
|
||
|
//
|
||
|
VOID
|
||
|
TDebugDeviceBacktrace::
|
||
|
InitSympath(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
if( _bDisplaySymbols )
|
||
|
{
|
||
|
TDebugString strRegistryPath;
|
||
|
|
||
|
//
|
||
|
// Get the base registry path.
|
||
|
//
|
||
|
BOOL bRetval = strRegistryPath.bUpdate( kstrSympathRegistryPath );
|
||
|
|
||
|
if( bRetval )
|
||
|
{
|
||
|
TDebugString strProcessName;
|
||
|
|
||
|
//
|
||
|
// Get this processes short name.
|
||
|
//
|
||
|
bRetval = GetProcessName( strProcessName );
|
||
|
|
||
|
if( bRetval )
|
||
|
{
|
||
|
//
|
||
|
// Build the registry path Path\processname
|
||
|
//
|
||
|
bRetval = strRegistryPath.bCat( kstrSlash ) && strRegistryPath.bCat( strProcessName );
|
||
|
|
||
|
if( bRetval )
|
||
|
{
|
||
|
//
|
||
|
// Open the registry key.
|
||
|
//
|
||
|
TDebugRegistry Registry( strRegistryPath, TDebugRegistry::kOpen|TDebugRegistry::kRead, HKEY_LOCAL_MACHINE );
|
||
|
|
||
|
bRetval = Registry.bValid();
|
||
|
|
||
|
if( bRetval )
|
||
|
{
|
||
|
//
|
||
|
// Read the symbol path if there.
|
||
|
//
|
||
|
bRetval = Registry.bRead( kstrSympathRegistryKey, _strSympath );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If the registry did not specifiy a symbol path then use the
|
||
|
// default symbol path that imagehlp has.
|
||
|
//
|
||
|
if( !bRetval )
|
||
|
{
|
||
|
_pDbgImagehlp->GetSymbolPath( _strSympath );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Set the symbol path
|
||
|
//
|
||
|
_pDbgImagehlp->SetSymbolPath( _strSympath );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If we are displaying symbols then as the first line in the output
|
||
|
// device indicate the symbol path.
|
||
|
//
|
||
|
VOID
|
||
|
TDebugDeviceBacktrace::
|
||
|
WriteSympathToOutputDevice(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
if( _bDisplaySymbols )
|
||
|
{
|
||
|
TDebugString strSympath;
|
||
|
|
||
|
strSympath.bFormat(kstrSympathFormat, _strSympath);
|
||
|
|
||
|
_pDbgDevice->bOutput(strSympath.uLen() * sizeof(TCHAR),
|
||
|
reinterpret_cast<LPBYTE>(
|
||
|
const_cast<LPTSTR>(
|
||
|
static_cast<LPCTSTR>(
|
||
|
strSympath))));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create and the set the output device type.
|
||
|
//
|
||
|
BOOL
|
||
|
TDebugDeviceBacktrace::
|
||
|
InitializeOutputDevice(
|
||
|
IN UINT uDevice,
|
||
|
IN LPCTSTR pszConfiguration,
|
||
|
IN UINT uCharacterType
|
||
|
)
|
||
|
{
|
||
|
if( bValid() )
|
||
|
{
|
||
|
//
|
||
|
// Get access to the debug factory.
|
||
|
//
|
||
|
TDebugFactory DebugFactory;
|
||
|
|
||
|
//
|
||
|
// If we failed to create the debug factory then exit.
|
||
|
//
|
||
|
if (DebugFactory.bValid())
|
||
|
{
|
||
|
//
|
||
|
// Release the existing debug device.
|
||
|
//
|
||
|
delete _pDbgDevice;
|
||
|
|
||
|
//
|
||
|
// Create the specified debug device using the factory.
|
||
|
//
|
||
|
_pDbgDevice = DebugFactory.Produce( uDevice, pszConfiguration, uCharacterType );
|
||
|
|
||
|
//
|
||
|
// If the debug device was created successfully.
|
||
|
//
|
||
|
if( _pDbgDevice )
|
||
|
{
|
||
|
//
|
||
|
// Initialize the sympath
|
||
|
//
|
||
|
InitSympath();
|
||
|
|
||
|
//
|
||
|
// Write sympath to output device.
|
||
|
//
|
||
|
WriteSympathToOutputDevice();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Indicate the debug device was created.
|
||
|
//
|
||
|
return _pDbgDevice != NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Get the device arguments from the configuration string.
|
||
|
//
|
||
|
BOOL
|
||
|
TDebugDeviceBacktrace::
|
||
|
CollectDeviceArguments(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
TDebugDevice::TIterator i( this );
|
||
|
|
||
|
for( i.First(); !i.IsDone(); i.Next() )
|
||
|
{
|
||
|
switch( i.Index() )
|
||
|
{
|
||
|
//
|
||
|
// Ignore the character type.
|
||
|
//
|
||
|
case 1:
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
// The second aregument is the symbol specifier.
|
||
|
//
|
||
|
case 2:
|
||
|
_bDisplaySymbols = !_tcsicmp( kstrSymbols, i.Current() );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|