1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | |
6 | |
7 | #include "common.h" |
8 | |
9 | #include "sourceline.h" |
10 | |
11 | ////////////////////////////////////////////////////////////////// |
12 | |
13 | #ifdef ENABLE_DIAGNOSTIC_SYMBOL_READING |
14 | |
15 | class CCallback : public IDiaLoadCallback |
16 | { |
17 | int m_nRefCount; |
18 | public: |
19 | CCallback() { |
20 | CONTRACTL |
21 | { |
22 | MODE_ANY; |
23 | GC_NOTRIGGER; |
24 | NOTHROW; |
25 | }CONTRACTL_END; |
26 | |
27 | m_nRefCount = 0; |
28 | } |
29 | |
30 | //IUnknown |
31 | ULONG STDMETHODCALLTYPE AddRef() { |
32 | LIMITED_METHOD_CONTRACT; |
33 | m_nRefCount++; |
34 | return m_nRefCount; |
35 | } |
36 | |
37 | ULONG STDMETHODCALLTYPE Release() { |
38 | CONTRACTL |
39 | { |
40 | THROWS; |
41 | GC_NOTRIGGER; |
42 | MODE_ANY; |
43 | SO_TOLERANT; |
44 | } CONTRACTL_END; |
45 | |
46 | BEGIN_SO_INTOLERANT_CODE(GetThread()); |
47 | if ( (--m_nRefCount) == 0 ) |
48 | delete this; |
49 | END_SO_INTOLERANT_CODE; |
50 | |
51 | return m_nRefCount; |
52 | } |
53 | |
54 | HRESULT STDMETHODCALLTYPE QueryInterface( REFIID rid, void **ppUnk ) { |
55 | WRAPPER_NO_CONTRACT; |
56 | STATIC_CONTRACT_SO_TOLERANT; |
57 | if ( ppUnk == NULL ) { |
58 | return E_INVALIDARG; |
59 | } |
60 | if (rid == __uuidof( IDiaLoadCallback ) ) |
61 | *ppUnk = (IDiaLoadCallback *)this; |
62 | else if (rid == __uuidof( IDiaLoadCallback ) ) |
63 | *ppUnk = (IDiaLoadCallback *)this; |
64 | else if (rid == __uuidof( IUnknown ) ) |
65 | *ppUnk = (IUnknown *)this; |
66 | else |
67 | *ppUnk = NULL; |
68 | |
69 | if ( *ppUnk != NULL ) { |
70 | AddRef(); |
71 | return S_OK; |
72 | } |
73 | |
74 | return E_NOINTERFACE; |
75 | } |
76 | |
77 | HRESULT STDMETHODCALLTYPE NotifyDebugDir( |
78 | BOOL fExecutable, |
79 | DWORD cbData, |
80 | BYTE data[]) // really a const struct _IMAGE_DEBUG_DIRECTORY * |
81 | { |
82 | LIMITED_METHOD_CONTRACT; |
83 | STATIC_CONTRACT_SO_TOLERANT; |
84 | return S_OK; |
85 | } |
86 | |
87 | HRESULT STDMETHODCALLTYPE NotifyOpenDBG( |
88 | LPCOLESTR dbgPath, |
89 | HRESULT resultCode) |
90 | { |
91 | LIMITED_METHOD_CONTRACT; |
92 | return S_OK; |
93 | } |
94 | |
95 | HRESULT STDMETHODCALLTYPE NotifyOpenPDB( |
96 | LPCOLESTR pdbPath, |
97 | HRESULT resultCode) |
98 | { |
99 | LIMITED_METHOD_CONTRACT; |
100 | return S_OK; |
101 | } |
102 | |
103 | HRESULT STDMETHODCALLTYPE RestrictRegistryAccess() // return hr != S_OK to prevent querying the registry for symbol search paths |
104 | { |
105 | LIMITED_METHOD_CONTRACT; |
106 | return S_OK; |
107 | } |
108 | |
109 | HRESULT STDMETHODCALLTYPE RestrictSymbolServerAccess() // return hr != S_OK to prevent accessing a symbol server |
110 | { |
111 | LIMITED_METHOD_CONTRACT; |
112 | return S_OK; |
113 | } |
114 | |
115 | HRESULT STDMETHODCALLTYPE RestrictOriginalPathAccess() // return hr != S_OK to prevent querying the registry for symbol search paths |
116 | { |
117 | LIMITED_METHOD_CONTRACT; |
118 | return S_OK; |
119 | } |
120 | |
121 | HRESULT STDMETHODCALLTYPE RestrictReferencePathAccess() // return hr != S_OK to prevent accessing a symbol server |
122 | { |
123 | LIMITED_METHOD_CONTRACT; |
124 | return S_OK; |
125 | } |
126 | |
127 | HRESULT STDMETHODCALLTYPE RestrictDBGAccess() |
128 | { |
129 | LIMITED_METHOD_CONTRACT; |
130 | return S_OK; |
131 | } |
132 | }; |
133 | |
134 | ////////////////////////////////////////////////////////////////// |
135 | |
136 | bool SourceLine::LoadDataFromPdb( __in_z LPWSTR wszFilename ) |
137 | { |
138 | CONTRACTL { |
139 | THROWS; |
140 | GC_TRIGGERS; |
141 | MODE_ANY; |
142 | } CONTRACTL_END; |
143 | |
144 | HRESULT hResult; |
145 | |
146 | // CComPtr(IDiaDataSource) pDataSource; |
147 | |
148 | hResult = CoInitialize(NULL); |
149 | |
150 | if (FAILED(hResult)){ |
151 | return FALSE; |
152 | } |
153 | |
154 | // Obtain Access To The Provider |
155 | hResult = CoCreateInstance(CLSID_DiaSource, |
156 | NULL, |
157 | CLSCTX_INPROC_SERVER, |
158 | IID_IDiaDataSource, |
159 | (void **) &pSource_); |
160 | |
161 | if (FAILED(hResult)){ |
162 | return FALSE; |
163 | } |
164 | |
165 | CCallback callback; |
166 | callback.AddRef(); |
167 | |
168 | if ( FAILED( pSource_->loadDataFromPdb( wszFilename ) ) |
169 | && FAILED( pSource_->loadDataForExe( wszFilename, W("symsrv*symsrv.dll*\\\\symbols\\\\symbols" ), &callback ) ) ) |
170 | return FALSE; |
171 | if ( FAILED( pSource_->openSession(&pSession_) ) ) |
172 | return FALSE; |
173 | if ( FAILED( pSession_->get_globalScope(&pGlobal_) ) ) |
174 | return FALSE; |
175 | |
176 | return TRUE; |
177 | } |
178 | |
179 | ////////////////////////////////////////////////////////////////// |
180 | |
181 | SourceLine::SourceLine( __in_z LPWSTR pszFileName ) |
182 | { |
183 | WRAPPER_NO_CONTRACT; |
184 | if (LoadDataFromPdb(pszFileName)) { |
185 | initialized_ = true; |
186 | } |
187 | else{ |
188 | initialized_ = false; |
189 | } |
190 | } |
191 | |
192 | ////////////////////////////////////////////////////////////////// |
193 | |
194 | HRESULT SourceLine::GetSourceLine( DWORD dwFunctionToken, DWORD dwOffset, __out_ecount(dwFileNameMaxLen) __out_z LPWSTR pszFileName, DWORD dwFileNameMaxLen, PDWORD pdwLineNumber ) |
195 | { |
196 | CONTRACTL { |
197 | THROWS; |
198 | GC_TRIGGERS; |
199 | MODE_ANY; |
200 | } CONTRACTL_END; |
201 | |
202 | _ASSERTE(initialized_); |
203 | |
204 | CComPtr(IDiaSymbol) pSymbol; |
205 | HRESULT hResult = pSession_->findSymbolByToken(dwFunctionToken, SymTagFunction, &pSymbol); |
206 | |
207 | if( SUCCEEDED(hResult) && pSymbol != NULL) { |
208 | |
209 | ULONGLONG length; |
210 | pSymbol->get_length(&length); |
211 | |
212 | DWORD rva; |
213 | CComPtr(IDiaEnumLineNumbers) pLines; |
214 | |
215 | if(SUCCEEDED(pSymbol->get_relativeVirtualAddress(&rva))) { |
216 | |
217 | DWORD initialOffset; |
218 | pSymbol->get_addressOffset(&initialOffset); |
219 | |
220 | DWORD isect; |
221 | pSymbol->get_addressSection(&isect); |
222 | |
223 | hResult = pSession_->findLinesByAddr(isect, initialOffset+dwOffset, 1, &pLines); |
224 | if( SUCCEEDED(hResult) ){ |
225 | |
226 | CComPtr(IDiaLineNumber) pLine; |
227 | |
228 | hResult = pLines->Item( 0, &pLine ); |
229 | |
230 | if(SUCCEEDED(hResult)){ |
231 | |
232 | pLine->get_lineNumber(pdwLineNumber); |
233 | |
234 | CComPtr(IDiaSourceFile) pSourceFile; |
235 | pLine->get_sourceFile( &pSourceFile ); |
236 | |
237 | BSTR sourceName; |
238 | pSourceFile->get_fileName( &sourceName ); |
239 | |
240 | wcsncpy_s( pszFileName, dwFileNameMaxLen, sourceName, dwFileNameMaxLen ); |
241 | } |
242 | } |
243 | } |
244 | } |
245 | |
246 | return hResult; |
247 | } |
248 | |
249 | ////////////////////////////////////////////////////////////////// |
250 | |
251 | HRESULT SourceLine::GetLocalName( DWORD dwFunctionToken, DWORD dwSlot, __out_ecount(dwNameMaxLen) __out_z LPWSTR pszName, DWORD dwNameMaxLen ) |
252 | { |
253 | CONTRACTL { |
254 | THROWS; |
255 | GC_TRIGGERS; |
256 | MODE_ANY; |
257 | } CONTRACTL_END; |
258 | |
259 | CComPtr(IDiaSymbol) pSymbol; |
260 | HRESULT hResult = pSession_->findSymbolByToken(dwFunctionToken, SymTagFunction, &pSymbol); |
261 | |
262 | if( SUCCEEDED(hResult) && pSymbol != NULL ) { |
263 | |
264 | ULONGLONG length; |
265 | pSymbol->get_length(&length); |
266 | |
267 | DWORD rva; |
268 | // CComPtr(IDiaEnumLineNumbers) pLines; |
269 | |
270 | hResult = pSymbol->get_relativeVirtualAddress(&rva); |
271 | |
272 | if(SUCCEEDED(hResult)) { |
273 | |
274 | CComPtr( IDiaSymbol ) pBlock; |
275 | hResult = pSession_->findSymbolByRVA( rva, SymTagBlock, &pBlock ); |
276 | |
277 | if( SUCCEEDED(hResult) && pBlock != NULL ) { |
278 | |
279 | ULONG celt = 0; |
280 | |
281 | CComPtr(IDiaSymbol) pLocalSymbol = NULL; |
282 | CComPtr( IDiaEnumSymbols ) pEnum; |
283 | hResult = pBlock->findChildren( SymTagData, NULL, nsNone, &pEnum ); |
284 | |
285 | if( SUCCEEDED(hResult) ) { |
286 | |
287 | // |
288 | // Find function local by slot |
289 | // |
290 | while (SUCCEEDED(hResult = pEnum->Next(1, &pLocalSymbol, &celt)) && celt == 1) { |
291 | |
292 | DWORD dwThisSlot; |
293 | pLocalSymbol->get_slot( &dwThisSlot ); |
294 | |
295 | if( dwThisSlot == dwSlot ) { |
296 | |
297 | BSTR name = NULL; |
298 | hResult = pLocalSymbol->get_name(&name); |
299 | |
300 | wcsncpy_s( pszName, dwNameMaxLen, name, _TRUNCATE ); |
301 | |
302 | return S_OK; |
303 | } |
304 | |
305 | pLocalSymbol = 0; |
306 | } |
307 | } |
308 | } |
309 | } |
310 | } |
311 | |
312 | return hResult; |
313 | } |
314 | |
315 | #else // !ENABLE_DIAGNOSTIC_SYMBOL_READING |
316 | SourceLine::SourceLine( __in_z LPWSTR pszFileName ) |
317 | { |
318 | LIMITED_METHOD_CONTRACT; |
319 | initialized_ = false; |
320 | } |
321 | |
322 | HRESULT SourceLine::GetSourceLine( DWORD dwFunctionToken, DWORD dwOffset, __out_ecount(dwFileNameMaxLen) __out_z LPWSTR pszFileName, DWORD dwFileNameMaxLen, PDWORD pdwLineNumber ) |
323 | { |
324 | LIMITED_METHOD_CONTRACT; |
325 | return E_NOTIMPL; |
326 | } |
327 | |
328 | HRESULT SourceLine::GetLocalName( DWORD dwFunctionToken, DWORD dwSlot, __out_ecount(dwNameMaxLen) __out_z LPWSTR pszName, DWORD dwNameMaxLen ) |
329 | { |
330 | LIMITED_METHOD_CONTRACT; |
331 | return E_NOTIMPL; |
332 | } |
333 | #endif // ENABLE_DIAGNOSTIC_SYMBOL_READING |
334 | |
335 | |