Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomáš Rylek <trylek@microsoft.com>2020-12-08 05:19:44 +0300
committerGitHub <noreply@github.com>2020-12-08 05:19:44 +0300
commit69e114c1abf91241a0eeecf1ecceab4711b8aa62 (patch)
treeb81a0b35748f5e598412bcc504335cdbd322cd43 /src/coreclr/binder
parent0ec07945a9759a72a689edbb01e69b232e26e05a (diff)
December infra rollout - remove duplicated 'src' from coreclr subrepo (src/coreclr/src becomes src/coreclr) (#44973)
* Move src/coreclr/src/Directory.Build.targets to src/coreclr Merge src/coreclr/src/CMakeLists.txt into src/coreclr/CMakeLists.txt * Mechanical move of src/coreclr/src to src/coreclr * Scripts adjustments to reflect the changed paths
Diffstat (limited to 'src/coreclr/binder')
-rw-r--r--src/coreclr/binder/CMakeLists.txt99
-rw-r--r--src/coreclr/binder/activitytracker.cpp42
-rw-r--r--src/coreclr/binder/applicationcontext.cpp336
-rw-r--r--src/coreclr/binder/assembly.cpp213
-rw-r--r--src/coreclr/binder/assemblybinder.cpp1579
-rw-r--r--src/coreclr/binder/assemblyidentitycache.cpp64
-rw-r--r--src/coreclr/binder/assemblyname.cpp498
-rw-r--r--src/coreclr/binder/bindertracing.cpp461
-rw-r--r--src/coreclr/binder/clrprivbinderassemblyloadcontext.cpp293
-rw-r--r--src/coreclr/binder/clrprivbindercoreclr.cpp263
-rw-r--r--src/coreclr/binder/coreclrbindercommon.cpp139
-rw-r--r--src/coreclr/binder/failurecache.cpp76
-rw-r--r--src/coreclr/binder/fusionassemblyname.cpp714
-rw-r--r--src/coreclr/binder/inc/activitytracker.h16
-rw-r--r--src/coreclr/binder/inc/applicationcontext.hpp152
-rw-r--r--src/coreclr/binder/inc/applicationcontext.inl86
-rw-r--r--src/coreclr/binder/inc/assembly.hpp167
-rw-r--r--src/coreclr/binder/inc/assembly.inl134
-rw-r--r--src/coreclr/binder/inc/assemblybinder.hpp122
-rw-r--r--src/coreclr/binder/inc/assemblyentry.hpp61
-rw-r--r--src/coreclr/binder/inc/assemblyhashtraits.hpp58
-rw-r--r--src/coreclr/binder/inc/assemblyidentity.hpp134
-rw-r--r--src/coreclr/binder/inc/assemblyidentitycache.hpp115
-rw-r--r--src/coreclr/binder/inc/assemblyname.hpp94
-rw-r--r--src/coreclr/binder/inc/assemblyname.inl133
-rw-r--r--src/coreclr/binder/inc/assemblyversion.hpp59
-rw-r--r--src/coreclr/binder/inc/assemblyversion.inl108
-rw-r--r--src/coreclr/binder/inc/bindertracing.h189
-rw-r--r--src/coreclr/binder/inc/bindertypes.hpp109
-rw-r--r--src/coreclr/binder/inc/bindresult.hpp80
-rw-r--r--src/coreclr/binder/inc/bindresult.inl212
-rw-r--r--src/coreclr/binder/inc/clrprivbinderassemblyloadcontext.h86
-rw-r--r--src/coreclr/binder/inc/clrprivbindercoreclr.h68
-rw-r--r--src/coreclr/binder/inc/contextentry.hpp110
-rw-r--r--src/coreclr/binder/inc/coreclrbindercommon.h47
-rw-r--r--src/coreclr/binder/inc/failurecache.hpp37
-rw-r--r--src/coreclr/binder/inc/failurecachehashtraits.hpp87
-rw-r--r--src/coreclr/binder/inc/fusionassemblyname.hpp111
-rw-r--r--src/coreclr/binder/inc/fusionhelpers.hpp72
-rw-r--r--src/coreclr/binder/inc/loadcontext.hpp46
-rw-r--r--src/coreclr/binder/inc/loadcontext.inl87
-rw-r--r--src/coreclr/binder/inc/stringlexer.hpp99
-rw-r--r--src/coreclr/binder/inc/stringlexer.inl242
-rw-r--r--src/coreclr/binder/inc/textualidentityparser.hpp69
-rw-r--r--src/coreclr/binder/inc/utils.hpp47
-rw-r--r--src/coreclr/binder/inc/variables.hpp40
-rw-r--r--src/coreclr/binder/stringlexer.cpp150
-rw-r--r--src/coreclr/binder/textualidentityparser.cpp766
-rw-r--r--src/coreclr/binder/utils.cpp255
-rw-r--r--src/coreclr/binder/variables.cpp49
50 files changed, 9274 insertions, 0 deletions
diff --git a/src/coreclr/binder/CMakeLists.txt b/src/coreclr/binder/CMakeLists.txt
new file mode 100644
index 00000000000..208f1214dd0
--- /dev/null
+++ b/src/coreclr/binder/CMakeLists.txt
@@ -0,0 +1,99 @@
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+include_directories(BEFORE "../vm/${ARCH_SOURCES_DIR}")
+include_directories(BEFORE "../vm")
+include_directories(BEFORE "inc")
+
+set(BINDER_COMMON_SOURCES
+ applicationcontext.cpp
+ assembly.cpp
+ assemblybinder.cpp
+ assemblyidentitycache.cpp
+ assemblyname.cpp
+ bindertracing.cpp
+ clrprivbindercoreclr.cpp
+ coreclrbindercommon.cpp
+ failurecache.cpp
+ fusionassemblyname.cpp
+ stringlexer.cpp
+ textualidentityparser.cpp
+ utils.cpp
+ variables.cpp
+)
+
+set(BINDER_COMMON_HEADERS
+ inc/applicationcontext.hpp
+ inc/applicationcontext.inl
+ inc/assembly.hpp
+ inc/assembly.inl
+ inc/assemblybinder.hpp
+ inc/assemblyentry.hpp
+ inc/assemblyhashtraits.hpp
+ inc/assemblyidentity.hpp
+ inc/assemblyidentitycache.hpp
+ inc/assemblyname.hpp
+ inc/assemblyname.inl
+ inc/assemblyversion.hpp
+ inc/assemblyversion.inl
+ inc/bindertypes.hpp
+ inc/bindertracing.h
+ inc/bindresult.hpp
+ inc/bindresult.inl
+ inc/clrprivbindercoreclr.h
+ inc/coreclrbindercommon.h
+ inc/failurecache.hpp
+ inc/failurecachehashtraits.hpp
+ inc/fusionassemblyname.hpp
+ inc/fusionhelpers.hpp
+ inc/loadcontext.hpp
+ inc/loadcontext.inl
+ inc/stringlexer.hpp
+ inc/stringlexer.inl
+ inc/textualidentityparser.hpp
+ inc/utils.hpp
+ inc/variables.hpp
+)
+
+set(BINDER_SOURCES
+ ${BINDER_COMMON_SOURCES}
+ activitytracker.cpp
+ clrprivbinderassemblyloadcontext.cpp
+)
+
+set(BINDER_HEADERS
+ ${BINDER_COMMON_HEADERS}
+ inc/activitytracker.h
+ inc/clrprivbinderassemblyloadcontext.h
+ inc/contextentry.hpp
+)
+
+set(BINDER_CROSSGEN_SOURCES
+ ${BINDER_COMMON_SOURCES}
+)
+
+set(BINDER_CROSSGEN_HEADERS
+ ${BINDER_COMMON_HEADERS}
+)
+
+if (CLR_CMAKE_TARGET_WIN32)
+ list(APPEND BINDER_SOURCES ${BINDER_HEADERS})
+ list(APPEND BINDER_CROSSGEN_SOURCES ${BINDER_CROSSGEN_HEADERS})
+endif(CLR_CMAKE_TARGET_WIN32)
+
+convert_to_absolute_path(BINDER_SOURCES ${BINDER_SOURCES})
+convert_to_absolute_path(BINDER_CROSSGEN_SOURCES ${BINDER_CROSSGEN_SOURCES})
+
+add_library_clr(v3binder_obj
+ OBJECT
+ ${BINDER_SOURCES}
+)
+add_dependencies(v3binder_obj eventing_headers)
+add_library(v3binder INTERFACE)
+target_sources(v3binder INTERFACE $<TARGET_OBJECTS:v3binder_obj>)
+
+add_library_clr(v3binder_crossgen
+ STATIC
+ ${BINDER_CROSSGEN_SOURCES}
+)
+add_dependencies(v3binder_crossgen eventing_headers)
+set_target_properties(v3binder_crossgen PROPERTIES CROSSGEN_COMPONENT TRUE)
+
diff --git a/src/coreclr/binder/activitytracker.cpp b/src/coreclr/binder/activitytracker.cpp
new file mode 100644
index 00000000000..b7287d3afa9
--- /dev/null
+++ b/src/coreclr/binder/activitytracker.cpp
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// activitytracker.cpp
+//
+
+
+//
+// Helpers for interaction with the managed ActivityTracker
+//
+// ============================================================
+
+#include "common.h"
+#include "activitytracker.h"
+
+void ActivityTracker::Start(/*out*/ GUID *activityId, /*out*/ GUID *relatedActivityId)
+{
+ GCX_COOP();
+
+ OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
+
+ PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__START_ASSEMBLY_LOAD);
+ DECLARE_ARGHOLDER_ARRAY(args, 2);
+ args[ARGNUM_0] = PTR_TO_ARGHOLDER(activityId);
+ args[ARGNUM_1] = PTR_TO_ARGHOLDER(relatedActivityId);
+
+ CALL_MANAGED_METHOD_NORET(args)
+}
+
+void ActivityTracker::Stop(/*out*/ GUID *activityId)
+{
+ GCX_COOP();
+
+ OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
+
+ PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__STOP_ASSEMBLY_LOAD);
+ DECLARE_ARGHOLDER_ARRAY(args, 1);
+ args[ARGNUM_0] = PTR_TO_ARGHOLDER(activityId);
+
+ CALL_MANAGED_METHOD_NORET(args)
+}
diff --git a/src/coreclr/binder/applicationcontext.cpp b/src/coreclr/binder/applicationcontext.cpp
new file mode 100644
index 00000000000..f865b424049
--- /dev/null
+++ b/src/coreclr/binder/applicationcontext.cpp
@@ -0,0 +1,336 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// ApplicationContext.cpp
+//
+
+
+//
+// Implements the ApplicationContext class
+//
+// ============================================================
+
+#include "applicationcontext.hpp"
+#include "stringarraylist.h"
+#include "loadcontext.hpp"
+#include "failurecache.hpp"
+#include "assemblyidentitycache.hpp"
+#include "utils.hpp"
+#include "variables.hpp"
+#include "ex.h"
+#include "clr/fs/path.h"
+using namespace clr::fs;
+
+namespace BINDER_SPACE
+{
+ STDMETHODIMP ApplicationContext::QueryInterface(REFIID riid,
+ void **ppv)
+ {
+ HRESULT hr = S_OK;
+
+ if (ppv == NULL)
+ {
+ hr = E_POINTER;
+ }
+ else
+ {
+ if (IsEqualIID(riid, IID_IUnknown))
+ {
+ AddRef();
+ *ppv = static_cast<IUnknown *>(this);
+ }
+ else
+ {
+ *ppv = NULL;
+ hr = E_NOINTERFACE;
+ }
+ }
+
+ return hr;
+ }
+
+ STDMETHODIMP_(ULONG) ApplicationContext::AddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }
+
+ STDMETHODIMP_(ULONG) ApplicationContext::Release()
+ {
+ ULONG ulRef = InterlockedDecrement(&m_cRef);
+
+ if (ulRef == 0)
+ {
+ delete this;
+ }
+
+ return ulRef;
+ }
+
+ ApplicationContext::ApplicationContext()
+ {
+ m_cRef = 1;
+ m_dwAppDomainId = 0;
+ m_pExecutionContext = NULL;
+ m_pFailureCache = NULL;
+ m_contextCS = NULL;
+ m_pTrustedPlatformAssemblyMap = nullptr;
+ m_binderID = 0;
+ }
+
+ ApplicationContext::~ApplicationContext()
+ {
+ SAFE_RELEASE(m_pExecutionContext);
+ SAFE_DELETE(m_pFailureCache);
+
+ if (m_contextCS != NULL)
+ {
+ ClrDeleteCriticalSection(m_contextCS);
+ }
+
+ if (m_pTrustedPlatformAssemblyMap != nullptr)
+ {
+ delete m_pTrustedPlatformAssemblyMap;
+ }
+ }
+
+ HRESULT ApplicationContext::Init(UINT_PTR binderID)
+ {
+ HRESULT hr = S_OK;
+
+ ReleaseHolder<ExecutionContext> pExecutionContext;
+
+ FailureCache *pFailureCache = NULL;
+
+ // Allocate context objects
+ SAFE_NEW(pExecutionContext, ExecutionContext);
+
+ SAFE_NEW(pFailureCache, FailureCache);
+
+ m_contextCS = ClrCreateCriticalSection(
+ CrstFusionAppCtx,
+ CRST_REENTRANCY);
+ if (!m_contextCS)
+ {
+ SAFE_DELETE(pFailureCache);
+ hr = E_OUTOFMEMORY;
+ }
+ else
+ {
+ m_pExecutionContext = pExecutionContext.Extract();
+
+ m_pFailureCache = pFailureCache;
+ }
+
+ m_binderID = binderID;
+ Exit:
+ return hr;
+ }
+
+ HRESULT ApplicationContext::SetupBindingPaths(SString &sTrustedPlatformAssemblies,
+ SString &sPlatformResourceRoots,
+ SString &sAppPaths,
+ SString &sAppNiPaths,
+ BOOL fAcquireLock)
+ {
+ HRESULT hr = S_OK;
+
+#ifndef CROSSGEN_COMPILE
+ CRITSEC_Holder contextLock(fAcquireLock ? GetCriticalSectionCookie() : NULL);
+#endif
+ if (m_pTrustedPlatformAssemblyMap != nullptr)
+ {
+ GO_WITH_HRESULT(S_OK);
+ }
+
+ //
+ // Parse TrustedPlatformAssemblies
+ //
+ m_pTrustedPlatformAssemblyMap = new SimpleNameToFileNameMap();
+
+ sTrustedPlatformAssemblies.Normalize();
+
+ for (SString::Iterator i = sTrustedPlatformAssemblies.Begin(); i != sTrustedPlatformAssemblies.End(); )
+ {
+ SString fileName;
+ SString simpleName;
+ bool isNativeImage = false;
+ HRESULT pathResult = S_OK;
+ IF_FAIL_GO(pathResult = GetNextTPAPath(sTrustedPlatformAssemblies, i, /*dllOnly*/ false, fileName, simpleName, isNativeImage));
+ if (pathResult == S_FALSE)
+ {
+ break;
+ }
+
+ const SimpleNameToFileNameMapEntry *pExistingEntry = m_pTrustedPlatformAssemblyMap->LookupPtr(simpleName.GetUnicode());
+
+ if (pExistingEntry != nullptr)
+ {
+ //
+ // We want to store only the first entry matching a simple name we encounter.
+ // The exception is if we first store an IL reference and later in the string
+ // we encounter a native image. Since we don't touch IL in the presence of
+ // native images, we replace the IL entry with the NI.
+ //
+ if ((pExistingEntry->m_wszILFileName != nullptr && !isNativeImage) ||
+ (pExistingEntry->m_wszNIFileName != nullptr && isNativeImage))
+ {
+ continue;
+ }
+ }
+
+ LPWSTR wszSimpleName = nullptr;
+ if (pExistingEntry == nullptr)
+ {
+ wszSimpleName = new WCHAR[simpleName.GetCount() + 1];
+ if (wszSimpleName == nullptr)
+ {
+ GO_WITH_HRESULT(E_OUTOFMEMORY);
+ }
+ wcscpy_s(wszSimpleName, simpleName.GetCount() + 1, simpleName.GetUnicode());
+ }
+ else
+ {
+ wszSimpleName = pExistingEntry->m_wszSimpleName;
+ }
+
+ LPWSTR wszFileName = new WCHAR[fileName.GetCount() + 1];
+ if (wszFileName == nullptr)
+ {
+ GO_WITH_HRESULT(E_OUTOFMEMORY);
+ }
+ wcscpy_s(wszFileName, fileName.GetCount() + 1, fileName.GetUnicode());
+
+ SimpleNameToFileNameMapEntry mapEntry;
+ mapEntry.m_wszSimpleName = wszSimpleName;
+ if (isNativeImage)
+ {
+ mapEntry.m_wszNIFileName = wszFileName;
+ mapEntry.m_wszILFileName = pExistingEntry == nullptr ? nullptr : pExistingEntry->m_wszILFileName;
+ }
+ else
+ {
+ mapEntry.m_wszILFileName = wszFileName;
+ mapEntry.m_wszNIFileName = pExistingEntry == nullptr ? nullptr : pExistingEntry->m_wszNIFileName;
+ }
+
+ m_pTrustedPlatformAssemblyMap->AddOrReplace(mapEntry);
+ }
+
+ //
+ // Parse PlatformResourceRoots
+ //
+ sPlatformResourceRoots.Normalize();
+ for (SString::Iterator i = sPlatformResourceRoots.Begin(); i != sPlatformResourceRoots.End(); )
+ {
+ SString pathName;
+ HRESULT pathResult = S_OK;
+
+ IF_FAIL_GO(pathResult = GetNextPath(sPlatformResourceRoots, i, pathName));
+ if (pathResult == S_FALSE)
+ {
+ break;
+ }
+
+#ifndef CROSSGEN_COMPILE
+ if (Path::IsRelative(pathName))
+ {
+ GO_WITH_HRESULT(E_INVALIDARG);
+ }
+#endif
+
+ m_platformResourceRoots.Append(pathName);
+ }
+
+ //
+ // Parse AppPaths
+ //
+ sAppPaths.Normalize();
+ for (SString::Iterator i = sAppPaths.Begin(); i != sAppPaths.End(); )
+ {
+ SString pathName;
+ HRESULT pathResult = S_OK;
+
+ IF_FAIL_GO(pathResult = GetNextPath(sAppPaths, i, pathName));
+ if (pathResult == S_FALSE)
+ {
+ break;
+ }
+
+#ifndef CROSSGEN_COMPILE
+ if (Path::IsRelative(pathName))
+ {
+ GO_WITH_HRESULT(E_INVALIDARG);
+ }
+#endif
+
+ m_appPaths.Append(pathName);
+ }
+
+ //
+ // Parse AppNiPaths
+ //
+ sAppNiPaths.Normalize();
+ for (SString::Iterator i = sAppNiPaths.Begin(); i != sAppNiPaths.End(); )
+ {
+ SString pathName;
+ HRESULT pathResult = S_OK;
+
+ IF_FAIL_GO(pathResult = GetNextPath(sAppNiPaths, i, pathName));
+ if (pathResult == S_FALSE)
+ {
+ break;
+ }
+
+#ifndef CROSSGEN_COMPILE
+ if (Path::IsRelative(pathName))
+ {
+ GO_WITH_HRESULT(E_INVALIDARG);
+ }
+#endif
+
+ m_appNiPaths.Append(pathName);
+ }
+
+ Exit:
+ return hr;
+ }
+
+ HRESULT ApplicationContext::GetAssemblyIdentity(LPCSTR szTextualIdentity,
+ AssemblyIdentityUTF8 **ppAssemblyIdentity)
+ {
+ HRESULT hr = S_OK;
+
+ _ASSERTE(szTextualIdentity != NULL);
+ _ASSERTE(ppAssemblyIdentity != NULL);
+
+ CRITSEC_Holder contextLock(GetCriticalSectionCookie());
+
+ AssemblyIdentityUTF8 *pAssemblyIdentity = m_assemblyIdentityCache.Lookup(szTextualIdentity);
+ if (pAssemblyIdentity == NULL)
+ {
+ NewHolder<AssemblyIdentityUTF8> pNewAssemblyIdentity;
+ SString sTextualIdentity;
+
+ SAFE_NEW(pNewAssemblyIdentity, AssemblyIdentityUTF8);
+ sTextualIdentity.SetUTF8(szTextualIdentity);
+
+ IF_FAIL_GO(TextualIdentityParser::Parse(sTextualIdentity, pNewAssemblyIdentity));
+ IF_FAIL_GO(m_assemblyIdentityCache.Add(szTextualIdentity, pNewAssemblyIdentity));
+
+ pNewAssemblyIdentity->PopulateUTF8Fields();
+
+ pAssemblyIdentity = pNewAssemblyIdentity.Extract();
+ }
+
+ *ppAssemblyIdentity = pAssemblyIdentity;
+
+ Exit:
+ return hr;
+ }
+
+ bool ApplicationContext::IsTpaListProvided()
+ {
+ return m_pTrustedPlatformAssemblyMap != nullptr;
+ }
+};
diff --git a/src/coreclr/binder/assembly.cpp b/src/coreclr/binder/assembly.cpp
new file mode 100644
index 00000000000..d4948c4d1ae
--- /dev/null
+++ b/src/coreclr/binder/assembly.cpp
@@ -0,0 +1,213 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// Assembly.cpp
+//
+
+
+//
+// Implements the Assembly class
+//
+// ============================================================
+#include "common.h"
+#include "assembly.hpp"
+#include "utils.hpp"
+
+namespace BINDER_SPACE
+{
+ namespace
+ {
+ BOOL IsPlatformArchitecture(PEKIND kArchitecture)
+ {
+ return ((kArchitecture != peMSIL) && (kArchitecture != peNone));
+ }
+ };
+
+ STDMETHODIMP Assembly::QueryInterface(REFIID riid,
+ void **ppv)
+ {
+ HRESULT hr = S_OK;
+
+ if (ppv == NULL)
+ {
+ hr = E_POINTER;
+ }
+ else
+ {
+ if (IsEqualIID(riid, IID_IUnknown))
+ {
+ AddRef();
+ *ppv = static_cast<IUnknown *>(this);
+ }
+ else
+ {
+ *ppv = NULL;
+ hr = E_NOINTERFACE;
+ }
+ }
+
+ return hr;
+ }
+
+ STDMETHODIMP_(ULONG) Assembly::AddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }
+
+ STDMETHODIMP_(ULONG) Assembly::Release()
+ {
+ ULONG ulRef = InterlockedDecrement(&m_cRef);
+
+ if (ulRef == 0)
+ {
+ delete this;
+ }
+
+ return ulRef;
+ }
+
+ Assembly::Assembly()
+ {
+ m_cRef = 1;
+ m_pPEImage = NULL;
+ m_pNativePEImage = NULL;
+ m_pAssemblyName = NULL;
+ m_pMDImport = NULL;
+ m_dwAssemblyFlags = FLAG_NONE;
+ m_pBinder = NULL;
+ }
+
+ Assembly::~Assembly()
+ {
+ if (m_pPEImage != NULL)
+ {
+ BinderReleasePEImage(m_pPEImage);
+ m_pPEImage = NULL;
+ }
+
+#ifdef FEATURE_PREJIT
+ if (m_pNativePEImage != NULL)
+ {
+ BinderReleasePEImage(m_pNativePEImage);
+ m_pNativePEImage = NULL;
+ }
+#endif
+
+ SAFE_RELEASE(m_pAssemblyName);
+ SAFE_RELEASE(m_pMDImport);
+ }
+
+ HRESULT Assembly::Init(IMDInternalImport *pIMetaDataAssemblyImport,
+ PEKIND PeKind,
+ PEImage *pPEImage,
+ PEImage *pNativePEImage,
+ SString &assemblyPath,
+ BOOL fIsInGAC)
+ {
+ HRESULT hr = S_OK;
+
+ ReleaseHolder<AssemblyName> pAssemblyName;
+ SAFE_NEW(pAssemblyName, AssemblyName);
+
+ // Get assembly name def from meta data import and store it for later refs access
+ IF_FAIL_GO(pAssemblyName->Init(pIMetaDataAssemblyImport, PeKind));
+ SetMDImport(pIMetaDataAssemblyImport);
+ if (!fIsInGAC)
+ {
+ GetPath().Set(assemblyPath);
+ }
+
+ // Safe architecture for validation
+ PEKIND kAssemblyArchitecture;
+ kAssemblyArchitecture = pAssemblyName->GetArchitecture();
+ SetIsInGAC(fIsInGAC);
+ SetPEImage(pPEImage);
+ SetNativePEImage(pNativePEImage);
+ pAssemblyName->SetIsDefinition(TRUE);
+
+ // Now take ownership of assembly names
+ SetAssemblyName(pAssemblyName.Extract(), FALSE /* fAddRef */);
+
+ // Finally validate architecture
+ if (!IsValidArchitecture(kAssemblyArchitecture))
+ {
+ // Assembly image can't be executed on this platform
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
+ }
+
+ Exit:
+ return hr;
+ }
+
+ HRESULT Assembly::GetMVID(GUID *pMVID)
+ {
+ // Zero init the GUID incase we fail
+ ZeroMemory(pMVID, sizeof(GUID));
+
+ return m_pMDImport->GetScopeProps(NULL, pMVID);
+ }
+
+ /* static */
+ PEKIND Assembly::GetSystemArchitecture()
+ {
+#if defined(TARGET_X86)
+ return peI386;
+#elif defined(TARGET_AMD64)
+ return peAMD64;
+#elif defined(TARGET_ARM)
+ return peARM;
+#elif defined(TARGET_ARM64)
+ return peARM64;
+#else
+ PORTABILITY_ASSERT("Assembly::GetSystemArchitecture");
+#endif
+ }
+
+ /* static */
+ BOOL Assembly::IsValidArchitecture(PEKIND kArchitecture)
+ {
+ if (!IsPlatformArchitecture(kArchitecture))
+ return TRUE;
+
+ return (kArchitecture == GetSystemArchitecture());
+ }
+
+ // --------------------------------------------------------------------
+ // ICLRPrivAssembly methods
+ // --------------------------------------------------------------------
+ LPCWSTR Assembly::GetSimpleName()
+ {
+ AssemblyName *pAsmName = GetAssemblyName();
+ return (pAsmName == nullptr ? nullptr : (LPCWSTR)pAsmName->GetSimpleName());
+ }
+
+ HRESULT Assembly::BindAssemblyByName(IAssemblyName * pIAssemblyName, ICLRPrivAssembly ** ppAssembly)
+ {
+ return (m_pBinder == NULL) ? E_FAIL : m_pBinder->BindAssemblyByName(pIAssemblyName, ppAssembly);
+ }
+
+ HRESULT Assembly::GetBinderID(UINT_PTR *pBinderId)
+ {
+ return (m_pBinder == NULL) ? E_FAIL : m_pBinder->GetBinderID(pBinderId);
+ }
+
+ HRESULT Assembly::GetLoaderAllocator(LPVOID* pLoaderAllocator)
+ {
+ return (m_pBinder == NULL) ? E_FAIL : m_pBinder->GetLoaderAllocator(pLoaderAllocator);
+ }
+
+ HRESULT Assembly::GetAvailableImageTypes(
+ LPDWORD pdwImageTypes)
+ {
+ HRESULT hr = E_FAIL;
+
+ if(pdwImageTypes == nullptr)
+ return E_INVALIDARG;
+
+ *pdwImageTypes = ASSEMBLY_IMAGE_TYPE_ASSEMBLY;
+
+ return S_OK;
+ }
+}
+
diff --git a/src/coreclr/binder/assemblybinder.cpp b/src/coreclr/binder/assemblybinder.cpp
new file mode 100644
index 00000000000..aa29465af82
--- /dev/null
+++ b/src/coreclr/binder/assemblybinder.cpp
@@ -0,0 +1,1579 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// AssemblyBinder.cpp
+//
+
+
+//
+// Implements the AssemblyBinder class
+//
+// ============================================================
+
+#include "assemblybinder.hpp"
+#include "assemblyname.hpp"
+#include "assembly.hpp"
+#include "applicationcontext.hpp"
+#include "bindertracing.h"
+#include "loadcontext.hpp"
+#include "bindresult.inl"
+#include "failurecache.hpp"
+#include "utils.hpp"
+#include "variables.hpp"
+#include "stringarraylist.h"
+#include "configuration.h"
+
+#define APP_DOMAIN_LOCKED_UNLOCKED 0x02
+#define APP_DOMAIN_LOCKED_CONTEXT 0x04
+
+#ifndef IMAGE_FILE_MACHINE_ARM64
+#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian
+#endif
+
+BOOL IsCompilationProcess();
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+#include "clrprivbindercoreclr.h"
+#include "clrprivbinderassemblyloadcontext.h"
+// Helper function in the VM, invoked by the Binder, to invoke the host assembly resolver
+extern HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin,
+ IAssemblyName *pIAssemblyName, CLRPrivBinderCoreCLR *pTPABinder,
+ BINDER_SPACE::AssemblyName *pAssemblyName, ICLRPrivAssembly **ppLoadedAssembly);
+
+#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+namespace BINDER_SPACE
+{
+ namespace
+ {
+ //
+ // This defines the assembly equivalence relation
+ //
+ bool IsCompatibleAssemblyVersion(/* in */ AssemblyName *pRequestedName,
+ /* in */ AssemblyName *pFoundName)
+ {
+ AssemblyVersion *pRequestedVersion = pRequestedName->GetVersion();
+ AssemblyVersion *pFoundVersion = pFoundName->GetVersion();
+
+ if (!pRequestedVersion->HasMajor())
+ {
+ // An unspecified requested version component matches any value for the same component in the found version,
+ // regardless of lesser-order version components
+ return true;
+ }
+ if (!pFoundVersion->HasMajor() || pRequestedVersion->GetMajor() > pFoundVersion->GetMajor())
+ {
+ // - A specific requested version component does not match an unspecified value for the same component in
+ // the found version, regardless of lesser-order version components
+ // - Or, the requested version is greater than the found version
+ return false;
+ }
+ if (pRequestedVersion->GetMajor() < pFoundVersion->GetMajor())
+ {
+ // The requested version is less than the found version
+ return true;
+ }
+
+ if (!pRequestedVersion->HasMinor())
+ {
+ return true;
+ }
+ if (!pFoundVersion->HasMinor() || pRequestedVersion->GetMinor() > pFoundVersion->GetMinor())
+ {
+ return false;
+ }
+ if (pRequestedVersion->GetMinor() < pFoundVersion->GetMinor())
+ {
+ return true;
+ }
+
+ if (!pRequestedVersion->HasBuild())
+ {
+ return true;
+ }
+ if (!pFoundVersion->HasBuild() || pRequestedVersion->GetBuild() > pFoundVersion->GetBuild())
+ {
+ return false;
+ }
+ if (pRequestedVersion->GetBuild() < pFoundVersion->GetBuild())
+ {
+ return true;
+ }
+
+ if (!pRequestedVersion->HasRevision())
+ {
+ return true;
+ }
+ if (!pFoundVersion->HasRevision() || pRequestedVersion->GetRevision() > pFoundVersion->GetRevision())
+ {
+ return false;
+ }
+ return true;
+ }
+
+ HRESULT URLToFullPath(PathString &assemblyPath)
+ {
+ HRESULT hr = S_OK;
+
+ SString::Iterator pos = assemblyPath.Begin();
+ if (assemblyPath.MatchCaseInsensitive(pos, g_BinderVariables->httpURLPrefix))
+ {
+ // HTTP downloads are unsupported
+ hr = FUSION_E_CODE_DOWNLOAD_DISABLED;
+ }
+ else
+ {
+ SString fullAssemblyPath;
+ WCHAR *pwzFullAssemblyPath = fullAssemblyPath.OpenUnicodeBuffer(MAX_LONGPATH);
+ DWORD dwCCFullAssemblyPath = MAX_LONGPATH + 1; // SString allocates extra byte for null.
+
+ MutateUrlToPath(assemblyPath);
+
+ dwCCFullAssemblyPath = WszGetFullPathName(assemblyPath.GetUnicode(),
+ dwCCFullAssemblyPath,
+ pwzFullAssemblyPath,
+ NULL);
+ if (dwCCFullAssemblyPath > MAX_LONGPATH)
+ {
+ fullAssemblyPath.CloseBuffer();
+ pwzFullAssemblyPath = fullAssemblyPath.OpenUnicodeBuffer(dwCCFullAssemblyPath - 1);
+ dwCCFullAssemblyPath = WszGetFullPathName(assemblyPath.GetUnicode(),
+ dwCCFullAssemblyPath,
+ pwzFullAssemblyPath,
+ NULL);
+ }
+ fullAssemblyPath.CloseBuffer(dwCCFullAssemblyPath);
+
+ if (dwCCFullAssemblyPath == 0)
+ {
+ hr = HRESULT_FROM_GetLastError();
+ }
+ else
+ {
+ assemblyPath.Set(fullAssemblyPath);
+ }
+ }
+
+ return hr;
+ }
+
+#ifndef CROSSGEN_COMPILE
+ HRESULT CreateImageAssembly(IMDInternalImport *pIMetaDataAssemblyImport,
+ PEKIND PeKind,
+ PEImage *pPEImage,
+ PEImage *pNativePEImage,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+ ReleaseHolder<Assembly> pAssembly;
+ PathString asesmblyPath;
+
+ SAFE_NEW(pAssembly, Assembly);
+ IF_FAIL_GO(pAssembly->Init(pIMetaDataAssemblyImport,
+ PeKind,
+ pPEImage,
+ pNativePEImage,
+ asesmblyPath,
+ FALSE /* fIsInGAC */));
+
+ pBindResult->SetResult(pAssembly);
+ pBindResult->SetIsFirstRequest(TRUE);
+
+ Exit:
+ return hr;
+ }
+#endif // !CROSSGEN_COMPILE
+ };
+
+ /* static */
+ HRESULT AssemblyBinder::Startup()
+ {
+ STATIC_CONTRACT_NOTHROW;
+
+ HRESULT hr = S_OK;
+
+ // This should only be called once
+ _ASSERTE(g_BinderVariables == NULL);
+ g_BinderVariables = new Variables();
+ IF_FAIL_GO(g_BinderVariables->Init());
+
+ Exit:
+ return hr;
+ }
+
+
+ HRESULT AssemblyBinder::TranslatePEToArchitectureType(DWORD *pdwPAFlags, PEKIND *PeKind)
+ {
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pdwPAFlags != NULL);
+ _ASSERTE(PeKind != NULL);
+
+ CorPEKind CLRPeKind = (CorPEKind) pdwPAFlags[0];
+ DWORD dwImageType = pdwPAFlags[1];
+
+ *PeKind = peNone;
+
+ if(CLRPeKind == peNot)
+ {
+ // Not a PE. Shouldn't ever get here.
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
+ }
+ else
+ {
+ if ((CLRPeKind & peILonly) && !(CLRPeKind & pe32Plus) &&
+ !(CLRPeKind & pe32BitRequired) && dwImageType == IMAGE_FILE_MACHINE_I386)
+ {
+ // Processor-agnostic (MSIL)
+ *PeKind = peMSIL;
+ }
+ else if (CLRPeKind & pe32Plus)
+ {
+ // 64-bit
+ if (CLRPeKind & pe32BitRequired)
+ {
+ // Invalid
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
+ }
+
+ // Regardless of whether ILONLY is set or not, the architecture
+ // is the machine type.
+ if(dwImageType == IMAGE_FILE_MACHINE_ARM64)
+ *PeKind = peARM64;
+ else if (dwImageType == IMAGE_FILE_MACHINE_AMD64)
+ *PeKind = peAMD64;
+ else
+ {
+ // We don't support other architectures
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
+ }
+ }
+ else
+ {
+ // 32-bit, non-agnostic
+ if(dwImageType == IMAGE_FILE_MACHINE_I386)
+ *PeKind = peI386;
+ else if(dwImageType == IMAGE_FILE_MACHINE_ARMNT)
+ *PeKind = peARM;
+ else
+ {
+ // Not supported
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
+ }
+ }
+ }
+
+ Exit:
+ return hr;
+ }
+
+ // See code:BINDER_SPACE::AssemblyBinder::GetAssembly for info on fNgenExplicitBind
+ // and fExplicitBindToNativeImage, and see code:CEECompileInfo::LoadAssemblyByPath
+ // for an example of how they're used.
+ HRESULT AssemblyBinder::BindAssembly(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ LPCWSTR szCodeBase,
+ /* in */ PEAssembly *pParentAssembly,
+ /* in */ BOOL fNgenExplicitBind,
+ /* in */ BOOL fExplicitBindToNativeImage,
+ /* in */ bool excludeAppPaths,
+ /* out */ Assembly **ppAssembly)
+ {
+ HRESULT hr = S_OK;
+ LONG kContextVersion = 0;
+ BindResult bindResult;
+
+ // Tracing happens outside the binder lock to avoid calling into managed code within the lock
+ BinderTracing::ResolutionAttemptedOperation tracer{pAssemblyName, pApplicationContext->GetBinderID(), 0 /*managedALC*/, hr};
+
+#ifndef CROSSGEN_COMPILE
+ Retry:
+ {
+ // Lock the binding application context
+ CRITSEC_Holder contextLock(pApplicationContext->GetCriticalSectionCookie());
+#endif
+
+ if (szCodeBase == NULL)
+ {
+ IF_FAIL_GO(BindByName(pApplicationContext,
+ pAssemblyName,
+ false, // skipFailureCaching
+ false, // skipVersionCompatibilityCheck
+ excludeAppPaths,
+ &bindResult));
+ }
+ else
+ {
+ PathString assemblyPath(szCodeBase);
+
+ // Convert URL to full path and block HTTP downloads
+ IF_FAIL_GO(URLToFullPath(assemblyPath));
+ BOOL fDoNgenExplicitBind = fNgenExplicitBind;
+
+ // Only use explicit ngen binding in the new coreclr path-based binding model
+ if (!pApplicationContext->IsTpaListProvided())
+ {
+ fDoNgenExplicitBind = FALSE;
+ }
+
+ IF_FAIL_GO(BindWhereRef(pApplicationContext,
+ assemblyPath,
+ fDoNgenExplicitBind,
+ fExplicitBindToNativeImage,
+ excludeAppPaths,
+ &bindResult));
+ }
+
+ // Remember the post-bind version
+ kContextVersion = pApplicationContext->GetVersion();
+
+#ifndef CROSSGEN_COMPILE
+ } // lock(pApplicationContext)
+#endif
+
+ Exit:
+ tracer.TraceBindResult(bindResult);
+
+ if (bindResult.HaveResult())
+ {
+#ifndef CROSSGEN_COMPILE
+ BindResult hostBindResult;
+
+ hr = RegisterAndGetHostChosen(pApplicationContext,
+ kContextVersion,
+ &bindResult,
+ &hostBindResult);
+
+ if (hr == S_FALSE)
+ {
+ // Another bind interfered. We need to retry the entire bind.
+ // This by design loops as long as needed because by construction we eventually
+ // will succeed or fail the bind.
+ bindResult.Reset();
+ goto Retry;
+ }
+ else if (hr == S_OK)
+ {
+ *ppAssembly = hostBindResult.GetAsAssembly(TRUE /* fAddRef */);
+ }
+#else // CROSSGEN_COMPILE
+
+ *ppAssembly = bindResult.GetAsAssembly(TRUE /* fAddRef */);
+
+#endif // CROSSGEN_COMPILE
+ }
+
+ return hr;
+ }
+
+ /* static */
+ HRESULT AssemblyBinder::BindToSystem(SString &systemDirectory,
+ Assembly **ppSystemAssembly,
+ bool fBindToNativeImage)
+ {
+ // Indirect check that binder was initialized.
+ _ASSERTE(g_BinderVariables != NULL);
+
+ HRESULT hr = S_OK;
+
+ _ASSERTE(ppSystemAssembly != NULL);
+
+ ReleaseHolder<Assembly> pSystemAssembly;
+
+ // At run-time, System.Private.CoreLib.dll is expected to be the NI image.
+ // System.Private.CoreLib.dll is expected to be found at one of the following locations:
+ // * Non-single-file app: In systemDirectory, beside coreclr.dll
+ // * Framework-dependent single-file app: In systemDirectory, beside coreclr.dll
+ // * Self-contained single-file app: Within the single-file bundle.
+ //
+ // CoreLib path (sCoreLib):
+ // * Absolute path when looking for a file on disk
+ // * Bundle-relative path when looking within the single-file bundle.
+
+ StackSString sCoreLibName(CoreLibName_IL_W);
+ StackSString sCoreLib;
+ BinderTracing::PathSource pathSource = BinderTracing::PathSource::Bundle;
+ BundleFileLocation bundleFileLocation = Bundle::ProbeAppBundle(sCoreLibName, /*pathIsBundleRelative */ true);
+ if (!bundleFileLocation.IsValid())
+ {
+ pathSource = BinderTracing::PathSource::ApplicationAssemblies;
+ }
+ sCoreLib.Set(systemDirectory);
+ CombinePath(sCoreLib, sCoreLibName, sCoreLib);
+
+ hr = AssemblyBinder::GetAssembly(sCoreLib,
+ TRUE /* fIsInGAC */,
+ fBindToNativeImage,
+ &pSystemAssembly,
+ NULL /* szMDAssemblyPath */,
+ bundleFileLocation);
+ BinderTracing::PathProbed(sCoreLib, pathSource, hr);
+
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ // Try to find corelib in the TPA
+ StackSString sCoreLibSimpleName(CoreLibName_W);
+ StackSString sTrustedPlatformAssemblies = Configuration::GetKnobStringValue(W("TRUSTED_PLATFORM_ASSEMBLIES"));
+ sTrustedPlatformAssemblies.Normalize();
+
+ bool found = false;
+ for (SString::Iterator i = sTrustedPlatformAssemblies.Begin(); i != sTrustedPlatformAssemblies.End(); )
+ {
+ SString fileName;
+ SString simpleName;
+ bool isNativeImage = false;
+ HRESULT pathResult = S_OK;
+ IF_FAIL_GO(pathResult = GetNextTPAPath(sTrustedPlatformAssemblies, i, /*dllOnly*/ true, fileName, simpleName, isNativeImage));
+ if (pathResult == S_FALSE)
+ {
+ break;
+ }
+
+ if (simpleName.EqualsCaseInsensitive(sCoreLibSimpleName))
+ {
+ sCoreLib = fileName;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ GO_WITH_HRESULT(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
+ }
+
+ hr = AssemblyBinder::GetAssembly(sCoreLib,
+ TRUE /* fIsInGAC */,
+ fBindToNativeImage,
+ &pSystemAssembly,
+ NULL /* szMDAssemblyPath */,
+ bundleFileLocation);
+
+ BinderTracing::PathProbed(sCoreLib, BinderTracing::PathSource::ApplicationAssemblies, hr);
+ }
+
+ IF_FAIL_GO(hr);
+
+ *ppSystemAssembly = pSystemAssembly.Extract();
+
+ Exit:
+ return hr;
+ }
+
+
+ /* static */
+ HRESULT AssemblyBinder::BindToSystemSatellite(SString& systemDirectory,
+ SString& simpleName,
+ SString& cultureName,
+ Assembly** ppSystemAssembly)
+ {
+ // Indirect check that binder was initialized.
+ _ASSERTE(g_BinderVariables != NULL);
+
+ HRESULT hr = S_OK;
+
+ _ASSERTE(ppSystemAssembly != NULL);
+
+ // Satellite assembly's relative path
+ StackSString relativePath;
+
+ // append culture name
+ if (!cultureName.IsEmpty())
+ {
+ CombinePath(relativePath, cultureName, relativePath);
+ }
+
+ // append satellite assembly's simple name
+ CombinePath(relativePath, simpleName, relativePath);
+
+ // append extension
+ relativePath.Append(W(".dll"));
+
+ // Satellite assembly's path:
+ // * Absolute path when looking for a file on disk
+ // * Bundle-relative path when looking within the single-file bundle.
+ StackSString sCoreLibSatellite;
+
+ BinderTracing::PathSource pathSource = BinderTracing::PathSource::Bundle;
+ BundleFileLocation bundleFileLocation = Bundle::ProbeAppBundle(relativePath, /*pathIsBundleRelative */ true);
+ if (!bundleFileLocation.IsValid())
+ {
+ sCoreLibSatellite.Set(systemDirectory);
+ pathSource = BinderTracing::PathSource::ApplicationAssemblies;
+ }
+ CombinePath(sCoreLibSatellite, relativePath, sCoreLibSatellite);
+
+ ReleaseHolder<Assembly> pSystemAssembly;
+ IF_FAIL_GO(AssemblyBinder::GetAssembly(sCoreLibSatellite,
+ TRUE /* fIsInGAC */,
+ FALSE /* fExplicitBindToNativeImage */,
+ &pSystemAssembly,
+ NULL /* szMDAssemblyPath */,
+ bundleFileLocation));
+ BinderTracing::PathProbed(sCoreLibSatellite, pathSource, hr);
+
+ *ppSystemAssembly = pSystemAssembly.Extract();
+
+ Exit:
+ return hr;
+ }
+
+ /* static */
+ HRESULT AssemblyBinder::BindByName(ApplicationContext *pApplicationContext,
+ AssemblyName *pAssemblyName,
+ bool skipFailureCaching,
+ bool skipVersionCompatibilityCheck,
+ bool excludeAppPaths,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+ PathString assemblyDisplayName;
+
+ // Look for already cached binding failure (ignore PA, every PA will lock the context)
+ pAssemblyName->GetDisplayName(assemblyDisplayName,
+ AssemblyName::INCLUDE_VERSION);
+
+ hr = pApplicationContext->GetFailureCache()->Lookup(assemblyDisplayName);
+ if (FAILED(hr))
+ {
+ if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) && skipFailureCaching)
+ {
+ // Ignore pre-existing transient bind error (re-bind will succeed)
+ pApplicationContext->GetFailureCache()->Remove(assemblyDisplayName);
+ }
+
+ goto LogExit;
+ }
+ else if (hr == S_FALSE)
+ {
+ // workaround: Special case for byte arrays. Rerun the bind to create binding log.
+ pAssemblyName->SetIsDefinition(TRUE);
+ hr = S_OK;
+ }
+
+ if (!Assembly::IsValidArchitecture(pAssemblyName->GetArchitecture()))
+ {
+ // Assembly reference contains wrong architecture
+ IF_FAIL_GO(FUSION_E_INVALID_NAME);
+ }
+
+ IF_FAIL_GO(BindLocked(pApplicationContext,
+ pAssemblyName,
+ skipVersionCompatibilityCheck,
+ excludeAppPaths,
+ pBindResult));
+
+ if (!pBindResult->HaveResult())
+ {
+ // Behavior rules are clueless now
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
+ }
+
+ Exit:
+ if (FAILED(hr))
+ {
+ if (skipFailureCaching)
+ {
+ if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ // Cache non-transient bind error for byte-array
+ hr = S_FALSE;
+ }
+ else
+ {
+ // Ignore transient bind error (re-bind will succeed)
+ goto LogExit;
+ }
+ }
+
+ hr = pApplicationContext->AddToFailureCache(assemblyDisplayName, hr);
+ }
+
+ LogExit:
+ return hr;
+ }
+
+ /* static */
+ // See code:BINDER_SPACE::AssemblyBinder::GetAssembly for info on fNgenExplicitBind
+ // and fExplicitBindToNativeImage, and see code:CEECompileInfo::LoadAssemblyByPath
+ // for an example of how they're used.
+ HRESULT AssemblyBinder::BindWhereRef(ApplicationContext *pApplicationContext,
+ PathString &assemblyPath,
+ BOOL fNgenExplicitBind,
+ BOOL fExplicitBindToNativeImage,
+ bool excludeAppPaths,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+
+ ReleaseHolder<Assembly> pAssembly;
+ BindResult lockedBindResult;
+
+ // Look for already cached binding failure
+ hr = pApplicationContext->GetFailureCache()->Lookup(assemblyPath);
+ if (FAILED(hr))
+ {
+ goto LogExit;
+ }
+
+ // If we return this assembly, then it is guaranteed to be not in GAC
+ // Design decision. For now, keep the V2 model of Fusion being oblivious of the strong name.
+ // Security team did not see any security concern with interpreting the version information.
+ IF_FAIL_GO(GetAssembly(assemblyPath,
+ FALSE /* fIsInGAC */,
+
+ // Pass through caller's intent of whether to bind to the
+ // NI using an explicit path to the NI that was
+ // specified. Generally only NGEN PDB generation has
+ // this TRUE.
+ fExplicitBindToNativeImage,
+ &pAssembly,
+ NULL /* szMDAssemblyPath */,
+ Bundle::ProbeAppBundle(assemblyPath)));
+
+ AssemblyName *pAssemblyName;
+ pAssemblyName = pAssembly->GetAssemblyName();
+
+ if (!fNgenExplicitBind)
+ {
+ IF_FAIL_GO(BindLocked(pApplicationContext,
+ pAssemblyName,
+ false, // skipVersionCompatibilityCheck
+ excludeAppPaths,
+ &lockedBindResult));
+ if (lockedBindResult.HaveResult())
+ {
+ pBindResult->SetResult(&lockedBindResult);
+ GO_WITH_HRESULT(S_OK);
+ }
+ }
+
+ hr = S_OK;
+ pBindResult->SetResult(pAssembly);
+
+ Exit:
+
+ if (FAILED(hr))
+ {
+ // Always cache binding failures
+ hr = pApplicationContext->AddToFailureCache(assemblyPath, hr);
+ }
+
+ LogExit:
+ return hr;
+ }
+
+ /* static */
+ HRESULT AssemblyBinder::BindLocked(ApplicationContext *pApplicationContext,
+ AssemblyName *pAssemblyName,
+ bool skipVersionCompatibilityCheck,
+ bool excludeAppPaths,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+
+ bool isTpaListProvided = pApplicationContext->IsTpaListProvided();
+#ifndef CROSSGEN_COMPILE
+ ContextEntry *pContextEntry = NULL;
+ hr = FindInExecutionContext(pApplicationContext, pAssemblyName, &pContextEntry);
+
+ // Add the attempt to the bind result on failure / not found. On success, it will be added after the version check.
+ if (FAILED(hr) || pContextEntry == NULL)
+ pBindResult->SetAttemptResult(hr, pContextEntry);
+
+ IF_FAIL_GO(hr);
+ if (pContextEntry != NULL)
+ {
+ if (!skipVersionCompatibilityCheck)
+ {
+ // Can't give higher version than already bound
+ bool isCompatible = IsCompatibleAssemblyVersion(pAssemblyName, pContextEntry->GetAssemblyName());
+ hr = isCompatible ? S_OK : FUSION_E_APP_DOMAIN_LOCKED;
+ pBindResult->SetAttemptResult(hr, pContextEntry);
+
+ // TPA binder returns FUSION_E_REF_DEF_MISMATCH for incompatible version
+ if (hr == FUSION_E_APP_DOMAIN_LOCKED && isTpaListProvided)
+ hr = FUSION_E_REF_DEF_MISMATCH;
+ }
+ else
+ {
+ pBindResult->SetAttemptResult(hr, pContextEntry);
+ }
+
+ IF_FAIL_GO(hr);
+
+ pBindResult->SetResult(pContextEntry);
+ }
+ else
+#endif // !CROSSGEN_COMPILE
+ if (isTpaListProvided)
+ {
+ // BindByTpaList handles setting attempt results on the bind result
+ hr = BindByTpaList(pApplicationContext,
+ pAssemblyName,
+ excludeAppPaths,
+ pBindResult);
+ if (SUCCEEDED(hr) && pBindResult->HaveResult())
+ {
+ bool isCompatible = IsCompatibleAssemblyVersion(pAssemblyName, pBindResult->GetAssemblyName());
+ hr = isCompatible ? S_OK : FUSION_E_APP_DOMAIN_LOCKED;
+ pBindResult->SetAttemptResult(hr, pBindResult->GetAsAssembly());
+
+ // TPA binder returns FUSION_E_REF_DEF_MISMATCH for incompatible version
+ if (hr == FUSION_E_APP_DOMAIN_LOCKED && isTpaListProvided)
+ hr = FUSION_E_REF_DEF_MISMATCH;
+ }
+
+ if (FAILED(hr))
+ {
+ pBindResult->SetNoResult();
+ }
+ IF_FAIL_GO(hr);
+ }
+ Exit:
+ return hr;
+ }
+
+#ifndef CROSSGEN_COMPILE
+ /* static */
+ HRESULT AssemblyBinder::FindInExecutionContext(ApplicationContext *pApplicationContext,
+ AssemblyName *pAssemblyName,
+ ContextEntry **ppContextEntry)
+ {
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pApplicationContext != NULL);
+ _ASSERTE(pAssemblyName != NULL);
+ _ASSERTE(ppContextEntry != NULL);
+
+ ExecutionContext *pExecutionContext = pApplicationContext->GetExecutionContext();
+ ContextEntry *pContextEntry = pExecutionContext->Lookup(pAssemblyName);
+
+ // Set any found context entry. It is up to the caller to check the returned HRESULT
+ // for errors due to validation
+ *ppContextEntry = pContextEntry;
+ if (pContextEntry != NULL)
+ {
+ AssemblyName *pContextName = pContextEntry->GetAssemblyName();
+ if (pAssemblyName->GetIsDefinition() &&
+ (pContextName->GetArchitecture() != pAssemblyName->GetArchitecture()))
+ {
+ return FUSION_E_APP_DOMAIN_LOCKED;
+ }
+ }
+
+ return pContextEntry != NULL ? S_OK : S_FALSE;
+ }
+
+#endif //CROSSGEN_COMPILE
+
+ //
+ // Tests whether a candidate assembly's name matches the requested.
+ // This does not do a version check. The binder applies version policy
+ // further up the stack once it gets a successful bind.
+ //
+ BOOL TestCandidateRefMatchesDef(AssemblyName *pRequestedAssemblyName,
+ AssemblyName *pBoundAssemblyName,
+ BOOL tpaListAssembly)
+ {
+ DWORD dwIncludeFlags = AssemblyName::INCLUDE_DEFAULT;
+
+ if (!tpaListAssembly)
+ {
+ SString &culture = pRequestedAssemblyName->GetCulture();
+ if (culture.IsEmpty() || culture.EqualsCaseInsensitive(g_BinderVariables->cultureNeutral))
+ {
+ dwIncludeFlags |= AssemblyName::EXCLUDE_CULTURE;
+ }
+ }
+
+ if (pRequestedAssemblyName->GetArchitecture() != peNone)
+ {
+ dwIncludeFlags |= AssemblyName::INCLUDE_ARCHITECTURE;
+ }
+
+ return pBoundAssemblyName->Equals(pRequestedAssemblyName, dwIncludeFlags);
+ }
+
+ namespace
+ {
+ HRESULT BindSatelliteResourceFromBundle(
+ AssemblyName* pRequestedAssemblyName,
+ SString &relativePath,
+ BindResult* pBindResult)
+ {
+ HRESULT hr = S_OK;
+
+ BundleFileLocation bundleFileLocation = Bundle::ProbeAppBundle(relativePath, /* pathIsBundleRelative */ true);
+ if (!bundleFileLocation.IsValid())
+ {
+ return hr;
+ }
+
+ ReleaseHolder<Assembly> pAssembly;
+ hr = AssemblyBinder::GetAssembly(relativePath,
+ FALSE /* fIsInGAC */,
+ FALSE /* fExplicitBindToNativeImage */,
+ &pAssembly,
+ NULL, // szMDAssemblyPath
+ bundleFileLocation);
+
+ BinderTracing::PathProbed(relativePath, BinderTracing::PathSource::Bundle, hr);
+
+ // Missing files are okay and expected when probing
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ return S_OK;
+ }
+
+ pBindResult->SetAttemptResult(hr, pAssembly);
+ if (FAILED(hr))
+ return hr;
+
+ AssemblyName* pBoundAssemblyName = pAssembly->GetAssemblyName();
+ if (TestCandidateRefMatchesDef(pRequestedAssemblyName, pBoundAssemblyName, false /*tpaListAssembly*/))
+ {
+ pBindResult->SetResult(pAssembly);
+ hr = S_OK;
+ }
+ else
+ {
+ hr = FUSION_E_REF_DEF_MISMATCH;
+ }
+
+ pBindResult->SetAttemptResult(hr, pAssembly);
+ return hr;
+ }
+
+ HRESULT BindSatelliteResourceByProbingPaths(
+ const StringArrayList *pResourceRoots,
+ AssemblyName *pRequestedAssemblyName,
+ SString &relativePath,
+ BindResult *pBindResult,
+ BinderTracing::PathSource pathSource)
+ {
+ HRESULT hr = S_OK;
+
+ for (UINT i = 0; i < pResourceRoots->GetCount(); i++)
+ {
+ ReleaseHolder<Assembly> pAssembly;
+ SString &wszBindingPath = (*pResourceRoots)[i];
+ SString fileName(wszBindingPath);
+ CombinePath(fileName, relativePath, fileName);
+
+ hr = AssemblyBinder::GetAssembly(fileName,
+ FALSE /* fIsInGAC */,
+ FALSE /* fExplicitBindToNativeImage */,
+ &pAssembly);
+ BinderTracing::PathProbed(fileName, pathSource, hr);
+
+ // Missing files are okay and expected when probing
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ continue;
+ }
+
+ pBindResult->SetAttemptResult(hr, pAssembly);
+ if (FAILED(hr))
+ return hr;
+
+ AssemblyName *pBoundAssemblyName = pAssembly->GetAssemblyName();
+ if (TestCandidateRefMatchesDef(pRequestedAssemblyName, pBoundAssemblyName, false /*tpaListAssembly*/))
+ {
+ pBindResult->SetResult(pAssembly);
+ hr = S_OK;
+ }
+ else
+ {
+ hr = FUSION_E_REF_DEF_MISMATCH;
+ }
+
+ pBindResult->SetAttemptResult(hr, pAssembly);
+ return hr;
+ }
+
+ // Up-stack expects S_OK when we don't find any candidate assemblies and no fatal error occurred (ie, no S_FALSE)
+ return S_OK;
+ }
+
+ HRESULT BindSatelliteResource(
+ ApplicationContext* pApplicationContext,
+ AssemblyName* pRequestedAssemblyName,
+ BindResult* pBindResult)
+ {
+ // Satellite resource probing strategy is to look:
+ // * First within the single-file bundle
+ // * Then under each of the Platform Resource Roots
+ // * Then under each of the App Paths.
+ //
+ // During each search, if we find a platform resource file with matching file name, but whose ref-def didn't match,
+ // fall back to application resource lookup to handle case where a user creates resources with the same
+ // names as platform ones.
+
+ HRESULT hr = S_OK;
+ SString& simpleNameRef = pRequestedAssemblyName->GetSimpleName();
+ SString& cultureRef = pRequestedAssemblyName->GetCulture();
+
+ _ASSERTE(!cultureRef.IsEmpty() && !cultureRef.EqualsCaseInsensitive(g_BinderVariables->cultureNeutral));
+
+ ReleaseHolder<Assembly> pAssembly;
+ SString fileName;
+ CombinePath(fileName, cultureRef, fileName);
+ CombinePath(fileName, simpleNameRef, fileName);
+ fileName.Append(W(".dll"));
+
+ hr = BindSatelliteResourceFromBundle(pRequestedAssemblyName, fileName, pBindResult);
+
+ if (pBindResult->HaveResult() || (FAILED(hr) && hr != FUSION_E_CONFIGURATION_ERROR))
+ {
+ return hr;
+ }
+
+ hr = BindSatelliteResourceByProbingPaths(pApplicationContext->GetPlatformResourceRoots(),
+ pRequestedAssemblyName,
+ fileName,
+ pBindResult,
+ BinderTracing::PathSource::PlatformResourceRoots);
+
+ if (pBindResult->HaveResult() || (FAILED(hr) && hr != FUSION_E_CONFIGURATION_ERROR))
+ {
+ return hr;
+ }
+
+ hr = BindSatelliteResourceByProbingPaths(pApplicationContext->GetAppPaths(),
+ pRequestedAssemblyName,
+ fileName,
+ pBindResult,
+ BinderTracing::PathSource::AppPaths);
+
+ return hr;
+ }
+
+ HRESULT BindAssemblyByProbingPaths(
+ const StringArrayList *pBindingPaths,
+ AssemblyName *pRequestedAssemblyName,
+ bool useNativeImages,
+ Assembly **ppAssembly)
+ {
+ SString &simpleName = pRequestedAssemblyName->GetSimpleName();
+ BinderTracing::PathSource pathSource = useNativeImages ? BinderTracing::PathSource::AppNativeImagePaths : BinderTracing::PathSource::AppPaths;
+ // Loop through the binding paths looking for a matching assembly
+ for (DWORD i = 0; i < pBindingPaths->GetCount(); i++)
+ {
+ HRESULT hr;
+ ReleaseHolder<Assembly> pAssembly;
+ LPCWSTR wszBindingPath = (*pBindingPaths)[i];
+
+ PathString fileNameWithoutExtension(wszBindingPath);
+ CombinePath(fileNameWithoutExtension, simpleName, fileNameWithoutExtension);
+
+ // Look for a matching dll first
+ PathString fileName(fileNameWithoutExtension);
+ fileName.Append(useNativeImages ? W(".ni.dll") : W(".dll"));
+ hr = AssemblyBinder::GetAssembly(fileName,
+ FALSE, // fIsInGAC
+ useNativeImages, // fExplicitBindToNativeImage
+ &pAssembly);
+ BinderTracing::PathProbed(fileName, pathSource, hr);
+
+ if (FAILED(hr))
+ {
+ fileName.Set(fileNameWithoutExtension);
+ fileName.Append(useNativeImages ? W(".ni.exe") : W(".exe"));
+ hr = AssemblyBinder::GetAssembly(fileName,
+ FALSE, // fIsInGAC
+ useNativeImages, // fExplicitBindToNativeImage
+ &pAssembly);
+ BinderTracing::PathProbed(fileName, pathSource, hr);
+ }
+
+ // Since we're probing, file not founds are ok and we should just try another
+ // probing path
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ continue;
+ }
+
+ // Set any found assembly. It is up to the caller to check the returned HRESULT for errors due to validation
+ *ppAssembly = pAssembly.Extract();
+ if (FAILED(hr))
+ return hr;
+
+ // We found a candidate.
+ //
+ // Below this point, we either establish that the ref-def matches, or
+ // we fail the bind.
+
+ // Compare requested AssemblyName with that from the candidate assembly
+ if (!TestCandidateRefMatchesDef(pRequestedAssemblyName, pAssembly->GetAssemblyName(), false /*tpaListAssembly*/))
+ return FUSION_E_REF_DEF_MISMATCH;
+
+ return S_OK;
+ }
+
+ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ }
+ }
+
+ /*
+ * BindByTpaList is the entry-point for the custom binding algorithm in CoreCLR.
+ *
+ * The search for assemblies will proceed in the following order:
+ *
+ * If this application is a single-file bundle, the meta-data contained in the bundle
+ * will be probed to find the requested assembly. If the assembly is not found,
+ * The list of platform assemblies (TPAs) are considered next.
+ *
+ * Platform assemblies are specified as a list of files. This list is the only set of
+ * assemblies that we will load as platform. They can be specified as IL or NIs.
+ *
+ * Resources for platform assemblies are located by probing starting at the Platform Resource Roots,
+ * a set of folders configured by the host.
+ *
+ * If a requested assembly identity cannot be found in the TPA list or the resource roots,
+ * it is considered an application assembly. We probe for application assemblies in one of two
+ * sets of paths: the AppNiPaths, a list of paths containing native images, and the AppPaths, a
+ * list of paths containing IL files and satellite resource folders.
+ *
+ */
+ /* static */
+ HRESULT AssemblyBinder::BindByTpaList(ApplicationContext *pApplicationContext,
+ AssemblyName *pRequestedAssemblyName,
+ bool excludeAppPaths,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+
+ SString &culture = pRequestedAssemblyName->GetCulture();
+ bool fPartialMatchOnTpa = false;
+
+ if (!culture.IsEmpty() && !culture.EqualsCaseInsensitive(g_BinderVariables->cultureNeutral))
+ {
+ IF_FAIL_GO(BindSatelliteResource(pApplicationContext, pRequestedAssemblyName, pBindResult));
+ }
+ else
+ {
+ ReleaseHolder<Assembly> pTPAAssembly;
+ SString& simpleName = pRequestedAssemblyName->GetSimpleName();
+
+ // Is assembly in the bundle?
+ // Single-file bundle contents take precedence over TPA.
+ // The list of bundled assemblies is contained in the bundle manifest, and NOT in the TPA.
+ // Therefore the bundle is first probed using the assembly's simple name.
+ // If found, the assembly is loaded from the bundle.
+ if (Bundle::AppIsBundle())
+ {
+ // Search Assembly.ni.dll, then Assembly.dll
+ // The Assembly.ni.dll paths are rare, and intended for supporting managed C++ R2R assemblies.
+ SString candidates[] = { W(".ni.dll"), W(".dll") };
+
+ // Loop through the binding paths looking for a matching assembly
+ for (int i = 0; i < 2; i++)
+ {
+ SString assemblyFileName(simpleName);
+ assemblyFileName.Append(candidates[i]);
+
+ SString assemblyFilePath(Bundle::AppBundle->BasePath());
+ assemblyFilePath.Append(assemblyFileName);
+
+ BundleFileLocation bundleFileLocation = Bundle::ProbeAppBundle(assemblyFileName, /* pathIsBundleRelative */ true);
+ if (bundleFileLocation.IsValid())
+ {
+ hr = GetAssembly(assemblyFilePath,
+ TRUE, // fIsInGAC
+ FALSE, // fExplicitBindToNativeImage
+ &pTPAAssembly,
+ NULL, // szMDAssemblyPath
+ bundleFileLocation);
+
+ BinderTracing::PathProbed(assemblyFilePath, BinderTracing::PathSource::Bundle, hr);
+
+ if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ // Any other error is fatal
+ IF_FAIL_GO(hr);
+
+ if (TestCandidateRefMatchesDef(pRequestedAssemblyName, pTPAAssembly->GetAssemblyName(), true /*tpaListAssembly*/))
+ {
+ // We have found the requested assembly match in the bundle with validation of the full-qualified name.
+ // Bind to it.
+ pBindResult->SetResult(pTPAAssembly);
+ GO_WITH_HRESULT(S_OK);
+ }
+ }
+ }
+ }
+ }
+
+ // Is assembly on TPA list?
+ SimpleNameToFileNameMap * tpaMap = pApplicationContext->GetTpaList();
+ const SimpleNameToFileNameMapEntry *pTpaEntry = tpaMap->LookupPtr(simpleName.GetUnicode());
+ if (pTpaEntry != nullptr)
+ {
+ if (pTpaEntry->m_wszNIFileName != nullptr)
+ {
+ SString fileName(pTpaEntry->m_wszNIFileName);
+
+ hr = GetAssembly(fileName,
+ TRUE, // fIsInGAC
+ TRUE, // fExplicitBindToNativeImage
+ &pTPAAssembly);
+ BinderTracing::PathProbed(fileName, BinderTracing::PathSource::ApplicationAssemblies, hr);
+ }
+ else
+ {
+ _ASSERTE(pTpaEntry->m_wszILFileName != nullptr);
+ SString fileName(pTpaEntry->m_wszILFileName);
+
+ hr = GetAssembly(fileName,
+ TRUE, // fIsInGAC
+ FALSE, // fExplicitBindToNativeImage
+ &pTPAAssembly);
+ BinderTracing::PathProbed(fileName, BinderTracing::PathSource::ApplicationAssemblies, hr);
+ }
+
+ pBindResult->SetAttemptResult(hr, pTPAAssembly);
+
+ // On file not found, simply fall back to app path probing
+ if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ // Any other error is fatal
+ IF_FAIL_GO(hr);
+
+ if (TestCandidateRefMatchesDef(pRequestedAssemblyName, pTPAAssembly->GetAssemblyName(), true /*tpaListAssembly*/))
+ {
+ // We have found the requested assembly match on TPA with validation of the full-qualified name. Bind to it.
+ pBindResult->SetResult(pTPAAssembly);
+ pBindResult->SetAttemptResult(S_OK, pTPAAssembly);
+ GO_WITH_HRESULT(S_OK);
+ }
+ else
+ {
+ // We found the assembly on TPA but it didn't match the RequestedAssembly assembly-name. In this case, lets proceed to see if we find the requested
+ // assembly in the App paths.
+ pBindResult->SetAttemptResult(FUSION_E_REF_DEF_MISMATCH, pTPAAssembly);
+ fPartialMatchOnTpa = true;
+ }
+ }
+
+ // We either didn't find a candidate, or the ref-def failed. Either way; fall back to app path probing.
+ }
+
+ if (!excludeAppPaths)
+ {
+ // Probe AppNiPaths first, then AppPaths
+ ReleaseHolder<Assembly> pAssembly;
+ hr = BindAssemblyByProbingPaths(pApplicationContext->GetAppNiPaths(),
+ pRequestedAssemblyName,
+ true, // useNativeImages
+ &pAssembly);
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ hr = BindAssemblyByProbingPaths(pApplicationContext->GetAppPaths(),
+ pRequestedAssemblyName,
+ false, // useNativeImages
+ &pAssembly);
+ }
+
+ pBindResult->SetAttemptResult(hr, pAssembly);
+ if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ IF_FAIL_GO(hr);
+
+ // At this point, we have found an assembly with the expected name in the App paths. If this was also found on TPA,
+ // make sure that the app assembly has the same fullname (excluding version) as the TPA version. If it does, then
+ // we should bind to the TPA assembly. If it does not, then bind to the app assembly since it has a different fullname than the
+ // TPA assembly.
+ if (fPartialMatchOnTpa)
+ {
+ if (TestCandidateRefMatchesDef(pAssembly->GetAssemblyName(), pTPAAssembly->GetAssemblyName(), true /*tpaListAssembly*/))
+ {
+ // Fullname (SimpleName+Culture+PKT) matched for TPA and app assembly - so bind to TPA instance.
+ pBindResult->SetResult(pTPAAssembly);
+ pBindResult->SetAttemptResult(hr, pTPAAssembly);
+ GO_WITH_HRESULT(S_OK);
+ }
+ else
+ {
+ // Fullname (SimpleName+Culture+PKT) did not match for TPA and app assembly - so bind to app instance.
+ pBindResult->SetResult(pAssembly);
+ GO_WITH_HRESULT(S_OK);
+ }
+ }
+ else
+ {
+ // We didn't see this assembly on TPA - so simply bind to the app instance.
+ pBindResult->SetResult(pAssembly);
+ GO_WITH_HRESULT(S_OK);
+ }
+ }
+ }
+ }
+
+ // Couldn't find a matching assembly in any of the probing paths
+ // Return S_FALSE here. BindByName will interpret a successful HRESULT
+ // and lack of BindResult as a failure to find a matching assembly.
+ hr = S_FALSE;
+
+ Exit:
+ return hr;
+ }
+
+ /* static */
+ HRESULT AssemblyBinder::GetAssembly(SString &assemblyPath,
+ BOOL fIsInGAC,
+
+ // When binding to the native image, should we
+ // assume assemblyPath explicitly specifies that
+ // NI? (If not, infer the path to the NI
+ // implicitly.)
+ BOOL fExplicitBindToNativeImage,
+
+ Assembly **ppAssembly,
+
+ // If assemblyPath refers to a native image without metadata,
+ // szMDAssemblyPath gives the alternative file to get metadata.
+ LPCTSTR szMDAssemblyPath,
+ BundleFileLocation bundleFileLocation)
+ {
+ HRESULT hr = S_OK;
+
+ _ASSERTE(ppAssembly != NULL);
+
+ ReleaseHolder<Assembly> pAssembly;
+ ReleaseHolder<IMDInternalImport> pIMetaDataAssemblyImport;
+ DWORD dwPAFlags[2];
+ PEKIND PeKind = peNone;
+ PEImage *pPEImage = NULL;
+ PEImage *pNativePEImage = NULL;
+
+ // Allocate assembly object
+ SAFE_NEW(pAssembly, Assembly);
+
+ // Obtain assembly meta data
+ {
+ LPCTSTR szAssemblyPath = const_cast<LPCTSTR>(assemblyPath.GetUnicode());
+
+ hr = BinderAcquirePEImage(szAssemblyPath, &pPEImage, &pNativePEImage, fExplicitBindToNativeImage, bundleFileLocation);
+ IF_FAIL_GO(hr);
+
+ // If we found a native image, it might be an MSIL assembly masquerading as an native image
+ // as a fallback mechanism for when the Triton tool chain wasn't able to generate a native image.
+ // In that case it will not have a native header, so just treat it like the MSIL assembly it is.
+ if (pNativePEImage)
+ {
+ BOOL hasHeader = TRUE;
+ IF_FAIL_GO(BinderHasNativeHeader(pNativePEImage, &hasHeader));
+ if (!hasHeader)
+ {
+ BinderReleasePEImage(pPEImage);
+ BinderReleasePEImage(pNativePEImage);
+
+ hr = BinderAcquirePEImage(szAssemblyPath, &pPEImage, &pNativePEImage, false, bundleFileLocation);
+ IF_FAIL_GO(hr);
+ }
+ }
+
+ if (pNativePEImage)
+ hr = BinderAcquireImport(pNativePEImage, &pIMetaDataAssemblyImport, dwPAFlags, TRUE);
+ else
+ hr = BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, FALSE);
+
+ IF_FAIL_GO(hr);
+
+ if (pIMetaDataAssemblyImport == NULL && pNativePEImage != NULL)
+ {
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
+ }
+
+ IF_FAIL_GO(TranslatePEToArchitectureType(dwPAFlags, &PeKind));
+ }
+
+ // Initialize assembly object
+ IF_FAIL_GO(pAssembly->Init(pIMetaDataAssemblyImport,
+ PeKind,
+ pPEImage,
+ pNativePEImage,
+ assemblyPath,
+ fIsInGAC));
+
+ // We're done
+ *ppAssembly = pAssembly.Extract();
+
+ Exit:
+
+ BinderReleasePEImage(pPEImage);
+ BinderReleasePEImage(pNativePEImage);
+
+ // Normalize file not found
+ if ((FAILED(hr)) && IsFileNotFound(hr))
+ {
+ hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ }
+
+ return hr;
+ }
+
+#ifndef CROSSGEN_COMPILE
+
+ /* static */
+ HRESULT AssemblyBinder::Register(ApplicationContext *pApplicationContext,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+
+ _ASSERTE(!pBindResult->GetIsContextBound());
+
+ pApplicationContext->IncrementVersion();
+
+ // Register the bindResult in the ExecutionContext only if we dont have it already.
+ // This method is invoked under a lock (by its caller), so we are thread safe.
+ ContextEntry *pContextEntry = NULL;
+ hr = FindInExecutionContext(pApplicationContext, pBindResult->GetAssemblyName(), &pContextEntry);
+ if (SUCCEEDED(hr))
+ {
+ if (pContextEntry == NULL)
+ {
+ ExecutionContext *pExecutionContext = pApplicationContext->GetExecutionContext();
+ IF_FAIL_GO(pExecutionContext->Register(pBindResult));
+ }
+ else
+ {
+ // Update the BindResult with the contents of the ContextEntry we found
+ pBindResult->SetResult(pContextEntry);
+ }
+ }
+
+ Exit:
+ return hr;
+ }
+
+ /* static */
+ HRESULT AssemblyBinder::RegisterAndGetHostChosen(ApplicationContext *pApplicationContext,
+ LONG kContextVersion,
+ BindResult *pBindResult,
+ BindResult *pHostBindResult)
+ {
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pBindResult != NULL);
+ _ASSERTE(pBindResult->HaveResult());
+ _ASSERTE(pHostBindResult != NULL);
+
+ if (!pBindResult->GetIsContextBound())
+ {
+ pHostBindResult->SetResult(pBindResult);
+
+ {
+ // Lock the application context
+ CRITSEC_Holder contextLock(pApplicationContext->GetCriticalSectionCookie());
+
+ // Only perform costly validation if other binds succeded before us
+ if (kContextVersion != pApplicationContext->GetVersion())
+ {
+ IF_FAIL_GO(AssemblyBinder::OtherBindInterfered(pApplicationContext,
+ pBindResult));
+
+ if (hr == S_FALSE)
+ {
+ // Another bind interfered
+ GO_WITH_HRESULT(hr);
+ }
+ }
+
+ // No bind interfered, we can now register
+ IF_FAIL_GO(Register(pApplicationContext,
+ pHostBindResult));
+ }
+ }
+ else
+ {
+ // No work required. Return the input
+ pHostBindResult->SetResult(pBindResult);
+ }
+
+ Exit:
+ return hr;
+ }
+
+ /* static */
+ HRESULT AssemblyBinder::OtherBindInterfered(ApplicationContext *pApplicationContext,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_FALSE;
+ AssemblyName *pAssemblyName = pBindResult->GetAssemblyName();
+ PathString assemblyDisplayName;
+
+ _ASSERTE(pAssemblyName != NULL);
+
+ // Look for already cached binding failure (ignore PA, every PA will lock the context)
+ pAssemblyName->GetDisplayName(assemblyDisplayName, AssemblyName::INCLUDE_VERSION);
+ hr = pApplicationContext->GetFailureCache()->Lookup(assemblyDisplayName);
+
+ if (hr == S_OK)
+ {
+ ContextEntry *pContextEntry = NULL;
+
+ hr = FindInExecutionContext(pApplicationContext, pAssemblyName, &pContextEntry);
+
+ if (SUCCEEDED(hr) && (pContextEntry == NULL))
+ {
+ // We can accept this bind in the domain
+ GO_WITH_HRESULT(S_OK);
+ }
+ }
+
+ // Some other bind interfered
+ GO_WITH_HRESULT(S_FALSE);
+
+ Exit:
+ return hr;
+ }
+
+#endif //CROSSGEN_COMPILE
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+HRESULT AssemblyBinder::BindUsingHostAssemblyResolver(/* in */ INT_PTR pManagedAssemblyLoadContextToBindWithin,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ IAssemblyName *pIAssemblyName,
+ /* in */ CLRPrivBinderCoreCLR *pTPABinder,
+ /* out */ Assembly **ppAssembly)
+{
+ HRESULT hr = E_FAIL;
+
+ _ASSERTE(pManagedAssemblyLoadContextToBindWithin != NULL);
+
+ // RuntimeInvokeHostAssemblyResolver will perform steps 2-4 of CLRPrivBinderAssemblyLoadContext::BindAssemblyByName.
+ ICLRPrivAssembly *pLoadedAssembly = NULL;
+ hr = RuntimeInvokeHostAssemblyResolver(pManagedAssemblyLoadContextToBindWithin, pIAssemblyName,
+ pTPABinder, pAssemblyName, &pLoadedAssembly);
+ if (SUCCEEDED(hr))
+ {
+ _ASSERTE(pLoadedAssembly != NULL);
+ *ppAssembly = static_cast<Assembly *>(pLoadedAssembly);
+ }
+
+ return hr;
+}
+
+/* static */
+HRESULT AssemblyBinder::BindUsingPEImage(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ BINDER_SPACE::AssemblyName *pAssemblyName,
+ /* in */ PEImage *pPEImage,
+ /* in */ PEKIND peKind,
+ /* in */ IMDInternalImport *pIMetaDataAssemblyImport,
+ /* [retval] [out] */ Assembly **ppAssembly)
+{
+ HRESULT hr = E_FAIL;
+
+ // Indirect check that binder was initialized.
+ _ASSERTE(g_BinderVariables != NULL);
+
+ LONG kContextVersion = 0;
+ BindResult bindResult;
+
+ // Prepare binding data
+ *ppAssembly = NULL;
+
+ // Tracing happens outside the binder lock to avoid calling into managed code within the lock
+ BinderTracing::ResolutionAttemptedOperation tracer{pAssemblyName, pApplicationContext->GetBinderID(), 0 /*managedALC*/, hr};
+
+ // Attempt the actual bind (eventually more than once)
+Retry:
+ bool mvidMismatch = false;
+ {
+ // Lock the application context
+ CRITSEC_Holder contextLock(pApplicationContext->GetCriticalSectionCookie());
+
+ // Attempt uncached bind and register stream if possible
+ // We skip version compatibility check - so assemblies with same simple name will be reported
+ // as a successful bind. Below we compare MVIDs in that case instead (which is a more precise equality check).
+ hr = BindByName(pApplicationContext,
+ pAssemblyName,
+ true, // skipFailureCaching
+ true, // skipVersionCompatibilityCheck
+ false, // excludeAppPaths
+ &bindResult);
+
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ IF_FAIL_GO(CreateImageAssembly(pIMetaDataAssemblyImport,
+ peKind,
+ pPEImage,
+ NULL,
+ &bindResult));
+ }
+ else if (hr == S_OK)
+ {
+ if (bindResult.HaveResult())
+ {
+ // Attempt was made to load an assembly that has the same name as a previously loaded one. Since same name
+ // does not imply the same assembly, we will need to check the MVID to confirm it is the same assembly as being
+ // requested.
+ //
+ GUID incomingMVID;
+ ZeroMemory(&incomingMVID, sizeof(GUID));
+
+ // If we cannot get MVID, then err on side of caution and fail the
+ // load.
+ IF_FAIL_GO(pIMetaDataAssemblyImport->GetScopeProps(NULL, &incomingMVID));
+
+ GUID boundMVID;
+ ZeroMemory(&boundMVID, sizeof(GUID));
+
+ // If we cannot get MVID, then err on side of caution and fail the
+ // load.
+ IF_FAIL_GO(bindResult.GetAsAssembly()->GetMVID(&boundMVID));
+
+ mvidMismatch = incomingMVID != boundMVID;
+ if (mvidMismatch)
+ {
+ // MVIDs do not match, so fail the load.
+ IF_FAIL_GO(COR_E_FILELOAD);
+ }
+
+ // MVIDs match - request came in for the same assembly that was previously loaded.
+ // Let it through...
+ }
+ }
+
+ // Remember the post-bind version of the context
+ kContextVersion = pApplicationContext->GetVersion();
+
+ } // lock(pApplicationContext)
+
+ if (bindResult.HaveResult())
+ {
+ BindResult hostBindResult;
+
+ // This has to happen outside the binder lock as it can cause new binds
+ IF_FAIL_GO(RegisterAndGetHostChosen(pApplicationContext,
+ kContextVersion,
+ &bindResult,
+ &hostBindResult));
+
+ if (hr == S_FALSE)
+ {
+ tracer.TraceBindResult(bindResult);
+
+ // Another bind interfered. We need to retry entire bind.
+ // This by design loops as long as needed because by construction we eventually
+ // will succeed or fail the bind.
+ bindResult.Reset();
+ goto Retry;
+ }
+ else if (hr == S_OK)
+ {
+ *ppAssembly = hostBindResult.GetAsAssembly(TRUE /* fAddRef */);
+ }
+ }
+
+Exit:
+ tracer.TraceBindResult(bindResult, mvidMismatch);
+ return hr;
+}
+#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+};
+
+
diff --git a/src/coreclr/binder/assemblyidentitycache.cpp b/src/coreclr/binder/assemblyidentitycache.cpp
new file mode 100644
index 00000000000..bff89d1ad29
--- /dev/null
+++ b/src/coreclr/binder/assemblyidentitycache.cpp
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// AssemblyIdentityCache.cpp
+//
+
+
+//
+// Implements the AssemblyIdentityCache class
+//
+// ============================================================
+
+#include "assemblyidentitycache.hpp"
+
+namespace BINDER_SPACE
+{
+ AssemblyIdentityCache::AssemblyIdentityCache() : SHash<AssemblyIdentityHashTraits>::SHash()
+ {
+ // Nothing to do here
+ }
+
+ AssemblyIdentityCache::~AssemblyIdentityCache()
+ {
+ // Delete entries and contents array
+ for (Hash::Iterator i = Hash::Begin(), end = Hash::End(); i != end; i++)
+ {
+ const AssemblyIdentityCacheEntry *pAssemblyIdentityCacheEntry = *i;
+ delete pAssemblyIdentityCacheEntry;
+ }
+ RemoveAll();
+ }
+
+ HRESULT AssemblyIdentityCache::Add(LPCSTR szTextualIdentity,
+ AssemblyIdentityUTF8 *pAssemblyIdentity)
+ {
+ HRESULT hr = S_OK;
+
+ NewHolder<AssemblyIdentityCacheEntry> pAssemblyIdentityCacheEntry;
+ SAFE_NEW(pAssemblyIdentityCacheEntry, AssemblyIdentityCacheEntry);
+
+ pAssemblyIdentityCacheEntry->SetTextualIdentity(szTextualIdentity);
+ pAssemblyIdentityCacheEntry->SetAssemblyIdentity(pAssemblyIdentity);
+
+ Hash::Add(pAssemblyIdentityCacheEntry);
+ pAssemblyIdentityCacheEntry.SuppressRelease();
+
+ Exit:
+ return hr;
+ }
+
+ AssemblyIdentityUTF8 *AssemblyIdentityCache::Lookup(LPCSTR szTextualIdentity)
+ {
+ AssemblyIdentityUTF8 *pAssemblyIdentity = NULL;
+ AssemblyIdentityCacheEntry *pAssemblyIdentityCacheEntry = Hash::Lookup(szTextualIdentity);
+
+ if (pAssemblyIdentityCacheEntry != NULL)
+ {
+ pAssemblyIdentity = pAssemblyIdentityCacheEntry->GetAssemblyIdentity();
+ }
+
+ return pAssemblyIdentity;
+ }
+};
diff --git a/src/coreclr/binder/assemblyname.cpp b/src/coreclr/binder/assemblyname.cpp
new file mode 100644
index 00000000000..71e70283c0b
--- /dev/null
+++ b/src/coreclr/binder/assemblyname.cpp
@@ -0,0 +1,498 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// AssemblyName.cpp
+//
+
+
+//
+// Implements the AssemblyName class
+//
+// ============================================================
+
+#include "assemblyname.hpp"
+#include "assembly.hpp"
+#include "utils.hpp"
+#include "variables.hpp"
+
+#include "fusionassemblyname.hpp"
+
+#include "textualidentityparser.hpp"
+
+#include "corpriv.h"
+
+#include "ex.h"
+
+namespace BINDER_SPACE
+{
+ AssemblyName::AssemblyName()
+ {
+ m_cRef = 1;
+ m_dwNameFlags = NAME_FLAG_NONE;
+ // Default values present in every assembly name
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_CULTURE |
+ AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL);
+ }
+
+ AssemblyName::~AssemblyName()
+ {
+ // Nothing to do here
+ }
+
+ HRESULT AssemblyName::Init(IMDInternalImport *pIMetaDataAssemblyImport,
+ PEKIND PeKind,
+ mdAssemblyRef mdar /* = 0 */,
+ BOOL fIsDefinition /* = TRUE */)
+ {
+ HRESULT hr = S_OK;
+ mdAssembly mda = 0;
+ AssemblyMetaDataInternal amd = {0};
+ CONST VOID *pvPublicKeyToken = NULL;
+ DWORD dwPublicKeyToken = 0;
+ LPCSTR pAssemblyName = NULL;
+ DWORD dwRefOrDefFlags = 0;
+ DWORD dwHashAlgId = 0;
+
+ if (fIsDefinition)
+ {
+ // Get the assembly token
+ IF_FAIL_GO(pIMetaDataAssemblyImport->GetAssemblyFromScope(&mda));
+ }
+
+ // Get name and metadata
+ if (fIsDefinition)
+ {
+ IF_FAIL_GO(pIMetaDataAssemblyImport->GetAssemblyProps(
+ mda, // [IN] The Assembly for which to get the properties.
+ &pvPublicKeyToken, // [OUT] Pointer to the PublicKeyToken blob.
+ &dwPublicKeyToken, // [OUT] Count of bytes in the PublicKeyToken Blob.
+ &dwHashAlgId, // [OUT] Hash Algorithm.
+ &pAssemblyName, // [OUT] Name.
+ &amd, // [OUT] Assembly MetaData.
+ &dwRefOrDefFlags // [OUT] Flags.
+ ));
+ }
+ else
+ {
+ IF_FAIL_GO(pIMetaDataAssemblyImport->GetAssemblyRefProps(
+ mdar, // [IN] The Assembly for which to get the properties.
+ &pvPublicKeyToken, // [OUT] Pointer to the PublicKeyToken blob.
+ &dwPublicKeyToken, // [OUT] Count of bytes in the PublicKeyToken Blob.
+ &pAssemblyName, // [OUT] Name.
+ &amd, // [OUT] Assembly MetaData.
+ NULL, // [OUT] Hash blob.
+ NULL, // [OUT] Count of bytes in hash blob.
+ &dwRefOrDefFlags // [OUT] Flags.
+ ));
+ }
+
+ {
+ StackSString culture;
+ culture.SetUTF8(amd.szLocale);
+ culture.Normalize();
+
+ SString::CIterator itr = culture.Begin();
+ if (culture.Find(itr, L';'))
+ {
+ culture = SString(culture, culture.Begin(), itr-1);
+ }
+
+ SetCulture(culture);
+ }
+
+ {
+ StackSString assemblyName;
+ assemblyName.SetUTF8(pAssemblyName);
+ assemblyName.Normalize();
+
+ COUNT_T assemblyNameLength = assemblyName.GetCount();
+ if (assemblyNameLength == 0 || assemblyNameLength >= MAX_PATH_FNAME)
+ {
+ IF_FAIL_GO(FUSION_E_INVALID_NAME);
+ }
+
+ SetSimpleName(assemblyName);
+ }
+
+ // See if the assembly[def] is retargetable (ie, for a generic assembly).
+ if (IsAfRetargetable(dwRefOrDefFlags))
+ {
+ SetIsRetargetable(TRUE);
+ }
+
+ // Set ContentType
+ if (IsAfContentType_Default(dwRefOrDefFlags))
+ {
+ SetContentType(AssemblyContentType_Default);
+ }
+ else
+ {
+ IF_FAIL_GO(FUSION_E_INVALID_NAME);
+ }
+
+ // Set the assembly version
+ {
+ AssemblyVersion *pAssemblyVersion = GetVersion();
+
+ pAssemblyVersion->SetFeatureVersion(amd.usMajorVersion, amd.usMinorVersion);
+ pAssemblyVersion->SetServiceVersion(amd.usBuildNumber, amd.usRevisionNumber);
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_VERSION);
+ }
+
+ // Set public key and/or public key token (if we have it)
+ if (pvPublicKeyToken && dwPublicKeyToken)
+ {
+ SBuffer publicKeyOrTokenBLOB((const BYTE *) pvPublicKeyToken, dwPublicKeyToken);
+
+ if (IsAfPublicKey(dwRefOrDefFlags))
+ {
+ SBuffer publicKeyTokenBLOB;
+
+ IF_FAIL_GO(GetTokenFromPublicKey(publicKeyOrTokenBLOB, publicKeyTokenBLOB));
+ GetPublicKeyTokenBLOB().Set(publicKeyTokenBLOB);
+ }
+ else
+ {
+ GetPublicKeyTokenBLOB().Set(publicKeyOrTokenBLOB);
+ }
+
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
+ }
+
+ SetArchitecture(PeKind);
+
+ Exit:
+ return hr;
+ }
+
+ HRESULT AssemblyName::Init(SString &assemblyDisplayName)
+ {
+ return TextualIdentityParser::Parse(assemblyDisplayName, this);
+ }
+
+ HRESULT AssemblyName::Init(IAssemblyName *pIAssemblyName)
+ {
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pIAssemblyName != NULL);
+
+ EX_TRY
+ {
+ {
+ // Set the simpleName
+ StackSString simpleName;
+ hr = fusion::util::GetSimpleName(pIAssemblyName, simpleName);
+ IF_FAIL_GO(hr);
+ SetSimpleName(simpleName);
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_SIMPLE_NAME);
+ }
+
+ // Display version
+ DWORD dwVersionParts[4] = {0,0,0,0};
+ DWORD cbVersionSize = sizeof(dwVersionParts[0]);
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_MAJOR_VERSION, static_cast<PVOID>(&dwVersionParts[0]), &cbVersionSize);
+ IF_FAIL_GO(hr);
+ if ((hr == S_OK) && (cbVersionSize != 0))
+ {
+ // Property is present - loop to get the individual version details
+ for(DWORD i = 0; i < 4; i++)
+ {
+ cbVersionSize = sizeof(dwVersionParts[i]);
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_MAJOR_VERSION+i, static_cast<PVOID>(&dwVersionParts[i]), &cbVersionSize);
+ IF_FAIL_GO(hr);
+ }
+
+ m_version.SetFeatureVersion(dwVersionParts[0], dwVersionParts[1]);
+ m_version.SetServiceVersion(dwVersionParts[2], dwVersionParts[3]);
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_VERSION);
+ }
+
+ {
+ // Display culture
+ StackSString culture;
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_CULTURE, culture);
+ IF_FAIL_GO(hr);
+ if (hr == S_OK)
+ {
+ SetCulture(culture);
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CULTURE);
+ }
+ }
+
+ {
+ // Display public key token
+ NewArrayHolder<BYTE> pPublicKeyToken;
+ DWORD cbPublicKeyToken = 0;
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_PUBLIC_KEY_TOKEN, static_cast<PBYTE*>(&pPublicKeyToken), &cbPublicKeyToken);
+ IF_FAIL_GO(hr);
+ if ((hr == S_OK) && (cbPublicKeyToken != 0))
+ {
+ m_publicKeyOrTokenBLOB.Set(pPublicKeyToken, cbPublicKeyToken);
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
+ }
+ else
+ {
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL);
+ }
+ }
+
+ // Display processor architecture
+ DWORD peKind = 0;
+ DWORD cbPeKind = sizeof(peKind);
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_ARCHITECTURE, static_cast<PVOID>(&peKind), &cbPeKind);
+ IF_FAIL_GO(hr);
+ if ((hr == S_OK) && (cbPeKind != 0))
+ {
+ PEKIND PeKind = (PEKIND)peKind;
+ if (PeKind != peNone)
+ {
+ SetArchitecture(PeKind);
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
+ }
+ }
+
+ // Display retarget flag
+ BOOL fRetarget = FALSE;
+ DWORD cbRetarget = sizeof(fRetarget);
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_RETARGET, static_cast<PVOID>(&fRetarget), &cbRetarget);
+ IF_FAIL_GO(hr);
+ if ((hr == S_OK) && (cbRetarget != 0))
+ {
+ if (fRetarget)
+ {
+ SetIsRetargetable(fRetarget);
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
+ }
+ }
+
+ // Display content type
+ DWORD dwContentType = AssemblyContentType_Default;
+ DWORD cbContentType = sizeof(dwContentType);
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_CONTENT_TYPE, static_cast<PVOID>(&dwContentType), &cbContentType);
+ IF_FAIL_GO(hr);
+ if ((hr == S_OK) && (cbContentType != 0))
+ {
+ if (dwContentType != AssemblyContentType_Default)
+ {
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
+ SetContentType((AssemblyContentType)dwContentType);
+ }
+ }
+
+ {
+ // Display custom flag. Dont set it if it is not present since that will end up adding the "Custom=null" attribute
+ // in the displayname of the assembly that maybe generated using this AssemblyName instance. This could create conflict when
+ // the displayname is generated from the assembly directly as that will not have a "Custom" field set.
+ NewArrayHolder<BYTE> pCustomBLOB;
+ DWORD cbCustomBLOB = 0;
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_CUSTOM, static_cast<PBYTE*>(&pCustomBLOB), &cbCustomBLOB);
+ IF_FAIL_GO(hr);
+ if ((hr == S_OK) && (cbCustomBLOB != 0))
+ {
+ m_customBLOB.Set(pCustomBLOB, cbCustomBLOB);
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CUSTOM);
+ }
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+Exit:
+ return hr;
+ }
+
+ ULONG AssemblyName::AddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }
+
+ ULONG AssemblyName::Release()
+ {
+ ULONG ulRef = InterlockedDecrement(&m_cRef);
+ if (ulRef == 0)
+ {
+ delete this;
+ }
+ return ulRef;
+ }
+
+ BOOL AssemblyName::IsCoreLib()
+ {
+ // TODO: Is this simple comparison enough?
+ return EqualsCaseInsensitive(GetSimpleName(), g_BinderVariables->corelib);
+ }
+
+ ULONG AssemblyName::Hash(DWORD dwIncludeFlags)
+ {
+ DWORD dwHash = 0;
+ DWORD dwUseIdentityFlags = m_dwIdentityFlags;
+
+ // Prune unwanted name parts
+ if ((dwIncludeFlags & INCLUDE_VERSION) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_VERSION;
+ }
+ if ((dwIncludeFlags & INCLUDE_ARCHITECTURE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE;
+ }
+ if ((dwIncludeFlags & INCLUDE_RETARGETABLE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE;
+ }
+ if ((dwIncludeFlags & INCLUDE_CONTENT_TYPE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE;
+ }
+ if ((dwIncludeFlags & INCLUDE_PUBLIC_KEY_TOKEN) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY;
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN;
+ }
+ if ((dwIncludeFlags & EXCLUDE_CULTURE) != 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_CULTURE;
+ }
+
+ dwHash ^= static_cast<DWORD>(HashCaseInsensitive(GetSimpleName()));
+ dwHash = _rotl(dwHash, 4);
+
+ if (AssemblyIdentity::Have(dwUseIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY) ||
+ AssemblyIdentity::Have(dwUseIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN))
+ {
+ const BYTE *pbPublicKeyOrToken = GetPublicKeyTokenBLOB();
+ DWORD dwcbPublicKeyOrToken = GetPublicKeyTokenBLOB().GetSize();
+
+ _ASSERTE(pbPublicKeyOrToken != NULL);
+
+ dwHash ^= HashBytes(pbPublicKeyOrToken, dwcbPublicKeyOrToken);
+ dwHash = _rotl(dwHash, 4);
+ }
+
+ if (AssemblyIdentity::Have(dwUseIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_VERSION))
+ {
+ AssemblyVersion *pAssemblyVersion = GetVersion();
+
+ dwHash ^= pAssemblyVersion->GetMajor();
+ dwHash = _rotl(dwHash, 8);
+ dwHash ^= pAssemblyVersion->GetMinor();
+ dwHash = _rotl(dwHash, 8);
+ dwHash ^= pAssemblyVersion->GetBuild();
+ dwHash = _rotl(dwHash, 8);
+ dwHash ^= pAssemblyVersion->GetRevision();
+ dwHash = _rotl(dwHash, 8);
+ }
+
+ if (AssemblyIdentity::Have(dwUseIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_CULTURE))
+ {
+ dwHash ^= static_cast<DWORD>(HashCaseInsensitive(GetNormalizedCulture()));
+ dwHash = _rotl(dwHash, 4);
+ }
+
+ if (AssemblyIdentity::Have(dwUseIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE))
+ {
+ dwHash ^= 1;
+ dwHash = _rotl(dwHash, 4);
+ }
+
+ if (AssemblyIdentity::Have(dwUseIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE))
+ {
+ dwHash ^= static_cast<DWORD>(GetArchitecture());
+ dwHash = _rotl(dwHash, 4);
+ }
+
+ if (AssemblyIdentity::Have(dwUseIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE))
+ {
+ dwHash ^= static_cast<DWORD>(GetContentType());
+ dwHash = _rotl(dwHash, 4);
+ }
+
+ return static_cast<ULONG>(dwHash);
+ }
+
+ BOOL AssemblyName::Equals(AssemblyName *pAssemblyName,
+ DWORD dwIncludeFlags)
+ {
+ BOOL fEquals = FALSE;
+
+ if (GetContentType() == AssemblyContentType_WindowsRuntime)
+ { // Assembly is meaningless for WinRT, all assemblies form one joint type namespace
+ return (GetContentType() == pAssemblyName->GetContentType());
+ }
+
+ if (EqualsCaseInsensitive(GetSimpleName(), pAssemblyName->GetSimpleName()) &&
+ (GetContentType() == pAssemblyName->GetContentType()))
+ {
+ fEquals = TRUE;
+
+ if ((dwIncludeFlags & EXCLUDE_CULTURE) == 0)
+ {
+ fEquals = EqualsCaseInsensitive(GetNormalizedCulture(), pAssemblyName->GetNormalizedCulture());
+ }
+
+ if (fEquals && (dwIncludeFlags & INCLUDE_PUBLIC_KEY_TOKEN) != 0)
+ {
+ fEquals = (GetPublicKeyTokenBLOB().Equals(pAssemblyName->GetPublicKeyTokenBLOB()));
+ }
+
+ if (fEquals && ((dwIncludeFlags & INCLUDE_ARCHITECTURE) != 0))
+ {
+ fEquals = (GetArchitecture() == pAssemblyName->GetArchitecture());
+ }
+
+ if (fEquals && ((dwIncludeFlags & INCLUDE_VERSION) != 0))
+ {
+ fEquals = GetVersion()->Equals(pAssemblyName->GetVersion());
+ }
+
+ if (fEquals && ((dwIncludeFlags & INCLUDE_RETARGETABLE) != 0))
+ {
+ fEquals = (GetIsRetargetable() == pAssemblyName->GetIsRetargetable());
+ }
+ }
+
+ return fEquals;
+ }
+
+ void AssemblyName::GetDisplayName(PathString &displayName,
+ DWORD dwIncludeFlags)
+ {
+ DWORD dwUseIdentityFlags = m_dwIdentityFlags;
+
+ // Prune unwanted name parts
+ if ((dwIncludeFlags & INCLUDE_VERSION) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_VERSION;
+ }
+ if ((dwIncludeFlags & INCLUDE_ARCHITECTURE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE;
+ }
+ if ((dwIncludeFlags & INCLUDE_RETARGETABLE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE;
+ }
+ if ((dwIncludeFlags & INCLUDE_CONTENT_TYPE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE;
+ }
+
+ TextualIdentityParser::ToString(this, dwUseIdentityFlags, displayName);
+ }
+
+ SString &AssemblyName::GetNormalizedCulture()
+ {
+ SString &culture = GetCulture();
+
+ if (culture.IsEmpty())
+ {
+ culture = g_BinderVariables->cultureNeutral;
+ }
+
+ return culture;
+ }
+}; // namespace BINDER_SPACE
diff --git a/src/coreclr/binder/bindertracing.cpp b/src/coreclr/binder/bindertracing.cpp
new file mode 100644
index 00000000000..29ba819ee6c
--- /dev/null
+++ b/src/coreclr/binder/bindertracing.cpp
@@ -0,0 +1,461 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// bindertracing.cpp
+//
+
+
+//
+// Implements helpers for binder tracing
+//
+// ============================================================
+
+#include "common.h"
+#include "bindertracing.h"
+#include "bindresult.hpp"
+
+#include "activitytracker.h"
+
+#ifdef FEATURE_EVENT_TRACE
+#include "eventtracebase.h"
+#endif // FEATURE_EVENT_TRACE
+
+using namespace BINDER_SPACE;
+
+namespace
+{
+ void FireAssemblyLoadStart(const BinderTracing::AssemblyBindOperation::BindRequest &request)
+ {
+#ifdef FEATURE_EVENT_TRACE
+ if (!EventEnabledAssemblyLoadStart())
+ return;
+
+ GUID activityId = GUID_NULL;
+ GUID relatedActivityId = GUID_NULL;
+ ActivityTracker::Start(&activityId, &relatedActivityId);
+
+ FireEtwAssemblyLoadStart(
+ GetClrInstanceId(),
+ request.AssemblyName,
+ request.AssemblyPath,
+ request.RequestingAssembly,
+ request.AssemblyLoadContext,
+ request.RequestingAssemblyLoadContext,
+ &activityId,
+ &relatedActivityId);
+#endif // FEATURE_EVENT_TRACE
+ }
+
+ void FireAssemblyLoadStop(const BinderTracing::AssemblyBindOperation::BindRequest &request, PEAssembly *resultAssembly, bool cached)
+ {
+#ifdef FEATURE_EVENT_TRACE
+ if (!EventEnabledAssemblyLoadStop())
+ return;
+
+ GUID activityId = GUID_NULL;
+ ActivityTracker::Stop(&activityId);
+
+ SString resultName;
+ SString resultPath;
+ bool success = resultAssembly != nullptr;
+ if (success)
+ {
+ resultPath = resultAssembly->GetPath();
+ resultAssembly->GetDisplayName(resultName);
+ }
+
+ FireEtwAssemblyLoadStop(
+ GetClrInstanceId(),
+ request.AssemblyName,
+ request.AssemblyPath,
+ request.RequestingAssembly,
+ request.AssemblyLoadContext,
+ request.RequestingAssemblyLoadContext,
+ success,
+ resultName,
+ resultPath,
+ cached,
+ &activityId);
+#endif // FEATURE_EVENT_TRACE
+ }
+
+ void GetAssemblyLoadContextNameFromManagedALC(INT_PTR managedALC, /* out */ SString &alcName)
+ {
+ if (managedALC == GetAppDomain()->GetTPABinderContext()->GetManagedAssemblyLoadContext())
+ {
+ alcName.Set(W("Default"));
+ return;
+ }
+
+#ifdef CROSSGEN_COMPILE
+ alcName.Set(W("Custom"));
+#else // CROSSGEN_COMPILE
+ OBJECTREF *alc = reinterpret_cast<OBJECTREF *>(managedALC);
+
+ GCX_COOP();
+ struct _gc {
+ STRINGREF alcName;
+ } gc;
+ ZeroMemory(&gc, sizeof(gc));
+
+ GCPROTECT_BEGIN(gc);
+
+ PREPARE_VIRTUAL_CALLSITE(METHOD__OBJECT__TO_STRING, *alc);
+ DECLARE_ARGHOLDER_ARRAY(args, 1);
+ args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(*alc);
+ CALL_MANAGED_METHOD_RETREF(gc.alcName, STRINGREF, args);
+ gc.alcName->GetSString(alcName);
+
+ GCPROTECT_END();
+#endif // CROSSGEN_COMPILE
+ }
+
+ void GetAssemblyLoadContextNameFromBinderID(UINT_PTR binderID, AppDomain *domain, /*out*/ SString &alcName)
+ {
+ ICLRPrivBinder *binder = reinterpret_cast<ICLRPrivBinder *>(binderID);
+ if (AreSameBinderInstance(binder, domain->GetTPABinderContext()))
+ {
+ alcName.Set(W("Default"));
+ }
+ else
+ {
+#ifdef CROSSGEN_COMPILE
+ GetAssemblyLoadContextNameFromManagedALC(0, alcName);
+#else // CROSSGEN_COMPILE
+ CLRPrivBinderAssemblyLoadContext *alcBinder = static_cast<CLRPrivBinderAssemblyLoadContext *>(binder);
+
+ GetAssemblyLoadContextNameFromManagedALC(alcBinder->GetManagedAssemblyLoadContext(), alcName);
+#endif // CROSSGEN_COMPILE
+ }
+ }
+
+ void GetAssemblyLoadContextNameFromBindContext(ICLRPrivBinder *bindContext, AppDomain *domain, /*out*/ SString &alcName)
+ {
+ _ASSERTE(bindContext != nullptr);
+
+ UINT_PTR binderID = 0;
+ HRESULT hr = bindContext->GetBinderID(&binderID);
+ _ASSERTE(SUCCEEDED(hr));
+ if (SUCCEEDED(hr))
+ GetAssemblyLoadContextNameFromBinderID(binderID, domain, alcName);
+ }
+
+ void GetAssemblyLoadContextNameFromSpec(AssemblySpec *spec, /*out*/ SString &alcName)
+ {
+ _ASSERTE(spec != nullptr);
+
+ AppDomain *domain = spec->GetAppDomain();
+ ICLRPrivBinder* bindContext = spec->GetBindingContext();
+ if (bindContext == nullptr)
+ bindContext = spec->GetBindingContextFromParentAssembly(domain);
+
+ GetAssemblyLoadContextNameFromBindContext(bindContext, domain, alcName);
+ }
+
+ void PopulateBindRequest(/*inout*/ BinderTracing::AssemblyBindOperation::BindRequest &request)
+ {
+ AssemblySpec *spec = request.AssemblySpec;
+ _ASSERTE(spec != nullptr);
+
+ if (request.AssemblyPath.IsEmpty())
+ request.AssemblyPath = spec->GetCodeBase();
+
+ if (spec->GetName() != nullptr)
+ spec->GetDisplayName(ASM_DISPLAYF_VERSION | ASM_DISPLAYF_CULTURE | ASM_DISPLAYF_PUBLIC_KEY_TOKEN, request.AssemblyName);
+
+ DomainAssembly *parentAssembly = spec->GetParentAssembly();
+ if (parentAssembly != nullptr)
+ {
+ PEAssembly *peAssembly = parentAssembly->GetFile();
+ _ASSERTE(peAssembly != nullptr);
+ peAssembly->GetDisplayName(request.RequestingAssembly);
+
+ AppDomain *domain = parentAssembly->GetAppDomain();
+ ICLRPrivBinder *bindContext = peAssembly->GetBindingContext();
+ if (bindContext == nullptr)
+ bindContext = domain->GetTPABinderContext(); // System.Private.CoreLib returns null
+
+ GetAssemblyLoadContextNameFromBindContext(bindContext, domain, request.RequestingAssemblyLoadContext);
+ }
+
+ GetAssemblyLoadContextNameFromSpec(spec, request.AssemblyLoadContext);
+ }
+
+ const WCHAR *s_assemblyNotFoundMessage = W("Could not locate assembly");
+}
+
+bool BinderTracing::IsEnabled()
+{
+#ifdef FEATURE_EVENT_TRACE
+ // Just check for the AssemblyLoadStart event being enabled.
+ return EventEnabledAssemblyLoadStart();
+#endif // FEATURE_EVENT_TRACE
+ return false;
+}
+
+namespace BinderTracing
+{
+ AssemblyBindOperation::AssemblyBindOperation(AssemblySpec *assemblySpec, const WCHAR *assemblyPath)
+ : m_bindRequest { assemblySpec, nullptr, assemblyPath }
+ , m_populatedBindRequest { false }
+ , m_checkedIgnoreBind { false }
+ , m_ignoreBind { false }
+ , m_resultAssembly { nullptr }
+ , m_cached { false }
+ {
+ _ASSERTE(assemblySpec != nullptr);
+
+ if (!BinderTracing::IsEnabled() || ShouldIgnoreBind())
+ return;
+
+ PopulateBindRequest(m_bindRequest);
+ m_populatedBindRequest = true;
+ FireAssemblyLoadStart(m_bindRequest);
+ }
+
+ AssemblyBindOperation::~AssemblyBindOperation()
+ {
+ if (BinderTracing::IsEnabled() && !ShouldIgnoreBind())
+ {
+ // Make sure the bind request is populated. Tracing may have been enabled mid-bind.
+ if (!m_populatedBindRequest)
+ PopulateBindRequest(m_bindRequest);
+
+ FireAssemblyLoadStop(m_bindRequest, m_resultAssembly, m_cached);
+ }
+
+ if (m_resultAssembly != nullptr)
+ m_resultAssembly->Release();
+ }
+
+ void AssemblyBindOperation::SetResult(PEAssembly *assembly, bool cached)
+ {
+ _ASSERTE(m_resultAssembly == nullptr);
+ m_resultAssembly = assembly;
+ if (m_resultAssembly != nullptr)
+ m_resultAssembly->AddRef();
+
+ m_cached = cached;
+ }
+
+ bool AssemblyBindOperation::ShouldIgnoreBind()
+ {
+ if (m_checkedIgnoreBind)
+ return m_ignoreBind;
+
+ // ActivityTracker or EventSource may have triggered the system satellite load.
+ // Don't track system satellite binding to avoid potential infinite recursion.
+ m_ignoreBind = m_bindRequest.AssemblySpec->IsCoreLibSatellite();
+ m_checkedIgnoreBind = true;
+ return m_ignoreBind;
+ }
+}
+
+namespace BinderTracing
+{
+ ResolutionAttemptedOperation::ResolutionAttemptedOperation(AssemblyName *assemblyName, UINT_PTR binderID, INT_PTR managedALC, const HRESULT& hr)
+ : m_hr { hr }
+ , m_stage { Stage::NotYetStarted }
+ , m_tracingEnabled { BinderTracing::IsEnabled() }
+ , m_assemblyNameObject { assemblyName }
+ , m_pFoundAssembly { nullptr }
+ {
+ _ASSERTE(binderID != 0 || managedALC != 0);
+
+ if (!m_tracingEnabled)
+ return;
+
+ // When binding the main assembly (by code base instead of name), the assembly name will be null. In this special case, we just
+ // leave the assembly name empty.
+ if (m_assemblyNameObject != nullptr)
+ m_assemblyNameObject->GetDisplayName(m_assemblyName, AssemblyName::INCLUDE_VERSION | AssemblyName::INCLUDE_PUBLIC_KEY_TOKEN);
+
+ if (managedALC != 0)
+ {
+ GetAssemblyLoadContextNameFromManagedALC(managedALC, m_assemblyLoadContextName);
+ }
+ else
+ {
+ GetAssemblyLoadContextNameFromBinderID(binderID, GetAppDomain(), m_assemblyLoadContextName);
+ }
+ }
+
+ // This function simply traces out the two stages represented by the bind result.
+ // It does not change the stage/assembly of the ResolutionAttemptedOperation class instance.
+ void ResolutionAttemptedOperation::TraceBindResult(const BindResult &bindResult, bool mvidMismatch)
+ {
+ if (!m_tracingEnabled)
+ return;
+
+ // Use the error message that would be reported in the file load exception
+ StackSString errorMsg;
+ if (mvidMismatch)
+ errorMsg.LoadResource(CCompRC::Error, IDS_HOST_ASSEMBLY_RESOLVER_ASSEMBLY_ALREADY_LOADED_IN_CONTEXT);
+
+ const BindResult::AttemptResult *inContextAttempt = bindResult.GetAttempt(true /*foundInContext*/);
+ const BindResult::AttemptResult *appAssembliesAttempt = bindResult.GetAttempt(false /*foundInContext*/);
+
+ if (inContextAttempt != nullptr)
+ {
+ // If there the attempt HR represents a success, but the tracked HR represents a failure (e.g. from further validation), report the failed HR
+ bool isLastAttempt = appAssembliesAttempt == nullptr;
+ TraceStage(Stage::FindInLoadContext,
+ isLastAttempt && FAILED(m_hr) && SUCCEEDED(inContextAttempt->HResult) ? m_hr : inContextAttempt->HResult,
+ inContextAttempt->Assembly,
+ mvidMismatch && isLastAttempt ? errorMsg.GetUnicode() : nullptr);
+ }
+
+ if (appAssembliesAttempt != nullptr)
+ TraceStage(Stage::ApplicationAssemblies, FAILED(m_hr) && SUCCEEDED(appAssembliesAttempt->HResult) ? m_hr : appAssembliesAttempt->HResult, appAssembliesAttempt->Assembly, mvidMismatch ? errorMsg.GetUnicode() : nullptr);
+ }
+
+ void ResolutionAttemptedOperation::TraceStage(Stage stage, HRESULT hr, BINDER_SPACE::Assembly *resultAssembly, const WCHAR *customError)
+ {
+ if (!m_tracingEnabled || stage == Stage::NotYetStarted)
+ return;
+
+ PathString resultAssemblyName;
+ StackSString resultAssemblyPath;
+ if (resultAssembly != nullptr)
+ {
+ resultAssembly->GetAssemblyName()->GetDisplayName(resultAssemblyName, AssemblyName::INCLUDE_VERSION | AssemblyName::INCLUDE_PUBLIC_KEY_TOKEN);
+ resultAssemblyPath = resultAssembly->GetPEImage()->GetPath();
+ }
+
+ Result result;
+ StackSString errorMsg;
+ if (customError != nullptr)
+ {
+ errorMsg.Set(customError);
+ result = Result::Failure;
+ }
+ else if (!m_exceptionMessage.IsEmpty())
+ {
+ errorMsg = m_exceptionMessage;
+ result = Result::Exception;
+ }
+ else
+ {
+ switch (hr)
+ {
+ case S_FALSE:
+ case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
+ static_assert(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == COR_E_FILENOTFOUND,
+ "COR_E_FILENOTFOUND has sane value");
+
+ result = Result::AssemblyNotFound;
+ errorMsg.Set(s_assemblyNotFoundMessage);
+ break;
+
+ case FUSION_E_APP_DOMAIN_LOCKED:
+ result = Result::IncompatibleVersion;
+
+ {
+ errorMsg.Set(W("Requested version"));
+ if (m_assemblyNameObject != nullptr)
+ {
+ const auto &reqVersion = m_assemblyNameObject->GetVersion();
+ errorMsg.AppendPrintf(W(" %d.%d.%d.%d"),
+ reqVersion->GetMajor(),
+ reqVersion->GetMinor(),
+ reqVersion->GetBuild(),
+ reqVersion->GetRevision());
+ }
+
+ errorMsg.Append(W(" is incompatible with found version"));
+ if (resultAssembly != nullptr)
+ {
+ const auto &foundVersion = resultAssembly->GetAssemblyName()->GetVersion();
+ errorMsg.AppendPrintf(W(" %d.%d.%d.%d"),
+ foundVersion->GetMajor(),
+ foundVersion->GetMinor(),
+ foundVersion->GetBuild(),
+ foundVersion->GetRevision());
+ }
+ }
+ break;
+
+ case FUSION_E_REF_DEF_MISMATCH:
+ result = Result::MismatchedAssemblyName;
+ errorMsg.Printf(W("Requested assembly name '%s' does not match found assembly name"), m_assemblyName.GetUnicode());
+ if (resultAssembly != nullptr)
+ errorMsg.AppendPrintf(W(" '%s'"), resultAssemblyName.GetUnicode());
+
+ break;
+
+ default:
+ if (SUCCEEDED(hr))
+ {
+ result = Result::Success;
+ _ASSERTE(resultAssembly != nullptr);
+ // Leave errorMsg empty in this case.
+ }
+ else
+ {
+ result = Result::Failure;
+ errorMsg.Printf(W("Resolution failed with HRESULT (%08x)"), m_hr);
+ }
+ }
+ }
+
+ FireEtwResolutionAttempted(
+ GetClrInstanceId(),
+ m_assemblyName,
+ static_cast<uint16_t>(stage),
+ m_assemblyLoadContextName,
+ static_cast<uint16_t>(result),
+ resultAssemblyName,
+ resultAssemblyPath,
+ errorMsg);
+ }
+
+ // static
+ void ResolutionAttemptedOperation::TraceAppDomainAssemblyResolve(AssemblySpec *spec, PEAssembly *resultAssembly, Exception *exception)
+ {
+ if (!BinderTracing::IsEnabled())
+ return;
+
+ Result result;
+ StackSString errorMessage;
+ StackSString resultAssemblyName;
+ StackSString resultAssemblyPath;
+ if (exception != nullptr)
+ {
+ exception->GetMessage(errorMessage);
+ result = Result::Exception;
+ }
+ else if (resultAssembly != nullptr)
+ {
+ result = Result::Success;
+ resultAssemblyPath = resultAssembly->GetPath();
+ resultAssembly->GetDisplayName(resultAssemblyName);
+ }
+ else
+ {
+ result = Result::AssemblyNotFound;
+ errorMessage.Set(s_assemblyNotFoundMessage);
+ }
+
+ StackSString assemblyName;
+ spec->GetDisplayName(ASM_DISPLAYF_VERSION | ASM_DISPLAYF_CULTURE | ASM_DISPLAYF_PUBLIC_KEY_TOKEN, assemblyName);
+
+ StackSString alcName;
+ GetAssemblyLoadContextNameFromSpec(spec, alcName);
+
+ FireEtwResolutionAttempted(
+ GetClrInstanceId(),
+ assemblyName,
+ static_cast<uint16_t>(Stage::AppDomainAssemblyResolveEvent),
+ alcName,
+ static_cast<uint16_t>(result),
+ resultAssemblyName,
+ resultAssemblyPath,
+ errorMessage);
+ }
+}
+
+void BinderTracing::PathProbed(const WCHAR *path, BinderTracing::PathSource source, HRESULT hr)
+{
+ FireEtwKnownPathProbed(GetClrInstanceId(), path, source, hr);
+}
diff --git a/src/coreclr/binder/clrprivbinderassemblyloadcontext.cpp b/src/coreclr/binder/clrprivbinderassemblyloadcontext.cpp
new file mode 100644
index 00000000000..69d8d833728
--- /dev/null
+++ b/src/coreclr/binder/clrprivbinderassemblyloadcontext.cpp
@@ -0,0 +1,293 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "common.h"
+#include "assemblybinder.hpp"
+#include "clrprivbindercoreclr.h"
+#include "clrprivbinderassemblyloadcontext.h"
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+using namespace BINDER_SPACE;
+
+// ============================================================================
+// CLRPrivBinderAssemblyLoadContext implementation
+// ============================================================================
+HRESULT CLRPrivBinderAssemblyLoadContext::BindAssemblyByNameWorker(BINDER_SPACE::AssemblyName *pAssemblyName,
+ BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly)
+{
+ VALIDATE_ARG_RET(pAssemblyName != nullptr && ppCoreCLRFoundAssembly != nullptr);
+ HRESULT hr = S_OK;
+
+#ifdef _DEBUG
+ // CoreLib should be bound using BindToSystem
+ _ASSERTE(!pAssemblyName->IsCoreLib());
+#endif
+
+ // Do we have the assembly already loaded in the context of the current binder?
+ hr = AssemblyBinder::BindAssembly(&m_appContext,
+ pAssemblyName,
+ NULL,
+ NULL,
+ FALSE, //fNgenExplicitBind,
+ FALSE, //fExplicitBindToNativeImage,
+ false, //excludeAppPaths,
+ ppCoreCLRFoundAssembly);
+ if (!FAILED(hr))
+ {
+ _ASSERTE(*ppCoreCLRFoundAssembly != NULL);
+ (*ppCoreCLRFoundAssembly)->SetBinder(this);
+ }
+
+ return hr;
+}
+
+HRESULT CLRPrivBinderAssemblyLoadContext::BindAssemblyByName(IAssemblyName *pIAssemblyName,
+ ICLRPrivAssembly **ppAssembly)
+{
+ HRESULT hr = S_OK;
+ VALIDATE_ARG_RET(pIAssemblyName != nullptr && ppAssembly != nullptr);
+
+ _ASSERTE(m_pTPABinder != NULL);
+
+ ReleaseHolder<BINDER_SPACE::Assembly> pCoreCLRFoundAssembly;
+ ReleaseHolder<AssemblyName> pAssemblyName;
+
+ SAFE_NEW(pAssemblyName, AssemblyName);
+ IF_FAIL_GO(pAssemblyName->Init(pIAssemblyName));
+
+ // When LoadContext needs to resolve an assembly reference, it will go through the following lookup order:
+ //
+ // 1) Lookup the assembly within the LoadContext itself. If assembly is found, use it.
+ // 2) Invoke the LoadContext's Load method implementation. If assembly is found, use it.
+ // 3) Lookup the assembly within TPABinder (except for satellite requests). If assembly is found, use it.
+ // 4) Invoke the LoadContext's ResolveSatelliteAssembly method (for satellite requests). If assembly is found, use it.
+ // 5) Invoke the LoadContext's Resolving event. If assembly is found, use it.
+ // 6) Raise exception.
+ //
+ // This approach enables a LoadContext to override assemblies that have been loaded in TPA context by loading
+ // a different (or even the same!) version.
+
+ {
+ // Step 1 - Try to find the assembly within the LoadContext.
+ hr = BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly);
+ if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) ||
+ (hr == FUSION_E_APP_DOMAIN_LOCKED) || (hr == FUSION_E_REF_DEF_MISMATCH))
+ {
+ // If we are here, one of the following is possible:
+ //
+ // 1) The assembly has not been found in the current binder's application context (i.e. it has not already been loaded), OR
+ // 2) An assembly with the same simple name was already loaded in the context of the current binder but we ran into a Ref/Def
+ // mismatch (either due to version difference or strong-name difference).
+ //
+ // Thus, if default binder has been overridden, then invoke it in an attempt to perform the binding for it make the call
+ // of what to do next. The host-overridden binder can either fail the bind or return reference to an existing assembly
+ // that has been loaded.
+ //
+ hr = AssemblyBinder::BindUsingHostAssemblyResolver(GetManagedAssemblyLoadContext(), pAssemblyName, pIAssemblyName, m_pTPABinder, &pCoreCLRFoundAssembly);
+ if (SUCCEEDED(hr))
+ {
+ // We maybe returned an assembly that was bound to a different AssemblyLoadContext instance.
+ // In such a case, we will not overwrite the binding context (which would be wrong since it would not
+ // be present in the cache of the current binding context).
+ if (pCoreCLRFoundAssembly->GetBinder() == NULL)
+ {
+ pCoreCLRFoundAssembly->SetBinder(this);
+ }
+ }
+ }
+ }
+
+ IF_FAIL_GO(hr);
+
+ // Extract the assembly reference.
+ //
+ // For TPA assemblies that were bound, TPABinder
+ // would have already set the binder reference for the assembly, so we just need to
+ // extract the reference now.
+ *ppAssembly = pCoreCLRFoundAssembly.Extract();
+
+Exit:;
+
+ return hr;
+}
+
+HRESULT CLRPrivBinderAssemblyLoadContext::BindUsingPEImage( /* in */ PEImage *pPEImage,
+ /* in */ BOOL fIsNativeImage,
+ /* [retval][out] */ ICLRPrivAssembly **ppAssembly)
+{
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ ReleaseHolder<BINDER_SPACE::Assembly> pCoreCLRFoundAssembly;
+ ReleaseHolder<BINDER_SPACE::AssemblyName> pAssemblyName;
+ ReleaseHolder<IMDInternalImport> pIMetaDataAssemblyImport;
+
+ PEKIND PeKind = peNone;
+
+ // Get the Metadata interface
+ DWORD dwPAFlags[2];
+ IF_FAIL_GO(BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, fIsNativeImage));
+ IF_FAIL_GO(AssemblyBinder::TranslatePEToArchitectureType(dwPAFlags, &PeKind));
+
+ _ASSERTE(pIMetaDataAssemblyImport != NULL);
+
+ // Using the information we just got, initialize the assemblyname
+ SAFE_NEW(pAssemblyName, AssemblyName);
+ IF_FAIL_GO(pAssemblyName->Init(pIMetaDataAssemblyImport, PeKind));
+
+ // Validate architecture
+ if (!BINDER_SPACE::Assembly::IsValidArchitecture(pAssemblyName->GetArchitecture()))
+ {
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
+ }
+
+ // Disallow attempt to bind to the core library. Aside from that,
+ // the LoadContext can load any assembly (even if it was in a different LoadContext like TPA).
+ if (pAssemblyName->IsCoreLib())
+ {
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
+ }
+
+ hr = AssemblyBinder::BindUsingPEImage(&m_appContext, pAssemblyName, pPEImage, PeKind, pIMetaDataAssemblyImport, &pCoreCLRFoundAssembly);
+ if (hr == S_OK)
+ {
+ _ASSERTE(pCoreCLRFoundAssembly != NULL);
+ pCoreCLRFoundAssembly->SetBinder(this);
+ *ppAssembly = pCoreCLRFoundAssembly.Extract();
+ }
+Exit:;
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
+
+HRESULT CLRPrivBinderAssemblyLoadContext::GetLoaderAllocator(LPVOID* pLoaderAllocator)
+{
+ _ASSERTE(pLoaderAllocator != NULL);
+ if (m_pAssemblyLoaderAllocator == NULL)
+ {
+ return E_FAIL;
+ }
+
+ *pLoaderAllocator = m_pAssemblyLoaderAllocator;
+ return S_OK;
+}
+
+//=============================================================================
+// Creates an instance of the AssemblyLoadContext Binder
+//
+// This method does not take a lock since it is invoked from the ctor of the
+// managed AssemblyLoadContext type.
+//=============================================================================
+/* static */
+HRESULT CLRPrivBinderAssemblyLoadContext::SetupContext(DWORD dwAppDomainId,
+ CLRPrivBinderCoreCLR *pTPABinder,
+ LoaderAllocator* pLoaderAllocator,
+ void* loaderAllocatorHandle,
+ UINT_PTR ptrAssemblyLoadContext,
+ CLRPrivBinderAssemblyLoadContext **ppBindContext)
+{
+ HRESULT hr = E_FAIL;
+ EX_TRY
+ {
+ if(ppBindContext != NULL)
+ {
+ ReleaseHolder<CLRPrivBinderAssemblyLoadContext> pBinder;
+
+ SAFE_NEW(pBinder, CLRPrivBinderAssemblyLoadContext);
+ UINT_PTR binderId;
+ pBinder->GetBinderID(&binderId);
+ hr = pBinder->m_appContext.Init(binderId);
+ if(SUCCEEDED(hr))
+ {
+ // Save the reference to the AppDomain in which the binder lives
+ pBinder->m_appContext.SetAppDomainId(dwAppDomainId);
+
+ // Save reference to the TPABinder that is required to be present.
+ _ASSERTE(pTPABinder != NULL);
+ pBinder->m_pTPABinder = pTPABinder;
+
+ // Save the reference to the IntPtr for GCHandle for the managed
+ // AssemblyLoadContext instance
+ pBinder->m_ptrManagedAssemblyLoadContext = ptrAssemblyLoadContext;
+
+ if (pLoaderAllocator != NULL)
+ {
+ // Link to LoaderAllocator, keep a reference to it
+ VERIFY(pLoaderAllocator->AddReferenceIfAlive());
+ }
+ pBinder->m_pAssemblyLoaderAllocator = pLoaderAllocator;
+ pBinder->m_loaderAllocatorHandle = loaderAllocatorHandle;
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ if (pLoaderAllocator != NULL)
+ {
+ ((AssemblyLoaderAllocator*)pLoaderAllocator)->RegisterBinder(pBinder);
+ }
+#endif
+ // Return reference to the allocated Binder instance
+ *ppBindContext = clr::SafeAddRef(pBinder.Extract());
+ }
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+Exit:
+ return hr;
+}
+
+void CLRPrivBinderAssemblyLoadContext::PrepareForLoadContextRelease(INT_PTR ptrManagedStrongAssemblyLoadContext)
+{
+ CONTRACTL
+ {
+ GC_NOTRIGGER;
+ THROWS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ // Add a strong handle so that the managed assembly load context stays alive until the
+ // CLRPrivBinderAssemblyLoadContext::ReleaseLoadContext is called.
+ // We keep the weak handle as well since this method can be running on one thread (e.g. the finalizer one)
+ // and other thread can be using the weak handle.
+ m_ptrManagedStrongAssemblyLoadContext = ptrManagedStrongAssemblyLoadContext;
+
+ _ASSERTE(m_pAssemblyLoaderAllocator != NULL);
+ _ASSERTE(m_loaderAllocatorHandle != NULL);
+
+ // We cannot delete the binder here as it is used indirectly when comparing assemblies with the same binder
+ // It will be deleted when the LoaderAllocator will be deleted
+ // But we can release the LoaderAllocator as we are no longer using it here
+ m_pAssemblyLoaderAllocator->Release();
+ m_pAssemblyLoaderAllocator = NULL;
+
+ // Destroy the strong handle to the LoaderAllocator in order to let it reach its finalizer
+ DestroyHandle(reinterpret_cast<OBJECTHANDLE>(m_loaderAllocatorHandle));
+ m_loaderAllocatorHandle = NULL;
+}
+
+CLRPrivBinderAssemblyLoadContext::CLRPrivBinderAssemblyLoadContext()
+{
+ m_pTPABinder = NULL;
+ m_ptrManagedStrongAssemblyLoadContext = NULL;
+}
+
+void CLRPrivBinderAssemblyLoadContext::ReleaseLoadContext()
+{
+ VERIFY(m_ptrManagedAssemblyLoadContext != NULL);
+ VERIFY(m_ptrManagedStrongAssemblyLoadContext != NULL);
+
+ // This method is called to release the weak and strong handles on the managed AssemblyLoadContext
+ // once the Unloading event has been fired
+ OBJECTHANDLE handle = reinterpret_cast<OBJECTHANDLE>(m_ptrManagedAssemblyLoadContext);
+ DestroyLongWeakHandle(handle);
+ handle = reinterpret_cast<OBJECTHANDLE>(m_ptrManagedStrongAssemblyLoadContext);
+ DestroyHandle(handle);
+ m_ptrManagedAssemblyLoadContext = NULL;
+}
+
+#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
diff --git a/src/coreclr/binder/clrprivbindercoreclr.cpp b/src/coreclr/binder/clrprivbindercoreclr.cpp
new file mode 100644
index 00000000000..571e127d7da
--- /dev/null
+++ b/src/coreclr/binder/clrprivbindercoreclr.cpp
@@ -0,0 +1,263 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "common.h"
+#include "assemblybinder.hpp"
+#include "clrprivbindercoreclr.h"
+#include "variables.hpp"
+
+using namespace BINDER_SPACE;
+
+//=============================================================================
+// Helper functions
+//-----------------------------------------------------------------------------
+
+HRESULT CLRPrivBinderCoreCLR::BindAssemblyByNameWorker(BINDER_SPACE::AssemblyName *pAssemblyName,
+ BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly,
+ bool excludeAppPaths)
+{
+ VALIDATE_ARG_RET(pAssemblyName != nullptr && ppCoreCLRFoundAssembly != nullptr);
+ HRESULT hr = S_OK;
+
+#ifdef _DEBUG
+ // CoreLib should be bound using BindToSystem
+ _ASSERTE(!pAssemblyName->IsCoreLib());
+#endif
+
+ hr = AssemblyBinder::BindAssembly(&m_appContext,
+ pAssemblyName,
+ NULL,
+ NULL,
+ FALSE, //fNgenExplicitBind,
+ FALSE, //fExplicitBindToNativeImage,
+ excludeAppPaths,
+ ppCoreCLRFoundAssembly);
+ if (!FAILED(hr))
+ {
+ (*ppCoreCLRFoundAssembly)->SetBinder(this);
+ }
+
+ return hr;
+}
+
+// ============================================================================
+// CLRPrivBinderCoreCLR implementation
+// ============================================================================
+HRESULT CLRPrivBinderCoreCLR::BindAssemblyByName(IAssemblyName *pIAssemblyName,
+ ICLRPrivAssembly **ppAssembly)
+{
+ HRESULT hr = S_OK;
+ VALIDATE_ARG_RET(pIAssemblyName != nullptr && ppAssembly != nullptr);
+
+ *ppAssembly = nullptr;
+
+ ReleaseHolder<BINDER_SPACE::Assembly> pCoreCLRFoundAssembly;
+ ReleaseHolder<AssemblyName> pAssemblyName;
+
+ SAFE_NEW(pAssemblyName, AssemblyName);
+ IF_FAIL_GO(pAssemblyName->Init(pIAssemblyName));
+
+ hr = BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly, false /* excludeAppPaths */);
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) ||
+ (hr == FUSION_E_APP_DOMAIN_LOCKED) || (hr == FUSION_E_REF_DEF_MISMATCH))
+ {
+ // If we are here, one of the following is possible:
+ //
+ // 1) The assembly has not been found in the current binder's application context (i.e. it has not already been loaded), OR
+ // 2) An assembly with the same simple name was already loaded in the context of the current binder but we ran into a Ref/Def
+ // mismatch (either due to version difference or strong-name difference).
+ //
+ // Attempt to resolve the assembly via managed ALC instance. This can either fail the bind or return reference to an existing
+ // assembly that has been loaded
+ INT_PTR pManagedAssemblyLoadContext = GetManagedAssemblyLoadContext();
+ if (pManagedAssemblyLoadContext == NULL)
+ {
+ // For satellite assemblies, the managed ALC has additional resolution logic (defined by the runtime) which
+ // should be run even if the managed default ALC has not yet been used. (For non-satellite assemblies, any
+ // additional logic comes through a user-defined event handler which would have initialized the managed ALC,
+ // so if the managed ALC is not set yet, there is no additional logic to run)
+ SString &culture = pAssemblyName->GetCulture();
+ if (!culture.IsEmpty() && !culture.EqualsCaseInsensitive(g_BinderVariables->cultureNeutral))
+ {
+ // Make sure the managed default ALC is initialized.
+ GCX_COOP();
+ PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__INITIALIZE_DEFAULT_CONTEXT);
+ DECLARE_ARGHOLDER_ARRAY(args, 0);
+ CALL_MANAGED_METHOD_NORET(args)
+
+ pManagedAssemblyLoadContext = GetManagedAssemblyLoadContext();
+ _ASSERTE(pManagedAssemblyLoadContext != NULL);
+ }
+ }
+
+ if (pManagedAssemblyLoadContext != NULL)
+ {
+ hr = AssemblyBinder::BindUsingHostAssemblyResolver(pManagedAssemblyLoadContext, pAssemblyName, pIAssemblyName,
+ NULL, &pCoreCLRFoundAssembly);
+ if (SUCCEEDED(hr))
+ {
+ // We maybe returned an assembly that was bound to a different AssemblyLoadContext instance.
+ // In such a case, we will not overwrite the binding context (which would be wrong since it would not
+ // be present in the cache of the current binding context).
+ if (pCoreCLRFoundAssembly->GetBinder() == NULL)
+ {
+ pCoreCLRFoundAssembly->SetBinder(this);
+ }
+ }
+ }
+ }
+#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+ IF_FAIL_GO(hr);
+
+ *ppAssembly = pCoreCLRFoundAssembly.Extract();
+
+Exit:;
+
+ return hr;
+}
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+HRESULT CLRPrivBinderCoreCLR::BindUsingPEImage( /* in */ PEImage *pPEImage,
+ /* in */ BOOL fIsNativeImage,
+ /* [retval][out] */ ICLRPrivAssembly **ppAssembly)
+{
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ ReleaseHolder<BINDER_SPACE::Assembly> pCoreCLRFoundAssembly;
+ ReleaseHolder<BINDER_SPACE::AssemblyName> pAssemblyName;
+ ReleaseHolder<IMDInternalImport> pIMetaDataAssemblyImport;
+
+ PEKIND PeKind = peNone;
+
+ // Get the Metadata interface
+ DWORD dwPAFlags[2];
+ IF_FAIL_GO(BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, fIsNativeImage));
+ IF_FAIL_GO(AssemblyBinder::TranslatePEToArchitectureType(dwPAFlags, &PeKind));
+
+ _ASSERTE(pIMetaDataAssemblyImport != NULL);
+
+ // Using the information we just got, initialize the assemblyname
+ SAFE_NEW(pAssemblyName, AssemblyName);
+ IF_FAIL_GO(pAssemblyName->Init(pIMetaDataAssemblyImport, PeKind));
+
+ // Validate architecture
+ if (!BINDER_SPACE::Assembly::IsValidArchitecture(pAssemblyName->GetArchitecture()))
+ {
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
+ }
+
+ // Easy out for CoreLib
+ if (pAssemblyName->IsCoreLib())
+ {
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
+ }
+
+ {
+ // Ensure we are not being asked to bind to a TPA assembly
+ //
+ SString& simpleName = pAssemblyName->GetSimpleName();
+ SimpleNameToFileNameMap* tpaMap = GetAppContext()->GetTpaList();
+ if (tpaMap->LookupPtr(simpleName.GetUnicode()) != NULL)
+ {
+ // The simple name of the assembly being requested to be bound was found in the TPA list.
+ // Now, perform the actual bind to see if the assembly was really in the TPA assembly list or not.
+ hr = BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly, true /* excludeAppPaths */);
+ if (SUCCEEDED(hr))
+ {
+ if (pCoreCLRFoundAssembly->GetIsInGAC())
+ {
+ *ppAssembly = pCoreCLRFoundAssembly.Extract();
+ goto Exit;
+ }
+ }
+ }
+ }
+
+ hr = AssemblyBinder::BindUsingPEImage(&m_appContext, pAssemblyName, pPEImage, PeKind, pIMetaDataAssemblyImport, &pCoreCLRFoundAssembly);
+ if (hr == S_OK)
+ {
+ _ASSERTE(pCoreCLRFoundAssembly != NULL);
+ pCoreCLRFoundAssembly->SetBinder(this);
+ *ppAssembly = pCoreCLRFoundAssembly.Extract();
+ }
+Exit:;
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
+#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+HRESULT CLRPrivBinderCoreCLR::SetupBindingPaths(SString &sTrustedPlatformAssemblies,
+ SString &sPlatformResourceRoots,
+ SString &sAppPaths,
+ SString &sAppNiPaths)
+{
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ hr = m_appContext.SetupBindingPaths(sTrustedPlatformAssemblies, sPlatformResourceRoots, sAppPaths, sAppNiPaths, TRUE /* fAcquireLock */);
+ }
+ EX_CATCH_HRESULT(hr);
+ return hr;
+}
+
+// See code:BINDER_SPACE::AssemblyBinder::GetAssembly for info on fNgenExplicitBind
+// and fExplicitBindToNativeImage, and see code:CEECompileInfo::LoadAssemblyByPath
+// for an example of how they're used.
+HRESULT CLRPrivBinderCoreCLR::Bind(SString &assemblyDisplayName,
+ LPCWSTR wszCodeBase,
+ PEAssembly *pParentAssembly,
+ BOOL fNgenExplicitBind,
+ BOOL fExplicitBindToNativeImage,
+ ICLRPrivAssembly **ppAssembly)
+{
+ HRESULT hr = S_OK;
+ VALIDATE_ARG_RET(ppAssembly != NULL);
+
+ AssemblyName assemblyName;
+
+ ReleaseHolder<AssemblyName> pAssemblyName;
+
+ if (!assemblyDisplayName.IsEmpty())
+ {
+ // AssemblyDisplayName can be empty if wszCodeBase is specified.
+ SAFE_NEW(pAssemblyName, AssemblyName);
+ IF_FAIL_GO(pAssemblyName->Init(assemblyDisplayName));
+ }
+
+ EX_TRY
+ {
+ ReleaseHolder<BINDER_SPACE::Assembly> pAsm;
+ hr = AssemblyBinder::BindAssembly(&m_appContext,
+ pAssemblyName,
+ wszCodeBase,
+ pParentAssembly,
+ fNgenExplicitBind,
+ fExplicitBindToNativeImage,
+ false, // excludeAppPaths
+ &pAsm);
+ if(SUCCEEDED(hr))
+ {
+ _ASSERTE(pAsm != NULL);
+ pAsm->SetBinder(this);
+ *ppAssembly = pAsm.Extract();
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+Exit:
+ return hr;
+}
+
+HRESULT CLRPrivBinderCoreCLR::GetLoaderAllocator(LPVOID* pLoaderAllocator)
+{
+ // Not supported by this binder
+ return E_FAIL;
+}
diff --git a/src/coreclr/binder/coreclrbindercommon.cpp b/src/coreclr/binder/coreclrbindercommon.cpp
new file mode 100644
index 00000000000..13ae1e52a57
--- /dev/null
+++ b/src/coreclr/binder/coreclrbindercommon.cpp
@@ -0,0 +1,139 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+
+#include "common.h"
+#include "assemblybinder.hpp"
+#include "coreclrbindercommon.h"
+#include "clrprivbindercoreclr.h"
+#include "bundle.h"
+
+using namespace BINDER_SPACE;
+
+//=============================================================================
+// Init code
+//-----------------------------------------------------------------------------
+/* static */
+HRESULT CCoreCLRBinderHelper::Init()
+{
+ STATIC_CONTRACT_NOTHROW;
+
+ return AssemblyBinder::Startup();
+}
+
+HRESULT CCoreCLRBinderHelper::DefaultBinderSetupContext(DWORD dwAppDomainId,CLRPrivBinderCoreCLR **ppTPABinder)
+{
+ HRESULT hr = S_OK;
+ EX_TRY
+ {
+ if(ppTPABinder != NULL)
+ {
+ ReleaseHolder<CLRPrivBinderCoreCLR> pBinder;
+ SAFE_NEW(pBinder, CLRPrivBinderCoreCLR);
+
+ BINDER_SPACE::ApplicationContext *pApplicationContext = pBinder->GetAppContext();
+ UINT_PTR binderId;
+ pBinder->GetBinderID(&binderId);
+ hr = pApplicationContext->Init(binderId);
+ if(SUCCEEDED(hr))
+ {
+ pApplicationContext->SetAppDomainId(dwAppDomainId);
+ pBinder->SetManagedAssemblyLoadContext(NULL);
+ *ppTPABinder = clr::SafeAddRef(pBinder.Extract());
+ }
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+Exit:
+ return hr;
+}
+
+HRESULT CCoreCLRBinderHelper::GetAssemblyIdentity(LPCSTR szTextualIdentity,
+ BINDER_SPACE::ApplicationContext *pApplicationContext,
+ NewHolder<AssemblyIdentityUTF8> &assemblyIdentityHolder)
+{
+ HRESULT hr = S_OK;
+ VALIDATE_ARG_RET(szTextualIdentity != NULL);
+
+ EX_TRY
+ {
+ AssemblyIdentityUTF8 *pAssemblyIdentity = NULL;
+ if (pApplicationContext != NULL)
+ {
+ // This returns a cached copy owned by application context
+ hr = pApplicationContext->GetAssemblyIdentity(szTextualIdentity, &pAssemblyIdentity);
+ if(SUCCEEDED(hr))
+ {
+ assemblyIdentityHolder = pAssemblyIdentity;
+ assemblyIdentityHolder.SuppressRelease();
+ }
+ }
+ else
+ {
+ SString sTextualIdentity;
+
+ sTextualIdentity.SetUTF8(szTextualIdentity);
+
+ // This is a private copy
+ pAssemblyIdentity = new AssemblyIdentityUTF8();
+ hr = TextualIdentityParser::Parse(sTextualIdentity, pAssemblyIdentity);
+ if(SUCCEEDED(hr))
+ {
+ pAssemblyIdentity->PopulateUTF8Fields();
+ assemblyIdentityHolder = pAssemblyIdentity;
+ }
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
+
+//=============================================================================
+// Functions that provides binding services beyond the ICLRPrivInterface
+//-----------------------------------------------------------------------------
+
+HRESULT CCoreCLRBinderHelper::BindToSystem(ICLRPrivAssembly **ppSystemAssembly, bool fBindToNativeImage)
+{
+ HRESULT hr = S_OK;
+ VALIDATE_ARG_RET(ppSystemAssembly != NULL);
+
+ EX_TRY
+ {
+ ReleaseHolder<BINDER_SPACE::Assembly> pAsm;
+ StackSString systemPath(SystemDomain::System()->SystemDirectory());
+ hr = AssemblyBinder::BindToSystem(systemPath, &pAsm, fBindToNativeImage);
+ if(SUCCEEDED(hr))
+ {
+ _ASSERTE(pAsm != NULL);
+ *ppSystemAssembly = pAsm.Extract();
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
+
+HRESULT CCoreCLRBinderHelper::BindToSystemSatellite(SString &systemPath,
+ SString &sSimpleName,
+ SString &sCultureName,
+ ICLRPrivAssembly **ppSystemAssembly)
+{
+ HRESULT hr = S_OK;
+ VALIDATE_ARG_RET(ppSystemAssembly != NULL && !systemPath.IsEmpty());
+
+ EX_TRY
+ {
+ ReleaseHolder<BINDER_SPACE::Assembly> pAsm;
+ hr = AssemblyBinder::BindToSystemSatellite(systemPath, sSimpleName, sCultureName, &pAsm);
+ if(SUCCEEDED(hr))
+ {
+ _ASSERTE(pAsm != NULL);
+ *ppSystemAssembly = pAsm.Extract();
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
diff --git a/src/coreclr/binder/failurecache.cpp b/src/coreclr/binder/failurecache.cpp
new file mode 100644
index 00000000000..c6e1f286fbb
--- /dev/null
+++ b/src/coreclr/binder/failurecache.cpp
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// FailureCache.cpp
+//
+
+
+//
+// Implements the FailureCache class
+//
+// ============================================================
+
+#include "failurecache.hpp"
+
+namespace BINDER_SPACE
+{
+ FailureCache::FailureCache() : SHash<FailureCacheHashTraits>::SHash()
+ {
+ // Nothing to do here
+ }
+
+ FailureCache::~FailureCache()
+ {
+ // Delete entries and contents array
+ for (Hash::Iterator i = Hash::Begin(), end = Hash::End(); i != end; i++)
+ {
+ const FailureCacheEntry *pFailureCacheEntry = *i;
+ delete pFailureCacheEntry;
+ }
+ RemoveAll();
+ }
+
+ HRESULT FailureCache::Add(SString &assemblyNameorPath,
+ HRESULT hrBindingResult)
+ {
+ HRESULT hr = S_OK;
+
+ NewHolder<FailureCacheEntry> pFailureCacheEntry;
+ SAFE_NEW(pFailureCacheEntry, FailureCacheEntry);
+
+ // No error occurred; report the original error
+ hr = hrBindingResult;
+
+ pFailureCacheEntry->GetAssemblyNameOrPath().Set(assemblyNameorPath);
+ pFailureCacheEntry->SetBindingResult(hrBindingResult);
+
+ Hash::Add(pFailureCacheEntry);
+ pFailureCacheEntry.SuppressRelease();
+
+ Exit:
+ return hr;
+ }
+
+ HRESULT FailureCache::Lookup(SString &assemblyNameorPath)
+ {
+ HRESULT hr = S_OK;
+ FailureCacheEntry *pFailureCachEntry = Hash::Lookup(assemblyNameorPath);
+
+ if (pFailureCachEntry != NULL)
+ {
+ hr = pFailureCachEntry->GetBindingResult();
+ }
+
+ return hr;
+ }
+
+ void FailureCache::Remove(SString &assemblyName)
+ {
+ FailureCacheEntry *pFailureCachEntry = Hash::Lookup(assemblyName);
+
+ // Hash::Remove does not clean up entries
+ Hash::Remove(assemblyName);
+ SAFE_DELETE(pFailureCachEntry);
+ }
+};
diff --git a/src/coreclr/binder/fusionassemblyname.cpp b/src/coreclr/binder/fusionassemblyname.cpp
new file mode 100644
index 00000000000..6da1cc3a3b2
--- /dev/null
+++ b/src/coreclr/binder/fusionassemblyname.cpp
@@ -0,0 +1,714 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// FusionAssemblyName.cpp
+//
+// Implements the CAssemblyName class
+//
+// ============================================================
+
+#include <windows.h>
+#include <winerror.h>
+#include "strongnameinternal.h"
+
+#include "fusionhelpers.hpp"
+#include "fusionassemblyname.hpp"
+
+#include <strsafe.h>
+#include "shlwapi.h"
+
+#include "assemblyidentity.hpp"
+#include "textualidentityparser.hpp"
+
+// ---------------------------------------------------------------------------
+// CPropertyArray ctor
+// ---------------------------------------------------------------------------
+CPropertyArray::CPropertyArray()
+{
+ _dwSig = 0x504f5250; /* 'PORP' */
+ memset(&_rProp, 0, ASM_NAME_MAX_PARAMS * sizeof(FusionProperty));
+}
+
+// ---------------------------------------------------------------------------
+// CPropertyArray dtor
+// ---------------------------------------------------------------------------
+CPropertyArray::~CPropertyArray()
+{
+ for (DWORD i = 0; i < ASM_NAME_MAX_PARAMS; i++)
+ {
+ if (_rProp[i].cb > sizeof(DWORD))
+ {
+ if (_rProp[i].pv != NULL)
+ {
+ FUSION_DELETE_ARRAY((LPBYTE) _rProp[i].pv);
+ _rProp[i].pv = NULL;
+ }
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+// CPropertyArray::Set
+// ---------------------------------------------------------------------------
+HRESULT CPropertyArray::Set(DWORD PropertyId,
+ LPCVOID pvProperty, DWORD cbProperty)
+{
+ HRESULT hr = S_OK;
+ FusionProperty *pItem = NULL;
+
+ pItem = &(_rProp[PropertyId]);
+
+ if (!cbProperty && !pvProperty)
+ {
+ if (pItem->cb > sizeof(DWORD))
+ {
+ if (pItem->pv != NULL)
+ FUSION_DELETE_ARRAY((LPBYTE) pItem->pv);
+ }
+ pItem->pv = NULL;
+ }
+ else if (cbProperty > sizeof(DWORD))
+ {
+ LPBYTE ptr = NEW(BYTE[cbProperty]);
+ if (!ptr)
+ {
+ hr = E_OUTOFMEMORY;
+ goto exit;
+ }
+
+ if (pItem->cb > sizeof(DWORD))
+ FUSION_DELETE_ARRAY((LPBYTE) pItem->pv);
+
+ memcpy(ptr, pvProperty, cbProperty);
+ pItem->pv = ptr;
+ }
+ else
+ {
+ if (pItem->cb > sizeof(DWORD))
+ FUSION_DELETE_ARRAY((LPBYTE) pItem->pv);
+
+ memcpy(&(pItem->pv), pvProperty, cbProperty);
+
+#ifdef _DEBUG
+ if (PropertyId == ASM_NAME_ARCHITECTURE) {
+ PEKIND pe = * ((PEKIND *)pvProperty);
+ _ASSERTE(pe != peInvalid);
+ }
+#endif
+ }
+ pItem->cb = cbProperty;
+
+exit:
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CPropertyArray::Get
+// ---------------------------------------------------------------------------
+HRESULT CPropertyArray::Get(DWORD PropertyId,
+ LPVOID pvProperty, LPDWORD pcbProperty)
+{
+ HRESULT hr = S_OK;
+ FusionProperty *pItem;
+
+ _ASSERTE(pcbProperty);
+
+ if (PropertyId >= ASM_NAME_MAX_PARAMS
+ || (!pvProperty && *pcbProperty))
+ {
+ _ASSERTE(!"Invalid Argument! Passed in NULL buffer with size non-zero!");
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+
+ pItem = &(_rProp[PropertyId]);
+
+ if (pItem->cb > *pcbProperty)
+ hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+ else if (pItem->cb && pvProperty)
+ memcpy(pvProperty, (pItem->cb > sizeof(DWORD) ?
+ pItem->pv : (LPBYTE) &(pItem->pv)), pItem->cb);
+
+ *pcbProperty = pItem->cb;
+
+exit:
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CPropertyArray::operator []
+// Wraps DWORD optimization test.
+// ---------------------------------------------------------------------------
+FusionProperty CPropertyArray::operator [] (DWORD PropertyId)
+{
+ FusionProperty prop;
+
+ prop.pv = _rProp[PropertyId].cb > sizeof(DWORD) ?
+ _rProp[PropertyId].pv : &(_rProp[PropertyId].pv);
+
+ prop.cb = _rProp[PropertyId].cb;
+
+ return prop;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::AddRef
+// ---------------------------------------------------------------------------
+STDMETHODIMP_(ULONG)
+CAssemblyName::AddRef()
+{
+ return InterlockedIncrement(&_cRef);
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::Release
+// ---------------------------------------------------------------------------
+STDMETHODIMP_(ULONG)
+CAssemblyName::Release()
+{
+ ULONG ulRef = InterlockedDecrement(&_cRef);
+ if (ulRef == 0)
+ {
+ delete this;
+ }
+
+ return ulRef;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::QueryInterface
+// ---------------------------------------------------------------------------
+STDMETHODIMP
+CAssemblyName::QueryInterface(REFIID riid, void** ppv)
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ if (!ppv)
+ {
+ hr = E_POINTER;
+ goto Exit;
+ }
+
+ if ( IsEqualIID(riid, IID_IUnknown)
+ || IsEqualIID(riid, IID_IAssemblyName)
+ )
+ {
+ *ppv = static_cast<IAssemblyName*> (this);
+ AddRef();
+ hr = S_OK;
+ goto Exit;
+ }
+ else
+ {
+ *ppv = NULL;
+ hr = E_NOINTERFACE;
+ goto Exit;
+ }
+
+ Exit:
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::SetProperty
+// ---------------------------------------------------------------------------
+STDMETHODIMP
+CAssemblyName::SetProperty(DWORD PropertyId,
+ LPCVOID pvProperty,
+ DWORD cbProperty)
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ hr = SetPropertyInternal(PropertyId, pvProperty, cbProperty);
+
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::GetProperty
+// ---------------------------------------------------------------------------
+STDMETHODIMP
+CAssemblyName::GetProperty(DWORD PropertyId,
+ LPVOID pvProperty, LPDWORD pcbProperty)
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // Retrieve the property.
+ switch(PropertyId)
+ {
+ case ASM_NAME_NULL_PUBLIC_KEY_TOKEN:
+ case ASM_NAME_NULL_PUBLIC_KEY:
+ {
+ hr = (_fPublicKeyToken && !_rProp[PropertyId].cb) ? S_OK : S_FALSE;
+ break;
+ }
+ case ASM_NAME_NULL_CUSTOM:
+ {
+ hr = (_fCustom && !_rProp[PropertyId].cb) ? S_OK : S_FALSE;
+ break;
+ }
+ default:
+ {
+ hr = _rProp.Get(PropertyId, pvProperty, pcbProperty);
+ break;
+ }
+ }
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::SetPropertyInternal
+// ---------------------------------------------------------------------------
+HRESULT CAssemblyName::SetPropertyInternal(DWORD PropertyId,
+ LPCVOID pvProperty,
+ DWORD cbProperty)
+{
+ HRESULT hr = S_OK;
+ LPBYTE pbSN = NULL;
+ DWORD cbSN = 0;
+
+ if (PropertyId >= ASM_NAME_MAX_PARAMS
+ || (!pvProperty && cbProperty))
+ {
+ _ASSERTE(!"Invalid Argument! Passed in NULL buffer with size non-zero!");
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+
+ // <REVISIT_TODO> - make this a switch statement.</REVISIT_TODO>
+ if (PropertyId == ASM_NAME_MAJOR_VERSION ||
+ PropertyId == ASM_NAME_MINOR_VERSION ||
+ PropertyId == ASM_NAME_BUILD_NUMBER ||
+ PropertyId == ASM_NAME_REVISION_NUMBER)
+ {
+ if (cbProperty > sizeof(WORD)) {
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+ }
+
+ // Check if public key is being set and if so,
+ // set the public key token if not already set.
+ if (PropertyId == ASM_NAME_PUBLIC_KEY)
+ {
+ // If setting true public key, generate hash.
+ if (pvProperty && cbProperty)
+ {
+ // Generate the public key token from the pk.
+ if (FAILED(hr = StrongNameTokenFromPublicKey((LPBYTE) pvProperty, cbProperty, &pbSN, &cbSN)))
+ goto exit;
+
+ // Set the public key token property.
+ if (FAILED(hr = SetPropertyInternal(ASM_NAME_PUBLIC_KEY_TOKEN, pbSN, cbSN)))
+ goto exit;
+ }
+ // Otherwise expect call to reset property.
+ else if (!cbProperty)
+ {
+ if (FAILED(hr = SetPropertyInternal(ASM_NAME_PUBLIC_KEY_TOKEN, pvProperty, cbProperty)))
+ goto exit;
+ }
+
+ }
+ // Setting NULL public key clears values in public key,
+ // public key token and sets public key token flag.
+ else if (PropertyId == ASM_NAME_NULL_PUBLIC_KEY)
+ {
+ pvProperty = NULL;
+ cbProperty = 0;
+ hr = SetPropertyInternal(ASM_NAME_NULL_PUBLIC_KEY_TOKEN, pvProperty, cbProperty);
+ goto exit;
+ }
+ // Setting or clearing public key token.
+ else if (PropertyId == ASM_NAME_PUBLIC_KEY_TOKEN)
+ {
+ // Defensive: invalid sized public key tokens should be avoided.
+ if (cbProperty > PUBLIC_KEY_TOKEN_LEN)
+ {
+ hr = SetPropertyInternal(ASM_NAME_NULL_PUBLIC_KEY_TOKEN, NULL, 0);
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+
+ if (pvProperty && cbProperty)
+ _fPublicKeyToken = TRUE;
+ else if (!cbProperty)
+ _fPublicKeyToken = FALSE;
+ }
+ // Setting NULL public key token clears public key token and
+ // sets public key token flag.
+ else if (PropertyId == ASM_NAME_NULL_PUBLIC_KEY_TOKEN)
+ {
+ _fPublicKeyToken = TRUE;
+ pvProperty = NULL;
+ cbProperty = 0;
+ PropertyId = ASM_NAME_PUBLIC_KEY_TOKEN;
+ }
+ else if (PropertyId == ASM_NAME_CUSTOM)
+ {
+ if (pvProperty && cbProperty)
+ _fCustom = TRUE;
+ else if (!cbProperty)
+ _fCustom = FALSE;
+ }
+ else if (PropertyId == ASM_NAME_NULL_CUSTOM)
+ {
+ _fCustom = TRUE;
+ pvProperty = NULL;
+ cbProperty = 0;
+ PropertyId = ASM_NAME_CUSTOM;
+ }
+
+ // Setting "neutral" as the culture is the same as "" culture (meaning
+ // culture-invariant).
+ else if (PropertyId == ASM_NAME_CULTURE) {
+ if (pvProperty && !FusionCompareStringI((LPWSTR)pvProperty, W("neutral"))) {
+ pvProperty = (void *)W("");
+ cbProperty = sizeof(W(""));
+ }
+ }
+
+ // Set property on array.
+ hr = _rProp.Set(PropertyId, pvProperty, cbProperty);
+
+exit:
+ // Free memory allocated by crypto wrapper.
+ if (pbSN) {
+ StrongNameFreeBuffer(pbSN);
+ }
+
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CreateAssemblyNameObject
+// ---------------------------------------------------------------------------
+
+// This is not external for CoreCLR
+STDAPI
+CreateAssemblyNameObject(
+ LPASSEMBLYNAME *ppAssemblyName,
+ LPCOLESTR szAssemblyName)
+{
+
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CAssemblyName *pName = NULL;
+
+ if (!ppAssemblyName)
+ {
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+
+ pName = NEW(CAssemblyName);
+ if (!pName)
+ {
+ hr = E_OUTOFMEMORY;
+ goto exit;
+ }
+
+ hr = pName->Parse((LPWSTR)szAssemblyName);
+ if (FAILED(hr))
+ {
+ SAFERELEASE(pName);
+ goto exit;
+ }
+
+ *ppAssemblyName = pName;
+
+exit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName constructor
+// ---------------------------------------------------------------------------
+CAssemblyName::CAssemblyName()
+{
+ _dwSig = 0x454d414e; /* 'EMAN' */
+ _fPublicKeyToken = FALSE;
+ _fCustom = TRUE;
+ _cRef = 1;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::Parse
+// ---------------------------------------------------------------------------
+HRESULT CAssemblyName::Parse(__in_z LPCWSTR szDisplayName)
+{
+ HRESULT hr = S_OK;
+
+ if (!(szDisplayName && *szDisplayName))
+ {
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+
+ EX_TRY {
+ BINDER_SPACE::AssemblyIdentity assemblyIdentity;
+ SString displayName(szDisplayName);
+
+ // Parse the textual identity
+ hr = BINDER_SPACE::TextualIdentityParser::Parse(displayName, &assemblyIdentity);
+ if (FAILED(hr)) {
+ goto exit;
+ }
+
+ // Set name.
+ hr = SetProperty(ASM_NAME_NAME,
+ (LPVOID) assemblyIdentity.m_simpleName.GetUnicode(),
+ (assemblyIdentity.m_simpleName.GetCount() + 1) * sizeof(WCHAR));
+ if (FAILED(hr)) {
+ goto exit;
+ }
+
+ // Set version.
+ if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_VERSION)) {
+ WORD wVersionPart = 0;
+
+ wVersionPart = (WORD) assemblyIdentity.m_version.GetMajor();
+ hr = SetProperty(ASM_NAME_MAJOR_VERSION, &wVersionPart, sizeof(WORD));
+ if (FAILED(hr)) {
+ goto exit;
+ }
+
+ wVersionPart = (WORD) assemblyIdentity.m_version.GetMinor();
+ hr = SetProperty(ASM_NAME_MINOR_VERSION, &wVersionPart, sizeof(WORD));
+ if (FAILED(hr)) {
+ goto exit;
+ }
+
+ wVersionPart = (WORD) assemblyIdentity.m_version.GetBuild();
+ hr = SetProperty(ASM_NAME_BUILD_NUMBER, &wVersionPart, sizeof(WORD));
+ if (FAILED(hr)) {
+ goto exit;
+ }
+
+ wVersionPart = (WORD) assemblyIdentity.m_version.GetRevision();
+ hr = SetProperty(ASM_NAME_REVISION_NUMBER, &wVersionPart, sizeof(WORD));
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ }
+
+ // Set culture.
+ if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CULTURE)) {
+ hr = SetProperty(ASM_NAME_CULTURE,
+ (LPVOID) assemblyIdentity.m_cultureOrLanguage.GetUnicode(),
+ (assemblyIdentity.m_cultureOrLanguage.GetCount()+1) * sizeof(WCHAR));
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ }
+
+ // Set public key (token) or NULL flag.
+ if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY)) {
+ SBuffer &publicKeyBuffer = assemblyIdentity.m_publicKeyOrTokenBLOB;
+ const void *pBytes = publicKeyBuffer;
+
+ // This also computes and sets the public key token.
+ hr = SetProperty(ASM_NAME_PUBLIC_KEY, (void *) pBytes, publicKeyBuffer.GetSize());
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ }
+ else if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN)) {
+ SBuffer &publicKeyTokenBuffer = assemblyIdentity.m_publicKeyOrTokenBLOB;
+ const void *pBytes = publicKeyTokenBuffer;
+
+ hr = SetProperty(ASM_NAME_PUBLIC_KEY_TOKEN,
+ (LPVOID) pBytes,
+ publicKeyTokenBuffer.GetSize());
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ }
+ else if (assemblyIdentity.
+ Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL)) {
+ hr = SetProperty(ASM_NAME_NULL_PUBLIC_KEY_TOKEN, NULL, 0);
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ }
+
+ // Set architecture.
+ if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE)) {
+ PEKIND peKind = assemblyIdentity.m_kProcessorArchitecture;
+
+ hr = SetProperty(ASM_NAME_ARCHITECTURE, (LPVOID) &peKind, sizeof(PEKIND));
+ if(FAILED(hr)) {
+ goto exit;
+ }
+ }
+
+ // Set retargetable flag.
+ if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE)) {
+ BOOL fRetarget = TRUE;
+
+ if (FAILED(hr = SetProperty(ASM_NAME_RETARGET, &fRetarget, sizeof(BOOL)))) {
+ goto exit;
+ }
+ }
+
+ // Set content type.
+ if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE)) {
+ DWORD dwContentType = assemblyIdentity.m_kContentType;
+
+ hr = SetProperty(ASM_NAME_CONTENT_TYPE, &dwContentType, sizeof(dwContentType));
+ IfFailGoto(hr, exit);
+ }
+
+ // Set custom or NULL flag.
+ if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CUSTOM)) {
+ SBuffer &customBuffer = assemblyIdentity.m_customBLOB;
+ const void *pBytes = customBuffer;
+
+ hr = SetProperty(ASM_NAME_CUSTOM, (void *) pBytes, customBuffer.GetSize());
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ }
+ else if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CUSTOM_NULL)) {
+ hr = SetProperty(ASM_NAME_NULL_CUSTOM, NULL, 0);
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ exit:
+ return hr;
+}
+
+namespace fusion
+{
+ namespace util
+ {
+ namespace priv
+ {
+ inline bool IsNullProperty(DWORD dwProperty)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return dwProperty == ASM_NAME_NULL_PUBLIC_KEY_TOKEN ||
+ dwProperty == ASM_NAME_NULL_PUBLIC_KEY ||
+ dwProperty == ASM_NAME_NULL_CUSTOM;
+ }
+ }
+
+ // Non-allocating helper.
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, PVOID pBuf, DWORD *pcbBuf)
+ {
+ LIMITED_METHOD_CONTRACT;
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pName != nullptr && pcbBuf != nullptr);
+ if (pName == nullptr || pcbBuf == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ hr = pName->GetProperty(dwProperty, pBuf, pcbBuf);
+ IfFailRet(hr);
+
+ // Zero-length non-null property means there is no value.
+ if (hr == S_OK && *pcbBuf == 0 && !priv::IsNullProperty(dwProperty))
+ {
+ hr = S_FALSE;
+ }
+
+ return hr;
+ }
+
+ // Allocating helper.
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, PBYTE * ppBuf, DWORD *pcbBuf)
+ {
+ LIMITED_METHOD_CONTRACT;
+ HRESULT hr = S_OK;
+
+ _ASSERTE(ppBuf != nullptr && (*ppBuf == nullptr || pcbBuf != nullptr));
+ if (ppBuf == nullptr || (*ppBuf != nullptr && pcbBuf == nullptr))
+ {
+ return E_INVALIDARG;
+ }
+
+ DWORD cbBuf = 0;
+ if (pcbBuf == nullptr)
+ pcbBuf = &cbBuf;
+
+ hr = GetProperty(pName, dwProperty, *ppBuf, pcbBuf);
+
+ // No provided buffer constitutes a request for one to be allocated.
+ if (*ppBuf == nullptr)
+ {
+ // If it's a null property, allocate a single-byte array to provide consistency.
+ if (hr == S_OK && priv::IsNullProperty(dwProperty))
+ {
+ *ppBuf = new (nothrow) BYTE[1];
+ IfNullRet(*ppBuf);
+ }
+ // Great, get the value.
+ else if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
+ {
+ NewArrayHolder<BYTE> pBuf = new (nothrow) BYTE[*pcbBuf];
+ IfNullRet(pBuf);
+ hr = pName->GetProperty(dwProperty, pBuf, pcbBuf);
+ IfFailRet(hr);
+ *ppBuf = pBuf.Extract();
+ hr = S_OK;
+ }
+ }
+
+ return hr;
+ }
+
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, SString & ssVal)
+ {
+ LIMITED_METHOD_CONTRACT;
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pName != nullptr);
+ if (pName == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ DWORD cbSize = 0;
+ hr = GetProperty(pName, dwProperty, static_cast<PBYTE>(nullptr), &cbSize);
+
+ if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
+ {
+ EX_TRY
+ {
+ PWSTR wzNameBuf = ssVal.OpenUnicodeBuffer(cbSize / sizeof(WCHAR) - 1);
+ hr = GetProperty(pName, dwProperty, reinterpret_cast<PBYTE>(wzNameBuf), &cbSize);
+ ssVal.CloseBuffer();
+ IfFailThrow(hr);
+ ssVal.Normalize();
+ }
+ EX_CATCH_HRESULT(hr);
+ IfFailRet(hr);
+ }
+
+ return hr;
+ }
+ }
+}
+
diff --git a/src/coreclr/binder/inc/activitytracker.h b/src/coreclr/binder/inc/activitytracker.h
new file mode 100644
index 00000000000..7ff8678a9f3
--- /dev/null
+++ b/src/coreclr/binder/inc/activitytracker.h
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// activitytracker.h
+//
+
+#ifndef __ACTIVITY_TRACKER_H__
+#define __ACTIVITY_TRACKER_H__
+
+namespace ActivityTracker
+{
+ void Start(/*out*/ GUID *activityId, /*out*/ GUID *relatedActivityId);
+ void Stop(/*out*/ GUID *activityId);
+};
+
+#endif // __ACTIVITY_TRACKER_H__
diff --git a/src/coreclr/binder/inc/applicationcontext.hpp b/src/coreclr/binder/inc/applicationcontext.hpp
new file mode 100644
index 00000000000..7bb3b364441
--- /dev/null
+++ b/src/coreclr/binder/inc/applicationcontext.hpp
@@ -0,0 +1,152 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// ApplicationContext.hpp
+//
+
+
+//
+// Defines the ApplicationContext class
+//
+// ============================================================
+
+#ifndef __BINDER__APPLICATION_CONTEXT_HPP__
+#define __BINDER__APPLICATION_CONTEXT_HPP__
+
+#include "bindertypes.hpp"
+#include "failurecache.hpp"
+#include "assemblyidentitycache.hpp"
+#include "stringarraylist.h"
+
+namespace BINDER_SPACE
+{
+ //=============================================================================================
+ // Data structures for Simple Name -> File Name hash
+
+ // Entry in SHash table that maps namespace to list of files
+ struct SimpleNameToFileNameMapEntry
+ {
+ LPWSTR m_wszSimpleName;
+ LPWSTR m_wszILFileName;
+ LPWSTR m_wszNIFileName;
+ };
+
+ // SHash traits for Namespace -> FileNameList hash
+ class SimpleNameToFileNameMapTraits : public NoRemoveSHashTraits< DefaultSHashTraits< SimpleNameToFileNameMapEntry > >
+ {
+ public:
+ typedef PCWSTR key_t;
+ static const SimpleNameToFileNameMapEntry Null() { SimpleNameToFileNameMapEntry e; e.m_wszSimpleName = nullptr; return e; }
+ static bool IsNull(const SimpleNameToFileNameMapEntry & e) { return e.m_wszSimpleName == nullptr; }
+ static key_t GetKey(const SimpleNameToFileNameMapEntry & e)
+ {
+ key_t key;
+ key = e.m_wszSimpleName;
+ return key;
+ }
+ static count_t Hash(const key_t &str)
+ {
+ SString ssKey(SString::Literal, str);
+ return ssKey.HashCaseInsensitive();
+ }
+ static BOOL Equals(const key_t &lhs, const key_t &rhs) { LIMITED_METHOD_CONTRACT; return (SString::_wcsicmp(lhs, rhs) == 0); }
+
+ void OnDestructPerEntryCleanupAction(const SimpleNameToFileNameMapEntry & e)
+ {
+ if (e.m_wszILFileName == nullptr && e.m_wszNIFileName == nullptr)
+ {
+ // Don't delete simple name here since it's a filename only entry and will be cleaned up
+ // by the SimpleName -> FileName entry which reuses the same filename pointer.
+ return;
+ }
+
+ if (e.m_wszSimpleName != nullptr)
+ {
+ delete [] e.m_wszSimpleName;
+ }
+ if (e.m_wszILFileName != nullptr)
+ {
+ delete [] e.m_wszILFileName;
+ }
+ if (e.m_wszNIFileName != nullptr)
+ {
+ delete [] e.m_wszNIFileName;
+ }
+ }
+ static const bool s_DestructPerEntryCleanupAction = true;
+ };
+
+ typedef SHash<SimpleNameToFileNameMapTraits> SimpleNameToFileNameMap;
+
+ class ApplicationContext
+ : public IUnknown
+ {
+ public:
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid,
+ void **ppv);
+ STDMETHOD_(ULONG, AddRef)();
+ STDMETHOD_(ULONG, Release)();
+
+ // ApplicationContext methods
+ ApplicationContext();
+ virtual ~ApplicationContext();
+ HRESULT Init(UINT_PTR binderID);
+
+ inline SString &GetApplicationName();
+ inline DWORD GetAppDomainId();
+ inline void SetAppDomainId(DWORD dwAppDomainId);
+
+ HRESULT SetupBindingPaths(/* in */ SString &sTrustedPlatformAssemblies,
+ /* in */ SString &sPlatformResourceRoots,
+ /* in */ SString &sAppPaths,
+ /* in */ SString &sAppNiPaths,
+ /* in */ BOOL fAcquireLock);
+
+ HRESULT GetAssemblyIdentity(/* in */ LPCSTR szTextualIdentity,
+ /* in */ AssemblyIdentityUTF8 **ppAssemblyIdentity);
+
+ // Getters/Setter
+ inline ExecutionContext *GetExecutionContext();
+ inline FailureCache *GetFailureCache();
+ inline HRESULT AddToFailureCache(SString &assemblyNameOrPath,
+ HRESULT hrBindResult);
+ inline StringArrayList *GetAppPaths();
+ inline SimpleNameToFileNameMap *GetTpaList();
+ inline StringArrayList *GetPlatformResourceRoots();
+ inline StringArrayList *GetAppNiPaths();
+
+ // Using a host-configured Trusted Platform Assembly list
+ bool IsTpaListProvided();
+ inline CRITSEC_COOKIE GetCriticalSectionCookie();
+ inline LONG GetVersion();
+ inline void IncrementVersion();
+
+ UINT_PTR GetBinderID() { return m_binderID; }
+
+ protected:
+ LONG m_cRef;
+ Volatile<LONG> m_cVersion;
+ SString m_applicationName;
+ DWORD m_dwAppDomainId;
+ ExecutionContext *m_pExecutionContext;
+ FailureCache *m_pFailureCache;
+ CRITSEC_COOKIE m_contextCS;
+
+ AssemblyIdentityCache m_assemblyIdentityCache;
+
+ StringArrayList m_platformResourceRoots;
+ StringArrayList m_appPaths;
+ StringArrayList m_appNiPaths;
+
+ SimpleNameToFileNameMap * m_pTrustedPlatformAssemblyMap;
+
+ UINT_PTR m_binderID;
+ };
+
+#include "applicationcontext.inl"
+
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/applicationcontext.inl b/src/coreclr/binder/inc/applicationcontext.inl
new file mode 100644
index 00000000000..4d006d5be6b
--- /dev/null
+++ b/src/coreclr/binder/inc/applicationcontext.inl
@@ -0,0 +1,86 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// ApplicationContext.inl
+//
+
+
+//
+// Implements inlined methods of ApplicationContext
+//
+// ============================================================
+
+#ifndef __BINDER__APPLICATION_CONTEXT_INL__
+#define __BINDER__APPLICATION_CONTEXT_INL__
+
+LONG ApplicationContext::GetVersion()
+{
+ return m_cVersion;
+}
+
+void ApplicationContext::IncrementVersion()
+{
+ InterlockedIncrement(&m_cVersion);
+}
+
+SString &ApplicationContext::GetApplicationName()
+{
+ return m_applicationName;
+}
+
+DWORD ApplicationContext::GetAppDomainId()
+{
+ return m_dwAppDomainId;
+}
+
+void ApplicationContext::SetAppDomainId(DWORD dwAppDomainId)
+{
+ m_dwAppDomainId = dwAppDomainId;
+}
+
+ExecutionContext *ApplicationContext::GetExecutionContext()
+{
+ return m_pExecutionContext;
+}
+
+FailureCache *ApplicationContext::GetFailureCache()
+{
+ _ASSERTE(m_pFailureCache != NULL);
+ return m_pFailureCache;
+}
+
+HRESULT ApplicationContext::AddToFailureCache(SString &assemblyNameOrPath,
+ HRESULT hrBindResult)
+{
+ HRESULT hr = GetFailureCache()->Add(assemblyNameOrPath, hrBindResult);
+ IncrementVersion();
+ return hr;
+}
+
+StringArrayList *ApplicationContext::GetAppPaths()
+{
+ return &m_appPaths;
+}
+
+SimpleNameToFileNameMap * ApplicationContext::GetTpaList()
+{
+ return m_pTrustedPlatformAssemblyMap;
+}
+
+StringArrayList * ApplicationContext::GetPlatformResourceRoots()
+{
+ return &m_platformResourceRoots;
+}
+
+StringArrayList * ApplicationContext::GetAppNiPaths()
+{
+ return &m_appNiPaths;
+}
+
+CRITSEC_COOKIE ApplicationContext::GetCriticalSectionCookie()
+{
+ return m_contextCS;
+}
+
+#endif
diff --git a/src/coreclr/binder/inc/assembly.hpp b/src/coreclr/binder/inc/assembly.hpp
new file mode 100644
index 00000000000..3f5fb87594e
--- /dev/null
+++ b/src/coreclr/binder/inc/assembly.hpp
@@ -0,0 +1,167 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// Assembly.hpp
+//
+
+
+//
+// Defines the Assembly class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_HPP__
+#define __BINDER__ASSEMBLY_HPP__
+
+#include "bindertypes.hpp"
+#include "assemblyname.hpp"
+
+#include "corpriv.h"
+#include "clrprivbinding.h"
+
+#include "clrprivbindercoreclr.h"
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+#include "clrprivbinderassemblyloadcontext.h"
+#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+#include "bundle.h"
+
+STDAPI BinderAcquirePEImage(LPCTSTR szAssemblyPath,
+ PEImage **ppPEImage,
+ PEImage **ppNativeImage,
+ BOOL fExplicitBindToNativeImage,
+ BundleFileLocation bundleFileLocation);
+
+STDAPI BinderAcquireImport(PEImage *pPEImage,
+ IMDInternalImport **pIMetaDataAssemblyImport,
+ DWORD *pdwPAFlags,
+ BOOL bNativeImage);
+
+STDAPI BinderHasNativeHeader(PEImage *pPEImage,
+ BOOL *result);
+
+STDAPI BinderReleasePEImage(PEImage *pPEImage);
+
+STDAPI BinderAddRefPEImage(PEImage *pPEImage);
+
+namespace BINDER_SPACE
+{
+
+ // An assembly represents a particular set of bits. However we extend this to
+ // also include whether those bits have precompiled information (NGEN). Thus
+ // and assembly knows whether it has an NGEN image or not.
+ //
+ // This allows us to preferentially use the NGEN image if it is available.
+ class Assembly
+ : public ICLRPrivAssembly
+ {
+ public:
+ // --------------------------------------------------------------------
+ // IUnknown methods
+ // --------------------------------------------------------------------
+ STDMETHOD(QueryInterface)(REFIID riid,
+ void ** ppv);
+ STDMETHOD_(ULONG, AddRef)();
+ STDMETHOD_(ULONG, Release)();
+
+ // --------------------------------------------------------------------
+ // ICLRPrivAssembly methods
+ // --------------------------------------------------------------------
+ LPCWSTR GetSimpleName();
+
+ STDMETHOD(BindAssemblyByName)(
+ IAssemblyName * pIAssemblyName,
+ ICLRPrivAssembly ** ppAssembly);
+
+ STDMETHOD(GetAvailableImageTypes)(PDWORD pdwImageTypes);
+
+ STDMETHOD(GetBinderID)(UINT_PTR *pBinderId);
+
+ STDMETHOD(GetLoaderAllocator)(LPVOID* pLoaderAllocator);
+
+ // --------------------------------------------------------------------
+ // Assembly methods
+ // --------------------------------------------------------------------
+ Assembly();
+ virtual ~Assembly();
+
+ HRESULT Init(/* in */ IMDInternalImport *pIMetaDataAssemblyImport,
+ /* in */ PEKIND PeKind,
+ /* in */ PEImage *pPEImage,
+ /* in */ PEImage *pPENativeImage,
+ /* in */ SString &assemblyPath,
+ /* in */ BOOL fIsInGAC);
+
+ inline AssemblyName *GetAssemblyName(BOOL fAddRef = FALSE);
+ inline BOOL GetIsInGAC();
+
+ inline SString &GetPath();
+
+ inline PEImage *GetPEImage(BOOL fAddRef = FALSE);
+ inline PEImage *GetNativePEImage(BOOL fAddRef = FALSE);
+ inline PEImage *GetNativeOrILPEImage(BOOL fAddRef = FALSE);
+
+ HRESULT GetMVID(GUID *pMVID);
+
+ static PEKIND GetSystemArchitecture();
+ static BOOL IsValidArchitecture(PEKIND kArchitecture);
+
+ inline ICLRPrivBinder* GetBinder()
+ {
+ return m_pBinder;
+ }
+
+#ifndef CROSSGEN_COMPILE
+ protected:
+#endif
+ // Assembly Flags
+ enum
+ {
+ FLAG_NONE = 0x00,
+ FLAG_IS_IN_GAC = 0x02,
+ //FLAG_IS_DYNAMIC_BIND = 0x04,
+ FLAG_IS_BYTE_ARRAY = 0x08,
+ };
+
+ inline void SetPEImage(PEImage *pPEImage);
+ inline void SetNativePEImage(PEImage *pNativePEImage);
+
+ inline void SetAssemblyName(AssemblyName *pAssemblyName,
+ BOOL fAddRef = TRUE);
+ inline void SetIsInGAC(BOOL fIsInGAC);
+
+ inline IMDInternalImport *GetMDImport();
+ inline void SetMDImport(IMDInternalImport *pMDImport);
+
+ LONG m_cRef;
+ PEImage *m_pPEImage;
+ PEImage *m_pNativePEImage;
+ IMDInternalImport *m_pMDImport;
+ AssemblyName *m_pAssemblyName;
+ SString m_assemblyPath;
+ DWORD m_dwAssemblyFlags;
+ ICLRPrivBinder *m_pBinder;
+
+ inline void SetBinder(ICLRPrivBinder *pBinder)
+ {
+ _ASSERTE(m_pBinder == NULL || m_pBinder == pBinder);
+ m_pBinder = pBinder;
+ }
+
+ friend class ::CLRPrivBinderCoreCLR;
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ friend class ::CLRPrivBinderAssemblyLoadContext;
+#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ };
+
+ // This is a fast version which goes around the COM interfaces and directly
+ // casts the interfaces and does't AddRef
+ inline BINDER_SPACE::Assembly * GetAssemblyFromPrivAssemblyFast(ICLRPrivAssembly *pPrivAssembly);
+
+#include "assembly.inl"
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/assembly.inl b/src/coreclr/binder/inc/assembly.inl
new file mode 100644
index 00000000000..ca0aa232e90
--- /dev/null
+++ b/src/coreclr/binder/inc/assembly.inl
@@ -0,0 +1,134 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// Assembly.inl
+//
+
+
+//
+// Implements the inline methods of Assembly
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_INL__
+#define __BINDER__ASSEMBLY_INL__
+
+PEImage *Assembly::GetPEImage(BOOL fAddRef /* = FALSE */)
+{
+ PEImage *pPEImage = m_pPEImage;
+
+ if (fAddRef)
+ {
+ BinderAddRefPEImage(pPEImage);
+ }
+
+ return pPEImage;
+}
+
+PEImage *Assembly::GetNativePEImage(BOOL fAddRef /* = FALSE */)
+{
+ PEImage *pNativePEImage = m_pNativePEImage;
+
+ if (fAddRef)
+ {
+ BinderAddRefPEImage(pNativePEImage);
+ }
+
+ return pNativePEImage;
+}
+
+PEImage *Assembly::GetNativeOrILPEImage(BOOL fAddRef /* = FALSE */)
+{
+ PEImage* pPEImage = GetNativePEImage(fAddRef);
+ if (pPEImage == NULL)
+ pPEImage = GetPEImage(fAddRef);
+ return pPEImage;
+}
+
+void Assembly::SetPEImage(PEImage *pPEImage)
+{
+ BinderAddRefPEImage(pPEImage);
+ m_pPEImage = pPEImage;
+}
+
+void Assembly::SetNativePEImage(PEImage *pNativePEImage)
+{
+ BinderAddRefPEImage(pNativePEImage);
+ m_pNativePEImage = pNativePEImage;
+}
+
+AssemblyName *Assembly::GetAssemblyName(BOOL fAddRef /* = FALSE */)
+{
+ AssemblyName *pAssemblyName = m_pAssemblyName;
+
+ if (fAddRef && (pAssemblyName != NULL))
+ {
+ pAssemblyName->AddRef();
+ }
+ return pAssemblyName;
+}
+
+void Assembly::SetAssemblyName(AssemblyName *pAssemblyName,
+ BOOL fAddRef /* = TRUE */)
+{
+ SAFE_RELEASE(m_pAssemblyName);
+
+ m_pAssemblyName = pAssemblyName;
+
+ if (fAddRef && (pAssemblyName != NULL))
+ {
+ pAssemblyName->AddRef();
+ }
+}
+
+BOOL Assembly::GetIsInGAC()
+{
+ return ((m_dwAssemblyFlags & FLAG_IS_IN_GAC) != 0);
+}
+
+void Assembly::SetIsInGAC(BOOL fIsInGAC)
+{
+ if (fIsInGAC)
+ {
+ m_dwAssemblyFlags |= FLAG_IS_IN_GAC;
+ }
+ else
+ {
+ m_dwAssemblyFlags &= ~FLAG_IS_IN_GAC;
+ }
+}
+
+SString &Assembly::GetPath()
+{
+ return m_assemblyPath;
+}
+
+IMDInternalImport *Assembly::GetMDImport()
+{
+ return m_pMDImport;
+}
+
+void Assembly::SetMDImport(IMDInternalImport *pMDImport)
+{
+ SAFE_RELEASE(m_pMDImport);
+
+ m_pMDImport = pMDImport;
+ m_pMDImport->AddRef();
+}
+
+BINDER_SPACE::Assembly* GetAssemblyFromPrivAssemblyFast(ICLRPrivAssembly *pPrivAssembly)
+{
+#ifdef _DEBUG
+ if(pPrivAssembly != nullptr)
+ {
+ // Ensure the pPrivAssembly we are about to cast is indeed a valid Assembly
+ DWORD dwImageType = 0;
+ pPrivAssembly->GetAvailableImageTypes(&dwImageType);
+ _ASSERTE((dwImageType & ASSEMBLY_IMAGE_TYPE_ASSEMBLY) == ASSEMBLY_IMAGE_TYPE_ASSEMBLY);
+ }
+#endif
+ return (BINDER_SPACE::Assembly *)pPrivAssembly;
+}
+
+#endif
diff --git a/src/coreclr/binder/inc/assemblybinder.hpp b/src/coreclr/binder/inc/assemblybinder.hpp
new file mode 100644
index 00000000000..6fc2f2dc457
--- /dev/null
+++ b/src/coreclr/binder/inc/assemblybinder.hpp
@@ -0,0 +1,122 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// AssemblyBinder.hpp
+//
+
+
+//
+// Defines the AssemblyBinder class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_BINDER_HPP__
+#define __BINDER__ASSEMBLY_BINDER_HPP__
+
+#include "bindertypes.hpp"
+#include "bindresult.hpp"
+#include "coreclrbindercommon.h"
+#include "bundle.h"
+
+class CLRPrivBinderAssemblyLoadContext;
+class CLRPrivBinderCoreCLR;
+
+namespace BINDER_SPACE
+{
+ class AssemblyBinder
+ {
+ public:
+ static HRESULT Startup();
+
+ // See code:BINDER_SPACE::AssemblyBinder::GetAssembly for info on fNgenExplicitBind
+ // and fExplicitBindToNativeImage, and see code:CEECompileInfo::LoadAssemblyByPath
+ // for an example of how they're used.
+ static HRESULT BindAssembly(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ LPCWSTR szCodeBase,
+ /* in */ PEAssembly *pParentAssembly,
+ /* in */ BOOL fNgenExplicitBind,
+ /* in */ BOOL fExplicitBindToNativeImage,
+ /* in */ bool excludeAppPaths,
+ /* out */ Assembly **ppAssembly);
+
+ static HRESULT BindToSystem(/* in */ SString &systemDirectory,
+ /* out */ Assembly **ppSystemAssembly,
+ /* in */ bool fBindToNativeImage);
+
+ static HRESULT BindToSystemSatellite(/* in */ SString &systemDirectory,
+ /* in */ SString &simpleName,
+ /* in */ SString &cultureName,
+ /* out */ Assembly **ppSystemAssembly);
+
+ static HRESULT GetAssembly(/* in */ SString &assemblyPath,
+ /* in */ BOOL fIsInGAC,
+ /* in */ BOOL fExplicitBindToNativeImage,
+ /* out */ Assembly **ppAssembly,
+ /* in */ LPCTSTR szMDAssemblyPath = NULL,
+ /* in */ BundleFileLocation bundleFileLocation = BundleFileLocation::Invalid());
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ static HRESULT BindUsingHostAssemblyResolver (/* in */ INT_PTR pManagedAssemblyLoadContextToBindWithin,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ IAssemblyName *pIAssemblyName,
+ /* in */ CLRPrivBinderCoreCLR *pTPABinder,
+ /* out */ Assembly **ppAssembly);
+
+ static HRESULT BindUsingPEImage(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ BINDER_SPACE::AssemblyName *pAssemblyName,
+ /* in */ PEImage *pPEImage,
+ /* in */ PEKIND peKind,
+ /* in */ IMDInternalImport *pIMetaDataAssemblyImport,
+ /* [retval] [out] */ Assembly **ppAssembly);
+#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+ static HRESULT TranslatePEToArchitectureType(DWORD *pdwPAFlags, PEKIND *PeKind);
+
+ private:
+ static HRESULT BindByName(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ bool skipFailureCaching,
+ /* in */ bool skipVersionCompatibilityCheck,
+ /* in */ bool excludeAppPaths,
+ /* out */ BindResult *pBindResult);
+
+ // See code:BINDER_SPACE::AssemblyBinder::GetAssembly for info on fNgenExplicitBind
+ // and fExplicitBindToNativeImage, and see code:CEECompileInfo::LoadAssemblyByPath
+ // for an example of how they're used.
+ static HRESULT BindWhereRef(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ PathString &assemblyPath,
+ /* in */ BOOL fNgenExplicitBind,
+ /* in */ BOOL fExplicitBindToNativeImage,
+ /* in */ bool excludeAppPaths,
+ /* out */ BindResult *pBindResult);
+
+ static HRESULT BindLocked(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ bool skipVersionCompatibilityCheck,
+ /* in */ bool excludeAppPaths,
+ /* out */ BindResult *pBindResult);
+
+ static HRESULT FindInExecutionContext(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* out */ ContextEntry **ppContextEntry);
+
+ static HRESULT BindByTpaList(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pRequestedAssemblyName,
+ /* in */ bool excludeAppPaths,
+ /* out */ BindResult *pBindResult);
+
+ static HRESULT Register(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ BindResult *pBindResult);
+ static HRESULT RegisterAndGetHostChosen(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ LONG kContextVersion,
+ /* in */ BindResult *pBindResult,
+ /* out */ BindResult *pHostBindResult);
+
+ static HRESULT OtherBindInterfered(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ BindResult *pBindResult);
+ };
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/assemblyentry.hpp b/src/coreclr/binder/inc/assemblyentry.hpp
new file mode 100644
index 00000000000..5a32e6f5cd9
--- /dev/null
+++ b/src/coreclr/binder/inc/assemblyentry.hpp
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// AssemblyEntry.hpp
+//
+
+
+//
+// Defines the AssemblyEntry class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_ENTRY_HPP__
+#define __BINDER__ASSEMBLY_ENTRY_HPP__
+
+#include "bindertypes.hpp"
+#include "assemblyname.hpp"
+
+namespace BINDER_SPACE
+{
+ class AssemblyEntry
+ {
+ public:
+ AssemblyEntry()
+ {
+ m_pAssemblyName = NULL;
+ }
+ virtual ~AssemblyEntry()
+ {
+ SAFE_RELEASE(m_pAssemblyName);
+ }
+
+ AssemblyName *GetAssemblyName(BOOL fAddRef = FALSE)
+ {
+ AssemblyName *pAssemblyName = m_pAssemblyName;
+
+ if (fAddRef && (pAssemblyName != NULL))
+ {
+ pAssemblyName->AddRef();
+ }
+ return pAssemblyName;
+ }
+
+ void SetAssemblyName(AssemblyName *pAssemblyName, BOOL fAddRef = TRUE)
+ {
+ SAFE_RELEASE(m_pAssemblyName);
+
+ if (fAddRef && (pAssemblyName != NULL))
+ {
+ pAssemblyName->AddRef();
+ }
+
+ m_pAssemblyName = pAssemblyName;
+ }
+ protected:
+ AssemblyName *m_pAssemblyName;
+ };
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/assemblyhashtraits.hpp b/src/coreclr/binder/inc/assemblyhashtraits.hpp
new file mode 100644
index 00000000000..9c28151e1db
--- /dev/null
+++ b/src/coreclr/binder/inc/assemblyhashtraits.hpp
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// AssemblyHashTraits.hpp
+//
+
+
+//
+// Defines the AssemblyHashTraits template class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_HASH_TRAITS_HPP__
+#define __BINDER__ASSEMBLY_HASH_TRAITS_HPP__
+
+#include "bindertypes.hpp"
+#include "assemblyentry.hpp"
+#include "shash.h"
+
+namespace BINDER_SPACE
+{
+ template<typename HashEntry, DWORD dwAssemblyNameFlags>
+ class AssemblyHashTraits : public NoRemoveSHashTraits<DefaultSHashTraits<HashEntry> >
+ {
+ public:
+ typedef typename NoRemoveSHashTraits<DefaultSHashTraits<HashEntry> >::element_t element_t;
+ typedef typename NoRemoveSHashTraits<DefaultSHashTraits<HashEntry> >::count_t count_t;
+
+ typedef AssemblyName* key_t;
+
+ // GetKey, Equals and Hash can throw due to SString
+ static const bool s_NoThrow = false;
+
+ static key_t GetKey(element_t pAssemblyEntry)
+ {
+ return pAssemblyEntry->GetAssemblyName();
+ }
+ static BOOL Equals(key_t pAssemblyName1, key_t pAssemblyName2)
+ {
+ return pAssemblyName1->Equals(pAssemblyName2, dwAssemblyNameFlags);
+ }
+ static count_t Hash(key_t pAssemblyName)
+ {
+ return pAssemblyName->Hash(dwAssemblyNameFlags);
+ }
+ static element_t Null()
+ {
+ return NULL;
+ }
+ static bool IsNull(const element_t &assemblyEntry)
+ {
+ return (assemblyEntry == NULL);
+ }
+ };
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/assemblyidentity.hpp b/src/coreclr/binder/inc/assemblyidentity.hpp
new file mode 100644
index 00000000000..e1fdec87b26
--- /dev/null
+++ b/src/coreclr/binder/inc/assemblyidentity.hpp
@@ -0,0 +1,134 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// AssemblyIdentity.hpp
+//
+
+
+//
+// Defines the AssemblyIdentity class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_IDENTITY_HPP__
+#define __BINDER__ASSEMBLY_IDENTITY_HPP__
+
+#include "bindertypes.hpp"
+#include "assemblyversion.hpp"
+
+namespace BINDER_SPACE
+{
+ class AssemblyIdentity
+ {
+ public:
+ enum
+ {
+ IDENTITY_FLAG_EMPTY = 0x000,
+ IDENTITY_FLAG_SIMPLE_NAME = 0x001,
+ IDENTITY_FLAG_VERSION = 0x002,
+ IDENTITY_FLAG_PUBLIC_KEY_TOKEN = 0x004,
+ IDENTITY_FLAG_PUBLIC_KEY = 0x008,
+ IDENTITY_FLAG_CULTURE = 0x010,
+ IDENTITY_FLAG_LANGUAGE = 0x020,
+ IDENTITY_FLAG_PROCESSOR_ARCHITECTURE = 0x040,
+ IDENTITY_FLAG_RETARGETABLE = 0x080,
+ IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL = 0x100,
+ IDENTITY_FLAG_CUSTOM = 0x200,
+ IDENTITY_FLAG_CUSTOM_NULL = 0x400,
+ IDENTITY_FLAG_CONTENT_TYPE = 0x800,
+ IDENTITY_FLAG_FULL_NAME = (IDENTITY_FLAG_SIMPLE_NAME |
+ IDENTITY_FLAG_VERSION)
+ };
+
+ AssemblyIdentity()
+ {
+ m_dwIdentityFlags = IDENTITY_FLAG_EMPTY;
+ m_kProcessorArchitecture = peNone;
+ m_kContentType = AssemblyContentType_Default;
+
+ // Need to pre-populate SBuffers because of bogus asserts
+ static const BYTE byteArr[] = { 0 };
+ m_publicKeyOrTokenBLOB.SetImmutable(byteArr, sizeof(byteArr));
+ m_customBLOB.SetImmutable(byteArr, sizeof(byteArr));
+ }
+ ~AssemblyIdentity()
+ {
+ // Nothing to do here
+ }
+
+ static BOOL Have(DWORD dwUseIdentityFlags, DWORD dwIdentityFlags)
+ {
+ return ((dwUseIdentityFlags & dwIdentityFlags) != 0);
+ }
+
+ BOOL Have(DWORD dwIdentityFlags)
+ {
+ return Have(m_dwIdentityFlags, dwIdentityFlags);
+ }
+
+ void SetHave(DWORD dwIdentityFlags)
+ {
+ m_dwIdentityFlags |= dwIdentityFlags;
+ }
+
+ void SetClear(DWORD dwIdentityFlags)
+ {
+ m_dwIdentityFlags &= ~dwIdentityFlags;
+ }
+
+ SString m_simpleName;
+ AssemblyVersion m_version;
+ SString m_cultureOrLanguage;
+ SBuffer m_publicKeyOrTokenBLOB;
+ PEKIND m_kProcessorArchitecture;
+ AssemblyContentType m_kContentType;
+ SBuffer m_customBLOB;
+ DWORD m_dwIdentityFlags;
+ };
+
+ class AssemblyIdentityUTF8 : public AssemblyIdentity
+ {
+ public:
+ AssemblyIdentityUTF8()
+ {
+ m_szSimpleNameUTF8 = NULL;
+ m_szCultureOrLanguageUTF8 = NULL;
+ }
+
+ void PopulateUTF8Fields()
+ {
+ m_szSimpleNameUTF8 = m_simpleName.GetUTF8(sSimpleNameBuffer);
+
+ if (Have(IDENTITY_FLAG_CULTURE) && !m_cultureOrLanguage.IsEmpty())
+ {
+ m_szCultureOrLanguageUTF8 = m_cultureOrLanguage.GetUTF8(sCultureBuffer);
+ }
+ }
+
+ inline LPCSTR GetSimpleNameUTF8()
+ {
+ return m_szSimpleNameUTF8;
+ }
+
+ inline LPCSTR GetCultureOrLanguageUTF8()
+ {
+ return m_szCultureOrLanguageUTF8;
+ }
+
+ inline const BYTE *GetPublicKeyOrTokenArray()
+ {
+ const BYTE *pPublicKeyOrToken = m_publicKeyOrTokenBLOB;
+
+ return pPublicKeyOrToken;
+ }
+
+ protected:
+ StackScratchBuffer sSimpleNameBuffer;
+ StackScratchBuffer sCultureBuffer;
+ LPCSTR m_szSimpleNameUTF8;
+ LPCSTR m_szCultureOrLanguageUTF8;
+ };
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/assemblyidentitycache.hpp b/src/coreclr/binder/inc/assemblyidentitycache.hpp
new file mode 100644
index 00000000000..bb70af109fd
--- /dev/null
+++ b/src/coreclr/binder/inc/assemblyidentitycache.hpp
@@ -0,0 +1,115 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// AssemblyIdentityCache.hpp
+//
+
+
+//
+// Defines the AssemblyIdentityCache class and its helpers
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_IDENTITY_CACHE_HPP__
+#define __BINDER__ASSEMBLY_IDENTITY_CACHE_HPP__
+
+#include "bindertypes.hpp"
+#include "assemblyidentity.hpp"
+#include "utils.hpp"
+#include "sstring.h"
+#include "shash.h"
+
+namespace BINDER_SPACE
+{
+ class AssemblyIdentityCacheEntry
+ {
+ public:
+ inline AssemblyIdentityCacheEntry()
+ {
+ m_szTextualIdentity = NULL;
+ m_pAssemblyIdentity = NULL;
+ }
+ inline ~AssemblyIdentityCacheEntry()
+ {
+ SAFE_DELETE_ARRAY(m_szTextualIdentity);
+ SAFE_DELETE(m_pAssemblyIdentity);
+ }
+
+ // Getters/Setters
+ inline LPCSTR GetTextualIdentity()
+ {
+ return m_szTextualIdentity;
+ }
+ inline void SetTextualIdentity(LPCSTR szTextualIdentity)
+ {
+ size_t len = strlen(szTextualIdentity) + 1;
+
+ m_szTextualIdentity = new char[len];
+ strcpy_s((LPSTR) m_szTextualIdentity, len, szTextualIdentity);
+ }
+ inline AssemblyIdentityUTF8 *GetAssemblyIdentity()
+ {
+ return m_pAssemblyIdentity;
+ }
+ inline void SetAssemblyIdentity(AssemblyIdentityUTF8 *pAssemblyIdentity)
+ {
+ m_pAssemblyIdentity = pAssemblyIdentity;
+ }
+
+ protected:
+ LPCSTR m_szTextualIdentity;
+ AssemblyIdentityUTF8 *m_pAssemblyIdentity;
+ };
+
+ class AssemblyIdentityHashTraits : public DefaultSHashTraits<AssemblyIdentityCacheEntry *>
+ {
+ public:
+ typedef LPCSTR key_t;
+
+ static key_t GetKey(element_t pAssemblyIdentityCacheEntry)
+ {
+ return pAssemblyIdentityCacheEntry->GetTextualIdentity();
+ }
+ static BOOL Equals(key_t textualIdentity1, key_t textualIdentity2)
+ {
+ if ((textualIdentity1 == NULL) && (textualIdentity2 == NULL))
+ return TRUE;
+ if ((textualIdentity1 == NULL) || (textualIdentity2 == NULL))
+ return FALSE;
+
+ return (strcmp(textualIdentity1, textualIdentity2) == 0);
+ }
+ static count_t Hash(key_t textualIdentity)
+ {
+ if (textualIdentity == NULL)
+ return 0;
+ else
+ return HashStringA(textualIdentity);
+ }
+ static element_t Null()
+ {
+ return NULL;
+ }
+ static bool IsNull(const element_t &assemblyIdentityCacheEntry)
+ {
+ return (assemblyIdentityCacheEntry == NULL);
+ }
+
+ };
+
+ class AssemblyIdentityCache : protected SHash<AssemblyIdentityHashTraits>
+ {
+ private:
+ typedef SHash<AssemblyIdentityHashTraits> Hash;
+ public:
+ AssemblyIdentityCache();
+ ~AssemblyIdentityCache();
+
+ HRESULT Add(/* in */ LPCSTR szTextualIdentity,
+ /* in */ AssemblyIdentityUTF8 *pAssemblyIdentity);
+ AssemblyIdentityUTF8 *Lookup(/* in */ LPCSTR szTextualIdentity);
+ };
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/assemblyname.hpp b/src/coreclr/binder/inc/assemblyname.hpp
new file mode 100644
index 00000000000..fb66d9830e0
--- /dev/null
+++ b/src/coreclr/binder/inc/assemblyname.hpp
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// AssemblyName.hpp
+//
+
+
+//
+// Defines the AssemblyName class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_NAME_HPP__
+#define __BINDER__ASSEMBLY_NAME_HPP__
+
+#include "bindertypes.hpp"
+#include "assemblyidentity.hpp"
+
+namespace BINDER_SPACE
+{
+ class AssemblyName : protected AssemblyIdentity
+ {
+ public:
+ typedef enum
+ {
+ INCLUDE_DEFAULT = 0x00,
+ INCLUDE_VERSION = 0x01,
+ INCLUDE_ARCHITECTURE = 0x02,
+ INCLUDE_RETARGETABLE = 0x04,
+ INCLUDE_CONTENT_TYPE = 0x08,
+ INCLUDE_PUBLIC_KEY_TOKEN = 0x10,
+ EXCLUDE_CULTURE = 0x20
+ } INCLUDE_FLAGS;
+
+ AssemblyName();
+ ~AssemblyName();
+
+ HRESULT Init(/* in */ IMDInternalImport *pIMetaDataAssemblyImport,
+ /* in */ PEKIND PeKind,
+ /* in */ mdAssemblyRef mda = 0,
+ /* in */ BOOL fIsDefinition = TRUE);
+ HRESULT Init(/* in */ SString &assemblyDisplayName);
+ HRESULT Init(/* in */ IAssemblyName *pIAssemblyName);
+
+ ULONG AddRef();
+ ULONG Release();
+
+ // Getters/Setters
+ inline SString &GetSimpleName();
+ inline void SetSimpleName(SString &simpleName);
+ inline AssemblyVersion *GetVersion();
+ inline void SetVersion(/* in */ AssemblyVersion *pAssemblyVersion);
+ inline SString &GetCulture();
+ inline void SetCulture(SString &culture);
+ inline SBuffer &GetPublicKeyTokenBLOB();
+ inline PEKIND GetArchitecture();
+ inline void SetArchitecture(PEKIND kArchitecture);
+ inline AssemblyContentType GetContentType();
+ inline void SetContentType(AssemblyContentType kContentType);
+ inline BOOL GetIsRetargetable();
+ inline void SetIsRetargetable(BOOL fIsRetargetable);
+ inline BOOL GetIsDefinition();
+ inline void SetIsDefinition(BOOL fIsDefinition);
+
+ inline void SetHave(DWORD dwIdentityFlags);
+
+ BOOL IsCoreLib();
+
+ ULONG Hash(/* in */ DWORD dwIncludeFlags);
+ BOOL Equals(/* in */ AssemblyName *pAssemblyName,
+ /* in */ DWORD dwIncludeFlags);
+
+ void GetDisplayName(/* out */ PathString &displayName,
+ /* in */ DWORD dwIncludeFlags);
+
+ protected:
+ enum
+ {
+ NAME_FLAG_NONE = 0x00,
+ NAME_FLAG_RETARGETABLE = 0x01,
+ NAME_FLAG_DEFINITION = 0x02,
+ };
+
+ SString &GetNormalizedCulture();
+
+ LONG m_cRef;
+ DWORD m_dwNameFlags;
+ };
+
+#include "assemblyname.inl"
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/assemblyname.inl b/src/coreclr/binder/inc/assemblyname.inl
new file mode 100644
index 00000000000..11d5dbbe869
--- /dev/null
+++ b/src/coreclr/binder/inc/assemblyname.inl
@@ -0,0 +1,133 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// AssemblyName.inl
+//
+
+
+//
+// Implements the inlined methods of AssemblyName class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_NAME_INL__
+#define __BINDER__ASSEMBLY_NAME_INL__
+
+SString &AssemblyName::GetSimpleName()
+{
+ return m_simpleName;
+}
+
+void AssemblyName::SetSimpleName(SString &simpleName)
+{
+ m_simpleName.Set(simpleName);
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_SIMPLE_NAME);
+}
+
+AssemblyVersion *AssemblyName::GetVersion()
+{
+ return &m_version;
+}
+
+void AssemblyName::SetVersion(AssemblyVersion *pAssemblyVersion)
+{
+ m_version.SetVersion(pAssemblyVersion);
+}
+
+SString &AssemblyName::GetCulture()
+{
+ return m_cultureOrLanguage;
+}
+
+void AssemblyName::SetCulture(SString &culture)
+{
+ m_cultureOrLanguage.Set(culture);
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_CULTURE);
+}
+
+SBuffer &AssemblyName::GetPublicKeyTokenBLOB()
+{
+ return m_publicKeyOrTokenBLOB;
+}
+
+PEKIND AssemblyName::GetArchitecture()
+{
+ return m_kProcessorArchitecture;
+}
+
+void AssemblyName::SetArchitecture(PEKIND kArchitecture)
+{
+ m_kProcessorArchitecture = kArchitecture;
+
+ if (kArchitecture != peNone)
+ {
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
+ }
+ else
+ {
+ SetClear(AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
+ }
+}
+
+AssemblyContentType AssemblyName::GetContentType()
+{
+ return m_kContentType;
+}
+
+void AssemblyName::SetContentType(AssemblyContentType kContentType)
+{
+ m_kContentType = kContentType;
+
+ if (kContentType != AssemblyContentType_Default)
+ {
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
+ }
+ else
+ {
+ SetClear(AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
+ }
+}
+
+BOOL AssemblyName::GetIsRetargetable()
+{
+ return m_dwIdentityFlags & AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE;
+}
+
+void AssemblyName::SetIsRetargetable(BOOL fIsRetargetable)
+{
+ if (fIsRetargetable)
+ {
+ m_dwNameFlags |= NAME_FLAG_RETARGETABLE;
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
+ }
+ else
+ {
+ m_dwNameFlags &= ~NAME_FLAG_RETARGETABLE;
+ SetClear(AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
+ }
+}
+
+BOOL AssemblyName::GetIsDefinition()
+{
+ return ((m_dwNameFlags & NAME_FLAG_DEFINITION) != 0);
+}
+
+void AssemblyName::SetIsDefinition(BOOL fIsDefinition)
+{
+ if (fIsDefinition)
+ {
+ m_dwNameFlags |= NAME_FLAG_DEFINITION;
+ }
+ else
+ {
+ m_dwNameFlags &= ~NAME_FLAG_DEFINITION;
+ }
+}
+
+void AssemblyName::SetHave(DWORD dwIdentityFlags)
+{
+ AssemblyIdentity::SetHave(dwIdentityFlags);
+}
+
+#endif
diff --git a/src/coreclr/binder/inc/assemblyversion.hpp b/src/coreclr/binder/inc/assemblyversion.hpp
new file mode 100644
index 00000000000..ff8be72a11c
--- /dev/null
+++ b/src/coreclr/binder/inc/assemblyversion.hpp
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// AssemblyVersion.hpp
+//
+
+
+//
+// Defines the AssemblyVersion class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_VERSION_HPP__
+#define __BINDER__ASSEMBLY_VERSION_HPP__
+
+#include "bindertypes.hpp"
+#include "textualidentityparser.hpp"
+
+namespace BINDER_SPACE
+{
+ class AssemblyVersion
+ {
+ private:
+ static const DWORD Unspecified = (DWORD)-1;
+ static const USHORT UnspecifiedShort = (USHORT)-1;
+
+ public:
+ inline AssemblyVersion();
+ inline ~AssemblyVersion();
+
+ inline BOOL HasMajor();
+ inline BOOL HasMinor();
+ inline BOOL HasBuild();
+ inline BOOL HasRevision();
+
+ inline DWORD GetMajor();
+ inline DWORD GetMinor();
+ inline DWORD GetBuild();
+ inline DWORD GetRevision();
+
+ inline void SetFeatureVersion(/* in */ DWORD dwMajor,
+ /* in */ DWORD dwMinor);
+ inline void SetServiceVersion(/* in */ DWORD dwBuild,
+ /* in */ DWORD dwRevision);
+ inline void SetVersion(AssemblyVersion *pAssemblyVersion);
+
+ inline BOOL Equals(AssemblyVersion *pAssemblyVersion);
+ private:
+ DWORD m_dwMajor;
+ DWORD m_dwMinor;
+ DWORD m_dwBuild;
+ DWORD m_dwRevision;
+ };
+
+#include "assemblyversion.inl"
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/assemblyversion.inl b/src/coreclr/binder/inc/assemblyversion.inl
new file mode 100644
index 00000000000..b479c0e74fc
--- /dev/null
+++ b/src/coreclr/binder/inc/assemblyversion.inl
@@ -0,0 +1,108 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// AssemblyVersion.inl
+//
+
+
+//
+// Implements the inline methods of AssemblyVersion
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_VERSION_INL__
+#define __BINDER__ASSEMBLY_VERSION_INL__
+
+AssemblyVersion::AssemblyVersion()
+{
+ m_dwMajor = m_dwMinor = m_dwBuild = m_dwRevision = static_cast<DWORD>(-1);
+}
+
+AssemblyVersion::~AssemblyVersion()
+{
+ // Noting to do here
+}
+
+BOOL AssemblyVersion::HasMajor()
+{
+ return m_dwMajor != Unspecified;
+}
+
+BOOL AssemblyVersion::HasMinor()
+{
+ return m_dwMinor != Unspecified;
+}
+
+BOOL AssemblyVersion::HasBuild()
+{
+ return m_dwBuild != Unspecified;
+}
+
+BOOL AssemblyVersion::HasRevision()
+{
+ return m_dwRevision != Unspecified;
+}
+
+DWORD AssemblyVersion::GetMajor()
+{
+ return m_dwMajor;
+}
+
+DWORD AssemblyVersion::GetMinor()
+{
+ return m_dwMinor;
+}
+
+DWORD AssemblyVersion::GetBuild()
+{
+ return m_dwBuild;
+}
+
+DWORD AssemblyVersion::GetRevision()
+{
+ return m_dwRevision;
+}
+
+void AssemblyVersion::SetFeatureVersion(DWORD dwMajor,
+ DWORD dwMinor)
+{
+ // BaseAssemblySpec and AssemblyName properties store uint16 components for the version. Version and AssemblyVersion store
+ // int32 or uint32. When the former are initialized from the latter, the components are truncated to uint16 size. When the
+ // latter are initialized from the former, they are zero-extended to int32 size. For uint16 components, the max value is
+ // used to indicate an unspecified component. For int32 components, -1 is used. Since we're treating the version as an
+ // assembly version here, map the uint16 unspecified value to the int32 size.
+ m_dwMajor = dwMajor == UnspecifiedShort ? Unspecified : dwMajor;
+ m_dwMinor = dwMinor == UnspecifiedShort ? Unspecified : dwMinor;
+}
+
+void AssemblyVersion::SetServiceVersion(DWORD dwBuild,
+ DWORD dwRevision)
+{
+ // See comment in SetFeatureVersion, the same applies here
+ m_dwBuild = dwBuild == UnspecifiedShort ? Unspecified : dwBuild;
+ m_dwRevision = dwRevision == UnspecifiedShort ? Unspecified : dwRevision;
+}
+
+void AssemblyVersion::SetVersion(AssemblyVersion *pAssemblyVersion)
+{
+ m_dwMajor = pAssemblyVersion->GetMajor();
+ m_dwMinor = pAssemblyVersion->GetMinor();
+ m_dwBuild = pAssemblyVersion->GetBuild();
+ m_dwRevision = pAssemblyVersion->GetRevision();
+}
+
+BOOL AssemblyVersion::Equals(AssemblyVersion *pAssemblyVersion)
+{
+ BOOL result = FALSE;
+ if ((GetMajor() == pAssemblyVersion->GetMajor()) &&
+ (GetMinor() == pAssemblyVersion->GetMinor()) &&
+ (GetBuild() == pAssemblyVersion->GetBuild()) &&
+ (GetRevision() == pAssemblyVersion->GetRevision()))
+ {
+ result = TRUE;
+ }
+ return result;
+}
+
+#endif
diff --git a/src/coreclr/binder/inc/bindertracing.h b/src/coreclr/binder/inc/bindertracing.h
new file mode 100644
index 00000000000..5d82888158a
--- /dev/null
+++ b/src/coreclr/binder/inc/bindertracing.h
@@ -0,0 +1,189 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// bindertracing.h
+//
+
+#ifndef __BINDER_TRACING_H__
+#define __BINDER_TRACING_H__
+
+class Assembly;
+class AssemblySpec;
+class PEAssembly;
+
+namespace BINDER_SPACE
+{
+ class Assembly;
+ class AssemblyName;
+}
+
+namespace BinderTracing
+{
+ bool IsEnabled();
+
+ // If tracing is enabled, this class fires an assembly bind start event on construction
+ // and the corresponding stop event on destruction
+ class AssemblyBindOperation
+ {
+ public:
+ // This class assumes the assembly spec will have a longer lifetime than itself
+ AssemblyBindOperation(AssemblySpec *assemblySpec, const WCHAR *assemblyPath = nullptr);
+ ~AssemblyBindOperation();
+
+ void SetResult(PEAssembly *assembly, bool cached = false);
+
+ struct BindRequest
+ {
+ AssemblySpec *AssemblySpec;
+ SString AssemblyName;
+ SString AssemblyPath;
+ SString RequestingAssembly;
+ SString AssemblyLoadContext;
+ SString RequestingAssemblyLoadContext;
+ };
+
+ private:
+ bool ShouldIgnoreBind();
+
+ private:
+ BindRequest m_bindRequest;
+ bool m_populatedBindRequest;
+
+ bool m_checkedIgnoreBind;
+ bool m_ignoreBind;
+
+ PEAssembly *m_resultAssembly;
+ bool m_cached;
+ };
+
+ // An object of this class manages firing events for all the stages during a binder resolving
+ // attempt operation. It has minimal cost if tracing for this event is disabled.
+ //
+ // This class should be declared in the stack. As information is determined by each stage
+ // (e.g. an AssemblySpec is initialized), the appropriate Set*() method should be called. All
+ // pointers held by an object of this class must either be a nullptr, or point to a valid
+ // object during the time it is in scope.
+ //
+ // As the resolution progresses to different stages, the GoToStage() method should be called.
+ // Calling it will fire an event for the previous stage with whatever context the class had
+ // at that point; it is assumed that if GoToStage() is called, the previous stage failed
+ // (the HRESULT is read by the dtor to assess success).
+ //
+ // It holds a reference to a HRESULT (that must be live during the lifetime of this object),
+ // which is used to determine the success or failure of a stage either at the moment this
+ // class is destructed (e.g. last stage), or when moving from one stage to another. (This
+ // is especially useful if the HRESULT is captured from an exception handler.)
+ class ResolutionAttemptedOperation
+ {
+ public:
+ // This must match the ResolutionAttemptedStage value map in ClrEtwAll.man
+ enum class Stage : uint16_t
+ {
+ FindInLoadContext = 0,
+ AssemblyLoadContextLoad = 1,
+ ApplicationAssemblies = 2,
+ DefaultAssemblyLoadContextFallback = 3,
+ ResolveSatelliteAssembly = 4,
+ AssemblyLoadContextResolvingEvent = 5,
+ AppDomainAssemblyResolveEvent = 6,
+ NotYetStarted = 0xffff, // Used as flag to not fire event; not present in value map
+ };
+
+ public: // static
+ static void TraceAppDomainAssemblyResolve(AssemblySpec *spec, PEAssembly *resultAssembly, Exception *exception = nullptr);
+
+ public:
+ // One of binder ID and managed ALC is expected to be non-zero. If the managed ALC is set, binder ID is ignored.
+ ResolutionAttemptedOperation(BINDER_SPACE::AssemblyName *assemblyName, UINT_PTR binderId, INT_PTR managedALC, const HRESULT& hr);
+
+ void TraceBindResult(const BINDER_SPACE::BindResult &bindResult, bool mvidMismatch = false);
+
+ void SetFoundAssembly(BINDER_SPACE::Assembly *assembly)
+ {
+ m_pFoundAssembly = assembly;
+ }
+
+ void GoToStage(Stage stage)
+ {
+ assert(m_stage != stage);
+ assert(stage != Stage::NotYetStarted);
+
+ if (!m_tracingEnabled)
+ return;
+
+ // Going to a different stage should only happen if the current
+ // stage failed (or if the binding process wasn't yet started).
+ // Firing the event at this point not only helps timing each binding
+ // stage, but avoids keeping track of which stages were reached to
+ // resolve the assembly.
+ TraceStage(m_stage, m_hr, m_pFoundAssembly);
+ m_stage = stage;
+ m_exceptionMessage.Clear();
+ }
+
+ void SetException(Exception *ex)
+ {
+ if (!m_tracingEnabled)
+ return;
+
+ ex->GetMessage(m_exceptionMessage);
+ }
+
+#ifdef FEATURE_EVENT_TRACE
+ ~ResolutionAttemptedOperation()
+ {
+ if (!m_tracingEnabled)
+ return;
+
+ TraceStage(m_stage, m_hr, m_pFoundAssembly);
+ }
+#endif // FEATURE_EVENT_TRACE
+
+ private:
+
+ // This must match the ResolutionAttemptedResult value map in ClrEtwAll.man
+ enum class Result : uint16_t
+ {
+ Success = 0,
+ AssemblyNotFound = 1,
+ IncompatibleVersion = 2,
+ MismatchedAssemblyName = 3,
+ Failure = 4,
+ Exception = 5,
+ };
+
+ // A reference to an HRESULT stored in the same scope as this object lets
+ // us determine if the last requested stage was successful or not, regardless
+ // if it was set through a function call (e.g. BindAssemblyByNameWorker()), or
+ // if an exception was thrown and captured by the EX_CATCH_HRESULT() macro.
+ const HRESULT &m_hr;
+
+ Stage m_stage;
+
+ bool m_tracingEnabled;
+
+ BINDER_SPACE::AssemblyName *m_assemblyNameObject;
+ PathString m_assemblyName;
+ SString m_assemblyLoadContextName;
+
+ SString m_exceptionMessage;
+ BINDER_SPACE::Assembly *m_pFoundAssembly;
+
+ void TraceStage(Stage stage, HRESULT hr, BINDER_SPACE::Assembly *resultAssembly, const WCHAR *errorMessage = nullptr);
+ };
+
+ // This must match the BindingPathSource value map in ClrEtwAll.man
+ enum PathSource
+ {
+ ApplicationAssemblies,
+ AppNativeImagePaths,
+ AppPaths,
+ PlatformResourceRoots,
+ SatelliteSubdirectory,
+ Bundle
+ };
+
+ void PathProbed(const WCHAR *path, PathSource source, HRESULT hr);
+};
+
+#endif // __BINDER_TRACING_H__
diff --git a/src/coreclr/binder/inc/bindertypes.hpp b/src/coreclr/binder/inc/bindertypes.hpp
new file mode 100644
index 00000000000..08159ebc840
--- /dev/null
+++ b/src/coreclr/binder/inc/bindertypes.hpp
@@ -0,0 +1,109 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// BinderTypes.hpp
+//
+
+
+//
+// Declares a bunch of binder classes, types and macros
+//
+// ============================================================
+
+#ifndef __BINDER_TYPES_HPP__
+#define __BINDER_TYPES_HPP__
+
+#include "clrtypes.h"
+#include "sstring.h"
+
+#include "fusionhelpers.hpp"
+
+extern void DECLSPEC_NORETURN ThrowOutOfMemory();
+
+#ifndef S_TRUE
+#define S_TRUE S_OK
+#endif
+
+class PEImage;
+class PEAssembly;
+
+namespace BINDER_SPACE
+{
+ class AssemblyVersion;
+ class AssemblyName;
+ class Assembly;
+
+ class ContextEntry;
+ class ExecutionContext;
+
+ class ApplicationContext;
+
+ class BindResult;
+ class FailureCache;
+ class AssemblyBinder;
+};
+
+#define IF_FAIL_GO(expr) \
+ hr = (expr); \
+ if (FAILED(hr)) \
+ { \
+ goto Exit; \
+ }
+
+#define IF_FALSE_GO(expr) \
+ if (!(expr)) { \
+ hr = E_FAIL; \
+ goto Exit; \
+ }
+
+#define GO_WITH_HRESULT(hrValue) \
+ hr = hrValue; \
+ goto Exit;
+
+#define IF_WIN32_ERROR_GO(expr) \
+ if (!(expr)) \
+ { \
+ hr = HRESULT_FROM_GetLastError(); \
+ goto Exit; \
+ }
+
+#define NEW_CONSTR(Object, Constr) \
+ (Object) = new (nothrow) Constr;
+
+#define SAFE_NEW_CONSTR(Object, Constr) \
+ (Object) = new (nothrow) Constr; \
+ if ((Object) == NULL) \
+ { \
+ hr = E_OUTOFMEMORY; \
+ goto Exit; \
+ }
+
+#define SAFE_NEW(Object, Class) \
+ SAFE_NEW_CONSTR(Object, Class());
+
+#define SAFE_RELEASE(objectPtr) \
+ if ((objectPtr) != NULL) \
+ { \
+ (objectPtr)->Release(); \
+ (objectPtr) = NULL; \
+ }
+
+#define SAFE_DELETE(objectPtr) \
+ if ((objectPtr) != NULL) \
+ { \
+ delete (objectPtr); \
+ (objectPtr) = NULL; \
+ }
+
+#define SAFE_DELETE_ARRAY(objectPtr) \
+ if ((objectPtr) != NULL) \
+ { \
+ delete[] (objectPtr); \
+ (objectPtr) = NULL; \
+ }
+
+#define LENGTH_OF(x) \
+ (sizeof(x) / sizeof(x[0]))
+
+#endif
diff --git a/src/coreclr/binder/inc/bindresult.hpp b/src/coreclr/binder/inc/bindresult.hpp
new file mode 100644
index 00000000000..b305c525c3b
--- /dev/null
+++ b/src/coreclr/binder/inc/bindresult.hpp
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// BindResult.hpp
+//
+
+
+//
+// Defines the BindResult class
+//
+// ============================================================
+
+#ifndef __BINDER__BIND_RESULT_HPP__
+#define __BINDER__BIND_RESULT_HPP__
+
+#include "bindertypes.hpp"
+
+namespace BINDER_SPACE
+{
+ class BindResult
+ {
+ public:
+ inline BindResult();
+ inline ~BindResult();
+
+ inline AssemblyName *GetAssemblyName(BOOL fAddRef = FALSE);
+ inline IUnknown *GetAssembly(BOOL fAddRef = FALSE);
+ inline Assembly *GetAsAssembly(BOOL fAddRef = FALSE);
+
+ inline BOOL GetIsInGAC();
+ inline void SetIsInGAC(BOOL fIsInGAC);
+ inline BOOL GetIsContextBound();
+ inline void SetIsContextBound(BOOL fIsContextBound);
+ inline BOOL GetIsFirstRequest();
+ inline void SetIsFirstRequest(BOOL fIsFirstRequest);
+
+ inline void SetResult(ContextEntry *pContextEntry, BOOL fIsContextBound = TRUE);
+ inline void SetResult(Assembly *pAssembly);
+ inline void SetResult(BindResult *pBindResult);
+
+ inline void SetNoResult();
+ inline BOOL HaveResult();
+
+ inline void Reset();
+
+ struct AttemptResult
+ {
+ HRESULT HResult;
+ ReleaseHolder<Assembly> Assembly;
+ bool Attempted = false;
+
+ void Set(const AttemptResult *result);
+
+ void Reset()
+ {
+ Assembly = nullptr;
+ Attempted = false;
+ }
+ };
+
+ // Set attempt result for binding to existing context entry
+ void SetAttemptResult(HRESULT hr, ContextEntry *pContextEntry);
+
+ // Set attempt result for binding to platform assemblies
+ void SetAttemptResult(HRESULT hr, Assembly *pAssembly);
+
+ const AttemptResult* GetAttempt(bool foundInContext) const;
+
+ protected:
+ DWORD m_dwResultFlags;
+ AssemblyName *m_pAssemblyName;
+ ReleaseHolder<IUnknown> m_pIUnknownAssembly;
+
+ AttemptResult m_inContextAttempt;
+ AttemptResult m_applicationAssembliesAttempt;
+ };
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/bindresult.inl b/src/coreclr/binder/inc/bindresult.inl
new file mode 100644
index 00000000000..183c7807a48
--- /dev/null
+++ b/src/coreclr/binder/inc/bindresult.inl
@@ -0,0 +1,212 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// BindResult.inl
+//
+
+
+//
+// Implements the inline methods of BindResult
+//
+// ============================================================
+
+#ifndef __BINDER__BIND_RESULT_INL__
+#define __BINDER__BIND_RESULT_INL__
+
+#include "contextentry.hpp"
+#include "assembly.hpp"
+
+namespace BINDER_SPACE
+{
+BindResult::BindResult()
+{
+ m_dwResultFlags = ContextEntry::RESULT_FLAG_NONE;
+ m_pAssemblyName = NULL;
+ m_pIUnknownAssembly = NULL;
+}
+
+BindResult::~BindResult()
+{
+ SAFE_RELEASE(m_pAssemblyName);
+}
+
+AssemblyName *BindResult::GetAssemblyName(BOOL fAddRef /* = FALSE */)
+{
+ AssemblyName *pAssemblyName = m_pAssemblyName;
+
+ if (fAddRef && (pAssemblyName != NULL))
+ {
+ pAssemblyName->AddRef();
+ }
+
+ return pAssemblyName;
+}
+
+IUnknown *BindResult::GetAssembly(BOOL fAddRef /* = FALSE */)
+{
+ IUnknown *pIUnknownAssembly = m_pIUnknownAssembly;
+
+ if (fAddRef && (pIUnknownAssembly != NULL))
+ {
+ pIUnknownAssembly->AddRef();
+ }
+
+ return pIUnknownAssembly;
+}
+
+Assembly *BindResult::GetAsAssembly(BOOL fAddRef /* = FALSE */)
+{
+ return static_cast<Assembly *>(GetAssembly(fAddRef));
+}
+
+BOOL BindResult::GetIsInGAC()
+{
+ return ((m_dwResultFlags & ContextEntry::RESULT_FLAG_IS_IN_GAC) != 0);
+}
+
+void BindResult::SetIsInGAC(BOOL fIsInGAC)
+{
+ if (fIsInGAC)
+ {
+ m_dwResultFlags |= ContextEntry::RESULT_FLAG_IS_IN_GAC;
+ }
+ else
+ {
+ m_dwResultFlags &= ~ContextEntry::RESULT_FLAG_IS_IN_GAC;
+ }
+}
+
+BOOL BindResult::GetIsContextBound()
+{
+ return ((m_dwResultFlags & ContextEntry::RESULT_FLAG_CONTEXT_BOUND) != 0);
+}
+
+void BindResult::SetIsContextBound(BOOL fIsContextBound)
+{
+ if (fIsContextBound)
+ {
+ m_dwResultFlags |= ContextEntry::RESULT_FLAG_CONTEXT_BOUND;
+ }
+ else
+ {
+ m_dwResultFlags &= ~ContextEntry::RESULT_FLAG_CONTEXT_BOUND;
+ }
+}
+
+BOOL BindResult::GetIsFirstRequest()
+{
+ return ((m_dwResultFlags & ContextEntry::RESULT_FLAG_FIRST_REQUEST) != 0);
+}
+
+void BindResult::SetIsFirstRequest(BOOL fIsFirstRequest)
+{
+ if (fIsFirstRequest)
+ {
+ m_dwResultFlags |= ContextEntry::RESULT_FLAG_FIRST_REQUEST;
+ }
+ else
+ {
+ m_dwResultFlags &= ~ContextEntry::RESULT_FLAG_FIRST_REQUEST;
+ }
+}
+
+void BindResult::SetResult(ContextEntry *pContextEntry, BOOL fIsContextBound /* = TRUE */)
+{
+ _ASSERTE(pContextEntry != NULL);
+
+ SetIsInGAC(pContextEntry->GetIsInGAC());
+ SetIsContextBound(fIsContextBound);
+ SAFE_RELEASE(m_pAssemblyName);
+ m_pAssemblyName = pContextEntry->GetAssemblyName(TRUE /* fAddRef */);
+ m_pIUnknownAssembly = pContextEntry->GetAssembly(TRUE /* fAddRef */);
+}
+
+void BindResult::SetResult(Assembly *pAssembly)
+{
+ _ASSERTE(pAssembly != NULL);
+
+ SetIsInGAC(pAssembly->GetIsInGAC());
+ SAFE_RELEASE(m_pAssemblyName);
+ m_pAssemblyName = pAssembly->GetAssemblyName(TRUE /* fAddRef */);
+ pAssembly->AddRef();
+ m_pIUnknownAssembly = static_cast<IUnknown *>(pAssembly);
+}
+
+void BindResult::SetResult(BindResult *pBindResult)
+{
+ _ASSERTE(pBindResult != NULL);
+
+ m_dwResultFlags = pBindResult->m_dwResultFlags;
+ SAFE_RELEASE(m_pAssemblyName);
+ m_pAssemblyName = pBindResult->GetAssemblyName(TRUE /* fAddRef */);
+ m_pIUnknownAssembly = pBindResult->GetAssembly(TRUE /* fAddRef */);
+
+ const AttemptResult *attempt = pBindResult->GetAttempt(true /*foundInContext*/);
+ if (attempt != nullptr)
+ m_inContextAttempt.Set(attempt);
+
+ attempt = pBindResult->GetAttempt(false /*foundInContext*/);
+ if (attempt != nullptr)
+ m_applicationAssembliesAttempt.Set(attempt);
+}
+
+void BindResult::SetNoResult()
+{
+ m_pAssemblyName = NULL;
+}
+
+BOOL BindResult::HaveResult()
+{
+ return (GetAssemblyName() != NULL);
+}
+
+void BindResult::Reset()
+{
+ SAFE_RELEASE(m_pAssemblyName);
+ m_pIUnknownAssembly = NULL;
+ m_dwResultFlags = ContextEntry::RESULT_FLAG_NONE;
+ m_inContextAttempt.Reset();
+ m_applicationAssembliesAttempt.Reset();
+}
+
+void BindResult::SetAttemptResult(HRESULT hr, ContextEntry *pContextEntry)
+{
+ Assembly *assembly = nullptr;
+ if (pContextEntry != nullptr)
+ assembly = static_cast<Assembly *>(pContextEntry->GetAssembly(TRUE /* fAddRef */));
+
+ m_inContextAttempt.Assembly = assembly;
+ m_inContextAttempt.HResult = hr;
+ m_inContextAttempt.Attempted = true;
+}
+
+void BindResult::SetAttemptResult(HRESULT hr, Assembly *pAssembly)
+{
+ if (pAssembly != nullptr)
+ pAssembly->AddRef();
+
+ m_applicationAssembliesAttempt.Assembly = pAssembly;
+ m_applicationAssembliesAttempt.HResult = hr;
+ m_applicationAssembliesAttempt.Attempted = true;
+}
+
+const BindResult::AttemptResult* BindResult::GetAttempt(bool foundInContext) const
+{
+ const BindResult::AttemptResult &result = foundInContext ? m_inContextAttempt : m_applicationAssembliesAttempt;
+ return result.Attempted ? &result : nullptr;
+}
+
+void BindResult::AttemptResult::Set(const BindResult::AttemptResult *result)
+{
+ BINDER_SPACE::Assembly *assembly = result->Assembly;
+ if (assembly != nullptr)
+ assembly->AddRef();
+
+ Assembly = assembly;
+ HResult = result->HResult;
+ Attempted = result->Attempted;
+}
+
+}
+#endif
diff --git a/src/coreclr/binder/inc/clrprivbinderassemblyloadcontext.h b/src/coreclr/binder/inc/clrprivbinderassemblyloadcontext.h
new file mode 100644
index 00000000000..3c1c4062302
--- /dev/null
+++ b/src/coreclr/binder/inc/clrprivbinderassemblyloadcontext.h
@@ -0,0 +1,86 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+
+#ifndef __CLRPRIVBINDERASSEMBLYLOADCONTEXT_H__
+#define __CLRPRIVBINDERASSEMBLYLOADCONTEXT_H__
+
+#include "coreclrbindercommon.h"
+#include "applicationcontext.hpp"
+#include "clrprivbindercoreclr.h"
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+namespace BINDER_SPACE
+{
+ class AssemblyIdentityUTF8;
+};
+
+class AppDomain;
+
+class Object;
+class Assembly;
+class LoaderAllocator;
+
+class CLRPrivBinderAssemblyLoadContext : public AssemblyLoadContext
+{
+public:
+
+ //=========================================================================
+ // ICLRPrivBinder functions
+ //-------------------------------------------------------------------------
+ STDMETHOD(BindAssemblyByName)(
+ /* [in] */ IAssemblyName *pIAssemblyName,
+ /* [retval][out] */ ICLRPrivAssembly **ppAssembly);
+
+ STDMETHOD(GetLoaderAllocator)(
+ /* [retval][out] */ LPVOID *pLoaderAllocator);
+
+public:
+ //=========================================================================
+ // Class functions
+ //-------------------------------------------------------------------------
+
+ static HRESULT SetupContext(DWORD dwAppDomainId,
+ CLRPrivBinderCoreCLR *pTPABinder,
+ LoaderAllocator* pLoaderAllocator,
+ void* loaderAllocatorHandle,
+ UINT_PTR ptrAssemblyLoadContext,
+ CLRPrivBinderAssemblyLoadContext **ppBindContext);
+
+ void PrepareForLoadContextRelease(INT_PTR ptrManagedStrongAssemblyLoadContext);
+ void ReleaseLoadContext();
+
+ CLRPrivBinderAssemblyLoadContext();
+
+ inline BINDER_SPACE::ApplicationContext *GetAppContext()
+ {
+ return &m_appContext;
+ }
+
+ HRESULT BindUsingPEImage( /* in */ PEImage *pPEImage,
+ /* in */ BOOL fIsNativeImage,
+ /* [retval][out] */ ICLRPrivAssembly **ppAssembly);
+
+ //=========================================================================
+ // Internal implementation details
+ //-------------------------------------------------------------------------
+private:
+ HRESULT BindAssemblyByNameWorker(BINDER_SPACE::AssemblyName *pAssemblyName, BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly);
+
+ BINDER_SPACE::ApplicationContext m_appContext;
+
+ CLRPrivBinderCoreCLR *m_pTPABinder;
+
+ // A strong GC handle to the managed AssemblyLoadContext. This handle is set when the unload of the AssemblyLoadContext is initiated
+ // to keep the managed AssemblyLoadContext alive until the unload is finished.
+ // We still keep the weak handle pointing to the same managed AssemblyLoadContext so that native code can use the handle above
+ // to refer to it during the whole lifetime of the AssemblyLoadContext.
+ INT_PTR m_ptrManagedStrongAssemblyLoadContext;
+
+ LoaderAllocator* m_pAssemblyLoaderAllocator;
+ void* m_loaderAllocatorHandle;
+};
+
+#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+#endif // __CLRPRIVBINDERASSEMBLYLOADCONTEXT_H__
diff --git a/src/coreclr/binder/inc/clrprivbindercoreclr.h b/src/coreclr/binder/inc/clrprivbindercoreclr.h
new file mode 100644
index 00000000000..bf11bcf113f
--- /dev/null
+++ b/src/coreclr/binder/inc/clrprivbindercoreclr.h
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+
+#ifndef __CLR_PRIV_BINDER_CORECLR_H__
+#define __CLR_PRIV_BINDER_CORECLR_H__
+
+#include "coreclrbindercommon.h"
+#include "applicationcontext.hpp"
+#include "assemblyloadcontext.h"
+
+namespace BINDER_SPACE
+{
+ class AssemblyIdentityUTF8;
+};
+
+class CLRPrivBinderCoreCLR : public AssemblyLoadContext
+{
+public:
+
+ //=========================================================================
+ // ICLRPrivBinder functions
+ //-------------------------------------------------------------------------
+ STDMETHOD(BindAssemblyByName)(
+ /* [in] */ IAssemblyName *pIAssemblyName,
+ /* [retval][out] */ ICLRPrivAssembly **ppAssembly);
+
+ STDMETHOD(GetLoaderAllocator)(
+ /* [retval][out] */ LPVOID *pLoaderAllocator);
+
+public:
+
+ HRESULT SetupBindingPaths(SString &sTrustedPlatformAssemblies,
+ SString &sPlatformResourceRoots,
+ SString &sAppPaths,
+ SString &sAppNiPaths);
+
+ inline BINDER_SPACE::ApplicationContext *GetAppContext()
+ {
+ return &m_appContext;
+ }
+
+ HRESULT Bind(SString &assemblyDisplayName,
+ LPCWSTR wszCodeBase,
+ PEAssembly *pParentAssembly,
+ BOOL fNgenExplicitBind,
+ BOOL fExplicitBindToNativeImage,
+ ICLRPrivAssembly **ppAssembly);
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ HRESULT BindUsingPEImage( /* in */ PEImage *pPEImage,
+ /* in */ BOOL fIsNativeImage,
+ /* [retval][out] */ ICLRPrivAssembly **ppAssembly);
+#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+ HRESULT BindAssemblyByNameWorker(
+ BINDER_SPACE::AssemblyName *pAssemblyName,
+ BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly,
+ bool excludeAppPaths);
+
+ //=========================================================================
+ // Internal implementation details
+ //-------------------------------------------------------------------------
+private:
+ BINDER_SPACE::ApplicationContext m_appContext;
+};
+
+#endif // __CLR_PRIV_BINDER_CORECLR_H__
diff --git a/src/coreclr/binder/inc/contextentry.hpp b/src/coreclr/binder/inc/contextentry.hpp
new file mode 100644
index 00000000000..ff3c8dba83c
--- /dev/null
+++ b/src/coreclr/binder/inc/contextentry.hpp
@@ -0,0 +1,110 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// ContextEntry.hpp
+//
+
+
+//
+// Defines the ContextEntry class
+//
+// ============================================================
+
+#ifndef __BINDER__CONTEXT_ENTRY_HPP__
+#define __BINDER__CONTEXT_ENTRY_HPP__
+
+#include "assemblyentry.hpp"
+#include "assembly.hpp"
+
+namespace BINDER_SPACE
+{
+ class ContextEntry : public AssemblyEntry
+ {
+ public:
+ typedef enum
+ {
+ RESULT_FLAG_NONE = 0x00,
+ //RESULT_FLAG_IS_DYNAMIC_BIND = 0x01,
+ RESULT_FLAG_IS_IN_GAC = 0x02,
+ //RESULT_FLAG_FROM_MANIFEST = 0x04,
+ RESULT_FLAG_CONTEXT_BOUND = 0x08,
+ RESULT_FLAG_FIRST_REQUEST = 0x10,
+ } ResultFlags;
+
+ ContextEntry() : AssemblyEntry()
+ {
+ m_dwResultFlags = RESULT_FLAG_NONE;
+ m_pIUnknownAssembly = NULL;
+ }
+
+ ~ContextEntry()
+ {
+ SAFE_RELEASE(m_pIUnknownAssembly);
+ }
+
+ BOOL GetIsInGAC()
+ {
+ return ((m_dwResultFlags & RESULT_FLAG_IS_IN_GAC) != 0);
+ }
+
+ void SetIsInGAC(BOOL fIsInGAC)
+ {
+ if (fIsInGAC)
+ {
+ m_dwResultFlags |= RESULT_FLAG_IS_IN_GAC;
+ }
+ else
+ {
+ m_dwResultFlags &= ~RESULT_FLAG_IS_IN_GAC;
+ }
+ }
+
+ BOOL GetIsFirstRequest()
+ {
+ return ((m_dwResultFlags & RESULT_FLAG_FIRST_REQUEST) != 0);
+ }
+
+ void SetIsFirstRequest(BOOL fIsFirstRequest)
+ {
+ if (fIsFirstRequest)
+ {
+ m_dwResultFlags |= RESULT_FLAG_FIRST_REQUEST;
+ }
+ else
+ {
+ m_dwResultFlags &= ~RESULT_FLAG_FIRST_REQUEST;
+ }
+ }
+
+ IUnknown *GetAssembly(BOOL fAddRef = FALSE)
+ {
+ IUnknown *pIUnknownAssembly = m_pIUnknownAssembly;
+
+ if (fAddRef && (pIUnknownAssembly != NULL))
+ {
+ pIUnknownAssembly->AddRef();
+ }
+
+ return pIUnknownAssembly;
+ }
+
+ void SetAssembly(IUnknown *pIUnknownAssembly)
+ {
+ SAFE_RELEASE(m_pIUnknownAssembly);
+
+ if (pIUnknownAssembly != NULL)
+ {
+ pIUnknownAssembly->AddRef();
+ }
+
+ m_pIUnknownAssembly = pIUnknownAssembly;
+ }
+
+ protected:
+ DWORD m_dwResultFlags;
+ IUnknown *m_pIUnknownAssembly;
+ };
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/coreclrbindercommon.h b/src/coreclr/binder/inc/coreclrbindercommon.h
new file mode 100644
index 00000000000..4fe3249363b
--- /dev/null
+++ b/src/coreclr/binder/inc/coreclrbindercommon.h
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+
+#ifndef __CORECLR_BINDER_COMMON_H__
+#define __CORECLR_BINDER_COMMON_H__
+
+#include "clrprivbinding.h"
+#include "internalunknownimpl.h"
+#include "applicationcontext.hpp"
+
+
+namespace BINDER_SPACE
+{
+ class AssemblyIdentityUTF8;
+};
+
+class CLRPrivBinderCoreCLR;
+
+// General purpose AssemblyBinder helper class
+class CCoreCLRBinderHelper
+{
+public:
+ static HRESULT Init();
+
+ static HRESULT DefaultBinderSetupContext(DWORD dwAppDomainId,
+ CLRPrivBinderCoreCLR **ppTPABinder);
+
+ // ABHI-TODO: The call indicates that this can come from a case where
+ // pDomain->GetFusionContext() is null, hence this is static function
+ // which handles a null binder. See if this actually happens
+ static HRESULT GetAssemblyIdentity(LPCSTR szTextualIdentity,
+ BINDER_SPACE::ApplicationContext *pApplicationContext,
+ NewHolder<BINDER_SPACE::AssemblyIdentityUTF8> &assemblyIdentityHolder);
+
+ //=============================================================================
+ // Class functions that provides binding services beyond the ICLRPrivInterface
+ //-----------------------------------------------------------------------------
+ static HRESULT BindToSystem(ICLRPrivAssembly **ppSystemAssembly, bool fBindToNativeImage);
+
+ static HRESULT BindToSystemSatellite(SString &systemPath,
+ SString &sSimpleName,
+ SString &sCultureName,
+ ICLRPrivAssembly **ppSystemAssembly);
+};
+
+#endif // __CORECLR_BINDER_COMMON_H__
diff --git a/src/coreclr/binder/inc/failurecache.hpp b/src/coreclr/binder/inc/failurecache.hpp
new file mode 100644
index 00000000000..bce67b33c50
--- /dev/null
+++ b/src/coreclr/binder/inc/failurecache.hpp
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// FailureCache.hpp
+//
+
+
+//
+// Defines the FailureCache class
+//
+// ============================================================
+
+
+#ifndef __BINDER__FAILURE_CACHE_HPP__
+#define __BINDER__FAILURE_CACHE_HPP__
+
+#include "failurecachehashtraits.hpp"
+
+namespace BINDER_SPACE
+{
+ class FailureCache : protected SHash<FailureCacheHashTraits>
+ {
+ private:
+ typedef SHash<FailureCacheHashTraits> Hash;
+ public:
+ FailureCache();
+ ~FailureCache();
+
+ HRESULT Add(/* in */ SString &assemblyNameorPath,
+ /* in */ HRESULT hrBindResult);
+ HRESULT Lookup(/* in */ SString &assemblyNameorPath);
+ void Remove(/* in */ SString &assemblyName);
+ };
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/failurecachehashtraits.hpp b/src/coreclr/binder/inc/failurecachehashtraits.hpp
new file mode 100644
index 00000000000..0d9ad26156d
--- /dev/null
+++ b/src/coreclr/binder/inc/failurecachehashtraits.hpp
@@ -0,0 +1,87 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// FailureCache.hpp
+//
+
+
+//
+// Defines the FailureCache class
+//
+// ============================================================
+
+#ifndef __BINDER__FAILURE_CACHE_HASH_TRAITS_HPP__
+#define __BINDER__FAILURE_CACHE_HASH_TRAITS_HPP__
+
+#include "bindertypes.hpp"
+#include "utils.hpp"
+#include "sstring.h"
+#include "shash.h"
+
+namespace BINDER_SPACE
+{
+ class FailureCacheEntry
+ {
+ public:
+ inline FailureCacheEntry()
+ {
+ m_hrBindingResult = S_OK;
+ }
+ inline ~FailureCacheEntry()
+ {
+ // Nothing to do here
+ }
+
+ // Getters/Setters
+ inline SString &GetAssemblyNameOrPath()
+ {
+ return m_assemblyNameOrPath;
+ }
+ inline HRESULT GetBindingResult()
+ {
+ return m_hrBindingResult;
+ }
+ inline void SetBindingResult(HRESULT hrBindingResult)
+ {
+ m_hrBindingResult = hrBindingResult;
+ }
+
+ protected:
+ SString m_assemblyNameOrPath;
+ HRESULT m_hrBindingResult;
+ };
+
+ class FailureCacheHashTraits : public DefaultSHashTraits<FailureCacheEntry *>
+ {
+ public:
+ typedef SString& key_t;
+
+ // GetKey, Equals, and Hash can throw due to SString
+ static const bool s_NoThrow = false;
+
+ static key_t GetKey(element_t pFailureCacheEntry)
+ {
+ return pFailureCacheEntry->GetAssemblyNameOrPath();
+ }
+ static BOOL Equals(key_t pAssemblyNameOrPath1, key_t pAssemblyNameOrPath2)
+ {
+ return EqualsCaseInsensitive(pAssemblyNameOrPath1, pAssemblyNameOrPath2);
+ }
+ static count_t Hash(key_t pAssemblyNameOrPath)
+ {
+ return HashCaseInsensitive(pAssemblyNameOrPath);
+ }
+ static element_t Null()
+ {
+ return NULL;
+ }
+ static bool IsNull(const element_t &propertyEntry)
+ {
+ return (propertyEntry == NULL);
+ }
+
+ };
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/fusionassemblyname.hpp b/src/coreclr/binder/inc/fusionassemblyname.hpp
new file mode 100644
index 00000000000..d5676c7c1c6
--- /dev/null
+++ b/src/coreclr/binder/inc/fusionassemblyname.hpp
@@ -0,0 +1,111 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// FusionAssemblyName.hpp
+//
+// Defines the CAssemblyName class
+//
+// ============================================================
+
+#ifndef __FUSION_ASSEMBLY_NAME_HPP__
+#define __FUSION_ASSEMBLY_NAME_HPP__
+
+#include "fusionhelpers.hpp"
+
+struct FusionProperty
+{
+ union {
+ LPVOID pv;
+ WCHAR* asStr; // For debugging.
+ };
+ DWORD cb;
+};
+
+class CPropertyArray
+{
+ friend class CAssemblyName;
+private:
+ DWORD _dwSig;
+ FusionProperty _rProp[ASM_NAME_MAX_PARAMS];
+
+public:
+ CPropertyArray();
+ ~CPropertyArray();
+
+ inline HRESULT Set(DWORD PropertyId, LPCVOID pvProperty, DWORD cbProperty);
+ inline HRESULT Get(DWORD PropertyId, LPVOID pvProperty, LPDWORD pcbProperty);
+ inline FusionProperty operator [] (DWORD dwPropId);
+};
+
+class CAssemblyName final : public IAssemblyName
+{
+private:
+ DWORD _dwSig;
+ Volatile<LONG> _cRef;
+ CPropertyArray _rProp;
+ BOOL _fPublicKeyToken;
+ BOOL _fCustom;
+
+public:
+ // IUnknown methods
+ STDMETHODIMP QueryInterface(REFIID riid,void ** ppv);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ // IAssemblyName methods
+ STDMETHOD(SetProperty)(
+ /* in */ DWORD PropertyId,
+ /* in */ LPCVOID pvProperty,
+ /* in */ DWORD cbProperty);
+
+ STDMETHOD(GetProperty)(
+ /* in */ DWORD PropertyId,
+ /* out */ LPVOID pvProperty,
+ /* in out */ LPDWORD pcbProperty);
+
+ HRESULT SetPropertyInternal(/* in */ DWORD PropertyId,
+ /* in */ LPCVOID pvProperty,
+ /* in */ DWORD cbProperty);
+
+ CAssemblyName();
+
+ HRESULT Parse(LPCWSTR szDisplayName);
+};
+
+STDAPI
+CreateAssemblyNameObject(
+ LPASSEMBLYNAME *ppAssemblyName,
+ LPCOLESTR szAssemblyName);
+
+namespace fusion
+{
+ namespace util
+ {
+ // Fills the provided buffer with the contents of the property. pcbBuf is
+ // set to be either the required buffer space when insufficient buffer is
+ // provided, or the number of bytes written.
+ //
+ // Returns S_FALSE if the property has not been set, regardless of the values of pBuf and pcbBuf.
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, PVOID pBuf, DWORD *pcbBuf);
+
+ // Fills the provided buffer with the contents of the property. If no buffer is provided
+ // (*ppBuf == nullptr), then a buffer is allocated for the caller and ppBuf is set to point
+ // at the allocated buffer on return. pcbBuf is set to be either the required buffer space
+ // when insufficient buffer is provided, or the number of bytes written.
+ //
+ // Returns S_FALSE if the property has not been set, regardless of the values of pBuf and pcbBuf.
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, PBYTE * ppBuf, DWORD *pcbBuf);
+
+ // Fills the provided SString with the contents of the property.
+ //
+ // Returns S_FALSE if the property has not been set.
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, SString & ssVal);
+
+ inline HRESULT GetSimpleName(IAssemblyName * pName, SString & ssName)
+ { return GetProperty(pName, ASM_NAME_NAME, ssName); }
+ } // namespace fusion.util
+} // namespace fusion
+
+
+#endif
diff --git a/src/coreclr/binder/inc/fusionhelpers.hpp b/src/coreclr/binder/inc/fusionhelpers.hpp
new file mode 100644
index 00000000000..e3e31af8406
--- /dev/null
+++ b/src/coreclr/binder/inc/fusionhelpers.hpp
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// FusionHelpers.hpp
+//
+// Defines various legacy fusion types
+//
+// ============================================================
+
+#ifndef __FUSION_HELPERS_HPP__
+#define __FUSION_HELPERS_HPP__
+
+#include "clrtypes.h"
+#include "sstring.h"
+
+#include "clrhost.h"
+#include "shlwapi.h"
+#include "winwrap.h"
+#include "ex.h"
+#include "fusion.h"
+
+
+#include "peinformation.h"
+
+#define FUSION_NEW_SINGLETON(_type) new (nothrow) _type
+#define FUSION_NEW_ARRAY(_type, _n) new (nothrow) _type[_n]
+#define FUSION_DELETE_ARRAY(_ptr) if((_ptr)) delete [] (_ptr)
+#define FUSION_DELETE_SINGLETON(_ptr) if((_ptr)) delete (_ptr)
+
+#define SAFEDELETE(p) if ((p) != NULL) { FUSION_DELETE_SINGLETON((p)); (p) = NULL; };
+#define SAFEDELETEARRAY(p) if ((p) != NULL) { FUSION_DELETE_ARRAY((p)); (p) = NULL; };
+#define SAFERELEASE(p) if ((p) != NULL) { (p)->Release(); (p) = NULL; };
+
+#ifndef NEW
+#define NEW(_type) FUSION_NEW_SINGLETON(_type)
+#endif // !NEW
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
+#endif // !ARRAYSIZE
+
+#define MAX_VERSION_DISPLAY_SIZE sizeof("65535.65535.65535.65535")
+
+#define ASM_DISPLAYF_DEFAULT (ASM_DISPLAYF_VERSION \
+ |ASM_DISPLAYF_CULTURE \
+ |ASM_DISPLAYF_PUBLIC_KEY_TOKEN \
+ |ASM_DISPLAYF_RETARGET)
+
+#define SIGNATURE_BLOB_LENGTH 0x80
+#define SIGNATURE_BLOB_LENGTH_HASH 0x14
+#define MVID_LENGTH sizeof(GUID)
+
+#define PUBLIC_KEY_TOKEN_LEN 8
+
+#define MAX_URL_LENGTH 2084 // same as INTERNET_MAX_URL_LENGTH
+
+// bit mask macro helpers
+#define MAX_ID_FROM_MASK(size) ((size) << 3)
+#define MASK_SIZE_FROM_ID(id) ((id) >> 3)
+#define IS_IN_RANGE(id, size) ((id) <= ((size) << 3))
+#define IS_BIT_SET(id, mask) (mask[((id)-1)>>3] & (0x1 << (((id)-1)&0x7)))
+#define SET_BIT(id, mask) (mask[((id)-1)>>3] |= (0x1<< (((id)-1)&0x7)))
+#define UNSET_BIT(id, mask) (mask[((id)-1)>>3] &= (0xFF - (0x1<<(((id)-1)&0x7))))
+
+inline
+int FusionCompareStringI(LPCWSTR pwz1, LPCWSTR pwz2)
+{
+ return SString::_wcsicmp(pwz1, pwz2);
+}
+
+#endif
diff --git a/src/coreclr/binder/inc/loadcontext.hpp b/src/coreclr/binder/inc/loadcontext.hpp
new file mode 100644
index 00000000000..e840a405df0
--- /dev/null
+++ b/src/coreclr/binder/inc/loadcontext.hpp
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// LoadContext.hpp
+//
+
+
+//
+// Defines the LoadContext template class
+//
+// ============================================================
+
+#ifndef __BINDER__LOAD_CONTEXT_HPP__
+#define __BINDER__LOAD_CONTEXT_HPP__
+
+#include "assemblyhashtraits.hpp"
+#include "contextentry.hpp"
+#include "bindresult.hpp"
+
+namespace BINDER_SPACE
+{
+ template <DWORD dwIncludeFlags>
+ class LoadContext : protected SHash<AssemblyHashTraits<ContextEntry *, dwIncludeFlags> >
+ {
+ private:
+ typedef SHash<AssemblyHashTraits<ContextEntry *, dwIncludeFlags> > Hash;
+ public:
+ LoadContext();
+ ~LoadContext();
+
+ ULONG AddRef();
+ ULONG Release();
+ ContextEntry *Lookup(/* in */ AssemblyName *pAssemblyName);
+ HRESULT Register(BindResult *pBindResult);
+
+ protected:
+ LONG m_cRef;
+ };
+
+#include "loadcontext.inl"
+
+ class ExecutionContext : public LoadContext<AssemblyName::INCLUDE_DEFAULT> {};
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/loadcontext.inl b/src/coreclr/binder/inc/loadcontext.inl
new file mode 100644
index 00000000000..fb463523ebb
--- /dev/null
+++ b/src/coreclr/binder/inc/loadcontext.inl
@@ -0,0 +1,87 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// LoadContext.inl
+//
+
+
+//
+// Implements the inlined methods of LoadContext template class
+//
+// ============================================================
+
+#ifndef __BINDER__LOAD_CONTEXT_INL__
+#define __BINDER__LOAD_CONTEXT_INL__
+
+template <DWORD dwIncludeFlags>
+LoadContext<dwIncludeFlags>::LoadContext() :
+ SHash<AssemblyHashTraits<ContextEntry *, dwIncludeFlags> >::SHash()
+{
+ m_cRef = 1;
+}
+
+template <DWORD dwIncludeFlags>
+LoadContext<dwIncludeFlags>::~LoadContext()
+{
+ // Delete context entries and contents array
+ for (typename Hash::Iterator i = Hash::Begin(), end = Hash::End(); i != end; i++)
+ {
+ const ContextEntry *pContextEntry = *i;
+ delete pContextEntry;
+ }
+ this->RemoveAll();
+}
+
+template <DWORD dwIncludeFlags>
+ULONG LoadContext<dwIncludeFlags>::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+template <DWORD dwIncludeFlags>
+ULONG LoadContext<dwIncludeFlags>::Release()
+{
+ ULONG ulRef = InterlockedDecrement(&m_cRef);
+
+ if (ulRef == 0)
+ {
+ delete this;
+ }
+
+ return ulRef;
+}
+
+template <DWORD dwIncludeFlags>
+ContextEntry *LoadContext<dwIncludeFlags>::Lookup(AssemblyName *pAssemblyName)
+{
+ ContextEntry *pContextEntry =
+ SHash<AssemblyHashTraits<ContextEntry *, dwIncludeFlags> >::Lookup(pAssemblyName);
+
+ return pContextEntry;
+}
+
+template <DWORD dwIncludeFlags>
+HRESULT LoadContext<dwIncludeFlags>::Register(BindResult *pBindResult)
+{
+ HRESULT hr = S_OK;
+ ContextEntry *pContextEntry = NULL;
+
+ SAFE_NEW(pContextEntry, ContextEntry);
+
+ pContextEntry->SetIsInGAC(pBindResult->GetIsInGAC());
+ pContextEntry->SetAssemblyName(pBindResult->GetAssemblyName(), TRUE /* fAddRef */);
+ pContextEntry->SetAssembly(pBindResult->GetAssembly());
+
+ if (pBindResult->GetIsFirstRequest())
+ {
+ pContextEntry->SetIsFirstRequest(TRUE);
+ }
+
+ SHash<AssemblyHashTraits<ContextEntry *, dwIncludeFlags> >::Add(pContextEntry);
+
+ Exit:
+ return hr;
+}
+
+#endif
diff --git a/src/coreclr/binder/inc/stringlexer.hpp b/src/coreclr/binder/inc/stringlexer.hpp
new file mode 100644
index 00000000000..41af7e7baa1
--- /dev/null
+++ b/src/coreclr/binder/inc/stringlexer.hpp
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// StringLexer.hpp
+//
+
+
+//
+// Defines the StringLexer class
+//
+// ============================================================
+
+#ifndef __BINDER__STRING_LEXER_HPP__
+#define __BINDER__STRING_LEXER_HPP__
+
+#include "bindertypes.hpp"
+
+#define GO_IF_NOT_EXPECTED(expr, kRequiredLexemeType) \
+ if ((expr) != kRequiredLexemeType) \
+ { \
+ fIsValid = FALSE; \
+ goto Exit; \
+ }
+
+#define GO_IF_END_OR_NOT_EXPECTED(expr, kRequiredLexemeType) \
+ { \
+ LEXEME_TYPE kGotLexemeType = (expr); \
+ if (kGotLexemeType == LEXEME_TYPE_END_OF_STREAM) \
+ { \
+ goto Exit; \
+ } \
+ else \
+ { \
+ GO_IF_NOT_EXPECTED(kGotLexemeType, kRequiredLexemeType); \
+ } \
+ }
+
+namespace BINDER_SPACE
+{
+ class StringLexer
+ {
+ public:
+ typedef enum
+ {
+ LEXEME_TYPE_INVALID,
+ LEXEME_TYPE_EQUALS,
+ LEXEME_TYPE_COMMA,
+ LEXEME_TYPE_COLON,
+ LEXEME_TYPE_SEMICOLON,
+ LEXEME_TYPE_STRING,
+ LEXEME_TYPE_END_OF_STREAM
+ } LEXEME_TYPE;
+
+ inline StringLexer();
+ inline ~StringLexer();
+
+ inline void Init(SString &inputString, BOOL fSupportEscaping);
+
+ static inline BOOL IsWhitespace(WCHAR wcChar);
+ static inline BOOL IsEOS(WCHAR wcChar);
+ static inline BOOL IsQuoteCharacter(WCHAR wcChar);
+
+ virtual BOOL IsSeparatorChar(WCHAR wcChar) = NULL;
+ virtual LEXEME_TYPE GetLexemeType(WCHAR wcChar) = NULL;
+
+ protected:
+ static const WCHAR INVALID_CHARACTER = -1;
+
+ LEXEME_TYPE GetNextLexeme(SString &currentString, BOOL fPermitUnescapedQuotes = FALSE);
+
+ inline WCHAR PopCharacter(BOOL *pfIsEscaped);
+ inline void PushCharacter(WCHAR wcCurrentChar,
+ BOOL fIsEscaped);
+
+ inline WCHAR GetRawCharacter();
+ inline void PushRawCharacter();
+ inline WCHAR DecodeUTF16Character();
+ inline WCHAR GetNextCharacter(BOOL *pfIsEscaped);
+
+ inline WCHAR ParseUnicode();
+ LEXEME_TYPE ParseString(SString &currentString,
+ BOOL fPermitUnescapeQuotes);
+
+ void TrimTrailingWhiteSpaces(SString &currentString);
+
+ SString::Iterator m_cursor;
+ SString::Iterator m_end;
+
+ WCHAR m_wcCurrentChar;
+ BOOL m_fCurrentCharIsEscaped;
+ BOOL m_fSupportEscaping;
+ BOOL m_fReadRawCharacter;
+ };
+
+#include "stringlexer.inl"
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/stringlexer.inl b/src/coreclr/binder/inc/stringlexer.inl
new file mode 100644
index 00000000000..bfe4bddeaa4
--- /dev/null
+++ b/src/coreclr/binder/inc/stringlexer.inl
@@ -0,0 +1,242 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// StringLexer.inl
+//
+
+
+//
+// Implements the inlined methods of StringLexer class
+//
+// ============================================================
+
+#ifndef __BINDER__STRING_LEXER_INL__
+#define __BINDER__STRING_LEXER_INL__
+
+StringLexer::StringLexer()
+{
+ m_wcCurrentChar = INVALID_CHARACTER;
+ m_fCurrentCharIsEscaped = FALSE;
+}
+
+StringLexer::~StringLexer()
+{
+ // Nothing to do here
+}
+
+void StringLexer::Init(SString &inputString, BOOL fSupportEscaping)
+{
+ m_cursor = inputString.Begin();
+ m_end = inputString.End();
+ m_fSupportEscaping = fSupportEscaping;
+ m_fReadRawCharacter = FALSE;
+}
+
+BOOL StringLexer::IsWhitespace(WCHAR wcChar)
+{
+ return ((wcChar == L'\n') || (wcChar == L'\r') || (wcChar == L' ') || (wcChar == L'\t'));
+}
+
+BOOL StringLexer::IsEOS(WCHAR wcChar)
+{
+ return (wcChar == 0);
+}
+
+BOOL StringLexer::IsQuoteCharacter(WCHAR wcChar)
+{
+ return ((wcChar == L'\'') || (wcChar == L'"'));
+}
+
+WCHAR StringLexer::PopCharacter(BOOL *pfIsEscaped)
+{
+ WCHAR wcCurrentChar = m_wcCurrentChar;
+ if (wcCurrentChar != INVALID_CHARACTER)
+ {
+ m_wcCurrentChar = INVALID_CHARACTER;
+ *pfIsEscaped = m_fCurrentCharIsEscaped;
+ }
+ else
+ {
+ wcCurrentChar = GetNextCharacter(pfIsEscaped);
+ }
+
+ return wcCurrentChar;
+}
+
+void StringLexer::PushCharacter(WCHAR wcCurrentChar,
+ BOOL fIsEscaped)
+{
+ _ASSERTE(m_wcCurrentChar == INVALID_CHARACTER);
+
+ m_wcCurrentChar = wcCurrentChar;
+ m_fCurrentCharIsEscaped = fIsEscaped;
+}
+
+WCHAR StringLexer::GetRawCharacter()
+{
+ WCHAR wcCurrentChar = 0;
+
+ if (m_cursor <= m_end)
+ {
+ wcCurrentChar = m_cursor[0];
+ m_fReadRawCharacter = TRUE;
+ m_cursor++;
+ }
+ else
+ {
+ m_fReadRawCharacter = FALSE;
+ }
+
+ return wcCurrentChar;
+}
+
+void StringLexer::PushRawCharacter()
+{
+ if (m_fReadRawCharacter)
+ {
+ m_cursor--;
+ m_fReadRawCharacter = FALSE;
+ }
+}
+
+WCHAR StringLexer::DecodeUTF16Character()
+{
+ // See http://www.ietf.org/rfc/rfc2781.txt for details on UTF-16 encoding.
+
+ WCHAR wcCurrentChar = 0;
+ SCOUNT_T nCharacters = m_end - m_cursor + 1;
+ WCHAR wcChar1 = GetRawCharacter();
+
+ if (wcChar1 < 0xd800)
+ {
+ wcCurrentChar = wcChar1;
+ }
+ else
+ {
+ // StringLexer is not designed to handle UTF-16 characters beyond the Basic Multilingual Plane,
+ // since it stores all characters in 16-bit WCHARs.
+ // However, since the vast majority of the time, we (Microsoft) produce the manifests,
+ // this is likely a non-scenario, as the other Unicode planes would never be used in practice.
+
+ if (wcChar1 <= 0xdbff) // 0xd800 - 0xdbff indicates the first WCHAR of a surrogate pair
+ {
+ if (nCharacters >= 2)
+ {
+ GetRawCharacter(); // Skip the second WCHAR of the surrogate pair
+ }
+ }
+ // Otherwise, the character is either in the 0xdc00 - 0xdfff range, indicating the second WCHAR of a surrogate pair,
+ // or in the 0xE000 - 0xFFFF range, which has within it ranges of invalid characters, and which we conservatively treat
+ // as invalid.
+
+ wcCurrentChar = INVALID_CHARACTER;
+ }
+
+ return wcCurrentChar;
+}
+
+
+WCHAR StringLexer::GetNextCharacter(BOOL *pfIsEscaped)
+{
+ *pfIsEscaped = FALSE;
+
+ WCHAR wcCurrentChar = GetRawCharacter(); // DecodeUTF16Character()
+ if (wcCurrentChar == L'\\')
+ {
+ WCHAR wcTempChar = GetRawCharacter(); // DecodeUTF16Character()
+
+ if (m_fSupportEscaping)
+ {
+ // Handle standard escapes
+ switch (wcTempChar)
+ {
+ case L'"':
+ case L'\'':
+ case L',':
+ case L'\\':
+ case L'/':
+ case L'=':
+ break;
+ case L't':
+ wcTempChar = 9;
+ break;
+ case L'n':
+ wcTempChar = 10;
+ break;
+ case L'r':
+ wcTempChar = 13;
+ break;
+ case L'u':
+ wcTempChar = ParseUnicode();
+ break;
+ default:
+ return INVALID_CHARACTER;
+ }
+
+ *pfIsEscaped = TRUE;
+ wcCurrentChar = wcTempChar;
+ }
+ else
+ {
+ // Do not handle escapes except for quotes
+ switch (wcTempChar)
+ {
+ case L'"':
+ case L'\'':
+ *pfIsEscaped = TRUE;
+ wcCurrentChar = wcTempChar;
+ break;
+ default:
+ PushRawCharacter();
+ break;
+ }
+ }
+ }
+
+ return wcCurrentChar;
+}
+
+WCHAR StringLexer::ParseUnicode()
+{
+ int nCharacters = 0;
+ WCHAR wcUnicodeChar = 0;
+
+ for(;;)
+ {
+ WCHAR wcCurrentChar = DecodeUTF16Character();
+ nCharacters++;
+
+ if (wcCurrentChar == L';')
+ {
+ break;
+ }
+ else if ((wcCurrentChar == INVALID_CHARACTER) || (nCharacters >= 9))
+ {
+ return INVALID_CHARACTER;
+ }
+
+ wcUnicodeChar <<= 4;
+
+ if ((wcCurrentChar >= L'0') && (wcCurrentChar <= L'9'))
+ {
+ wcUnicodeChar += (wcCurrentChar - L'0');
+ }
+ else if ((wcCurrentChar >= L'a') && (wcCurrentChar <= L'f'))
+ {
+ wcUnicodeChar += (wcCurrentChar - L'a') + 10;
+ }
+ else if ((wcCurrentChar >= L'A') && (wcCurrentChar <= L'F'))
+ {
+ wcUnicodeChar += (wcCurrentChar - L'A') + 10;
+ }
+ else
+ {
+ return INVALID_CHARACTER;
+ }
+ }
+
+ return wcUnicodeChar;
+}
+
+#endif
diff --git a/src/coreclr/binder/inc/textualidentityparser.hpp b/src/coreclr/binder/inc/textualidentityparser.hpp
new file mode 100644
index 00000000000..a5187d254a6
--- /dev/null
+++ b/src/coreclr/binder/inc/textualidentityparser.hpp
@@ -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.
+// ============================================================
+//
+// TextualIdentityParser.hpp
+//
+
+
+//
+// Defines the TextualIdentityParser class
+//
+// ============================================================
+
+#ifndef __BINDER__TEXTUAL_IDENTITY_PARSER_HPP__
+#define __BINDER__TEXTUAL_IDENTITY_PARSER_HPP__
+
+#include "bindertypes.hpp"
+#include "stringlexer.hpp"
+
+namespace BINDER_SPACE
+{
+ class AssemblyVersion;
+ class AssemblyIdentity;
+
+ class TextualIdentityParser : public StringLexer
+ {
+ public:
+ TextualIdentityParser(AssemblyIdentity *pAssemblyIdentity);
+ ~TextualIdentityParser();
+
+ virtual BOOL IsSeparatorChar(WCHAR wcChar);
+ virtual StringLexer::LEXEME_TYPE GetLexemeType(WCHAR wcChar);
+
+ static HRESULT Parse(/* in */ SString &textualIdentity,
+ /* out */ AssemblyIdentity *pAssemblyIdentity,
+ /* in */ BOOL fPermitUnescapedQuotes = FALSE);
+ static HRESULT ToString(/* in */ AssemblyIdentity *pAssemblyIdentity,
+ /* in */ DWORD dwIdentityFlags,
+ /* out */ SString &textualIdentity);
+
+ static BOOL ParseVersion(/* in */ SString &versionString,
+ /* out */ AssemblyVersion *pAssemblyVersion);
+
+ static BOOL HexToBlob(/* in */ SString &publicKeyOrToken,
+ /* in */ BOOL fValidateHex,
+ /* in */ BOOL fIsToken,
+ /* out */ SBuffer &publicKeyOrTokenBLOB);
+ static void BlobToHex(/* in */ SBuffer &publicKeyOrTokenBLOB,
+ /* out */ SString &publicKeyOrToken);
+
+ BOOL ParseString(/* in */ SString &textualString,
+ /* out */ SString &contentString);
+
+ protected:
+ BOOL Parse(/* in */ SString &textualIdentity,
+ /* in */ BOOL fPermitUnescapedQuotes = FALSE);
+
+ BOOL PopulateAssemblyIdentity(/* in */ SString &attributeString,
+ /* in */ SString &valueString);
+
+ static void EscapeString(/* in */ SString &input,
+ /* out*/ SString &result);
+
+ AssemblyIdentity *m_pAssemblyIdentity;
+ DWORD m_dwAttributesSeen;
+ };
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/utils.hpp b/src/coreclr/binder/inc/utils.hpp
new file mode 100644
index 00000000000..1c8ea114f5e
--- /dev/null
+++ b/src/coreclr/binder/inc/utils.hpp
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// Utils.hpp
+//
+
+
+//
+// Declares a bunch of binder auxilary functions
+//
+// ============================================================
+
+#ifndef __BINDER_UTILS_HPP__
+#define __BINDER_UTILS_HPP__
+
+#include "bindertypes.hpp"
+
+namespace BINDER_SPACE
+{
+ inline BOOL EqualsCaseInsensitive(SString &a, SString &b)
+ {
+ return a.EqualsCaseInsensitive(b);
+ }
+
+ inline ULONG HashCaseInsensitive(SString &string)
+ {
+ return string.HashCaseInsensitive();
+ }
+
+ void MutateUrlToPath(SString &urlOrPath);
+
+ // It is safe to use either A or B as CombinedPath.
+ void CombinePath(SString &pathA,
+ SString &pathB,
+ SString &combinedPath);
+
+ HRESULT GetTokenFromPublicKey(SBuffer &publicKeyBLOB,
+ SBuffer &publicKeyTokenBLOB);
+
+ BOOL IsFileNotFound(HRESULT hr);
+
+ HRESULT GetNextPath(SString& paths, SString::Iterator& startPos, SString& outPath);
+ HRESULT GetNextTPAPath(SString& paths, SString::Iterator& startPos, bool dllOnly, SString& outPath, SString& simpleName, bool& isNativeImage);
+};
+
+#endif
diff --git a/src/coreclr/binder/inc/variables.hpp b/src/coreclr/binder/inc/variables.hpp
new file mode 100644
index 00000000000..d060a691bbe
--- /dev/null
+++ b/src/coreclr/binder/inc/variables.hpp
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// Variables.hpp
+//
+
+
+//
+// Defines the Variables class
+//
+// ============================================================
+
+#ifndef __BINDER__VARIABLES_HPP__
+#define __BINDER__VARIABLES_HPP__
+
+#include "bindertypes.hpp"
+
+namespace BINDER_SPACE
+{
+ class Variables
+ {
+ public:
+ Variables();
+ ~Variables();
+
+ HRESULT Init();
+
+ // AssemblyBinder string constants
+ SString httpURLPrefix;
+
+ // AssemblyName string constants
+ SString cultureNeutral;
+ SString corelib;
+ };
+
+ extern Variables *g_BinderVariables;
+};
+
+#endif
diff --git a/src/coreclr/binder/stringlexer.cpp b/src/coreclr/binder/stringlexer.cpp
new file mode 100644
index 00000000000..b6b722fa77a
--- /dev/null
+++ b/src/coreclr/binder/stringlexer.cpp
@@ -0,0 +1,150 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// StringLexer.cpp
+//
+
+
+//
+// Implements the StringLexer class
+//
+// ============================================================
+
+#include "stringlexer.hpp"
+#include "utils.hpp"
+
+#include "ex.h"
+
+namespace BINDER_SPACE
+{
+ StringLexer::LEXEME_TYPE
+ StringLexer::GetNextLexeme(SString &currentString, BOOL fPermitUnescapedQuotes)
+ {
+ BOOL fIsEscaped = FALSE;
+ WCHAR wcCurrentChar = INVALID_CHARACTER;
+
+ // Remove any white spaces
+ do
+ {
+ wcCurrentChar = PopCharacter(&fIsEscaped);
+ }
+ while (IsWhitespace(wcCurrentChar));
+
+ // Determine lexeme type
+ if (!fIsEscaped)
+ {
+ LEXEME_TYPE kLexemeType = GetLexemeType(wcCurrentChar);
+ if (kLexemeType != LEXEME_TYPE_STRING)
+ {
+ return kLexemeType;
+ }
+ }
+
+ // First character of string lexeme; push it back
+ PushCharacter(wcCurrentChar, fIsEscaped);
+ return ParseString(currentString, fPermitUnescapedQuotes);
+ }
+
+ StringLexer::LEXEME_TYPE
+ StringLexer::ParseString(SString &currentString, BOOL fPermitUnescapedQuotes)
+ {
+ BOOL fIsFirstCharacter = TRUE;
+ WCHAR wcCurrentChar = INVALID_CHARACTER;
+ WCHAR wcOpeningQuote = INVALID_CHARACTER;
+
+ currentString.Clear();
+
+ // Read until we find another lexeme that's not a string character
+ for (;;)
+ {
+ BOOL fIsEscaped = FALSE;
+ wcCurrentChar = PopCharacter(&fIsEscaped);
+
+ if (wcCurrentChar == INVALID_CHARACTER)
+ {
+ // Found invalid character encoding
+ return LEXEME_TYPE_INVALID;
+ }
+
+ if (IsEOS(wcCurrentChar))
+ {
+ if (IsQuoteCharacter(wcOpeningQuote))
+ {
+ // EOS and unclosed quotes is an error
+ return LEXEME_TYPE_INVALID;
+ }
+ else
+ {
+ // Reached end of input and therefore of string
+ break;
+ }
+ }
+
+ if (fIsFirstCharacter)
+ {
+ fIsFirstCharacter = FALSE;
+
+ // If first character is quote, then record its quoteness
+ if (IsQuoteCharacter(wcCurrentChar))
+ {
+ wcOpeningQuote = wcCurrentChar;
+ continue;
+ }
+ }
+
+ if (wcCurrentChar == wcOpeningQuote)
+ {
+ // We've found the closing quote for a quoted string
+ break;
+ }
+
+ if (!fPermitUnescapedQuotes && !fIsEscaped && IsQuoteCharacter(wcCurrentChar) && !IsQuoteCharacter(wcOpeningQuote))
+ {
+ // Unescaped quotes in the middle of the string are an error
+ return LEXEME_TYPE_INVALID;
+ }
+
+ if (IsSeparatorChar(wcCurrentChar) && !IsQuoteCharacter(wcOpeningQuote) && !fIsEscaped)
+ {
+ // Unescaped separator char terminates the string
+ PushCharacter(wcCurrentChar, fIsEscaped);
+ break;
+ }
+
+ // Add character to current string
+ currentString.Append(wcCurrentChar);
+ }
+
+ if (!IsQuoteCharacter(wcOpeningQuote))
+ {
+ // Remove trailing white spaces from unquoted string
+ TrimTrailingWhiteSpaces(currentString);
+ }
+
+ return LEXEME_TYPE_STRING;
+ }
+
+ void StringLexer::TrimTrailingWhiteSpaces(SString &currentString)
+ {
+ SString::Iterator begin = currentString.Begin();
+ SString::Iterator cursor = currentString.End() - 1;
+ BOOL fFoundWhiteSpace = FALSE;
+
+ for (;;)
+ {
+ if ((cursor >= begin) && IsWhitespace(cursor[0]))
+ {
+ fFoundWhiteSpace = TRUE;
+ cursor--;
+ continue;
+ }
+ break;
+ }
+
+ if (fFoundWhiteSpace)
+ {
+ currentString.Truncate(cursor + 1);
+ }
+ }
+};
diff --git a/src/coreclr/binder/textualidentityparser.cpp b/src/coreclr/binder/textualidentityparser.cpp
new file mode 100644
index 00000000000..939ffe9f468
--- /dev/null
+++ b/src/coreclr/binder/textualidentityparser.cpp
@@ -0,0 +1,766 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// TextualIdentityParser.cpp
+//
+
+
+//
+// Implements the TextualIdentityParser class
+//
+// ============================================================
+
+#include "textualidentityparser.hpp"
+#include "assemblyidentity.hpp"
+#include "utils.hpp"
+
+#include "ex.h"
+
+#define GO_IF_SEEN(kAssemblyIdentityFlag) \
+ if ((m_dwAttributesSeen & kAssemblyIdentityFlag) != 0) \
+ { \
+ fIsValid = FALSE; \
+ goto Exit; \
+ } \
+ else \
+ { \
+ m_dwAttributesSeen |= kAssemblyIdentityFlag; \
+ }
+
+#define GO_IF_WILDCARD(valueString) \
+ { \
+ SmallStackSString wildCard(W("*")); \
+ if (valueString.Equals(wildCard)) \
+ { \
+ goto Exit; \
+ } \
+ }
+
+#define GO_IF_VALIDATE_FAILED(validateProc, kIdentityFlag) \
+ if (!validateProc(valueString)) \
+ { \
+ fIsValid = FALSE; \
+ goto Exit; \
+ } \
+ else \
+ { \
+ m_pAssemblyIdentity->SetHave(kIdentityFlag); \
+ }
+
+#define FROMHEX(a) ((a)>=W('a') ? a - W('a') + 10 : a - W('0'))
+#define TOHEX(a) ((a)>=10 ? W('a')+(a)-10 : W('0')+(a))
+#define TOLOWER(a) (((a) >= W('A') && (a) <= W('Z')) ? (W('a') + (a - W('A'))) : (a))
+
+namespace BINDER_SPACE
+{
+ namespace
+ {
+ const int iPublicKeyTokenLength = 8;
+
+ const int iVersionMax = 65535;
+ const int iVersionParts = 4;
+
+ inline void UnicodeHexToBin(LPCWSTR pSrc, UINT cSrc, LPBYTE pDest)
+ {
+ BYTE v;
+ LPBYTE pd = pDest;
+ LPCWSTR ps = pSrc;
+
+ if (cSrc == 0)
+ return;
+
+ for (UINT i = 0; i < cSrc-1; i+=2)
+ {
+ v = (BYTE)FROMHEX(TOLOWER(ps[i])) << 4;
+ v |= FROMHEX(TOLOWER(ps[i+1]));
+ *(pd++) = v;
+ }
+ }
+
+ inline void BinToUnicodeHex(const BYTE *pSrc, UINT cSrc, __out_ecount(2*cSrc) LPWSTR pDst)
+ {
+ UINT x;
+ UINT y;
+
+ for (x = 0, y = 0 ; x < cSrc; ++x)
+ {
+ UINT v;
+
+ v = pSrc[x]>>4;
+ pDst[y++] = (WCHAR)TOHEX(v);
+ v = pSrc[x] & 0x0f;
+ pDst[y++] = (WCHAR)TOHEX(v);
+ }
+ }
+
+ inline BOOL EqualsCaseInsensitive(SString &a, LPCWSTR wzB)
+ {
+ SString b(SString::Literal, wzB);
+
+ return ::BINDER_SPACE::EqualsCaseInsensitive(a, b);
+ }
+
+ BOOL ValidateHex(SString &publicKeyOrToken)
+ {
+ if ((publicKeyOrToken.GetCount() == 0) || ((publicKeyOrToken.GetCount() % 2) != 0))
+ {
+ return FALSE;
+ }
+
+ SString::Iterator cursor = publicKeyOrToken.Begin();
+ SString::Iterator end = publicKeyOrToken.End() - 1;
+
+ while (cursor <= end)
+ {
+ WCHAR wcCurrentChar = cursor[0];
+
+ if (((wcCurrentChar >= W('0')) && (wcCurrentChar <= W('9'))) ||
+ ((wcCurrentChar >= W('a')) && (wcCurrentChar <= W('f'))) ||
+ ((wcCurrentChar >= W('A')) && (wcCurrentChar <= W('F'))))
+ {
+ cursor++;
+ continue;
+ }
+
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ inline BOOL ValidatePublicKeyToken(SString &publicKeyToken)
+ {
+ return ((publicKeyToken.GetCount() == (iPublicKeyTokenLength * 2)) &&
+ ValidateHex(publicKeyToken));
+ }
+
+ inline BOOL ValidatePublicKey(SString &publicKey)
+ {
+ return ValidateHex(publicKey);
+ }
+
+ const struct {
+ LPCWSTR strValue;
+ PEKIND enumValue;
+ } wszKnownArchitectures[] = { { W("x86"), peI386 },
+ { W("IA64"), peIA64 },
+ { W("AMD64"), peAMD64 },
+ { W("ARM"), peARM },
+ { W("MSIL"), peMSIL } };
+
+ BOOL ValidateAndConvertProcessorArchitecture(SString &processorArchitecture,
+ PEKIND *pkProcessorArchitecture)
+ {
+ for (int i = LENGTH_OF(wszKnownArchitectures); i--;)
+ {
+ if (EqualsCaseInsensitive(processorArchitecture, wszKnownArchitectures[i].strValue))
+ {
+ *pkProcessorArchitecture = wszKnownArchitectures[i].enumValue;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+ LPCWSTR PeKindToString(PEKIND kProcessorArchitecture)
+ {
+ _ASSERTE(kProcessorArchitecture != peNone);
+
+ for (int i = LENGTH_OF(wszKnownArchitectures); i--;)
+ {
+ if (wszKnownArchitectures[i].enumValue == kProcessorArchitecture)
+ {
+ return wszKnownArchitectures[i].strValue;
+ }
+ }
+
+ return NULL;
+ }
+
+ LPCWSTR ContentTypeToString(AssemblyContentType kContentType)
+ {
+ _ASSERTE(kContentType != AssemblyContentType_Default);
+
+ if (kContentType == AssemblyContentType_WindowsRuntime)
+ {
+ return W("WindowsRuntime");
+ }
+
+ return NULL;
+ }
+ }; // namespace (anonymous)
+
+ TextualIdentityParser::TextualIdentityParser(AssemblyIdentity *pAssemblyIdentity)
+ {
+ m_pAssemblyIdentity = pAssemblyIdentity;
+ m_dwAttributesSeen = AssemblyIdentity::IDENTITY_FLAG_EMPTY;
+ }
+
+ TextualIdentityParser::~TextualIdentityParser()
+ {
+ // Nothing to do here
+ }
+
+ BOOL TextualIdentityParser::IsSeparatorChar(WCHAR wcChar)
+ {
+ return ((wcChar == W(',')) || (wcChar == W('=')));
+ }
+
+ StringLexer::LEXEME_TYPE TextualIdentityParser::GetLexemeType(WCHAR wcChar)
+ {
+ switch (wcChar)
+ {
+ case W('='):
+ return LEXEME_TYPE_EQUALS;
+ case W(','):
+ return LEXEME_TYPE_COMMA;
+ case 0:
+ return LEXEME_TYPE_END_OF_STREAM;
+ default:
+ return LEXEME_TYPE_STRING;
+ }
+ }
+
+ /* static */
+ HRESULT TextualIdentityParser::Parse(SString &textualIdentity,
+ AssemblyIdentity *pAssemblyIdentity,
+ BOOL fPermitUnescapedQuotes)
+ {
+ HRESULT hr = S_OK;
+
+ IF_FALSE_GO(pAssemblyIdentity != NULL);
+
+ EX_TRY
+ {
+ TextualIdentityParser identityParser(pAssemblyIdentity);
+
+ if (!identityParser.Parse(textualIdentity, fPermitUnescapedQuotes))
+ {
+ IF_FAIL_GO(FUSION_E_INVALID_NAME);
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ Exit:
+ return hr;
+ }
+
+ /* static */
+ HRESULT TextualIdentityParser::ToString(AssemblyIdentity *pAssemblyIdentity,
+ DWORD dwIdentityFlags,
+ SString &textualIdentity)
+ {
+ HRESULT hr = S_OK;
+
+ IF_FALSE_GO(pAssemblyIdentity != NULL);
+
+ EX_TRY
+ {
+ SmallStackSString tmpString;
+
+ textualIdentity.Clear();
+
+ if (pAssemblyIdentity->m_simpleName.IsEmpty())
+ {
+ goto Exit;
+ }
+
+ EscapeString(pAssemblyIdentity->m_simpleName, tmpString);
+ textualIdentity.Append(tmpString);
+
+ if (AssemblyIdentity::Have(dwIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_VERSION))
+ {
+ tmpString.Clear();
+ tmpString.Printf(W("%d.%d.%d.%d"),
+ (DWORD)(USHORT)pAssemblyIdentity->m_version.GetMajor(),
+ (DWORD)(USHORT)pAssemblyIdentity->m_version.GetMinor(),
+ (DWORD)(USHORT)pAssemblyIdentity->m_version.GetBuild(),
+ (DWORD)(USHORT)pAssemblyIdentity->m_version.GetRevision());
+
+ textualIdentity.Append(W(", Version="));
+ textualIdentity.Append(tmpString);
+ }
+
+ if (AssemblyIdentity::Have(dwIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_CULTURE))
+ {
+ textualIdentity.Append(W(", Culture="));
+ if (pAssemblyIdentity->m_cultureOrLanguage.IsEmpty())
+ {
+ textualIdentity.Append(W("neutral"));
+ }
+ else
+ {
+ EscapeString(pAssemblyIdentity->m_cultureOrLanguage, tmpString);
+ textualIdentity.Append(tmpString);
+ }
+ }
+
+ if (AssemblyIdentity::Have(dwIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY))
+ {
+ textualIdentity.Append(W(", PublicKey="));
+ tmpString.Clear();
+ BlobToHex(pAssemblyIdentity->m_publicKeyOrTokenBLOB, tmpString);
+ textualIdentity.Append(tmpString);
+ }
+ else if (AssemblyIdentity::Have(dwIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN))
+ {
+ textualIdentity.Append(W(", PublicKeyToken="));
+ tmpString.Clear();
+ BlobToHex(pAssemblyIdentity->m_publicKeyOrTokenBLOB, tmpString);
+ textualIdentity.Append(tmpString);
+ }
+ else if (AssemblyIdentity::Have(dwIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL))
+ {
+ textualIdentity.Append(W(", PublicKeyToken=null"));
+ }
+
+ if (AssemblyIdentity::Have(dwIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE))
+ {
+ textualIdentity.Append(W(", processorArchitecture="));
+ textualIdentity.Append(PeKindToString(pAssemblyIdentity->m_kProcessorArchitecture));
+ }
+
+ if (AssemblyIdentity::Have(dwIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE))
+ {
+ textualIdentity.Append(W(", Retargetable=Yes"));
+ }
+
+ if (AssemblyIdentity::Have(dwIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE))
+ {
+ textualIdentity.Append(W(", ContentType="));
+ textualIdentity.Append(ContentTypeToString(pAssemblyIdentity->m_kContentType));
+ }
+
+ if (AssemblyIdentity::Have(dwIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_CUSTOM))
+ {
+ textualIdentity.Append(W(", Custom="));
+ tmpString.Clear();
+ BlobToHex(pAssemblyIdentity->m_customBLOB, tmpString);
+ textualIdentity.Append(tmpString);
+ }
+ else if (AssemblyIdentity::Have(dwIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_CUSTOM_NULL))
+ {
+ textualIdentity.Append(W(", Custom=null"));
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ Exit:
+ return hr;
+ }
+
+ /* static */
+ BOOL TextualIdentityParser::ParseVersion(SString &versionString,
+ AssemblyVersion *pAssemblyVersion)
+ {
+ BOOL fIsValid = FALSE;
+ DWORD dwFoundNumbers = 0;
+ bool foundUnspecifiedComponent = false;
+ const DWORD UnspecifiedNumber = (DWORD)-1;
+ DWORD dwCurrentNumber = UnspecifiedNumber;
+ DWORD dwNumbers[iVersionParts] = {UnspecifiedNumber, UnspecifiedNumber, UnspecifiedNumber, UnspecifiedNumber};
+
+ if (versionString.GetCount() > 0) {
+ SString::Iterator cursor = versionString.Begin();
+ SString::Iterator end = versionString.End();
+
+ while (cursor <= end)
+ {
+ WCHAR wcCurrentChar = cursor[0];
+
+ if (dwFoundNumbers >= static_cast<DWORD>(iVersionParts))
+ {
+ goto Exit;
+ }
+ else if (wcCurrentChar == W('.') || wcCurrentChar == W('\0'))
+ {
+ if (dwCurrentNumber == UnspecifiedNumber)
+ {
+ // Difference from .NET Framework, compat with Version(string) constructor: A missing version component
+ // is considered invalid.
+ //
+ // Examples:
+ // "MyAssembly, Version=."
+ // "MyAssembly, Version=1."
+ // "MyAssembly, Version=.1"
+ // "MyAssembly, Version=1..1"
+ goto Exit;
+ }
+
+ // Compat with .NET Framework: A value of iVersionMax is considered unspecified. Once an unspecified
+ // component is found, validate the remaining components but consider them as unspecified as well.
+ if (dwCurrentNumber == iVersionMax)
+ {
+ foundUnspecifiedComponent = true;
+ dwCurrentNumber = UnspecifiedNumber;
+ }
+ else if (!foundUnspecifiedComponent)
+ {
+ dwNumbers[dwFoundNumbers] = dwCurrentNumber;
+ dwCurrentNumber = UnspecifiedNumber;
+ }
+
+ dwFoundNumbers++;
+ }
+ else if ((wcCurrentChar >= W('0')) && (wcCurrentChar <= W('9')))
+ {
+ if (dwCurrentNumber == UnspecifiedNumber)
+ {
+ dwCurrentNumber = 0;
+ }
+ dwCurrentNumber = (dwCurrentNumber * 10) + (wcCurrentChar - W('0'));
+
+ if (dwCurrentNumber > static_cast<DWORD>(iVersionMax))
+ {
+ goto Exit;
+ }
+ }
+ else
+ {
+ goto Exit;
+ }
+
+ cursor++;
+ }
+
+ // Difference from .NET Framework: If the major or minor version are unspecified, the version is considered invalid.
+ //
+ // Examples:
+ // "MyAssembly, Version="
+ // "MyAssembly, Version=1"
+ // "MyAssembly, Version=65535.1"
+ // "MyAssembly, Version=1.65535"
+ if (dwFoundNumbers < 2 || dwNumbers[0] == UnspecifiedNumber || dwNumbers[1] == UnspecifiedNumber)
+ {
+ goto Exit;
+ }
+
+ pAssemblyVersion->SetFeatureVersion(dwNumbers[0], dwNumbers[1]);
+ pAssemblyVersion->SetServiceVersion(dwNumbers[2], dwNumbers[3]);
+ fIsValid = TRUE;
+ }
+
+ Exit:
+ return fIsValid;
+ }
+
+ /* static */
+ BOOL TextualIdentityParser::HexToBlob(SString &publicKeyOrToken,
+ BOOL fValidateHex,
+ BOOL fIsToken,
+ SBuffer &publicKeyOrTokenBLOB)
+ {
+ // Optional input verification
+ if (fValidateHex)
+ {
+ if ((fIsToken && !ValidatePublicKeyToken(publicKeyOrToken)) ||
+ (!fIsToken && !ValidatePublicKey(publicKeyOrToken)))
+ {
+ return FALSE;
+ }
+ }
+
+ UINT ccPublicKeyOrToken = publicKeyOrToken.GetCount();
+ BYTE *pByteBLOB = publicKeyOrTokenBLOB.OpenRawBuffer(ccPublicKeyOrToken / 2);
+
+ UnicodeHexToBin(publicKeyOrToken.GetUnicode(), ccPublicKeyOrToken, pByteBLOB);
+ publicKeyOrTokenBLOB.CloseRawBuffer();
+
+ return TRUE;
+ }
+
+ /* static */
+ void TextualIdentityParser::BlobToHex(SBuffer &publicKeyOrTokenBLOB,
+ SString &publicKeyOrToken)
+ {
+ UINT cbPublicKeyOrTokenBLOB = publicKeyOrTokenBLOB.GetSize();
+ WCHAR *pwzpublicKeyOrToken =
+ publicKeyOrToken.OpenUnicodeBuffer(cbPublicKeyOrTokenBLOB * 2);
+
+ BinToUnicodeHex(publicKeyOrTokenBLOB, cbPublicKeyOrTokenBLOB, pwzpublicKeyOrToken);
+ publicKeyOrToken.CloseBuffer(cbPublicKeyOrTokenBLOB * 2);
+ }
+
+ BOOL TextualIdentityParser::Parse(SString &textualIdentity, BOOL fPermitUnescapedQuotes)
+ {
+ BOOL fIsValid = TRUE;
+ SString unicodeTextualIdentity;
+
+ // Lexer modifies input string
+ textualIdentity.ConvertToUnicode(unicodeTextualIdentity);
+ Init(unicodeTextualIdentity, TRUE /* fSupportEscaping */);
+
+ SmallStackSString currentString;
+
+ // Identity format is simple name (, attr = value)*
+ GO_IF_NOT_EXPECTED(GetNextLexeme(currentString, fPermitUnescapedQuotes), LEXEME_TYPE_STRING);
+ m_pAssemblyIdentity->m_simpleName.Set(currentString);
+ m_pAssemblyIdentity->m_simpleName.Normalize();
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_SIMPLE_NAME);
+
+ for (;;)
+ {
+ SmallStackSString attributeString;
+ SmallStackSString valueString;
+
+ GO_IF_END_OR_NOT_EXPECTED(GetNextLexeme(currentString), LEXEME_TYPE_COMMA);
+ GO_IF_NOT_EXPECTED(GetNextLexeme(attributeString), LEXEME_TYPE_STRING);
+ GO_IF_NOT_EXPECTED(GetNextLexeme(currentString), LEXEME_TYPE_EQUALS);
+ GO_IF_NOT_EXPECTED(GetNextLexeme(valueString), LEXEME_TYPE_STRING);
+
+ if (!PopulateAssemblyIdentity(attributeString, valueString))
+ {
+ fIsValid = FALSE;
+ break;
+ }
+ }
+
+ Exit:
+ return fIsValid;
+ }
+
+ BOOL TextualIdentityParser::ParseString(SString &textualString,
+ SString &contentString)
+ {
+ BOOL fIsValid = TRUE;
+ SString unicodeTextualString;
+
+ // Lexer modifies input string
+ textualString.ConvertToUnicode(unicodeTextualString);
+ Init(unicodeTextualString, TRUE /* fSupportEscaping */);
+
+ SmallStackSString currentString;
+ GO_IF_NOT_EXPECTED(GetNextLexeme(currentString), LEXEME_TYPE_STRING);
+
+ contentString.Set(currentString);
+ currentString.Normalize();
+
+ Exit:
+ return fIsValid;
+ }
+
+ BOOL TextualIdentityParser::PopulateAssemblyIdentity(SString &attributeString,
+ SString &valueString)
+ {
+ BOOL fIsValid = TRUE;
+
+ if (EqualsCaseInsensitive(attributeString, W("culture")) ||
+ EqualsCaseInsensitive(attributeString, W("language")))
+ {
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_CULTURE);
+ GO_IF_WILDCARD(valueString);
+
+ if (!EqualsCaseInsensitive(valueString, W("neutral")))
+ {
+ // culture/language is preserved as is
+ m_pAssemblyIdentity->m_cultureOrLanguage.Set(valueString);
+ m_pAssemblyIdentity->m_cultureOrLanguage.Normalize();
+ }
+
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_CULTURE);
+ }
+ else if (EqualsCaseInsensitive(attributeString, W("version")))
+ {
+ AssemblyVersion *pAssemblyVersion = &(m_pAssemblyIdentity->m_version);
+
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_VERSION);
+ GO_IF_WILDCARD(valueString);
+
+ if (ParseVersion(valueString, pAssemblyVersion))
+ {
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_VERSION);
+ }
+ else
+ {
+ fIsValid = FALSE;
+ }
+ }
+ else if (EqualsCaseInsensitive(attributeString, W("publickeytoken")))
+ {
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY);
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
+ GO_IF_WILDCARD(valueString);
+
+ if (!EqualsCaseInsensitive(valueString, W("null")) &&
+ !EqualsCaseInsensitive(valueString, W("neutral")))
+ {
+ GO_IF_VALIDATE_FAILED(ValidatePublicKeyToken,
+ AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
+ HexToBlob(valueString,
+ FALSE /* fValidateHex */,
+ TRUE /* fIsToken */,
+ m_pAssemblyIdentity->m_publicKeyOrTokenBLOB);
+ }
+ else
+ {
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL);
+ }
+ }
+ else if (EqualsCaseInsensitive(attributeString, W("publickey")))
+ {
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY);
+
+ if (!EqualsCaseInsensitive(valueString, W("null")) &&
+ !EqualsCaseInsensitive(valueString, W("neutral")))
+ {
+ GO_IF_VALIDATE_FAILED(ValidatePublicKey, AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY);
+ HexToBlob(valueString,
+ FALSE /* fValidateHex */,
+ FALSE /* fIsToken */,
+ m_pAssemblyIdentity->m_publicKeyOrTokenBLOB);
+ }
+ }
+ else if (EqualsCaseInsensitive(attributeString, W("processorarchitecture")))
+ {
+ PEKIND kProcessorArchitecture = peNone;
+
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
+ GO_IF_WILDCARD(valueString);
+
+ if (ValidateAndConvertProcessorArchitecture(valueString, &kProcessorArchitecture))
+ {
+ m_pAssemblyIdentity->m_kProcessorArchitecture = kProcessorArchitecture;
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
+ }
+ else
+ {
+ fIsValid = FALSE;
+ }
+ }
+ else if (EqualsCaseInsensitive(attributeString, W("retargetable")))
+ {
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
+
+ if (EqualsCaseInsensitive(valueString, W("yes")))
+ {
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
+ }
+ else if (!EqualsCaseInsensitive(valueString, W("no")))
+ {
+ fIsValid = FALSE;
+ }
+ }
+ else if (EqualsCaseInsensitive(attributeString, W("contenttype")))
+ {
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
+ GO_IF_WILDCARD(valueString);
+
+ if (EqualsCaseInsensitive(valueString, W("windowsruntime")))
+ {
+ m_pAssemblyIdentity->m_kContentType = AssemblyContentType_WindowsRuntime;
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
+ }
+ else
+ {
+ fIsValid = FALSE;
+ }
+ }
+ else if (EqualsCaseInsensitive(attributeString, W("custom")))
+ {
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_CUSTOM);
+
+ if (EqualsCaseInsensitive(valueString, W("null")))
+ {
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_CUSTOM_NULL);
+ }
+ else
+ {
+ GO_IF_VALIDATE_FAILED(ValidateHex, AssemblyIdentity::IDENTITY_FLAG_CUSTOM);
+ HexToBlob(valueString,
+ FALSE /* fValidateHex */,
+ FALSE /* fIsToken */,
+ m_pAssemblyIdentity->m_customBLOB);
+ }
+ }
+
+ Exit:
+ return fIsValid;
+ }
+
+ /* static */
+ void TextualIdentityParser::EscapeString(SString &input,
+ SString &result)
+ {
+ BOOL fNeedQuotes = FALSE;
+ WCHAR wcQuoteCharacter = W('"');
+
+ SmallStackSString tmpString;
+ SString::Iterator cursor = input.Begin();
+ SString::Iterator end = input.End() - 1;
+
+ // Leading/Trailing white space require quotes
+ if (IsWhitespace(cursor[0]) || IsWhitespace(end[0]))
+ {
+ fNeedQuotes = TRUE;
+ }
+
+ // Fusion textual identity compat: escape all non-quote characters even if quoted
+ while (cursor <= end)
+ {
+ WCHAR wcCurrentChar = cursor[0];
+
+ switch (wcCurrentChar)
+ {
+ case W('"'):
+ case W('\''):
+ if (fNeedQuotes && (wcQuoteCharacter != wcCurrentChar))
+ {
+ tmpString.Append(wcCurrentChar);
+ }
+ else if (!fNeedQuotes)
+ {
+ fNeedQuotes = TRUE;
+ wcQuoteCharacter = (wcCurrentChar == W('"') ? W('\'') : W('"'));
+ tmpString.Append(wcCurrentChar);
+ }
+ else
+ {
+ tmpString.Append(W('\\'));
+ tmpString.Append(wcCurrentChar);
+ }
+ break;
+ case W('='):
+ case W(','):
+ case W('\\'):
+ tmpString.Append(W('\\'));
+ tmpString.Append(wcCurrentChar);
+ break;
+ case 9:
+ tmpString.Append(W("\\t"));
+ break;
+ case 10:
+ tmpString.Append(W("\\n"));
+ break;
+ case 13:
+ tmpString.Append(W("\\r"));
+ break;
+ default:
+ tmpString.Append(wcCurrentChar);
+ break;
+ }
+
+ cursor++;
+ }
+
+ if (fNeedQuotes)
+ {
+ result.Clear();
+ result.Append(wcQuoteCharacter);
+ result.Append(tmpString);
+ result.Append(wcQuoteCharacter);
+ }
+ else
+ {
+ result.Set(tmpString);
+ }
+ }
+};
diff --git a/src/coreclr/binder/utils.cpp b/src/coreclr/binder/utils.cpp
new file mode 100644
index 00000000000..21fc115a776
--- /dev/null
+++ b/src/coreclr/binder/utils.cpp
@@ -0,0 +1,255 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// Utils.cpp
+//
+
+
+//
+// Implements a bunch of binder auxilary functions
+//
+// ============================================================
+
+#include "utils.hpp"
+
+#include "strongnameinternal.h"
+#include "corpriv.h"
+#include "clr/fs/path.h"
+using namespace clr::fs;
+
+namespace BINDER_SPACE
+{
+ namespace
+ {
+ inline const WCHAR *GetPlatformPathSeparator()
+ {
+#ifdef TARGET_UNIX
+ return W("/");
+#else
+ return W("\\");
+#endif // TARGET_UNIX
+ }
+ }
+
+ void MutateUrlToPath(SString &urlOrPath)
+ {
+ const SString fileUrlPrefix(SString::Literal, W("file://"));
+ SString::Iterator i = urlOrPath.Begin();
+
+ if (urlOrPath.MatchCaseInsensitive(i, fileUrlPrefix))
+ {
+ urlOrPath.Delete(i, fileUrlPrefix.GetCount());
+
+ i = urlOrPath.Begin() + 1;
+ if (i[0] == W(':'))
+ {
+ // CLR erroneously passes in file:// prepended to file paths,
+ // so we can't tell the difference between UNC and local file.
+ goto Exit;
+ }
+
+ i = urlOrPath.Begin();
+#if !defined(TARGET_UNIX)
+ if (i[0] == W('/'))
+ {
+ // Disk path file:///
+ urlOrPath.Delete(i, 1);
+ }
+ else if (i[0] != W('\\'))
+ {
+ // UNC Path, re-insert "//" if not the wrong file://\\...
+ urlOrPath.Insert(i, W("//"));
+ }
+#else
+ // Unix doesn't have a distinction between local and network path
+ _ASSERTE(i[0] == W('\\') || i[0] == W('/'));
+#endif
+ }
+
+ Exit:
+ while (urlOrPath.Find(i, W('/')))
+ {
+ urlOrPath.Replace(i, W('\\'));
+ }
+ }
+
+ void CombinePath(SString &pathA,
+ SString &pathB,
+ SString &combinedPath)
+ {
+ SString platformPathSeparator(SString::Literal, GetPlatformPathSeparator());
+ combinedPath.Set(pathA);
+
+ if (!combinedPath.IsEmpty() && !combinedPath.EndsWith(platformPathSeparator))
+ {
+ combinedPath.Append(platformPathSeparator);
+ }
+
+ combinedPath.Append(pathB);
+ }
+
+ HRESULT GetTokenFromPublicKey(SBuffer &publicKeyBLOB,
+ SBuffer &publicKeyTokenBLOB)
+ {
+ HRESULT hr = S_OK;
+
+ const BYTE *pByteKey = publicKeyBLOB;
+ DWORD dwKeyLen = publicKeyBLOB.GetSize();
+ BYTE *pByteToken = NULL;
+ DWORD dwTokenLen = 0;
+
+ IF_FAIL_GO(StrongNameTokenFromPublicKey(
+ const_cast<BYTE*>(pByteKey),
+ dwKeyLen,
+ &pByteToken,
+ &dwTokenLen));
+
+ _ASSERTE(pByteToken != NULL);
+ publicKeyTokenBLOB.Set(pByteToken, dwTokenLen);
+ StrongNameFreeBuffer(pByteToken);
+
+ Exit:
+ return hr;
+ }
+
+ BOOL IsFileNotFound(HRESULT hr)
+ {
+ return RuntimeFileNotFound(hr);
+ }
+
+ HRESULT GetNextPath(SString& paths, SString::Iterator& startPos, SString& outPath)
+ {
+ HRESULT hr = S_OK;
+
+ bool wrappedWithQuotes = false;
+
+ // Skip any leading spaces or path separators
+ while (paths.Skip(startPos, W(' ')) || paths.Skip(startPos, PATH_SEPARATOR_CHAR_W)) {}
+
+ if (startPos == paths.End())
+ {
+ // No more paths in the string and we just skipped over some white space
+ outPath.Set(W(""));
+ return S_FALSE;
+ }
+
+ // Support paths being wrapped with quotations
+ if (paths.Skip(startPos, W('\"')))
+ {
+ wrappedWithQuotes = true;
+ }
+
+ SString::Iterator iEnd = startPos; // Where current path ends
+ SString::Iterator iNext; // Where next path starts
+ if (wrappedWithQuotes)
+ {
+ if (paths.Find(iEnd, W('\"')))
+ {
+ iNext = iEnd;
+ // Find where the next path starts - there should be a path separator right after the closing quotation mark
+ if (paths.Find(iNext, PATH_SEPARATOR_CHAR_W))
+ {
+ iNext++;
+ }
+ else
+ {
+ iNext = paths.End();
+ }
+ }
+ else
+ {
+ // There was no terminating quotation mark - that's bad
+ GO_WITH_HRESULT(E_INVALIDARG);
+ }
+ }
+ else if (paths.Find(iEnd, PATH_SEPARATOR_CHAR_W))
+ {
+ iNext = iEnd + 1;
+ }
+ else
+ {
+ iNext = iEnd = paths.End();
+ }
+
+ // Skip any trailing spaces
+ while (iEnd[-1] == W(' '))
+ {
+ iEnd--;
+ }
+
+ _ASSERTE(startPos < iEnd);
+
+ outPath.Set(paths, startPos, iEnd);
+ startPos = iNext;
+ Exit:
+ return hr;
+ }
+
+ HRESULT GetNextTPAPath(SString& paths, SString::Iterator& startPos, bool dllOnly, SString& outPath, SString& simpleName, bool& isNativeImage)
+ {
+ HRESULT hr = S_OK;
+ isNativeImage = false;
+
+ HRESULT pathResult = S_OK;
+ IF_FAIL_GO(pathResult = GetNextPath(paths, startPos, outPath));
+ if (pathResult == S_FALSE)
+ {
+ return S_FALSE;
+ }
+
+#ifndef CROSSGEN_COMPILE
+ if (Path::IsRelative(outPath))
+ {
+ GO_WITH_HRESULT(E_INVALIDARG);
+ }
+#endif
+
+ {
+ // Find the beginning of the simple name
+ SString::Iterator iSimpleNameStart = outPath.End();
+
+ if (!outPath.FindBack(iSimpleNameStart, DIRECTORY_SEPARATOR_CHAR_W))
+ {
+ iSimpleNameStart = outPath.Begin();
+ }
+ else
+ {
+ // Advance past the directory separator to the first character of the file name
+ iSimpleNameStart++;
+ }
+
+ if (iSimpleNameStart == outPath.End())
+ {
+ GO_WITH_HRESULT(E_INVALIDARG);
+ }
+
+ // GCC complains if we create SStrings inline as part of a function call
+ SString sNiDll(W(".ni.dll"));
+ SString sNiExe(W(".ni.exe"));
+ SString sDll(W(".dll"));
+ SString sExe(W(".exe"));
+
+ if (!dllOnly && (outPath.EndsWithCaseInsensitive(sNiDll) ||
+ outPath.EndsWithCaseInsensitive(sNiExe)))
+ {
+ simpleName.Set(outPath, iSimpleNameStart, outPath.End() - 7);
+ isNativeImage = true;
+ }
+ else if (outPath.EndsWithCaseInsensitive(sDll) ||
+ (!dllOnly && outPath.EndsWithCaseInsensitive(sExe)))
+ {
+ simpleName.Set(outPath, iSimpleNameStart, outPath.End() - 4);
+ }
+ else
+ {
+ // Invalid filename
+ GO_WITH_HRESULT(E_INVALIDARG);
+ }
+ }
+
+ Exit:
+ return hr;
+ }
+
+};
diff --git a/src/coreclr/binder/variables.cpp b/src/coreclr/binder/variables.cpp
new file mode 100644
index 00000000000..fbdd106b4dd
--- /dev/null
+++ b/src/coreclr/binder/variables.cpp
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// ============================================================
+//
+// Variables.cpp
+//
+
+
+//
+// Implements the Variables class
+//
+// ============================================================
+
+#include "variables.hpp"
+
+#include "ex.h"
+
+namespace BINDER_SPACE
+{
+ Variables *g_BinderVariables = NULL;
+
+ Variables::Variables()
+ {
+ // Nothing to do here
+ }
+
+ Variables::~Variables()
+ {
+ // Nothing to do here
+ }
+
+ HRESULT Variables::Init()
+ {
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ // AssemblyBinder string constants
+ httpURLPrefix.SetLiteral(W("http://"));
+
+ // AssemblyName string constants
+ cultureNeutral.SetLiteral(W("neutral"));
+ corelib.SetLiteral(CoreLibName_W);
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+ }
+};