/*++ 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( 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( const_cast( static_cast( 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; }