JIT: Fix bug in finally cloning caused by unsound callfinally reordering
[platform/upstream/coreclr.git] / src / debug / ildbsymlib / symread.cpp
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 //-----------------------------------------------------------
22 HRESULT
23 SymReader::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
46 ErrExit:
47
48     RELEASE( pSymReader );
49
50     return hr;
51 }
52
53
54 //-----------------------------------------------------------
55 // ~SymReader
56 //-----------------------------------------------------------
57 SymReader::~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 //----------------------------------------------------------- 
67 void 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 //-----------------------------------------------------------
108 HRESULT
109 SymReader::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
140 ErrExit:
141
142     return hr;
143 }
144
145 static 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
154 ErrExit:
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 //-----------------------------------------------------------
164 HRESULT 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
207 ErrExit:
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 //-----------------------------------------------------------
228 HRESULT 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
325 ErrExit:
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 //-----------------------------------------------------------
335 HRESULT 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
417 ErrExit:
418     return hr;
419 }
420
421 //-----------------------------------------------------------
422 // Validate a reference to the bytes array
423 //-----------------------------------------------------------
424 HRESULT 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 //-----------------------------------------------------------
440 HRESULT 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;
528 ErrExit:
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 //-----------------------------------------------------------
544 HRESULT
545 SymReader::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
725 ErrExit:
726     
727     return hr;
728 }
729
730 //-----------------------------------------------------------
731 // GetDocument
732 // Get the document for the passed in information
733 //-----------------------------------------------------------
734 HRESULT
735 SymReader::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
796 ErrExit:
797     DELETEARRAY(wcsDocumentUrlAlloc);
798
799     RELEASE( pDoc );
800
801     return hr;
802 }
803
804 //-----------------------------------------------------------
805 // GetDocuments
806 // Get the documents for this reader
807 //-----------------------------------------------------------
808 HRESULT
809 SymReader::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
840 ErrExit:
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 //-----------------------------------------------------------
856 HRESULT
857 SymReader::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     }
878 ErrExit:    
879     return hr;
880 }
881
882 // Compare the method token with the SymMethodInfo Entry and return the
883 // value expected by bsearch
884 int __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 //-----------------------------------------------------------
896 HRESULT
897 SymReader::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      
924 ErrExit:
925     return hr;
926 }
927
928 //-----------------------------------------------------------
929 // GetMethodByVersion
930 //-----------------------------------------------------------
931 HRESULT
932 SymReader::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 //-----------------------------------------------------------
947 HRESULT
948 SymReader::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
1041 ErrExit:
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
1059 HRESULT
1060 SymReader::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
1198 ErrExit:
1199     return hr;
1200 }
1201
1202 //-----------------------------------------------------------
1203 // GetSymbolStoreFileName
1204 //-----------------------------------------------------------
1205 HRESULT
1206 SymReader::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 //-----------------------------------------------------------
1233 HRESULT
1234 SymReader::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;
1248 ErrExit:
1249     return hr;
1250 }
1251
1252 //-----------------------------------------------------------
1253 // GetDocumentVersion
1254 //-----------------------------------------------------------
1255 HRESULT
1256 SymReader::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     }
1277 ErrExit:    
1278     return hr;
1279 }
1280
1281 //-----------------------------------------------------------
1282 // GetDocument
1283 // Return the document for the given entry
1284 //-----------------------------------------------------------
1285 HRESULT 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
1319 ErrExit:
1320     return hr;
1321 }
1322
1323 HRESULT
1324 SymReader::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
1334 HRESULT
1335 SymReader::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 //-----------------------------------------------------------
1348 HRESULT
1349 SymReader::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 //-----------------------------------------------------------
1366 HRESULT
1367 SymReader::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 //-----------------------------------------------------------
1383 HRESULT
1384 SymReader::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 //-----------------------------------------------------------
1401 HRESULT
1402 SymReader::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
1417 HRESULT
1418 SymDocument::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 //-----------------------------------------------------------
1444 HRESULT
1445 SymDocument::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 //-----------------------------------------------------------
1478 HRESULT
1479 SymDocument::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);
1488 ErrExit:
1489     return hr;
1490 }
1491
1492 //-----------------------------------------------------------
1493 // GetLanguage
1494 //-----------------------------------------------------------
1495 HRESULT
1496 SymDocument::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);
1506 ErrExit:        
1507     return hr;
1508 }
1509
1510 //-----------------------------------------------------------
1511 // GetLanguageVendor
1512 //-----------------------------------------------------------
1513 HRESULT
1514 SymDocument::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);
1523 ErrExit:
1524     return hr;
1525 }
1526
1527 //-----------------------------------------------------------
1528 // GetCheckSumAlgorithmId
1529 //-----------------------------------------------------------
1530 HRESULT
1531 SymDocument::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);
1540 ErrExit:
1541     return hr;
1542 }
1543
1544 //-----------------------------------------------------------
1545 // GetCheckSum
1546 //-----------------------------------------------------------
1547 HRESULT
1548 SymDocument::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 //-----------------------------------------------------------
1571 HRESULT
1572 SymDocument::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
1625 ErrExit:
1626     return hr;
1627 }
1628
1629 //-----------------------------------------------------------
1630 // SymDocument HasEmbeddedSource
1631 //-----------------------------------------------------------
1632 HRESULT
1633 SymDocument::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 //-----------------------------------------------------------
1647 HRESULT
1648 SymDocument::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 //-----------------------------------------------------------
1662 HRESULT
1663 SymDocument::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  * ------------------------------------------------------------------------- */
1683 HRESULT
1684 SymMethod::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 //-----------------------------------------------------------
1709 HRESULT
1710 SymMethod::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();
1719 ErrExit:
1720     return hr;
1721 }
1722
1723
1724 //-----------------------------------------------------------
1725 // GetSequencePointCount
1726 //-----------------------------------------------------------
1727 HRESULT
1728 SymMethod::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());
1739 ErrExit:    
1740     return hr;
1741 }
1742
1743 //-----------------------------------------------------------
1744 // GetSequencePoints
1745 //-----------------------------------------------------------
1746 HRESULT
1747 SymMethod::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
1804 ErrExit:
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 //-----------------------------------------------------------
1822 HRESULT
1823 SymMethod::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     }
1840 ErrExit:
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 //-----------------------------------------------------------
1849 HRESULT
1850 SymMethod::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     }
1888 ErrExit:    
1889     return hr;
1890 }
1891
1892 //-----------------------------------------------------------
1893 // GetRanges
1894 //-----------------------------------------------------------
1895 HRESULT
1896 SymMethod::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
1994 ErrExit:    
1995     return hr;
1996 }
1997
1998 //-----------------------------------------------------------
1999 // GetScopeFromOffset
2000 //-----------------------------------------------------------
2001 HRESULT
2002 SymMethod::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 //-----------------------------------------------------------
2017 HRESULT
2018 SymMethod::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 //-----------------------------------------------------------
2035 HRESULT
2036 SymMethod::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 //-----------------------------------------------------------
2050 HRESULT
2051 SymMethod::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 //-----------------------------------------------------------
2072 HRESULT
2073 SymScope::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 //-----------------------------------------------------------
2098 HRESULT
2099 SymScope::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
2111 ErrExit:
2112     return hr;
2113 }
2114
2115 //-----------------------------------------------------------
2116 // GetParent
2117 //-----------------------------------------------------------
2118 HRESULT
2119 SymScope::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     }
2136 ErrExit:    
2137     return hr;
2138 }
2139
2140 //-----------------------------------------------------------
2141 // GetChildren
2142 //-----------------------------------------------------------
2143 HRESULT
2144 SymScope::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
2182 ErrExit:    
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 //-----------------------------------------------------------
2197 HRESULT
2198 SymScope::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();
2206 ErrExit:
2207     return hr;
2208 }
2209
2210 //-----------------------------------------------------------
2211 // GetEndOffset
2212 //-----------------------------------------------------------
2213 HRESULT
2214 SymScope::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();
2222 ErrExit:
2223     return hr;
2224 }
2225
2226 //-----------------------------------------------------------
2227 // GetLocalCount
2228 //-----------------------------------------------------------
2229 HRESULT
2230 SymScope::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;
2258 ErrExit:    
2259     return hr;
2260 }
2261
2262 //-----------------------------------------------------------
2263 // GetLocals
2264 // Input: either pcLocals or
2265 //        cLocals and pLocals 
2266 //-----------------------------------------------------------
2267 HRESULT
2268 SymScope::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     }
2306 ErrExit:
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 //-----------------------------------------------------------
2323 HRESULT
2324 SymScope::GetNamespaces(
2325     ULONG32 cNameSpaces,    // [optional] number of entries pNameSpaces
2326     ULONG32 *pcNameSpaces,  // [optional, out] Maximum number of Namespace
2327     ISymUnmanagedNamespace *pNameSpaces[] // [optinal] 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     }
2356 ErrExit:
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 //-----------------------------------------------------------
2374 HRESULT
2375 SymReaderVar::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 //-----------------------------------------------------------
2400 HRESULT
2401 SymReaderVar::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
2435 ErrExit:
2436     return hr;
2437 }
2438
2439 //-----------------------------------------------------------
2440 // GetAttributes
2441 //-----------------------------------------------------------
2442 HRESULT
2443 SymReaderVar::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 //-----------------------------------------------------------
2457 HRESULT
2458 SymReaderVar::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
2478 ErrExit:
2479     return hr;
2480 }
2481
2482 //-----------------------------------------------------------
2483 // GetAddressKind
2484 //-----------------------------------------------------------
2485 HRESULT
2486 SymReaderVar::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();
2494 ErrExit:
2495     return S_OK;
2496 }
2497
2498 //-----------------------------------------------------------
2499 // GetAddressField1
2500 //-----------------------------------------------------------
2501 HRESULT
2502 SymReaderVar::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
2513 ErrExit:
2514     
2515     return hr;
2516 }
2517
2518 //-----------------------------------------------------------
2519 // GetAddressField2
2520 //-----------------------------------------------------------
2521 HRESULT
2522 SymReaderVar::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
2533 ErrExit:
2534     
2535     return hr;
2536 }
2537
2538 //-----------------------------------------------------------
2539 // GetAddressField3
2540 //-----------------------------------------------------------
2541 HRESULT
2542 SymReaderVar::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
2553 ErrExit:
2554     
2555     return hr;
2556 }
2557
2558 //-----------------------------------------------------------
2559 // GetStartOffset
2560 //-----------------------------------------------------------
2561 HRESULT
2562 SymReaderVar::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 //-----------------------------------------------------------
2575 HRESULT
2576 SymReaderVar::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 //-----------------------------------------------------------
2594 HRESULT
2595 SymReaderNamespace::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 //-----------------------------------------------------------
2620 HRESULT
2621 SymReaderNamespace::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
2650 ErrExit:
2651     return hr;
2652 }
2653
2654 //-----------------------------------------------------------
2655 // GetNamespaces
2656 //-----------------------------------------------------------
2657 HRESULT
2658 SymReaderNamespace::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 //-----------------------------------------------------------
2672 HRESULT
2673 SymReaderNamespace::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 //-----------------------------------------------------------
2691 bool 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 //-----------------------------------------------------------
2729 bool 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 //-----------------------------------------------------------
2738 bool 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 //-----------------------------------------------------------
2749 bool 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 //-----------------------------------------------------------
2762 bool SequencePoint::IsUserLine()
2763 {
2764     return StartLine() != CODE_WITH_NO_SOURCE;
2765 }