|
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: Main module for addr2line pinpointing. |
|
15 * |
|
16 */ |
|
17 |
|
18 #include "../inc/cataddr2line.h" |
|
19 #include "../inc/CATMemoryAddress.h" |
|
20 #include "../inc/CATBase.h" |
|
21 #include "../inc/CATDatParser.h" |
|
22 |
|
23 #define ASCII_CHAR_CARRIAGE_RETURN 0x0D |
|
24 |
|
25 CATAddr2line::CATAddr2line() |
|
26 { |
|
27 LOG_FUNC_ENTRY("CATAddr2line::CATAddr2line"); |
|
28 } |
|
29 |
|
30 bool CATAddr2line::Open( const string& sParameter, const unsigned long /* iLong */ ) |
|
31 { |
|
32 LOG_FUNC_ENTRY("CATAddr2line::Open"); |
|
33 //Debugging for addr2line task. |
|
34 //debug.open( "addr2line-lines.txt", ios_base::trunc ); |
|
35 |
|
36 m_sMapFileName.clear(); |
|
37 // Add .map extendsion |
|
38 m_sMapFileName.append( sParameter ); |
|
39 m_sMapFileName.append( ".map" ); |
|
40 |
|
41 ReadMapFileArmv5(); |
|
42 |
|
43 //Make symfile path+name |
|
44 string sFullPathToSymFile(sParameter); |
|
45 sFullPathToSymFile.erase( sFullPathToSymFile.find_last_of( "." ), string::npos ); |
|
46 sFullPathToSymFile.append( ".sym" ); |
|
47 |
|
48 // Check with extension + .sym also. |
|
49 if ( ! CATBase::FileExists( sFullPathToSymFile.c_str() ) ) |
|
50 { |
|
51 sFullPathToSymFile.clear(); |
|
52 sFullPathToSymFile.append( sParameter ); |
|
53 sFullPathToSymFile.append( ".sym" ); |
|
54 } |
|
55 |
|
56 return server.Initialize( sFullPathToSymFile ); |
|
57 } |
|
58 |
|
59 string CATAddr2line::GetError( void ) |
|
60 { |
|
61 LOG_FUNC_ENTRY("CATAddr2line::GetError"); |
|
62 string s; |
|
63 return s; |
|
64 } |
|
65 |
|
66 bool CATAddr2line::Close( void ) |
|
67 { |
|
68 LOG_FUNC_ENTRY("CATAddr2line::Close"); |
|
69 //Debugging for addr2line task. |
|
70 //debug.close(); |
|
71 return true; |
|
72 } |
|
73 |
|
74 bool CATAddr2line::AddressToLine( CATMemoryAddress* result ) |
|
75 { |
|
76 LOG_FUNC_ENTRY("CATAddr2line::AddressToLine"); |
|
77 |
|
78 result->SetAddressToLineState( CATMemoryAddress::OUT_OF_RANGE); |
|
79 |
|
80 if( !server.GetProcessCreatedState() ) |
|
81 return false; |
|
82 //Count address |
|
83 ULONG uStartA = result->GetModuleStartAddress(); |
|
84 ULONG uMemoryA = result->GetAddress(); |
|
85 ULONG uCountedA = uMemoryA - uStartA; |
|
86 uCountedA += FUNCTIONS_OFFSET_IN_GCCE; |
|
87 |
|
88 string sTemp = CATBase::NumberToHexString( uCountedA ); |
|
89 //Remove "0x" |
|
90 size_t iCounter = sTemp.find_first_of('x'); |
|
91 if( iCounter != string::npos ) |
|
92 { |
|
93 sTemp.erase( 0, (int)iCounter+1 ); |
|
94 } |
|
95 // Write to pipe that is the standard input for a child process. |
|
96 server.WriteToPipe( sTemp ); |
|
97 |
|
98 // Read from pipe that is the standard output for child process. |
|
99 string s = server.ReadFromPipe(); |
|
100 |
|
101 //If output not empty, parse output |
|
102 if( !s.empty() ) |
|
103 { |
|
104 //Debugging code for addr2line task. |
|
105 //debug.write( "##########\n", 12 ); |
|
106 //debug.write( s.c_str(), s.size() ); |
|
107 result->SetAddressToLineState( CATMemoryAddress::EXACT ); |
|
108 |
|
109 string s2; |
|
110 size_t iLocation = s.find_first_of( ASCII_CHAR_CARRIAGE_RETURN ); |
|
111 |
|
112 bool bFunctionNameFoundUsingAddr2line = false; |
|
113 |
|
114 //Function name |
|
115 |
|
116 if(iLocation != string::npos ) |
|
117 { |
|
118 s2 = s.substr( 0, iLocation ); |
|
119 //All characters ascii? |
|
120 if( CATBase::IsAscii( s2.c_str(), (int)s2.length() ) ) |
|
121 { |
|
122 //addr2line returns $x if function name not found |
|
123 //length must over 2 to be real function name |
|
124 if( s2.length() > 2 ) |
|
125 { |
|
126 bFunctionNameFoundUsingAddr2line = true; |
|
127 result->SetFunctionName( s2 ); |
|
128 s.erase( 0, iLocation+2 ); |
|
129 } |
|
130 } |
|
131 } |
|
132 //If function name not found using addr2line find it from map file |
|
133 if( !bFunctionNameFoundUsingAddr2line ) |
|
134 { |
|
135 string sFuncName( GetFunctionNameUsingAddress( uCountedA ) ); |
|
136 //If function name empty, print "???" |
|
137 if( sFuncName.empty() ) |
|
138 { |
|
139 s2 = "???"; |
|
140 result->SetFunctionName( s2 ); |
|
141 if(iLocation != string::npos ) |
|
142 { |
|
143 s.erase( 0, iLocation+2 ); |
|
144 } |
|
145 } |
|
146 else |
|
147 result->SetFunctionName( sFuncName ); |
|
148 } |
|
149 iLocation = s.find_first_of( ':' ); |
|
150 |
|
151 //Filename and location |
|
152 |
|
153 if(iLocation != string::npos ) |
|
154 { |
|
155 s2 = s.substr( 0, iLocation ); |
|
156 result->SetFileName( s2 ); |
|
157 s.erase( 0, iLocation+1 ); |
|
158 } |
|
159 |
|
160 //Exact line number |
|
161 |
|
162 s2 = s.substr( 0, s.find_first_of( ASCII_CHAR_CARRIAGE_RETURN ) ); |
|
163 result->SetExactLineNumber( atoi( s2.c_str() ) ); |
|
164 } |
|
165 return true; |
|
166 } |
|
167 |
|
168 bool CATAddr2line::ReadMapFileArmv5() |
|
169 { |
|
170 LOG_FUNC_ENTRY("CATModule2::ReadMapFileArmv5"); |
|
171 // Open .map file |
|
172 ifstream in( m_sMapFileName.c_str() ); |
|
173 // File open ok? |
|
174 if( ! in.good() ) |
|
175 { |
|
176 in.close(); |
|
177 return false; |
|
178 } |
|
179 char cTemp[MAX_LINE_LENGTH]; |
|
180 bool bFirstFuncFound = false; |
|
181 bool bFirstLine = true; |
|
182 // Get all lines where is "Thumb" |
|
183 do |
|
184 { |
|
185 // Load one line from .map file |
|
186 in.getline( cTemp, MAX_LINE_LENGTH ); |
|
187 if( bFirstLine ) |
|
188 { |
|
189 bFirstLine = false; |
|
190 if( strstr( cTemp, "ARM Linker" ) == NULL ) |
|
191 return false; |
|
192 } |
|
193 // Find _E32Startup |
|
194 if( !bFirstFuncFound && ( strstr( cTemp, "_E32Startup" ) != NULL) ) |
|
195 { |
|
196 bFirstFuncFound = true; |
|
197 } |
|
198 else if( !bFirstFuncFound && ( strstr( cTemp, "_E32Dll" ) != NULL) ) |
|
199 { |
|
200 bFirstFuncFound = true; |
|
201 } |
|
202 else if( !bFirstFuncFound ) |
|
203 // Skip if _E32Startup not found |
|
204 continue; |
|
205 |
|
206 if( strstr( cTemp, "Thumb Code" ) != NULL || strstr( cTemp, "ARM Code" ) != NULL) |
|
207 { |
|
208 MAP_FUNC_INFO structMapFileLineInfo; |
|
209 structMapFileLineInfo.sWholeLine.append( cTemp ); |
|
210 |
|
211 // Get memory string address from line |
|
212 char* pStart = strstr( cTemp, "0x" ); |
|
213 // Check did strstr return null. |
|
214 if ( pStart == NULL ) |
|
215 continue; |
|
216 char* pTemp = pStart; |
|
217 char TempString[MAX_LINE_LENGTH]; |
|
218 TempString[0] = 0; |
|
219 size_t iLength = 0; |
|
220 while( *pTemp != ' ' ) |
|
221 { |
|
222 TempString[iLength] = *pTemp; |
|
223 pTemp++; |
|
224 iLength++; |
|
225 } |
|
226 TempString[iLength] = 0; |
|
227 |
|
228 structMapFileLineInfo.iAddress = CATDatParser::_httoi( TempString ); |
|
229 |
|
230 pTemp = cTemp; |
|
231 TempString[0] = 0; |
|
232 |
|
233 // Get function name |
|
234 |
|
235 // Skip spaces |
|
236 while( *pTemp == ' ' ) |
|
237 { |
|
238 pTemp++; |
|
239 } |
|
240 iLength = 0; |
|
241 // Find end of function name |
|
242 string sTemp( pTemp ); |
|
243 |
|
244 // Location of character ')' |
|
245 iLength = sTemp.find_first_of(')'); |
|
246 |
|
247 // Location of character ' ' |
|
248 size_t iLength2 = sTemp.find_first_of(' '); |
|
249 |
|
250 // If ')' character is the last char and |
|
251 // character ' ' is closer than ')' use location of ' ' |
|
252 if( ( iLength + 1 ) == sTemp.length() && iLength2 < iLength ) |
|
253 iLength = iLength2 - 1; |
|
254 |
|
255 if( iLength != string::npos ) |
|
256 sTemp.resize( (iLength + 1) ); |
|
257 |
|
258 structMapFileLineInfo.sFunctionName.append( sTemp.c_str() ); |
|
259 |
|
260 bool bARM = false; |
|
261 // Find function length |
|
262 pStart = strstr( cTemp, "Thumb Code" ); |
|
263 if( pStart == NULL ) |
|
264 { |
|
265 pStart = strstr( cTemp, "ARM Code" ); |
|
266 bARM = true; |
|
267 } |
|
268 if( pStart != NULL ) |
|
269 { |
|
270 if( bARM ) |
|
271 pStart += 8; |
|
272 else |
|
273 pStart += 10; |
|
274 while(*pStart == ' ') |
|
275 { |
|
276 pStart++; |
|
277 } |
|
278 sTemp.clear(); |
|
279 sTemp.append( pStart ); |
|
280 size_t iSize = sTemp.find_first_of(' '); |
|
281 if( iSize != string::npos ) |
|
282 sTemp.resize( iSize ); |
|
283 } |
|
284 |
|
285 structMapFileLineInfo.iFuncLength = atoi( sTemp.c_str() ); |
|
286 if( bFirstFuncFound && structMapFileLineInfo.iFuncLength > 0 ) |
|
287 // Save to list |
|
288 m_vMapFileFuncList.push_back( structMapFileLineInfo ); |
|
289 } |
|
290 } |
|
291 while( in.good() ); |
|
292 in.close(); |
|
293 return true; |
|
294 } |
|
295 |
|
296 // Find function name of given address |
|
297 string CATAddr2line::GetFunctionNameUsingAddress( unsigned long iAddress ) |
|
298 { |
|
299 LOG_LOW_FUNC_ENTRY("CATAddr2line::GetSymbolIndexUsingAddress"); |
|
300 string sRet; |
|
301 for( size_t i = 0; i < m_vMapFileFuncList.size(); i++ ) |
|
302 { |
|
303 unsigned long iStart = m_vMapFileFuncList.at( i ).iAddress; |
|
304 unsigned long iEnd = ( m_vMapFileFuncList.at( i ).iAddress |
|
305 + m_vMapFileFuncList.at( i ).iFuncLength ); |
|
306 |
|
307 if ( iAddress >= iStart && iAddress < iEnd ) |
|
308 return m_vMapFileFuncList.at( i ).sFunctionName; |
|
309 } |
|
310 return sRet; |
|
311 } |
|
312 |
|
313 //Note: New filtering functions commented out until they are taken into use. |
|
314 /** |
|
315 * Filter string out of unwanted characters. |
|
316 */ |
|
317 /* |
|
318 void CATAddr2line::FilterString( string &sString ) |
|
319 { |
|
320 LOG_LOW_FUNC_ENTRY("CATAddr2line::FilterString"); |
|
321 string sFiltered(""); |
|
322 for( size_t i = 0 ; i < sString.length() ; i++ ) |
|
323 { |
|
324 const char p = sString.at( i ); |
|
325 if ( p != 0 && strchr( ADDR2LINEALLOWEDCHARS, p ) != 0 ) |
|
326 sFiltered.push_back( p ); |
|
327 } |
|
328 sString = sFiltered; |
|
329 } |
|
330 */ |
|
331 /** |
|
332 * Find line feed position from string. |
|
333 */ |
|
334 /* |
|
335 size_t CATAddr2line::FindLineFeed( const string& sString ) |
|
336 { |
|
337 LOG_LOW_FUNC_ENTRY("CATAddr2line::FindLineFeed"); |
|
338 size_t iLineFeed1 = sString.find( 12 ); |
|
339 size_t iLineFeed2 = sString.find( 15 ); |
|
340 if ( iLineFeed1 < iLineFeed2 && iLineFeed1 != string::npos ) |
|
341 return iLineFeed1; |
|
342 else if ( iLineFeed2 != string::npos ) |
|
343 return iLineFeed2; |
|
344 else |
|
345 return string::npos; |
|
346 } |
|
347 */ |
|
348 /** |
|
349 * Erase characters from start of the string until other char than linefeed found. |
|
350 */ |
|
351 /* |
|
352 void CATAddr2line::EraseUntilNoLineFeed( string& sString ) |
|
353 { |
|
354 LOG_LOW_FUNC_ENTRY("CATAddr2line::EraseUntilNoLineFeed"); |
|
355 for ( size_t i = 0 ; i < sString.length() ; i++ ) |
|
356 { |
|
357 if ( sString.at( i ) != 15 && sString.at( i ) != 12 ) |
|
358 break; |
|
359 } |
|
360 sString.erase( 0, i ); |
|
361 } |
|
362 */ |
|
363 /** |
|
364 * Split multiple line string with unexpected line feeds to vector of strings. |
|
365 */ |
|
366 /* |
|
367 vector<string> CATAddr2line::SplitToStrings( string& sMultiLineString ) |
|
368 { |
|
369 LOG_LOW_FUNC_ENTRY("CATAddr2line::SplitToStrings"); |
|
370 vector<string> vLines; |
|
371 while ( 1 ) |
|
372 { |
|
373 size_t iLineFeed = FindLineFeed( sMultiLineString ); |
|
374 if ( iLineFeed == string::npos ) |
|
375 break; |
|
376 string sCell = sMultiLineString.substr(0, iLineFeed ); |
|
377 sMultiLineString.erase(0, iLineFeed ); |
|
378 EraseUntilNoLineFeed( sMultiLineString ); |
|
379 FilterString( sCell ); |
|
380 vLines.push_back( sCell ); |
|
381 } |
|
382 // If no lines were found set single one. |
|
383 if ( vLines.size() == 0 ) |
|
384 vLines.push_back( sMultiLineString ); |
|
385 return vLines; |
|
386 } |
|
387 */ |
|
388 //EOF |