summaryrefslogtreecommitdiff
path: root/src/debug/ildbsymlib
diff options
context:
space:
mode:
Diffstat (limited to 'src/debug/ildbsymlib')
-rw-r--r--src/debug/ildbsymlib/.gitmirror1
-rw-r--r--src/debug/ildbsymlib/CMakeLists.txt18
-rw-r--r--src/debug/ildbsymlib/classfactory.h95
-rw-r--r--src/debug/ildbsymlib/dirs.proj19
-rw-r--r--src/debug/ildbsymlib/ildbsymbols.cpp155
-rw-r--r--src/debug/ildbsymlib/ildbsymlib.props29
-rw-r--r--src/debug/ildbsymlib/ildbsymlib.vcproj213
-rw-r--r--src/debug/ildbsymlib/pch.h41
-rw-r--r--src/debug/ildbsymlib/pdbdata.h92
-rw-r--r--src/debug/ildbsymlib/symbinder.cpp163
-rw-r--r--src/debug/ildbsymlib/symbinder.h73
-rw-r--r--src/debug/ildbsymlib/symread.cpp2765
-rw-r--r--src/debug/ildbsymlib/symread.h554
-rw-r--r--src/debug/ildbsymlib/symwrite.cpp1553
-rw-r--r--src/debug/ildbsymlib/symwrite.h1226
-rw-r--r--src/debug/ildbsymlib/umisc.h69
16 files changed, 7066 insertions, 0 deletions
diff --git a/src/debug/ildbsymlib/.gitmirror b/src/debug/ildbsymlib/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/debug/ildbsymlib/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/debug/ildbsymlib/CMakeLists.txt b/src/debug/ildbsymlib/CMakeLists.txt
new file mode 100644
index 0000000000..1bd1096ed6
--- /dev/null
+++ b/src/debug/ildbsymlib/CMakeLists.txt
@@ -0,0 +1,18 @@
+if(WIN32)
+ #use static crt
+ add_definitions(-MT)
+endif(WIN32)
+
+set( ILDBSYMLIB_SOURCES
+ symread.cpp
+ symbinder.cpp
+ ildbsymbols.cpp
+ symwrite.cpp
+)
+
+if(CLR_CMAKE_PLATFORM_UNIX)
+ add_compile_options(-fPIC)
+endif(CLR_CMAKE_PLATFORM_UNIX)
+
+add_library_clr(ildbsymlib ${ILDBSYMLIB_SOURCES})
+
diff --git a/src/debug/ildbsymlib/classfactory.h b/src/debug/ildbsymlib/classfactory.h
new file mode 100644
index 0000000000..2b38167747
--- /dev/null
+++ b/src/debug/ildbsymlib/classfactory.h
@@ -0,0 +1,95 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ===========================================================================
+// File: ClassFactory.h
+//
+
+// ===========================================================================
+
+//*****************************************************************************
+// ClassFactory.h
+//
+// Class factories are used by the pluming in COM to activate new objects.
+// This module contains the class factory code to instantiate the
+// ISymUnmanaged Reader,Writer and Binder
+//*****************************************************************************
+#ifndef __ILDBClassFactory__h__
+#define __ILDBClassFactory__h__
+
+// This typedef is for a function which will create a new instance of an object.
+typedef HRESULT (* PFN_CREATE_OBJ)(REFIID riid, void**ppvObject);
+
+//*****************************************************************************
+// This structure is used to declare a global list of coclasses. The class
+// factory object is created with a pointer to the correct one of these, so
+// that when create instance is called, it can be created.
+//*****************************************************************************
+struct COCLASS_REGISTER
+{
+ const GUID *pClsid; // Class ID of the coclass.
+ LPCWSTR szProgID; // Prog ID of the class.
+ PFN_CREATE_OBJ pfnCreateObject; // Creation function for an instance.
+};
+
+
+
+//*****************************************************************************
+// One class factory object satifies all of our clsid's, to reduce overall
+// code bloat.
+//*****************************************************************************
+class CIldbClassFactory :
+ public IClassFactory
+{
+ CIldbClassFactory() { } // Can't use without data.
+
+public:
+ CIldbClassFactory(const COCLASS_REGISTER *pCoClass)
+ : m_cRef(1), m_pCoClass(pCoClass)
+ { }
+
+ virtual ~CIldbClassFactory() {}
+
+ //
+ // IUnknown methods.
+ //
+
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void **ppvObject);
+
+ virtual ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }
+
+ virtual ULONG STDMETHODCALLTYPE Release()
+ {
+ LONG cRef = InterlockedDecrement(&m_cRef);
+ if (cRef <= 0)
+ DELETE(this);
+ return (cRef);
+ }
+
+
+ //
+ // IClassFactory methods.
+ //
+
+ virtual HRESULT STDMETHODCALLTYPE CreateInstance(
+ IUnknown *pUnkOuter,
+ REFIID riid,
+ void **ppvObject);
+
+ virtual HRESULT STDMETHODCALLTYPE LockServer(
+ BOOL fLock);
+
+
+private:
+ LONG m_cRef; // Reference count.
+ const COCLASS_REGISTER *m_pCoClass; // The class we belong to.
+};
+
+
+
+#endif // __ClassFactory__h__
diff --git a/src/debug/ildbsymlib/dirs.proj b/src/debug/ildbsymlib/dirs.proj
new file mode 100644
index 0000000000..b171f7bca5
--- /dev/null
+++ b/src/debug/ildbsymlib/dirs.proj
@@ -0,0 +1,19 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup>
+ <BuildInPhase1>true</BuildInPhase1>
+ <BuildInPhaseDefault>false</BuildInPhaseDefault>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ </PropertyGroup>
+
+ <!--The following projects will build during PHASE 1-->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1'">
+ <ProjectFile Condition="'$(FeatureDbiDebugging)'=='true'" Include="HostLocal\ildbsymlib.nativeproj" />
+ </ItemGroup>
+
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" />
+</Project>
diff --git a/src/debug/ildbsymlib/ildbsymbols.cpp b/src/debug/ildbsymlib/ildbsymbols.cpp
new file mode 100644
index 0000000000..1c9219ce62
--- /dev/null
+++ b/src/debug/ildbsymlib/ildbsymbols.cpp
@@ -0,0 +1,155 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ===========================================================================
+// File: ildbsymbols.cpp
+//
+
+// ===========================================================================
+
+#include "pch.h"
+
+#include "classfactory.h"
+
+// GUID identifying the ILDB format version.
+extern "C" const GUID ILDB_VERSION_GUID = {0x9e02e5b6, 0x8aef, 0x4d06, { 0x82, 0xe8, 0xe, 0x9b, 0x45, 0x49, 0x97, 0x16} };
+
+// Version used for the "first source release", no longer supported.
+extern "C" const GUID ILDB_VERSION_GUID_FSR = {0xCB2F6723, 0xAB3A, 0x11d, { 0x9C, 0x40, 0x00, 0xC0, 0x4F, 0xA3, 0x0A, 0x3E} };
+
+// This map contains the list of coclasses which are exported from this module.
+const COCLASS_REGISTER g_CoClasses[] =
+{
+// pClsid szProgID pfnCreateObject
+ { &CLSID_CorSymReader_SxS, W("CorSymReader"), SymReader::NewSymReader},
+ { &CLSID_CorSymWriter_SxS, W("CorSymWriter"), SymWriter::NewSymWriter},
+ { &CLSID_CorSymBinder_SxS, W("CorSymBinder"), SymBinder::NewSymBinder},
+ { NULL, NULL, NULL }
+};
+
+STDAPI IldbSymbolsGetClassObject(REFCLSID rclsid, REFIID riid, void** ppvObject)
+{
+ CIldbClassFactory *pClassFactory; // To create class factory object.
+ const COCLASS_REGISTER *pCoClass; // Loop control.
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+
+ _ASSERTE(IsValidCLSID(rclsid));
+ _ASSERTE(IsValidIID(riid));
+ _ASSERTE(IsValidWritePtr(ppvObject, void*));
+
+ if (ppvObject)
+ {
+ *ppvObject = NULL;
+
+ // Scan for the right one.
+ for (pCoClass=g_CoClasses; pCoClass->pClsid; pCoClass++)
+ {
+ if (*pCoClass->pClsid == rclsid)
+ {
+ // Allocate the new factory object.
+ pClassFactory = NEW(CIldbClassFactory(pCoClass));
+ if (!pClassFactory)
+ return (E_OUTOFMEMORY);
+
+ // Pick the v-table based on the caller's request.
+ hr = pClassFactory->QueryInterface(riid, ppvObject);
+
+ // Always release the local reference, if QI failed it will be
+ // the only one and the object gets freed.
+ pClassFactory->Release();
+ break;
+ }
+ }
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+
+ return hr;
+}
+
+/* ------------------------------------------------------------------------- *
+ * CIldbClassFactory class
+ * ------------------------------------------------------------------------- */
+
+//*****************************************************************************
+// QueryInterface is called to pick a v-table on the co-class.
+//*****************************************************************************
+HRESULT STDMETHODCALLTYPE CIldbClassFactory::QueryInterface(
+ REFIID riid,
+ void **ppvObject)
+{
+ HRESULT hr;
+
+ if (ppvObject == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ // Avoid confusion.
+ *ppvObject = NULL;
+
+ // Pick the right v-table based on the IID passed in.
+ if (riid == IID_IUnknown)
+ *ppvObject = (IUnknown *) this;
+ else if (riid == IID_IClassFactory)
+ *ppvObject = (IClassFactory *) this;
+
+ // If successful, add a reference for out pointer and return.
+ if (*ppvObject)
+ {
+ hr = S_OK;
+ AddRef();
+ }
+ else
+ hr = E_NOINTERFACE;
+ return (hr);
+}
+
+
+//*****************************************************************************
+// CreateInstance is called to create a new instance of the coclass for which
+// this class was created in the first place. The returned pointer is the
+// v-table matching the IID if there.
+//*****************************************************************************
+HRESULT STDMETHODCALLTYPE CIldbClassFactory::CreateInstance(
+ IUnknown *pUnkOuter,
+ REFIID riid,
+ void **ppvObject)
+{
+ HRESULT hr;
+
+ _ASSERTE(IsValidIID(riid));
+ _ASSERTE(IsValidWritePtr(ppvObject, void*));
+
+ // Avoid confusion.
+ *ppvObject = NULL;
+ _ASSERTE(m_pCoClass);
+
+ // Aggregation is not supported by these objects.
+ if (pUnkOuter)
+ return (CLASS_E_NOAGGREGATION);
+
+ // Ask the object to create an instance of itself, and check the iid.
+ hr = (*m_pCoClass->pfnCreateObject)(riid, ppvObject);
+ return (hr);
+}
+
+// Version of CreateInstance called directly from clients
+STDAPI IldbSymbolsCreateInstance(REFCLSID rclsid, REFIID riid, void** ppvIUnknown)
+{
+ IClassFactory *pClassFactory = NULL;
+ HRESULT hr = IldbSymbolsGetClassObject(rclsid, IID_IClassFactory, (void**)&pClassFactory);
+ if (SUCCEEDED(hr))
+ hr = pClassFactory->CreateInstance(NULL, riid, ppvIUnknown);
+ if (pClassFactory)
+ pClassFactory->Release();
+ return hr;
+}
+
+HRESULT STDMETHODCALLTYPE CIldbClassFactory::LockServer(
+ BOOL fLock)
+{
+ return (S_OK);
+}
diff --git a/src/debug/ildbsymlib/ildbsymlib.props b/src/debug/ildbsymlib/ildbsymlib.props
new file mode 100644
index 0000000000..2a64f2eb7e
--- /dev/null
+++ b/src/debug/ildbsymlib/ildbsymlib.props
@@ -0,0 +1,29 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+ <!--*****************************************************-->
+ <!--This MSBuild project file was automatically generated-->
+ <!--from the original SOURCES/DIRS file by the KBC tool.-->
+ <!--*****************************************************-->
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <TargetType>LIBRARY</TargetType>
+ <OutputPath>$(ClrLibDest)</OutputPath>
+ <LinkSubsystem>windows</LinkSubsystem>
+ <UseMsvcrt />
+ <ExceptionHandling>$(Sehonly)</ExceptionHandling>
+ <UserIncludes>$(UserIncludes);
+ ..\;
+ ..\..\..\inc;
+ </UserIncludes>
+ <CDefines>$(CDefines);UNICODE;_UNICODE</CDefines>
+ </PropertyGroup>
+ <!--Leaf Project Items-->
+ <ItemGroup>
+ <CppCompile Include="..\symread.cpp" />
+ <CppCompile Include="..\symbinder.cpp" />
+ <CppCompile Include="..\ildbsymbols.cpp" />
+ <CppCompile Include="..\symwrite.cpp" />
+ </ItemGroup>
+
+</Project>
diff --git a/src/debug/ildbsymlib/ildbsymlib.vcproj b/src/debug/ildbsymlib/ildbsymlib.vcproj
new file mode 100644
index 0000000000..07202121d9
--- /dev/null
+++ b/src/debug/ildbsymlib/ildbsymlib.vcproj
@@ -0,0 +1,213 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="ildbsymlib"
+ ProjectGUID="{08C26436-55DD-4332-804C-C963A859E4DE}"
+ RootNamespace="ildbsymlib"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="4"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=".;..\..\inc"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;-DUNICODE -D_UNICODE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="4"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=".;..\..\inc"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;-DUNICODE -D_UNICODE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\classfactory.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\inc\IldbSymLib.h"
+ >
+ </File>
+ <File
+ RelativePath=".\pch.h"
+ >
+ </File>
+ <File
+ RelativePath=".\pdbdata.h"
+ >
+ </File>
+ <File
+ RelativePath=".\symbinder.h"
+ >
+ </File>
+ <File
+ RelativePath=".\SymRead.h"
+ >
+ </File>
+ <File
+ RelativePath=".\SymWrite.h"
+ >
+ </File>
+ <File
+ RelativePath=".\umisc.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\ildbsymbols.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\symbinder.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\SymRead.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\symwrite.cpp"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/debug/ildbsymlib/pch.h b/src/debug/ildbsymlib/pch.h
new file mode 100644
index 0000000000..ddd4787aa0
--- /dev/null
+++ b/src/debug/ildbsymlib/pch.h
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ===========================================================================
+// File: pch.h
+//
+
+// ===========================================================================
+
+#ifndef _ILDBSYMLIB_PCH_H_
+#define _ILDBSYMLIB_PCH_H_
+
+#include "ole2.h"
+
+#include "winwrap.h"
+#include "umisc.h"
+
+#include "corhdr.h"
+#include "corsym.h"
+#include "palclr.h"
+#include "cor.h"
+#include "genericstackprobe.h"
+
+// I'm not sure why this code uses these macros for memory management (they should at least be
+// in-line functions). DELETE is a symbol defined in WinNt.h as an access-type. We're probably
+// not going to try and use that, so we'll just override it for now.
+#ifdef DELETE
+#undef DELETE
+#endif
+
+
+#define NEW( x ) ( ::new (nothrow) x )
+#define DELETE( x ) ( ::delete(x) )
+#define DELETEARRAY( x ) (::delete[] (x))
+
+#include "ildbsymlib.h"
+#include "symwrite.h"
+#include "symread.h"
+#include "symbinder.h"
+
+#endif
diff --git a/src/debug/ildbsymlib/pdbdata.h b/src/debug/ildbsymlib/pdbdata.h
new file mode 100644
index 0000000000..cf09d782e7
--- /dev/null
+++ b/src/debug/ildbsymlib/pdbdata.h
@@ -0,0 +1,92 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ===========================================================================
+// File: pdbdata.h
+//
+
+// ===========================================================================
+
+#ifndef PDBDATA_H_
+#define PDBDATA_H_
+
+#include "umisc.h"
+#include "palclr.h"
+
+struct SymMethodInfo;
+struct SymLexicalScope;
+struct SymVariable;
+struct SymUsingNamespace;
+struct SymConstant;
+struct SequencePoint;
+struct DocumentInfo;
+struct MethodInfo;
+
+extern "C" const GUID ILDB_VERSION_GUID_FSR;
+extern "C" const GUID ILDB_VERSION_GUID;
+
+#define ILDB_MINOR_VERSION_NUMBER 0
+#define ILDB_SIGNATURE "_ildb_signature"
+#define ILDB_SIGNATURE_SIZE (16)
+
+typedef struct PDBInfo {
+
+ // Entry point of the PE
+ mdMethodDef m_userEntryPoint;
+
+ UINT32 m_CountOfMethods;
+ UINT32 m_CountOfScopes;
+ UINT32 m_CountOfVars;
+ UINT32 m_CountOfUsing;
+ UINT32 m_CountOfConstants;
+ UINT32 m_CountOfDocuments;
+ UINT32 m_CountOfSequencePoints;
+ UINT32 m_CountOfBytes;
+ UINT32 m_CountOfStringBytes;
+
+public:
+ PDBInfo()
+ {
+ memset(this, 0, sizeof(PDBInfo));
+ // Make sure m_userEntryPoint initialized correctly
+ _ASSERTE(mdTokenNil == 0);
+ }
+
+#if BIGENDIAN
+ void ConvertEndianness() {
+ m_userEntryPoint = VAL32(m_userEntryPoint);
+ m_CountOfMethods = VAL32(m_CountOfMethods);
+ m_CountOfScopes = VAL32(m_CountOfScopes);
+ m_CountOfVars = VAL32(m_CountOfVars);
+ m_CountOfUsing = VAL32(m_CountOfUsing);
+ m_CountOfConstants = VAL32(m_CountOfConstants);
+ m_CountOfSequencePoints = VAL32(m_CountOfSequencePoints);
+ m_CountOfDocuments = VAL32(m_CountOfDocuments);
+ m_CountOfBytes = VAL32(m_CountOfBytes);
+ m_CountOfStringBytes = VAL32(m_CountOfStringBytes);
+ }
+#else
+ void ConvertEndianness() {}
+#endif
+
+} PDBInfo;
+
+// The signature, Guid version + PDBInfo data
+#define ILDB_HEADER_SIZE (ILDB_SIGNATURE_SIZE + sizeof(GUID) + sizeof(PDBInfo) )
+
+typedef struct PDBDataPointers
+{
+ SymMethodInfo * m_pMethods; // Method information
+ SymLexicalScope *m_pScopes; // Scopes
+ SymVariable *m_pVars; // Local Variables
+ SymUsingNamespace *m_pUsings; // list of using/imports
+ SymConstant *m_pConstants; // Constants
+ DocumentInfo *m_pDocuments; // Documents
+ SequencePoint *m_pSequencePoints; // Sequence Points
+ // Array of various bytes (variable signature, etc)
+ BYTE *m_pBytes;
+ // Strings
+ BYTE *m_pStringsBytes;
+} PDBDataPointers;
+
+#endif /* PDBDATA_H_ */
diff --git a/src/debug/ildbsymlib/symbinder.cpp b/src/debug/ildbsymlib/symbinder.cpp
new file mode 100644
index 0000000000..d3cf1c647b
--- /dev/null
+++ b/src/debug/ildbsymlib/symbinder.cpp
@@ -0,0 +1,163 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ===========================================================================
+// File: symbinder.cpp
+//
+
+// ===========================================================================
+
+#include "pch.h"
+#include "symbinder.h"
+
+/* ------------------------------------------------------------------------- *
+ * SymBinder class
+ * ------------------------------------------------------------------------- */
+
+HRESULT
+SymBinder::QueryInterface(
+ REFIID riid,
+ void **ppvObject
+ )
+{
+ HRESULT hr = S_OK;
+
+ _ASSERTE(IsValidIID(riid));
+ _ASSERTE(IsValidWritePtr(ppvObject, void*));
+
+ IfFalseGo( ppvObject, E_INVALIDARG );
+
+ if (riid == IID_ISymUnmanagedBinder)
+ {
+ *ppvObject = (ISymUnmanagedBinder*) this;
+ }
+ else if (riid == IID_ISymUnmanagedBinder2)
+ {
+ *ppvObject = (ISymUnmanagedBinder2*) this;
+ }
+ else if (riid == IID_IUnknown)
+ {
+ *ppvObject = (IUnknown*)this;
+ }
+ else
+ {
+ *ppvObject = NULL;
+ hr = E_NOINTERFACE;
+ }
+
+ if (*ppvObject)
+ {
+ AddRef();
+ }
+
+ErrExit:
+
+ return hr;
+}
+
+HRESULT
+SymBinder::NewSymBinder(
+ REFCLSID clsid,
+ void** ppObj
+ )
+{
+ HRESULT hr = S_OK;
+ SymBinder* pSymBinder = NULL;
+
+ _ASSERTE(IsValidCLSID(clsid));
+ _ASSERTE(IsValidWritePtr(ppObj, IUnknown*));
+
+ if (clsid != IID_ISymUnmanagedBinder)
+ return (E_UNEXPECTED);
+
+ IfFalseGo( ppObj, E_INVALIDARG );
+
+ *ppObj = NULL;
+
+ IfNullGo( pSymBinder = NEW(SymBinder()) );
+ *ppObj = pSymBinder;
+ pSymBinder->AddRef();
+ pSymBinder = NULL;
+
+ErrExit:
+
+ RELEASE( pSymBinder );
+
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetReaderForFile
+//-----------------------------------------------------------
+HRESULT
+SymBinder::GetReaderForFile(
+ IUnknown *importer, // IMetaDataImporter
+ const WCHAR *fileName, // File we're looking symbols for
+ const WCHAR *searchPath, // Search path for file
+ ISymUnmanagedReader **ppRetVal) // Out: SymReader for file
+{
+ HRESULT hr = S_OK;
+ ISymUnmanagedReader *pSymReader = NULL;
+ IfFalseGo( ppRetVal && fileName && fileName[0] != '\0', E_INVALIDARG );
+
+ // Init Out parameter
+ *ppRetVal = NULL;
+
+ // Call the class factory directly.
+ IfFailGo(IldbSymbolsCreateInstance(CLSID_CorSymReader_SxS,
+ IID_ISymUnmanagedReader,
+ (void**)&pSymReader));
+
+ IfFailGo(pSymReader->Initialize(importer, fileName, searchPath, NULL));
+
+ // Transfer ownership to the out parameter
+ *ppRetVal = pSymReader;
+ pSymReader = NULL;
+
+ErrExit:
+ RELEASE(pSymReader);
+ return hr;
+}
+
+HRESULT
+SymBinder::GetReaderFromStream(
+ IUnknown *importer,
+ IStream *pStream,
+ ISymUnmanagedReader **ppRetVal
+ )
+{
+ HRESULT hr = S_OK;
+ ISymUnmanagedReader *pSymReader = NULL;
+ IfFalseGo( ppRetVal && importer && pStream, E_INVALIDARG );
+
+ // Init Out parameter
+ *ppRetVal = NULL;
+
+ // Call the class factory directly
+ IfFailGo(IldbSymbolsCreateInstance(CLSID_CorSymReader_SxS,
+ IID_ISymUnmanagedReader,
+ (void**)&pSymReader));
+
+ IfFailGo(pSymReader->Initialize(importer, NULL, NULL, pStream));
+
+ // Transfer ownership to the out parameter
+ *ppRetVal = pSymReader;
+ pSymReader = NULL;
+
+ErrExit:
+ RELEASE(pSymReader);
+ return hr;
+}
+
+HRESULT SymBinder::GetReaderForFile2(
+ IUnknown *importer,
+ const WCHAR *fileName,
+ const WCHAR *searchPath,
+ ULONG32 searchPolicy,
+ ISymUnmanagedReader **pRetVal)
+{
+ // This API exists just to allow VS to function properly.
+ // ILDB doesn't support any search policy or search path - we only look
+ // next to the image file.
+ return GetReaderForFile(importer, fileName, searchPath, pRetVal);
+}
diff --git a/src/debug/ildbsymlib/symbinder.h b/src/debug/ildbsymlib/symbinder.h
new file mode 100644
index 0000000000..a0dcf7d4c7
--- /dev/null
+++ b/src/debug/ildbsymlib/symbinder.h
@@ -0,0 +1,73 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ===========================================================================
+// File: SymBinder.h
+//
+
+// ===========================================================================
+
+#ifndef SYMBINDER_H_
+#define SYMBINDER_H_
+
+/* ------------------------------------------------------------------------- *
+ * SymBinder class
+ * ------------------------------------------------------------------------- */
+
+class SymBinder : ISymUnmanagedBinder2
+{
+// ctor/dtor
+public:
+ SymBinder()
+ {
+ m_refCount = 0;
+ }
+
+ virtual ~SymBinder() {}
+
+ static HRESULT NewSymBinder( REFCLSID clsid, void** ppObj );
+
+// IUnknown methods
+public:
+
+ //-----------------------------------------------------------
+ // IUnknown support
+ //-----------------------------------------------------------
+ ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return (InterlockedIncrement((LONG *) &m_refCount));
+ }
+
+ ULONG STDMETHODCALLTYPE Release()
+ {
+ LONG refCount = InterlockedDecrement((LONG *) &m_refCount);
+ if (refCount == 0)
+ DELETE(this);
+
+ return (refCount);
+ }
+ STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject);
+
+ // ISymUnmanagedBinder
+public:
+
+ STDMETHOD(GetReaderForFile)( IUnknown *importer,
+ const WCHAR *fileName,
+ const WCHAR *searchPath,
+ ISymUnmanagedReader **pRetVal);
+ STDMETHOD(GetReaderFromStream)(IUnknown *importer,
+ IStream *pstream,
+ ISymUnmanagedReader **pRetVal);
+
+ // ISymUnmanagedBinder2
+ STDMETHOD(GetReaderForFile2)( IUnknown *importer,
+ const WCHAR *fileName,
+ const WCHAR *searchPath,
+ ULONG32 searchPolicy,
+ ISymUnmanagedReader **pRetVal);
+
+private:
+ SIZE_T m_refCount;
+
+};
+#endif
diff --git a/src/debug/ildbsymlib/symread.cpp b/src/debug/ildbsymlib/symread.cpp
new file mode 100644
index 0000000000..3fe3c8c9cc
--- /dev/null
+++ b/src/debug/ildbsymlib/symread.cpp
@@ -0,0 +1,2765 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ===========================================================================
+// File: symread.cpp
+//
+
+// ===========================================================================
+#include "pch.h"
+#include "symread.h"
+#include "corimage.h"
+
+#define CODE_WITH_NO_SOURCE 0xfeefee
+// -------------------------------------------------------------------------
+// SymReader class
+// -------------------------------------------------------------------------
+
+//-----------------------------------------------------------
+// NewSymReader
+// Static function used to create a new instance of SymReader
+//-----------------------------------------------------------
+HRESULT
+SymReader::NewSymReader(
+ REFCLSID clsid,
+ void** ppObj
+ )
+{
+ HRESULT hr = S_OK;
+ SymReader* pSymReader = NULL;
+
+ _ASSERTE(IsValidCLSID(clsid));
+ _ASSERTE(IsValidWritePtr(ppObj, IUnknown*));
+
+ if (clsid != IID_ISymUnmanagedReader)
+ return (E_UNEXPECTED);
+
+ IfFalseGo(ppObj, E_INVALIDARG);
+
+ *ppObj = NULL;
+ IfNullGo( pSymReader = NEW(SymReader()));
+
+ *ppObj = pSymReader;
+ pSymReader->AddRef();
+ pSymReader = NULL;
+
+ErrExit:
+
+ RELEASE( pSymReader );
+
+ return hr;
+}
+
+
+//-----------------------------------------------------------
+// ~SymReader
+//-----------------------------------------------------------
+SymReader::~SymReader()
+{
+ Cleanup();
+}
+
+//-----------------------------------------------------------
+// Cleanup
+// Release all memory and clear initialized data structures
+// (eg. as a result of a failed Initialization attempt)
+//-----------------------------------------------------------
+void SymReader::Cleanup()
+{
+ if (m_pDocs)
+ {
+ unsigned i;
+ for(i = 0; i < m_pPDBInfo->m_CountOfDocuments; i++)
+ {
+ RELEASE(m_pDocs[i]);
+ }
+ }
+
+ DELETE(m_pPDBInfo);
+ m_pPDBInfo = NULL;
+
+ // If we loaded from stream, then free the memory we allocated
+ if (m_fInitializeFromStream)
+ {
+ DELETEARRAY(m_DataPointers.m_pBytes);
+ DELETEARRAY(m_DataPointers.m_pConstants);
+ DELETEARRAY(m_DataPointers.m_pDocuments);
+ DELETEARRAY(m_DataPointers.m_pMethods);
+ DELETEARRAY(m_DataPointers.m_pScopes);
+ DELETEARRAY(m_DataPointers.m_pSequencePoints);
+ DELETEARRAY(m_DataPointers.m_pStringsBytes);
+ DELETEARRAY(m_DataPointers.m_pUsings);
+ DELETEARRAY(m_DataPointers.m_pVars);
+ }
+
+ DELETEARRAY(m_pDocs);
+ m_pDocs = NULL;
+
+ RELEASE(m_pImporter);
+ m_pImporter = NULL;
+
+ memset(&m_DataPointers, 0, sizeof(PDBDataPointers));
+ m_szPath[0] = '\0';
+}
+
+//-----------------------------------------------------------
+// ~QueryInterface
+//-----------------------------------------------------------
+HRESULT
+SymReader::QueryInterface(
+ REFIID riid,
+ void **ppvObject
+ )
+{
+ HRESULT hr = S_OK;
+
+ _ASSERTE(IsValidIID(riid));
+ _ASSERTE(IsValidWritePtr(ppvObject, void*));
+
+ IfFalseGo(ppvObject, E_INVALIDARG);
+ if (riid == IID_ISymUnmanagedReader)
+ {
+ *ppvObject = (ISymUnmanagedReader*) this;
+ }
+ else
+ if (riid == IID_IUnknown)
+ {
+ *ppvObject = (IUnknown*)this;
+ }
+ else
+ {
+ *ppvObject = NULL;
+ hr = E_NOINTERFACE;
+ }
+
+ if (*ppvObject)
+ {
+ AddRef();
+ }
+
+ErrExit:
+
+ return hr;
+}
+
+static HRESULT ReadFromStream(IStream *pIStream, void *pv, ULONG cb)
+{
+ HRESULT hr = NOERROR;
+ ULONG ulBytesRead;
+
+ IfFailGo(pIStream->Read(pv, cb, &ulBytesRead));
+ if (ulBytesRead != cb)
+ IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// Initialize
+// Pass in the required information to read in the debug info
+// If a stream is passed in, it is used, otherwise a filename
+// must be passed in
+//-----------------------------------------------------------
+HRESULT SymReader::Initialize(
+ IUnknown *importer, // Cash it to be consistent with CLR
+ const WCHAR* szFileName, // File name of the ildb
+ const WCHAR* szsearchPath, // Search Path
+ IStream *pIStream // IStream
+ )
+{
+ HRESULT hr = NOERROR;
+ _ASSERTE(szFileName || pIStream);
+ IfFalseGo(szFileName || pIStream, E_INVALIDARG );
+
+ _ASSERTE(!m_fInitialized);
+ IfFalseGo(!m_fInitialized, E_UNEXPECTED);
+
+ // If it's passed in, we need to AddRef to be consistent the
+ // desktop version since ReleaseImporterFromISymUnmanagedReader (ceeload.cpp)
+ // assumes there's an addref
+ if (importer)
+ {
+ m_pImporter = importer;
+ m_pImporter->AddRef();
+ }
+
+ // See if we're reading from a file or stream
+ if (pIStream == NULL)
+ {
+ // We're initializing from a file
+ m_fInitializeFromStream = false;
+ IfFailGo(InitializeFromFile(szFileName, szsearchPath));
+ }
+ else
+ {
+ // We're reading in from a stream
+ m_fInitializeFromStream = true;
+ IfFailGo(InitializeFromStream(pIStream));
+ }
+
+ // Note that up to this point, the data we've read in has not been validated. Since we don't trust
+ // our input, it's important that we don't proceed with using this data until validation has been
+ // successful.
+ IfFailGo(ValidateData());
+
+
+ErrExit:
+ // If we have not succeeded, then we need to clean up our data structures. This would allow a client to call
+ // Initialize again, but also ensures we can't possibly use partial or otherwise invalid (possibly
+ // malicious) data.
+ if (FAILED(hr))
+ {
+ Cleanup();
+ }
+ else
+ {
+ // Otherwise we are not properly initialized
+ m_fInitialized = true;
+ }
+
+ return hr;
+}
+
+//-----------------------------------------------------------
+// Initialize the data structures by reading from the supplied stream
+// Note that upon completion the data has not yet been validated for safety.
+//-----------------------------------------------------------
+HRESULT SymReader::InitializeFromStream(
+ IStream *pIStream // IStream
+ )
+{
+ GUID GuidVersion;
+ BYTE *pSignature;
+ HRESULT hr = S_OK;
+
+ // Reset the stream to the begining
+ LARGE_INTEGER li;
+ li.u.HighPart = 0;
+ li.u.LowPart = 0;
+
+ // Make sure we're at the beginning of the stream
+ IfFailGo(pIStream->Seek(li, STREAM_SEEK_SET, NULL));
+
+ IfNullGo(pSignature = (BYTE *)_alloca(ILDB_SIGNATURE_SIZE));
+ IfFailGo(ReadFromStream(pIStream, pSignature, ILDB_SIGNATURE_SIZE));
+
+ // Verify that we're looking at an ILDB File
+ if (memcmp(pSignature, ILDB_SIGNATURE, ILDB_SIGNATURE_SIZE))
+ {
+ IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
+ }
+
+ IfFailGo(ReadFromStream(pIStream, &GuidVersion, sizeof(GUID)));
+
+ SwapGuid(&GuidVersion);
+
+ if (memcmp(&GuidVersion, &ILDB_VERSION_GUID, sizeof(GUID)))
+ {
+ IfFailGo(HrFromWin32(ERROR_INVALID_DATA));
+ }
+
+ IfNullGo(m_pPDBInfo = NEW(PDBInfo));
+
+ memset(m_pPDBInfo, 0 , sizeof(PDBInfo));
+ IfFailGo(ReadFromStream(pIStream, m_pPDBInfo, sizeof(PDBInfo)));
+
+ // Swap the counts
+ m_pPDBInfo->ConvertEndianness();
+
+ if (m_pPDBInfo->m_CountOfConstants)
+ {
+ IfNullGo(m_DataPointers.m_pConstants = NEW(SymConstant[m_pPDBInfo->m_CountOfConstants]));
+ IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pConstants, m_pPDBInfo->m_CountOfConstants*sizeof(SymConstant)));
+ }
+
+ if (m_pPDBInfo->m_CountOfMethods)
+ {
+ IfNullGo(m_DataPointers.m_pMethods = NEW(SymMethodInfo[m_pPDBInfo->m_CountOfMethods]));
+ IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pMethods, m_pPDBInfo->m_CountOfMethods*sizeof(SymMethodInfo)));
+ }
+
+ if (m_pPDBInfo->m_CountOfScopes)
+ {
+ IfNullGo(m_DataPointers.m_pScopes = NEW(SymLexicalScope[m_pPDBInfo->m_CountOfScopes]));
+ IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pScopes, m_pPDBInfo->m_CountOfScopes*sizeof(SymLexicalScope)));
+ }
+
+ if (m_pPDBInfo->m_CountOfVars)
+ {
+ IfNullGo(m_DataPointers.m_pVars = NEW(SymVariable[m_pPDBInfo->m_CountOfVars]));
+ IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pVars, m_pPDBInfo->m_CountOfVars*sizeof(SymVariable)));
+ }
+
+ if (m_pPDBInfo->m_CountOfUsing)
+ {
+ IfNullGo(m_DataPointers.m_pUsings = NEW(SymUsingNamespace[m_pPDBInfo->m_CountOfUsing]));
+ IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pUsings, m_pPDBInfo->m_CountOfUsing*sizeof(SymUsingNamespace)));
+ }
+
+ if (m_pPDBInfo->m_CountOfSequencePoints)
+ {
+ IfNullGo(m_DataPointers.m_pSequencePoints = NEW(SequencePoint[m_pPDBInfo->m_CountOfSequencePoints]));
+ IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pSequencePoints, m_pPDBInfo->m_CountOfSequencePoints*sizeof(SequencePoint)));
+ }
+
+ if (m_pPDBInfo->m_CountOfDocuments)
+ {
+ IfNullGo(m_DataPointers.m_pDocuments = NEW(DocumentInfo[m_pPDBInfo->m_CountOfDocuments]));
+ IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pDocuments, m_pPDBInfo->m_CountOfDocuments*sizeof(DocumentInfo)));
+ }
+
+ if (m_pPDBInfo->m_CountOfBytes)
+ {
+ IfNullGo(m_DataPointers.m_pBytes = NEW(BYTE[m_pPDBInfo->m_CountOfBytes]));
+ IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pBytes, m_pPDBInfo->m_CountOfBytes*sizeof(BYTE)));
+ }
+
+
+ if (m_pPDBInfo->m_CountOfStringBytes)
+ {
+ IfNullGo(m_DataPointers.m_pStringsBytes = NEW(BYTE[m_pPDBInfo->m_CountOfStringBytes]));
+ IfFailGo(ReadFromStream(pIStream, m_DataPointers.m_pStringsBytes, m_pPDBInfo->m_CountOfStringBytes));
+ }
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// ValidateData
+// Checks the contents of everything in m_DataPointers (i.e. all the structures read from the file)
+// to make sure it is valid. Specifically, validates that all indexes are within bounds for the
+// sizes allocated.
+//-----------------------------------------------------------
+HRESULT SymReader::ValidateData()
+{
+ HRESULT hr = S_OK;
+
+ for (UINT32 i = 0; i < m_pPDBInfo->m_CountOfConstants; i++)
+ {
+ SymConstant & c = m_DataPointers.m_pConstants[i];
+ IfFalseGo(c.ParentScope() < m_pPDBInfo->m_CountOfScopes, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(c.Name() < m_pPDBInfo->m_CountOfStringBytes, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFailGo(ValidateBytes(c.Signature(), c.SignatureSize()));
+ }
+
+ for (UINT32 i = 0; i < m_pPDBInfo->m_CountOfMethods; i++)
+ {
+ // Note that start/end values may equal the count (i.e. point one past the end) because
+ // the end is the extent, and start can equal end to indicate no entries.
+ SymMethodInfo & m = m_DataPointers.m_pMethods[i];
+ IfFalseGo(m.StartScopes() <= m_pPDBInfo->m_CountOfScopes, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.EndScopes() <= m_pPDBInfo->m_CountOfScopes, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.StartScopes() <= m.EndScopes(), HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.StartVars() <= m_pPDBInfo->m_CountOfVars, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.EndVars() <= m_pPDBInfo->m_CountOfVars, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.StartVars() <= m.EndVars(), HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.StartUsing() <= m_pPDBInfo->m_CountOfUsing, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.EndUsing() <= m_pPDBInfo->m_CountOfUsing, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.StartUsing() <= m.EndUsing(), HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.StartConstant() <= m_pPDBInfo->m_CountOfConstants, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.EndConstant() <= m_pPDBInfo->m_CountOfConstants, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.StartConstant() <= m.EndConstant(), HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.StartDocuments() <= m_pPDBInfo->m_CountOfDocuments, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.EndDocuments() <= m_pPDBInfo->m_CountOfDocuments, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.StartDocuments() <= m.EndDocuments(), HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.StartSequencePoints() <= m_pPDBInfo->m_CountOfSequencePoints, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.EndSequencePoints() <= m_pPDBInfo->m_CountOfSequencePoints, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(m.StartSequencePoints() <= m.EndSequencePoints(), HrFromWin32(ERROR_BAD_FORMAT));
+ }
+
+ for (UINT32 i = 0; i < m_pPDBInfo->m_CountOfScopes; i++)
+ {
+ SymLexicalScope & s = m_DataPointers.m_pScopes[i];
+ IfFalseGo((s.ParentScope() == (UINT32)-1) || (s.ParentScope() < m_pPDBInfo->m_CountOfScopes), HrFromWin32(ERROR_BAD_FORMAT));
+ }
+
+ for (UINT32 i = 0; i < m_pPDBInfo->m_CountOfVars; i++)
+ {
+ SymVariable & v = m_DataPointers.m_pVars[i];
+ IfFalseGo(v.Scope() < m_pPDBInfo->m_CountOfScopes, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(v.Name() < m_pPDBInfo->m_CountOfStringBytes, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFailGo(ValidateBytes(v.Signature(), v.SignatureSize()));
+ }
+
+ for (UINT32 i = 0; i < m_pPDBInfo->m_CountOfUsing; i++)
+ {
+ SymUsingNamespace & u = m_DataPointers.m_pUsings[i];
+ IfFalseGo(u.ParentScope() < m_pPDBInfo->m_CountOfScopes, HrFromWin32(ERROR_BAD_FORMAT));
+ IfFalseGo(u.Name() < m_pPDBInfo->m_CountOfStringBytes, HrFromWin32(ERROR_BAD_FORMAT));
+ }
+
+ for (UINT32 i = 0; i < m_pPDBInfo->m_CountOfSequencePoints; i++)
+ {
+ SequencePoint & s = m_DataPointers.m_pSequencePoints[i];
+ IfFalseGo(s.Document() < m_pPDBInfo->m_CountOfDocuments, HrFromWin32(ERROR_BAD_FORMAT));
+ }
+
+ for (UINT32 i = 0; i < m_pPDBInfo->m_CountOfDocuments; i++)
+ {
+ DocumentInfo & d = m_DataPointers.m_pDocuments[i];
+ IfFailGo(ValidateBytes(d.CheckSumEntry(), d.CheckSumSize()));
+ IfFailGo(ValidateBytes(d.SourceEntry(), d.SourceSize()));
+ IfFalseGo(d.UrlEntry() < m_pPDBInfo->m_CountOfStringBytes, HrFromWin32(ERROR_BAD_FORMAT));
+ }
+
+ // Nothing to validate for the m_pBytes array - each reference must validate above that it's
+ // length doesn't exceed the array
+
+ // We expect all strings to be null terminated. To ensure no string operation overruns the buffer
+ // it sufficies to check that the buffer ends in a null character
+ if (m_pPDBInfo->m_CountOfStringBytes > 0)
+ {
+ IfFalseGo(m_DataPointers.m_pStringsBytes[m_pPDBInfo->m_CountOfStringBytes-1] == '\0', HrFromWin32(ERROR_BAD_FORMAT));
+ }
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// Validate a reference to the bytes array
+//-----------------------------------------------------------
+HRESULT SymReader::ValidateBytes(UINT32 bytesIndex, UINT32 bytesLen)
+{
+ S_UINT32 extent = S_UINT32(bytesIndex) + S_UINT32(bytesLen);
+ if (!extent.IsOverflow() &&
+ (extent.Value() <= m_pPDBInfo->m_CountOfBytes))
+ {
+ return S_OK;
+ }
+
+ return HrFromWin32(ERROR_BAD_FORMAT);
+}
+
+//-----------------------------------------------------------
+// VerifyPEDebugInfo
+// Verify that the debug info in the PE is the one we want
+//-----------------------------------------------------------
+HRESULT SymReader::VerifyPEDebugInfo(const WCHAR* szFileName)
+{
+ HRESULT hr = E_FAIL;
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ HANDLE hMapFile = INVALID_HANDLE_VALUE;
+ BYTE *pMod = NULL;
+ DWORD dwFileSize;
+ IMAGE_DEBUG_DIRECTORY *pDebugDir;
+ RSDSI *pDebugInfo;
+ DWORD dwUtf8Length;
+ DWORD dwUnicodeLength;
+
+ // We need to change the .pdb extension to .ildb
+ // compatible with VS7
+ wchar_t fullpath[_MAX_PATH];
+ wchar_t drive[_MAX_DRIVE];
+ wchar_t dir[_MAX_DIR];
+ wchar_t fname[_MAX_FNAME];
+
+ IMAGE_NT_HEADERS*pNT;
+
+ hFile = WszCreateFile(szFileName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ // Get the last error if we can
+ return HrFromWin32(GetLastError());
+ }
+
+ dwFileSize = GetFileSize(hFile, NULL);
+ if (dwFileSize < ILDB_HEADER_SIZE)
+ {
+ IfFailGo(HrFromWin32(ERROR_INVALID_DATA));
+ }
+
+ hMapFile = WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (hMapFile == NULL)
+ IfFailGo(HrFromWin32(GetLastError()));
+
+ pMod = (BYTE *) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
+ if (pMod == NULL)
+ IfFailGo(HrFromWin32(GetLastError()));
+
+ pNT = Cor_RtlImageNtHeader(pMod, dwFileSize);
+
+ // If there is no DebugEntry, then just error out
+ if (VAL32(pNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) == 0)
+ IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
+
+ // NOTE: This code is not secure against malformed PE files - any of the pointer additions below
+ // may be outside the range of memory mapped for the file. If we ever want to use this code
+ // on untrusted PE files, we should properly validate everything (probably by using PEDecoder).
+
+ DWORD offset;
+ offset = Cor_RtlImageRvaToOffset(pNT, VAL32(pNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress), dwFileSize);
+ if (offset == NULL)
+ IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
+ pDebugDir = (IMAGE_DEBUG_DIRECTORY *)(pMod + offset);
+ pDebugInfo = (RSDSI *)(pMod + VAL32(pDebugDir->PointerToRawData));
+
+ if (pDebugInfo->dwSig != VAL32(0x53445352)) // "SDSR"
+ {
+ IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
+ }
+
+
+ // Try the returned Stored Name since it might be a fully qualified path
+ dwUtf8Length = VAL32(pDebugDir->SizeOfData) - sizeof(RSDSI);
+ dwUnicodeLength = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR) pDebugInfo->szPDB, dwUtf8Length, fullpath, COUNTOF(fullpath) - 1);
+
+ // Make sure it's NULL terminated
+ _ASSERTE(dwUnicodeLength < COUNTOF(fullpath));
+ fullpath[dwUnicodeLength]='\0';
+
+ // Replace the extension with ildb
+ if (_wsplitpath_s( fullpath, drive, COUNTOF(drive), dir, COUNTOF(dir), fname, COUNTOF(fname), NULL, 0 ))
+ IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
+ if (_wmakepath_s(m_szStoredSymbolName, MAX_LONGPATH, drive, dir, fname, W("ildb") ))
+ IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
+
+ // It looks valid, make sure to set the return code
+ hr = S_OK;
+ErrExit:
+ if (pMod)
+ UnmapViewOfFile(pMod);
+ if (hMapFile != INVALID_HANDLE_VALUE)
+ CloseHandle(hMapFile);
+ if (hFile != INVALID_HANDLE_VALUE)
+ CloseHandle(hFile);
+ return hr;
+
+}
+
+//-----------------------------------------------------------
+// InitializeFromFile
+// Initialize the reader using the passed in file name
+// Note that upon completion the data hasn't yet been validated for safety.
+//-----------------------------------------------------------
+HRESULT
+SymReader::InitializeFromFile(
+ const WCHAR* szFileName,
+ const WCHAR* szsearchPath)
+{
+ HRESULT hr = S_OK;
+ wchar_t fullpath[_MAX_PATH];
+ wchar_t drive[_MAX_DRIVE];
+ wchar_t dir[_MAX_DIR];
+ wchar_t fname[_MAX_FNAME];
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ HANDLE hMapFile = INVALID_HANDLE_VALUE;
+ HMODULE hMod = NULL;
+ BYTE *CurrentOffset;
+ DWORD dwFileSize;
+ S_UINT32 dwDataSize;
+ GUID VersionInfo;
+
+ _ASSERTE(szFileName);
+ IfFalseGo(szFileName, E_INVALIDARG );
+
+ IfFailGo(VerifyPEDebugInfo(szFileName));
+ // We need to open the exe and check to see if the DebugInfo matches
+
+ if (_wsplitpath_s( szFileName, drive, COUNTOF(drive), dir, COUNTOF(dir), fname, COUNTOF(fname), NULL, 0 ))
+ IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
+ if (_wmakepath_s( fullpath, _MAX_PATH, drive, dir, fname, W("ildb") ))
+ IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
+ if (wcsncpy_s( m_szPath, COUNTOF(m_szPath), fullpath, _TRUNCATE) == STRUNCATE)
+ IfFailGo(HrFromWin32(ERROR_INSUFFICIENT_BUFFER));
+
+ hFile = WszCreateFile(m_szPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+
+ // If the stored string is empty, don't do anything
+ if (m_szStoredSymbolName[0] == '\0')
+ {
+ return HrFromWin32(GetLastError());
+ }
+
+ if (_wsplitpath_s( m_szStoredSymbolName, drive, COUNTOF(drive), dir, COUNTOF(dir), fname, COUNTOF(fname), NULL, 0 ))
+ IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
+ if (_wmakepath_s( fullpath, _MAX_PATH, drive, dir, fname, W("ildb") ))
+ IfFailGo(HrFromWin32(ERROR_BAD_FORMAT));
+ if (wcsncpy_s( m_szPath, COUNTOF(m_szPath), fullpath, _TRUNCATE) == STRUNCATE)
+ IfFailGo(HrFromWin32(ERROR_INSUFFICIENT_BUFFER));
+
+ hFile = WszCreateFile(m_szPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ return HrFromWin32(GetLastError());
+ }
+ }
+
+ dwFileSize = GetFileSize(hFile, NULL);
+ if (dwFileSize < ILDB_HEADER_SIZE)
+ {
+ IfFailGo(HrFromWin32(ERROR_INVALID_DATA));
+ }
+
+ hMapFile = WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (hMapFile == NULL)
+ IfFailGo(HrFromWin32(GetLastError()));
+
+ hMod = (HMODULE) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
+ if (hMod == NULL)
+ IfFailGo(HrFromWin32(GetLastError()));
+
+ // We've opened the file, now let's get the pertinent info
+ CurrentOffset = (BYTE *)hMod;
+
+ // Verify that we're looking at an ILDB File
+ if (memcmp(CurrentOffset, ILDB_SIGNATURE, ILDB_SIGNATURE_SIZE))
+ {
+ IfFailGo(E_FAIL);
+ }
+ CurrentOffset += ILDB_SIGNATURE_SIZE;
+
+ memcpy( &VersionInfo, CurrentOffset, sizeof(GUID));
+ SwapGuid( &VersionInfo );
+ CurrentOffset += sizeof(GUID);
+
+ if (memcmp(&VersionInfo, &ILDB_VERSION_GUID, sizeof(GUID)))
+ {
+ IfFailGo(HrFromWin32(ERROR_INVALID_DATA));
+ }
+
+ IfNullGo(m_pPDBInfo = NEW(PDBInfo));
+
+ memcpy(m_pPDBInfo, CurrentOffset, sizeof(PDBInfo));
+
+ // Swap the counts
+ m_pPDBInfo->ConvertEndianness();
+
+ // Check to make sure we have enough data to be read in.
+ dwDataSize = S_UINT32(ILDB_HEADER_SIZE);
+ dwDataSize += m_pPDBInfo->m_CountOfConstants*sizeof(SymConstant);
+ dwDataSize += m_pPDBInfo->m_CountOfMethods * sizeof(SymMethodInfo);
+ dwDataSize += m_pPDBInfo->m_CountOfScopes*sizeof(SymLexicalScope);
+ dwDataSize += m_pPDBInfo->m_CountOfVars*sizeof(SymVariable);
+ dwDataSize += m_pPDBInfo->m_CountOfUsing*sizeof(SymUsingNamespace);
+ dwDataSize += m_pPDBInfo->m_CountOfSequencePoints*sizeof(SequencePoint);
+ dwDataSize += m_pPDBInfo->m_CountOfDocuments*sizeof(DocumentInfo);
+ dwDataSize += m_pPDBInfo->m_CountOfBytes*sizeof(BYTE);
+ dwDataSize += m_pPDBInfo->m_CountOfStringBytes*sizeof(BYTE);
+
+ if (dwDataSize.IsOverflow() || dwDataSize.Value() > dwFileSize)
+ {
+ IfFailGo(HrFromWin32(ERROR_INVALID_DATA));
+ }
+
+ CurrentOffset += sizeof(PDBInfo);
+
+ if (m_pPDBInfo->m_CountOfConstants)
+ {
+ m_DataPointers.m_pConstants = (SymConstant*)CurrentOffset;
+ CurrentOffset += (m_pPDBInfo->m_CountOfConstants*sizeof(SymConstant));
+ }
+
+ if (m_pPDBInfo->m_CountOfMethods)
+ {
+ m_DataPointers.m_pMethods = (SymMethodInfo *)CurrentOffset;
+ CurrentOffset += (m_pPDBInfo->m_CountOfMethods*sizeof(SymMethodInfo));
+ }
+
+ if (m_pPDBInfo->m_CountOfScopes)
+ {
+ m_DataPointers.m_pScopes = (SymLexicalScope *)CurrentOffset;
+ CurrentOffset += (m_pPDBInfo->m_CountOfScopes*sizeof(SymLexicalScope));
+ }
+
+ if (m_pPDBInfo->m_CountOfVars)
+ {
+ m_DataPointers.m_pVars = (SymVariable *)CurrentOffset;
+ CurrentOffset += (m_pPDBInfo->m_CountOfVars*sizeof(SymVariable));
+ }
+
+ if (m_pPDBInfo->m_CountOfUsing)
+ {
+ m_DataPointers.m_pUsings = (SymUsingNamespace *)CurrentOffset;
+ CurrentOffset += (m_pPDBInfo->m_CountOfUsing*sizeof(SymUsingNamespace));
+ }
+
+ if (m_pPDBInfo->m_CountOfSequencePoints)
+ {
+ m_DataPointers.m_pSequencePoints = (SequencePoint*)CurrentOffset;
+ CurrentOffset += (m_pPDBInfo->m_CountOfSequencePoints*sizeof(SequencePoint));
+ }
+
+ if (m_pPDBInfo->m_CountOfDocuments)
+ {
+ m_DataPointers.m_pDocuments = (DocumentInfo*)CurrentOffset;
+ CurrentOffset += (m_pPDBInfo->m_CountOfDocuments*sizeof(DocumentInfo));
+ }
+
+ if (m_pPDBInfo->m_CountOfBytes)
+ {
+ m_DataPointers.m_pBytes = (BYTE*)CurrentOffset;
+ CurrentOffset += (m_pPDBInfo->m_CountOfBytes*sizeof(BYTE));
+ }
+
+ if (m_pPDBInfo->m_CountOfStringBytes)
+ {
+ m_DataPointers.m_pStringsBytes = (BYTE*)CurrentOffset;
+ }
+
+ErrExit:
+
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetDocument
+// Get the document for the passed in information
+//-----------------------------------------------------------
+HRESULT
+SymReader::GetDocument(
+ __in LPWSTR wcsUrl, // URL of the document
+ GUID language, // Language for the file
+ GUID languageVendor, // Language vendor
+ GUID documentType, // Type of document
+ ISymUnmanagedDocument **ppRetVal // [out] Document
+ )
+{
+ HRESULT hr = S_OK;
+ unsigned i;
+ SymDocument* pDoc = NULL;
+ WCHAR *wcsDocumentUrl = NULL;
+ WCHAR *wcsDocumentUrlAlloc = NULL;
+
+ _ASSERTE(m_fInitialized);
+ IfFalseGo(m_fInitialized, E_UNEXPECTED);
+
+ _ASSERTE(ppRetVal && wcsUrl);
+ IfFalseGo(ppRetVal, E_INVALIDARG);
+ IfFalseGo(wcsUrl, E_INVALIDARG);
+
+ // Init Out Parameter
+ *ppRetVal = NULL;
+
+ for (i = 0; i < m_pPDBInfo->m_CountOfDocuments; i++)
+ {
+ int cchName;
+
+ // Convert the UTF8 string to Wide
+ cchName = (ULONG32) MultiByteToWideChar(CP_UTF8,
+ 0,
+ (LPCSTR)&(m_DataPointers.m_pStringsBytes[m_DataPointers.m_pDocuments[i].UrlEntry()]),
+ -1,
+ 0,
+ NULL);
+ IfNullGo( wcsDocumentUrlAlloc = NEW(WCHAR[cchName]) );
+
+ cchName = (ULONG32) MultiByteToWideChar(CP_UTF8,
+ 0,
+ (LPCSTR)&(m_DataPointers.m_pStringsBytes[m_DataPointers.m_pDocuments[i].UrlEntry()]),
+ -1,
+ wcsDocumentUrlAlloc,
+ cchName);
+ wcsDocumentUrl = wcsDocumentUrlAlloc;
+
+ // Compare the url
+ if (wcscmp(wcsUrl, wcsDocumentUrl) == 0)
+ {
+ IfFailGo(GetDocument(i, &pDoc));
+ break;
+ }
+ DELETEARRAY(wcsDocumentUrlAlloc);
+ wcsDocumentUrlAlloc = NULL;
+ }
+
+ if (pDoc)
+ {
+ IfFailGo( pDoc->QueryInterface( IID_ISymUnmanagedDocument,
+ (void**) ppRetVal ) );
+ }
+
+ErrExit:
+ DELETEARRAY(wcsDocumentUrlAlloc);
+
+ RELEASE( pDoc );
+
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetDocuments
+// Get the documents for this reader
+//-----------------------------------------------------------
+HRESULT
+SymReader::GetDocuments(
+ ULONG32 cDocs,
+ ULONG32 *pcDocs,
+ ISymUnmanagedDocument *pDocs[]
+ )
+{
+ HRESULT hr = S_OK;
+ unsigned cDocCount = 0;
+
+ _ASSERTE(m_fInitialized);
+ IfFalseGo(m_fInitialized, E_UNEXPECTED);
+
+ _ASSERTE(pDocs || pcDocs);
+ IfFalseGo(pDocs || pcDocs, E_INVALIDARG);
+
+ cDocs = min(cDocs, m_pPDBInfo->m_CountOfDocuments);
+
+ for (cDocCount = 0; cDocCount < cDocs; cDocCount++)
+ {
+ if (pDocs)
+ {
+ SymDocument *pDoc;
+ IfFailGo(GetDocument(cDocCount, &pDoc));
+ pDocs[cDocCount] = pDoc;
+ }
+ }
+ if (pcDocs)
+ {
+ *pcDocs = (ULONG32)m_pPDBInfo->m_CountOfDocuments;
+ }
+
+ErrExit:
+ if (FAILED(hr))
+ {
+ unsigned i;
+ for (i = 0; i < cDocCount; i++)
+ {
+ RELEASE(pDocs[cDocCount]);
+ }
+ }
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetUserEntryPoint
+// Get the entry point for the pe
+//-----------------------------------------------------------
+HRESULT
+SymReader::GetUserEntryPoint(
+ mdMethodDef *pRetVal
+ )
+{
+ HRESULT hr = S_OK;
+
+ _ASSERTE(m_fInitialized);
+ IfFalseGo(m_fInitialized, E_UNEXPECTED);
+
+ _ASSERTE(pRetVal);
+ IfFalseGo(pRetVal, E_INVALIDARG);
+
+ // If it wasn't set then return E_FAIL
+ if (m_pPDBInfo->m_userEntryPoint == mdTokenNil)
+ {
+ hr = E_FAIL;
+ }
+ else
+ {
+ *pRetVal = m_pPDBInfo->m_userEntryPoint;
+ }
+ErrExit:
+ return hr;
+}
+
+// Compare the method token with the SymMethodInfo Entry and return the
+// value expected by bsearch
+int __cdecl CompareMethodToToken(const void *pMethodToken, const void *pMethodInfoEntry)
+{
+ mdMethodDef MethodDef = *(mdMethodDef *)pMethodToken;
+ SymMethodInfo *pMethodInfo = (SymMethodInfo *)pMethodInfoEntry;
+
+ return MethodDef - pMethodInfo->MethodToken();
+}
+
+//-----------------------------------------------------------
+// GetMethod
+// Get the method for the methoddef
+//-----------------------------------------------------------
+HRESULT
+SymReader::GetMethod(
+ mdMethodDef method, // MethodDef
+ ISymUnmanagedMethod **ppRetVal // [out] Method
+ )
+{
+ HRESULT hr = S_OK;
+ UINT32 MethodEntry = 0;
+ SymMethodInfo *pMethodInfo;
+ SymMethod * pMethod = NULL;
+
+ _ASSERTE(m_fInitialized);
+ IfFalseGo(m_fInitialized, E_UNEXPECTED);
+
+ _ASSERTE(ppRetVal);
+ IfFalseGo(ppRetVal, E_INVALIDARG);
+
+ pMethodInfo = (SymMethodInfo *)bsearch(&method, m_DataPointers.m_pMethods, m_pPDBInfo->m_CountOfMethods, sizeof(SymMethodInfo), CompareMethodToToken);
+ IfFalseGo(pMethodInfo, E_FAIL); // no matching method found
+
+ // Found a match
+ MethodEntry = UINT32 (pMethodInfo - m_DataPointers.m_pMethods);
+ _ASSERTE(m_DataPointers.m_pMethods[MethodEntry].MethodToken() == method);
+ IfNullGo( pMethod = NEW(SymMethod(this, &m_DataPointers, MethodEntry)) );
+ *ppRetVal = pMethod;
+ pMethod->AddRef();
+ hr = S_OK;
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetMethodByVersion
+//-----------------------------------------------------------
+HRESULT
+SymReader::GetMethodByVersion(
+ mdMethodDef method,
+ int version,
+ ISymUnmanagedMethod **ppRetVal
+ )
+{
+ // Don't support multiple version of the same Method so just
+ // call GetMethod
+ return GetMethod(method, ppRetVal);
+}
+
+
+//-----------------------------------------------------------
+// GetMethodFromDocumentPosition
+//-----------------------------------------------------------
+HRESULT
+SymReader::GetMethodFromDocumentPosition(
+ ISymUnmanagedDocument *document,
+ ULONG32 line,
+ ULONG32 column,
+ ISymUnmanagedMethod **ppRetVal
+)
+{
+ HRESULT hr = S_OK;
+ UINT32 DocumentEntry;
+ UINT32 Method;
+ UINT32 point;
+ SequencePoint *pSequencePointBefore;
+ SequencePoint *pSequencePointAfter;
+ bool found = false;
+
+ _ASSERTE(m_fInitialized);
+ IfFalseGo(m_fInitialized, E_UNEXPECTED);
+
+ _ASSERTE(document && ppRetVal);
+ IfFalseGo(document, E_INVALIDARG);
+ IfFalseGo(ppRetVal, E_INVALIDARG);
+
+ DocumentEntry = ((SymDocument *)document)->GetDocumentEntry();
+
+ // Init out parameter
+ *ppRetVal = NULL;
+
+ // Walk all Methods, check their Document and SequencePoints to see if it's in this doc
+ // and the line/column
+
+ // This function returns the first match if more than one methods cover the specified position.
+ for (Method = 0; Method < m_pPDBInfo->m_CountOfMethods; Method++)
+ {
+ pSequencePointBefore = NULL;
+ pSequencePointAfter = NULL;
+
+ // Walk the sequence points
+ for (point = m_DataPointers.m_pMethods[Method].StartSequencePoints();
+ point < m_DataPointers.m_pMethods[Method].EndSequencePoints();
+ point++)
+ {
+ // Check to see if this sequence point is in this doc
+ if (m_DataPointers.m_pSequencePoints[point].Document() == DocumentEntry)
+ {
+ // If the point is position is within the sequence point then
+ // we're done.
+ if (m_DataPointers.m_pSequencePoints[point].IsWithin(line, column))
+ {
+ IfFailGo(GetMethod(m_DataPointers.m_pMethods[Method].MethodToken(), ppRetVal));
+ found = true;
+ break;
+ }
+
+ // If the sequence is before the point then just remember the point
+ if (m_DataPointers.m_pSequencePoints[point].IsUserLine() &&
+ m_DataPointers.m_pSequencePoints[point].IsLessThan(line, column))
+ {
+ pSequencePointBefore = &m_DataPointers.m_pSequencePoints[point];
+ }
+
+ // If the sequence is before the point then just remember the point
+ if (m_DataPointers.m_pSequencePoints[point].IsUserLine() &&
+ m_DataPointers.m_pSequencePoints[point].IsGreaterThan(line, column))
+ {
+ pSequencePointAfter = &m_DataPointers.m_pSequencePoints[point];
+ }
+ }
+ }
+
+ // If we found an exact match, we're done.
+ if (found)
+ {
+ break;
+ }
+
+ // If we found sequence points within the method before and after
+ // the line/column then we may have found the method. Record the return value, but keep looking
+ // to see if we find an exact match. This may not actually be the right method. Iron Python, for instance,
+ // issues a "method" containing sequence points for all the method headers in a class. Sequence points
+ // in this "method" would then span the sequence points in the bodies of all but the last method.
+ if (pSequencePointBefore && pSequencePointAfter)
+ {
+ IfFailGo(GetMethod(m_DataPointers.m_pMethods[Method].MethodToken(), ppRetVal));
+ }
+ }
+
+ // This function returns E_FAIL if no match is found.
+ // Note that this is different from the behaviour of GetMethodsFromDocumentPosition() (see below).
+ if (*ppRetVal == NULL)
+ {
+ hr = E_FAIL;
+ }
+
+ErrExit:
+ return hr;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Return all methods with sequence points covering the specified source location. This
+// is actually not as straighforward as it sounds, since we need to mimic the behaviour of
+// diasymreader and PDBs here. For PDBs, diasymreader actually does two passes over the
+// sequence points. It tries to find an exact match in the first pass, and if that fails,
+// it'll do a second pass looking for an approximate match. An approximate match is a sequence
+// point which doesn't start on the specified line but covers it. If there's an exact match,
+// then it ignores all the approximate matches. In both cases, diasymreader only checks the
+// start line number of the sequence point and it ignores the column number.
+//
+// For backward compatibility, I'm leaving GetMethodFromDocumentPosition() unchanged.
+//
+
+HRESULT
+SymReader::GetMethodsFromDocumentPosition(
+ ISymUnmanagedDocument *document,
+ ULONG32 line,
+ ULONG32 column,
+ ULONG32 cMethod,
+ ULONG32* pcMethod, //[Optional]: How many method actually returned
+ ISymUnmanagedMethod** ppRetVal
+ )
+{
+ HRESULT hr = S_OK;
+ UINT32 DocumentEntry;
+ UINT32 Method;
+ UINT32 point;
+
+ UINT CurMethod = 0;
+ bool found = false;
+ bool fExactMatch = true;
+
+ ULONG32 maxPreLine = 0;
+
+ _ASSERTE(m_fInitialized);
+ IfFalseGo(m_fInitialized, E_UNEXPECTED);
+
+ _ASSERTE(document);
+ IfFalseGo(document, E_INVALIDARG);
+
+ _ASSERTE((cMethod == 0) || (ppRetVal != NULL));
+ IfFalseGo(cMethod == 0 || ppRetVal != NULL, E_INVALIDARG);
+
+ // Initialize the out parameter if it has been provided.
+ if (pcMethod != NULL)
+ {
+ *pcMethod = 0;
+ }
+
+ DocumentEntry = ((SymDocument *)document)->GetDocumentEntry();
+
+ // Enumerate the sequence points in two passes.
+ while (true)
+ {
+ // Walk all Methods, check their Document and SequencePoints to see if it's in this doc
+ // and the line/column
+
+ for (Method = 0; Method < m_pPDBInfo->m_CountOfMethods; Method++)
+ {
+ found = false;
+
+ // Walk the sequence points
+ for (point = m_DataPointers.m_pMethods[Method].StartSequencePoints();
+ point < m_DataPointers.m_pMethods[Method].EndSequencePoints();
+ point++)
+ {
+ // Check to see if this sequence point is in this doc
+ if (m_DataPointers.m_pSequencePoints[point].Document() == DocumentEntry)
+ {
+ // PDBs (more specifically the DIA APIs) only check the start line number and not the end line number when
+ // trying to determine whether a sequence point covers the specified line number. We need to match this
+ // behaviour here. For backward compatibility reasons, GetMethodFromDocumentPosition() is still checking
+ // against the entire range of a sequence point, but we should revisit that in the next release.
+ ULONG32 curLine = m_DataPointers.m_pSequencePoints[point].StartLine();
+
+ if (fExactMatch)
+ {
+ if (curLine == line)
+ {
+ found = true;
+ }
+ else if ((maxPreLine < curLine) && (curLine < line))
+ {
+ // This is not an exact match, but let's keep track of the sequence point closest to the specified
+ // line. We'll use this info if we have to do a second pass.
+ maxPreLine = curLine;
+ }
+ }
+ else
+ {
+ // We are in the second pass, looking for approximate matches.
+ if ((maxPreLine != 0) && (maxPreLine == curLine))
+ {
+ // Make sure the sequence point covers the specified line.
+ if (m_DataPointers.m_pSequencePoints[point].IsWithinLineOnly(line))
+ {
+ found = true;
+ }
+ }
+ }
+
+ // If we have found a match (whether it's exact or approximate), then save this method unless the caller is
+ // only interested in the number of matching methods or the array provided by the caller isn't big enough.
+ if (found)
+ {
+ if (CurMethod < cMethod)
+ {
+ IfFailGo(GetMethod(m_DataPointers.m_pMethods[Method].MethodToken(), &(ppRetVal[CurMethod])));
+ }
+ CurMethod++;
+ break;
+ }
+ }
+ }
+
+ if (found)
+ {
+ // If we have already filled out the entire array provided by the caller, then we are done.
+ if ((cMethod > 0) && (cMethod == CurMethod))
+ {
+ break;
+ }
+ else
+ {
+ // Otherwise move on to the next method.
+ continue;
+ }
+ }
+ }
+
+ // If we haven't found an exact match, then try it again looking for a sequence point covering the specified line.
+ if (fExactMatch && (CurMethod == 0))
+ {
+ fExactMatch = false;
+ continue;
+ }
+ else
+ {
+ // If we have found an exact match, or if we have done two passes already, then bail.
+ break;
+ }
+ }
+
+ // Note that unlike GetMethodFromDocumentPosition(), this function returns S_OK even if a match is not found.
+ if (SUCCEEDED(hr))
+ {
+ if (pcMethod != NULL)
+ {
+ *pcMethod = CurMethod;
+ }
+ }
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetSymbolStoreFileName
+//-----------------------------------------------------------
+HRESULT
+SymReader::GetSymbolStoreFileName(
+ ULONG32 cchName, // Length of szName
+ ULONG32 *pcchName, // [Optional]
+ __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[] // [Optional]
+ )
+{
+ _ASSERTE(m_fInitialized);
+ if (!m_fInitialized)
+ return E_UNEXPECTED;
+
+ if (pcchName)
+ {
+ *pcchName = (ULONG32)(wcslen(m_szPath)+1);
+ }
+
+ if( szName )
+ {
+ if (wcsncpy_s( szName, cchName, m_szPath, _TRUNCATE) == STRUNCATE)
+ return HrFromWin32(ERROR_INSUFFICIENT_BUFFER);
+ }
+
+ return NOERROR;
+}
+
+//-----------------------------------------------------------
+// GetMethodVersion
+//-----------------------------------------------------------
+HRESULT
+SymReader::GetMethodVersion(
+ ISymUnmanagedMethod * pMethod,
+ int* pVersion
+ )
+{
+ HRESULT hr = S_OK;
+
+ _ASSERTE(m_fInitialized);
+ IfFalseGo(m_fInitialized, E_UNEXPECTED);
+
+ _ASSERTE(pMethod && pVersion);
+ IfFalseGo( pMethod && pVersion, E_INVALIDARG);
+ // This symbol store only supports one version of a method
+ *pVersion = 0;
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetDocumentVersion
+//-----------------------------------------------------------
+HRESULT
+SymReader::GetDocumentVersion(
+ ISymUnmanagedDocument* pDoc,
+ int* pVersion,
+ BOOL* pbCurrent // [Optional]
+ )
+{
+ HRESULT hr = S_OK;
+
+ _ASSERTE(m_fInitialized);
+ IfFalseGo(m_fInitialized, E_UNEXPECTED);
+
+ _ASSERTE(pVersion && pDoc);
+ IfFalseGo(pVersion, E_INVALIDARG);
+ IfFalseGo(pDoc, E_INVALIDARG);
+
+ // This symbol store only supports one version of a document
+ *pVersion = 0;
+ if (pbCurrent)
+ {
+ *pbCurrent = TRUE;
+ }
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetDocument
+// Return the document for the given entry
+//-----------------------------------------------------------
+HRESULT SymReader::GetDocument(
+ UINT32 DocumentEntry,
+ SymDocument **ppDocument)
+{
+ HRESULT hr = NOERROR;
+
+ _ASSERTE(m_fInitialized);
+ IfFalseGo(m_fInitialized, E_UNEXPECTED);
+
+ _ASSERTE(ppDocument);
+ IfFalseGo(ppDocument, E_INVALIDARG);
+
+ _ASSERTE(DocumentEntry < m_pPDBInfo->m_CountOfDocuments);
+ IfFalseGo(DocumentEntry < m_pPDBInfo->m_CountOfDocuments, E_INVALIDARG);
+
+ if (m_pDocs == NULL)
+ {
+ IfNullGo(m_pDocs = NEW(SymDocument *[m_pPDBInfo->m_CountOfDocuments]));
+ memset(m_pDocs, 0, m_pPDBInfo->m_CountOfDocuments * sizeof(void *));
+ }
+
+ if (m_pDocs[DocumentEntry] == NULL)
+ {
+ m_pDocs[DocumentEntry] = NEW(SymDocument(this, &m_DataPointers, m_pPDBInfo->m_CountOfMethods, DocumentEntry));
+ IfNullGo(m_pDocs[DocumentEntry]);
+ // AddRef the table version
+ m_pDocs[DocumentEntry]->AddRef();
+
+ }
+
+ //Set and AddRef the Out Parameter
+ *ppDocument = m_pDocs[DocumentEntry];
+ (*ppDocument)->AddRef();
+
+ErrExit:
+ return hr;
+}
+
+HRESULT
+SymReader::UpdateSymbolStore(
+ const WCHAR *filename,
+ IStream *pIStream
+ )
+{
+ // This symbol store doesn't support updating the symbol store.
+ _ASSERTE(!"NYI");
+ return E_NOTIMPL;
+}
+
+HRESULT
+SymReader::ReplaceSymbolStore(
+ const WCHAR *filename,
+ IStream *pIStream
+ )
+{
+ // This symbol store doesn't support updating the symbol store.
+ _ASSERTE(!"NYI");
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// GetVariables
+//-----------------------------------------------------------
+HRESULT
+SymReader::GetVariables(
+ mdToken parent,
+ ULONG32 cVars,
+ ULONG32 *pcVars,
+ ISymUnmanagedVariable *pVars[]
+ )
+{
+ //
+ // This symbol reader doesn't support non-local variables.
+ //
+ _ASSERTE(!"NYI");
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// GetGlobalVariables
+//-----------------------------------------------------------
+HRESULT
+SymReader::GetGlobalVariables(
+ ULONG32 cVars,
+ ULONG32 *pcVars,
+ ISymUnmanagedVariable *pVars[]
+ )
+{
+ //
+ // This symbol reader doesn't support non-local variables.
+ //
+ _ASSERTE(!"NYI");
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// GetSymAttribute
+//-----------------------------------------------------------
+HRESULT
+SymReader::GetSymAttribute(
+ mdToken parent,
+ __in LPWSTR name,
+ ULONG32 cBuffer,
+ ULONG32 *pcBuffer,
+ __out_bcount_part_opt(cBuffer, *pcBuffer) BYTE buffer[]
+ )
+{
+ // This symbol store doesn't support attributes
+ // VS may query for certain attributes, but will survive without them,
+ // so don't ASSERT here.
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// GetNamespaces
+//-----------------------------------------------------------
+HRESULT
+SymReader::GetNamespaces(
+ ULONG32 cNameSpaces,
+ ULONG32 *pcNameSpaces,
+ ISymUnmanagedNamespace *namespaces[]
+ )
+{
+ // This symbol store doesn't support this
+ _ASSERTE(!"NYI");
+ return E_NOTIMPL;
+}
+
+/* ------------------------------------------------------------------------- *
+ * SymDocument class
+ * ------------------------------------------------------------------------- */
+
+HRESULT
+SymDocument::QueryInterface(
+ REFIID riid,
+ void **ppInterface
+ )
+{
+ if (ppInterface == NULL)
+ return E_INVALIDARG;
+
+ if (riid == IID_ISymUnmanagedDocument)
+ *ppInterface = (ISymUnmanagedDocument*)this;
+ else if (riid == IID_IUnknown)
+ *ppInterface = (IUnknown*)(ISymUnmanagedDocument*)this;
+ else
+ {
+ *ppInterface = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+
+//-----------------------------------------------------------
+// GetURL
+//-----------------------------------------------------------
+HRESULT
+SymDocument::GetURL(
+ ULONG32 cchUrl, // The allocated size of the buffer
+ ULONG32 *pcchUrl, // [optional,out] The number of characters available for return
+ __out_ecount_part_opt(cchUrl, *pcchUrl) WCHAR szUrl[] // [optional,out] The string buffer.
+ )
+{
+ if (pcchUrl)
+ {
+ // Convert the UTF8 string to Wide
+ *pcchUrl = (ULONG32) MultiByteToWideChar(CP_UTF8,
+ 0,
+ (LPCSTR)&(m_pData->m_pStringsBytes[m_pData->m_pDocuments[m_DocumentEntry].UrlEntry()]),
+ -1,
+ 0,
+ NULL);
+ }
+
+ if( szUrl )
+ {
+ // Convert the UTF8 string to Wide
+ MultiByteToWideChar(CP_UTF8,
+ 0,
+ (LPCSTR)&(m_pData->m_pStringsBytes[m_pData->m_pDocuments[m_DocumentEntry].UrlEntry()]),
+ -1,
+ szUrl,
+ cchUrl);
+ }
+ return NOERROR;
+}
+
+//-----------------------------------------------------------
+// GetDocumentType
+//-----------------------------------------------------------
+HRESULT
+SymDocument::GetDocumentType(
+ GUID *pRetVal
+ )
+{
+ HRESULT hr = NOERROR;
+ _ASSERTE(pRetVal);
+ IfFalseGo(pRetVal, E_INVALIDARG);
+ *pRetVal = m_pData->m_pDocuments[m_DocumentEntry].DocumentType();
+ SwapGuid(pRetVal);
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetLanguage
+//-----------------------------------------------------------
+HRESULT
+SymDocument::GetLanguage(
+ GUID *pRetVal
+ )
+{
+ HRESULT hr = NOERROR;
+ _ASSERTE(pRetVal);
+ IfFalseGo(pRetVal, E_INVALIDARG);
+
+ *pRetVal = m_pData->m_pDocuments[m_DocumentEntry].Language();
+ SwapGuid(pRetVal);
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetLanguageVendor
+//-----------------------------------------------------------
+HRESULT
+SymDocument::GetLanguageVendor(
+ GUID *pRetVal
+ )
+{
+ HRESULT hr = NOERROR;
+ _ASSERTE(pRetVal);
+ IfFalseGo(pRetVal, E_INVALIDARG);
+ *pRetVal = m_pData->m_pDocuments[m_DocumentEntry].LanguageVendor();
+ SwapGuid(pRetVal);
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetCheckSumAlgorithmId
+//-----------------------------------------------------------
+HRESULT
+SymDocument::GetCheckSumAlgorithmId(
+ GUID *pRetVal
+ )
+{
+ HRESULT hr = NOERROR;
+ _ASSERTE(pRetVal);
+ IfFalseGo(pRetVal, E_INVALIDARG);
+ *pRetVal = m_pData->m_pDocuments[m_DocumentEntry].AlgorithmId();
+ SwapGuid(pRetVal);
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetCheckSum
+//-----------------------------------------------------------
+HRESULT
+SymDocument::GetCheckSum(
+ ULONG32 cData, // The allocated size of the buffer.
+ ULONG32 *pcData, // [optional] The number of bytes available for return
+ BYTE data[]) // [optional] The buffer to receive the checksum.
+{
+ BYTE *pCheckSum = &m_pData->m_pBytes[m_pData->m_pDocuments[m_DocumentEntry].CheckSumEntry()];
+ ULONG32 CheckSumSize = m_pData->m_pDocuments[m_DocumentEntry].CheckSumSize();
+ if (pcData)
+ {
+ *pcData = CheckSumSize;
+ }
+ if(data)
+ {
+ memcpy(data, pCheckSum, min(CheckSumSize, cData));
+ }
+ return NOERROR;
+}
+
+//-----------------------------------------------------------
+// FindClosestLine
+// Search the sequence points looking a line that is closest
+// line following this one that is a sequence point
+//-----------------------------------------------------------
+HRESULT
+SymDocument::FindClosestLine(
+ ULONG32 line,
+ ULONG32 *pRetVal
+ )
+{
+ HRESULT hr = NOERROR;
+ UINT32 Method;
+ UINT32 point;
+ ULONG32 closestLine = 0; // GCC can't tell this isn't used before initialization
+ bool found = false;
+
+ _ASSERTE(pRetVal);
+ IfFalseGo(pRetVal, E_INVALIDARG);
+
+ // Walk all Methods, check their Document and SequencePoints to see if it's in this doc
+ // and the line/column
+ for (Method = 0; Method < m_CountOfMethods; Method++)
+ {
+ // Walk the sequence points
+ for (point = m_pData->m_pMethods[Method].StartSequencePoints();
+ point < m_pData->m_pMethods[Method].EndSequencePoints();
+ point++)
+ {
+ SequencePoint & sp = m_pData->m_pSequencePoints[point];
+ // Check to see if this sequence point is in this doc, and is at or
+ // after the requested line
+ if ((sp.Document() == m_DocumentEntry) && sp.IsUserLine())
+ {
+ if (sp.IsWithin(line, 0) || sp.IsGreaterThan(line, 0))
+ {
+ // This sequence point is at or after the requested line. If we haven't
+ // already found a "closest", or this is even closer than the one we have,
+ // then mark this as the best line so far.
+ if (!found || m_pData->m_pSequencePoints[point].StartLine() < closestLine)
+ {
+ found = true;
+ closestLine = m_pData->m_pSequencePoints[point].StartLine();
+ }
+ }
+ }
+ }
+ }
+
+ if (found)
+ {
+ *pRetVal = closestLine;
+ }
+ else
+ {
+ // Didn't find any lines at or after the one requested.
+ hr = E_FAIL;
+ }
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// SymDocument HasEmbeddedSource
+//-----------------------------------------------------------
+HRESULT
+SymDocument::HasEmbeddedSource(
+ BOOL *pRetVal
+ )
+{
+ //
+ // This symbol reader doesn't support embedded source.
+ //
+ _ASSERTE(!"NYI");
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// SymDocument GetSourceLength
+//-----------------------------------------------------------
+HRESULT
+SymDocument::GetSourceLength(
+ ULONG32 *pRetVal
+ )
+{
+ //
+ // This symbol reader doesn't support embedded source.
+ //
+ _ASSERTE(!"NYI");
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// SymDocument GetSourceRange
+//-----------------------------------------------------------
+HRESULT
+SymDocument::GetSourceRange(
+ ULONG32 startLine,
+ ULONG32 startColumn,
+ ULONG32 endLine,
+ ULONG32 endColumn,
+ ULONG32 cSourceBytes,
+ ULONG32 *pcSourceBytes,
+ BYTE source[]
+ )
+{
+ //
+ // This symbol reader doesn't support embedded source.
+ //
+ _ASSERTE(!"NYI");
+ return E_NOTIMPL;
+}
+
+/* ------------------------------------------------------------------------- *
+ * SymMethod class
+ * ------------------------------------------------------------------------- */
+HRESULT
+SymMethod::QueryInterface(
+ REFIID riid,
+ void **ppInterface
+ )
+{
+ if (ppInterface == NULL)
+ return E_INVALIDARG;
+
+ if (riid == IID_ISymUnmanagedMethod)
+ *ppInterface = (ISymUnmanagedMethod*)this;
+ else if (riid == IID_IUnknown)
+ *ppInterface = (IUnknown*)(ISymUnmanagedMethod*)this;
+ else
+ {
+ *ppInterface = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+//-----------------------------------------------------------
+// GetToken
+//-----------------------------------------------------------
+HRESULT
+SymMethod::GetToken(
+ mdMethodDef *pRetVal
+)
+{
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pRetVal);
+ IfFalseGo(pRetVal, E_INVALIDARG);
+ *pRetVal = m_pData->m_pMethods[m_MethodEntry].MethodToken();
+ErrExit:
+ return hr;
+}
+
+
+//-----------------------------------------------------------
+// GetSequencePointCount
+//-----------------------------------------------------------
+HRESULT
+SymMethod::GetSequencePointCount(
+ ULONG32* pRetVal
+ )
+{
+
+ HRESULT hr = S_OK;
+ _ASSERTE(pRetVal);
+ IfFalseGo(pRetVal, E_INVALIDARG);
+
+ *pRetVal = (ULONG32)(m_pData->m_pMethods[m_MethodEntry].EndSequencePoints() -
+ m_pData->m_pMethods[m_MethodEntry].StartSequencePoints());
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetSequencePoints
+//-----------------------------------------------------------
+HRESULT
+SymMethod::GetSequencePoints(
+ ULONG32 cPoints, // The size of the allocated arrays.
+ ULONG32* pcPoints, // [optional] The number of sequence points available for return.
+ ULONG32 offsets[], // [optional]
+ ISymUnmanagedDocument *documents[], // [Optional]
+ ULONG32 lines[], // [Optional]
+ ULONG32 columns[], // [Optional]
+ ULONG32 endLines[], // [Optional]
+ ULONG32 endColumns[] // [Optional]
+ )
+{
+ HRESULT hr = NOERROR;
+ UINT32 i = 0;
+ ULONG32 Points = 0;
+
+ for (i = m_pData->m_pMethods[m_MethodEntry].StartSequencePoints();
+ (i < m_pData->m_pMethods[m_MethodEntry].EndSequencePoints());
+ i++, Points++)
+ {
+ if (Points < cPoints)
+ {
+ if (documents)
+ {
+ SymDocument *pDoc;
+ IfFailGo(m_pReader->GetDocument(m_pData->m_pSequencePoints[i].Document(), &pDoc));
+ documents[Points] = pDoc;
+ }
+
+ if (offsets)
+ {
+ offsets[Points] = m_pData->m_pSequencePoints[i].Offset();
+ }
+
+ if (lines)
+ {
+ lines[Points] = m_pData->m_pSequencePoints[i].StartLine();
+ }
+ if (columns)
+ {
+ columns[Points] = m_pData->m_pSequencePoints[i].StartColumn();
+ }
+ if (endLines)
+ {
+ endLines[Points] = m_pData->m_pSequencePoints[i].EndLine();
+ }
+ if (endColumns)
+ {
+ endColumns[Points] = m_pData->m_pSequencePoints[i].EndColumn();
+ }
+ }
+ }
+
+ if (pcPoints)
+ {
+ *pcPoints = Points;
+ }
+
+ErrExit:
+ if (FAILED(hr))
+ {
+ if (documents)
+ {
+ unsigned j;
+ for (j = 0; j < i; j++)
+ {
+ RELEASE(documents[i]);
+ }
+ }
+ }
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetRootScope
+//-----------------------------------------------------------
+HRESULT
+SymMethod::GetRootScope(
+ ISymUnmanagedScope **ppRetVal
+ )
+{
+ HRESULT hr = S_OK;
+ SymScope *pScope = NULL;
+ _ASSERTE(ppRetVal);
+ IfFalseGo(ppRetVal, E_INVALIDARG);
+
+ // Init Out Param
+ *ppRetVal = NULL;
+ if (m_pData->m_pMethods[m_MethodEntry].EndScopes() - m_pData->m_pMethods[m_MethodEntry].StartScopes())
+ {
+ IfNullGo(pScope = NEW(SymScope(this, m_pData, m_MethodEntry, m_pData->m_pMethods[m_MethodEntry].StartScopes())));
+ pScope->AddRef();
+ *ppRetVal = pScope;
+ }
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetOffset
+// Given a position in a document, gets the offset within the
+// method that corresponds to the position.
+//-----------------------------------------------------------
+HRESULT
+SymMethod::GetOffset(
+ ISymUnmanagedDocument *document,
+ ULONG32 line,
+ ULONG32 column,
+ ULONG32 *pRetVal
+ )
+{
+ HRESULT hr = S_OK;
+ bool fFound = false;
+ _ASSERTE(pRetVal);
+ IfFalseGo(pRetVal, E_INVALIDARG);
+
+ UINT32 point;
+ UINT32 DocumentEntry;
+
+ DocumentEntry = ((SymDocument *)document)->GetDocumentEntry();
+
+ // Walk the sequence points
+ for (point = m_pData->m_pMethods[m_MethodEntry].StartSequencePoints();
+ point < m_pData->m_pMethods[m_MethodEntry].EndSequencePoints();
+ point++)
+ {
+ // Check to see if this sequence point is in this doc
+ if (m_pData->m_pSequencePoints[point].Document() == DocumentEntry)
+ {
+ // Check to see if it's within the sequence point
+ if (m_pData->m_pSequencePoints[point].IsWithin(line, column))
+ {
+ *pRetVal = m_pData->m_pSequencePoints[point].Offset();
+ fFound = true;
+ break;
+ }
+ }
+ }
+ if (!fFound)
+ {
+ hr = E_FAIL;
+ }
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetRanges
+//-----------------------------------------------------------
+HRESULT
+SymMethod::GetRanges(
+ ISymUnmanagedDocument *pDocument, // [in] Document we're working on
+ ULONG32 line, // [in] The document line corresponding to the ranges.
+ ULONG32 column, // [in] Ignored
+ ULONG32 cRanges, // [in] The size of the allocated ranges[] array.
+ ULONG32 *pcRanges, // [out] The number of ranges available for return
+ ULONG32 ranges[] // [out] The range array.
+ )
+{
+ HRESULT hr = NOERROR;
+ DWORD iRange = 0;
+ UINT32 DocumentEntry;
+ UINT32 point;
+ bool fFound = false;
+
+ // Validate some of the parameters
+ _ASSERTE(pDocument && (cRanges % 2) == 0);
+ IfFalseGo(pDocument, E_INVALIDARG);
+ IfFalseGo((cRanges % 2) == 0, E_INVALIDARG);
+
+ // Init out parameter
+ if (pcRanges)
+ {
+ *pcRanges=0;
+ }
+
+ DocumentEntry = ((SymDocument *)pDocument)->GetDocumentEntry();
+
+ // Walk the sequence points
+ for (point = m_pData->m_pMethods[m_MethodEntry].StartSequencePoints();
+ point < m_pData->m_pMethods[m_MethodEntry].EndSequencePoints();
+ point++)
+ {
+ // Check to see if this sequence point is in this doc
+ if (m_pData->m_pSequencePoints[point].Document() == DocumentEntry)
+ {
+ // Check to see if the line is within this sequence
+ // Note, to be compatible with VS7, ignore the column information
+ if (line >= m_pData->m_pSequencePoints[point].StartLine() &&
+ line <= m_pData->m_pSequencePoints[point].EndLine())
+ {
+ fFound = true;
+ break;
+ }
+ }
+ }
+
+ if (fFound)
+ {
+ for (;point < m_pData->m_pMethods[m_MethodEntry].EndSequencePoints(); point++)
+ {
+
+ // Search through all the sequence points since line might have there
+ // IL spread accross multiple ranges (for loops for example)
+ if (m_pData->m_pSequencePoints[point].Document() == DocumentEntry &&
+ line >= m_pData->m_pSequencePoints[point].StartLine() &&
+ line <= m_pData->m_pSequencePoints[point].EndLine())
+ {
+ if (iRange < cRanges)
+ {
+ ranges[iRange] = m_pData->m_pSequencePoints[point].Offset();
+ }
+ iRange++;
+ if (iRange < cRanges)
+ {
+ if (point+1 < m_pData->m_pMethods[m_MethodEntry].EndSequencePoints())
+ {
+ ranges[iRange] = m_pData->m_pSequencePoints[point+1].Offset();
+ }
+ else
+ {
+ // Then it must be till the end of the function which is the root scope's endoffset
+ ranges[iRange] = m_pData->m_pScopes[m_pData->m_pMethods[m_MethodEntry].StartScopes()].EndOffset()+1;
+ }
+ }
+ iRange++;
+ }
+ }
+ if (pcRanges)
+ {
+ // If cRanges passed in, return the number
+ // of elements actually filled in
+ if (cRanges)
+ {
+ *pcRanges = min(iRange, cRanges);
+ }
+ else
+ {
+ // Otherwise return the max number
+ *pcRanges = iRange;
+ }
+ }
+ }
+ else
+ {
+ return E_FAIL;
+ }
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetScopeFromOffset
+//-----------------------------------------------------------
+HRESULT
+SymMethod::GetScopeFromOffset(
+ ULONG32 offset,
+ ISymUnmanagedScope **pRetVal
+ )
+{
+ //
+ // This symbol reader doesn't support this functionality
+ //
+ _ASSERTE(!"NYI");
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// GetParameters
+//-----------------------------------------------------------
+HRESULT
+SymMethod::GetParameters(
+ ULONG32 cParams,
+ ULONG32 *pcParams,
+ ISymUnmanagedVariable *params[]
+ )
+{
+ //
+ // This symbol reader doesn't support parameter access. Parameters
+ // can be found in the normal metadata.
+ //
+ _ASSERTE(!"NYI");
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// GetNamespace
+//-----------------------------------------------------------
+HRESULT
+SymMethod::GetNamespace(
+ ISymUnmanagedNamespace **ppRetVal
+ )
+{
+ //
+ // This symbol reader doesn't support namespaces
+ //
+ _ASSERTE(!"NYI");
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// GetSourceStartEnd
+//-----------------------------------------------------------
+HRESULT
+SymMethod::GetSourceStartEnd(
+ ISymUnmanagedDocument *docs[2],
+ ULONG32 lines[2],
+ ULONG32 columns[2],
+ BOOL *pRetVal
+ )
+{
+ //
+ // This symbol reader doesn't support source start/end for methods.
+ //
+ _ASSERTE(!"NYI");
+ return E_NOTIMPL;
+}
+
+/* ------------------------------------------------------------------------- *
+ * SymScope class
+ * ------------------------------------------------------------------------- */
+
+//-----------------------------------------------------------
+// QueryInterface
+//-----------------------------------------------------------
+HRESULT
+SymScope::QueryInterface(
+ REFIID riid,
+ void **ppInterface
+ )
+{
+ if (ppInterface == NULL)
+ return E_INVALIDARG;
+
+ if (riid == IID_ISymUnmanagedScope)
+ *ppInterface = (ISymUnmanagedScope*)this;
+ else if (riid == IID_IUnknown)
+ *ppInterface = (IUnknown*)(ISymUnmanagedScope*)this;
+ else
+ {
+ *ppInterface = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+//-----------------------------------------------------------
+// GetMethod
+//-----------------------------------------------------------
+HRESULT
+SymScope::GetMethod(
+ ISymUnmanagedMethod **ppRetVal
+ )
+{
+ HRESULT hr = S_OK;
+
+ _ASSERTE(ppRetVal);
+ IfFalseGo(ppRetVal, E_INVALIDARG);
+
+ *ppRetVal = m_pSymMethod;
+ m_pSymMethod->AddRef();
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetParent
+//-----------------------------------------------------------
+HRESULT
+SymScope::GetParent(
+ ISymUnmanagedScope **ppRetVal
+ )
+{
+ HRESULT hr = S_OK;
+ _ASSERTE(ppRetVal);
+ IfFalseGo(ppRetVal, E_INVALIDARG);
+ if (m_pData->m_pScopes[m_ScopeEntry].ParentScope() != (UINT32)-1)
+ {
+ IfNullGo(*ppRetVal = static_cast<ISymUnmanagedScope *>(NEW(SymScope(m_pSymMethod, m_pData, m_MethodEntry,
+ m_pData->m_pScopes[m_ScopeEntry].ParentScope()))));
+ (*ppRetVal)->AddRef();
+ }
+ else
+ {
+ *ppRetVal = NULL;
+ }
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetChildren
+//-----------------------------------------------------------
+HRESULT
+SymScope::GetChildren(
+ ULONG32 cChildren, // [optional] Number of entries in children
+ ULONG32 *pcChildren, // [optional, out] Number of Children available for retur
+ ISymUnmanagedScope *children[] // [optional] array to store children into
+ )
+{
+ HRESULT hr = S_OK;
+ ULONG32 ChildrenCount = 0;
+ _ASSERTE(pcChildren || (children && cChildren));
+ IfFalseGo((pcChildren || (children && cChildren)), E_INVALIDARG);
+
+ if (m_pData->m_pScopes[m_ScopeEntry].HasChildren())
+ {
+ UINT32 ScopeEntry;
+ for(ScopeEntry = m_pData->m_pMethods[m_MethodEntry].StartScopes();
+ (ScopeEntry < m_pData->m_pMethods[m_MethodEntry].EndScopes());
+ ScopeEntry++)
+ {
+ if (m_pData->m_pScopes[ScopeEntry].ParentScope() == m_ScopeEntry)
+ {
+ if (children && ChildrenCount < cChildren)
+ {
+ SymScope *pScope;
+ // Found a child
+ IfNullGo(pScope = NEW(SymScope(m_pSymMethod, m_pData, m_MethodEntry, ScopeEntry)));
+ children[ChildrenCount] = pScope;
+ pScope->AddRef();
+ }
+ ChildrenCount++;
+ }
+ }
+ }
+
+ if (pcChildren)
+ {
+ *pcChildren = ChildrenCount;
+ }
+
+ErrExit:
+ if (FAILED(hr) && ChildrenCount)
+ {
+ unsigned i;
+ for (i =0; i< ChildrenCount; i++)
+ {
+ RELEASE(children[i]);
+ }
+ }
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetStartOffset
+//-----------------------------------------------------------
+HRESULT
+SymScope::GetStartOffset(
+ ULONG32* pRetVal
+ )
+{
+ HRESULT hr = S_OK;
+ _ASSERTE(pRetVal);
+ IfFalseGo(pRetVal, E_INVALIDARG);
+ *pRetVal = m_pData->m_pScopes[m_ScopeEntry].StartOffset();
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetEndOffset
+//-----------------------------------------------------------
+HRESULT
+SymScope::GetEndOffset(
+ ULONG32* pRetVal
+ )
+{
+ HRESULT hr = S_OK;
+ _ASSERTE(pRetVal);
+ IfFalseGo(pRetVal, E_INVALIDARG);
+ *pRetVal = m_pData->m_pScopes[m_ScopeEntry].EndOffset();
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetLocalCount
+//-----------------------------------------------------------
+HRESULT
+SymScope::GetLocalCount(
+ ULONG32 *pRetVal
+ )
+{
+ HRESULT hr = S_OK;
+ ULONG32 LocalCount = 0;
+ _ASSERTE(pRetVal);
+ IfFalseGo(pRetVal, E_INVALIDARG);
+
+ // Init out parameter
+ *pRetVal = 0;
+ if (m_pData->m_pScopes[m_ScopeEntry].HasVars())
+ {
+ UINT32 var;
+ // Walk and get the locals for this Scope
+ for (var = m_pData->m_pMethods[m_MethodEntry].StartVars();
+ var < m_pData->m_pMethods[m_MethodEntry].EndVars();
+ var++)
+ {
+ if (m_pData->m_pVars[var].Scope() == m_ScopeEntry &&
+ m_pData->m_pVars[var].IsParam() == false)
+ {
+ LocalCount++;
+ }
+ }
+ }
+
+ *pRetVal = LocalCount;
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetLocals
+// Input: either pcLocals or
+// cLocals and pLocals
+//-----------------------------------------------------------
+HRESULT
+SymScope::GetLocals(
+ ULONG32 cLocals, // [optional] available entries in pLocals
+ ULONG32 *pcLocals, // [optional, out] Number of locals returned
+ ISymUnmanagedVariable *pLocals[] // [optional] array to store locals into
+ )
+{
+ HRESULT hr = S_OK;
+
+ ULONG32 LocalCount = 0;
+ _ASSERTE(pcLocals || pLocals);
+ IfFalseGo(pcLocals || pLocals, E_INVALIDARG);
+
+ if (m_pData->m_pScopes[m_ScopeEntry].HasVars())
+ {
+ UINT32 var;
+ // Walk and get the locals for this Scope
+ for (var = m_pData->m_pMethods[m_MethodEntry].StartVars();
+ var < m_pData->m_pMethods[m_MethodEntry].EndVars();
+ var++)
+ {
+ if (m_pData->m_pVars[var].Scope() == m_ScopeEntry &&
+ m_pData->m_pVars[var].IsParam() == false)
+ {
+ if (pLocals && LocalCount < cLocals)
+ {
+ SymReaderVar *pVar;
+ IfNullGo( pVar = NEW(SymReaderVar(this, m_pData, var)));
+ pLocals[LocalCount] = pVar;
+ pVar->AddRef();
+ }
+ LocalCount++;
+ }
+ }
+ }
+ if (pcLocals)
+ {
+ *pcLocals = LocalCount;
+ }
+ErrExit:
+ if (FAILED(hr) && LocalCount != 0)
+ {
+ unsigned i;
+ for (i =0; i < LocalCount; i++)
+ {
+ RELEASE(pLocals[i]);
+ }
+ }
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetNamespaces
+// Input: either pcNameSpaces or
+// cNameSpaces and pNameSpaces
+//-----------------------------------------------------------
+HRESULT
+SymScope::GetNamespaces(
+ ULONG32 cNameSpaces, // [optional] number of entries pNameSpaces
+ ULONG32 *pcNameSpaces, // [optional, out] Maximum number of Namespace
+ ISymUnmanagedNamespace *pNameSpaces[] // [optinal] array to store namespaces into
+ )
+{
+ HRESULT hr = NOERROR;
+ unsigned i;
+ UINT32 NameSpace;
+ unsigned NameSpaceCount = 0;
+
+ _ASSERTE(pcNameSpaces || (pNameSpaces && cNameSpaces));
+ IfFalseGo(pcNameSpaces || (pNameSpaces && cNameSpaces), E_INVALIDARG);
+
+ for (NameSpace = m_pData->m_pMethods[m_MethodEntry].StartUsing();
+ NameSpace < m_pData->m_pMethods[m_MethodEntry].EndUsing();
+ NameSpace++)
+ {
+ if (m_pData->m_pUsings[NameSpace].ParentScope() == m_ScopeEntry)
+ {
+ if (pNameSpaces && (NameSpaceCount < cNameSpaces) )
+ {
+ IfNullGo(pNameSpaces[NameSpaceCount] = NEW(SymReaderNamespace(this, m_pData, NameSpace)));
+ pNameSpaces[NameSpaceCount]->AddRef();
+ }
+ NameSpaceCount++;
+ }
+ }
+ if (pcNameSpaces)
+ {
+ *pcNameSpaces = NameSpaceCount;
+ }
+ErrExit:
+ if (FAILED(hr) && pNameSpaces)
+ {
+ for (i = 0; (i < cNameSpaces) && (i < NameSpaceCount); i++)
+ {
+ RELEASE(pNameSpaces[i]);
+ }
+ }
+ return hr;
+}
+
+/* ------------------------------------------------------------------------- *
+ * SymReaderVar class
+ * ------------------------------------------------------------------------- */
+
+//-----------------------------------------------------------
+// QueryInterface
+//-----------------------------------------------------------
+HRESULT
+SymReaderVar::QueryInterface(
+ REFIID riid,
+ void **ppInterface
+ )
+{
+ if (ppInterface == NULL)
+ return E_INVALIDARG;
+
+ if (riid == IID_ISymUnmanagedVariable)
+ *ppInterface = (ISymUnmanagedVariable*)this;
+ else if (riid == IID_IUnknown)
+ *ppInterface = (IUnknown*)(ISymUnmanagedVariable*)this;
+ else
+ {
+ *ppInterface = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+//-----------------------------------------------------------
+// GetName
+//-----------------------------------------------------------
+HRESULT
+SymReaderVar::GetName(
+ ULONG32 cchName, // [optional] Length of szName buffer
+ ULONG32 *pcchName, // [optional, out] Total size needed to return the name
+ __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[] // [optional] Buffer to store the name into.
+ )
+{
+ HRESULT hr = S_OK;
+
+ // We must have at least one combination
+ _ASSERTE(pcchName || (szName && cchName));
+ IfFalseGo( (pcchName || (szName && cchName)), E_INVALIDARG );
+
+ if (pcchName)
+ {
+ // Convert the UTF8 string to Wide
+ *pcchName = (ULONG32) MultiByteToWideChar(CP_UTF8,
+ 0,
+ (LPCSTR)&(m_pData->m_pStringsBytes[m_pData->m_pVars[m_VarEntry].Name()]),
+ -1,
+ 0,
+ NULL);
+
+ }
+ if (szName)
+ {
+ // Convert the UTF8 string to Wide
+ MultiByteToWideChar(CP_UTF8,
+ 0,
+ (LPCSTR)&(m_pData->m_pStringsBytes[m_pData->m_pVars[m_VarEntry].Name()]),
+ -1,
+ szName,
+ cchName);
+ }
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetAttributes
+//-----------------------------------------------------------
+HRESULT
+SymReaderVar::GetAttributes(
+ ULONG32 *pRetVal // [out]
+ )
+{
+ if (pRetVal == NULL)
+ return E_INVALIDARG;
+
+ *pRetVal = m_pData->m_pVars[m_VarEntry].Attributes();
+ return S_OK;
+}
+
+//-----------------------------------------------------------
+// GetSignature
+//-----------------------------------------------------------
+HRESULT
+SymReaderVar::GetSignature(
+ ULONG32 cSig, // Size of allocated buffer passed in (sig)
+ ULONG32 *pcSig, // [optional, out] Total size needed to return the signature
+ BYTE sig[] // [Optional] Signature
+ )
+{
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pcSig || sig);
+ IfFalseGo( pcSig || sig, E_INVALIDARG );
+ if (pcSig)
+ {
+ *pcSig = m_pData->m_pVars[m_VarEntry].SignatureSize();
+ }
+ if (sig)
+ {
+ cSig = min(m_pData->m_pVars[m_VarEntry].SignatureSize(), cSig);
+ memcpy(sig, &m_pData->m_pBytes[m_pData->m_pVars[m_VarEntry].Signature()],cSig);
+ }
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetAddressKind
+//-----------------------------------------------------------
+HRESULT
+SymReaderVar::GetAddressKind(
+ ULONG32 *pRetVal // [out]
+ )
+{
+ HRESULT hr = S_OK;
+ _ASSERTE(pRetVal);
+ IfFalseGo( pRetVal, E_INVALIDARG );
+ *pRetVal = m_pData->m_pVars[m_VarEntry].AddrKind();
+ErrExit:
+ return S_OK;
+}
+
+//-----------------------------------------------------------
+// GetAddressField1
+//-----------------------------------------------------------
+HRESULT
+SymReaderVar::GetAddressField1(
+ ULONG32 *pRetVal // [out]
+ )
+{
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pRetVal);
+ IfFalseGo( pRetVal, E_INVALIDARG );
+
+ *pRetVal = m_pData->m_pVars[m_VarEntry].Addr1();
+
+ErrExit:
+
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetAddressField2
+//-----------------------------------------------------------
+HRESULT
+SymReaderVar::GetAddressField2(
+ ULONG32 *pRetVal // [out]
+ )
+{
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pRetVal);
+ IfFalseGo( pRetVal, E_INVALIDARG );
+
+ *pRetVal = m_pData->m_pVars[m_VarEntry].Addr2();
+
+ErrExit:
+
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetAddressField3
+//-----------------------------------------------------------
+HRESULT
+SymReaderVar::GetAddressField3(
+ ULONG32 *pRetVal // [out]
+ )
+{
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pRetVal);
+ IfFalseGo( pRetVal, E_INVALIDARG );
+
+ *pRetVal = m_pData->m_pVars[m_VarEntry].Addr3();
+
+ErrExit:
+
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetStartOffset
+//-----------------------------------------------------------
+HRESULT
+SymReaderVar::GetStartOffset(
+ ULONG32 *pRetVal
+ )
+{
+ //
+ // This symbol reader doesn't support variable sub-offsets.
+ //
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// GetEndOffset
+//-----------------------------------------------------------
+HRESULT
+SymReaderVar::GetEndOffset(
+ ULONG32 *pRetVal
+ )
+{
+ //
+ // This symbol reader doesn't support variable sub-offsets.
+ //
+ return E_NOTIMPL;
+}
+
+
+/* ------------------------------------------------------------------------- *
+ * SymReaderNamespace class
+ * ------------------------------------------------------------------------- */
+
+//-----------------------------------------------------------
+// QueryInterface
+//-----------------------------------------------------------
+HRESULT
+SymReaderNamespace::QueryInterface(
+ REFIID riid,
+ void** ppInterface
+ )
+{
+ if (ppInterface == NULL)
+ return E_INVALIDARG;
+
+ if (riid == IID_ISymUnmanagedNamespace)
+ *ppInterface = (ISymUnmanagedNamespace*)this;
+ else if (riid == IID_IUnknown)
+ *ppInterface = (IUnknown*)(ISymUnmanagedNamespace*)this;
+ else
+ {
+ *ppInterface = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+//-----------------------------------------------------------
+// GetName
+//-----------------------------------------------------------
+HRESULT
+SymReaderNamespace::GetName(
+ ULONG32 cchName, // [optional] Chars available in szName
+ ULONG32 *pcchName, // [optional] Total size needed to return the name
+ __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[] // [optional] Location to store the name into.
+ )
+{
+ HRESULT hr = S_OK;
+ _ASSERTE(pcchName || (szName && cchName));
+ IfFalseGo( (pcchName || (szName && cchName)), E_INVALIDARG );
+
+ if (pcchName)
+ {
+ *pcchName = (ULONG32) MultiByteToWideChar(CP_UTF8,
+ 0,
+ (LPCSTR)&(m_pData->m_pStringsBytes[m_pData->m_pUsings[m_NamespaceEntry].Name()]),
+ -1,
+ 0,
+ NULL);
+ }
+ if (szName)
+ {
+ MultiByteToWideChar(CP_UTF8,
+ 0,
+ (LPCSTR)&(m_pData->m_pStringsBytes[m_pData->m_pUsings[m_NamespaceEntry].Name()]),
+ -1,
+ szName,
+ cchName);
+ }
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// GetNamespaces
+//-----------------------------------------------------------
+HRESULT
+SymReaderNamespace::GetNamespaces(
+ ULONG32 cNamespaces,
+ ULONG32 *pcNamespaces,
+ ISymUnmanagedNamespace* namespaces[]
+ )
+{
+ // This symbol store doesn't support namespaces.
+ _ASSERTE(!"NYI");
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// GetVariables
+//-----------------------------------------------------------
+HRESULT
+SymReaderNamespace::GetVariables(
+ ULONG32 cVariables,
+ ULONG32 *pcVariables,
+ ISymUnmanagedVariable *pVars[])
+{
+ // This symbol store doesn't support namespaces.
+ _ASSERTE(!"NYI");
+ return E_NOTIMPL;
+}
+
+
+/* ------------------------------------------------------------------------- *
+ * SequencePoint struct functions
+ * ------------------------------------------------------------------------- */
+
+//-----------------------------------------------------------
+// IsWithin - Is the point given within this sequence point
+//-----------------------------------------------------------
+bool SequencePoint::IsWithin(
+ ULONG32 line,
+ ULONG32 column)
+{
+ // If the sequence point starts on the same line
+ // Check the start column (if present)
+ if (StartLine() == line)
+ {
+ if (0 < column && StartColumn() > column)
+ {
+ return false;
+ }
+ }
+
+ // If the sequence point ends on the same line
+ // Check the end column
+ if (EndLine() == line)
+ {
+ if (EndColumn() < column)
+ {
+ return false;
+ }
+ }
+
+ // Make sure the line is within this sequence point
+ if (!((StartLine() <= line) && (EndLine() >= line)))
+ {
+ return false;
+ }
+
+ // Yep it's within this sequence point
+ return true;
+
+}
+
+//-----------------------------------------------------------
+// IsWithinLineOnly - Is the given line within this sequence point
+//-----------------------------------------------------------
+bool SequencePoint::IsWithinLineOnly(
+ ULONG32 line)
+{
+ return ((StartLine() <= line) && (line <= EndLine()));
+}
+
+//-----------------------------------------------------------
+// IsGreaterThan - Is the sequence point greater than the position
+//-----------------------------------------------------------
+bool SequencePoint::IsGreaterThan(
+ ULONG32 line,
+ ULONG32 column)
+{
+ return (StartLine() > line) ||
+ (StartLine() == line && StartColumn() > column);
+}
+
+//-----------------------------------------------------------
+// IsLessThan - Is the sequence point less than the position
+//-----------------------------------------------------------
+bool SequencePoint::IsLessThan
+(
+ ULONG32 line,
+ ULONG32 column
+)
+{
+ return (StartLine() < line) ||
+ (StartLine() == line && StartColumn() < column);
+}
+
+//-----------------------------------------------------------
+// IsUserLine - Is the sequence part of user code
+//-----------------------------------------------------------
+bool SequencePoint::IsUserLine()
+{
+ return StartLine() != CODE_WITH_NO_SOURCE;
+}
diff --git a/src/debug/ildbsymlib/symread.h b/src/debug/ildbsymlib/symread.h
new file mode 100644
index 0000000000..6264e42bdc
--- /dev/null
+++ b/src/debug/ildbsymlib/symread.h
@@ -0,0 +1,554 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ===========================================================================
+// File: SymRead.h
+//
+
+// ===========================================================================
+
+#ifndef SYMREAD_H_
+#define SYMREAD_H_
+
+class SymScope;
+class SymReaderVar;
+class SymDocument;
+
+// -------------------------------------------------------------------------
+// SymReader class
+// -------------------------------------------------------------------------
+
+class SymReader : public ISymUnmanagedReader
+{
+// ctor/dtor
+public:
+ SymReader()
+ {
+ m_refCount = 0;
+ m_pPDBInfo = NULL;
+ m_pDocs = NULL;
+ m_pImporter = NULL;
+ m_fInitialized = false;
+ m_fInitializeFromStream = false;
+ memset(&m_DataPointers, 0, sizeof(PDBDataPointers));
+ m_szPath[0] = '\0';
+ }
+ virtual ~SymReader();
+ static HRESULT NewSymReader( REFCLSID clsid, void** ppObj );
+
+public:
+ //-----------------------------------------------------------
+ // IUnknown support
+ //-----------------------------------------------------------
+ ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return (InterlockedIncrement((LONG *) &m_refCount));
+ }
+
+ ULONG STDMETHODCALLTYPE Release()
+ {
+ LONG refCount = InterlockedDecrement((LONG *) &m_refCount);
+ if (refCount == 0)
+ DELETE(this);
+
+ return (refCount);
+ }
+ STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject);
+
+// ISymUnmanagedReader
+public:
+ STDMETHOD(GetDocument)(__in LPWSTR url,
+ GUID language,
+ GUID languageVendor,
+ GUID documentType,
+ ISymUnmanagedDocument **pRetVal);
+ STDMETHOD(GetDocuments)(ULONG32 cDocs,
+ ULONG32 *pcDocs,
+ ISymUnmanagedDocument *pDocs[]);
+ STDMETHOD(GetUserEntryPoint)(mdMethodDef *pRetVal);
+ STDMETHOD(GetMethod)(mdMethodDef method,
+ ISymUnmanagedMethod **pRetVal);
+ STDMETHOD(GetMethodByVersion)(mdMethodDef method,
+ int version,
+ ISymUnmanagedMethod **pRetVal);
+ STDMETHOD(GetVariables)(mdToken parent,
+ ULONG32 cVars,
+ ULONG32 *pcVars,
+ ISymUnmanagedVariable *pVars[]);
+ STDMETHOD(GetGlobalVariables)(ULONG32 cVars,
+ ULONG32 *pcVars,
+ ISymUnmanagedVariable *pVars[]);
+ STDMETHOD(GetMethodFromDocumentPosition)(ISymUnmanagedDocument *document,
+ ULONG32 line,
+ ULONG32 column,
+ ISymUnmanagedMethod **pRetVal);
+ STDMETHOD(GetSymAttribute)(mdToken parent,
+ __in LPWSTR name,
+ ULONG32 cBuffer,
+ ULONG32 *pcBuffer,
+ __out_bcount_part_opt(cBuffer, *pcBuffer) BYTE buffer[]);
+ STDMETHOD(GetNamespaces)(ULONG32 cNameSpaces,
+ ULONG32 *pcNameSpaces,
+ ISymUnmanagedNamespace *namespaces[]);
+ STDMETHOD(Initialize)(IUnknown *importer,
+ const WCHAR* szFileName,
+ const WCHAR* szsearchPath,
+ IStream *pIStream);
+ STDMETHOD(UpdateSymbolStore)(const WCHAR *filename,
+ IStream *pIStream);
+
+ STDMETHOD(ReplaceSymbolStore)(const WCHAR *filename,
+ IStream *pIStream);
+
+ STDMETHOD(GetSymbolStoreFileName)(ULONG32 cchName,
+ ULONG32 *pcchName,
+ __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
+
+ STDMETHOD(GetMethodsFromDocumentPosition)(ISymUnmanagedDocument* document,
+ ULONG32 line,
+ ULONG32 column,
+ ULONG32 cMethod,
+ ULONG32* pcMethod,
+ ISymUnmanagedMethod* pRetVal[]);
+
+ STDMETHOD(GetDocumentVersion)(ISymUnmanagedDocument *pDoc, int* version, BOOL* pbCurrent);
+
+ STDMETHOD(GetMethodVersion)(ISymUnmanagedMethod* pMethod, int* version);
+
+ //-----------------------------------------------------------
+ // Methods not exposed via a COM interface.
+ //-----------------------------------------------------------
+public:
+ HRESULT GetDocument(UINT32 DocumentEntry, SymDocument **ppDocument);
+private:
+ void Cleanup();
+
+ HRESULT InitializeFromFile(const WCHAR* szFileName,
+ const WCHAR* szsearchPath);
+
+ HRESULT InitializeFromStream(IStream * pIStream);
+
+ HRESULT VerifyPEDebugInfo(const WCHAR* szFileName);
+
+ HRESULT ValidateData();
+
+ HRESULT ValidateBytes(UINT32 bytesIndex, UINT32 bytesLength);
+
+private:
+ // Data Members
+ UINT32 m_refCount;
+
+ // Symbol File Name
+ WCHAR m_szPath[ _MAX_PATH ];
+ WCHAR m_szStoredSymbolName[ _MAX_PATH ];
+
+ PDBInfo *m_pPDBInfo;
+ SymDocument **m_pDocs;
+ IUnknown *m_pImporter;
+ PDBDataPointers m_DataPointers;
+
+ // Are we initialized yet?
+ bool m_fInitialized;
+
+ // Did we initialize from stream
+ bool m_fInitializeFromStream;
+ };
+
+/* ------------------------------------------------------------------------- *
+ * SymDocument class
+ * ------------------------------------------------------------------------- */
+
+class SymDocument : public ISymUnmanagedDocument
+{
+// ctor/dtor
+public:
+ SymDocument(SymReader *pReader,
+ PDBDataPointers *pData,
+ UINT32 CountOfMethods,
+ UINT32 DocumentEntry)
+ {
+ m_refCount = 0;
+ m_pData = pData;
+ m_DocumentEntry = DocumentEntry;
+ m_CountOfMethods = CountOfMethods;
+ m_pReader = pReader;
+ pReader->AddRef();
+
+ }
+ virtual ~SymDocument()
+ {
+ RELEASE(m_pReader);
+ }
+
+// IUnknown
+public:
+ //-----------------------------------------------------------
+ // IUnknown support
+ //-----------------------------------------------------------
+ ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return (InterlockedIncrement((LONG *) &m_refCount));
+ }
+
+ ULONG STDMETHODCALLTYPE Release()
+ {
+ LONG refCount = InterlockedDecrement((LONG *) &m_refCount);
+ if (refCount == 0)
+ DELETE(this);
+
+ return (refCount);
+ }
+ STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject);
+
+// ISymUnmanagedDocument
+public:
+ STDMETHOD(GetURL)(ULONG32 cchUrl,
+ ULONG32 *pcchUrl,
+ __out_ecount_part_opt(cchUrl, *pcchUrl) WCHAR szUrl[]);
+ STDMETHOD(GetDocumentType)(GUID *pRetVal);
+ STDMETHOD(GetLanguage)(GUID *pRetVal);
+ STDMETHOD(GetLanguageVendor)(GUID *pRetVal);
+ STDMETHOD(GetCheckSumAlgorithmId)(GUID *pRetVal);
+ STDMETHOD(GetCheckSum)(ULONG32 cData,
+ ULONG32 *pcData,
+ BYTE data[]);
+ STDMETHOD(FindClosestLine)(ULONG32 line, ULONG32 *pRetVal);
+ STDMETHOD(HasEmbeddedSource)(BOOL *pRetVal);
+ STDMETHOD(GetSourceLength)(ULONG32 *pRetVal);
+ STDMETHOD(GetSourceRange)(ULONG32 startLine,
+ ULONG32 startColumn,
+ ULONG32 endLine,
+ ULONG32 endColumn,
+ ULONG32 cSourceBytes,
+ ULONG32 *pcSourceBytes,
+ BYTE source[]);
+
+ //-----------------------------------------------------------
+ // Methods not exposed via a COM interface.
+ //-----------------------------------------------------------
+ UINT32 GetDocumentEntry()
+ {
+ return m_DocumentEntry;
+ }
+
+// Data members
+private:
+ UINT32 m_refCount;
+
+ SymReader *m_pReader;
+
+ // Data Pointer
+ PDBDataPointers *m_pData;
+
+ // Entry into the document array
+ UINT32 m_DocumentEntry;
+
+ // Total number of methods in the ildb
+ UINT32 m_CountOfMethods;
+
+};
+
+/* ------------------------------------------------------------------------- *
+ * SymMethod class
+ * ------------------------------------------------------------------------- */
+
+class SymMethod : public ISymUnmanagedMethod
+{
+// ctor/dtor
+public:
+ SymMethod(SymReader *pSymReader, PDBDataPointers *pData, UINT32 MethodEntry)
+ {
+ m_pData = pData;
+ m_MethodEntry = MethodEntry;
+ m_refCount = 0;
+ m_pReader = pSymReader;
+ pSymReader->AddRef();
+ }
+
+ virtual ~SymMethod()
+ {
+ RELEASE(m_pReader);
+ };
+
+public:
+
+ //-----------------------------------------------------------
+ // IUnknown support
+ //-----------------------------------------------------------
+ ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return (InterlockedIncrement((LONG *) &m_refCount));
+ }
+
+ ULONG STDMETHODCALLTYPE Release()
+ {
+ LONG refCount = InterlockedDecrement((LONG *) &m_refCount);
+ if (refCount == 0)
+ DELETE(this);
+
+ return (refCount);
+ }
+ STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject);
+
+// ISymUnmanagedMethod
+public:
+ STDMETHOD(GetToken)(mdMethodDef *pRetVal);
+ STDMETHOD(GetSequencePointCount)(ULONG32 *pRetVal);
+
+ STDMETHOD(GetRootScope)(ISymUnmanagedScope **pRetVal);
+ STDMETHOD(GetScopeFromOffset)(ULONG32 offset,
+ ISymUnmanagedScope **pRetVal);
+ STDMETHOD(GetOffset)(ISymUnmanagedDocument *document,
+ ULONG32 line,
+ ULONG32 column,
+ ULONG32 *pRetVal);
+ STDMETHOD(GetRanges)(ISymUnmanagedDocument *document,
+ ULONG32 line,
+ ULONG32 column,
+ ULONG32 cRanges,
+ ULONG32 *pcRanges,
+ ULONG32 ranges[]);
+ STDMETHOD(GetParameters)(ULONG32 cParams,
+ ULONG32 *pcParams,
+ ISymUnmanagedVariable *params[]);
+ STDMETHOD(GetNamespace)(ISymUnmanagedNamespace **pRetVal);
+ STDMETHOD(GetSourceStartEnd)(ISymUnmanagedDocument *docs[2],
+ ULONG32 lines[2],
+ ULONG32 columns[2],
+ BOOL *pRetVal);
+ STDMETHOD(GetSequencePoints)(ULONG32 cpoints,
+ ULONG32* pcpoints,
+ ULONG32 offsets[],
+ ISymUnmanagedDocument *documents[],
+ ULONG32 lines[],
+ ULONG32 columns[],
+ ULONG32 endlines[],
+ ULONG32 endcolumns[]);
+
+// Data members
+private:
+ // AddRef/Release support
+ UINT32 m_refCount;
+
+ // Data Pointer
+ PDBDataPointers *m_pData;
+
+ // SymReader
+ SymReader *m_pReader;
+
+ // Entry into the SymMethodInfo array
+ UINT32 m_MethodEntry;
+
+};
+
+/* ------------------------------------------------------------------------- *
+ * SymScope class
+ * ------------------------------------------------------------------------- */
+
+class SymScope : public ISymUnmanagedScope
+{
+// ctor/dtor
+public:
+ SymScope(
+ ISymUnmanagedMethod *pSymMethod,
+ PDBDataPointers *pData,
+ UINT32 MethodEntry,
+ UINT32 ScopeEntry)
+ {
+ m_pSymMethod = pSymMethod;
+ m_pSymMethod->AddRef();
+ m_pData = pData;
+ m_MethodEntry = MethodEntry;
+ m_ScopeEntry = ScopeEntry;
+ m_refCount = 0;
+ }
+ virtual ~SymScope()
+ {
+ RELEASE(m_pSymMethod);
+ }
+
+public:
+ //-----------------------------------------------------------
+ // IUnknown support
+ //-----------------------------------------------------------
+ ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return (InterlockedIncrement((LONG *) &m_refCount));
+ }
+
+ ULONG STDMETHODCALLTYPE Release()
+ {
+ LONG refCount = InterlockedDecrement((LONG *) &m_refCount);
+ if (refCount == 0)
+ DELETE(this);
+
+ return (refCount);
+ }
+ STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject);
+
+// ISymUnmanagedScope
+public:
+ STDMETHOD(GetMethod)(ISymUnmanagedMethod **pRetVal);
+ STDMETHOD(GetParent)(ISymUnmanagedScope **pRetVal);
+ STDMETHOD(GetChildren)(ULONG32 cChildren,
+ ULONG32 *pcChildren,
+ ISymUnmanagedScope *children[]);
+ STDMETHOD(GetStartOffset)(ULONG32 *pRetVal);
+ STDMETHOD(GetEndOffset)(ULONG32 *pRetVal);
+ STDMETHOD(GetLocalCount)(ULONG32 *pRetVal);
+ STDMETHOD(GetLocals)(ULONG32 cLocals,
+ ULONG32 *pcLocals,
+ ISymUnmanagedVariable *locals[]);
+ STDMETHOD(GetNamespaces)(ULONG32 cNameSpaces,
+ ULONG32 *pcNameSpaces,
+ ISymUnmanagedNamespace *namespaces[]);
+
+// Data members
+private:
+
+ UINT32 m_refCount; // Add/Ref Release
+
+ ISymUnmanagedMethod *m_pSymMethod;
+
+ // Data Pointer
+ PDBDataPointers *m_pData;
+ // Entry into the SymMethodInfo array
+ UINT32 m_MethodEntry;
+ // Entry into the scope array
+ UINT32 m_ScopeEntry;
+};
+
+/* ------------------------------------------------------------------------- *
+ * SymReaderVar class
+ * ------------------------------------------------------------------------- */
+
+class SymReaderVar : public ISymUnmanagedVariable
+{
+// ctor/dtor
+public:
+ SymReaderVar(SymScope *pScope, PDBDataPointers *pData, UINT32 VarEntry)
+ {
+ m_pData = pData;
+ m_VarEntry = VarEntry;
+ m_refCount = 0;
+ m_pScope = pScope;
+ pScope->AddRef();
+ }
+ virtual ~SymReaderVar()
+ {
+ RELEASE(m_pScope);
+ }
+
+public:
+ //-----------------------------------------------------------
+ // IUnknown support
+ //-----------------------------------------------------------
+ ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return (InterlockedIncrement((LONG *) &m_refCount));
+ }
+
+ ULONG STDMETHODCALLTYPE Release()
+ {
+ LONG refCount = InterlockedDecrement((LONG *) &m_refCount);
+ if (refCount == 0)
+ DELETE(this);
+
+ return (refCount);
+ }
+ STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject);
+
+// ISymUnmanagedReaderVar
+public:
+ STDMETHOD(GetName)(ULONG32 cchName,
+ ULONG32 *pcchName,
+ __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
+ STDMETHOD(GetAttributes)(ULONG32 *pRetVal);
+ STDMETHOD(GetSignature)(ULONG32 cSig,
+ ULONG32 *pcSig,
+ BYTE sig[]);
+ STDMETHOD(GetAddressKind)(ULONG32 *pRetVal);
+ STDMETHOD(GetAddressField1)(ULONG32 *pRetVal);
+ STDMETHOD(GetAddressField2)(ULONG32 *pRetVal);
+ STDMETHOD(GetAddressField3)(ULONG32 *pRetVal);
+ STDMETHOD(GetStartOffset)(ULONG32 *pRetVal);
+ STDMETHOD(GetEndOffset)(ULONG32 *pRetVal);
+
+
+// Data members
+private:
+ UINT32 m_refCount; // Add/Ref Release
+
+ // Data Pointer
+ PDBDataPointers *m_pData;
+
+ // Scope of the variable
+ SymScope *m_pScope;
+
+ // Entry into the SymMethodInfo array
+ UINT32 m_VarEntry;
+};
+
+class SymReaderNamespace : public ISymUnmanagedNamespace
+{
+
+public:
+ SymReaderNamespace(SymScope *pScope, PDBDataPointers *pData, UINT32 NamespaceEntry)
+ {
+ m_pData = pData;
+ m_NamespaceEntry = NamespaceEntry;
+ m_refCount = 0;
+ m_pScope = pScope;
+ pScope->AddRef();
+ }
+ virtual ~SymReaderNamespace()
+ {
+ }
+
+public:
+ //-----------------------------------------------------------
+ // IUnknown support
+ //-----------------------------------------------------------
+ ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return (InterlockedIncrement((LONG *) &m_refCount));
+ }
+
+ ULONG STDMETHODCALLTYPE Release()
+ {
+ LONG refCount = InterlockedDecrement((LONG *) &m_refCount);
+ if (refCount == 0)
+ DELETE(this);
+
+ return (refCount);
+ }
+ STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject);
+
+public:
+ //-----------------------------------------------------------
+ // ISymUnmanagedNamespace support
+ //-----------------------------------------------------------
+ STDMETHOD(GetName)(ULONG32 cchName,
+ ULONG32 *pcchName,
+ __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
+ STDMETHOD(GetNamespaces)(ULONG32 cNamespaces,
+ ULONG32 *pcNamespaces,
+ ISymUnmanagedNamespace* namespaces[]);
+ STDMETHOD(GetVariables)(ULONG32 cchName,
+ ULONG32 *pcchName,
+ ISymUnmanagedVariable *pVars[]);
+
+private:
+ UINT32 m_refCount; // Add/Ref Release
+
+ // Owning scope
+ SymScope *m_pScope;
+
+ // Data Pointer
+ PDBDataPointers *m_pData;
+ // Entry into the NameSpace array
+ UINT32 m_NamespaceEntry;
+
+};
+
+#endif
diff --git a/src/debug/ildbsymlib/symwrite.cpp b/src/debug/ildbsymlib/symwrite.cpp
new file mode 100644
index 0000000000..c09fd37498
--- /dev/null
+++ b/src/debug/ildbsymlib/symwrite.cpp
@@ -0,0 +1,1553 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ===========================================================================
+// File: symwrite.cpp
+//
+
+//
+// Note: The various SymWriter_* and SymDocumentWriter_* are entry points
+// called via PInvoke from the managed symbol wrapper used by managed languages
+// to emit debug information (such as jscript)
+// ===========================================================================
+
+#include "pch.h"
+#include "symwrite.h"
+
+
+// -------------------------------------------------------------------------
+// SymWriter class
+// -------------------------------------------------------------------------
+
+// This is a COM object which is called both directly from the runtime, and from managed code
+// via PInvoke (CoreSymWrapper) and IJW (ISymWrapper). This is an unusual pattern, and it's not
+// clear exactly how best to address it. Eg., should we be using BEGIN_EXTERNAL_ENTRYPOINT
+// macros? Conceptually this is just a drop-in replacement for diasymreader.dll, and could
+// live in a different DLL instead of being statically linked into the runtime. But since it
+// relies on utilcode (and actually gets the runtime utilcode, not the nohost utilcode like
+// other external tools), it does have some properties of runtime code.
+//
+
+//-----------------------------------------------------------
+// NewSymWriter
+// Static function used to create a new instance of SymWriter
+//-----------------------------------------------------------
+HRESULT SymWriter::NewSymWriter(const GUID& id, void **object)
+{
+ if (id != IID_ISymUnmanagedWriter)
+ return (E_UNEXPECTED);
+
+ SymWriter *writer = NEW(SymWriter());
+
+ if (writer == NULL)
+ return (E_OUTOFMEMORY);
+
+ *object = (ISymUnmanagedWriter*)writer;
+ writer->AddRef();
+
+ return (S_OK);
+}
+
+//-----------------------------------------------------------
+// SymWriter Constuctor
+//-----------------------------------------------------------
+SymWriter::SymWriter() :
+ m_refCount(0),
+ m_openMethodToken(mdMethodDefNil),
+ m_LargestMethodToken(mdMethodDefNil),
+ m_pmethod(NULL),
+ m_currentScope(k_noScope),
+ m_hFile(NULL),
+ m_pIStream(NULL),
+ m_pStringPool(NULL),
+ m_closed( false ),
+ m_sortLines (false),
+ m_sortMethodEntries(false)
+{
+ memset(m_szPath, 0, sizeof(m_szPath));
+ memset(&ModuleLevelInfo, 0, sizeof(PDBInfo));
+}
+
+//-----------------------------------------------------------
+// SymWriter QI
+//-----------------------------------------------------------
+COM_METHOD SymWriter::QueryInterface(REFIID riid, void **ppInterface)
+{
+ if (ppInterface == NULL)
+ return E_INVALIDARG;
+
+ if (riid == IID_ISymUnmanagedWriter )
+ *ppInterface = (ISymUnmanagedWriter*)this;
+ /* ROTORTODO: Pretend that we do not implement ISymUnmanagedWriter2 to prevent C# compiler from using it.
+ This is against COM rules since ISymUnmanagedWriter3 inherits from ISymUnmanagedWriter2.
+ else if (riid == IID_ISymUnmanagedWriter2 )
+ *ppInterface = (ISymUnmanagedWriter2*)this;
+ */
+ else if (riid == IID_ISymUnmanagedWriter3 )
+ *ppInterface = (ISymUnmanagedWriter3*)this;
+ else if (riid == IID_IUnknown)
+ *ppInterface = (IUnknown*)(ISymUnmanagedWriter*)this;
+ else
+ {
+ *ppInterface = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+//-----------------------------------------------------------
+// SymWriter Destructor
+//-----------------------------------------------------------
+SymWriter::~SymWriter()
+{
+ // Note that this must be thread-safe - it may be invoked on the finalizer thread
+ // But since this dtor can only be invoked when all references have been released,
+ // no other threads can be manipulating the writer.
+ // Ideally we'd probably just add locking to all methods, but this is low-priority
+ // because diasymreader.dll isn't thread-safe and so we need to ensure the CLR's use
+ // of these interfaces are properly syncrhonized.
+ if ( !m_closed )
+ Close();
+ RELEASE(m_pIStream);
+ DELETE(m_pStringPool);
+}
+
+//-----------------------------------------------------------
+// SymWriter Initialize the SymWriter
+//-----------------------------------------------------------
+COM_METHOD SymWriter::Initialize
+(
+ IUnknown *emitter, // Emitter (IMetaData Emit/Import) - unused by ILDB
+ const WCHAR *szFilename, // FileName of the exe we're creating
+ IStream *pIStream, // Stream to store into
+ BOOL fFullBuild // Is this a full build or an incremental build
+)
+{
+ HRESULT hr = S_OK;
+
+ // Incremental compile not implemented in Rotor
+ _ASSERTE(fFullBuild);
+
+ if (emitter == NULL)
+ return E_INVALIDARG;
+
+ if (pIStream != NULL)
+ {
+ m_pIStream = pIStream;
+ pIStream->AddRef();
+ }
+ else
+ {
+ if (szFilename == NULL)
+ {
+ IfFailRet(E_INVALIDARG);
+ }
+ }
+
+ m_pStringPool = NEW(StgStringPool());
+ IfFailRet(m_pStringPool->InitNew());
+
+ if (szFilename != NULL)
+ {
+ wchar_t fullpath[_MAX_PATH];
+ wchar_t drive[_MAX_DRIVE];
+ wchar_t dir[_MAX_DIR];
+ wchar_t fname[_MAX_FNAME];
+ _wsplitpath_s( szFilename, drive, COUNTOF(drive), dir, COUNTOF(dir), fname, COUNTOF(fname), NULL, 0 );
+ _wmakepath_s( fullpath, COUNTOF(fullpath), drive, dir, fname, W("ildb") );
+ if (wcsncpy_s( m_szPath, COUNTOF(m_szPath), fullpath, _TRUNCATE) == STRUNCATE)
+ return HrFromWin32(ERROR_INSUFFICIENT_BUFFER);
+ }
+
+ // Note that we don't need the emitter - ILDB is agnostic to the module metadata.
+
+ return hr;
+}
+
+//-----------------------------------------------------------
+// SymWriter Initialize2 the SymWriter
+// Delegate to Initialize then use the szFullPathName param
+//-----------------------------------------------------------
+COM_METHOD SymWriter::Initialize2
+(
+ IUnknown *emitter, // Emitter (IMetaData Emit/Import)
+ const WCHAR *szTempPath, // Location of the file
+ IStream *pIStream, // Stream to store into
+ BOOL fFullBuild, // Full build or not
+ const WCHAR *szFullPathName // Final destination of the ildb
+)
+{
+ HRESULT hr = S_OK;
+ IfFailGo( Initialize( emitter, szTempPath, pIStream, fFullBuild ) );
+ // We don't need the final location of the ildb
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// SymWriter GetorCreateDocument
+// creates a new symbol document writer for a specified source
+// Arguments:
+// input: wcsUrl - The source file name
+// output: ppRetVal - The new document writer
+// Return Value: hr - S_OK if success, OOM otherwise
+//-----------------------------------------------------------
+HRESULT SymWriter::GetOrCreateDocument(
+ const WCHAR *wcsUrl, // Document name
+ const GUID *pLanguage, // What Language we're compiling
+ const GUID *pLanguageVendor, // What vendor
+ const GUID *pDocumentType, // Type
+ ISymUnmanagedDocumentWriter **ppRetVal // [out] Created DocumentWriter
+)
+{
+ ULONG UrlEntry;
+ DWORD strLength = WszWideCharToMultiByte(CP_UTF8, 0, wcsUrl, -1, 0, 0, 0, 0);
+ LPSTR multiByteURL = (LPSTR) new char [strLength+1];
+ HRESULT hr = S_OK;
+
+ if (multiByteURL == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ WszWideCharToMultiByte(CP_UTF8, 0, wcsUrl, -1, multiByteURL, strLength+1, 0, 0);
+
+ if (m_pStringPool->FindString(multiByteURL, &UrlEntry) == S_FALSE) // no file of that name has been seen before
+ {
+ hr = CreateDocument(wcsUrl, pLanguage, pLanguageVendor, pDocumentType, ppRetVal);
+ }
+ else // we already have a writer for this file
+ {
+ UINT32 docInfo = 0;
+
+ CRITSEC_COOKIE cs = ClrCreateCriticalSection(CrstLeafLock, CRST_DEFAULT);
+
+ ClrEnterCriticalSection(cs);
+
+ while ((docInfo < m_MethodInfo.m_documents.count()) && (m_MethodInfo.m_documents[docInfo].UrlEntry() != UrlEntry))
+ {
+ docInfo++;
+ }
+
+ if (docInfo == m_MethodInfo.m_documents.count()) // something went wrong and we didn't find the writer
+ {
+ hr = CreateDocument(wcsUrl, pLanguage, pLanguageVendor, pDocumentType, ppRetVal);
+ }
+ else
+ {
+ *ppRetVal = m_MethodInfo.m_documents[docInfo].DocumentWriter();
+ (*ppRetVal)->AddRef();
+ }
+ ClrLeaveCriticalSection(cs);
+ }
+
+ delete [] multiByteURL;
+ return hr;
+
+} // SymWriter::GetOrCreateDocument
+
+//-----------------------------------------------------------
+// SymWriter CreateDocument
+// creates a new symbol document writer for a specified source
+// Arguments:
+// input: wcsUrl - The source file name
+// output: ppRetVal - The new document writer
+// Return Value: hr - S_OK if success, OOM otherwise
+//-----------------------------------------------------------
+HRESULT SymWriter::CreateDocument(const WCHAR *wcsUrl, // Document name
+ const GUID *pLanguage, // What Language we're compiling
+ const GUID *pLanguageVendor, // What vendor
+ const GUID *pDocumentType, // Type
+ ISymUnmanagedDocumentWriter **ppRetVal // [out] Created DocumentWriter
+)
+
+{
+ DocumentInfo* pDocument = NULL;
+ SymDocumentWriter *sdw = NULL;
+ UINT32 DocumentEntry;
+ ULONG UrlEntry;
+ HRESULT hr = NOERROR;
+
+ DocumentEntry = m_MethodInfo.m_documents.count();
+ IfNullGo(pDocument = m_MethodInfo.m_documents.next());
+ memset(pDocument, 0, sizeof(DocumentInfo));
+
+ // Create the new document writer.
+ sdw = NEW(SymDocumentWriter(DocumentEntry, this));
+ IfNullGo(sdw);
+
+ pDocument->SetLanguage(*pLanguage);
+ pDocument->SetLanguageVendor(*pLanguageVendor);
+ pDocument->SetDocumentType(*pDocumentType);
+ pDocument->SetDocumentWriter(sdw);
+
+ // stack check needed to call back into utilcode
+ BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD_FORCE_SO();
+ hr = m_pStringPool->AddStringW(wcsUrl, (UINT32 *)&UrlEntry);
+ END_SO_INTOLERANT_CODE;
+ IfFailGo(hr);
+
+ pDocument->SetUrlEntry(UrlEntry);
+
+ // Pass out the new ISymUnmanagedDocumentWriter.
+ sdw->AddRef();
+ *ppRetVal = (ISymUnmanagedDocumentWriter*)sdw;
+ sdw = NULL;
+
+ErrExit:
+ DELETE(sdw);
+ return hr;
+}
+
+//-----------------------------------------------------------
+// SymWriter DefineDocument
+//-----------------------------------------------------------
+COM_METHOD SymWriter::DefineDocument(
+ const WCHAR *wcsUrl, // Document name
+ const GUID *pLanguage, // What Language we're compiling
+ const GUID *pLanguageVendor, // What vendor
+ const GUID *pDocumentType, // Type
+ ISymUnmanagedDocumentWriter **ppRetVal // [out] Created DocumentWriter
+)
+{
+ HRESULT hr = NOERROR;
+
+ IfFalseGo(wcsUrl, E_INVALIDARG);
+ IfFalseGo(pLanguage, E_INVALIDARG);
+ IfFalseGo(pLanguageVendor, E_INVALIDARG);
+ IfFalseGo(pDocumentType, E_INVALIDARG);
+ IfFalseGo(ppRetVal, E_INVALIDARG);
+
+ // Init out parameter
+ *ppRetVal = NULL;
+
+ hr = GetOrCreateDocument(wcsUrl, pLanguage, pLanguageVendor, pDocumentType, ppRetVal);
+ErrExit:
+ return hr;
+}
+
+
+//-----------------------------------------------------------
+// SymWriter SetDocumentSrc
+//-----------------------------------------------------------
+HRESULT SymWriter::SetDocumentSrc(
+ UINT32 DocumentEntry,
+ DWORD SourceSize,
+ BYTE* pSource
+)
+{
+ DocumentInfo* pDocument = NULL;
+ HRESULT hr = S_OK;
+
+ IfFalseGo( SourceSize == 0 || pSource, E_INVALIDARG);
+ IfFalseGo( DocumentEntry < m_MethodInfo.m_documents.count(), E_INVALIDARG);
+
+ pDocument = &m_MethodInfo.m_documents[DocumentEntry];
+
+ if (pSource)
+ {
+ UINT32 i;
+ IfFalseGo( m_MethodInfo.m_bytes.grab(SourceSize, &i), E_OUTOFMEMORY);
+ memcpy(&m_MethodInfo.m_bytes[i], pSource, SourceSize);
+ pDocument->SetSourceEntry(i);
+ pDocument->SetSourceSize(SourceSize);
+ }
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// SymWriter SetDocumentCheckSum
+//-----------------------------------------------------------
+HRESULT SymWriter::SetDocumentCheckSum(
+ UINT32 DocumentEntry,
+ GUID AlgorithmId,
+ DWORD CheckSumSize,
+ BYTE* pCheckSum
+)
+{
+ DocumentInfo* pDocument = NULL;
+ HRESULT hr = S_OK;
+
+ IfFalseGo( CheckSumSize == 0 || pCheckSum, E_INVALIDARG);
+ IfFalseGo( DocumentEntry < m_MethodInfo.m_documents.count(), E_INVALIDARG);
+
+ pDocument = &m_MethodInfo.m_documents[DocumentEntry];
+
+ if (pCheckSum)
+ {
+ UINT32 i;
+ IfFalseGo( m_MethodInfo.m_bytes.grab(CheckSumSize, &i), E_OUTOFMEMORY);
+ memcpy(&m_MethodInfo.m_bytes[i], pCheckSum, CheckSumSize);
+ pDocument->SetCheckSumEntry(i);
+ pDocument->SetCheckSymSize(CheckSumSize);
+ }
+
+ pDocument->SetAlgorithmId(AlgorithmId);
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// SymWriter SetUserEntryPoint
+//-----------------------------------------------------------
+COM_METHOD SymWriter::SetUserEntryPoint(mdMethodDef entryMethod)
+{
+ HRESULT hr = S_OK;
+
+ // Make sure that an entry point hasn't already been set.
+ if (ModuleLevelInfo.m_userEntryPoint == 0)
+ ModuleLevelInfo.m_userEntryPoint = entryMethod;
+
+ return hr;
+}
+
+//-----------------------------------------------------------
+// SymWriter OpenMethod
+// Get ready to get information about a new method
+//-----------------------------------------------------------
+COM_METHOD SymWriter::OpenMethod(mdMethodDef method)
+{
+ HRESULT hr = S_OK;
+
+ // We can only have one open method at a time.
+ if (m_openMethodToken != mdMethodDefNil)
+ return E_INVALIDARG;
+
+ m_LargestMethodToken = max(method, m_LargestMethodToken);
+
+ if (m_LargestMethodToken != method)
+ {
+ m_sortMethodEntries = true;
+ // Check to see if we're trying to open a method we've already done
+ unsigned i;
+ for (i = 0; i < m_MethodInfo.m_methods.count(); i++)
+ {
+ if (m_MethodInfo.m_methods[i].MethodToken() == method)
+ {
+ return E_INVALIDARG;
+ }
+ }
+ }
+
+ // Remember the token for this method.
+ m_openMethodToken = method;
+
+ IfNullGo( m_pmethod = m_MethodInfo.m_methods.next() );
+ m_pmethod->SetMethodToken(m_openMethodToken);
+ m_pmethod->SetStartScopes(m_MethodInfo.m_scopes.count());
+ m_pmethod->SetStartVars(m_MethodInfo.m_vars.count());
+ m_pmethod->SetStartUsing(m_MethodInfo.m_usings.count());
+ m_pmethod->SetStartConstant(m_MethodInfo.m_constants.count());
+ m_pmethod->SetStartDocuments(m_MethodInfo.m_documents.count());
+ m_pmethod->SetStartSequencePoints(m_MethodInfo.m_auxSequencePoints.count());
+
+ // By default assume the lines are inserted in the correct order
+ m_sortLines = false;
+
+ // Initialize the maximum scope end offset for this method
+ m_maxScopeEnd = 1;
+
+ // Open the implicit root scope for the method
+ _ASSERTE(m_currentScope == k_noScope);
+
+ IfFailRet(OpenScope(0, NULL));
+
+ _ASSERTE(m_currentScope != k_noScope);
+
+ErrExit:
+ return hr;
+}
+
+COM_METHOD SymWriter::OpenMethod2(
+ mdMethodDef method,
+ ULONG32 isect,
+ ULONG32 offset)
+{
+ // This symbol writer doesn't support section offsets
+ _ASSERTE(FALSE);
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// compareAuxLines
+// Used to sort SequencePoint
+//-----------------------------------------------------------
+int __cdecl SequencePoint::compareAuxLines(const void *elem1, const void *elem2 )
+{
+ SequencePoint* p1 = (SequencePoint*)elem1;
+ SequencePoint* p2 = (SequencePoint*)elem2;
+ return p1->Offset() - p2->Offset();
+}
+
+//-----------------------------------------------------------
+// SymWriter CloseMethod
+// We're done with this function, write it out.
+//-----------------------------------------------------------
+COM_METHOD SymWriter::CloseMethod()
+{
+ HRESULT hr = S_OK;
+ UINT32 CountOfSequencePoints;
+
+ // Must have an open method.
+ if (m_openMethodToken == mdMethodDefNil)
+ return E_UNEXPECTED;
+
+ // All scopes up to the root must have been closed (and the root must not have been closed).
+ _ASSERTE(m_currentScope != k_noScope);
+ if (m_MethodInfo.m_scopes[m_currentScope].ParentScope() != k_noScope)
+ return E_FAIL;
+
+ // Close the implicit root scope using the largest end offset we've seen in this method, or 1 if none.
+ IfFailRet(CloseScopeInternal(m_maxScopeEnd));
+
+ m_pmethod->SetEndScopes(m_MethodInfo.m_scopes.count());
+ m_pmethod->SetEndVars(m_MethodInfo.m_vars.count());
+ m_pmethod->SetEndUsing(m_MethodInfo.m_usings.count());
+ m_pmethod->SetEndConstant(m_MethodInfo.m_constants.count());
+ m_pmethod->SetEndDocuments(m_MethodInfo.m_documents.count());
+ m_pmethod->SetEndSequencePoints(m_MethodInfo.m_auxSequencePoints.count());
+
+ CountOfSequencePoints = m_pmethod->EndSequencePoints() - m_pmethod->StartSequencePoints();
+ // Write any sequence points.
+ if (CountOfSequencePoints > 0 ) {
+ // sort the sequence points
+ if ( m_sortLines )
+ {
+ qsort(&m_MethodInfo.m_auxSequencePoints[m_pmethod->StartSequencePoints()],
+ CountOfSequencePoints,
+ sizeof( SequencePoint ),
+ SequencePoint::compareAuxLines );
+ }
+ }
+
+ // All done with this method.
+ m_openMethodToken = mdMethodDefNil;
+
+ return hr;
+}
+
+//-----------------------------------------------------------
+// SymWriter DefineSequencePoints
+// Define the sequence points for this function
+//-----------------------------------------------------------
+COM_METHOD SymWriter::DefineSequencePoints(
+ ISymUnmanagedDocumentWriter *document, //
+ ULONG32 spCount, // Count of sequence points
+ ULONG32 offsets[], // Offsets
+ ULONG32 lines[], // Beginning Lines
+ ULONG32 columns[], // [optional] Columns
+ ULONG32 endLines[], // [optional] End Lines
+ ULONG32 endColumns[] // [optional] End Columns
+)
+{
+ HRESULT hr = S_OK;
+ DWORD docnum;
+
+ // We must have a document, offsets, and lines.
+ IfFalseGo(document && offsets && lines, E_INVALIDARG);
+ // Must have some sequence points
+ IfFalseGo(spCount != 0, E_INVALIDARG);
+ // Must have an open method.
+ IfFalseGo(m_openMethodToken != mdMethodDefNil, E_INVALIDARG);
+
+ // Remember that we've loaded the sequence points and
+ // which document they were for.
+ docnum = (DWORD)((SymDocumentWriter *)document)->GetDocumentEntry();;
+
+ // if sets of lines have been inserted out-of-order, remember to sort when emitting
+ if ( m_MethodInfo.m_auxSequencePoints.count() > 0 && m_MethodInfo.m_auxSequencePoints[ m_MethodInfo.m_auxSequencePoints.count()-1 ].Offset() > offsets[0] )
+ m_sortLines = true;
+
+ // Copy the incomming arrays into the internal format.
+
+ for ( UINT32 i = 0; i < spCount; i++)
+ {
+ SequencePoint * paux;
+ IfNullGo(paux = m_MethodInfo.m_auxSequencePoints.next());
+ paux->SetOffset(offsets[i]);
+ paux->SetStartLine(lines[i]);
+ paux->SetStartColumn(columns ? columns[i] : 0);
+ // If no endLines specified, assume same as start
+ paux->SetEndLine(endLines ? endLines[i] : lines[i]);
+ paux->SetEndColumn(endColumns ? endColumns[i]: 0);
+ paux->SetDocument(docnum);
+ }
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// SymWriter OpenScope
+// Open a new scope for this function
+//-----------------------------------------------------------
+COM_METHOD SymWriter::OpenScope(ULONG32 startOffset, ULONG32 *scopeID)
+{
+ HRESULT hr = S_OK;
+
+ // Make sure the startOffset is within the current scope.
+ if ((m_currentScope != k_noScope) &&
+ (unsigned int)startOffset < m_MethodInfo.m_scopes[m_currentScope].StartOffset())
+ return E_INVALIDARG;
+
+ // Fill in the new scope.
+ UINT32 newScope = m_MethodInfo.m_scopes.count();
+
+ // Make sure that adding 1 below won't overflow (although "next" should fail much
+ // sooner if we were anywhere near close enough).
+ if (newScope >= UINT_MAX)
+ return E_UNEXPECTED;
+
+ SymLexicalScope *sc;
+ IfNullGo( sc = m_MethodInfo.m_scopes.next());
+ sc->SetParentScope(m_currentScope); // parent is the current scope.
+ sc->SetStartOffset(startOffset);
+ sc->SetHasChildren(FALSE);
+ sc->SetHasVars(FALSE);
+ sc->SetEndOffset(0);
+
+ // The current scope has a child now.
+ if (m_currentScope != k_noScope)
+ m_MethodInfo.m_scopes[m_currentScope].SetHasChildren(TRUE);
+
+ // The new scope is now the current scope.
+ m_currentScope = newScope;
+ _ASSERTE(m_currentScope != k_noScope);
+
+ // Pass out the "scope id", which is a _1_ based id for the scope.
+ if (scopeID)
+ *scopeID = m_currentScope + 1;
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// SymWriter CloseScope
+//-----------------------------------------------------------
+COM_METHOD SymWriter::CloseScope(
+ ULONG32 endOffset // Closing offset of scope
+)
+{
+ // This API can only be used to close explicit user scopes.
+ // The implicit root scope is only closed internally by CloseMethod.
+ if ((m_currentScope == k_noScope) || (m_MethodInfo.m_scopes[m_currentScope].ParentScope() == k_noScope))
+ return E_FAIL;
+
+ HRESULT hr = CloseScopeInternal(endOffset);
+
+ _ASSERTE(m_currentScope != k_noScope);
+
+ return hr;
+}
+
+//-----------------------------------------------------------
+// CloseScopeInternal
+// Implementation for ISymUnmanagedWriter::CloseScope but can be called even to
+// close the implicit root scope.
+//-----------------------------------------------------------
+COM_METHOD SymWriter::CloseScopeInternal(
+ ULONG32 endOffset // Closing offset of scope
+)
+{
+ _ASSERTE(m_currentScope != k_noScope);
+
+ // Capture the end offset
+ m_MethodInfo.m_scopes[m_currentScope].SetEndOffset(endOffset);
+
+ // The current scope is now the parent scope.
+ m_currentScope = m_MethodInfo.m_scopes[m_currentScope].ParentScope();
+
+ // Update the maximum scope end offset for this method
+ if (endOffset > m_maxScopeEnd)
+ m_maxScopeEnd = endOffset;
+
+ return S_OK;
+}
+
+//-----------------------------------------------------------
+// SymWriter SetScopeRange
+// Set the Start/End Offset for this scope
+//-----------------------------------------------------------
+COM_METHOD SymWriter::SetScopeRange(
+ ULONG32 scopeID, // ID for the scope
+ ULONG32 startOffset, // Start Offset
+ ULONG32 endOffset // End Offset
+)
+{
+ if (scopeID <= 0)
+ return E_INVALIDARG;
+
+ if (scopeID > m_MethodInfo.m_scopes.count() )
+ return E_INVALIDARG;
+
+ // Remember the new start and end offsets. Also remember that the
+ // scopeID is _1_ based!!!
+ SymLexicalScope *sc = &(m_MethodInfo.m_scopes[scopeID - 1]);
+ sc->SetStartOffset(startOffset);
+ sc->SetEndOffset(endOffset);
+
+ // Update the maximum scope end offset for this method
+ if (endOffset > m_maxScopeEnd)
+ m_maxScopeEnd = endOffset;
+
+ return S_OK;
+}
+
+//-----------------------------------------------------------
+// SymWriter DefineLocalVariable
+//-----------------------------------------------------------
+COM_METHOD SymWriter::DefineLocalVariable(
+ const WCHAR *name, // Name of the variable
+ ULONG32 attributes, // Attributes for the var
+ ULONG32 cSig, // Signature for the variable
+ BYTE signature[],
+ ULONG32 addrKind,
+ ULONG32 addr1, ULONG32 addr2, ULONG32 addr3,
+ ULONG32 startOffset, ULONG32 endOffset)
+{
+ HRESULT hr = S_OK;
+ ULONG NameEntry;
+
+ // We must have a current scope.
+ if (m_currentScope == k_noScope)
+ return E_FAIL;
+
+ // We must have a name and a signature.
+ if (!name || !signature)
+ return E_INVALIDARG;
+
+ if (cSig == 0)
+ return E_INVALIDARG;
+
+ // Make a new local variable and copy the data.
+ SymVariable *var;
+ IfNullGo( var = m_MethodInfo.m_vars.next());
+ var->SetIsParam(FALSE);
+ var->SetAttributes(attributes);
+ var->SetAddrKind(addrKind);
+ var->SetIsHidden(attributes & VAR_IS_COMP_GEN);
+ var->SetAddr1(addr1);
+ var->SetAddr2(addr2);
+ var->SetAddr3(addr3);
+
+
+ // Length of the sig?
+ ULONG32 sigLen;
+ sigLen = cSig;
+
+ // stack check needed to call back into utilcode
+ BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD_FORCE_SO();
+ // Copy the name.
+ hr = m_pStringPool->AddStringW(name, (UINT32 *)&NameEntry);
+ END_SO_INTOLERANT_CODE;
+ IfFailGo(hr);
+ var->SetName(NameEntry);
+
+ // Copy the signature
+ // Note that we give this back exactly as-is, but callers typically remove any calling
+ // convention prefix.
+ UINT32 i;
+ IfFalseGo(m_MethodInfo.m_bytes.grab(sigLen, &i), E_OUTOFMEMORY);
+ memcpy(&m_MethodInfo.m_bytes[i], signature, sigLen);
+ var->SetSignature(i);
+ var->SetSignatureSize(sigLen);
+
+ // This var is in the current scope
+ var->SetScope(m_currentScope);
+ m_MethodInfo.m_scopes[m_currentScope].SetHasVars(TRUE);
+
+ var->SetStartOffset(startOffset);
+ var->SetEndOffset(endOffset);
+
+ErrExit:
+ return hr;
+}
+
+COM_METHOD SymWriter::DefineLocalVariable2(
+ const WCHAR *name,
+ ULONG32 attributes,
+ mdSignature sigToken,
+ ULONG32 addrKind,
+ ULONG32 addr1, ULONG32 addr2, ULONG32 addr3,
+ ULONG32 startOffset, ULONG32 endOffset)
+{
+ // This symbol writer doesn't support definiting signatures via tokens
+ _ASSERTE(FALSE);
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// SymWriter DefineParameter
+//-----------------------------------------------------------
+COM_METHOD SymWriter::DefineParameter(
+ const WCHAR *name, // Param name
+ ULONG32 attributes, // Attribute for the parameter
+ ULONG32 sequence,
+ ULONG32 addrKind,
+ ULONG32 addr1, ULONG32 addr2, ULONG32 addr3)
+{
+ HRESULT hr = S_OK;
+ ULONG NameEntry;
+
+ // We must have a method.
+ if (m_openMethodToken == mdMethodDefNil)
+ return E_INVALIDARG;
+
+ // We must have a name.
+ if (!name)
+ return E_INVALIDARG;
+
+ SymVariable *var;
+ IfNullGo( var = m_MethodInfo.m_vars.next());
+ var->SetIsParam(TRUE);
+ var->SetAttributes(attributes);
+ var->SetAddrKind(addrKind);
+ var->SetIsHidden(attributes & VAR_IS_COMP_GEN);
+ var->SetAddr1(addr1);
+ var->SetAddr2(addr2);
+ var->SetAddr3(addr3);
+ var->SetSequence(sequence);
+
+
+ // stack check needed to call back into utilcode
+ BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD_FORCE_SO();
+ // Copy the name.
+ hr = m_pStringPool->AddStringW(name, (UINT32 *)&NameEntry);
+ END_SO_INTOLERANT_CODE;
+ IfFailGo(hr);
+ var->SetName(NameEntry);
+
+ // This var is in the current scope
+ if (m_currentScope != k_noScope)
+ m_MethodInfo.m_scopes[m_currentScope].SetHasVars(TRUE);
+
+ var->SetStartOffset(0);
+ var->SetEndOffset(0);
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// verifyConstTypes
+// Verify that the type is a type we support
+//-----------------------------------------------------------
+static bool verifyConstTypes( DWORD vt )
+{
+ switch ( vt ) {
+ case VT_UI8:
+ case VT_I8:
+ case VT_I4:
+ case VT_UI1: // value < LF_NUMERIC
+ case VT_I2:
+ case VT_R4:
+ case VT_R8:
+ case VT_BOOL: // value < LF_NUMERIC
+ case VT_DATE:
+ case VT_BSTR:
+ case VT_I1:
+ case VT_UI2:
+ case VT_UI4:
+ case VT_INT:
+ case VT_UINT:
+ case VT_DECIMAL:
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------
+// SymWriter DefineConstant
+//-----------------------------------------------------------
+COM_METHOD SymWriter::DefineConstant(
+ const WCHAR __RPC_FAR *name,
+ VARIANT value,
+ ULONG32 cSig,
+ unsigned char __RPC_FAR signature[])
+{
+ HRESULT hr = S_OK;
+ ULONG ValueBstr = 0;
+ ULONG Name;
+
+ // currently we only support local constants
+
+ // We must have a method.
+ if (m_openMethodToken == mdMethodDefNil)
+ return E_INVALIDARG;
+
+ // We must have a name and signature.
+ IfFalseGo(name, E_INVALIDARG);
+ IfFalseGo(signature, E_INVALIDARG);
+ IfFalseGo(cSig > 0, E_INVALIDARG);
+
+ //
+ // Support byref decimal values
+ //
+ if ( (V_VT(&value)) == ( VT_BYREF | VT_DECIMAL ) ) {
+ if ( V_DECIMALREF(&value) == NULL )
+ return E_INVALIDARG;
+ V_DECIMAL(&value) = *V_DECIMALREF(&value);
+ V_VT(&value) = VT_DECIMAL;
+ }
+
+ // we only support non-ref constants
+ if ( ( V_VT(&value) & VT_BYREF ) != 0 )
+ return E_INVALIDARG;
+
+ if ( !verifyConstTypes( V_VT(&value) ) )
+ return E_INVALIDARG;
+
+ // If it's a BSTR, we need to persist the Bstr as an entry into
+ // the stringpool
+ if (V_VT(&value) == VT_BSTR)
+ {
+ // stack check needed to call back into utilcode
+ BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD_FORCE_SO();
+ // Copy the bstrValue.
+ hr = m_pStringPool->AddStringW(V_BSTR(&value), (UINT32 *)&ValueBstr);
+ END_SO_INTOLERANT_CODE;
+ IfFailGo(hr);
+ V_BSTR(&value) = NULL;
+ }
+
+ SymConstant *con;
+ IfNullGo( con = m_MethodInfo.m_constants.next());
+ con->SetValue(value, ValueBstr);
+
+
+ // stack check needed to call back into utilcode
+ BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD_FORCE_SO();
+ // Copy the name.
+ hr = m_pStringPool->AddStringW(name, (UINT32 *)&Name);
+ END_SO_INTOLERANT_CODE;
+ IfFailGo(hr);
+ con->SetName(Name);
+
+ // Copy the signature
+ UINT32 i;
+ IfFalseGo(m_MethodInfo.m_bytes.grab(cSig, &i), E_OUTOFMEMORY);
+ memcpy(&m_MethodInfo.m_bytes[i], signature, cSig);
+ con->SetSignature(i);
+ con->SetSignatureSize(cSig);
+
+ // This const is in the current scope
+ con->SetParentScope(m_currentScope);
+ m_MethodInfo.m_scopes[m_currentScope].SetHasVars(TRUE);
+
+ErrExit:
+ return hr;
+}
+
+COM_METHOD SymWriter::DefineConstant2(
+ const WCHAR *name,
+ VARIANT value,
+ mdSignature sigToken)
+{
+ // This symbol writer doesn't support definiting signatures via tokens
+ _ASSERTE(FALSE);
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// SymWriter Abort
+//-----------------------------------------------------------
+COM_METHOD SymWriter::Abort(void)
+{
+ m_closed = true;
+ return S_OK;
+}
+
+//-----------------------------------------------------------
+// SymWriter DefineField
+//-----------------------------------------------------------
+COM_METHOD SymWriter::DefineField(
+ mdTypeDef parent,
+ const WCHAR *name,
+ ULONG32 attributes,
+ ULONG32 csig,
+ BYTE signature[],
+ ULONG32 addrKind,
+ ULONG32 addr1, ULONG32 addr2, ULONG32 addr3)
+{
+ // This symbol store doesn't support extra random variable
+ // definitions.
+ return S_OK;
+}
+
+//-----------------------------------------------------------
+// SymWriter DefineGlobalVariable
+//-----------------------------------------------------------
+COM_METHOD SymWriter::DefineGlobalVariable(
+ const WCHAR *name,
+ ULONG32 attributes,
+ ULONG32 csig,
+ BYTE signature[],
+ ULONG32 addrKind,
+ ULONG32 addr1, ULONG32 addr2, ULONG32 addr3)
+{
+ // This symbol writer doesn't support global variables
+ _ASSERTE(FALSE);
+ return E_NOTIMPL;
+}
+
+COM_METHOD SymWriter::DefineGlobalVariable2(
+ const WCHAR *name,
+ ULONG32 attributes,
+ mdSignature sigToken,
+ ULONG32 addrKind,
+ ULONG32 addr1, ULONG32 addr2, ULONG32 addr3)
+{
+ // This symbol writer doesn't support global variables
+ _ASSERTE(FALSE);
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// compareMethods
+// Used to sort method entries
+//-----------------------------------------------------------
+int __cdecl SymMethodInfo::compareMethods(const void *elem1, const void *elem2 )
+{
+ SymMethodInfo* p1 = (SymMethodInfo*)elem1;
+ SymMethodInfo* p2 = (SymMethodInfo*)elem2;
+ return p1->MethodToken() - p2->MethodToken();
+}
+
+//-----------------------------------------------------------
+// SymWriter Close
+//-----------------------------------------------------------
+COM_METHOD SymWriter::Close()
+{
+ HRESULT hr = Commit();
+ m_closed = true;
+ for (UINT32 docInfo = 0; docInfo < m_MethodInfo.m_documents.count(); docInfo++)
+ {
+ m_MethodInfo.m_documents[docInfo].SetDocumentWriter(NULL);
+ }
+ return hr;
+}
+
+//-----------------------------------------------------------
+// SymWriter Commit
+//-----------------------------------------------------------
+COM_METHOD SymWriter::Commit(void)
+{
+ // Sort the entries if need be
+ if (m_sortMethodEntries)
+ {
+ // First remap any tokens we need to
+ if (m_MethodMap.count())
+ {
+ unsigned i;
+ for (i = 0; i< m_MethodMap.count(); i++)
+ {
+ m_MethodInfo.m_methods[m_MethodMap[i].MethodEntry].SetMethodToken(m_MethodMap[i].m_MethodToken);
+ }
+ }
+
+ // Now sort the array
+ qsort(&m_MethodInfo.m_methods[0],
+ m_MethodInfo.m_methods.count(),
+ sizeof( SymMethodInfo ),
+ SymMethodInfo::compareMethods );
+ m_sortMethodEntries = false;
+ }
+ return WritePDB();
+}
+
+//-----------------------------------------------------------
+// SymWriter SetSymAttribute
+//-----------------------------------------------------------
+COM_METHOD SymWriter::SetSymAttribute(
+ mdToken parent,
+ const WCHAR *name,
+ ULONG32 cData,
+ BYTE data[])
+{
+ // Setting attributes on the symbol isn't supported
+
+ // ROTORTODO: #156785 in PS
+ return S_OK;
+}
+
+//-----------------------------------------------------------
+// SymWriter OpenNamespace
+//-----------------------------------------------------------
+COM_METHOD SymWriter::OpenNamespace(const WCHAR *name)
+{
+ // This symbol store doesn't support namespaces.
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// SymWriter OpenNamespace
+//-----------------------------------------------------------
+COM_METHOD SymWriter::CloseNamespace()
+{
+ // This symbol store doesn't support namespaces.
+ return S_OK;
+}
+
+//-----------------------------------------------------------
+// SymWriter UsingNamespace
+// Add a Namespace to the list of namespace for this method
+//-----------------------------------------------------------
+COM_METHOD SymWriter::UsingNamespace(const WCHAR *fullName)
+{
+ HRESULT hr = S_OK;
+ ULONG Name;
+
+ // We must have a current scope.
+ if (m_currentScope == k_noScope)
+ return E_FAIL;
+
+ // We must have a name.
+ if (!fullName)
+ return E_INVALIDARG;
+
+
+ SymUsingNamespace *use;
+ IfNullGo( use = m_MethodInfo.m_usings.next());
+
+ // stack check needed to call back into utilcode
+ BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD_FORCE_SO();
+ // Copy the name.
+ hr = m_pStringPool->AddStringW(fullName, (UINT32 *)&Name);
+ END_SO_INTOLERANT_CODE;
+ IfFailGo(hr);
+ use->SetName(Name);
+
+ use->SetParentScope(m_currentScope);
+
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// SymWriter SetMethodSourceRange
+//-----------------------------------------------------------
+COM_METHOD SymWriter::SetMethodSourceRange(
+ ISymUnmanagedDocumentWriter *startDoc,
+ ULONG32 startLine,
+ ULONG32 startColumn,
+ ISymUnmanagedDocumentWriter *endDoc,
+ ULONG32 endLine,
+ ULONG32 endColumn)
+{
+ // This symbol store doesn't support source ranges.
+ return E_NOTIMPL;
+}
+
+//-----------------------------------------------------------
+// UnicodeToUTF8
+// Translate the Unicode string to a UTF8 string
+// Return the length in UTF8 of the Unicode string
+// Including NULL terminator
+//-----------------------------------------------------------
+inline int WINAPI UnicodeToUTF8(
+ LPCWSTR pUni, // Unicode string
+ __out_bcount_opt(cbUTF) PSTR pUTF8, // [optional, out] Buffer for UTF8 string
+ int cbUTF // length of UTF8 buffer
+)
+{
+ // Pass in the length including the NULL terminator
+ int cchSrc = (int)wcslen(pUni)+1;
+ return WideCharToMultiByte(CP_UTF8, 0, pUni, cchSrc, pUTF8, cbUTF, NULL, NULL);
+}
+
+//-----------------------------------------------------------
+// SymWriter GetDebugCVInfo
+// Get the size and potentially the debug info
+//-----------------------------------------------------------
+COM_METHOD SymWriter::GetDebugCVInfo(
+ DWORD cbBuf, // [optional] Size of buf
+ DWORD *pcbBuf, // [out] Size needed for the DebugInfo
+ BYTE buf[]) // [optional, out] Buffer for DebugInfo
+{
+
+ if ( m_szPath == NULL || *m_szPath == 0 )
+ return E_UNEXPECTED;
+
+ // We need to change the .ildb extension to .pdb to be
+ // compatible with VS7
+ wchar_t fullpath[_MAX_PATH];
+ wchar_t drive[_MAX_DRIVE];
+ wchar_t dir[_MAX_DIR];
+ wchar_t fname[_MAX_FNAME];
+ if (_wsplitpath_s( m_szPath, drive, COUNTOF(drive), dir, COUNTOF(dir), fname, COUNTOF(fname), NULL, 0 ))
+ return E_FAIL;
+ if (_wmakepath_s( fullpath, COUNTOF(fullpath), drive, dir, fname, W("pdb") ))
+ return E_FAIL;
+
+ // Get UTF-8 string size, including the Null Terminator
+ int Utf8Length = UnicodeToUTF8( fullpath, NULL, 0 );
+ if (Utf8Length < 0 )
+ return HRESULT_FROM_GetLastError();
+
+ DWORD dwSize = sizeof(RSDSI) + DWORD(Utf8Length);
+
+ // If the caller is just checking for the size
+ if ( cbBuf == 0 && pcbBuf != NULL )
+ {
+ *pcbBuf = dwSize;
+ return S_OK;
+ }
+
+ if (cbBuf < dwSize)
+ {
+ return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+ }
+
+ if ( buf == NULL )
+ {
+ return E_INVALIDARG;
+ }
+
+ RSDSI* pRsdsi = (RSDSI*)buf;
+ pRsdsi->dwSig = VAL32(0x53445352); // "SDSR";
+ pRsdsi->guidSig = ILDB_VERSION_GUID;
+ SwapGuid(&(pRsdsi->guidSig));
+ // Age of 0 represent VC6.0 format so make sure it's 1
+ pRsdsi->age = VAL32(1);
+ UnicodeToUTF8( fullpath, pRsdsi->szPDB, Utf8Length );
+ if ( pcbBuf )
+ *pcbBuf = dwSize;
+ return S_OK;
+}
+
+//-----------------------------------------------------------
+// SymWriter GetDebugInfo
+// Get the size and potentially the debug info
+//-----------------------------------------------------------
+COM_METHOD SymWriter::GetDebugInfo(
+ IMAGE_DEBUG_DIRECTORY *pIDD, // [out] IDD to fill in
+ DWORD cData, // [optional] size of data
+ DWORD *pcData, // [optional, out] return needed size for DebugInfo
+ BYTE data[]) // [optional] Buffer to store into
+{
+ HRESULT hr = S_OK;
+ if ( cData == 0 && pcData != NULL )
+ {
+ // just checking for the size
+ return GetDebugCVInfo( 0, pcData, NULL );
+ }
+
+ if ( pIDD == NULL )
+ return E_INVALIDARG;
+
+ DWORD cTheData = 0;
+ IfFailGo( GetDebugCVInfo( cData, &cTheData, data ) );
+
+ memset( pIDD, 0, sizeof( *pIDD ) );
+ pIDD->Type = VAL32(IMAGE_DEBUG_TYPE_CODEVIEW);
+ pIDD->SizeOfData = VAL32(cTheData);
+
+ if ( pcData ) {
+ *pcData = cTheData;
+ }
+
+ErrExit:
+ return hr;
+}
+
+COM_METHOD SymWriter::RemapToken(mdToken oldToken, mdToken newToken)
+{
+ HRESULT hr = NOERROR;
+ if (oldToken != newToken)
+ {
+ // We only care about methods
+ if ((TypeFromToken(oldToken) == mdtMethodDef) ||
+ (TypeFromToken(newToken) == mdtMethodDef))
+ {
+ // Make sure they are both methods
+ _ASSERTE(TypeFromToken(newToken) == mdtMethodDef);
+ _ASSERTE(TypeFromToken(oldToken) == mdtMethodDef);
+
+ // Make sure we sort before saving
+ m_sortMethodEntries = true;
+
+ // Check to see if we're trying to map a token we know about
+ unsigned i;
+ for (i = 0; i < m_MethodInfo.m_methods.count(); i++)
+ {
+ if (m_MethodInfo.m_methods[i].MethodToken() == oldToken)
+ {
+ // Remember the map, we need to actually do the actual
+ // mapping later because we might already have a function
+ // with a token 'newToken'
+ SymMap *pMethodMap;
+ IfNullGo( pMethodMap = m_MethodMap.next() );
+ pMethodMap->m_MethodToken = newToken;
+ pMethodMap->MethodEntry = i;
+ break;
+ }
+ }
+ }
+ }
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// SymWriter Write
+// Write the information to a file or to a stream
+//-----------------------------------------------------------
+COM_METHOD SymWriter::Write(void *pData, DWORD SizeOfData)
+{
+ HRESULT hr = NOERROR;
+ DWORD NumberOfBytesWritten = 0;
+ if (m_pIStream)
+ {
+ IfFailGo(m_pIStream->Write(pData,
+ SizeOfData,
+ &NumberOfBytesWritten));
+ }
+ else
+ {
+ // Write out a signature to recognize that we're an ildb
+ if (!WriteFile(m_hFile, pData, SizeOfData, &NumberOfBytesWritten, NULL))
+ return HrFromWin32(GetLastError());
+ }
+ _ASSERTE(NumberOfBytesWritten == SizeOfData);
+ErrExit:
+ return hr;
+}
+
+//-----------------------------------------------------------
+// SymWriter WriteStringPool
+// Write the information to a file or to a stream
+//-----------------------------------------------------------
+COM_METHOD SymWriter::WriteStringPool()
+{
+ IStream *pIStream = NULL;
+ BYTE *pStreamMem = NULL;
+
+ HRESULT hr = NOERROR;
+ if (m_pIStream)
+ {
+ IfFailGo(m_pStringPool->PersistToStream(m_pIStream));
+ }
+ else
+ {
+ LARGE_INTEGER disp = { {0, 0} };
+ DWORD NumberOfBytes;
+ DWORD SizeOfData;
+ STATSTG statStg;
+
+ IfFailGo(CreateStreamOnHGlobal(NULL,
+ TRUE,
+ &pIStream));
+
+ IfFailGo(m_pStringPool->PersistToStream(pIStream));
+
+ IfFailGo(pIStream->Stat(&statStg, STATFLAG_NONAME));
+ SizeOfData = statStg.cbSize.u.LowPart;
+
+ IfFailGo(pIStream->Seek(disp, STREAM_SEEK_SET, NULL));
+
+ pStreamMem = NEW(BYTE[SizeOfData]);
+ IfFailGo(pIStream->Read(pStreamMem, SizeOfData, &NumberOfBytes));
+
+ if (!WriteFile(m_hFile, pStreamMem, SizeOfData, &NumberOfBytes, NULL))
+ return HrFromWin32(GetLastError());
+
+ _ASSERTE(NumberOfBytes == SizeOfData);
+
+ }
+ErrExit:
+ RELEASE(pIStream);
+ DELETEARRAY(pStreamMem);
+ return hr;
+}
+
+//-----------------------------------------------------------
+// SymWriter WritePDB
+// Write the PDB information to a file or to a stream
+//-----------------------------------------------------------
+COM_METHOD SymWriter::WritePDB()
+{
+
+ HRESULT hr = NOERROR;
+ GUID ildb_guid = ILDB_VERSION_GUID;
+
+ // Make sure the ModuleLevelInfo is set
+ ModuleLevelInfo.m_CountOfVars = VAL32(m_MethodInfo.m_vars.count());
+ ModuleLevelInfo.m_CountOfBytes = VAL32(m_MethodInfo.m_bytes.count());
+ ModuleLevelInfo.m_CountOfUsing = VAL32(m_MethodInfo.m_usings.count());
+ ModuleLevelInfo.m_CountOfScopes = VAL32(m_MethodInfo.m_scopes.count());
+ ModuleLevelInfo.m_CountOfMethods = VAL32(m_MethodInfo.m_methods.count());
+ if (m_pStringPool)
+ {
+ DWORD dwSaveSize;
+ IfFailGo(m_pStringPool->GetSaveSize((UINT32 *)&dwSaveSize));
+ ModuleLevelInfo.m_CountOfStringBytes = VAL32(dwSaveSize);
+ }
+ else
+ {
+ ModuleLevelInfo.m_CountOfStringBytes = 0;
+ }
+ ModuleLevelInfo.m_CountOfConstants = VAL32(m_MethodInfo.m_constants.count());
+ ModuleLevelInfo.m_CountOfDocuments = VAL32(m_MethodInfo.m_documents.count());
+ ModuleLevelInfo.m_CountOfSequencePoints = VAL32(m_MethodInfo.m_auxSequencePoints.count());
+
+ // Open the file
+ if (m_pIStream == NULL)
+ {
+ // We need to open the output file.
+ m_hFile = WszCreateFile(m_szPath,
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (m_hFile == INVALID_HANDLE_VALUE)
+ {
+ IfFailGo(HrFromWin32(GetLastError()));
+ }
+ }
+ else
+ {
+ // We're writing to a stream. Make sure we're at the beginning
+ // (eg. if this is being called more than once).
+ // Note that technically we should probably call SetSize to truncate the
+ // stream to ensure we don't leave reminants of the previous contents
+ // at the end of the new stream. But with our current CGrowableStream
+ // implementation, this would have a big performance impact (causing us to
+ // do linear growth and lots of reallocations at every write). We only
+ // ever add data to a symbol writer (don't remove anything), and so subsequent
+ // streams should always get larger. Regardless, ILDB supports trailing garbage
+ // without a problem (we used to always have the remainder of a page at the end
+ // of the stream), and so this is not an issue of correctness.
+ LARGE_INTEGER pos0;
+ pos0.QuadPart = 0;
+ IfFailGo(m_pIStream->Seek(pos0, STREAM_SEEK_SET, NULL));
+ }
+
+#if _DEBUG
+ // We need to make sure the Variant entry in the constants is 8 byte
+ // aligned so make sure everything up to the there is aligned correctly
+ if ((ILDB_SIGNATURE_SIZE % 8) ||
+ (sizeof(PDBInfo) % 8) ||
+ (sizeof(GUID) % 8))
+ {
+ _ASSERTE(!"We need to safe the data in an aligned format");
+ }
+#endif
+
+ // Write out a signature to recognize that we're an ildb
+ IfFailGo(Write((void *)ILDB_SIGNATURE, ILDB_SIGNATURE_SIZE));
+ // Write out a guid representing the version
+ SwapGuid(&ildb_guid);
+ IfFailGo(Write((void *)&ildb_guid, sizeof(GUID)));
+
+ // Now we need to write the Project level
+ IfFailGo(Write(&ModuleLevelInfo, sizeof(PDBInfo)));
+
+ // Now we have to write out each array as appropriate
+ IfFailGo(Write(m_MethodInfo.m_constants.m_array, sizeof(SymConstant) * m_MethodInfo.m_constants.count()));
+
+ // These members are all 4 byte aligned
+ IfFailGo(Write(m_MethodInfo.m_methods.m_array, sizeof(SymMethodInfo) * m_MethodInfo.m_methods.count()));
+ IfFailGo(Write(m_MethodInfo.m_scopes.m_array, sizeof(SymLexicalScope) * m_MethodInfo.m_scopes.count()));
+ IfFailGo(Write(m_MethodInfo.m_vars.m_array, sizeof(SymVariable) * m_MethodInfo.m_vars.count()));
+ IfFailGo(Write(m_MethodInfo.m_usings.m_array, sizeof(SymUsingNamespace) * m_MethodInfo.m_usings.count()));
+ IfFailGo(Write(m_MethodInfo.m_auxSequencePoints.m_array, sizeof(SequencePoint) * m_MethodInfo.m_auxSequencePoints.count()));
+ IfFailGo(Write(m_MethodInfo.m_documents.m_array, sizeof(DocumentInfo) * m_MethodInfo.m_documents.count()));
+ IfFailGo(Write(m_MethodInfo.m_bytes.m_array, sizeof(BYTE) * m_MethodInfo.m_bytes.count()));
+ IfFailGo(WriteStringPool());
+
+ErrExit:
+ if (m_hFile)
+ CloseHandle(m_hFile);
+ return hr;
+}
+
+/* ------------------------------------------------------------------------- *
+ * SymDocumentWriter class
+ * ------------------------------------------------------------------------- */
+SymDocumentWriter::SymDocumentWriter(
+ UINT32 DocumentEntry,
+ SymWriter *pEmitter
+) :
+ m_refCount ( 0 ),
+ m_DocumentEntry ( DocumentEntry ),
+ m_pEmitter( pEmitter )
+{
+ _ASSERTE(pEmitter);
+ m_pEmitter->AddRef();
+}
+
+SymDocumentWriter::~SymDocumentWriter()
+{
+ // Note that this must be thread-safe - it may be invoked on the finalizer thread
+ RELEASE(m_pEmitter);
+}
+
+COM_METHOD SymDocumentWriter::QueryInterface(REFIID riid, void **ppInterface)
+{
+ if (ppInterface == NULL)
+ return E_INVALIDARG;
+
+ if (riid == IID_ISymUnmanagedDocumentWriter)
+ *ppInterface = (ISymUnmanagedDocumentWriter*)this;
+ else if (riid == IID_IUnknown)
+ *ppInterface = (IUnknown*)(ISymUnmanagedDocumentWriter*)this;
+ else
+ {
+ *ppInterface = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+//-----------------------------------------------------------
+// SymDocumentWriter SetSource
+//-----------------------------------------------------------
+COM_METHOD SymDocumentWriter::SetSource(ULONG32 sourceSize,
+ BYTE source[])
+{
+ return m_pEmitter->SetDocumentSrc(m_DocumentEntry, sourceSize, source);
+}
+
+//-----------------------------------------------------------
+// SymDocumentWriter SetCheckSum
+//-----------------------------------------------------------
+COM_METHOD SymDocumentWriter::SetCheckSum(GUID algorithmId,
+ ULONG32 checkSumSize,
+ BYTE checkSum[])
+{
+ return m_pEmitter->SetDocumentCheckSum(m_DocumentEntry, algorithmId, checkSumSize, checkSum);
+}
+
+
+//-----------------------------------------------------------
+// DocumentInfo SetDocumentWriter
+//-----------------------------------------------------------
+// Set the pointer to the SymDocumentWriter instance corresponding to this instance of DocumentInfo
+// An argument of NULL will call Release
+// Arguments
+// input: pDoc - pointer to the associated SymDocumentWriter or NULL
+
+void DocumentInfo::SetDocumentWriter(SymDocumentWriter * pDoc)
+{
+ if (m_pDocumentWriter != NULL)
+ {
+ m_pDocumentWriter->Release();
+ }
+ m_pDocumentWriter = pDoc;
+ if (m_pDocumentWriter != NULL)
+ {
+ pDoc->AddRef();
+ }
+}
diff --git a/src/debug/ildbsymlib/symwrite.h b/src/debug/ildbsymlib/symwrite.h
new file mode 100644
index 0000000000..055b8ec21f
--- /dev/null
+++ b/src/debug/ildbsymlib/symwrite.h
@@ -0,0 +1,1226 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ===========================================================================
+// File: SymWrite.h
+//
+
+// ===========================================================================
+
+#ifndef SYMWRITE_H_
+#define SYMWRITE_H_
+#ifdef _MSC_VER
+#pragma warning(disable:4786)
+#endif
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cor.h"
+#include "umisc.h"
+#include "stgpool.h"
+#include "safemath.h"
+
+#include <corsym.h>
+#include "pdbdata.h"
+
+class SymDocumentWriter;
+
+#if BIGENDIAN
+/***
+*PUBLIC void VariantSwap
+*Purpose:
+* Swap the Variant members
+*
+*Entry:
+* SrcInBigEndian = whether pvarg is in BIGENDIAN or not
+* pvargDest = Destination variant
+* pvarg = pointer to a VARIANT to swap
+*
+*Exit:
+* Filled in pvarDest
+*
+***********************************************************************/
+inline HRESULT VariantSwap(bool SrcInBigEndian, VARIANT FAR *pvargDest, VARIANT FAR* pvarg)
+{
+ if (pvargDest == NULL || pvarg == NULL)
+ return E_INVALIDARG;
+ VARTYPE vt = VT_EMPTY;
+
+ if (SrcInBigEndian)
+ {
+ vt = V_VT(pvarg);
+ }
+ *(UINT32*)pvargDest = VAL32(*(UINT32*)pvarg);
+ if (!SrcInBigEndian)
+ {
+ vt = V_VT(pvargDest);
+ }
+
+ switch (vt)
+ {
+ case VT_EMPTY:
+ case VT_NULL:
+ // No Value to swap
+ break;
+
+ // 1 byte
+ case VT_I1:
+ case VT_UI1:
+ V_I1(pvargDest) = V_I1(pvarg);
+ break;
+
+ // 2 bytes
+ case VT_I2:
+ case VT_UI2:
+ case VT_INT:
+ case VT_UINT:
+ case VT_BOOL:
+ V_I2(pvargDest) = VAL16(V_I2(pvarg));
+ break;
+
+ // 4 bytes
+ case VT_I4:
+ case VT_UI4:
+ case VT_R4:
+ V_I4(pvargDest) = VAL32(V_I4(pvarg));
+ break;
+
+ // 8 bytes
+ case VT_I8:
+ case VT_UI8:
+ case VT_R8:
+ case VT_DATE:
+ V_I8(pvargDest) = VAL64(V_I8(pvarg));
+ break;
+
+ case VT_DECIMAL:
+ DECIMAL_HI32(V_DECIMAL(pvargDest)) = VAL32(DECIMAL_HI32(V_DECIMAL(pvarg)));
+ DECIMAL_LO32(V_DECIMAL(pvargDest)) = VAL32(DECIMAL_LO32(V_DECIMAL(pvarg)));
+ DECIMAL_MID32(V_DECIMAL(pvargDest)) = VAL32(DECIMAL_MID32(V_DECIMAL(pvarg)));
+ break;
+
+ // These aren't currently supported
+ case VT_CY: //6
+ case VT_BSTR: //8
+ case VT_DISPATCH: //9
+ case VT_ERROR: //10
+ case VT_VARIANT: //12
+ case VT_UNKNOWN: //13
+ case VT_VOID: //24
+ case VT_HRESULT: //25
+ case VT_PTR: //26
+ case VT_SAFEARRAY: //27
+ case VT_CARRAY: //28
+ case VT_USERDEFINED://29
+ case VT_LPSTR: //30
+ case VT_LPWSTR: //31
+ case VT_FILETIME: //64
+ case VT_BLOB: //65
+ case VT_STREAM: //66
+ case VT_STORAGE: //67
+ case VT_STREAMED_OBJECT: //68
+ case VT_STORED_OBJECT: //69
+ case VT_BLOB_OBJECT: //70
+ case VT_CF: //71
+ case VT_CLSID: //72
+ default:
+ _ASSERTE(!"NYI");
+ break;
+ }
+ return NOERROR;
+}
+#endif // BIGENDIAN
+
+// Default space sizes for the various arrays. Make it too small in a
+// checked build so we exercise the growing code.
+#ifdef _DEBUG
+#define DEF_LOCAL_SPACE 2
+#define DEF_MISC_SPACE 64
+#else
+#define DEF_LOCAL_SPACE 64
+#define DEF_MISC_SPACE 1024
+#endif
+
+/* ------------------------------------------------------------------------- *
+ * SymVariable struct
+ * ------------------------------------------------------------------------- */
+struct SymVariable
+{
+private:
+ UINT32 m_Scope; // index of parent scope
+ UINT32 m_Name; // index into misc byte array
+ ULONG32 m_Attributes; // Attributes
+ UINT32 m_Signature; // index into misc byte array
+ ULONG32 m_SignatureSize; // Signature size
+ ULONG32 m_AddrKind; // Address Kind
+ ULONG32 m_Addr1; // Additional info
+ ULONG32 m_Addr2;
+ ULONG32 m_Addr3;
+ ULONG32 m_StartOffset; // StartOffset
+ ULONG32 m_EndOffset; // EndOffset
+ ULONG32 m_Sequence;
+ BOOL m_IsParam; // parameter?
+ BOOL m_IsHidden; // Is not visible to the user
+
+public:
+ UINT32 Scope()
+ {
+ return VAL32(m_Scope);
+ }
+ void SetScope(UINT32 Scope)
+ {
+ m_Scope = VAL32(Scope);
+ }
+
+ UINT32 Name()
+ {
+ return VAL32(m_Name);
+ }
+ void SetName(UINT32 Name)
+ {
+ m_Name = VAL32(Name);
+ }
+
+ ULONG32 Attributes()
+ {
+ return VAL32(m_Attributes);
+ }
+ void SetAttributes(ULONG32 Attributes)
+ {
+ m_Attributes = VAL32(Attributes);
+ }
+
+ UINT32 Signature()
+ {
+ return VAL32(m_Signature);
+ }
+ void SetSignature(UINT32 Signature)
+ {
+ m_Signature = VAL32(Signature);
+ }
+ ULONG32 SignatureSize()
+ {
+ return VAL32(m_SignatureSize);
+ }
+ void SetSignatureSize(ULONG32 SignatureSize)
+ {
+ m_SignatureSize = VAL32(SignatureSize);
+ }
+
+ ULONG32 AddrKind()
+ {
+ return VAL32(m_AddrKind);
+ }
+ void SetAddrKind(ULONG32 AddrKind)
+ {
+ m_AddrKind = VAL32(AddrKind);
+ }
+ ULONG32 Addr1()
+ {
+ return VAL32(m_Addr1);
+ }
+ void SetAddr1(ULONG32 Addr1)
+ {
+ m_Addr1 = VAL32(Addr1);
+ }
+
+ ULONG32 Addr2()
+ {
+ return VAL32(m_Addr2);
+ }
+ void SetAddr2(ULONG32 Addr2)
+ {
+ m_Addr2 = VAL32(Addr2);
+ }
+
+ ULONG32 Addr3()
+ {
+ return VAL32(m_Addr3);
+ }
+ void SetAddr3(ULONG32 Addr3)
+ {
+ m_Addr3 = VAL32(Addr3);
+ }
+
+ ULONG32 StartOffset()
+ {
+ return VAL32(m_StartOffset);
+ }
+ void SetStartOffset(ULONG32 StartOffset)
+ {
+ m_StartOffset = VAL32(StartOffset);
+ }
+ ULONG32 EndOffset()
+ {
+ return VAL32(m_EndOffset);
+ }
+ void SetEndOffset(ULONG EndOffset)
+ {
+ m_EndOffset = VAL32(EndOffset);
+ }
+ ULONG32 Sequence()
+ {
+ return VAL32(m_Sequence);
+ }
+ void SetSequence(ULONG32 Sequence)
+ {
+ m_Sequence = VAL32(Sequence);
+ }
+
+ BOOL IsParam()
+ {
+ return VAL32(m_IsParam);
+ }
+ void SetIsParam(BOOL IsParam)
+ {
+ m_IsParam = IsParam;
+ }
+ BOOL IsHidden()
+ {
+ return VAL32(m_IsHidden);
+ }
+ void SetIsHidden(BOOL IsHidden)
+ {
+ m_IsHidden = IsHidden;
+ }
+};
+
+/* ------------------------------------------------------------------------- *
+ * SymLexicalScope struct
+ * ------------------------------------------------------------------------- */
+struct SymLexicalScope
+{
+private:
+
+ UINT32 m_ParentScope; // parent index (-1 for no parent)
+ ULONG32 m_StartOffset; // start offset
+ ULONG32 m_EndOffset; // end offset
+ BOOL m_HasChildren; // scope has children
+ BOOL m_HasVars; // scope has vars?
+public:
+ UINT32 ParentScope()
+ {
+ return VAL32(m_ParentScope);
+ }
+ void SetParentScope(UINT32 ParentScope)
+ {
+ m_ParentScope = VAL32(ParentScope);
+ }
+
+ ULONG32 StartOffset()
+ {
+ return VAL32(m_StartOffset);
+ }
+ void SetStartOffset(ULONG32 StartOffset)
+ {
+ m_StartOffset = VAL32(StartOffset);
+ }
+ ULONG32 EndOffset()
+ {
+ return VAL32(m_EndOffset);
+ }
+ void SetEndOffset(ULONG32 EndOffset)
+ {
+ m_EndOffset = VAL32(EndOffset);
+ }
+ BOOL HasChildren()
+ {
+ return m_HasChildren;
+ }
+ void SetHasChildren(BOOL HasChildren)
+ {
+ m_HasChildren = HasChildren;
+ }
+ BOOL HasVars()
+ {
+ return m_HasVars;
+ }
+ void SetHasVars(BOOL HasVars)
+ {
+ m_HasVars = HasVars;
+ }
+
+};
+
+/* ------------------------------------------------------------------------- *
+ * SymUsingNamespace struct
+ * ------------------------------------------------------------------------- */
+struct SymUsingNamespace
+{
+private:
+
+ UINT32 m_ParentScope; // index of parent scope
+ UINT32 m_Name; // Index of name
+public:
+ UINT32 ParentScope()
+ {
+ return VAL32(m_ParentScope);
+ }
+ void SetParentScope(UINT32 ParentScope)
+ {
+ m_ParentScope = VAL32(ParentScope);
+ }
+ UINT32 Name()
+ {
+ return VAL32(m_Name);
+ }
+ void SetName(UINT32 Name)
+ {
+ m_Name = VAL32(Name);
+ }
+};
+
+/* ------------------------------------------------------------------------- *
+ * SymConstant struct
+ * ------------------------------------------------------------------------- */
+struct SymConstant
+{
+private:
+
+ VARIANT m_Value; // Constant Value
+ UINT32 m_ParentScope; // Parent scope
+ UINT32 m_Name; // Name index
+ UINT32 m_Signature; // Signature index
+ ULONG32 m_SignatureSize;// Signature size
+ UINT32 m_ValueBstr; // If the variant is a bstr, store the string
+
+public:
+ UINT32 ParentScope()
+ {
+ return VAL32(m_ParentScope);
+ }
+ void SetParentScope(UINT32 ParentScope)
+ {
+ m_ParentScope = VAL32(ParentScope);
+ }
+ UINT32 Name()
+ {
+ return VAL32(m_Name);
+ }
+ void SetName(UINT32 Name)
+ {
+ m_Name = VAL32(Name);
+ }
+ UINT32 Signature()
+ {
+ return VAL32(m_Signature);
+ }
+ void SetSignature(UINT32 Signature)
+ {
+ m_Signature = VAL32(Signature);
+ }
+ ULONG32 SignatureSize()
+ {
+ return VAL32(m_SignatureSize);
+ }
+ void SetSignatureSize(ULONG32 SignatureSize)
+ {
+ m_SignatureSize = VAL32(SignatureSize);
+ }
+ VARIANT Value(UINT32 *pValueBstr)
+ {
+ *pValueBstr = VAL32(m_ValueBstr);
+#if BIGENDIAN
+ VARIANT VariantValue;
+ VariantInit(&VariantValue);
+ // VT_BSTR's are dealt with ValueBStr
+ if (m_ValueBstr)
+ {
+ V_VT(&VariantValue) = VT_BSTR;
+ }
+ else
+ {
+ VariantSwap(false, &VariantValue, &m_Value);
+ }
+ return VariantValue;
+#else
+ return m_Value;
+#endif
+ }
+ void SetValue(VARIANT VariantValue, UINT32 ValueBstr)
+ {
+ m_Value = VariantValue;
+ m_ValueBstr = VAL32(ValueBstr);
+#if BIGENDIAN
+ // VT_BSTR's are dealt with ValueBStr
+ if (m_ValueBstr)
+ {
+ V_VT(&m_Value) = VAL16(VT_BSTR);
+ }
+ else
+ {
+ VariantSwap(true, &m_Value, &VariantValue);
+ }
+#endif
+ }
+};
+
+/* ------------------------------------------------------------------------- *
+ * SymMethodInfo struct
+ * ------------------------------------------------------------------------- */
+struct SymMethodInfo
+{
+private:
+
+ mdMethodDef m_MethodToken; // Method token
+
+ // Start/End Entries into the respective tables
+ // End values are extents - one past the last index (and so may actually be an index off
+ // the end of the array). Start may equal end if the method has none of the item.
+ UINT32 m_StartScopes;
+ UINT32 m_EndScopes;
+ UINT32 m_StartVars;
+ UINT32 m_EndVars;
+ UINT32 m_StartUsing;
+ UINT32 m_EndUsing;
+ UINT32 m_StartConstant;
+ UINT32 m_EndConstant;
+ UINT32 m_StartDocuments;
+ UINT32 m_EndDocuments;
+ UINT32 m_StartSequencePoints;
+ UINT32 m_EndSequencePoints;
+
+public:
+ static int __cdecl compareMethods(const void *elem1, const void *elem2 );
+
+ mdMethodDef MethodToken()
+ {
+ return VAL32(m_MethodToken);
+ }
+ void SetMethodToken(mdMethodDef MethodToken)
+ {
+ m_MethodToken = VAL32(MethodToken);
+ }
+ UINT32 StartScopes()
+ {
+ return VAL32(m_StartScopes);
+ }
+ void SetStartScopes(UINT32 StartScopes)
+ {
+ m_StartScopes = VAL32(StartScopes);
+ }
+ UINT32 EndScopes()
+ {
+ return VAL32(m_EndScopes);
+ }
+ void SetEndScopes(UINT32 EndScopes)
+ {
+ m_EndScopes = VAL32(EndScopes);
+ }
+ UINT32 StartVars()
+ {
+ return VAL32(m_StartVars);
+ }
+ void SetStartVars(UINT32 StartVars)
+ {
+ m_StartVars = VAL32(StartVars);
+ }
+ UINT32 EndVars()
+ {
+ return VAL32(m_EndVars);
+ }
+ void SetEndVars(UINT32 EndVars)
+ {
+ m_EndVars = VAL32(EndVars);
+ }
+ UINT32 StartUsing()
+ {
+ return VAL32(m_StartUsing);
+ }
+ void SetStartUsing(UINT32 StartUsing)
+ {
+ m_StartUsing = VAL32(StartUsing);
+ }
+ UINT32 EndUsing()
+ {
+ return VAL32(m_EndUsing);
+ }
+ void SetEndUsing(UINT32 EndUsing)
+ {
+ m_EndUsing = VAL32(EndUsing);
+ }
+ UINT32 StartConstant()
+ {
+ return VAL32(m_StartConstant);
+ }
+ void SetStartConstant(UINT32 StartConstant)
+ {
+ m_StartConstant = VAL32(StartConstant);
+ }
+ UINT32 EndConstant()
+ {
+ return VAL32(m_EndConstant);
+ }
+ void SetEndConstant(UINT32 EndConstant)
+ {
+ m_EndConstant = VAL32(EndConstant);
+ }
+ UINT32 StartDocuments()
+ {
+ return VAL32(m_StartDocuments);
+ }
+ void SetStartDocuments(UINT32 StartDocuments)
+ {
+ m_StartDocuments = VAL32(StartDocuments);
+ }
+ UINT32 EndDocuments()
+ {
+ return VAL32(m_EndDocuments);
+ }
+ void SetEndDocuments(UINT32 EndDocuments)
+ {
+ m_EndDocuments = VAL32(EndDocuments);
+ }
+ UINT32 StartSequencePoints()
+ {
+ return VAL32(m_StartSequencePoints);
+ }
+ void SetStartSequencePoints(UINT32 StartSequencePoints)
+ {
+ m_StartSequencePoints = VAL32(StartSequencePoints);
+ }
+ UINT32 EndSequencePoints()
+ {
+ return VAL32(m_EndSequencePoints);
+ }
+ void SetEndSequencePoints(UINT32 EndSequencePoints)
+ {
+ m_EndSequencePoints = VAL32(EndSequencePoints);
+ }
+};
+
+/* ------------------------------------------------------------------------- *
+ * SymMap struct
+ * ------------------------------------------------------------------------- */
+struct SymMap
+{
+ mdMethodDef m_MethodToken; // New Method token
+ UINT32 MethodEntry; // Method Entry
+};
+
+/* ------------------------------------------------------------------------- *
+ * SequencePoint struct
+ * ------------------------------------------------------------------------- */
+struct SequencePoint {
+
+private:
+
+ DWORD m_Offset;
+ DWORD m_StartLine;
+ DWORD m_StartColumn;
+ DWORD m_EndLine;
+ DWORD m_EndColumn;
+ DWORD m_Document;
+
+public:
+ bool IsWithin(ULONG32 line, ULONG32 column);
+ bool IsWithinLineOnly(ULONG32 line);
+ bool IsGreaterThan(ULONG32 line, ULONG32 column);
+ bool IsLessThan(ULONG32 line, ULONG32 column);
+ bool IsUserLine();
+ static int __cdecl compareAuxLines(const void *elem1, const void *elem2 );
+
+ DWORD Offset()
+ {
+ return VAL32(m_Offset);
+ }
+ void SetOffset(DWORD Offset)
+ {
+ m_Offset = VAL32(Offset);
+ }
+ DWORD StartLine()
+ {
+ return VAL32(m_StartLine);
+ }
+ void SetStartLine(DWORD StartLine)
+ {
+ m_StartLine = VAL32(StartLine);
+ }
+
+ DWORD StartColumn()
+ {
+ return VAL32(m_StartColumn);
+ }
+ void SetStartColumn(DWORD StartColumn)
+ {
+ m_StartColumn = VAL32(StartColumn);
+ }
+
+ DWORD EndLine()
+ {
+ return VAL32(m_EndLine);
+ }
+ void SetEndLine(DWORD EndLine)
+ {
+ m_EndLine = VAL32(EndLine);
+ }
+ DWORD EndColumn()
+ {
+ return VAL32(m_EndColumn);
+ }
+ void SetEndColumn(DWORD EndColumn)
+ {
+ m_EndColumn = VAL32(EndColumn);
+ }
+ DWORD Document()
+ {
+ return VAL32(m_Document);
+ }
+ void SetDocument(DWORD Document)
+ {
+ m_Document = VAL32(Document);
+ }
+};
+
+
+/* ------------------------------------------------------------------------- *
+ * DocumentInfo struct
+ * ------------------------------------------------------------------------- */
+typedef struct DocumentInfo {
+
+private:
+
+ GUID m_Language;
+ GUID m_LanguageVendor;
+ GUID m_DocumentType;
+ GUID m_AlgorithmId;
+ DWORD m_CheckSumSize;
+ UINT32 m_CheckSumEntry;
+ UINT32 m_SourceSize;
+ UINT32 m_SourceEntry;
+ UINT32 m_UrlEntry;
+ SymDocumentWriter * m_pDocumentWriter;
+
+public:
+
+ GUID Language()
+ {
+ GUID TmpGuid = m_Language;
+ SwapGuid(&TmpGuid);
+ return TmpGuid;
+ }
+ void SetLanguage(GUID Language)
+ {
+ SwapGuid(&Language);
+ m_Language = Language;
+ }
+ GUID LanguageVendor()
+ {
+ GUID TmpGuid = m_LanguageVendor;
+ SwapGuid(&TmpGuid);
+ return TmpGuid;
+ }
+ void SetLanguageVendor(GUID LanguageVendor)
+ {
+ SwapGuid(&LanguageVendor);
+ m_LanguageVendor = LanguageVendor;
+ }
+ GUID DocumentType()
+ {
+ GUID TmpGuid = m_DocumentType;
+ SwapGuid(&TmpGuid);
+ return TmpGuid;
+ }
+ void SetDocumentType(GUID DocumentType)
+ {
+ SwapGuid(&DocumentType);
+ m_DocumentType = DocumentType;
+ }
+
+ // Set the pointer to the SymDocumentWriter instance corresponding to this instance of DocumentInfo
+ // An argument of NULL will call Release
+ void SetDocumentWriter(SymDocumentWriter * pDoc);
+
+ // get the associated SymDocumentWriter
+ SymDocumentWriter * DocumentWriter()
+ {
+ return m_pDocumentWriter;
+ }
+
+ GUID AlgorithmId()
+ {
+ GUID TmpGuid = m_AlgorithmId;
+ SwapGuid(&TmpGuid);
+ return TmpGuid;
+ }
+ void SetAlgorithmId(GUID AlgorithmId)
+ {
+ SwapGuid(&AlgorithmId);
+ m_AlgorithmId = AlgorithmId;
+ }
+
+ DWORD CheckSumSize()
+ {
+ return VAL32(m_CheckSumSize);
+ }
+ void SetCheckSymSize(DWORD CheckSumSize)
+ {
+ m_CheckSumSize = VAL32(CheckSumSize);
+ }
+ UINT32 CheckSumEntry()
+ {
+ return VAL32(m_CheckSumEntry);
+ }
+ void SetCheckSumEntry(UINT32 CheckSumEntry)
+ {
+ m_CheckSumEntry = VAL32(CheckSumEntry);
+ }
+ UINT32 SourceSize()
+ {
+ return VAL32(m_SourceSize);
+ }
+ void SetSourceSize(UINT32 SourceSize)
+ {
+ m_SourceSize = VAL32(SourceSize);
+ }
+ UINT32 SourceEntry()
+ {
+ return VAL32(m_SourceEntry);
+ }
+ void SetSourceEntry(UINT32 SourceEntry)
+ {
+ m_SourceEntry = VAL32(SourceEntry);
+ }
+ UINT32 UrlEntry()
+ {
+ return VAL32(m_UrlEntry);
+ }
+ void SetUrlEntry(UINT32 UrlEntry)
+ {
+ m_UrlEntry = VAL32(UrlEntry);
+ }
+
+} DocumentInfo;
+
+template <class T>
+class ArrayStorage
+{
+public:
+
+ ArrayStorage( int initialSize = 0 )
+ : m_spaceSize(0), m_instanceCount( 0 ), m_array( NULL )
+ {
+ grow( initialSize );
+ }
+ ~ArrayStorage()
+ {
+
+ if ( m_array )
+ DELETEARRAY(m_array);
+ m_array = NULL;
+ m_spaceSize = 0;
+ m_instanceCount = 0;
+ }
+ T* next()
+ {
+ if( !grow ( m_instanceCount ) )
+ return NULL;
+ _ASSERTE( m_instanceCount < m_spaceSize );
+ return &m_array[ m_instanceCount++ ];
+ }
+ bool grab(UINT32 n, UINT32 * pIndex)
+ {
+ S_UINT32 newSize = S_UINT32(m_instanceCount) + S_UINT32(n);
+ if (newSize.IsOverflow())
+ return false;
+ if (!grow(newSize.Value()))
+ return false;
+ _ASSERTE( m_instanceCount < m_spaceSize );
+ *pIndex = m_instanceCount;
+ m_instanceCount += n;
+ return true;
+ }
+
+ T& operator[]( UINT32 i ) {
+ _ASSERTE( i < m_instanceCount );
+ if (i >= m_instanceCount)
+ {
+ // Help mitigate the impact of buffer overflow
+ // Fail fast with a null-reference AV
+ return *(static_cast<T*>(0)) ;
+ }
+ return m_array[ i ];
+ }
+ void reset() {
+ m_instanceCount = 0;
+ }
+ UINT32 size() {
+ return m_spaceSize;
+ }
+ UINT32 count() {
+ return m_instanceCount;
+ }
+
+ UINT32 m_spaceSize; // Total size of array in elements
+ UINT32 m_instanceCount; // total T's in the file
+ T *m_array; // array of T's
+private:
+ bool grow( UINT32 n )
+ {
+ if (n >= m_spaceSize)
+ {
+ // Make a new, bigger array.
+ UINT32 newSpaceSize;
+
+ if (n == 0)
+ newSpaceSize = DEF_LOCAL_SPACE;
+ else
+ newSpaceSize = max( m_spaceSize * 2, n);
+
+ // Make sure we're not asking for more than 4GB of bytes to ensure no integer-overflow attacks are possible
+ S_UINT32 newBytes = S_UINT32(newSpaceSize) * S_UINT32(sizeof(T));
+ if (newBytes.IsOverflow())
+ return false;
+
+ T *newTs;
+ newTs = NEW(T[newSpaceSize]);
+ if ( newTs == NULL )
+ return false;
+
+ // Copy over the old Ts.
+ memcpy(newTs, m_array,
+ sizeof(T) * m_spaceSize);
+
+ // Delete the old Ts.
+ DELETEARRAY(m_array);
+
+ // Hang onto the new array.
+ m_array = newTs;
+ m_spaceSize = newSpaceSize;
+ }
+ return true;
+ }
+
+};
+
+typedef struct MethodInfo {
+
+ ArrayStorage<SymMethodInfo> m_methods; // Methods information
+ ArrayStorage<SymLexicalScope> m_scopes; // Scope information for the method
+ ArrayStorage<SymVariable> m_vars; // Variables
+ ArrayStorage<SymUsingNamespace> m_usings; // using/imports
+ ArrayStorage<SymConstant> m_constants; // Constants
+ ArrayStorage<DocumentInfo> m_documents; // Document Source Format
+ ArrayStorage<SequencePoint> m_auxSequencePoints; // Sequence Points
+ // Array of various bytes (variable signature, etc)
+ ArrayStorage<BYTE> m_bytes;
+
+
+public:
+
+ MethodInfo() :
+ m_bytes( DEF_MISC_SPACE )
+ {
+ }
+} MethodInfo;
+
+/* ------------------------------------------------------------------------- *
+ * SymWriter class
+ * ------------------------------------------------------------------------- */
+
+class SymWriter : public ISymUnmanagedWriter3
+{
+public:
+ SymWriter();
+ virtual ~SymWriter();
+
+ //-----------------------------------------------------------
+ // IUnknown support
+ //-----------------------------------------------------------
+ ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return (InterlockedIncrement((LONG *) &m_refCount));
+ }
+
+ ULONG STDMETHODCALLTYPE Release()
+ {
+ // Note that this must be thread-safe - it may be invoked on the finalizer thread
+ LONG refCount = InterlockedDecrement((LONG *) &m_refCount);
+ if (refCount == 0)
+ DELETE(this);
+
+ return (refCount);
+ }
+ COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
+
+ //-----------------------------------------------------------
+ // ISymUnmanagedWriter
+ //-----------------------------------------------------------
+ COM_METHOD DefineDocument(const WCHAR *url,
+ const GUID *language,
+ const GUID *languageVendor,
+ const GUID *documentType,
+ ISymUnmanagedDocumentWriter **pRetVal);
+ COM_METHOD SetUserEntryPoint(mdMethodDef entryMethod);
+ COM_METHOD OpenMethod(mdMethodDef method);
+ COM_METHOD CloseMethod();
+ COM_METHOD DefineSequencePoints(ISymUnmanagedDocumentWriter *document,
+ ULONG32 spCount,
+ ULONG32 offsets[],
+ ULONG32 lines[],
+ ULONG32 columns[],
+ ULONG32 endLines[],
+ ULONG32 encColumns[]);
+ COM_METHOD OpenScope(ULONG32 startOffset, ULONG32 *scopeID);
+ COM_METHOD CloseScope(ULONG32 endOffset);
+ COM_METHOD SetScopeRange(ULONG32 scopeID, ULONG32 startOffset, ULONG32 endOffset);
+ COM_METHOD DefineLocalVariable(const WCHAR *name,
+ ULONG32 attributes,
+ ULONG32 cSig,
+ BYTE signature[],
+ ULONG32 addrKind,
+ ULONG32 addr1, ULONG32 addr2, ULONG32 addr3,
+ ULONG32 startOffset, ULONG32 endOffset);
+ COM_METHOD DefineParameter(const WCHAR *name,
+ ULONG32 attributes,
+ ULONG32 sequence,
+ ULONG32 addrKind,
+ ULONG32 addr1, ULONG32 addr2, ULONG32 addr3);
+ COM_METHOD DefineField(mdTypeDef parent,
+ const WCHAR *name,
+ ULONG32 attributes,
+ ULONG32 cSig,
+ BYTE signature[],
+ ULONG32 addrKind,
+ ULONG32 addr1, ULONG32 addr2, ULONG32 addr3);
+ COM_METHOD DefineGlobalVariable(const WCHAR *name,
+ ULONG32 attributes,
+ ULONG32 cSig,
+ BYTE signature[],
+ ULONG32 addrKind,
+ ULONG32 addr1, ULONG32 addr2, ULONG32 addr3);
+ COM_METHOD Close();
+ COM_METHOD SetSymAttribute(mdToken parent,
+ const WCHAR *name,
+ ULONG32 cData,
+ BYTE data[]);
+ COM_METHOD OpenNamespace(const WCHAR *name);
+ COM_METHOD CloseNamespace();
+ COM_METHOD UsingNamespace(const WCHAR *fullName);
+ COM_METHOD SetMethodSourceRange(ISymUnmanagedDocumentWriter *startDoc,
+ ULONG32 startLine,
+ ULONG32 startColumn,
+ ISymUnmanagedDocumentWriter *endDoc,
+ ULONG32 endLine,
+ ULONG32 endColumn);
+ COM_METHOD GetDebugCVInfo(DWORD cData,
+ DWORD *pcData,
+ BYTE data[]);
+
+ COM_METHOD Initialize(IUnknown *emitter,
+ const WCHAR *filename,
+ IStream *pIStream,
+ BOOL fFullBuild);
+
+ COM_METHOD Initialize2(IUnknown *emitter,
+ const WCHAR *pdbTempPath, // location to write pdb file
+ IStream *pIStream,
+ BOOL fFullBuild,
+ const WCHAR *pdbFinalPath); // location exe should contain for pdb file
+
+ COM_METHOD GetDebugInfo(IMAGE_DEBUG_DIRECTORY *pIDD,
+ DWORD cData,
+ DWORD *pcData,
+ BYTE data[]);
+
+ COM_METHOD RemapToken(mdToken oldToken,
+ mdToken newToken);
+
+ COM_METHOD DefineConstant(const WCHAR __RPC_FAR *name,
+ VARIANT value,
+ ULONG32 cSig,
+ unsigned char __RPC_FAR signature[ ]);
+
+ COM_METHOD Abort(void);
+
+ //-----------------------------------------------------------
+ // ISymUnmanagedWriter2
+ //-----------------------------------------------------------
+ COM_METHOD DefineLocalVariable2(const WCHAR *name,
+ ULONG32 attributes,
+ mdSignature sigToken,
+ ULONG32 addrKind,
+ ULONG32 addr1,
+ ULONG32 addr2,
+ ULONG32 addr3,
+ ULONG32 startOffset,
+ ULONG32 endOffset);
+
+ COM_METHOD DefineGlobalVariable2(const WCHAR *name,
+ ULONG32 attributes,
+ mdSignature sigToken,
+ ULONG32 addrKind,
+ ULONG32 addr1,
+ ULONG32 addr2,
+ ULONG32 addr3);
+
+ COM_METHOD DefineConstant2(const WCHAR *name,
+ VARIANT value,
+ mdSignature sigToken);
+
+ //-----------------------------------------------------------
+ // ISymUnmanagedWriter3
+ //-----------------------------------------------------------
+
+ COM_METHOD OpenMethod2(mdMethodDef method,
+ ULONG32 isect,
+ ULONG32 offset);
+
+ COM_METHOD Commit();
+
+ //-----------------------------------------------------------
+ // Methods not exposed via a COM interface.
+ //-----------------------------------------------------------
+
+ static HRESULT NewSymWriter(REFIID clsid, void** ppObj);
+ HRESULT SetDocumentCheckSum(
+ UINT32 DocumentEntry,
+ GUID AlgorithmId,
+ DWORD CheckSumSize,
+ BYTE* pCheckSum);
+ HRESULT SetDocumentSrc(UINT32 DocumentEntry,
+ DWORD SourceSize,
+ BYTE* pSource);
+
+ COM_METHOD Write(void *pData, DWORD SizeOfData);
+ COM_METHOD WriteStringPool();
+ COM_METHOD WritePDB();
+
+ COM_METHOD Initialize(const WCHAR *szFilename, IStream *pIStream);
+
+ void SetFullPathName(const WCHAR *szFullPathName)
+ {
+
+ }
+
+private:
+ // Helper API for CloserScope
+ COM_METHOD CloseScopeInternal(ULONG32 endOffset);
+ HRESULT GetOrCreateDocument(
+ const WCHAR *wcsUrl, // Document name
+ const GUID *pLanguage, // What Language we're compiling
+ const GUID *pLanguageVendor, // What vendor
+ const GUID *pDocumentType, // Type
+ ISymUnmanagedDocumentWriter **ppRetVal // [out] Created DocumentWriter
+ );
+ HRESULT CreateDocument(
+ const WCHAR *wcsUrl, // Document name
+ const GUID *pLanguage, // What Language we're compiling
+ const GUID *pLanguageVendor, // What vendor
+ const GUID *pDocumentType, // Type
+ ISymUnmanagedDocumentWriter **ppRetVal // [out] Created DocumentWriter
+ );
+
+
+ //-----------------------------------------------------------
+ // Data members
+ //-----------------------------------------------------------
+private:
+ UINT32 m_refCount; // AddRef/Release
+
+ mdMethodDef m_openMethodToken;
+ mdMethodDef m_LargestMethodToken;
+ SymMethodInfo * m_pmethod;
+
+ // index of currently open scope
+ UINT32 m_currentScope;
+
+ // special scope "index" meaning there is no such scope
+ static const UINT32 k_noScope = (UINT32)-1;
+
+ // maximum scope end offset seen so far in this method
+ ULONG32 m_maxScopeEnd;
+
+ MethodInfo m_MethodInfo;
+ ArrayStorage<SymMap> m_MethodMap; // Methods information
+
+ // Symbol File Name
+ WCHAR m_szPath[ _MAX_PATH ];
+ // File Handle
+ HANDLE m_hFile;
+ // Stream we're storing into if asked to.
+ IStream* m_pIStream;
+
+ // StringPool we use to store the string into
+ StgStringPool *m_pStringPool;
+
+ // Project level symbol information
+ PDBInfo ModuleLevelInfo;
+
+ bool m_closed; // Have we closed the file yet?
+ bool m_sortLines; // sort the line for current method
+ bool m_sortMethodEntries; // Sort the method entries
+
+
+};
+
+/* ------------------------------------------------------------------------- *
+ * SymDocumentWriter class
+ * ------------------------------------------------------------------------- */
+
+class SymDocumentWriter : public ISymUnmanagedDocumentWriter
+{
+public:
+ SymDocumentWriter(UINT32 DocumentEntry,
+ SymWriter *pEmitter);
+
+ virtual ~SymDocumentWriter();
+
+ //-----------------------------------------------------------
+ // IUnknown support
+ //-----------------------------------------------------------
+ ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return (InterlockedIncrement((LONG *) &m_refCount));
+ }
+
+ ULONG STDMETHODCALLTYPE Release()
+ {
+ // Note that this must be thread-safe - it may be invoked on the finalizer thread
+ LONG refCount = InterlockedDecrement((LONG *) &m_refCount);
+ if (refCount == 0)
+ DELETE(this);
+
+ return (refCount);
+ }
+ COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
+
+ //-----------------------------------------------------------
+ // ISymUnmanagedDocumentWriter
+ //-----------------------------------------------------------
+ COM_METHOD SetSource(ULONG32 sourceSize, BYTE source[]);
+ COM_METHOD SetCheckSum(GUID algorithmId,
+ ULONG32 checkSumSize, BYTE checkSum[]);
+
+ //-----------------------------------------------------------
+ // Methods not exposed via a COM interface.
+ //-----------------------------------------------------------
+ //
+ // Commit the doc to the pdb
+ //
+ UINT32 GetDocumentEntry()
+ {
+ return m_DocumentEntry;
+ }
+
+ //-----------------------------------------------------------
+ // Data members
+ //-----------------------------------------------------------
+private:
+ UINT32 m_refCount; // AddRef/Release
+ UINT32 m_DocumentEntry; // Entry into the documents array
+ SymWriter *m_pEmitter; // Associated SymWriter
+};
+
+// Debug Info
+struct RSDSI // RSDS debug info
+{
+ DWORD dwSig; // RSDS
+ GUID guidSig;
+ DWORD age;
+ char szPDB[0]; // followed by a zero-terminated UTF8 file name
+};
+
+#endif /* SYMWRITE_H_ */
diff --git a/src/debug/ildbsymlib/umisc.h b/src/debug/ildbsymlib/umisc.h
new file mode 100644
index 0000000000..fda40474ff
--- /dev/null
+++ b/src/debug/ildbsymlib/umisc.h
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ===========================================================================
+// File: umisc.h
+//
+
+// ===========================================================================
+
+
+// Abstract:
+//
+// A collection of utility macros.
+//
+
+#ifndef UMISC_H
+#define UMISC_H
+
+#define COM_METHOD HRESULT STDMETHODCALLTYPE
+
+inline HRESULT HrFromWin32(DWORD dwWin32Error)
+{
+ return HRESULT_FROM_WIN32(dwWin32Error);
+}
+
+// Some helper #def's to safely Release, close & delete Objects under
+// failure conditions
+
+#define RELEASE(x) \
+ do \
+ { \
+ if (x) \
+ { \
+ IUnknown *punk = x; \
+ x = NULL; \
+ punk->Release(); \
+ } \
+ } while (0)
+
+
+#include "debugmacros.h"
+//
+// Good for verifying params withing range.
+//
+#define IfFalseGo(expr, HR) IfFailGo((expr) ? S_OK : (HR))
+
+// ----------------------------------------------------------------------------
+// Validation macros
+// Note that the Win32 APIs like IsBadReadPtr are banned
+//
+#define IsValidReadPtr(ptr, type) ((ptr)!=NULL)
+
+#define IsValidWritePtr(ptr, type) ((ptr)!=NULL)
+
+#define IsValidReadBufferPtr(ptr, type, len) ((ptr)!=NULL)
+
+#define IsValidWriteBufferPtr(ptr, type, len) ((ptr)!=NULL)
+
+#define IsValidInterfacePtr(ptr, type) ((ptr)!=NULL)
+
+#define IsValidCodePtr(ptr) ((ptr)!=NULL)
+
+#define IsValidStringPtr(ptr) ((ptr)!=NULL)
+
+#define IsValidIID(iid) TRUE
+
+#define IsValidCLSID(clsid) TRUE
+
+#endif