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
15class CCallback : public IDiaLoadCallback
16{
17 int m_nRefCount;
18public:
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
136bool 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
181SourceLine::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
194HRESULT 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
251HRESULT 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
316SourceLine::SourceLine( __in_z LPWSTR pszFileName )
317{
318 LIMITED_METHOD_CONTRACT;
319 initialized_ = false;
320}
321
322HRESULT 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
328HRESULT 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