|
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 } |