memana/analyzetoolclient/commandlineengine/internal/src/catdbghelper.cpp
changeset 2 6a82cd05fb1e
parent 1 3ff3fecb12fe
equal deleted inserted replaced
1:3ff3fecb12fe 2:6a82cd05fb1e
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Windows debug api implementation for IAddressToLine interface.
       
    15 *
       
    16 */
       
    17 
       
    18 #include "../inc/catdbghelper.h"
       
    19 #include "../inc/CATBase.h"
       
    20 #include "../inc/CATMemoryAddress.h"
       
    21 #include <dbghelp.h>
       
    22 
       
    23 /**
       
    24 * Notes on version number of api functions.
       
    25 * 5.1	Windows XP
       
    26 * 5.2	Windows Server 2003
       
    27 * 6.8	Debugging Tools for Windows 6.8
       
    28 * SymSetOptions			DbgHelp.dll 5.1 or later
       
    29 * SymSetSearchPath		DbgHelp.dll 5.1 or later
       
    30 * SymLoadModuleEx			Versions 5.2 and 6.0
       
    31 * SymLoadModule64			DbgHelp.dll 5.1 or later
       
    32 * SymFromAddr				Versions 4.0 and 5.1
       
    33 * SymGetLineFromAddr64	DbgHelp.dll 5.1 or later
       
    34 */
       
    35 
       
    36 // Wrapper class for symbol information package.
       
    37 struct CSymbolInfo : public SYMBOL_INFO_PACKAGE
       
    38 {
       
    39 	CSymbolInfo()
       
    40 	{
       
    41 		si.SizeOfStruct = sizeof( SYMBOL_INFO );
       
    42 		si.MaxNameLen = sizeof( name );
       
    43 	}
       
    44 };
       
    45 
       
    46 // Wrapper class for line information container.
       
    47 struct CLineInfo : public IMAGEHLP_LINE64
       
    48 {
       
    49 	CLineInfo()
       
    50 	{
       
    51 		SizeOfStruct = sizeof( IMAGEHLP_LINE64 );
       
    52 	}
       
    53 };
       
    54 
       
    55 CATDbgHelper::CATDbgHelper()
       
    56 {
       
    57 	LOG_FUNC_ENTRY("CATDbgHelper::CDbgHelper");
       
    58 	// Set the some "default" base address.
       
    59 	m_BaseAddress = 0x2;
       
    60 	m_bMap = false;
       
    61 	m_pBinaryFile = NULL;
       
    62 }
       
    63 
       
    64 CATDbgHelper::~CATDbgHelper()
       
    65 {
       
    66 	LOG_FUNC_ENTRY("CATDbgHelper::~CDbgHelper");
       
    67 	// Close dbghelper only once.
       
    68 	if ( CDBGHELPER_OPEN )
       
    69 	{
       
    70 		Close();
       
    71 	}
       
    72 	if ( m_pBinaryFile )
       
    73 	{
       
    74 		delete[] m_pBinaryFile;
       
    75 		m_pBinaryFile = NULL;
       
    76 	}
       
    77 }
       
    78 
       
    79 bool CATDbgHelper::Open( const string& sParameter, const unsigned long iLong )
       
    80 {
       
    81 	LOG_FUNC_ENTRY("CATDbgHelper::Open");
       
    82 	// Verify that file exits. Version 5.1.2600.5512 of dbghelp.dll does not correctly
       
    83 	// return error code if missing image file. This can lead upto applicaton crash.
       
    84 	if ( ! CATBase::FileExists( sParameter.c_str() ) )
       
    85 	{
       
    86 		LOG_STRING( "Missing image file: " << sParameter );
       
    87 		return false;
       
    88 	}
       
    89 
       
    90 	// Is it urel try read map?
       
    91 	if ( sParameter.find( "\\urel\\" ) != string::npos )
       
    92 	{
       
    93 		string sMapFile = sParameter;
       
    94 		sMapFile.append( ".map" );
       
    95 		ReadMapFile( sMapFile );
       
    96 	}
       
    97 
       
    98 	// Set base address used
       
    99 	m_BaseAddress = iLong + AT_VIRTUAL_OFFSET_DBGHELPER;
       
   100 	// Binary file (also referred as symbol).
       
   101 	size_t length = sParameter.length();
       
   102 	if ( length == 0 )
       
   103 	{
       
   104 		LOG_STRING("DbgHelp:Invalid binary parameter.");
       
   105 		return false;
       
   106 	}
       
   107 
       
   108 	char* pChar = new char[ sParameter.length()+1 ];
       
   109 	strcpy( pChar, sParameter.c_str() );
       
   110 	// Have to be casted to PSTR before using dbg api. Even tho its typedef same.
       
   111 	// This will avoid access violations bug.
       
   112 	// Note pChar is not deleted because its the member pointer just casted its
       
   113 	// memory allocation freed in destructor.
       
   114 	if ( m_pBinaryFile )
       
   115 		delete[] m_pBinaryFile;
       
   116 
       
   117 	m_pBinaryFile = (PSTR) pChar;
       
   118 
       
   119 	// Initialize dbghelper if not done only once.
       
   120 	if ( ! CDBGHELPER_OPEN )
       
   121 	{
       
   122 		// Set symbol options
       
   123 		SymSetOptions( SYMOPT_LOAD_LINES | SYMOPT_DEBUG | SYMOPT_UNDNAME | SYMOPT_LOAD_ANYTHING );
       
   124 		if ( !SymInitialize( GetCurrentProcess(), NULL, TRUE ) )
       
   125 		{
       
   126 			LOG_STRING("DbgHelp:Error initializing dbghelper " << (int) GetLastError());
       
   127 			return false;
       
   128 		}
       
   129 		LOG_STRING("DbgHelp:dbghelper opened.");
       
   130 		CDBGHELPER_OPEN = true;
       
   131 	}
       
   132 
       
   133 	// Set symbol search path.
       
   134 	if ( !SymSetSearchPath( GetCurrentProcess(), NULL ) )
       
   135 	{
       
   136 		LOG_STRING("DbgHelp:Error setting symbol search path " << (int) GetLastError());
       
   137 		return false;
       
   138 	}
       
   139 
       
   140 	// Load module.
       
   141 	DWORD64 ret;
       
   142 	ret = SymLoadModule64( GetCurrentProcess(), NULL, m_pBinaryFile, NULL, m_BaseAddress, NULL ); // 5.1 api version.
       
   143 	if ( ret != m_BaseAddress  && ret != 0)
       
   144 	{
       
   145 		LOG_STRING("Dbghelp:Module load failed " << (int) GetLastError());
       
   146 		return false;
       
   147 	}
       
   148 	CDBGHELPER_CLIENTS++;
       
   149 	return true;
       
   150 }
       
   151 
       
   152 string CATDbgHelper::GetError( void )
       
   153 {
       
   154 	LOG_FUNC_ENTRY("CATDbgHelper::GetError");
       
   155 	return string("not implemented.");
       
   156 }
       
   157 
       
   158 bool CATDbgHelper::Close( void )
       
   159 {
       
   160 	LOG_FUNC_ENTRY("CATDbgHelper::Close");
       
   161 	if ( ! SymUnloadModule64( GetCurrentProcess(), m_BaseAddress ) )
       
   162 	{
       
   163 		LOG_STRING("Dbghelp:Module unload failed.");
       
   164 	}
       
   165 	CDBGHELPER_CLIENTS--;
       
   166 	if ( CDBGHELPER_OPEN && CDBGHELPER_CLIENTS == 0)
       
   167 	{
       
   168 		// Cleanup dbghelper.
       
   169 		if ( ! SymCleanup( GetCurrentProcess() ) )
       
   170 		{
       
   171 			LOG_STRING("dbghelper cleanup failed.");
       
   172 			return false;
       
   173 		}
       
   174 		LOG_STRING("dbghelper closed.");
       
   175 		// Set state not opened.
       
   176 		CDBGHELPER_OPEN = false;
       
   177 	}
       
   178 	return true;
       
   179 }
       
   180 
       
   181 bool CATDbgHelper::AddressToLine( CATMemoryAddress* result )
       
   182 {
       
   183 	LOG_FUNC_ENTRY("CATDbgHelper::AddressToLine");
       
   184 	
       
   185 	// Set state out of range
       
   186 	result->SetAddressToLineState( CATMemoryAddress::OUT_OF_RANGE );
       
   187 
       
   188 	// check that dbghelper has been initialized successfully.
       
   189 	if ( ! CDBGHELPER_OPEN )
       
   190 		return false;
       
   191 
       
   192 	// Check has binary been moved, if so unload and load to new base address.
       
   193 	if ( result->GetModuleStartAddress() + AT_VIRTUAL_OFFSET_DBGHELPER != m_BaseAddress )
       
   194 	{
       
   195 		// Unload.
       
   196 		if ( SymUnloadModule64( GetCurrentProcess(), m_BaseAddress ) )
       
   197 		{
       
   198 			// Set new base address.
       
   199 			m_BaseAddress = result->GetModuleStartAddress() + AT_VIRTUAL_OFFSET_DBGHELPER;
       
   200 			// (Re)load.
       
   201 			DWORD64 loading = SymLoadModule64( GetCurrentProcess(), NULL, m_pBinaryFile, NULL, m_BaseAddress, NULL );
       
   202 			if ( loading != m_BaseAddress  && loading != 0)	
       
   203 			{
       
   204 				LOG_STRING("Dbghelp:Module load failed " << (int) GetLastError());
       
   205 				return false;
       
   206 			}
       
   207 		}
       
   208 		else
       
   209 			LOG_STRING("Dbghelp:Module unload failed " << (int) GetLastError() );
       
   210 	}
       
   211 	// Address to find (offset+given address).
       
   212 	unsigned long iAddressToFind = result->GetAddress() + AT_VIRTUAL_OFFSET_DBGHELPER;
       
   213 	// Displacements of line/symbol information.
       
   214 	DWORD64 displacementSymbol;
       
   215 	DWORD displacementLine;
       
   216 	// Structure to get symbol information.
       
   217 	CSymbolInfo symbol;
       
   218 	// Structure to get line information.
       
   219 	CLineInfo line;
       
   220 	// Find Symbol for given address 
       
   221 	if( ! SymFromAddr( GetCurrentProcess(), iAddressToFind , &displacementSymbol, &symbol.si ) )
       
   222 	{
       
   223 		LOG_STRING("Failed to find symbol information for given line.");
       
   224 		return AddressToFunction( result );
       
   225 	}
       
   226 	// Find line information
       
   227 	if( ! SymGetLineFromAddr64( GetCurrentProcess(), iAddressToFind, &displacementLine, &line ) )
       
   228 	{
       
   229 		// If it fails get symbol line information
       
   230 		LOG_STRING("Dbghelp:Failed to find line information for address, trying for symbol of address.");
       
   231 		if( ! SymGetLineFromAddr64( GetCurrentProcess(), symbol.si.Address, &displacementLine, &line ) )
       
   232 		{
       
   233 			LOG_STRING("Dbghelp:Failed to find line information for symbol address.");
       
   234 			return AddressToFunction( result );
       
   235 		}
       
   236 	}
       
   237 	// Set the results.
       
   238 	result->SetFileName( string( line.FileName ) );
       
   239 	result->SetFunctionName( string( symbol.si.Name ) );
       
   240 	result->SetExactLineNumber( (int) line.LineNumber );
       
   241 	result->SetAddressToLineState( CATMemoryAddress::EXACT );
       
   242 	// Return.
       
   243 	return true;
       
   244 }
       
   245 
       
   246 bool CATDbgHelper::AddressToFunction( CATMemoryAddress* result )
       
   247 {
       
   248 	LOG_FUNC_ENTRY("CATDbgHelper::AddressToFunction");
       
   249 	bool bFound = false;
       
   250 	// If map file read use it and return.
       
   251 	if ( m_bMap )
       
   252 	{
       
   253 		ULONG uCountedA = result->GetOffSetFromModuleStart();
       
   254 		for ( vector<MAP_FUNC_INFO>::iterator it = m_vMapFileFuncList.begin() ; it != m_vMapFileFuncList.end() ; it++ )
       
   255 		{
       
   256 			// Check is this the symbol where address is.
       
   257 			unsigned long iStart = it->iAddress;
       
   258 			unsigned long iEnd = it->iAddress + it->iFuncLength;
       
   259 			if ( uCountedA >= iStart 
       
   260 				&& uCountedA < iEnd )
       
   261 			{
       
   262 				result->SetAddressToLineState( CATMemoryAddress::SYMBOL );
       
   263 				result->SetFunctionName( it->sMangledName );
       
   264 				bFound = true;
       
   265 				break;
       
   266 			}
       
   267 		}
       
   268 	}
       
   269 	return bFound;
       
   270 }
       
   271 
       
   272 void CATDbgHelper::ReadMapFile( const string sMapFileName )
       
   273 {
       
   274 	LOG_FUNC_ENTRY("CATDbgHelper::ReadMapFile");
       
   275 	try {
       
   276 		ifstream in( sMapFileName.c_str() );
       
   277 		if ( ! in.good() )
       
   278 		{
       
   279 			in.close();
       
   280 			return;
       
   281 		}
       
   282 		char cLine[MAX_LINE_LENGTH];
       
   283 		do {
       
   284 			in.getline( cLine, MAX_LINE_LENGTH );
       
   285 			// Search pattern for 'image ro' symbols is ".text"
       
   286 			string sLine( cLine );
       
   287 			if ( sLine.find( ".text" ) != string::npos )
       
   288 			{
       
   289 				MAP_FUNC_INFO symbol;
       
   290 				// Pickup symbol attributes
       
   291 				// Address
       
   292 				string sAddress = CATBase::GetStringUntilNextSpace( sLine, true );
       
   293 				symbol.iAddress = CATBase::_httoi( sAddress.c_str() );
       
   294 				// Lenght
       
   295 				string sLength = CATBase::GetStringUntilNextSpace( sLine, true );
       
   296 				symbol.iFuncLength = CATBase::_httoi( sLength.c_str() );
       
   297 				// Name
       
   298 				size_t iStart = sLine.find_first_of( '(' );
       
   299 				size_t iEnd = sLine.find_last_of( ')' );
       
   300 				if ( iStart != string::npos && iEnd != string::npos )
       
   301 				{
       
   302 					symbol.sMangledName = sLine.substr( iStart+1, iEnd-iStart-1 );
       
   303 					// Add symbol to vector
       
   304 					m_vMapFileFuncList.push_back( symbol );
       
   305 				}
       
   306 			}
       
   307 		} while ( in.good() );
       
   308 		in.close();
       
   309 		m_bMap = true;
       
   310 	} catch (...) {
       
   311 		m_bMap = false;
       
   312 		LOG_STRING("DbgHelp: Error reading map file.");
       
   313 	}
       
   314 }