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// File: symread.cpp
6//
7
8// ===========================================================================
9#include "pch.h"
10#include "symread.h"
11#include "corimage.h"
12
13#define CODE_WITH_NO_SOURCE 0xfeefee
14// -------------------------------------------------------------------------
15// SymReader class
16// -------------------------------------------------------------------------
17
18//-----------------------------------------------------------
19// NewSymReader
20// Static function used to create a new instance of SymReader
21//-----------------------------------------------------------
22HRESULT
23SymReader::NewSymReader(
24 REFCLSID clsid,
25 void** ppObj
26 )
27{
28 HRESULT hr = S_OK;
29 SymReader* pSymReader = NULL;
30
31 _ASSERTE(IsValidCLSID(clsid));
32 _ASSERTE(IsValidWritePtr(ppObj, IUnknown*));
33
34 if (clsid != IID_ISymUnmanagedReader)
35 return (E_UNEXPECTED);
36
37 IfFalseGo(ppObj, E_INVALIDARG);
38
39 *ppObj = NULL;
40 IfNullGo( pSymReader = NEW(SymReader()));
41
42 *ppObj = pSymReader;
43 pSymReader->AddRef();
44 pSymReader = NULL;
45
46ErrExit:
47
48 RELEASE( pSymReader );
49
50 return hr;
51}
52
53
54//-----------------------------------------------------------
55// ~SymReader
56//-----------------------------------------------------------
57SymReader::~SymReader()
58{
59 Cleanup();
60}
61
62//-----------------------------------------------------------
63// Cleanup
64// Release all memory and clear initialized data structures
65// (eg. as a result of a failed Initialization attempt)
66//-----------------------------------------------------------
67void SymReader::Cleanup()
68{
69 if (m_pDocs)
70 {
71 unsigned i;
72 for(i = 0; i < m_pPDBInfo->m_CountOfDocuments; i++)
73 {
74 RELEASE(m_pDocs[i]);
75 }
76 }
77
78 DELETE(m_pPDBInfo);
79 m_pPDBInfo = NULL;
80
81 // If we loaded from stream, then free the memory we allocated
82 if (m_fInitializeFromStream)
83 {
84 DELETEARRAY(m_DataPointers.m_pBytes);
85 DELETEARRAY(m_DataPointers.m_pConstants);
86 DELETEARRAY(m_DataPointers.m_pDocuments);
87 DELETEARRAY(m_DataPointers.m_pMethods);
88 DELETEARRAY(m_DataPointers.m_pScopes);
89 DELETEARRAY(m_DataPointers.m_pSequencePoints);
90 DELETEARRAY(m_DataPointers.m_pStringsBytes);
91 DELETEARRAY(m_DataPointers.m_pUsings);
92 DELETEARRAY(m_DataPointers.m_pVars);
93 }
94
95 DELETEARRAY(m_pDocs);
96 m_pDocs = NULL;
97
98 RELEASE(m_pImporter);
99 m_pImporter = NULL;
100
101 memset(&m_DataPointers, 0, sizeof(PDBDataPointers));
102 m_szPath[0] = '\0';
103}
104
105//-----------------------------------------------------------
106// ~QueryInterface
107//-----------------------------------------------------------
108HRESULT
109SymReader::QueryInterface(
110 REFIID riid,
111 void **ppvObject
112 )
113{
114 HRESULT hr = S_OK;
115
116 _ASSERTE(IsValidIID(riid));
117 _ASSERTE(IsValidWritePtr(ppvObject, void*));
118
119 IfFalseGo(ppvObject, E_INVALIDARG);
120 if (riid == IID_ISymUnmanagedReader)
121 {
122 *ppvObject = (ISymUnmanagedReader*) this;
123 }
124 else
125 if (riid == IID_IUnknown)
126 {
127 *ppvObject = (IUnknown*)this;
128 }
129 else
130 {
131 *ppvObject = NULL;
132 hr = E_NOINTERFACE;
133 }
134
135 if (*ppvObject)
136 {
137 AddRef();
138 }
139
140ErrExit:
141
142 return hr;
143}
144
145static HRESULT ReadFromStream(IStream *pIStream, void *pv, ULONG cb)
146{
147 HRESULT hr = NOERROR;
148 ULONG ulBytesRead;
149
150 IfFailGo(pIStream->Read(pv, cb, &ulBytesRead));
151 if (ulBytesRead != cb)
152 IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
153
154ErrExit:
155 return hr;
156}
157
158//-----------------------------------------------------------
159// Initialize
160// Pass in the required information to read in the debug info
161// If a stream is passed in, it is used, otherwise a filename
162// must be passed in
163//-----------------------------------------------------------
164HRESULT SymReader::Initialize(
165 IUnknown *importer, // Cash it to be consistent with CLR
166 const WCHAR* szFileName, // File name of the ildb
167 const WCHAR* szsearchPath, // Search Path
168 IStream *pIStream // IStream
169 )
170{
171 HRESULT hr = NOERROR;
172 _ASSERTE(szFileName || pIStream);
173 IfFalseGo(szFileName || pIStream, E_INVALIDARG );
174
175 _ASSERTE(!m_fInitialized);
176 IfFalseGo(!m_fInitialized, E_UNEXPECTED);
177
178 // If it's passed in, we need to AddRef to be consistent the
179 // desktop version since ReleaseImporterFromISymUnmanagedReader (ceeload.cpp)
180 // assumes there's an addref
181 if (importer)
182 {
183 m_pImporter = importer;
184 m_pImporter->AddRef();
185 }
186
187 // See if we're reading from a file or stream
188 if (pIStream == NULL)
189 {
190 // We're initializing from a file
191 m_fInitializeFromStream = false;
192 IfFailGo(InitializeFromFile(szFileName, szsearchPath));
193 }
194 else
195 {
196 // We're reading in from a stream
197 m_fInitializeFromStream = true;
198 IfFailGo(InitializeFromStream(pIStream));
199 }
200
201 // Note that up to this point, the data we've read in has not been validated. Since we don't trust
202 // our input, it's important that we don't proceed with using this data until validation has been
203 // successful.
204 IfFailGo(ValidateData());
205
206
207ErrExit:
208 // If we have not succeeded, then we need to clean up our data structures. This would allow a client to call
209 // Initialize again, but also ensures we can't possibly use partial or otherwise invalid (possibly
210 // malicious) data.
211 if (FAILED(hr))
212 {
213 Cleanup();
214 }
215 else
216 {
217 // Otherwise we are not properly initialized
218 m_fInitialized = true;
219 }
220
221 return hr;
222}
223
224//-----------------------------------------------------------
225// Initialize the data structures by reading from the supplied stream
226// Note that upon completion the data has not yet been validated for safety.
227//-----------------------------------------------------------
228HRESULT SymReader::InitializeFromStream(
229 IStream *pIStream // IStream
230 )
231{
232 GUID GuidVersion;
233 BYTE *pSignature;
234 HRESULT hr = S_OK;
235
236 // Reset the stream to the begining
237 LARGE_INTEGER li;
238 li.u.HighPart = 0;
239 li.u.LowPart = 0;
240
241 // Make sure we're at the beginning of the stream
242 IfFailGo(pIStream->Seek(li, STREAM_SEEK_SET, NULL));
243
244 IfNullGo(pSignature = (BYTE *)_alloca(ILDB_SIGNATURE_SIZE));
245 IfFailGo(ReadFromStream(pIStream, pSignature, ILDB_SIGNATURE_SIZE));
246
247 // Verify that we're looking at an ILDB File
248 if (memcmp(pSignature, ILDB_SIGNATURE, ILDB_SIGNATURE_SIZE))
249 {
250 IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
251 }
252
253 IfFailGo(ReadFromStream(pIStream, &GuidVersion, sizeof(GUID)));
254
255 SwapGuid(&GuidVersion);
256
257 if (memcmp(&GuidVersion, &ILDB_VERSION_GUID, sizeof(GUID)))
258 {
259 IfFailGo(HrFromWin32(ERROR_INVALID_DATA));
260 }
261
262 IfNullGo(m_pPDBInfo = NEW(PDBInfo));
263
264 memset(m_pPDBInfo, 0 , sizeof(PDBInfo));
265 IfFailGo(ReadFromStream(pIStream, m_pPDBInfo, sizeof(PDBInfo)));
266
267 // Swap the counts
268 m_pPDBInfo->ConvertEndianness();
269
270 if (m_pPDBInfo->m_CountOfConstants)
271 {
272 IfNullGo(m_DataPointers.m_pConstants = NEW(SymConstant[m_pPDBInfo->m_CountOfConstants]));
273 IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pConstants, m_pPDBInfo->m_CountOfConstants*sizeof(SymConstant)));
274 }
275
276 if (m_pPDBInfo->m_CountOfMethods)
277 {
278 IfNullGo(m_DataPointers.m_pMethods = NEW(SymMethodInfo[m_pPDBInfo->m_CountOfMethods]));
279 IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pMethods, m_pPDBInfo->m_CountOfMethods*sizeof(SymMethodInfo)));
280 }
281
282 if (m_pPDBInfo->m_CountOfScopes)
283 {
284 IfNullGo(m_DataPointers.m_pScopes = NEW(SymLexicalScope[m_pPDBInfo->m_CountOfScopes]));
285 IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pScopes, m_pPDBInfo->m_CountOfScopes*sizeof(SymLexicalScope)));
286 }
287
288 if (m_pPDBInfo->m_CountOfVars)
289 {
290 IfNullGo(m_DataPointers.m_pVars = NEW(SymVariable[m_pPDBInfo->m_CountOfVars]));
291 IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pVars, m_pPDBInfo->m_CountOfVars*sizeof(SymVariable)));
292 }
293
294 if (m_pPDBInfo->m_CountOfUsing)
295 {
296 IfNullGo(m_DataPointers.m_pUsings = NEW(SymUsingNamespace[m_pPDBInfo->m_CountOfUsing]));
297 IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pUsings, m_pPDBInfo->m_CountOfUsing*sizeof(SymUsingNamespace)));
298 }
299
300 if (m_pPDBInfo->m_CountOfSequencePoints)
301 {
302 IfNullGo(m_DataPointers.m_pSequencePoints = NEW(SequencePoint[m_pPDBInfo->m_CountOfSequencePoints]));
303 IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pSequencePoints, m_pPDBInfo->m_CountOfSequencePoints*sizeof(SequencePoint)));
304 }
305
306 if (m_pPDBInfo->m_CountOfDocuments)
307 {
308 IfNullGo(m_DataPointers.m_pDocuments = NEW(DocumentInfo[m_pPDBInfo->m_CountOfDocuments]));
309 IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pDocuments, m_pPDBInfo->m_CountOfDocuments*sizeof(DocumentInfo)));
310 }
311
312 if (m_pPDBInfo->m_CountOfBytes)
313 {
314 IfNullGo(m_DataPointers.m_pBytes = NEW(BYTE[m_pPDBInfo->m_CountOfBytes]));
315 IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pBytes, m_pPDBInfo->m_CountOfBytes*sizeof(BYTE)));
316 }
317
318
319 if (m_pPDBInfo->m_CountOfStringBytes)
320 {
321 IfNullGo(m_DataPointers.m_pStringsBytes = NEW(BYTE[m_pPDBInfo->m_CountOfStringBytes]));
322 IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pStringsBytes, m_pPDBInfo->m_CountOfStringBytes));
323 }
324
325ErrExit:
326 return hr;
327}
328
329//-----------------------------------------------------------
330// ValidateData
331// Checks the contents of everything in m_DataPointers (i.e. all the structures read from the file)
332// to make sure it is valid. Specifically, validates that all indexes are within bounds for the
333// sizes allocated.
334//-----------------------------------------------------------
335HRESULT SymReader::ValidateData()
336{
337 HRESULT hr = S_OK;
338
339 for (UINT32 i = 0; i < m_pPDBInfo->m_CountOfConstants; i++)
340 {
341 SymConstant & c = m_DataPointers.m_pConstants[i];
342 IfFalseGo(c.ParentScope() < m_pPDBInfo->m_CountOfScopes, HrFromWin32(ERROR_BAD_FORMAT));
343 IfFalseGo(c.Name() < m_pPDBInfo->m_CountOfStringBytes, HrFromWin32(ERROR_BAD_FORMAT));
344 IfFailGo(ValidateBytes(c.Signature(), c.SignatureSize()));
345 }
346
347 for (UINT32 i = 0; i < m_pPDBInfo->m_CountOfMethods; i++)
348 {
349 // Note that start/end values may equal the count (i.e. point one past the end) because
350 // the end is the extent, and start can equal end to indicate no entries.
351 SymMethodInfo & m = m_DataPointers.m_pMethods[i];
352 IfFalseGo(m.StartScopes() <= m_pPDBInfo->m_CountOfScopes, HrFromWin32(ERROR_BAD_FORMAT));
353 IfFalseGo(m.EndScopes() <= m_pPDBInfo->m_CountOfScopes, HrFromWin32(ERROR_BAD_FORMAT));
354 IfFalseGo(m.StartScopes() <= m.EndScopes(), HrFromWin32(ERROR_BAD_FORMAT));
355 IfFalseGo(m.StartVars() <= m_pPDBInfo->m_CountOfVars, HrFromWin32(ERROR_BAD_FORMAT));
356 IfFalseGo(m.EndVars() <= m_pPDBInfo->m_CountOfVars, HrFromWin32(ERROR_BAD_FORMAT));
357 IfFalseGo(m.StartVars() <= m.EndVars(), HrFromWin32(ERROR_BAD_FORMAT));
358 IfFalseGo(m.StartUsing() <= m_pPDBInfo->m_CountOfUsing, HrFromWin32(ERROR_BAD_FORMAT));
359 IfFalseGo(m.EndUsing() <= m_pPDBInfo->m_CountOfUsing, HrFromWin32(ERROR_BAD_FORMAT));
360 IfFalseGo(m.StartUsing() <= m.EndUsing(), HrFromWin32(ERROR_BAD_FORMAT));
361 IfFalseGo(m.StartConstant() <= m_pPDBInfo->m_CountOfConstants, HrFromWin32(ERROR_BAD_FORMAT));
362 IfFalseGo(m.EndConstant() <= m_pPDBInfo->m_CountOfConstants, HrFromWin32(ERROR_BAD_FORMAT));
363 IfFalseGo(m.StartConstant() <= m.EndConstant(), HrFromWin32(ERROR_BAD_FORMAT));
364 IfFalseGo(m.StartDocuments() <= m_pPDBInfo->m_CountOfDocuments, HrFromWin32(ERROR_BAD_FORMAT));
365 IfFalseGo(m.EndDocuments() <= m_pPDBInfo->m_CountOfDocuments, HrFromWin32(ERROR_BAD_FORMAT));
366 IfFalseGo(m.StartDocuments() <= m.EndDocuments(), HrFromWin32(ERROR_BAD_FORMAT));
367 IfFalseGo(m.StartSequencePoints() <= m_pPDBInfo->m_CountOfSequencePoints, HrFromWin32(ERROR_BAD_FORMAT));
368 IfFalseGo(m.EndSequencePoints() <= m_pPDBInfo->m_CountOfSequencePoints, HrFromWin32(ERROR_BAD_FORMAT));
369 IfFalseGo(m.StartSequencePoints() <= m.EndSequencePoints(), HrFromWin32(ERROR_BAD_FORMAT));
370 }
371
372 for (UINT32 i = 0; i < m_pPDBInfo->m_CountOfScopes; i++)
373 {
374 SymLexicalScope & s = m_DataPointers.m_pScopes[i];
375 IfFalseGo((s.ParentScope() == (UINT32)-1) || (s.ParentScope() < m_pPDBInfo->m_CountOfScopes), HrFromWin32(ERROR_BAD_FORMAT));
376 }
377
378 for (UINT32 i = 0; i < m_pPDBInfo->m_CountOfVars; i++)
379 {
380 SymVariable & v = m_DataPointers.m_pVars[i];
381 IfFalseGo(v.Scope() < m_pPDBInfo->m_CountOfScopes, HrFromWin32(ERROR_BAD_FORMAT));
382 IfFalseGo(v.Name() < m_pPDBInfo->m_CountOfStringBytes, HrFromWin32(ERROR_BAD_FORMAT));
383 IfFailGo(ValidateBytes(v.Signature(), v.SignatureSize()));
384 }
385
386 for (UINT32 i = 0; i < m_pPDBInfo->m_CountOfUsing; i++)
387 {
388 SymUsingNamespace & u = m_DataPointers.m_pUsings[i];
389 IfFalseGo(u.ParentScope() < m_pPDBInfo->m_CountOfScopes, HrFromWin32(ERROR_BAD_FORMAT));
390 IfFalseGo(u.Name() < m_pPDBInfo->m_CountOfStringBytes, HrFromWin32(ERROR_BAD_FORMAT));
391 }
392
393 for (UINT32 i = 0; i < m_pPDBInfo->m_CountOfSequencePoints; i++)
394 {
395 SequencePoint & s = m_DataPointers.m_pSequencePoints[i];
396 IfFalseGo(s.Document() < m_pPDBInfo->m_CountOfDocuments, HrFromWin32(ERROR_BAD_FORMAT));
397 }
398
399 for (UINT32 i = 0; i < m_pPDBInfo->m_CountOfDocuments; i++)
400 {
401 DocumentInfo & d = m_DataPointers.m_pDocuments[i];
402 IfFailGo(ValidateBytes(d.CheckSumEntry(), d.CheckSumSize()));
403 IfFailGo(ValidateBytes(d.SourceEntry(), d.SourceSize()));
404 IfFalseGo(d.UrlEntry() < m_pPDBInfo->m_CountOfStringBytes, HrFromWin32(ERROR_BAD_FORMAT));
405 }
406
407 // Nothing to validate for the m_pBytes array - each reference must validate above that it's
408 // length doesn't exceed the array
409
410 // We expect all strings to be null terminated. To ensure no string operation overruns the buffer
411 // it sufficies to check that the buffer ends in a null character
412 if (m_pPDBInfo->m_CountOfStringBytes > 0)
413 {
414 IfFalseGo(m_DataPointers.m_pStringsBytes[m_pPDBInfo->m_CountOfStringBytes-1] == '\0', HrFromWin32(ERROR_BAD_FORMAT));
415 }
416
417ErrExit:
418 return hr;
419}
420
421//-----------------------------------------------------------
422// Validate a reference to the bytes array
423//-----------------------------------------------------------
424HRESULT SymReader::ValidateBytes(UINT32 bytesIndex, UINT32 bytesLen)
425{
426 S_UINT32 extent = S_UINT32(bytesIndex) + S_UINT32(bytesLen);
427 if (!extent.IsOverflow() &&
428 (extent.Value() <= m_pPDBInfo->m_CountOfBytes))
429 {
430 return S_OK;
431 }
432
433 return HrFromWin32(ERROR_BAD_FORMAT);
434}
435
436//-----------------------------------------------------------
437// VerifyPEDebugInfo
438// Verify that the debug info in the PE is the one we want
439//-----------------------------------------------------------
440HRESULT SymReader::VerifyPEDebugInfo(const WCHAR* szFileName)
441{
442 HRESULT hr = E_FAIL;
443 HANDLE hFile = INVALID_HANDLE_VALUE;
444 HANDLE hMapFile = INVALID_HANDLE_VALUE;
445 BYTE *pMod = NULL;
446 DWORD dwFileSize;
447 IMAGE_DEBUG_DIRECTORY *pDebugDir;
448 RSDSI *pDebugInfo;
449 DWORD dwUtf8Length;
450 DWORD dwUnicodeLength;
451
452 // We need to change the .pdb extension to .ildb
453 // compatible with VS7
454 wchar_t fullpath[_MAX_PATH];
455 wchar_t drive[_MAX_DRIVE];
456 wchar_t dir[_MAX_DIR];
457 wchar_t fname[_MAX_FNAME];
458
459 IMAGE_NT_HEADERS*pNT;
460
461 hFile = WszCreateFile(szFileName,
462 GENERIC_READ,
463 FILE_SHARE_READ,
464 NULL,
465 OPEN_EXISTING,
466 FILE_ATTRIBUTE_NORMAL,
467 NULL);
468
469 if (hFile == INVALID_HANDLE_VALUE)
470 {
471 // Get the last error if we can
472 return HrFromWin32(GetLastError());
473 }
474
475 dwFileSize = GetFileSize(hFile, NULL);
476 if (dwFileSize < ILDB_HEADER_SIZE)
477 {
478 IfFailGo(HrFromWin32(ERROR_INVALID_DATA));
479 }
480
481 hMapFile = WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
482 if (hMapFile == NULL)
483 IfFailGo(HrFromWin32(GetLastError()));
484
485 pMod = (BYTE *) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
486 if (pMod == NULL)
487 IfFailGo(HrFromWin32(GetLastError()));
488
489 pNT = Cor_RtlImageNtHeader(pMod, dwFileSize);
490
491 // If there is no DebugEntry, then just error out
492 if (VAL32(pNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) == 0)
493 IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
494
495 // NOTE: This code is not secure against malformed PE files - any of the pointer additions below
496 // may be outside the range of memory mapped for the file. If we ever want to use this code
497 // on untrusted PE files, we should properly validate everything (probably by using PEDecoder).
498
499 DWORD offset;
500 offset = Cor_RtlImageRvaToOffset(pNT, VAL32(pNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress), dwFileSize);
501 if (offset == NULL)
502 IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
503 pDebugDir = (IMAGE_DEBUG_DIRECTORY *)(pMod + offset);
504 pDebugInfo = (RSDSI *)(pMod + VAL32(pDebugDir->PointerToRawData));
505
506 if (pDebugInfo->dwSig != VAL32(0x53445352)) // "SDSR"
507 {
508 IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
509 }
510
511
512 // Try the returned Stored Name since it might be a fully qualified path
513 dwUtf8Length = VAL32(pDebugDir->SizeOfData) - sizeof(RSDSI);
514 dwUnicodeLength = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR) pDebugInfo->szPDB, dwUtf8Length, fullpath, COUNTOF(fullpath) - 1);
515
516 // Make sure it's NULL terminated
517 _ASSERTE(dwUnicodeLength < COUNTOF(fullpath));
518 fullpath[dwUnicodeLength]='\0';
519
520 // Replace the extension with ildb
521 if (_wsplitpath_s( fullpath, drive, COUNTOF(drive), dir, COUNTOF(dir), fname, COUNTOF(fname), NULL, 0 ))
522 IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
523 if (_wmakepath_s(m_szStoredSymbolName, MAX_LONGPATH, drive, dir, fname, W("ildb") ))
524 IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
525
526 // It looks valid, make sure to set the return code
527 hr = S_OK;
528ErrExit:
529 if (pMod)
530 UnmapViewOfFile(pMod);
531 if (hMapFile != INVALID_HANDLE_VALUE)
532 CloseHandle(hMapFile);
533 if (hFile != INVALID_HANDLE_VALUE)
534 CloseHandle(hFile);
535 return hr;
536
537}
538
539//-----------------------------------------------------------
540// InitializeFromFile
541// Initialize the reader using the passed in file name
542// Note that upon completion the data hasn't yet been validated for safety.
543//-----------------------------------------------------------
544HRESULT
545SymReader::InitializeFromFile(
546 const WCHAR* szFileName,
547 const WCHAR* szsearchPath)
548{
549 HRESULT hr = S_OK;
550 wchar_t fullpath[_MAX_PATH];
551 wchar_t drive[_MAX_DRIVE];
552 wchar_t dir[_MAX_DIR];
553 wchar_t fname[_MAX_FNAME];
554 HANDLE hFile = INVALID_HANDLE_VALUE;
555 HANDLE hMapFile = INVALID_HANDLE_VALUE;
556 HMODULE hMod = NULL;
557 BYTE *CurrentOffset;
558 DWORD dwFileSize;
559 S_UINT32 dwDataSize;
560 GUID VersionInfo;
561
562 _ASSERTE(szFileName);
563 IfFalseGo(szFileName, E_INVALIDARG );
564
565 IfFailGo(VerifyPEDebugInfo(szFileName));
566 // We need to open the exe and check to see if the DebugInfo matches
567
568 if (_wsplitpath_s( szFileName, drive, COUNTOF(drive), dir, COUNTOF(dir), fname, COUNTOF(fname), NULL, 0 ))
569 IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
570 if (_wmakepath_s( fullpath, _MAX_PATH, drive, dir, fname, W("ildb") ))
571 IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
572 if (wcsncpy_s( m_szPath, COUNTOF(m_szPath), fullpath, _TRUNCATE) == STRUNCATE)
573 IfFailGo(HrFromWin32(ERROR_INSUFFICIENT_BUFFER));
574
575 hFile = WszCreateFile(m_szPath,
576 GENERIC_READ,
577 FILE_SHARE_READ,
578 NULL,
579 OPEN_EXISTING,
580 FILE_ATTRIBUTE_NORMAL,
581 NULL);
582
583 if (hFile == INVALID_HANDLE_VALUE)
584 {
585
586 // If the stored string is empty, don't do anything
587 if (m_szStoredSymbolName[0] == '\0')
588 {
589 return HrFromWin32(GetLastError());
590 }
591
592 if (_wsplitpath_s( m_szStoredSymbolName, drive, COUNTOF(drive), dir, COUNTOF(dir), fname, COUNTOF(fname), NULL, 0 ))
593 IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
594 if (_wmakepath_s( fullpath, _MAX_PATH, drive, dir, fname, W("ildb") ))
595 IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
596 if (wcsncpy_s( m_szPath, COUNTOF(m_szPath), fullpath, _TRUNCATE) == STRUNCATE)
597 IfFailGo(HrFromWin32(ERROR_INSUFFICIENT_BUFFER));
598
599 hFile = WszCreateFile(m_szPath,
600 GENERIC_READ,
601 FILE_SHARE_READ,
602 NULL,
603 OPEN_EXISTING,
604 FILE_ATTRIBUTE_NORMAL,
605 NULL);
606
607 if (hFile == INVALID_HANDLE_VALUE)
608 {
609 return HrFromWin32(GetLastError());
610 }
611 }
612
613 dwFileSize = GetFileSize(hFile, NULL);
614 if (dwFileSize < ILDB_HEADER_SIZE)
615 {
616 IfFailGo(HrFromWin32(ERROR_INVALID_DATA));
617 }
618
619 hMapFile = WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
620 if (hMapFile == NULL)
621 IfFailGo(HrFromWin32(GetLastError()));
622
623 hMod = (HMODULE) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
624 if (hMod == NULL)
625 IfFailGo(HrFromWin32(GetLastError()));
626
627 // We've opened the file, now let's get the pertinent info
628 CurrentOffset = (BYTE *)hMod;
629
630 // Verify that we're looking at an ILDB File
631 if (memcmp(CurrentOffset, ILDB_SIGNATURE, ILDB_SIGNATURE_SIZE))
632 {
633 IfFailGo(E_FAIL);
634 }
635 CurrentOffset += ILDB_SIGNATURE_SIZE;
636
637 memcpy( &VersionInfo, CurrentOffset, sizeof(GUID));
638 SwapGuid( &VersionInfo );
639 CurrentOffset += sizeof(GUID);
640
641 if (memcmp(&VersionInfo, &ILDB_VERSION_GUID, sizeof(GUID)))
642 {
643 IfFailGo(HrFromWin32(ERROR_INVALID_DATA));
644 }
645
646 IfNullGo(m_pPDBInfo = NEW(PDBInfo));
647
648 memcpy(m_pPDBInfo, CurrentOffset, sizeof(PDBInfo));
649
650 // Swap the counts
651 m_pPDBInfo->ConvertEndianness();
652
653 // Check to make sure we have enough data to be read in.
654 dwDataSize = S_UINT32(ILDB_HEADER_SIZE);
655 dwDataSize += m_pPDBInfo->m_CountOfConstants*sizeof(SymConstant);
656 dwDataSize += m_pPDBInfo->m_CountOfMethods * sizeof(SymMethodInfo);
657 dwDataSize += m_pPDBInfo->m_CountOfScopes*sizeof(SymLexicalScope);
658 dwDataSize += m_pPDBInfo->m_CountOfVars*sizeof(SymVariable);
659 dwDataSize += m_pPDBInfo->m_CountOfUsing*sizeof(SymUsingNamespace);
660 dwDataSize += m_pPDBInfo->m_CountOfSequencePoints*sizeof(SequencePoint);
661 dwDataSize += m_pPDBInfo->m_CountOfDocuments*sizeof(DocumentInfo);
662 dwDataSize += m_pPDBInfo->m_CountOfBytes*sizeof(BYTE);
663 dwDataSize += m_pPDBInfo->m_CountOfStringBytes*sizeof(BYTE);
664
665 if (dwDataSize.IsOverflow() || dwDataSize.Value() > dwFileSize)
666 {
667 IfFailGo(HrFromWin32(ERROR_INVALID_DATA));
668 }
669
670 CurrentOffset += sizeof(PDBInfo);
671
672 if (m_pPDBInfo->m_CountOfConstants)
673 {
674 m_DataPointers.m_pConstants = (SymConstant*)CurrentOffset;
675 CurrentOffset += (m_pPDBInfo->m_CountOfConstants*sizeof(SymConstant));
676 }
677
678 if (m_pPDBInfo->m_CountOfMethods)
679 {
680 m_DataPointers.m_pMethods = (SymMethodInfo *)CurrentOffset;
681 CurrentOffset += (m_pPDBInfo->m_CountOfMethods*sizeof(SymMethodInfo));
682 }
683
684 if (m_pPDBInfo->m_CountOfScopes)
685 {
686 m_DataPointers.m_pScopes = (SymLexicalScope *)CurrentOffset;
687 CurrentOffset += (m_pPDBInfo->m_CountOfScopes*sizeof(SymLexicalScope));
688 }
689
690 if (m_pPDBInfo->m_CountOfVars)
691 {
692 m_DataPointers.m_pVars = (SymVariable *)CurrentOffset;
693 CurrentOffset += (m_pPDBInfo->m_CountOfVars*sizeof(SymVariable));
694 }
695
696 if (m_pPDBInfo->m_CountOfUsing)
697 {
698 m_DataPointers.m_pUsings = (SymUsingNamespace *)CurrentOffset;
699 CurrentOffset += (m_pPDBInfo->m_CountOfUsing*sizeof(SymUsingNamespace));
700 }
701
702 if (m_pPDBInfo->m_CountOfSequencePoints)
703 {
704 m_DataPointers.m_pSequencePoints = (SequencePoint*)CurrentOffset;
705 CurrentOffset += (m_pPDBInfo->m_CountOfSequencePoints*sizeof(SequencePoint));
706 }
707
708 if (m_pPDBInfo->m_CountOfDocuments)
709 {
710 m_DataPointers.m_pDocuments = (DocumentInfo*)CurrentOffset;
711 CurrentOffset += (m_pPDBInfo->m_CountOfDocuments*sizeof(DocumentInfo));
712 }
713
714 if (m_pPDBInfo->m_CountOfBytes)
715 {
716 m_DataPointers.m_pBytes = (BYTE*)CurrentOffset;
717 CurrentOffset += (m_pPDBInfo->m_CountOfBytes*sizeof(BYTE));
718 }
719
720 if (m_pPDBInfo->m_CountOfStringBytes)
721 {
722 m_DataPointers.m_pStringsBytes = (BYTE*)CurrentOffset;
723 }
724
725ErrExit:
726
727 return hr;
728}
729
730//-----------------------------------------------------------
731// GetDocument
732// Get the document for the passed in information
733//-----------------------------------------------------------
734HRESULT
735SymReader::GetDocument(
736 __in LPWSTR wcsUrl, // URL of the document
737 GUID language, // Language for the file
738 GUID languageVendor, // Language vendor
739 GUID documentType, // Type of document
740 ISymUnmanagedDocument **ppRetVal // [out] Document
741 )
742{
743 HRESULT hr = S_OK;
744 unsigned i;
745 SymDocument* pDoc = NULL;
746 WCHAR *wcsDocumentUrl = NULL;
747 WCHAR *wcsDocumentUrlAlloc = NULL;
748
749 _ASSERTE(m_fInitialized);
750 IfFalseGo(m_fInitialized, E_UNEXPECTED);
751
752 _ASSERTE(ppRetVal && wcsUrl);
753 IfFalseGo(ppRetVal, E_INVALIDARG);
754 IfFalseGo(wcsUrl, E_INVALIDARG);
755
756 // Init Out Parameter
757 *ppRetVal = NULL;
758
759 for (i = 0; i < m_pPDBInfo->m_CountOfDocuments; i++)
760 {
761 int cchName;
762
763 // Convert the UTF8 string to Wide
764 cchName = (ULONG32) MultiByteToWideChar(CP_UTF8,
765 0,
766 (LPCSTR)&(m_DataPointers.m_pStringsBytes[m_DataPointers.m_pDocuments[i].UrlEntry()]),
767 -1,
768 0,
769 NULL);
770 IfNullGo( wcsDocumentUrlAlloc = NEW(WCHAR[cchName]) );
771
772 cchName = (ULONG32) MultiByteToWideChar(CP_UTF8,
773 0,
774 (LPCSTR)&(m_DataPointers.m_pStringsBytes[m_DataPointers.m_pDocuments[i].UrlEntry()]),
775 -1,
776 wcsDocumentUrlAlloc,
777 cchName);
778 wcsDocumentUrl = wcsDocumentUrlAlloc;
779
780 // Compare the url
781 if (wcscmp(wcsUrl, wcsDocumentUrl) == 0)
782 {
783 IfFailGo(GetDocument(i, &pDoc));
784 break;
785 }
786 DELETEARRAY(wcsDocumentUrlAlloc);
787 wcsDocumentUrlAlloc = NULL;
788 }
789
790 if (pDoc)
791 {
792 IfFailGo( pDoc->QueryInterface( IID_ISymUnmanagedDocument,
793 (void**) ppRetVal ) );
794 }
795
796ErrExit:
797 DELETEARRAY(wcsDocumentUrlAlloc);
798
799 RELEASE( pDoc );
800
801 return hr;
802}
803
804//-----------------------------------------------------------
805// GetDocuments
806// Get the documents for this reader
807//-----------------------------------------------------------
808HRESULT
809SymReader::GetDocuments(
810 ULONG32 cDocs,
811 ULONG32 *pcDocs,
812 ISymUnmanagedDocument *pDocs[]
813 )
814{
815 HRESULT hr = S_OK;
816 unsigned cDocCount = 0;
817
818 _ASSERTE(m_fInitialized);
819 IfFalseGo(m_fInitialized, E_UNEXPECTED);
820
821 _ASSERTE(pDocs || pcDocs);
822 IfFalseGo(pDocs || pcDocs, E_INVALIDARG);
823
824 cDocs = min(cDocs, m_pPDBInfo->m_CountOfDocuments);
825
826 for (cDocCount = 0; cDocCount < cDocs; cDocCount++)
827 {
828 if (pDocs)
829 {
830 SymDocument *pDoc;
831 IfFailGo(GetDocument(cDocCount, &pDoc));
832 pDocs[cDocCount] = pDoc;
833 }
834 }
835 if (pcDocs)
836 {
837 *pcDocs = (ULONG32)m_pPDBInfo->m_CountOfDocuments;
838 }
839
840ErrExit:
841 if (FAILED(hr))
842 {
843 unsigned i;
844 for (i = 0; i < cDocCount; i++)
845 {
846 RELEASE(pDocs[cDocCount]);
847 }
848 }
849 return hr;
850}
851
852//-----------------------------------------------------------
853// GetUserEntryPoint
854// Get the entry point for the pe
855//-----------------------------------------------------------
856HRESULT
857SymReader::GetUserEntryPoint(
858 mdMethodDef *pRetVal
859 )
860{
861 HRESULT hr = S_OK;
862
863 _ASSERTE(m_fInitialized);
864 IfFalseGo(m_fInitialized, E_UNEXPECTED);
865
866 _ASSERTE(pRetVal);
867 IfFalseGo(pRetVal, E_INVALIDARG);
868
869 // If it wasn't set then return E_FAIL
870 if (m_pPDBInfo->m_userEntryPoint == mdTokenNil)
871 {
872 hr = E_FAIL;
873 }
874 else
875 {
876 *pRetVal = m_pPDBInfo->m_userEntryPoint;
877 }
878ErrExit:
879 return hr;
880}
881
882// Compare the method token with the SymMethodInfo Entry and return the
883// value expected by bsearch
884int __cdecl CompareMethodToToken(const void *pMethodToken, const void *pMethodInfoEntry)
885{
886 mdMethodDef MethodDef = *(mdMethodDef *)pMethodToken;
887 SymMethodInfo *pMethodInfo = (SymMethodInfo *)pMethodInfoEntry;
888
889 return MethodDef - pMethodInfo->MethodToken();
890}
891
892//-----------------------------------------------------------
893// GetMethod
894// Get the method for the methoddef
895//-----------------------------------------------------------
896HRESULT
897SymReader::GetMethod(
898 mdMethodDef method, // MethodDef
899 ISymUnmanagedMethod **ppRetVal // [out] Method
900 )
901{
902 HRESULT hr = S_OK;
903 UINT32 MethodEntry = 0;
904 SymMethodInfo *pMethodInfo;
905 SymMethod * pMethod = NULL;
906
907 _ASSERTE(m_fInitialized);
908 IfFalseGo(m_fInitialized, E_UNEXPECTED);
909
910 _ASSERTE(ppRetVal);
911 IfFalseGo(ppRetVal, E_INVALIDARG);
912
913 pMethodInfo = (SymMethodInfo *)bsearch(&method, m_DataPointers.m_pMethods, m_pPDBInfo->m_CountOfMethods, sizeof(SymMethodInfo), CompareMethodToToken);
914 IfFalseGo(pMethodInfo, E_FAIL); // no matching method found
915
916 // Found a match
917 MethodEntry = UINT32 (pMethodInfo - m_DataPointers.m_pMethods);
918 _ASSERTE(m_DataPointers.m_pMethods[MethodEntry].MethodToken() == method);
919 IfNullGo( pMethod = NEW(SymMethod(this, &m_DataPointers, MethodEntry)) );
920 *ppRetVal = pMethod;
921 pMethod->AddRef();
922 hr = S_OK;
923
924ErrExit:
925 return hr;
926}
927
928//-----------------------------------------------------------
929// GetMethodByVersion
930//-----------------------------------------------------------
931HRESULT
932SymReader::GetMethodByVersion(
933 mdMethodDef method,
934 int version,
935 ISymUnmanagedMethod **ppRetVal
936 )
937{
938 // Don't support multiple version of the same Method so just
939 // call GetMethod
940 return GetMethod(method, ppRetVal);
941}
942
943
944//-----------------------------------------------------------
945// GetMethodFromDocumentPosition
946//-----------------------------------------------------------
947HRESULT
948SymReader::GetMethodFromDocumentPosition(
949 ISymUnmanagedDocument *document,
950 ULONG32 line,
951 ULONG32 column,
952 ISymUnmanagedMethod **ppRetVal
953)
954{
955 HRESULT hr = S_OK;
956 UINT32 DocumentEntry;
957 UINT32 Method;
958 UINT32 point;
959 SequencePoint *pSequencePointBefore;
960 SequencePoint *pSequencePointAfter;
961 bool found = false;
962
963 _ASSERTE(m_fInitialized);
964 IfFalseGo(m_fInitialized, E_UNEXPECTED);
965
966 _ASSERTE(document && ppRetVal);
967 IfFalseGo(document, E_INVALIDARG);
968 IfFalseGo(ppRetVal, E_INVALIDARG);
969
970 DocumentEntry = ((SymDocument *)document)->GetDocumentEntry();
971
972 // Init out parameter
973 *ppRetVal = NULL;
974
975 // Walk all Methods, check their Document and SequencePoints to see if it's in this doc
976 // and the line/column
977
978 // This function returns the first match if more than one methods cover the specified position.
979 for (Method = 0; Method < m_pPDBInfo->m_CountOfMethods; Method++)
980 {
981 pSequencePointBefore = NULL;
982 pSequencePointAfter = NULL;
983
984 // Walk the sequence points
985 for (point = m_DataPointers.m_pMethods[Method].StartSequencePoints();
986 point < m_DataPointers.m_pMethods[Method].EndSequencePoints();
987 point++)
988 {
989 // Check to see if this sequence point is in this doc
990 if (m_DataPointers.m_pSequencePoints[point].Document() == DocumentEntry)
991 {
992 // If the point is position is within the sequence point then
993 // we're done.
994 if (m_DataPointers.m_pSequencePoints[point].IsWithin(line, column))
995 {
996 IfFailGo(GetMethod(m_DataPointers.m_pMethods[Method].MethodToken(), ppRetVal));
997 found = true;
998 break;
999 }
1000
1001 // If the sequence is before the point then just remember the point
1002 if (m_DataPointers.m_pSequencePoints[point].IsUserLine() &&
1003 m_DataPointers.m_pSequencePoints[point].IsLessThan(line, column))
1004 {
1005 pSequencePointBefore = &m_DataPointers.m_pSequencePoints[point];
1006 }
1007
1008 // If the sequence is before the point then just remember the point
1009 if (m_DataPointers.m_pSequencePoints[point].IsUserLine() &&
1010 m_DataPointers.m_pSequencePoints[point].IsGreaterThan(line, column))
1011 {
1012 pSequencePointAfter = &m_DataPointers.m_pSequencePoints[point];
1013 }
1014 }
1015 }
1016
1017 // If we found an exact match, we're done.
1018 if (found)
1019 {
1020 break;
1021 }
1022
1023 // If we found sequence points within the method before and after
1024 // the line/column then we may have found the method. Record the return value, but keep looking
1025 // to see if we find an exact match. This may not actually be the right method. Iron Python, for instance,
1026 // issues a "method" containing sequence points for all the method headers in a class. Sequence points
1027 // in this "method" would then span the sequence points in the bodies of all but the last method.
1028 if (pSequencePointBefore && pSequencePointAfter)
1029 {
1030 IfFailGo(GetMethod(m_DataPointers.m_pMethods[Method].MethodToken(), ppRetVal));
1031 }
1032 }
1033
1034 // This function returns E_FAIL if no match is found.
1035 // Note that this is different from the behaviour of GetMethodsFromDocumentPosition() (see below).
1036 if (*ppRetVal == NULL)
1037 {
1038 hr = E_FAIL;
1039 }
1040
1041ErrExit:
1042 return hr;
1043}
1044
1045//---------------------------------------------------------------------------------------
1046//
1047// Return all methods with sequence points covering the specified source location. This
1048// is actually not as straighforward as it sounds, since we need to mimic the behaviour of
1049// diasymreader and PDBs here. For PDBs, diasymreader actually does two passes over the
1050// sequence points. It tries to find an exact match in the first pass, and if that fails,
1051// it'll do a second pass looking for an approximate match. An approximate match is a sequence
1052// point which doesn't start on the specified line but covers it. If there's an exact match,
1053// then it ignores all the approximate matches. In both cases, diasymreader only checks the
1054// start line number of the sequence point and it ignores the column number.
1055//
1056// For backward compatibility, I'm leaving GetMethodFromDocumentPosition() unchanged.
1057//
1058
1059HRESULT
1060SymReader::GetMethodsFromDocumentPosition(
1061 ISymUnmanagedDocument *document,
1062 ULONG32 line,
1063 ULONG32 column,
1064 ULONG32 cMethod,
1065 ULONG32* pcMethod, //[Optional]: How many method actually returned
1066 ISymUnmanagedMethod** ppRetVal
1067 )
1068{
1069 HRESULT hr = S_OK;
1070 UINT32 DocumentEntry;
1071 UINT32 Method;
1072 UINT32 point;
1073
1074 UINT CurMethod = 0;
1075 bool found = false;
1076 bool fExactMatch = true;
1077
1078 ULONG32 maxPreLine = 0;
1079
1080 _ASSERTE(m_fInitialized);
1081 IfFalseGo(m_fInitialized, E_UNEXPECTED);
1082
1083 _ASSERTE(document);
1084 IfFalseGo(document, E_INVALIDARG);
1085
1086 _ASSERTE((cMethod == 0) || (ppRetVal != NULL));
1087 IfFalseGo(cMethod == 0 || ppRetVal != NULL, E_INVALIDARG);
1088
1089 // Initialize the out parameter if it has been provided.
1090 if (pcMethod != NULL)
1091 {
1092 *pcMethod = 0;
1093 }
1094
1095 DocumentEntry = ((SymDocument *)document)->GetDocumentEntry();
1096
1097 // Enumerate the sequence points in two passes.
1098 while (true)
1099 {
1100 // Walk all Methods, check their Document and SequencePoints to see if it's in this doc
1101 // and the line/column
1102
1103 for (Method = 0; Method < m_pPDBInfo->m_CountOfMethods; Method++)
1104 {
1105 found = false;
1106
1107 // Walk the sequence points
1108 for (point = m_DataPointers.m_pMethods[Method].StartSequencePoints();
1109 point < m_DataPointers.m_pMethods[Method].EndSequencePoints();
1110 point++)
1111 {
1112 // Check to see if this sequence point is in this doc
1113 if (m_DataPointers.m_pSequencePoints[point].Document() == DocumentEntry)
1114 {
1115 // PDBs (more specifically the DIA APIs) only check the start line number and not the end line number when
1116 // trying to determine whether a sequence point covers the specified line number. We need to match this
1117 // behaviour here. For backward compatibility reasons, GetMethodFromDocumentPosition() is still checking
1118 // against the entire range of a sequence point, but we should revisit that in the next release.
1119 ULONG32 curLine = m_DataPointers.m_pSequencePoints[point].StartLine();
1120
1121 if (fExactMatch)
1122 {
1123 if (curLine == line)
1124 {
1125 found = true;
1126 }
1127 else if ((maxPreLine < curLine) && (curLine < line))
1128 {
1129 // This is not an exact match, but let's keep track of the sequence point closest to the specified
1130 // line. We'll use this info if we have to do a second pass.
1131 maxPreLine = curLine;
1132 }
1133 }
1134 else
1135 {
1136 // We are in the second pass, looking for approximate matches.
1137 if ((maxPreLine != 0) && (maxPreLine == curLine))
1138 {
1139 // Make sure the sequence point covers the specified line.
1140 if (m_DataPointers.m_pSequencePoints[point].IsWithinLineOnly(line))
1141 {
1142 found = true;
1143 }
1144 }
1145 }
1146
1147 // If we have found a match (whether it's exact or approximate), then save this method unless the caller is
1148 // only interested in the number of matching methods or the array provided by the caller isn't big enough.
1149 if (found)
1150 {
1151 if (CurMethod < cMethod)
1152 {
1153 IfFailGo(GetMethod(m_DataPointers.m_pMethods[Method].MethodToken(), &(ppRetVal[CurMethod])));
1154 }
1155 CurMethod++;
1156 break;
1157 }
1158 }
1159 }
1160
1161 if (found)
1162 {
1163 // If we have already filled out the entire array provided by the caller, then we are done.
1164 if ((cMethod > 0) && (cMethod == CurMethod))
1165 {
1166 break;
1167 }
1168 else
1169 {
1170 // Otherwise move on to the next method.
1171 continue;
1172 }
1173 }
1174 }
1175
1176 // If we haven't found an exact match, then try it again looking for a sequence point covering the specified line.
1177 if (fExactMatch && (CurMethod == 0))
1178 {
1179 fExactMatch = false;
1180 continue;
1181 }
1182 else
1183 {
1184 // If we have found an exact match, or if we have done two passes already, then bail.
1185 break;
1186 }
1187 }
1188
1189 // Note that unlike GetMethodFromDocumentPosition(), this function returns S_OK even if a match is not found.
1190 if (SUCCEEDED(hr))
1191 {
1192 if (pcMethod != NULL)
1193 {
1194 *pcMethod = CurMethod;
1195 }
1196 }
1197
1198ErrExit:
1199 return hr;
1200}
1201
1202//-----------------------------------------------------------
1203// GetSymbolStoreFileName
1204//-----------------------------------------------------------
1205HRESULT
1206SymReader::GetSymbolStoreFileName(
1207 ULONG32 cchName, // Length of szName
1208 ULONG32 *pcchName, // [Optional]
1209 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[] // [Optional]
1210 )
1211{
1212 _ASSERTE(m_fInitialized);
1213 if (!m_fInitialized)
1214 return E_UNEXPECTED;
1215
1216 if (pcchName)
1217 {
1218 *pcchName = (ULONG32)(wcslen(m_szPath)+1);
1219 }
1220
1221 if( szName )
1222 {
1223 if (wcsncpy_s( szName, cchName, m_szPath, _TRUNCATE) == STRUNCATE)
1224 return HrFromWin32(ERROR_INSUFFICIENT_BUFFER);
1225 }
1226
1227 return NOERROR;
1228}
1229
1230//-----------------------------------------------------------
1231// GetMethodVersion
1232//-----------------------------------------------------------
1233HRESULT
1234SymReader::GetMethodVersion(
1235 ISymUnmanagedMethod * pMethod,
1236 int* pVersion
1237 )
1238{
1239 HRESULT hr = S_OK;
1240
1241 _ASSERTE(m_fInitialized);
1242 IfFalseGo(m_fInitialized, E_UNEXPECTED);
1243
1244 _ASSERTE(pMethod && pVersion);
1245 IfFalseGo( pMethod && pVersion, E_INVALIDARG);
1246 // This symbol store only supports one version of a method
1247 *pVersion = 0;
1248ErrExit:
1249 return hr;
1250}
1251
1252//-----------------------------------------------------------
1253// GetDocumentVersion
1254//-----------------------------------------------------------
1255HRESULT
1256SymReader::GetDocumentVersion(
1257 ISymUnmanagedDocument* pDoc,
1258 int* pVersion,
1259 BOOL* pbCurrent // [Optional]
1260 )
1261{
1262 HRESULT hr = S_OK;
1263
1264 _ASSERTE(m_fInitialized);
1265 IfFalseGo(m_fInitialized, E_UNEXPECTED);
1266
1267 _ASSERTE(pVersion && pDoc);
1268 IfFalseGo(pVersion, E_INVALIDARG);
1269 IfFalseGo(pDoc, E_INVALIDARG);
1270
1271 // This symbol store only supports one version of a document
1272 *pVersion = 0;
1273 if (pbCurrent)
1274 {
1275 *pbCurrent = TRUE;
1276 }
1277ErrExit:
1278 return hr;
1279}
1280
1281//-----------------------------------------------------------
1282// GetDocument
1283// Return the document for the given entry
1284//-----------------------------------------------------------
1285HRESULT SymReader::GetDocument(
1286 UINT32 DocumentEntry,
1287 SymDocument **ppDocument)
1288{
1289 HRESULT hr = NOERROR;
1290
1291 _ASSERTE(m_fInitialized);
1292 IfFalseGo(m_fInitialized, E_UNEXPECTED);
1293
1294 _ASSERTE(ppDocument);
1295 IfFalseGo(ppDocument, E_INVALIDARG);
1296
1297 _ASSERTE(DocumentEntry < m_pPDBInfo->m_CountOfDocuments);
1298 IfFalseGo(DocumentEntry < m_pPDBInfo->m_CountOfDocuments, E_INVALIDARG);
1299
1300 if (m_pDocs == NULL)
1301 {
1302 IfNullGo(m_pDocs = NEW(SymDocument *[m_pPDBInfo->m_CountOfDocuments]));
1303 memset(m_pDocs, 0, m_pPDBInfo->m_CountOfDocuments * sizeof(void *));
1304 }
1305
1306 if (m_pDocs[DocumentEntry] == NULL)
1307 {
1308 m_pDocs[DocumentEntry] = NEW(SymDocument(this, &m_DataPointers, m_pPDBInfo->m_CountOfMethods, DocumentEntry));
1309 IfNullGo(m_pDocs[DocumentEntry]);
1310 // AddRef the table version
1311 m_pDocs[DocumentEntry]->AddRef();
1312
1313 }
1314
1315 //Set and AddRef the Out Parameter
1316 *ppDocument = m_pDocs[DocumentEntry];
1317 (*ppDocument)->AddRef();
1318
1319ErrExit:
1320 return hr;
1321}
1322
1323HRESULT
1324SymReader::UpdateSymbolStore(
1325 const WCHAR *filename,
1326 IStream *pIStream
1327 )
1328{
1329 // This symbol store doesn't support updating the symbol store.
1330 _ASSERTE(!"NYI");
1331 return E_NOTIMPL;
1332}
1333
1334HRESULT
1335SymReader::ReplaceSymbolStore(
1336 const WCHAR *filename,
1337 IStream *pIStream
1338 )
1339{
1340 // This symbol store doesn't support updating the symbol store.
1341 _ASSERTE(!"NYI");
1342 return E_NOTIMPL;
1343}
1344
1345//-----------------------------------------------------------
1346// GetVariables
1347//-----------------------------------------------------------
1348HRESULT
1349SymReader::GetVariables(
1350 mdToken parent,
1351 ULONG32 cVars,
1352 ULONG32 *pcVars,
1353 ISymUnmanagedVariable *pVars[]
1354 )
1355{
1356 //
1357 // This symbol reader doesn't support non-local variables.
1358 //
1359 _ASSERTE(!"NYI");
1360 return E_NOTIMPL;
1361}
1362
1363//-----------------------------------------------------------
1364// GetGlobalVariables
1365//-----------------------------------------------------------
1366HRESULT
1367SymReader::GetGlobalVariables(
1368 ULONG32 cVars,
1369 ULONG32 *pcVars,
1370 ISymUnmanagedVariable *pVars[]
1371 )
1372{
1373 //
1374 // This symbol reader doesn't support non-local variables.
1375 //
1376 _ASSERTE(!"NYI");
1377 return E_NOTIMPL;
1378}
1379
1380//-----------------------------------------------------------
1381// GetSymAttribute
1382//-----------------------------------------------------------
1383HRESULT
1384SymReader::GetSymAttribute(
1385 mdToken parent,
1386 __in LPWSTR name,
1387 ULONG32 cBuffer,
1388 ULONG32 *pcBuffer,
1389 __out_bcount_part_opt(cBuffer, *pcBuffer) BYTE buffer[]
1390 )
1391{
1392 // This symbol store doesn't support attributes
1393 // VS may query for certain attributes, but will survive without them,
1394 // so don't ASSERT here.
1395 return E_NOTIMPL;
1396}
1397
1398//-----------------------------------------------------------
1399// GetNamespaces
1400//-----------------------------------------------------------
1401HRESULT
1402SymReader::GetNamespaces(
1403 ULONG32 cNameSpaces,
1404 ULONG32 *pcNameSpaces,
1405 ISymUnmanagedNamespace *namespaces[]
1406 )
1407{
1408 // This symbol store doesn't support this
1409 _ASSERTE(!"NYI");
1410 return E_NOTIMPL;
1411}
1412
1413/* ------------------------------------------------------------------------- *
1414 * SymDocument class
1415 * ------------------------------------------------------------------------- */
1416
1417HRESULT
1418SymDocument::QueryInterface(
1419 REFIID riid,
1420 void **ppInterface
1421 )
1422{
1423 if (ppInterface == NULL)
1424 return E_INVALIDARG;
1425
1426 if (riid == IID_ISymUnmanagedDocument)
1427 *ppInterface = (ISymUnmanagedDocument*)this;
1428 else if (riid == IID_IUnknown)
1429 *ppInterface = (IUnknown*)(ISymUnmanagedDocument*)this;
1430 else
1431 {
1432 *ppInterface = NULL;
1433 return E_NOINTERFACE;
1434 }
1435
1436 AddRef();
1437 return S_OK;
1438}
1439
1440
1441//-----------------------------------------------------------
1442// GetURL
1443//-----------------------------------------------------------
1444HRESULT
1445SymDocument::GetURL(
1446 ULONG32 cchUrl, // The allocated size of the buffer
1447 ULONG32 *pcchUrl, // [optional,out] The number of characters available for return
1448 __out_ecount_part_opt(cchUrl, *pcchUrl) WCHAR szUrl[] // [optional,out] The string buffer.
1449 )
1450{
1451 if (pcchUrl)
1452 {
1453 // Convert the UTF8 string to Wide
1454 *pcchUrl = (ULONG32) MultiByteToWideChar(CP_UTF8,
1455 0,
1456 (LPCSTR)&(m_pData->m_pStringsBytes[m_pData->m_pDocuments[m_DocumentEntry].UrlEntry()]),
1457 -1,
1458 0,
1459 NULL);
1460 }
1461
1462 if( szUrl )
1463 {
1464 // Convert the UTF8 string to Wide
1465 MultiByteToWideChar(CP_UTF8,
1466 0,
1467 (LPCSTR)&(m_pData->m_pStringsBytes[m_pData->m_pDocuments[m_DocumentEntry].UrlEntry()]),
1468 -1,
1469 szUrl,
1470 cchUrl);
1471 }
1472 return NOERROR;
1473}
1474
1475//-----------------------------------------------------------
1476// GetDocumentType
1477//-----------------------------------------------------------
1478HRESULT
1479SymDocument::GetDocumentType(
1480 GUID *pRetVal
1481 )
1482{
1483 HRESULT hr = NOERROR;
1484 _ASSERTE(pRetVal);
1485 IfFalseGo(pRetVal, E_INVALIDARG);
1486 *pRetVal = m_pData->m_pDocuments[m_DocumentEntry].DocumentType();
1487 SwapGuid(pRetVal);
1488ErrExit:
1489 return hr;
1490}
1491
1492//-----------------------------------------------------------
1493// GetLanguage
1494//-----------------------------------------------------------
1495HRESULT
1496SymDocument::GetLanguage(
1497 GUID *pRetVal
1498 )
1499{
1500 HRESULT hr = NOERROR;
1501 _ASSERTE(pRetVal);
1502 IfFalseGo(pRetVal, E_INVALIDARG);
1503
1504 *pRetVal = m_pData->m_pDocuments[m_DocumentEntry].Language();
1505 SwapGuid(pRetVal);
1506ErrExit:
1507 return hr;
1508}
1509
1510//-----------------------------------------------------------
1511// GetLanguageVendor
1512//-----------------------------------------------------------
1513HRESULT
1514SymDocument::GetLanguageVendor(
1515 GUID *pRetVal
1516 )
1517{
1518 HRESULT hr = NOERROR;
1519 _ASSERTE(pRetVal);
1520 IfFalseGo(pRetVal, E_INVALIDARG);
1521 *pRetVal = m_pData->m_pDocuments[m_DocumentEntry].LanguageVendor();
1522 SwapGuid(pRetVal);
1523ErrExit:
1524 return hr;
1525}
1526
1527//-----------------------------------------------------------
1528// GetCheckSumAlgorithmId
1529//-----------------------------------------------------------
1530HRESULT
1531SymDocument::GetCheckSumAlgorithmId(
1532 GUID *pRetVal
1533 )
1534{
1535 HRESULT hr = NOERROR;
1536 _ASSERTE(pRetVal);
1537 IfFalseGo(pRetVal, E_INVALIDARG);
1538 *pRetVal = m_pData->m_pDocuments[m_DocumentEntry].AlgorithmId();
1539 SwapGuid(pRetVal);
1540ErrExit:
1541 return hr;
1542}
1543
1544//-----------------------------------------------------------
1545// GetCheckSum
1546//-----------------------------------------------------------
1547HRESULT
1548SymDocument::GetCheckSum(
1549 ULONG32 cData, // The allocated size of the buffer.
1550 ULONG32 *pcData, // [optional] The number of bytes available for return
1551 BYTE data[]) // [optional] The buffer to receive the checksum.
1552{
1553 BYTE *pCheckSum = &m_pData->m_pBytes[m_pData->m_pDocuments[m_DocumentEntry].CheckSumEntry()];
1554 ULONG32 CheckSumSize = m_pData->m_pDocuments[m_DocumentEntry].CheckSumSize();
1555 if (pcData)
1556 {
1557 *pcData = CheckSumSize;
1558 }
1559 if(data)
1560 {
1561 memcpy(data, pCheckSum, min(CheckSumSize, cData));
1562 }
1563 return NOERROR;
1564}
1565
1566//-----------------------------------------------------------
1567// FindClosestLine
1568// Search the sequence points looking a line that is closest
1569// line following this one that is a sequence point
1570//-----------------------------------------------------------
1571HRESULT
1572SymDocument::FindClosestLine(
1573 ULONG32 line,
1574 ULONG32 *pRetVal
1575 )
1576{
1577 HRESULT hr = NOERROR;
1578 UINT32 Method;
1579 UINT32 point;
1580 ULONG32 closestLine = 0; // GCC can't tell this isn't used before initialization
1581 bool found = false;
1582
1583 _ASSERTE(pRetVal);
1584 IfFalseGo(pRetVal, E_INVALIDARG);
1585
1586 // Walk all Methods, check their Document and SequencePoints to see if it's in this doc
1587 // and the line/column
1588 for (Method = 0; Method < m_CountOfMethods; Method++)
1589 {
1590 // Walk the sequence points
1591 for (point = m_pData->m_pMethods[Method].StartSequencePoints();
1592 point < m_pData->m_pMethods[Method].EndSequencePoints();
1593 point++)
1594 {
1595 SequencePoint & sp = m_pData->m_pSequencePoints[point];
1596 // Check to see if this sequence point is in this doc, and is at or
1597 // after the requested line
1598 if ((sp.Document() == m_DocumentEntry) && sp.IsUserLine())
1599 {
1600 if (sp.IsWithin(line, 0) || sp.IsGreaterThan(line, 0))
1601 {
1602 // This sequence point is at or after the requested line. If we haven't
1603 // already found a "closest", or this is even closer than the one we have,
1604 // then mark this as the best line so far.
1605 if (!found || m_pData->m_pSequencePoints[point].StartLine() < closestLine)
1606 {
1607 found = true;
1608 closestLine = m_pData->m_pSequencePoints[point].StartLine();
1609 }
1610 }
1611 }
1612 }
1613 }
1614
1615 if (found)
1616 {
1617 *pRetVal = closestLine;
1618 }
1619 else
1620 {
1621 // Didn't find any lines at or after the one requested.
1622 hr = E_FAIL;
1623 }
1624
1625ErrExit:
1626 return hr;
1627}
1628
1629//-----------------------------------------------------------
1630// SymDocument HasEmbeddedSource
1631//-----------------------------------------------------------
1632HRESULT
1633SymDocument::HasEmbeddedSource(
1634 BOOL *pRetVal
1635 )
1636{
1637 //
1638 // This symbol reader doesn't support embedded source.
1639 //
1640 _ASSERTE(!"NYI");
1641 return E_NOTIMPL;
1642}
1643
1644//-----------------------------------------------------------
1645// SymDocument GetSourceLength
1646//-----------------------------------------------------------
1647HRESULT
1648SymDocument::GetSourceLength(
1649 ULONG32 *pRetVal
1650 )
1651{
1652 //
1653 // This symbol reader doesn't support embedded source.
1654 //
1655 _ASSERTE(!"NYI");
1656 return E_NOTIMPL;
1657}
1658
1659//-----------------------------------------------------------
1660// SymDocument GetSourceRange
1661//-----------------------------------------------------------
1662HRESULT
1663SymDocument::GetSourceRange(
1664 ULONG32 startLine,
1665 ULONG32 startColumn,
1666 ULONG32 endLine,
1667 ULONG32 endColumn,
1668 ULONG32 cSourceBytes,
1669 ULONG32 *pcSourceBytes,
1670 BYTE source[]
1671 )
1672{
1673 //
1674 // This symbol reader doesn't support embedded source.
1675 //
1676 _ASSERTE(!"NYI");
1677 return E_NOTIMPL;
1678}
1679
1680/* ------------------------------------------------------------------------- *
1681 * SymMethod class
1682 * ------------------------------------------------------------------------- */
1683HRESULT
1684SymMethod::QueryInterface(
1685 REFIID riid,
1686 void **ppInterface
1687 )
1688{
1689 if (ppInterface == NULL)
1690 return E_INVALIDARG;
1691
1692 if (riid == IID_ISymUnmanagedMethod)
1693 *ppInterface = (ISymUnmanagedMethod*)this;
1694 else if (riid == IID_IUnknown)
1695 *ppInterface = (IUnknown*)(ISymUnmanagedMethod*)this;
1696 else
1697 {
1698 *ppInterface = NULL;
1699 return E_NOINTERFACE;
1700 }
1701
1702 AddRef();
1703 return S_OK;
1704}
1705
1706//-----------------------------------------------------------
1707// GetToken
1708//-----------------------------------------------------------
1709HRESULT
1710SymMethod::GetToken(
1711 mdMethodDef *pRetVal
1712)
1713{
1714 HRESULT hr = S_OK;
1715
1716 _ASSERTE(pRetVal);
1717 IfFalseGo(pRetVal, E_INVALIDARG);
1718 *pRetVal = m_pData->m_pMethods[m_MethodEntry].MethodToken();
1719ErrExit:
1720 return hr;
1721}
1722
1723
1724//-----------------------------------------------------------
1725// GetSequencePointCount
1726//-----------------------------------------------------------
1727HRESULT
1728SymMethod::GetSequencePointCount(
1729 ULONG32* pRetVal
1730 )
1731{
1732
1733 HRESULT hr = S_OK;
1734 _ASSERTE(pRetVal);
1735 IfFalseGo(pRetVal, E_INVALIDARG);
1736
1737 *pRetVal = (ULONG32)(m_pData->m_pMethods[m_MethodEntry].EndSequencePoints() -
1738 m_pData->m_pMethods[m_MethodEntry].StartSequencePoints());
1739ErrExit:
1740 return hr;
1741}
1742
1743//-----------------------------------------------------------
1744// GetSequencePoints
1745//-----------------------------------------------------------
1746HRESULT
1747SymMethod::GetSequencePoints(
1748 ULONG32 cPoints, // The size of the allocated arrays.
1749 ULONG32* pcPoints, // [optional] The number of sequence points available for return.
1750 ULONG32 offsets[], // [optional]
1751 ISymUnmanagedDocument *documents[], // [Optional]
1752 ULONG32 lines[], // [Optional]
1753 ULONG32 columns[], // [Optional]
1754 ULONG32 endLines[], // [Optional]
1755 ULONG32 endColumns[] // [Optional]
1756 )
1757{
1758 HRESULT hr = NOERROR;
1759 UINT32 i = 0;
1760 ULONG32 Points = 0;
1761
1762 for (i = m_pData->m_pMethods[m_MethodEntry].StartSequencePoints();
1763 (i < m_pData->m_pMethods[m_MethodEntry].EndSequencePoints());
1764 i++, Points++)
1765 {
1766 if (Points < cPoints)
1767 {
1768 if (documents)
1769 {
1770 SymDocument *pDoc;
1771 IfFailGo(m_pReader->GetDocument(m_pData->m_pSequencePoints[i].Document(), &pDoc));
1772 documents[Points] = pDoc;
1773 }
1774
1775 if (offsets)
1776 {
1777 offsets[Points] = m_pData->m_pSequencePoints[i].Offset();
1778 }
1779
1780 if (lines)
1781 {
1782 lines[Points] = m_pData->m_pSequencePoints[i].StartLine();
1783 }
1784 if (columns)
1785 {
1786 columns[Points] = m_pData->m_pSequencePoints[i].StartColumn();
1787 }
1788 if (endLines)
1789 {
1790 endLines[Points] = m_pData->m_pSequencePoints[i].EndLine();
1791 }
1792 if (endColumns)
1793 {
1794 endColumns[Points] = m_pData->m_pSequencePoints[i].EndColumn();
1795 }
1796 }
1797 }
1798
1799 if (pcPoints)
1800 {
1801 *pcPoints = Points;
1802 }
1803
1804ErrExit:
1805 if (FAILED(hr))
1806 {
1807 if (documents)
1808 {
1809 unsigned j;
1810 for (j = 0; j < i; j++)
1811 {
1812 RELEASE(documents[i]);
1813 }
1814 }
1815 }
1816 return hr;
1817}
1818
1819//-----------------------------------------------------------
1820// GetRootScope
1821//-----------------------------------------------------------
1822HRESULT
1823SymMethod::GetRootScope(
1824 ISymUnmanagedScope **ppRetVal
1825 )
1826{
1827 HRESULT hr = S_OK;
1828 SymScope *pScope = NULL;
1829 _ASSERTE(ppRetVal);
1830 IfFalseGo(ppRetVal, E_INVALIDARG);
1831
1832 // Init Out Param
1833 *ppRetVal = NULL;
1834 if (m_pData->m_pMethods[m_MethodEntry].EndScopes() - m_pData->m_pMethods[m_MethodEntry].StartScopes())
1835 {
1836 IfNullGo(pScope = NEW(SymScope(this, m_pData, m_MethodEntry, m_pData->m_pMethods[m_MethodEntry].StartScopes())));
1837 pScope->AddRef();
1838 *ppRetVal = pScope;
1839 }
1840ErrExit:
1841 return hr;
1842}
1843
1844//-----------------------------------------------------------
1845// GetOffset
1846// Given a position in a document, gets the offset within the
1847// method that corresponds to the position.
1848//-----------------------------------------------------------
1849HRESULT
1850SymMethod::GetOffset(
1851 ISymUnmanagedDocument *document,
1852 ULONG32 line,
1853 ULONG32 column,
1854 ULONG32 *pRetVal
1855 )
1856{
1857 HRESULT hr = S_OK;
1858 bool fFound = false;
1859 _ASSERTE(pRetVal);
1860 IfFalseGo(pRetVal, E_INVALIDARG);
1861
1862 UINT32 point;
1863 UINT32 DocumentEntry;
1864
1865 DocumentEntry = ((SymDocument *)document)->GetDocumentEntry();
1866
1867 // Walk the sequence points
1868 for (point = m_pData->m_pMethods[m_MethodEntry].StartSequencePoints();
1869 point < m_pData->m_pMethods[m_MethodEntry].EndSequencePoints();
1870 point++)
1871 {
1872 // Check to see if this sequence point is in this doc
1873 if (m_pData->m_pSequencePoints[point].Document() == DocumentEntry)
1874 {
1875 // Check to see if it's within the sequence point
1876 if (m_pData->m_pSequencePoints[point].IsWithin(line, column))
1877 {
1878 *pRetVal = m_pData->m_pSequencePoints[point].Offset();
1879 fFound = true;
1880 break;
1881 }
1882 }
1883 }
1884 if (!fFound)
1885 {
1886 hr = E_FAIL;
1887 }
1888ErrExit:
1889 return hr;
1890}
1891
1892//-----------------------------------------------------------
1893// GetRanges
1894//-----------------------------------------------------------
1895HRESULT
1896SymMethod::GetRanges(
1897 ISymUnmanagedDocument *pDocument, // [in] Document we're working on
1898 ULONG32 line, // [in] The document line corresponding to the ranges.
1899 ULONG32 column, // [in] Ignored
1900 ULONG32 cRanges, // [in] The size of the allocated ranges[] array.
1901 ULONG32 *pcRanges, // [out] The number of ranges available for return
1902 ULONG32 ranges[] // [out] The range array.
1903 )
1904{
1905 HRESULT hr = NOERROR;
1906 DWORD iRange = 0;
1907 UINT32 DocumentEntry;
1908 UINT32 point;
1909 bool fFound = false;
1910
1911 // Validate some of the parameters
1912 _ASSERTE(pDocument && (cRanges % 2) == 0);
1913 IfFalseGo(pDocument, E_INVALIDARG);
1914 IfFalseGo((cRanges % 2) == 0, E_INVALIDARG);
1915
1916 // Init out parameter
1917 if (pcRanges)
1918 {
1919 *pcRanges=0;
1920 }
1921
1922 DocumentEntry = ((SymDocument *)pDocument)->GetDocumentEntry();
1923
1924 // Walk the sequence points
1925 for (point = m_pData->m_pMethods[m_MethodEntry].StartSequencePoints();
1926 point < m_pData->m_pMethods[m_MethodEntry].EndSequencePoints();
1927 point++)
1928 {
1929 // Check to see if this sequence point is in this doc
1930 if (m_pData->m_pSequencePoints[point].Document() == DocumentEntry)
1931 {
1932 // Check to see if the line is within this sequence
1933 // Note, to be compatible with VS7, ignore the column information
1934 if (line >= m_pData->m_pSequencePoints[point].StartLine() &&
1935 line <= m_pData->m_pSequencePoints[point].EndLine())
1936 {
1937 fFound = true;
1938 break;
1939 }
1940 }
1941 }
1942
1943 if (fFound)
1944 {
1945 for (;point < m_pData->m_pMethods[m_MethodEntry].EndSequencePoints(); point++)
1946 {
1947
1948 // Search through all the sequence points since line might have there
1949 // IL spread accross multiple ranges (for loops for example)
1950 if (m_pData->m_pSequencePoints[point].Document() == DocumentEntry &&
1951 line >= m_pData->m_pSequencePoints[point].StartLine() &&
1952 line <= m_pData->m_pSequencePoints[point].EndLine())
1953 {
1954 if (iRange < cRanges)
1955 {
1956 ranges[iRange] = m_pData->m_pSequencePoints[point].Offset();
1957 }
1958 iRange++;
1959 if (iRange < cRanges)
1960 {
1961 if (point+1 < m_pData->m_pMethods[m_MethodEntry].EndSequencePoints())
1962 {
1963 ranges[iRange] = m_pData->m_pSequencePoints[point+1].Offset();
1964 }
1965 else
1966 {
1967 // Then it must be till the end of the function which is the root scope's endoffset
1968 ranges[iRange] = m_pData->m_pScopes[m_pData->m_pMethods[m_MethodEntry].StartScopes()].EndOffset()+1;
1969 }
1970 }
1971 iRange++;
1972 }
1973 }
1974 if (pcRanges)
1975 {
1976 // If cRanges passed in, return the number
1977 // of elements actually filled in
1978 if (cRanges)
1979 {
1980 *pcRanges = min(iRange, cRanges);
1981 }
1982 else
1983 {
1984 // Otherwise return the max number
1985 *pcRanges = iRange;
1986 }
1987 }
1988 }
1989 else
1990 {
1991 return E_FAIL;
1992 }
1993
1994ErrExit:
1995 return hr;
1996}
1997
1998//-----------------------------------------------------------
1999// GetScopeFromOffset
2000//-----------------------------------------------------------
2001HRESULT
2002SymMethod::GetScopeFromOffset(
2003 ULONG32 offset,
2004 ISymUnmanagedScope **pRetVal
2005 )
2006{
2007 //
2008 // This symbol reader doesn't support this functionality
2009 //
2010 _ASSERTE(!"NYI");
2011 return E_NOTIMPL;
2012}
2013
2014//-----------------------------------------------------------
2015// GetParameters
2016//-----------------------------------------------------------
2017HRESULT
2018SymMethod::GetParameters(
2019 ULONG32 cParams,
2020 ULONG32 *pcParams,
2021 ISymUnmanagedVariable *params[]
2022 )
2023{
2024 //
2025 // This symbol reader doesn't support parameter access. Parameters
2026 // can be found in the normal metadata.
2027 //
2028 _ASSERTE(!"NYI");
2029 return E_NOTIMPL;
2030}
2031
2032//-----------------------------------------------------------
2033// GetNamespace
2034//-----------------------------------------------------------
2035HRESULT
2036SymMethod::GetNamespace(
2037 ISymUnmanagedNamespace **ppRetVal
2038 )
2039{
2040 //
2041 // This symbol reader doesn't support namespaces
2042 //
2043 _ASSERTE(!"NYI");
2044 return E_NOTIMPL;
2045}
2046
2047//-----------------------------------------------------------
2048// GetSourceStartEnd
2049//-----------------------------------------------------------
2050HRESULT
2051SymMethod::GetSourceStartEnd(
2052 ISymUnmanagedDocument *docs[2],
2053 ULONG32 lines[2],
2054 ULONG32 columns[2],
2055 BOOL *pRetVal
2056 )
2057{
2058 //
2059 // This symbol reader doesn't support source start/end for methods.
2060 //
2061 _ASSERTE(!"NYI");
2062 return E_NOTIMPL;
2063}
2064
2065/* ------------------------------------------------------------------------- *
2066 * SymScope class
2067 * ------------------------------------------------------------------------- */
2068
2069//-----------------------------------------------------------
2070// QueryInterface
2071//-----------------------------------------------------------
2072HRESULT
2073SymScope::QueryInterface(
2074 REFIID riid,
2075 void **ppInterface
2076 )
2077{
2078 if (ppInterface == NULL)
2079 return E_INVALIDARG;
2080
2081 if (riid == IID_ISymUnmanagedScope)
2082 *ppInterface = (ISymUnmanagedScope*)this;
2083 else if (riid == IID_IUnknown)
2084 *ppInterface = (IUnknown*)(ISymUnmanagedScope*)this;
2085 else
2086 {
2087 *ppInterface = NULL;
2088 return E_NOINTERFACE;
2089 }
2090
2091 AddRef();
2092 return S_OK;
2093}
2094
2095//-----------------------------------------------------------
2096// GetMethod
2097//-----------------------------------------------------------
2098HRESULT
2099SymScope::GetMethod(
2100 ISymUnmanagedMethod **ppRetVal
2101 )
2102{
2103 HRESULT hr = S_OK;
2104
2105 _ASSERTE(ppRetVal);
2106 IfFalseGo(ppRetVal, E_INVALIDARG);
2107
2108 *ppRetVal = m_pSymMethod;
2109 m_pSymMethod->AddRef();
2110
2111ErrExit:
2112 return hr;
2113}
2114
2115//-----------------------------------------------------------
2116// GetParent
2117//-----------------------------------------------------------
2118HRESULT
2119SymScope::GetParent(
2120 ISymUnmanagedScope **ppRetVal
2121 )
2122{
2123 HRESULT hr = S_OK;
2124 _ASSERTE(ppRetVal);
2125 IfFalseGo(ppRetVal, E_INVALIDARG);
2126 if (m_pData->m_pScopes[m_ScopeEntry].ParentScope() != (UINT32)-1)
2127 {
2128 IfNullGo(*ppRetVal = static_cast<ISymUnmanagedScope *>(NEW(SymScope(m_pSymMethod, m_pData, m_MethodEntry,
2129 m_pData->m_pScopes[m_ScopeEntry].ParentScope()))));
2130 (*ppRetVal)->AddRef();
2131 }
2132 else
2133 {
2134 *ppRetVal = NULL;
2135 }
2136ErrExit:
2137 return hr;
2138}
2139
2140//-----------------------------------------------------------
2141// GetChildren
2142//-----------------------------------------------------------
2143HRESULT
2144SymScope::GetChildren(
2145 ULONG32 cChildren, // [optional] Number of entries in children
2146 ULONG32 *pcChildren, // [optional, out] Number of Children available for retur
2147 ISymUnmanagedScope *children[] // [optional] array to store children into
2148 )
2149{
2150 HRESULT hr = S_OK;
2151 ULONG32 ChildrenCount = 0;
2152 _ASSERTE(pcChildren || (children && cChildren));
2153 IfFalseGo((pcChildren || (children && cChildren)), E_INVALIDARG);
2154
2155 if (m_pData->m_pScopes[m_ScopeEntry].HasChildren())
2156 {
2157 UINT32 ScopeEntry;
2158 for(ScopeEntry = m_pData->m_pMethods[m_MethodEntry].StartScopes();
2159 (ScopeEntry < m_pData->m_pMethods[m_MethodEntry].EndScopes());
2160 ScopeEntry++)
2161 {
2162 if (m_pData->m_pScopes[ScopeEntry].ParentScope() == m_ScopeEntry)
2163 {
2164 if (children && ChildrenCount < cChildren)
2165 {
2166 SymScope *pScope;
2167 // Found a child
2168 IfNullGo(pScope = NEW(SymScope(m_pSymMethod, m_pData, m_MethodEntry, ScopeEntry)));
2169 children[ChildrenCount] = pScope;
2170 pScope->AddRef();
2171 }
2172 ChildrenCount++;
2173 }
2174 }
2175 }
2176
2177 if (pcChildren)
2178 {
2179 *pcChildren = ChildrenCount;
2180 }
2181
2182ErrExit:
2183 if (FAILED(hr) && ChildrenCount)
2184 {
2185 unsigned i;
2186 for (i =0; i< ChildrenCount; i++)
2187 {
2188 RELEASE(children[i]);
2189 }
2190 }
2191 return hr;
2192}
2193
2194//-----------------------------------------------------------
2195// GetStartOffset
2196//-----------------------------------------------------------
2197HRESULT
2198SymScope::GetStartOffset(
2199 ULONG32* pRetVal
2200 )
2201{
2202 HRESULT hr = S_OK;
2203 _ASSERTE(pRetVal);
2204 IfFalseGo(pRetVal, E_INVALIDARG);
2205 *pRetVal = m_pData->m_pScopes[m_ScopeEntry].StartOffset();
2206ErrExit:
2207 return hr;
2208}
2209
2210//-----------------------------------------------------------
2211// GetEndOffset
2212//-----------------------------------------------------------
2213HRESULT
2214SymScope::GetEndOffset(
2215 ULONG32* pRetVal
2216 )
2217{
2218 HRESULT hr = S_OK;
2219 _ASSERTE(pRetVal);
2220 IfFalseGo(pRetVal, E_INVALIDARG);
2221 *pRetVal = m_pData->m_pScopes[m_ScopeEntry].EndOffset();
2222ErrExit:
2223 return hr;
2224}
2225
2226//-----------------------------------------------------------
2227// GetLocalCount
2228//-----------------------------------------------------------
2229HRESULT
2230SymScope::GetLocalCount(
2231 ULONG32 *pRetVal
2232 )
2233{
2234 HRESULT hr = S_OK;
2235 ULONG32 LocalCount = 0;
2236 _ASSERTE(pRetVal);
2237 IfFalseGo(pRetVal, E_INVALIDARG);
2238
2239 // Init out parameter
2240 *pRetVal = 0;
2241 if (m_pData->m_pScopes[m_ScopeEntry].HasVars())
2242 {
2243 UINT32 var;
2244 // Walk and get the locals for this Scope
2245 for (var = m_pData->m_pMethods[m_MethodEntry].StartVars();
2246 var < m_pData->m_pMethods[m_MethodEntry].EndVars();
2247 var++)
2248 {
2249 if (m_pData->m_pVars[var].Scope() == m_ScopeEntry &&
2250 m_pData->m_pVars[var].IsParam() == false)
2251 {
2252 LocalCount++;
2253 }
2254 }
2255 }
2256
2257 *pRetVal = LocalCount;
2258ErrExit:
2259 return hr;
2260}
2261
2262//-----------------------------------------------------------
2263// GetLocals
2264// Input: either pcLocals or
2265// cLocals and pLocals
2266//-----------------------------------------------------------
2267HRESULT
2268SymScope::GetLocals(
2269 ULONG32 cLocals, // [optional] available entries in pLocals
2270 ULONG32 *pcLocals, // [optional, out] Number of locals returned
2271 ISymUnmanagedVariable *pLocals[] // [optional] array to store locals into
2272 )
2273{
2274 HRESULT hr = S_OK;
2275
2276 ULONG32 LocalCount = 0;
2277 _ASSERTE(pcLocals || pLocals);
2278 IfFalseGo(pcLocals || pLocals, E_INVALIDARG);
2279
2280 if (m_pData->m_pScopes[m_ScopeEntry].HasVars())
2281 {
2282 UINT32 var;
2283 // Walk and get the locals for this Scope
2284 for (var = m_pData->m_pMethods[m_MethodEntry].StartVars();
2285 var < m_pData->m_pMethods[m_MethodEntry].EndVars();
2286 var++)
2287 {
2288 if (m_pData->m_pVars[var].Scope() == m_ScopeEntry &&
2289 m_pData->m_pVars[var].IsParam() == false)
2290 {
2291 if (pLocals && LocalCount < cLocals)
2292 {
2293 SymReaderVar *pVar;
2294 IfNullGo( pVar = NEW(SymReaderVar(this, m_pData, var)));
2295 pLocals[LocalCount] = pVar;
2296 pVar->AddRef();
2297 }
2298 LocalCount++;
2299 }
2300 }
2301 }
2302 if (pcLocals)
2303 {
2304 *pcLocals = LocalCount;
2305 }
2306ErrExit:
2307 if (FAILED(hr) && LocalCount != 0)
2308 {
2309 unsigned i;
2310 for (i =0; i < LocalCount; i++)
2311 {
2312 RELEASE(pLocals[i]);
2313 }
2314 }
2315 return hr;
2316}
2317
2318//-----------------------------------------------------------
2319// GetNamespaces
2320// Input: either pcNameSpaces or
2321// cNameSpaces and pNameSpaces
2322//-----------------------------------------------------------
2323HRESULT
2324SymScope::GetNamespaces(
2325 ULONG32 cNameSpaces, // [optional] number of entries pNameSpaces
2326 ULONG32 *pcNameSpaces, // [optional, out] Maximum number of Namespace
2327 ISymUnmanagedNamespace *pNameSpaces[] // [optional] array to store namespaces into
2328 )
2329{
2330 HRESULT hr = NOERROR;
2331 unsigned i;
2332 UINT32 NameSpace;
2333 unsigned NameSpaceCount = 0;
2334
2335 _ASSERTE(pcNameSpaces || (pNameSpaces && cNameSpaces));
2336 IfFalseGo(pcNameSpaces || (pNameSpaces && cNameSpaces), E_INVALIDARG);
2337
2338 for (NameSpace = m_pData->m_pMethods[m_MethodEntry].StartUsing();
2339 NameSpace < m_pData->m_pMethods[m_MethodEntry].EndUsing();
2340 NameSpace++)
2341 {
2342 if (m_pData->m_pUsings[NameSpace].ParentScope() == m_ScopeEntry)
2343 {
2344 if (pNameSpaces && (NameSpaceCount < cNameSpaces) )
2345 {
2346 IfNullGo(pNameSpaces[NameSpaceCount] = NEW(SymReaderNamespace(this, m_pData, NameSpace)));
2347 pNameSpaces[NameSpaceCount]->AddRef();
2348 }
2349 NameSpaceCount++;
2350 }
2351 }
2352 if (pcNameSpaces)
2353 {
2354 *pcNameSpaces = NameSpaceCount;
2355 }
2356ErrExit:
2357 if (FAILED(hr) && pNameSpaces)
2358 {
2359 for (i = 0; (i < cNameSpaces) && (i < NameSpaceCount); i++)
2360 {
2361 RELEASE(pNameSpaces[i]);
2362 }
2363 }
2364 return hr;
2365}
2366
2367/* ------------------------------------------------------------------------- *
2368 * SymReaderVar class
2369 * ------------------------------------------------------------------------- */
2370
2371//-----------------------------------------------------------
2372// QueryInterface
2373//-----------------------------------------------------------
2374HRESULT
2375SymReaderVar::QueryInterface(
2376 REFIID riid,
2377 void **ppInterface
2378 )
2379{
2380 if (ppInterface == NULL)
2381 return E_INVALIDARG;
2382
2383 if (riid == IID_ISymUnmanagedVariable)
2384 *ppInterface = (ISymUnmanagedVariable*)this;
2385 else if (riid == IID_IUnknown)
2386 *ppInterface = (IUnknown*)(ISymUnmanagedVariable*)this;
2387 else
2388 {
2389 *ppInterface = NULL;
2390 return E_NOINTERFACE;
2391 }
2392
2393 AddRef();
2394 return S_OK;
2395}
2396
2397//-----------------------------------------------------------
2398// GetName
2399//-----------------------------------------------------------
2400HRESULT
2401SymReaderVar::GetName(
2402 ULONG32 cchName, // [optional] Length of szName buffer
2403 ULONG32 *pcchName, // [optional, out] Total size needed to return the name
2404 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[] // [optional] Buffer to store the name into.
2405 )
2406{
2407 HRESULT hr = S_OK;
2408
2409 // We must have at least one combination
2410 _ASSERTE(pcchName || (szName && cchName));
2411 IfFalseGo( (pcchName || (szName && cchName)), E_INVALIDARG );
2412
2413 if (pcchName)
2414 {
2415 // Convert the UTF8 string to Wide
2416 *pcchName = (ULONG32) MultiByteToWideChar(CP_UTF8,
2417 0,
2418 (LPCSTR)&(m_pData->m_pStringsBytes[m_pData->m_pVars[m_VarEntry].Name()]),
2419 -1,
2420 0,
2421 NULL);
2422
2423 }
2424 if (szName)
2425 {
2426 // Convert the UTF8 string to Wide
2427 MultiByteToWideChar(CP_UTF8,
2428 0,
2429 (LPCSTR)&(m_pData->m_pStringsBytes[m_pData->m_pVars[m_VarEntry].Name()]),
2430 -1,
2431 szName,
2432 cchName);
2433 }
2434
2435ErrExit:
2436 return hr;
2437}
2438
2439//-----------------------------------------------------------
2440// GetAttributes
2441//-----------------------------------------------------------
2442HRESULT
2443SymReaderVar::GetAttributes(
2444 ULONG32 *pRetVal // [out]
2445 )
2446{
2447 if (pRetVal == NULL)
2448 return E_INVALIDARG;
2449
2450 *pRetVal = m_pData->m_pVars[m_VarEntry].Attributes();
2451 return S_OK;
2452}
2453
2454//-----------------------------------------------------------
2455// GetSignature
2456//-----------------------------------------------------------
2457HRESULT
2458SymReaderVar::GetSignature(
2459 ULONG32 cSig, // Size of allocated buffer passed in (sig)
2460 ULONG32 *pcSig, // [optional, out] Total size needed to return the signature
2461 BYTE sig[] // [Optional] Signature
2462 )
2463{
2464 HRESULT hr = S_OK;
2465
2466 _ASSERTE(pcSig || sig);
2467 IfFalseGo( pcSig || sig, E_INVALIDARG );
2468 if (pcSig)
2469 {
2470 *pcSig = m_pData->m_pVars[m_VarEntry].SignatureSize();
2471 }
2472 if (sig)
2473 {
2474 cSig = min(m_pData->m_pVars[m_VarEntry].SignatureSize(), cSig);
2475 memcpy(sig, &m_pData->m_pBytes[m_pData->m_pVars[m_VarEntry].Signature()],cSig);
2476 }
2477
2478ErrExit:
2479 return hr;
2480}
2481
2482//-----------------------------------------------------------
2483// GetAddressKind
2484//-----------------------------------------------------------
2485HRESULT
2486SymReaderVar::GetAddressKind(
2487 ULONG32 *pRetVal // [out]
2488 )
2489{
2490 HRESULT hr = S_OK;
2491 _ASSERTE(pRetVal);
2492 IfFalseGo( pRetVal, E_INVALIDARG );
2493 *pRetVal = m_pData->m_pVars[m_VarEntry].AddrKind();
2494ErrExit:
2495 return S_OK;
2496}
2497
2498//-----------------------------------------------------------
2499// GetAddressField1
2500//-----------------------------------------------------------
2501HRESULT
2502SymReaderVar::GetAddressField1(
2503 ULONG32 *pRetVal // [out]
2504 )
2505{
2506 HRESULT hr = S_OK;
2507
2508 _ASSERTE(pRetVal);
2509 IfFalseGo( pRetVal, E_INVALIDARG );
2510
2511 *pRetVal = m_pData->m_pVars[m_VarEntry].Addr1();
2512
2513ErrExit:
2514
2515 return hr;
2516}
2517
2518//-----------------------------------------------------------
2519// GetAddressField2
2520//-----------------------------------------------------------
2521HRESULT
2522SymReaderVar::GetAddressField2(
2523 ULONG32 *pRetVal // [out]
2524 )
2525{
2526 HRESULT hr = S_OK;
2527
2528 _ASSERTE(pRetVal);
2529 IfFalseGo( pRetVal, E_INVALIDARG );
2530
2531 *pRetVal = m_pData->m_pVars[m_VarEntry].Addr2();
2532
2533ErrExit:
2534
2535 return hr;
2536}
2537
2538//-----------------------------------------------------------
2539// GetAddressField3
2540//-----------------------------------------------------------
2541HRESULT
2542SymReaderVar::GetAddressField3(
2543 ULONG32 *pRetVal // [out]
2544 )
2545{
2546 HRESULT hr = S_OK;
2547
2548 _ASSERTE(pRetVal);
2549 IfFalseGo( pRetVal, E_INVALIDARG );
2550
2551 *pRetVal = m_pData->m_pVars[m_VarEntry].Addr3();
2552
2553ErrExit:
2554
2555 return hr;
2556}
2557
2558//-----------------------------------------------------------
2559// GetStartOffset
2560//-----------------------------------------------------------
2561HRESULT
2562SymReaderVar::GetStartOffset(
2563 ULONG32 *pRetVal
2564 )
2565{
2566 //
2567 // This symbol reader doesn't support variable sub-offsets.
2568 //
2569 return E_NOTIMPL;
2570}
2571
2572//-----------------------------------------------------------
2573// GetEndOffset
2574//-----------------------------------------------------------
2575HRESULT
2576SymReaderVar::GetEndOffset(
2577 ULONG32 *pRetVal
2578 )
2579{
2580 //
2581 // This symbol reader doesn't support variable sub-offsets.
2582 //
2583 return E_NOTIMPL;
2584}
2585
2586
2587/* ------------------------------------------------------------------------- *
2588 * SymReaderNamespace class
2589 * ------------------------------------------------------------------------- */
2590
2591//-----------------------------------------------------------
2592// QueryInterface
2593//-----------------------------------------------------------
2594HRESULT
2595SymReaderNamespace::QueryInterface(
2596 REFIID riid,
2597 void** ppInterface
2598 )
2599{
2600 if (ppInterface == NULL)
2601 return E_INVALIDARG;
2602
2603 if (riid == IID_ISymUnmanagedNamespace)
2604 *ppInterface = (ISymUnmanagedNamespace*)this;
2605 else if (riid == IID_IUnknown)
2606 *ppInterface = (IUnknown*)(ISymUnmanagedNamespace*)this;
2607 else
2608 {
2609 *ppInterface = NULL;
2610 return E_NOINTERFACE;
2611 }
2612
2613 AddRef();
2614 return S_OK;
2615}
2616
2617//-----------------------------------------------------------
2618// GetName
2619//-----------------------------------------------------------
2620HRESULT
2621SymReaderNamespace::GetName(
2622 ULONG32 cchName, // [optional] Chars available in szName
2623 ULONG32 *pcchName, // [optional] Total size needed to return the name
2624 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[] // [optional] Location to store the name into.
2625 )
2626{
2627 HRESULT hr = S_OK;
2628 _ASSERTE(pcchName || (szName && cchName));
2629 IfFalseGo( (pcchName || (szName && cchName)), E_INVALIDARG );
2630
2631 if (pcchName)
2632 {
2633 *pcchName = (ULONG32) MultiByteToWideChar(CP_UTF8,
2634 0,
2635 (LPCSTR)&(m_pData->m_pStringsBytes[m_pData->m_pUsings[m_NamespaceEntry].Name()]),
2636 -1,
2637 0,
2638 NULL);
2639 }
2640 if (szName)
2641 {
2642 MultiByteToWideChar(CP_UTF8,
2643 0,
2644 (LPCSTR)&(m_pData->m_pStringsBytes[m_pData->m_pUsings[m_NamespaceEntry].Name()]),
2645 -1,
2646 szName,
2647 cchName);
2648 }
2649
2650ErrExit:
2651 return hr;
2652}
2653
2654//-----------------------------------------------------------
2655// GetNamespaces
2656//-----------------------------------------------------------
2657HRESULT
2658SymReaderNamespace::GetNamespaces(
2659 ULONG32 cNamespaces,
2660 ULONG32 *pcNamespaces,
2661 ISymUnmanagedNamespace* namespaces[]
2662 )
2663{
2664 // This symbol store doesn't support namespaces.
2665 _ASSERTE(!"NYI");
2666 return E_NOTIMPL;
2667}
2668
2669//-----------------------------------------------------------
2670// GetVariables
2671//-----------------------------------------------------------
2672HRESULT
2673SymReaderNamespace::GetVariables(
2674 ULONG32 cVariables,
2675 ULONG32 *pcVariables,
2676 ISymUnmanagedVariable *pVars[])
2677{
2678 // This symbol store doesn't support namespaces.
2679 _ASSERTE(!"NYI");
2680 return E_NOTIMPL;
2681}
2682
2683
2684/* ------------------------------------------------------------------------- *
2685 * SequencePoint struct functions
2686 * ------------------------------------------------------------------------- */
2687
2688//-----------------------------------------------------------
2689// IsWithin - Is the point given within this sequence point
2690//-----------------------------------------------------------
2691bool SequencePoint::IsWithin(
2692 ULONG32 line,
2693 ULONG32 column)
2694{
2695 // If the sequence point starts on the same line
2696 // Check the start column (if present)
2697 if (StartLine() == line)
2698 {
2699 if (0 < column && StartColumn() > column)
2700 {
2701 return false;
2702 }
2703 }
2704
2705 // If the sequence point ends on the same line
2706 // Check the end column
2707 if (EndLine() == line)
2708 {
2709 if (EndColumn() < column)
2710 {
2711 return false;
2712 }
2713 }
2714
2715 // Make sure the line is within this sequence point
2716 if (!((StartLine() <= line) && (EndLine() >= line)))
2717 {
2718 return false;
2719 }
2720
2721 // Yep it's within this sequence point
2722 return true;
2723
2724}
2725
2726//-----------------------------------------------------------
2727// IsWithinLineOnly - Is the given line within this sequence point
2728//-----------------------------------------------------------
2729bool SequencePoint::IsWithinLineOnly(
2730 ULONG32 line)
2731{
2732 return ((StartLine() <= line) && (line <= EndLine()));
2733}
2734
2735//-----------------------------------------------------------
2736// IsGreaterThan - Is the sequence point greater than the position
2737//-----------------------------------------------------------
2738bool SequencePoint::IsGreaterThan(
2739 ULONG32 line,
2740 ULONG32 column)
2741{
2742 return (StartLine() > line) ||
2743 (StartLine() == line && StartColumn() > column);
2744}
2745
2746//-----------------------------------------------------------
2747// IsLessThan - Is the sequence point less than the position
2748//-----------------------------------------------------------
2749bool SequencePoint::IsLessThan
2750(
2751 ULONG32 line,
2752 ULONG32 column
2753)
2754{
2755 return (StartLine() < line) ||
2756 (StartLine() == line && StartColumn() < column);
2757}
2758
2759//-----------------------------------------------------------
2760// IsUserLine - Is the sequence part of user code
2761//-----------------------------------------------------------
2762bool SequencePoint::IsUserLine()
2763{
2764 return StartLine() != CODE_WITH_NO_SOURCE;
2765}
2766