diff -r 000000000000 -r f0f2b8682603 memana/analyzetoolclient/commandlineengine/internal/src/cataddr2line.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/memana/analyzetoolclient/commandlineengine/internal/src/cataddr2line.cpp Thu Feb 11 15:51:35 2010 +0200 @@ -0,0 +1,388 @@ +/* +* 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: Main module for addr2line pinpointing. +* +*/ + +#include "../inc/cataddr2line.h" +#include "../inc/CATMemoryAddress.h" +#include "../inc/CATBase.h" +#include "../inc/CATDatParser.h" + +#define ASCII_CHAR_CARRIAGE_RETURN 0x0D + +CATAddr2line::CATAddr2line() +{ + LOG_FUNC_ENTRY("CATAddr2line::CATAddr2line"); +} + +bool CATAddr2line::Open( const string& sParameter, const unsigned long /* iLong */ ) +{ + LOG_FUNC_ENTRY("CATAddr2line::Open"); + //Debugging for addr2line task. + //debug.open( "addr2line-lines.txt", ios_base::trunc ); + + m_sMapFileName.clear(); + // Add .map extendsion + m_sMapFileName.append( sParameter ); + m_sMapFileName.append( ".map" ); + + ReadMapFileArmv5(); + + //Make symfile path+name + string sFullPathToSymFile(sParameter); + sFullPathToSymFile.erase( sFullPathToSymFile.find_last_of( "." ), string::npos ); + sFullPathToSymFile.append( ".sym" ); + + // Check with extension + .sym also. + if ( ! CATBase::FileExists( sFullPathToSymFile.c_str() ) ) + { + sFullPathToSymFile.clear(); + sFullPathToSymFile.append( sParameter ); + sFullPathToSymFile.append( ".sym" ); + } + + return server.Initialize( sFullPathToSymFile ); +} + +string CATAddr2line::GetError( void ) +{ + LOG_FUNC_ENTRY("CATAddr2line::GetError"); + string s; + return s; +} + +bool CATAddr2line::Close( void ) +{ + LOG_FUNC_ENTRY("CATAddr2line::Close"); + //Debugging for addr2line task. + //debug.close(); + return true; +} + +bool CATAddr2line::AddressToLine( CATMemoryAddress* result ) +{ + LOG_FUNC_ENTRY("CATAddr2line::AddressToLine"); + + result->SetAddressToLineState( CATMemoryAddress::ADDRESS_TO_LINE_STATE::OUT_OF_RANGE); + + if( !server.GetProcessCreatedState() ) + return false; + //Count address + ULONG uStartA = result->GetModuleStartAddress(); + ULONG uMemoryA = result->GetAddress(); + ULONG uCountedA = uMemoryA - uStartA; + uCountedA += FUNCTIONS_OFFSET_IN_GCCE; + + string sTemp = CATBase::NumberToHexString( uCountedA ); + //Remove "0x" + size_t iCounter = sTemp.find_first_of('x'); + if( iCounter != string::npos ) + { + sTemp.erase( 0, (int)iCounter+1 ); + } + // Write to pipe that is the standard input for a child process. + server.WriteToPipe( sTemp ); + + // Read from pipe that is the standard output for child process. + string s = server.ReadFromPipe(); + + //If output not empty, parse output + if( !s.empty() ) + { + //Debugging code for addr2line task. + //debug.write( "##########\n", 12 ); + //debug.write( s.c_str(), s.size() ); + result->SetAddressToLineState( CATMemoryAddress::ADDRESS_TO_LINE_STATE::EXACT ); + + string s2; + size_t iLocation = s.find_first_of( ASCII_CHAR_CARRIAGE_RETURN ); + + bool bFunctionNameFoundUsingAddr2line = false; + + //Function name + + if(iLocation != string::npos ) + { + s2 = s.substr( 0, iLocation ); + //All characters ascii? + if( CATBase::IsAscii( s2.c_str(), (int)s2.length() ) ) + { + //addr2line returns $x if function name not found + //length must over 2 to be real function name + if( s2.length() > 2 ) + { + bFunctionNameFoundUsingAddr2line = true; + result->SetFunctionName( s2 ); + s.erase( 0, iLocation+2 ); + } + } + } + //If function name not found using addr2line find it from map file + if( !bFunctionNameFoundUsingAddr2line ) + { + string sFuncName( GetFunctionNameUsingAddress( uCountedA ) ); + //If function name empty, print "???" + if( sFuncName.empty() ) + { + s2 = "???"; + result->SetFunctionName( s2 ); + if(iLocation != string::npos ) + { + s.erase( 0, iLocation+2 ); + } + } + else + result->SetFunctionName( sFuncName ); + } + iLocation = s.find_first_of( ':' ); + + //Filename and location + + if(iLocation != string::npos ) + { + s2 = s.substr( 0, iLocation ); + result->SetFileName( s2 ); + s.erase( 0, iLocation+1 ); + } + + //Exact line number + + s2 = s.substr( 0, s.find_first_of( ASCII_CHAR_CARRIAGE_RETURN ) ); + result->SetExactLineNumber( atoi( s2.c_str() ) ); + } + return true; +} + +bool CATAddr2line::ReadMapFileArmv5() +{ + LOG_FUNC_ENTRY("CATModule2::ReadMapFileArmv5"); + // Open .map file + ifstream in( m_sMapFileName.c_str() ); + // File open ok? + if( ! in.good() ) + { + in.close(); + return false; + } + char cTemp[MAX_LINE_LENGTH]; + bool bFirstFuncFound = false; + bool bFirstLine = true; + // Get all lines where is "Thumb" + do + { + // Load one line from .map file + in.getline( cTemp, MAX_LINE_LENGTH ); + if( bFirstLine ) + { + bFirstLine = false; + if( strstr( cTemp, "ARM Linker" ) == NULL ) + return false; + } + // Find _E32Startup + if( !bFirstFuncFound && ( strstr( cTemp, "_E32Startup" ) != NULL) ) + { + bFirstFuncFound = true; + } + else if( !bFirstFuncFound && ( strstr( cTemp, "_E32Dll" ) != NULL) ) + { + bFirstFuncFound = true; + } + else if( !bFirstFuncFound ) + // Skip if _E32Startup not found + continue; + + if( strstr( cTemp, "Thumb Code" ) != NULL || strstr( cTemp, "ARM Code" ) != NULL) + { + MAP_FUNC_INFO structMapFileLineInfo; + structMapFileLineInfo.sWholeLine.append( cTemp ); + + // Get memory string address from line + char* pStart = strstr( cTemp, "0x" ); + // Check did strstr return null. + if ( pStart == NULL ) + continue; + char* pTemp = pStart; + char TempString[MAX_LINE_LENGTH]; + TempString[0] = 0; + size_t iLength = 0; + while( *pTemp != ' ' ) + { + TempString[iLength] = *pTemp; + pTemp++; + iLength++; + } + TempString[iLength] = 0; + + structMapFileLineInfo.iAddress = CATDatParser::_httoi( TempString ); + + pTemp = cTemp; + TempString[0] = 0; + + // Get function name + + // Skip spaces + while( *pTemp == ' ' ) + { + pTemp++; + } + iLength = 0; + // Find end of function name + string sTemp( pTemp ); + + // Location of character ')' + iLength = sTemp.find_first_of(')'); + + // Location of character ' ' + size_t iLength2 = sTemp.find_first_of(' '); + + // If ')' character is the last char and + // character ' ' is closer than ')' use location of ' ' + if( ( iLength + 1 ) == sTemp.length() && iLength2 < iLength ) + iLength = iLength2 - 1; + + if( iLength != string::npos ) + sTemp.resize( (iLength + 1) ); + + structMapFileLineInfo.sFunctionName.append( sTemp.c_str() ); + + bool bARM = false; + // Find function length + pStart = strstr( cTemp, "Thumb Code" ); + if( pStart == NULL ) + { + pStart = strstr( cTemp, "ARM Code" ); + bARM = true; + } + if( pStart != NULL ) + { + if( bARM ) + pStart += 8; + else + pStart += 10; + while(*pStart == ' ') + { + pStart++; + } + sTemp.clear(); + sTemp.append( pStart ); + size_t iSize = sTemp.find_first_of(' '); + if( iSize != string::npos ) + sTemp.resize( iSize ); + } + + structMapFileLineInfo.iFuncLength = atoi( sTemp.c_str() ); + if( bFirstFuncFound && structMapFileLineInfo.iFuncLength > 0 ) + // Save to list + m_vMapFileFuncList.push_back( structMapFileLineInfo ); + } + } + while( in.good() ); + in.close(); + return true; +} + +// Find function name of given address +string CATAddr2line::GetFunctionNameUsingAddress( unsigned long iAddress ) +{ + LOG_LOW_FUNC_ENTRY("CATAddr2line::GetSymbolIndexUsingAddress"); + string sRet; + for( size_t i = 0; i < m_vMapFileFuncList.size(); i++ ) + { + unsigned long iStart = m_vMapFileFuncList.at( i ).iAddress; + unsigned long iEnd = ( m_vMapFileFuncList.at( i ).iAddress + + m_vMapFileFuncList.at( i ).iFuncLength ); + + if ( iAddress >= iStart && iAddress < iEnd ) + return m_vMapFileFuncList.at( i ).sFunctionName; + } + return sRet; +} + +//Note: New filtering functions commented out until they are taken into use. +/** +* Filter string out of unwanted characters. +*/ +/* +void CATAddr2line::FilterString( string &sString ) +{ + LOG_LOW_FUNC_ENTRY("CATAddr2line::FilterString"); + string sFiltered(""); + for( size_t i = 0 ; i < sString.length() ; i++ ) + { + const char p = sString.at( i ); + if ( p != 0 && strchr( ADDR2LINEALLOWEDCHARS, p ) != 0 ) + sFiltered.push_back( p ); + } + sString = sFiltered; +} +*/ +/** +* Find line feed position from string. +*/ +/* +size_t CATAddr2line::FindLineFeed( const string& sString ) +{ + LOG_LOW_FUNC_ENTRY("CATAddr2line::FindLineFeed"); + size_t iLineFeed1 = sString.find( 12 ); + size_t iLineFeed2 = sString.find( 15 ); + if ( iLineFeed1 < iLineFeed2 && iLineFeed1 != string::npos ) + return iLineFeed1; + else if ( iLineFeed2 != string::npos ) + return iLineFeed2; + else + return string::npos; +} +*/ +/** +* Erase characters from start of the string until other char than linefeed found. +*/ +/* +void CATAddr2line::EraseUntilNoLineFeed( string& sString ) +{ + LOG_LOW_FUNC_ENTRY("CATAddr2line::EraseUntilNoLineFeed"); + for ( size_t i = 0 ; i < sString.length() ; i++ ) + { + if ( sString.at( i ) != 15 && sString.at( i ) != 12 ) + break; + } + sString.erase( 0, i ); +} +*/ +/** +* Split multiple line string with unexpected line feeds to vector of strings. +*/ +/* +vector CATAddr2line::SplitToStrings( string& sMultiLineString ) +{ + LOG_LOW_FUNC_ENTRY("CATAddr2line::SplitToStrings"); + vector vLines; + while ( 1 ) + { + size_t iLineFeed = FindLineFeed( sMultiLineString ); + if ( iLineFeed == string::npos ) + break; + string sCell = sMultiLineString.substr(0, iLineFeed ); + sMultiLineString.erase(0, iLineFeed ); + EraseUntilNoLineFeed( sMultiLineString ); + FilterString( sCell ); + vLines.push_back( sCell ); + } + // If no lines were found set single one. + if ( vLines.size() == 0 ) + vLines.push_back( sMultiLineString ); + return vLines; +} +*/ +//EOF