diff -r 000000000000 -r f0f2b8682603 memana/analyzetoolclient/commandlineengine/internal/src/catdbghelper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/memana/analyzetoolclient/commandlineengine/internal/src/catdbghelper.cpp Thu Feb 11 15:51:35 2010 +0200 @@ -0,0 +1,314 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Windows debug api implementation for IAddressToLine interface. +* +*/ + +#include "../inc/catdbghelper.h" +#include "../inc/CATBase.h" +#include "../inc/CATMemoryAddress.h" +#include + +/** +* Notes on version number of api functions. +* 5.1 Windows XP +* 5.2 Windows Server 2003 +* 6.8 Debugging Tools for Windows 6.8 +* SymSetOptions DbgHelp.dll 5.1 or later +* SymSetSearchPath DbgHelp.dll 5.1 or later +* SymLoadModuleEx Versions 5.2 and 6.0 +* SymLoadModule64 DbgHelp.dll 5.1 or later +* SymFromAddr Versions 4.0 and 5.1 +* SymGetLineFromAddr64 DbgHelp.dll 5.1 or later +*/ + +// Wrapper class for symbol information package. +struct CSymbolInfo : public SYMBOL_INFO_PACKAGE +{ + CSymbolInfo() + { + si.SizeOfStruct = sizeof( SYMBOL_INFO ); + si.MaxNameLen = sizeof( name ); + } +}; + +// Wrapper class for line information container. +struct CLineInfo : public IMAGEHLP_LINE64 +{ + CLineInfo() + { + SizeOfStruct = sizeof( IMAGEHLP_LINE64 ); + } +}; + +CATDbgHelper::CATDbgHelper() +{ + LOG_FUNC_ENTRY("CATDbgHelper::CDbgHelper"); + // Set the some "default" base address. + m_BaseAddress = 0x2; + m_bMap = false; + m_pBinaryFile = NULL; +} + +CATDbgHelper::~CATDbgHelper() +{ + LOG_FUNC_ENTRY("CATDbgHelper::~CDbgHelper"); + // Close dbghelper only once. + if ( CDBGHELPER_OPEN ) + { + Close(); + } + if ( m_pBinaryFile ) + { + delete[] m_pBinaryFile; + m_pBinaryFile = NULL; + } +} + +bool CATDbgHelper::Open( const string& sParameter, const unsigned long iLong ) +{ + LOG_FUNC_ENTRY("CATDbgHelper::Open"); + // Verify that file exits. Version 5.1.2600.5512 of dbghelp.dll does not correctly + // return error code if missing image file. This can lead upto applicaton crash. + if ( ! CATBase::FileExists( sParameter.c_str() ) ) + { + LOG_STRING( "Missing image file: " << sParameter ); + return false; + } + + // Is it urel try read map? + if ( sParameter.find( "\\urel\\" ) != string::npos ) + { + string sMapFile = sParameter; + sMapFile.append( ".map" ); + ReadMapFile( sMapFile ); + } + + // Set base address used + m_BaseAddress = iLong + AT_VIRTUAL_OFFSET_DBGHELPER; + // Binary file (also referred as symbol). + size_t length = sParameter.length(); + if ( length == 0 ) + { + LOG_STRING("DbgHelp:Invalid binary parameter."); + return false; + } + + char* pChar = new char[ sParameter.length()+1 ]; + strcpy( pChar, sParameter.c_str() ); + // Have to be casted to PSTR before using dbg api. Even tho its typedef same. + // This will avoid access violations bug. + // Note pChar is not deleted because its the member pointer just casted its + // memory allocation freed in destructor. + if ( m_pBinaryFile ) + delete[] m_pBinaryFile; + + m_pBinaryFile = (PSTR) pChar; + + // Initialize dbghelper if not done only once. + if ( ! CDBGHELPER_OPEN ) + { + // Set symbol options + SymSetOptions( SYMOPT_LOAD_LINES | SYMOPT_DEBUG | SYMOPT_UNDNAME | SYMOPT_LOAD_ANYTHING ); + if ( !SymInitialize( GetCurrentProcess(), NULL, TRUE ) ) + { + LOG_STRING("DbgHelp:Error initializing dbghelper " << (int) GetLastError()); + return false; + } + LOG_STRING("DbgHelp:dbghelper opened."); + CDBGHELPER_OPEN = true; + } + + // Set symbol search path. + if ( !SymSetSearchPath( GetCurrentProcess(), NULL ) ) + { + LOG_STRING("DbgHelp:Error setting symbol search path " << (int) GetLastError()); + return false; + } + + // Load module. + DWORD64 ret; + ret = SymLoadModule64( GetCurrentProcess(), NULL, m_pBinaryFile, NULL, m_BaseAddress, NULL ); // 5.1 api version. + if ( ret != m_BaseAddress && ret != 0) + { + LOG_STRING("Dbghelp:Module load failed " << (int) GetLastError()); + return false; + } + CDBGHELPER_CLIENTS++; + return true; +} + +string CATDbgHelper::GetError( void ) +{ + LOG_FUNC_ENTRY("CATDbgHelper::GetError"); + return string("not implemented."); +} + +bool CATDbgHelper::Close( void ) +{ + LOG_FUNC_ENTRY("CATDbgHelper::Close"); + if ( ! SymUnloadModule64( GetCurrentProcess(), m_BaseAddress ) ) + { + LOG_STRING("Dbghelp:Module unload failed."); + } + CDBGHELPER_CLIENTS--; + if ( CDBGHELPER_OPEN && CDBGHELPER_CLIENTS == 0) + { + // Cleanup dbghelper. + if ( ! SymCleanup( GetCurrentProcess() ) ) + { + LOG_STRING("dbghelper cleanup failed."); + return false; + } + LOG_STRING("dbghelper closed."); + // Set state not opened. + CDBGHELPER_OPEN = false; + } + return true; +} + +bool CATDbgHelper::AddressToLine( CATMemoryAddress* result ) +{ + LOG_FUNC_ENTRY("CATDbgHelper::AddressToLine"); + + // Set state out of range + result->SetAddressToLineState( CATMemoryAddress::OUT_OF_RANGE ); + + // check that dbghelper has been initialized successfully. + if ( ! CDBGHELPER_OPEN ) + return false; + + // Check has binary been moved, if so unload and load to new base address. + if ( result->GetModuleStartAddress() + AT_VIRTUAL_OFFSET_DBGHELPER != m_BaseAddress ) + { + // Unload. + if ( SymUnloadModule64( GetCurrentProcess(), m_BaseAddress ) ) + { + // Set new base address. + m_BaseAddress = result->GetModuleStartAddress() + AT_VIRTUAL_OFFSET_DBGHELPER; + // (Re)load. + DWORD64 loading = SymLoadModule64( GetCurrentProcess(), NULL, m_pBinaryFile, NULL, m_BaseAddress, NULL ); + if ( loading != m_BaseAddress && loading != 0) + { + LOG_STRING("Dbghelp:Module load failed " << (int) GetLastError()); + return false; + } + } + else + LOG_STRING("Dbghelp:Module unload failed " << (int) GetLastError() ); + } + // Address to find (offset+given address). + unsigned long iAddressToFind = result->GetAddress() + AT_VIRTUAL_OFFSET_DBGHELPER; + // Displacements of line/symbol information. + DWORD64 displacementSymbol; + DWORD displacementLine; + // Structure to get symbol information. + CSymbolInfo symbol; + // Structure to get line information. + CLineInfo line; + // Find Symbol for given address + if( ! SymFromAddr( GetCurrentProcess(), iAddressToFind , &displacementSymbol, &symbol.si ) ) + { + LOG_STRING("Failed to find symbol information for given line."); + return AddressToFunction( result ); + } + // Find line information + if( ! SymGetLineFromAddr64( GetCurrentProcess(), iAddressToFind, &displacementLine, &line ) ) + { + // If it fails get symbol line information + LOG_STRING("Dbghelp:Failed to find line information for address, trying for symbol of address."); + if( ! SymGetLineFromAddr64( GetCurrentProcess(), symbol.si.Address, &displacementLine, &line ) ) + { + LOG_STRING("Dbghelp:Failed to find line information for symbol address."); + return AddressToFunction( result ); + } + } + // Set the results. + result->SetFileName( string( line.FileName ) ); + result->SetFunctionName( string( symbol.si.Name ) ); + result->SetExactLineNumber( (int) line.LineNumber ); + result->SetAddressToLineState( CATMemoryAddress::EXACT ); + // Return. + return true; +} + +bool CATDbgHelper::AddressToFunction( CATMemoryAddress* result ) +{ + LOG_FUNC_ENTRY("CATDbgHelper::AddressToFunction"); + bool bFound = false; + // If map file read use it and return. + if ( m_bMap ) + { + ULONG uCountedA = result->GetOffSetFromModuleStart(); + for ( vector::iterator it = m_vMapFileFuncList.begin() ; it != m_vMapFileFuncList.end() ; it++ ) + { + // Check is this the symbol where address is. + unsigned long iStart = it->iAddress; + unsigned long iEnd = it->iAddress + it->iFuncLength; + if ( uCountedA >= iStart + && uCountedA < iEnd ) + { + result->SetAddressToLineState( CATMemoryAddress::SYMBOL ); + result->SetFunctionName( it->sMangledName ); + bFound = true; + break; + } + } + } + return bFound; +} + +void CATDbgHelper::ReadMapFile( const string sMapFileName ) +{ + LOG_FUNC_ENTRY("CATDbgHelper::ReadMapFile"); + try { + ifstream in( sMapFileName.c_str() ); + if ( ! in.good() ) + { + in.close(); + return; + } + char cLine[MAX_LINE_LENGTH]; + do { + in.getline( cLine, MAX_LINE_LENGTH ); + // Search pattern for 'image ro' symbols is ".text" + string sLine( cLine ); + if ( sLine.find( ".text" ) != string::npos ) + { + MAP_FUNC_INFO symbol; + // Pickup symbol attributes + // Address + string sAddress = CATBase::GetStringUntilNextSpace( sLine, true ); + symbol.iAddress = CATBase::_httoi( sAddress.c_str() ); + // Lenght + string sLength = CATBase::GetStringUntilNextSpace( sLine, true ); + symbol.iFuncLength = CATBase::_httoi( sLength.c_str() ); + // Name + size_t iStart = sLine.find_first_of( '(' ); + size_t iEnd = sLine.find_last_of( ')' ); + if ( iStart != string::npos && iEnd != string::npos ) + { + symbol.sMangledName = sLine.substr( iStart+1, iEnd-iStart-1 ); + // Add symbol to vector + m_vMapFileFuncList.push_back( symbol ); + } + } + } while ( in.good() ); + in.close(); + m_bMap = true; + } catch (...) { + m_bMap = false; + LOG_STRING("DbgHelp: Error reading map file."); + } +} \ No newline at end of file