/*++ Copyright (c) 1998-1999 Microsoft Corporation All rights reserved. Module Name: dbgback.cxx Abstract: Debug Imagehlp Author: Steve Kiraly (SteveKi) 17-May-1998 Revision History: --*/ #include "precomp.hxx" #pragma hdrstop #include "dbgloadl.hxx" #include "dbgimage.hxx" #include // // Initialize the imagehlp library. // TDebugImagehlp:: TDebugImagehlp( VOID ) : _ImageHlp( TEXT("ImageHlp.dll") ), _bValid( FALSE ), _pfSymGetModuleInfo( NULL ), _pfSymFunctionTableAccess( NULL ), _pfSymGetModuleBase( NULL ), _pfStackWalk( NULL ), _pfSymInitialize( NULL ), _pfSymSetOptions( NULL ), _pfSymGetSymFromAddr( NULL ), _pfSymUnDName( NULL ) { if( _ImageHlp.bValid() ) { _pfSymGetModuleInfo = (pfSymGetModuleInfo) _ImageHlp.pfnGetProc( "SymGetModuleInfo" ); _pfStackWalk = (pfStackWalk) _ImageHlp.pfnGetProc( "StackWalk" ); _pfSymSetOptions = (pfSymSetOptions) _ImageHlp.pfnGetProc( "SymSetOptions" ); _pfSymInitialize = (pfSymInitialize) _ImageHlp.pfnGetProc( "SymInitialize" ); _pfSymFunctionTableAccess = (pfSymFunctionTableAccess)_ImageHlp.pfnGetProc( "SymFunctionTableAccess" ); _pfSymGetModuleBase = (pfSymGetModuleBase) _ImageHlp.pfnGetProc( "SymGetModuleBase" ); _pfSymGetSymFromAddr = (pfSymGetSymFromAddr) _ImageHlp.pfnGetProc( "SymGetSymFromAddr" ); _pfSymUnDName = (pfSymUnDName) _ImageHlp.pfnGetProc( "SymUnDName" ); _pfSymGetSearchPath = (pfSymGetSearchPath) _ImageHlp.pfnGetProc( "SymGetSearchPath" ); _pfSymSetSearchPath = (pfSymSetSearchPath) _ImageHlp.pfnGetProc( "SymSetSearchPath" ); if( _pfSymGetModuleInfo && _pfStackWalk && _pfSymSetOptions && _pfSymInitialize && _pfSymFunctionTableAccess && _pfSymGetModuleBase && _pfSymGetSymFromAddr && _pfSymUnDName ) { _pfSymSetOptions( SYMOPT_DEFERRED_LOADS ); _pfSymInitialize( GetCurrentProcess(), NULL, TRUE ); _bValid = TRUE; #ifndef UNICODE _pszSymbolFormatSpecifier = _T("%08lx %s!%s+0x%x\n"); #else _pszSymbolFormatSpecifier = _T("%08lx %S!%S+0x%x\n"); #endif } } } // // Destroy the imagehlp library. // TDebugImagehlp:: ~TDebugImagehlp( VOID ) { } // // Return the object state. // BOOL TDebugImagehlp:: bValid( VOID ) { return _bValid; } // // Capture the current backtrace. // BOOL TDebugImagehlp:: bCaptureBacktrace( IN UINT nSkip, IN ULONG nTotal, OUT VOID **apvBacktrace, OUT ULONG *puCount ) { HANDLE hThread = NULL; CONTEXT context = {0}; hThread = GetCurrentThread(); context.ContextFlags = CONTEXT_FULL; if (GetThreadContext(hThread, &context)) { STACKFRAME stkfrm = {0}; DWORD dwMachType = 0; stkfrm.AddrPC.Mode = AddrModeFlat; #if defined(_M_IX86) dwMachType = IMAGE_FILE_MACHINE_I386; stkfrm.AddrPC.Offset = context.Eip; // Program Counter stkfrm.AddrStack.Offset = context.Esp; // Stack Pointer stkfrm.AddrStack.Mode = AddrModeFlat; // Stack address mode stkfrm.AddrFrame.Offset = context.Ebp; // Frame Pointer stkfrm.AddrFrame.Mode = AddrModeFlat; // Frame address mode #elif defined(_M_MRX000) dwMachType = IMAGE_FILE_MACHINE_R4000; stkfrm.AddrPC.Offset = context.Fir; // Program Counter #elif defined(_M_ALPHA) dwMachType = IMAGE_FILE_MACHINE_ALPHA; stkfrm.AddrPC.Offset = (ULONG) context.Fir; // Program Counter #elif defined(_M_PPC) dwMachType = IMAGE_FILE_MACHINE_POWERPC; stkfrm.AddrPC.Offset = context.Iar; // Program Counter #elif defined(_M_IA64) dwMachType = IMAGE_FILE_MACHINE_IA64; stkfrm.AddrPC.Offset = context.StIIP; #else #error("Unknown Target Machine"); #endif // // Clear the valid entry count. // *puCount = 0; // // Walk the stack saving the addresses. // for( UINT i = 0; i < nSkip + nTotal; i++ ) { if( !_pfStackWalk( dwMachType, GetCurrentProcess(), GetCurrentProcess(), &stkfrm, &context, NULL, _pfSymFunctionTableAccess, _pfSymGetModuleBase, NULL )) { break; } if (i >= nSkip) { if( stkfrm.AddrPC.Offset ) { apvBacktrace[(*puCount)++] = (VOID *)stkfrm.AddrPC.Offset; } } } } return *puCount > 0; } // // Resolve the specified address to a human readable symbol. // BOOL TDebugImagehlp:: ResolveAddressToSymbol( IN PVOID pvAddress, IN LPTSTR pszName, IN UINT cchNameLength, IN EDecoration eDecorateType ) { IMAGEHLP_MODULE mod = {0}; DWORD dwDisplacement = 0; INT iLen = 0; UINT_PTR Address = (UINT_PTR)pvAddress; LPCSTR pszSymbolName = NULL; CHAR szUnDDump[kMaxSymbolNameLength]; CHAR dump[sizeof(IMAGEHLP_SYMBOL) + kMaxSymbolNameLength]; PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)&dump; // // Fetch the module name // mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE); _pfSymGetModuleInfo(GetCurrentProcess(), Address, &mod); // // Have to do this because size of sym is dynamically determined // pSym->SizeOfStruct = sizeof(dump); pSym->MaxNameLength = kMaxSymbolNameLength; // // Fetch the symbol // if (_pfSymGetSymFromAddr(GetCurrentProcess(), Address, &dwDisplacement, pSym)) { // // Assume the caller wants a decorated symbol name. // pszSymbolName = pSym->Name; if( eDecorateType == kUnDecorateName ) { // // Get the undecorated name for this symbol. // if( _pfSymUnDName( pSym, szUnDDump, sizeof( szUnDDump ) ) ) { pszSymbolName = szUnDDump; } } } // // Format the symbol name. // iLen = _sntprintf( pszName, cchNameLength, _pszSymbolFormatSpecifier, Address, mod.ModuleName, pszSymbolName, dwDisplacement ); return iLen > 0; } // // Get the current symbol search path for this process // BOOL TDebugImagehlp:: GetSymbolPath( IN TDebugString &strSearchPath ) const { BOOL bRetval = FALSE; CHAR szNarowSearchPath[MAX_PATH]; LPTSTR pszSearchPath; bRetval = _pfSymGetSearchPath( GetCurrentProcess(), szNarowSearchPath, COUNTOF( szNarowSearchPath ) ); if( bRetval ) { bRetval = StringA2T( &pszSearchPath, szNarowSearchPath ); if( bRetval ) { bRetval = strSearchPath.bUpdate( pszSearchPath ); INTERNAL_DELETE [] pszSearchPath; } } return bRetval; } // // Set the current symbol search path for this process // BOOL TDebugImagehlp:: SetSymbolPath( IN LPCTSTR pszSearchPath ) { BOOL bRetval = FALSE; LPSTR pszNarrowSearchPath = NULL; bRetval = StringT2A( &pszNarrowSearchPath, pszSearchPath ); if( bRetval ) { bRetval = _pfSymSetSearchPath( GetCurrentProcess(), pszNarrowSearchPath ); INTERNAL_DELETE [] pszNarrowSearchPath; } return bRetval; }