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