summaryrefslogtreecommitdiff
path: root/src/vm/pefile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/pefile.cpp')
-rw-r--r--src/vm/pefile.cpp5163
1 files changed, 5163 insertions, 0 deletions
diff --git a/src/vm/pefile.cpp b/src/vm/pefile.cpp
new file mode 100644
index 0000000000..86785e2417
--- /dev/null
+++ b/src/vm/pefile.cpp
@@ -0,0 +1,5163 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// --------------------------------------------------------------------------------
+// PEFile.cpp
+//
+
+// --------------------------------------------------------------------------------
+
+
+#include "common.h"
+#include "pefile.h"
+#include "strongname.h"
+#include "corperm.h"
+#include "eecontract.h"
+#include "apithreadstress.h"
+#include "eeconfig.h"
+#ifdef FEATURE_FUSION
+#include "fusionpriv.h"
+#include "shlwapi.h"
+#endif
+#include "product_version.h"
+#include "eventtrace.h"
+#include "security.h"
+#include "corperm.h"
+#include "dbginterface.h"
+#include "peimagelayout.inl"
+#include "dlwrap.h"
+#include "invokeutil.h"
+#ifdef FEATURE_PREJIT
+#include "compile.h"
+#endif
+#include "strongnameinternal.h"
+
+#ifdef FEATURE_VERSIONING
+#include "../binder/inc/applicationcontext.hpp"
+#endif
+
+#ifndef FEATURE_FUSION
+#include "clrprivbinderutil.h"
+#include "../binder/inc/coreclrbindercommon.h"
+#endif
+
+#ifdef FEATURE_CAS_POLICY
+#include <wintrust.h>
+#endif
+
+#ifdef FEATURE_PREJIT
+#include "compile.h"
+
+#ifdef DEBUGGING_SUPPORTED
+SVAL_IMPL_INIT(DWORD, PEFile, s_NGENDebugFlags, 0);
+#endif
+#endif
+
+#include "sha1.h"
+
+#if defined(FEATURE_FUSION)
+#include "clrprivbinderfusion.h"
+#include "clrprivbinderappx.h"
+#include "clrprivbinderloadfile.h"
+#endif
+
+#ifndef DACCESS_COMPILE
+
+// ================================================================================
+// PEFile class - this is an abstract base class for PEModule and PEAssembly
+// <TODO>@todo: rename TargetFile</TODO>
+// ================================================================================
+
+PEFile::PEFile(PEImage *identity, BOOL fCheckAuthenticodeSignature/*=TRUE*/) :
+#if _DEBUG
+ m_pDebugName(NULL),
+#endif
+ m_identity(NULL),
+ m_openedILimage(NULL),
+#ifdef FEATURE_PREJIT
+ m_nativeImage(NULL),
+ m_fCanUseNativeImage(TRUE),
+#endif
+ m_MDImportIsRW_Debugger_Use_Only(FALSE),
+ m_bHasPersistentMDImport(FALSE),
+ m_pMDImport(NULL),
+ m_pImporter(NULL),
+ m_pEmitter(NULL),
+#ifndef FEATURE_CORECLR
+ m_pAssemblyImporter(NULL),
+ m_pAssemblyEmitter(NULL),
+#endif
+ m_pMetadataLock(::new SimpleRWLock(PREEMPTIVE, LOCK_TYPE_DEFAULT)),
+ m_refCount(1),
+ m_hash(NULL),
+ m_flags(0),
+ m_fStrongNameVerified(FALSE)
+#ifdef FEATURE_CAS_POLICY
+ ,m_certificate(NULL),
+ m_fCheckedCertificate(FALSE)
+ ,m_pSecurityManager(NULL)
+ ,m_securityManagerLock(CrstPEFileSecurityManager)
+#endif // FEATURE_CAS_POLICY
+ ,m_pHostAssembly(nullptr)
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+ ,m_pFallbackLoadContextBinder(nullptr)
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+{
+ CONTRACTL
+ {
+ CONSTRUCTOR_CHECK;
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if (identity)
+ {
+ identity->AddRef();
+ m_identity = identity;
+
+ if(identity->IsOpened())
+ {
+ //already opened, prepopulate
+ identity->AddRef();
+ m_openedILimage = identity;
+ }
+ }
+
+
+#ifdef FEATURE_CAS_POLICY
+ if (fCheckAuthenticodeSignature)
+ {
+ CheckAuthenticodeSignature();
+ }
+#endif // FEATURE_CAS_POLICY
+}
+
+
+
+PEFile::~PEFile()
+{
+ CONTRACTL
+ {
+ DESTRUCTOR_CHECK;
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ ReleaseMetadataInterfaces(TRUE);
+
+ if (m_hash != NULL)
+ delete m_hash;
+
+#ifdef FEATURE_PREJIT
+ if (m_nativeImage != NULL)
+ {
+ MarkNativeImageInvalidIfOwned();
+
+ m_nativeImage->Release();
+ }
+#endif //FEATURE_PREJIT
+
+
+ if (m_openedILimage != NULL)
+ m_openedILimage->Release();
+ if (m_identity != NULL)
+ m_identity->Release();
+ if (m_pMetadataLock)
+ delete m_pMetadataLock;
+#ifdef FEATURE_CAS_POLICY
+ if (m_pSecurityManager) {
+ m_pSecurityManager->Release();
+ m_pSecurityManager = NULL;
+ }
+ if (m_certificate && !g_pCertificateCache->Contains(m_certificate))
+ CoTaskMemFree(m_certificate);
+#endif // FEATURE_CAS_POLICY
+
+ if (m_pHostAssembly != NULL)
+ {
+ m_pHostAssembly->Release();
+ }
+}
+
+#ifndef DACCESS_COMPILE
+void PEFile::ReleaseIL()
+{
+ WRAPPER_NO_CONTRACT;
+ if (m_openedILimage!=NULL )
+ {
+ ReleaseMetadataInterfaces(TRUE, TRUE);
+ if (m_identity != NULL)
+ {
+ m_identity->Release();
+ m_identity=NULL;
+ }
+ m_openedILimage->Release();
+ m_openedILimage = NULL;
+ }
+}
+#endif
+
+/* static */
+PEFile *PEFile::Open(PEImage *image)
+{
+ CONTRACT(PEFile *)
+ {
+ PRECONDITION(image != NULL);
+ PRECONDITION(image->CheckFormat());
+ POSTCONDITION(RETVAL != NULL);
+ POSTCONDITION(!RETVAL->IsModule());
+ POSTCONDITION(!RETVAL->IsAssembly());
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACT_END;
+
+ PEFile *pFile = new PEFile(image, FALSE);
+
+ if (image->HasNTHeaders() && image->HasCorHeader())
+ pFile->OpenMDImport_Unsafe(); //no one else can see the object yet
+
+#if _DEBUG
+ pFile->m_debugName = image->GetPath();
+ pFile->m_debugName.Normalize();
+ pFile->m_pDebugName = pFile->m_debugName;
+#endif
+
+ RETURN pFile;
+}
+
+// ------------------------------------------------------------
+// Loader support routines
+// ------------------------------------------------------------
+
+template<class T> void CoTaskFree(T *p)
+{
+ if (p != NULL)
+ {
+ p->T::~T();
+
+ CoTaskMemFree(p);
+ }
+}
+
+
+NEW_WRAPPER_TEMPLATE1(CoTaskNewHolder, CoTaskFree<_TYPE>);
+
+BOOL PEFile::CanLoadLibrary()
+{
+ WRAPPER_NO_CONTRACT;
+
+ // Dynamic and resource modules don't need LoadLibrary.
+ if (IsDynamic() || IsResource()||IsLoaded())
+ return TRUE;
+
+ // If we're been granted skip verification, OK
+ if (HasSkipVerification())
+ return TRUE;
+
+ // Otherwise, we can only load if IL only.
+ return IsILOnly();
+}
+
+#ifdef FEATURE_MIXEDMODE
+
+#ifndef CROSSGEN_COMPILE
+
+// Returns TRUE if this file references managed CRT (msvcmNN*).
+BOOL PEFile::ReferencesManagedCRT()
+{
+ STANDARD_VM_CONTRACT;
+
+ IMDInternalImportHolder pImport = GetMDImport();
+ MDEnumHolder hEnum(pImport);
+
+ IfFailThrow(pImport->EnumInit(mdtModuleRef, mdTokenNil, &hEnum));
+
+ mdModuleRef tk;
+ while (pImport->EnumNext(&hEnum, &tk))
+ {
+ // we are looking for "msvcmNN*"
+ LPCSTR szName;
+ IfFailThrow(pImport->GetModuleRefProps(tk, &szName));
+
+ if (_strnicmp(szName, "msvcm", 5) == 0 && isdigit(szName[5]) && isdigit(szName[6]))
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+void PEFile::CheckForDisallowedInProcSxSLoadWorker()
+{
+ STANDARD_VM_CONTRACT;
+
+ // provide an opt-out switch for now
+ if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DisableIJWVersionCheck) != 0)
+ return;
+
+ // ************************************************************************************************
+ // 1. See if this file should be checked
+ // The following checks filter out non-mixed mode assemblies that don't reference msvcmNN*. We only
+ // care about non-ILONLY images (IJW) or 2.0 C++/CLI pure images.
+ if (IsResource() || IsDynamic())
+ return;
+
+ // check the metadata version string
+ COUNT_T size;
+ PVOID pMetaData = (PVOID)GetMetadata(&size);
+ if (!pMetaData)
+ {
+ // No metadata section? Well somebody should have caught this earlier so report as
+ // ExecutionEngine rather than BIF.
+ EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
+ }
+
+ LPCSTR pVersion = NULL;
+ IfFailThrow(GetImageRuntimeVersionString(pMetaData, &pVersion));
+
+ char chV;
+ unsigned uiMajor, uiMinor;
+ BOOL fLegacyImage = (sscanf_s(pVersion, "%c%u.%u", &chV, 1, &uiMajor, &uiMinor) == 3 && (chV == W('v') || chV == W('V')) && uiMajor <= 2);
+
+ // Note that having VTFixups properly working really is limited to non-ILONLY images. In particular,
+ // the shim does not even attempt to patch ILONLY images in any way with bootstrap thunks.
+ if (IsILOnly())
+ {
+ // all >2.0 ILONLY images are fine because >2.0 managed CRTs can be loaded in multiple runtimes
+ if (!fLegacyImage)
+ return;
+
+ // legacy ILONLY images that don't reference the managed CRT are fine
+ if (!ReferencesManagedCRT())
+ return;
+ }
+
+ // get the version of this runtime
+ WCHAR wzThisRuntimeVersion[_MAX_PATH];
+ DWORD cchVersion = COUNTOF(wzThisRuntimeVersion);
+ IfFailThrow(g_pCLRRuntime->GetVersionString(wzThisRuntimeVersion, &cchVersion));
+
+ // ************************************************************************************************
+ // 2. For legacy assemblies, verify that legacy APIs are/would be bound to this runtime
+ if (fLegacyImage)
+ {
+ WCHAR wzAPIVersion[_MAX_PATH];
+ bool fLegacyAPIsAreBound = false;
+
+ { // Check if the legacy APIs have already been bound to us using the new hosting APIs.
+ ReleaseHolder<ICLRMetaHost> pMetaHost;
+ IfFailThrow(CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost));
+
+ ReleaseHolder<ICLRRuntimeInfo> pInfo;
+ // Returns S_FALSE when no runtime is currently bound, S_OK when one is.
+ HRESULT hr = pMetaHost->QueryLegacyV2RuntimeBinding(IID_ICLRRuntimeInfo, (LPVOID*)&pInfo);
+ IfFailThrow(hr);
+
+ if (hr == S_OK)
+ { // Legacy APIs are bound, now check if they are bound to us.
+ fLegacyAPIsAreBound = true;
+
+ cchVersion = COUNTOF(wzAPIVersion);
+ IfFailThrow(pInfo->GetVersionString(wzAPIVersion, &cchVersion));
+
+ if (SString::_wcsicmp(wzThisRuntimeVersion, wzAPIVersion) == 0)
+ { // This runtime is the one bound to the legacy APIs, ok to load legacy assembly.
+ return;
+ }
+ }
+ }
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4996) // we are going to call deprecated APIs
+#endif
+ // We need the above QueryLegacyV2RuntimeBinding check because GetRequestedRuntimeInfo will not take into
+ // account the current binding, which could have been set by the host rather than through an EXE config.
+ // If, however, the legacy APIs are not bound (indicated in fLegacyAPIsAreBound) then we can assume that
+ // the legacy APIs would bind using the equivalent of CorBindToRuntime(NULL) as a result of loading this
+ // legacy IJW assembly, and so we use GetRequestedRuntimeInfo to check without actually causing the bind.
+ // By avoiding causing the bind, we avoid a binding side effect in the failure case.
+ if (!fLegacyAPIsAreBound &&
+ SUCCEEDED(GetRequestedRuntimeInfo(NULL, NULL, NULL, 0, // pExe, pwszVersion, pConfigurationFile, startupFlags
+ RUNTIME_INFO_UPGRADE_VERSION | RUNTIME_INFO_DONT_RETURN_DIRECTORY | RUNTIME_INFO_DONT_SHOW_ERROR_DIALOG,
+ NULL, 0, NULL, // pDirectory, dwDirectory, pdwDirectoryLength
+ wzAPIVersion, COUNTOF(wzAPIVersion), &cchVersion))) // pVersion, cchBuffer, pdwLength
+ {
+ if (SString::_wcsicmp(wzThisRuntimeVersion, wzAPIVersion) == 0)
+ {
+ // it came back as this version - call CorBindToRuntime to actually bind it
+ ReleaseHolder<ICLRRuntimeHost> pHost;
+ IfFailThrow(CorBindToRuntime(wzAPIVersion, NULL, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID *)&pHost));
+
+ // and verify that nobody beat us to it
+ IfFailThrow(GetCORVersion(wzAPIVersion, COUNTOF(wzAPIVersion), &cchVersion));
+
+ if (SString::_wcsicmp(wzThisRuntimeVersion, wzAPIVersion) == 0)
+ {
+ // we have verified that when the assembly calls CorBindToRuntime(NULL),
+ // it will get this runtime, so we allow it to be loaded
+ return;
+ }
+ }
+ }
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+ MAKE_WIDEPTR_FROMUTF8(pwzVersion, pVersion);
+
+ ExternalLog(LF_LOADER, LL_ERROR, W("ERR: Rejecting IJW module built against %s because it could be loaded into another runtime in this process."), pwzVersion);
+ COMPlusThrow(kFileLoadException, IDS_EE_IJWLOAD_CROSSVERSION_DISALLOWED, pwzVersion, QUOTE_MACRO_L(VER_MAJORVERSION.VER_MINORVERSION));
+ }
+
+ // ************************************************************************************************
+ // 3. For 4.0+ assemblies, verify that it hasn't been loaded into another runtime
+ ReleaseHolder<ICLRRuntimeHostInternal> pRuntimeHostInternal;
+ IfFailThrow(g_pCLRRuntime->GetInterface(CLSID_CLRRuntimeHostInternal,
+ IID_ICLRRuntimeHostInternal,
+ &pRuntimeHostInternal));
+
+ PTR_VOID pModuleBase = GetLoadedIL()->GetBase();
+
+ ReleaseHolder<ICLRRuntimeInfo> pRuntimeInfo;
+ HRESULT hr = pRuntimeHostInternal->LockModuleForRuntime((BYTE *)pModuleBase, IID_ICLRRuntimeInfo, &pRuntimeInfo);
+
+ IfFailThrow(hr);
+
+ if (hr == S_OK)
+ {
+ // this runtime was the first one to lock the module
+ return;
+ }
+
+ // another runtime has loaded this module so we have to block the load
+ WCHAR wzLoadedRuntimeVersion[_MAX_PATH];
+ cchVersion = COUNTOF(wzLoadedRuntimeVersion);
+ IfFailThrow(pRuntimeInfo->GetVersionString(wzLoadedRuntimeVersion, &cchVersion));
+
+ ExternalLog(LF_LOADER, LL_ERROR, W("ERR: Rejecting IJW module because it is already loaded into runtime version %s in this process."), wzLoadedRuntimeVersion);
+ COMPlusThrow(kFileLoadException, IDS_EE_IJWLOAD_MULTIRUNTIME_DISALLOWED, wzThisRuntimeVersion, wzLoadedRuntimeVersion);
+}
+
+// We don't allow loading IJW and C++/CLI pure images built against <=2.0 if legacy APIs are not bound to this
+// runtime. For IJW images built against >2.0, we don't allow the load if the image has already been loaded by
+// another runtime in this process.
+void PEFile::CheckForDisallowedInProcSxSLoad()
+{
+ STANDARD_VM_CONTRACT;
+
+ // have we checked this one before?
+ if (!IsInProcSxSLoadVerified())
+ {
+ CheckForDisallowedInProcSxSLoadWorker();
+
+ // if no exception was thrown, remember the fact that we don't have to do the check again
+ SetInProcSxSLoadVerified();
+ }
+}
+
+#else // CROSSGEN_COMPILE
+
+void PEFile::CheckForDisallowedInProcSxSLoad()
+{
+ // Noop for crossgen
+}
+
+#endif // CROSSGEN_COMPILE
+
+#endif // FEATURE_MIXEDMODE
+
+
+//-----------------------------------------------------------------------------------------------------
+// Catch attempts to load x64 assemblies on x86, etc.
+//-----------------------------------------------------------------------------------------------------
+static void ValidatePEFileMachineType(PEFile *peFile)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (peFile->IsIntrospectionOnly())
+ return; // ReflectionOnly assemblies permitted to violate CPU restrictions
+
+ if (peFile->IsDynamic())
+ return; // PEFiles for ReflectionEmit assemblies don't cache the machine type.
+
+ if (peFile->IsResource())
+ return; // PEFiles for resource assemblies don't cache the machine type.
+
+ if (peFile->HasNativeImage())
+ return; // If it passed the native binder, no need to do the check again esp. at the risk of inviting an IL page-in.
+
+ DWORD peKind;
+ DWORD actualMachineType;
+ peFile->GetPEKindAndMachine(&peKind, &actualMachineType);
+
+ if (actualMachineType == IMAGE_FILE_MACHINE_I386 && ((peKind & (peILonly | pe32BitRequired)) == peILonly))
+ return; // Image is marked CPU-agnostic.
+
+ if (actualMachineType != IMAGE_FILE_MACHINE_NATIVE && actualMachineType != IMAGE_FILE_MACHINE_NATIVE_NI)
+ {
+#ifdef _TARGET_AMD64_
+ // v4.0 64-bit compatibility workaround. The 64-bit v4.0 CLR's Reflection.Load(byte[]) api does not detect cpu-matches. We should consider fixing that in
+ // the next SxS release. In the meantime, this bypass will retain compat for 64-bit v4.0 CLR for target platforms that existed at the time.
+ //
+ // Though this bypass kicks in for all Load() flavors, the other Load() flavors did detect cpu-matches through various other code paths that still exist.
+ // Or to put it another way, this #ifdef makes the (4.5 only) ValidatePEFileMachineType() a NOP for x64, hence preserving 4.0 compatibility.
+ if (actualMachineType == IMAGE_FILE_MACHINE_I386 || actualMachineType == IMAGE_FILE_MACHINE_IA64)
+ return;
+#endif // _WIN64_
+
+ // Image has required machine that doesn't match the CLR.
+ StackSString name;
+ if (peFile->IsAssembly())
+ ((PEAssembly*)peFile)->GetDisplayName(name);
+ else
+ name = StackSString(SString::Utf8, peFile->GetSimpleName());
+
+ COMPlusThrow(kBadImageFormatException, IDS_CLASSLOAD_WRONGCPU, name.GetUnicode());
+ }
+
+ return; // If we got here, all is good.
+}
+
+void PEFile::LoadLibrary(BOOL allowNativeSkip/*=TRUE*/) // if allowNativeSkip==FALSE force IL image load
+{
+ CONTRACT_VOID
+ {
+ INSTANCE_CHECK;
+ POSTCONDITION(CheckLoaded());
+ STANDARD_VM_CHECK;
+ }
+ CONTRACT_END;
+
+ // Catch attempts to load x64 assemblies on x86, etc.
+ ValidatePEFileMachineType(this);
+
+ // See if we've already loaded it.
+ if (CheckLoaded(allowNativeSkip))
+ {
+#ifdef FEATURE_MIXEDMODE
+ // Prevent loading C++/CLI images into multiple runtimes in the same process. Note that if ILOnly images
+ // stop being LoadLibrary'ed, the check for pure 2.0 C++/CLI images will need to be done somewhere else.
+ if (!IsIntrospectionOnly())
+ CheckForDisallowedInProcSxSLoad();
+#endif // FEATURE_MIXEDMODE
+ RETURN;
+ }
+
+ // Note that we may be racing other threads here, in the case of domain neutral files
+
+ // Resource images are always flat.
+ if (IsResource())
+ {
+ GetILimage()->LoadNoMetaData(IsIntrospectionOnly());
+ RETURN;
+ }
+
+#if !defined(_WIN64)
+ if (!HasNativeImage() && (!GetILimage()->Has32BitNTHeaders()) && !IsIntrospectionOnly())
+ {
+ // Tried to load 64-bit assembly on 32-bit platform.
+ EEFileLoadException::Throw(this, COR_E_BADIMAGEFORMAT, NULL);
+ }
+#endif
+
+ // Don't do this if we are unverifiable
+ if (!CanLoadLibrary())
+ ThrowHR(SECURITY_E_UNVERIFIABLE);
+
+
+ // We need contents now
+ if (!HasNativeImage())
+ {
+ EnsureImageOpened();
+ }
+
+ if (IsIntrospectionOnly())
+ {
+ GetILimage()->LoadForIntrospection();
+ RETURN;
+ }
+
+
+ //---- Below this point, only do the things necessary for execution ----
+ _ASSERTE(!IsIntrospectionOnly());
+
+#ifdef FEATURE_PREJIT
+ // For on-disk Dlls, we can call LoadLibrary
+ if (IsDll() && !((HasNativeImage()?m_nativeImage:GetILimage())->GetPath().IsEmpty()))
+ {
+ // Note that we may get a DllMain notification inside here.
+ if (allowNativeSkip && HasNativeImage())
+ {
+ m_nativeImage->Load();
+ if(!m_nativeImage->IsNativeILILOnly())
+ GetILimage()->Load(); // For IJW we have to load IL also...
+ }
+ else
+ GetILimage()->Load();
+ }
+ else
+#endif // FEATURE_PREJIT
+ {
+
+ // Since we couldn't call LoadLibrary, we must be an IL only image
+ // or the image may still contain unfixed up stuff
+ // Note that we make an exception for CompilationDomains, since PEImage
+ // will map non-ILOnly images in a compilation domain.
+ if (!GetILimage()->IsILOnly() && !GetAppDomain()->IsCompilationDomain())
+ {
+ if (!GetILimage()->HasV1Metadata())
+ ThrowHR(COR_E_FIXUPSINEXE); // <TODO>@todo: better error</TODO>
+ }
+
+
+
+ // If we are already mapped, we can just use the current image.
+#ifdef FEATURE_PREJIT
+ if (allowNativeSkip && HasNativeImage())
+ {
+ m_nativeImage->LoadFromMapped();
+
+ if( !m_nativeImage->IsNativeILILOnly())
+ GetILimage()->LoadFromMapped(); // For IJW we have to load IL also...
+ }
+ else
+#endif
+ {
+ if (GetILimage()->IsFile())
+ GetILimage()->LoadFromMapped();
+ else
+ GetILimage()->LoadNoFile();
+ }
+ }
+
+#ifdef FEATURE_MIXEDMODE
+ // Prevent loading C++/CLI images into multiple runtimes in the same process. Note that if ILOnly images
+ // stop being LoadLibrary'ed, the check for pure 2.0 C++/CLI images will need to be done somewhere else.
+ CheckForDisallowedInProcSxSLoad();
+#endif // FEATURE_MIXEDMODE
+
+ RETURN;
+}
+
+void PEFile::SetLoadedHMODULE(HMODULE hMod)
+{
+ CONTRACT_VOID
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(CheckPointer(hMod));
+ PRECONDITION(CanLoadLibrary());
+ POSTCONDITION(CheckLoaded());
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACT_END;
+
+ // See if the image is an internal PEImage.
+ GetILimage()->SetLoadedHMODULE(hMod);
+
+ RETURN;
+}
+
+/* static */
+void PEFile::DefineEmitScope(
+ GUID iid,
+ void **ppEmit)
+{
+ CONTRACT_VOID
+ {
+ PRECONDITION(CheckPointer(ppEmit));
+ POSTCONDITION(CheckPointer(*ppEmit));
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACT_END;
+
+ SafeComHolder<IMetaDataDispenserEx> pDispenser;
+
+ // Get the Dispenser interface.
+ MetaDataGetDispenser(
+ CLSID_CorMetaDataDispenser,
+ IID_IMetaDataDispenserEx,
+ (void **)&pDispenser);
+ if (pDispenser == NULL)
+ {
+ ThrowOutOfMemory();
+ }
+
+ // Set the option on the dispenser turn on duplicate check for TypeDef and moduleRef
+ VARIANT varOption;
+ V_VT(&varOption) = VT_UI4;
+ V_I4(&varOption) = MDDupDefault | MDDupTypeDef | MDDupModuleRef | MDDupExportedType | MDDupAssemblyRef | MDDupPermission | MDDupFile;
+ IfFailThrow(pDispenser->SetOption(MetaDataCheckDuplicatesFor, &varOption));
+
+ // Set minimal MetaData size
+ V_VT(&varOption) = VT_UI4;
+ V_I4(&varOption) = MDInitialSizeMinimal;
+ IfFailThrow(pDispenser->SetOption(MetaDataInitialSize, &varOption));
+
+ // turn on the thread safety!
+ V_I4(&varOption) = MDThreadSafetyOn;
+ IfFailThrow(pDispenser->SetOption(MetaDataThreadSafetyOptions, &varOption));
+
+ IfFailThrow(pDispenser->DefineScope(CLSID_CorMetaDataRuntime, 0, iid, (IUnknown **)ppEmit));
+
+ RETURN;
+} // PEFile::DefineEmitScope
+
+// ------------------------------------------------------------
+// Identity
+// ------------------------------------------------------------
+
+BOOL PEFile::Equals(PEFile *pFile)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(CheckPointer(pFile));
+ GC_NOTRIGGER;
+ NOTHROW;
+ CANNOT_TAKE_LOCK;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // Same object is equal
+ if (pFile == this)
+ return TRUE;
+
+
+ // Execution and introspection files are NOT equal
+ if ( (!IsIntrospectionOnly()) != !(pFile->IsIntrospectionOnly()) )
+ {
+ return FALSE;
+ }
+
+ // Different host assemblies cannot be equal unless they are associated with the same host binder
+ // It's ok if only one has a host binder because multiple threads can race to load the same assembly
+ // and that may cause temporary candidate PEAssembly objects that never get bound to a host assembly
+ // because another thread beats it; the losing thread will pick up the PEAssembly in the cache.
+ if (pFile->HasHostAssembly() && this->HasHostAssembly())
+ {
+ UINT_PTR fileBinderId = 0;
+ if (FAILED(pFile->GetHostAssembly()->GetBinderID(&fileBinderId)))
+ return FALSE;
+
+ UINT_PTR thisBinderId = 0;
+ if (FAILED(this->GetHostAssembly()->GetBinderID(&thisBinderId)))
+ return FALSE;
+
+ if (fileBinderId != thisBinderId)
+ return FALSE;
+
+ }
+
+ // Same identity is equal
+ if (m_identity != NULL && pFile->m_identity != NULL
+ && m_identity->Equals(pFile->m_identity))
+ return TRUE;
+
+ // Same image is equal
+ if (m_openedILimage != NULL && pFile->m_openedILimage != NULL
+ && m_openedILimage->Equals(pFile->m_openedILimage))
+ return TRUE;
+
+ return FALSE;
+}
+
+BOOL PEFile::Equals(PEImage *pImage)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(CheckPointer(pImage));
+ GC_NOTRIGGER;
+ NOTHROW;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // Same object is equal
+ if (pImage == m_identity || pImage == m_openedILimage)
+ return TRUE;
+
+#ifdef FEATURE_PREJIT
+ if(pImage == m_nativeImage)
+ return TRUE;
+#endif
+ // Same identity is equal
+ if (m_identity != NULL
+ && m_identity->Equals(pImage))
+ return TRUE;
+
+ // Same image is equal
+ if (m_openedILimage != NULL
+ && m_openedILimage->Equals(pImage))
+ return TRUE;
+
+
+ return FALSE;
+}
+
+// ------------------------------------------------------------
+// Descriptive strings
+// ------------------------------------------------------------
+
+void PEFile::GetCodeBaseOrName(SString &result)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+ if (m_identity != NULL && !m_identity->GetPath().IsEmpty())
+ {
+ result.Set(m_identity->GetPath());
+ }
+ else if (IsAssembly())
+ {
+ ((PEAssembly*)this)->GetCodeBase(result);
+ }
+ else
+ result.SetUTF8(GetSimpleName());
+}
+
+#ifdef FEATURE_CAS_POLICY
+
+// Returns security information for the assembly based on the codebase
+void PEFile::GetSecurityIdentity(SString &codebase, SecZone *pdwZone, DWORD dwFlags, BYTE *pbUniqueID, DWORD *pcbUniqueID)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pdwZone));
+ PRECONDITION(CheckPointer(pbUniqueID));
+ PRECONDITION(CheckPointer(pcbUniqueID));
+ }
+ CONTRACTL_END;
+
+ if (IsAssembly())
+ {
+ ((PEAssembly*)this)->GetCodeBase(codebase);
+ }
+ else if (m_identity != NULL && !m_identity->GetPath().IsEmpty())
+ {
+ codebase.Set(W("file:///"));
+ codebase.Append(m_identity->GetPath());
+ }
+ else
+ {
+ _ASSERTE( !"Unable to determine security identity" );
+ }
+
+ GCX_PREEMP();
+
+ if(!codebase.IsEmpty())
+ {
+ *pdwZone = NoZone;
+
+ InitializeSecurityManager();
+
+ // We have a class name, return a class factory for it
+ _ASSERTE(sizeof(SecZone) == sizeof(DWORD));
+ IfFailThrow(m_pSecurityManager->MapUrlToZone(codebase,
+ reinterpret_cast<DWORD *>(pdwZone),
+ dwFlags));
+
+ if (*pdwZone>=NumZones)
+ IfFailThrow(SecurityPolicy::ApplyCustomZoneOverride(pdwZone));
+
+ IfFailThrow(m_pSecurityManager->GetSecurityId(codebase,
+ pbUniqueID,
+ pcbUniqueID,
+ 0));
+ }
+}
+
+void PEFile::InitializeSecurityManager()
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ CAN_TAKE_LOCK;
+ MODE_PREEMPTIVE;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+ if(m_pSecurityManager == NULL)
+ {
+ CrstHolder holder(&m_securityManagerLock);
+ if (m_pSecurityManager == NULL)
+ {
+ IfFailThrow(CoInternetCreateSecurityManager(NULL,
+ &m_pSecurityManager,
+ 0));
+ }
+ }
+}
+
+#endif // FEATURE_CAS_POLICY
+
+// ------------------------------------------------------------
+// Checks
+// ------------------------------------------------------------
+
+
+
+CHECK PEFile::CheckLoaded(BOOL bAllowNativeSkip/*=TRUE*/)
+{
+ CONTRACT_CHECK
+ {
+ INSTANCE_CHECK;
+ NOTHROW;
+ GC_NOTRIGGER;
+ SO_TOLERANT;
+ MODE_ANY;
+ }
+ CONTRACT_CHECK_END;
+
+ CHECK(IsLoaded(bAllowNativeSkip)
+ // We are allowed to skip LoadLibrary in most cases for ngen'ed IL only images
+ || (bAllowNativeSkip && HasNativeImage() && IsILOnly()));
+
+ CHECK_OK;
+}
+
+#ifndef FEATURE_CORECLR
+// ------------------------------------------------------------
+// Hash support
+// ------------------------------------------------------------
+
+#ifndef SHA1_HASH_SIZE
+#define SHA1_HASH_SIZE 20
+#endif
+
+void PEFile::GetSHA1Hash(SBuffer &result)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(CheckValue(result));
+ THROWS;
+ MODE_ANY;
+ GC_TRIGGERS;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+ // Cache the SHA1 hash in a buffer
+ if (m_hash == NULL)
+ {
+ // We shouldn't have to compute a SHA1 hash in any scenarios
+ // where the image opening should be suppressed.
+ EnsureImageOpened();
+
+ m_hash = new InlineSBuffer<SHA1_HASH_SIZE>();
+ GetILimage()->ComputeHash(CALG_SHA1, *m_hash);
+ }
+
+ result.Set(*m_hash);
+}
+#endif // FEATURE_CORECLR
+
+// ------------------------------------------------------------
+// Metadata access
+// ------------------------------------------------------------
+
+PTR_CVOID PEFile::GetMetadata(COUNT_T *pSize)
+{
+ CONTRACT(PTR_CVOID)
+ {
+ INSTANCE_CHECK;
+ POSTCONDITION(CheckPointer(pSize, NULL_OK));
+ POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ SUPPORTS_DAC;
+ }
+ CONTRACT_END;
+
+#ifdef FEATURE_PREJIT
+ if (HasNativeImageMetadata())
+ {
+ RETURN m_nativeImage->GetMetadata(pSize);
+ }
+#endif
+
+ if (IsDynamic()
+ || !GetILimage()->HasNTHeaders()
+ || !GetILimage()->HasCorHeader())
+ {
+ if (pSize != NULL)
+ *pSize = 0;
+ RETURN NULL;
+ }
+ else
+ {
+ RETURN GetILimage()->GetMetadata(pSize);
+ }
+}
+#endif // #ifndef DACCESS_COMPILE
+
+PTR_CVOID PEFile::GetLoadedMetadata(COUNT_T *pSize)
+{
+ CONTRACT(PTR_CVOID)
+ {
+ INSTANCE_CHECK;
+ POSTCONDITION(CheckPointer(pSize, NULL_OK));
+ POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ SUPPORTS_DAC;
+ }
+ CONTRACT_END;
+
+#ifdef FEATURE_PREJIT
+ if (HasNativeImageMetadata())
+ {
+ RETURN GetLoadedNative()->GetMetadata(pSize);
+ }
+#endif
+
+ if (!HasLoadedIL()
+ || !GetLoadedIL()->HasNTHeaders()
+ || !GetLoadedIL()->HasCorHeader())
+ {
+ if (pSize != NULL)
+ *pSize = 0;
+ RETURN NULL;
+ }
+ else
+ {
+ RETURN GetLoadedIL()->GetMetadata(pSize);
+ }
+}
+
+TADDR PEFile::GetIL(RVA il)
+{
+ CONTRACT(TADDR)
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(il != 0);
+ PRECONDITION(!IsDynamic());
+ PRECONDITION(!IsResource());
+#ifndef DACCESS_COMPILE
+ PRECONDITION(CheckLoaded());
+#endif
+ POSTCONDITION(RETVAL != NULL);
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ SUPPORTS_DAC;
+ }
+ CONTRACT_END;
+
+ PEImageLayout *image = NULL;
+
+#ifdef FEATURE_PREJIT
+ // Note it is important to get the IL from the native image if
+ // available, since we are using the metadata from the native image
+ // which has different IL rva's.
+ if (HasNativeImageMetadata())
+ {
+ image = GetLoadedNative();
+
+#ifndef DACCESS_COMPILE
+ // NGen images are trusted to be well-formed.
+ _ASSERTE(image->CheckILMethod(il));
+#endif
+ }
+ else
+#endif // FEATURE_PREJIT
+ {
+ image = GetLoadedIL();
+
+#ifndef DACCESS_COMPILE
+ // Verify that the IL blob is valid before giving it out
+ if (!image->CheckILMethod(il))
+ COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL_RANGE);
+#endif
+ }
+
+ RETURN image->GetRvaData(il);
+}
+
+#ifndef DACCESS_COMPILE
+
+void PEFile::OpenImporter()
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+ // Make sure internal MD is in RW format.
+ ConvertMDInternalToReadWrite();
+
+ IMetaDataImport2 *pIMDImport = NULL;
+ IfFailThrow(GetMetaDataPublicInterfaceFromInternal((void*)GetPersistentMDImport(),
+ IID_IMetaDataImport2,
+ (void **)&pIMDImport));
+
+ // Atomically swap it into the field (release it if we lose the race)
+ if (FastInterlockCompareExchangePointer(&m_pImporter, pIMDImport, NULL) != NULL)
+ pIMDImport->Release();
+}
+
+void PEFile::ConvertMDInternalToReadWrite()
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ INJECT_FAULT(EX_THROW(EEMessageException, (E_OUTOFMEMORY)););
+ }
+ CONTRACTL_END;
+
+ IMDInternalImport *pOld; // Old (current RO) value of internal import.
+ IMDInternalImport *pNew = NULL; // New (RW) value of internal import.
+
+ // Take a local copy of *ppImport. This may be a pointer to an RO
+ // or to an RW MDInternalXX.
+ pOld = m_pMDImport;
+ IMetaDataImport *pIMDImport = m_pImporter;
+ if (pIMDImport != NULL)
+ {
+ HRESULT hr = GetMetaDataInternalInterfaceFromPublic(pIMDImport, IID_IMDInternalImport, (void **)&pNew);
+ if (FAILED(hr))
+ {
+ EX_THROW(EEMessageException, (hr));
+ }
+ if (pNew == pOld)
+ {
+ pNew->Release();
+ return;
+ }
+ }
+ else
+ {
+ // If an RO, convert to an RW, return S_OK. If already RW, no conversion
+ // needed, return S_FALSE.
+ HRESULT hr = ConvertMDInternalImport(pOld, &pNew);
+
+ if (FAILED(hr))
+ {
+ EX_THROW(EEMessageException, (hr));
+ }
+
+ // If no conversion took place, don't change pointers.
+ if (hr == S_FALSE)
+ return;
+ }
+
+ // Swap the pointers in a thread safe manner. If the contents of *ppImport
+ // equals pOld then no other thread got here first, and the old contents are
+ // replaced with pNew. The old contents are returned.
+ _ASSERTE(m_bHasPersistentMDImport);
+ if (FastInterlockCompareExchangePointer(&m_pMDImport, pNew, pOld) == pOld)
+ {
+ //if the debugger queries, it will now see that we have RW metadata
+ m_MDImportIsRW_Debugger_Use_Only = TRUE;
+
+ // Swapped -- get the metadata to hang onto the old Internal import.
+ HRESULT hr=m_pMDImport->SetUserContextData(pOld);
+ _ASSERTE(SUCCEEDED(hr)||!"Leaking old MDImport");
+ IfFailThrow(hr);
+ }
+ else
+ { // Some other thread finished first. Just free the results of this conversion.
+ pNew->Release();
+ }
+}
+
+void PEFile::ConvertMetadataToRWForEnC()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ SO_INTOLERANT;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // This should only ever be called on EnC capable files.
+ // One can check this using Module::IsEditAndContinueCapable().
+
+ // This should only be called if we're debugging, stopped, and on the helper thread.
+ _ASSERTE(CORDebuggerAttached());
+ _ASSERTE((g_pDebugInterface != NULL) && g_pDebugInterface->ThisIsHelperThread());
+ _ASSERTE((g_pDebugInterface != NULL) && g_pDebugInterface->IsStopped());
+
+ // Convert the metadata to RW for Edit and Continue, properly replacing the metadata import interface pointer and
+ // properly preserving the old importer. This will be called before the EnC system tries to apply a delta to the module's
+ // metadata. ConvertMDInternalToReadWrite() does that quite nicely for us.
+ ConvertMDInternalToReadWrite();
+}
+
+void PEFile::OpenMDImport_Unsafe()
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+ if (m_pMDImport != NULL)
+ return;
+#ifdef FEATURE_PREJIT
+ if (m_nativeImage != NULL
+#ifdef FEATURE_CORECLR
+ && m_nativeImage->GetMDImport() != NULL
+#endif
+ )
+ {
+ // Use native image for metadata
+ m_flags |= PEFILE_HAS_NATIVE_IMAGE_METADATA;
+ m_pMDImport=m_nativeImage->GetMDImport();
+ }
+ else
+#endif
+ {
+#ifdef FEATURE_PREJIT
+ m_flags &= ~PEFILE_HAS_NATIVE_IMAGE_METADATA;
+#endif
+ if (!IsDynamic()
+ && GetILimage()->HasNTHeaders()
+ && GetILimage()->HasCorHeader())
+ {
+ m_pMDImport=GetILimage()->GetMDImport();
+ }
+ else
+ ThrowHR(COR_E_BADIMAGEFORMAT);
+
+ m_bHasPersistentMDImport=TRUE;
+ }
+ _ASSERTE(m_pMDImport);
+ m_pMDImport->AddRef();
+}
+
+void PEFile::OpenEmitter()
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+ // Make sure internal MD is in RW format.
+ ConvertMDInternalToReadWrite();
+
+ IMetaDataEmit *pIMDEmit = NULL;
+ IfFailThrow(GetMetaDataPublicInterfaceFromInternal((void*)GetPersistentMDImport(),
+ IID_IMetaDataEmit,
+ (void **)&pIMDEmit));
+
+ // Atomically swap it into the field (release it if we lose the race)
+ if (FastInterlockCompareExchangePointer(&m_pEmitter, pIMDEmit, NULL) != NULL)
+ pIMDEmit->Release();
+}
+
+#ifndef FEATURE_CORECLR
+void PEFile::OpenAssemblyImporter()
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+ // Make sure internal MD is in RW format.
+ ConvertMDInternalToReadWrite();
+
+ // Get the interface
+ IMetaDataAssemblyImport *pIMDAImport = NULL;
+ IfFailThrow(GetMetaDataPublicInterfaceFromInternal((void*)GetPersistentMDImport(),
+ IID_IMetaDataAssemblyImport,
+ (void **)&pIMDAImport));
+
+ // Atomically swap it into the field (release it if we lose the race)
+ if (FastInterlockCompareExchangePointer(&m_pAssemblyImporter, pIMDAImport, NULL) != NULL)
+ pIMDAImport->Release();
+}
+
+void PEFile::OpenAssemblyEmitter()
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+ // Make sure internal MD is in RW format.
+ ConvertMDInternalToReadWrite();
+
+ IMetaDataAssemblyEmit *pIMDAssemblyEmit = NULL;
+ IfFailThrow(GetMetaDataPublicInterfaceFromInternal((void*)GetPersistentMDImport(),
+ IID_IMetaDataAssemblyEmit,
+ (void **)&pIMDAssemblyEmit));
+
+ // Atomically swap it into the field (release it if we lose the race)
+ if (FastInterlockCompareExchangePointer(&m_pAssemblyEmitter, pIMDAssemblyEmit, NULL) != NULL)
+ pIMDAssemblyEmit->Release();
+}
+#endif // FEATURE_CORECLR
+
+void PEFile::ReleaseMetadataInterfaces(BOOL bDestructor, BOOL bKeepNativeData/*=FALSE*/)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(bDestructor||m_pMetadataLock->IsWriterLock());
+ }
+ CONTRACTL_END;
+ _ASSERTE(bDestructor || !m_bHasPersistentMDImport);
+#ifndef FEATURE_CORECLR
+ if (m_pAssemblyImporter != NULL)
+ {
+ m_pAssemblyImporter->Release();
+ m_pAssemblyImporter = NULL;
+ }
+ if(m_pAssemblyEmitter)
+ {
+ m_pAssemblyEmitter->Release();
+ m_pAssemblyEmitter=NULL;
+ }
+#endif
+
+ if (m_pImporter != NULL)
+ {
+ m_pImporter->Release();
+ m_pImporter = NULL;
+ }
+ if (m_pEmitter != NULL)
+ {
+ m_pEmitter->Release();
+ m_pEmitter = NULL;
+ }
+
+ if (m_pMDImport != NULL && (!bKeepNativeData || !HasNativeImage()))
+ {
+ m_pMDImport->Release();
+ m_pMDImport=NULL;
+ }
+}
+
+#ifdef FEATURE_CAS_POLICY
+
+void PEFile::CheckAuthenticodeSignature()
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+ // Check any security signature in the header.
+
+ // This publisher data can potentially be cached and passed back in via
+ // PEAssembly::CreateDelayed.
+ //
+ // HOWEVER - even if we cache it, the certificate still may need to be verified at
+ // load time. The only real caching can be done when the COR_TRUST certificate is
+ // ABSENT.
+ //
+ // (In the case where it is present, we could still theoretically
+ // cache the certificate and re-verify it and at least avoid touching the image
+ // again, however this path is not implemented yet, so this is TBD if we decide
+ // it is an important case to optimize for.)
+
+ if (!HasSecurityDirectory())
+ {
+ LOG((LF_SECURITY, LL_INFO1000, "No certificates found in module\n"));
+ }
+ else if(g_pConfig->GeneratePublisherEvidence())
+ {
+ // <TODO>@todo: Just because we don't have a file path, doesn't mean we can't have a certicate (does it?)</TODO>
+ if (!GetPath().IsEmpty())
+ {
+ GCX_PREEMP();
+
+ // Ignore any errors here - if we fail to validate a certificate, we just don't
+ // include it as evidence.
+
+ DWORD size;
+ CoTaskNewHolder<COR_TRUST> pCor = NULL;
+ // Failing to find a signature is OK.
+ LPWSTR pFileName = (LPWSTR) GetPath().GetUnicode();
+ DWORD dwAuthFlags = COR_NOUI|COR_NOPOLICY;
+#ifndef FEATURE_CORECLR
+ // Authenticode Verification Start
+ FireEtwAuthenticodeVerificationStart_V1(dwAuthFlags, 0, pFileName, GetClrInstanceId());
+#endif // !FEATURE_CORECLR
+
+ HRESULT hr = ::GetPublisher(pFileName,
+ NULL,
+ dwAuthFlags,
+ &pCor,
+ &size);
+
+#ifndef FEATURE_CORECLR
+ // Authenticode Verification End
+ FireEtwAuthenticodeVerificationStop_V1(dwAuthFlags, (ULONG)hr, pFileName, GetClrInstanceId());
+#endif // !FEATURE_CORECLR
+
+ if( SUCCEEDED(hr) ) {
+ DWORD index = 0;
+ EnumCertificateAdditionFlags dwFlags = g_pCertificateCache->AddEntry(pCor, &index);
+ switch (dwFlags) {
+ case CacheSaturated:
+ pCor.SuppressRelease();
+ m_certificate = pCor.GetValue();
+ break;
+
+ case Success:
+ pCor.SuppressRelease();
+ // falling through
+ case AlreadyExists:
+ m_certificate = g_pCertificateCache->GetEntry(index);
+ _ASSERTE(m_certificate);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ LOG((LF_SECURITY, LL_INFO1000, "Assembly has an Authenticode signature, but Publisher evidence has been disabled.\n"));
+ }
+
+ m_fCheckedCertificate = TRUE;
+}
+
+HRESULT STDMETHODCALLTYPE
+GetPublisher(__in __in_z IN LPWSTR pwsFileName, // File name, this is required even with the handle
+ IN HANDLE hFile, // Optional file name
+ IN DWORD dwFlags, // COR_NOUI or COR_NOPOLICY
+ OUT PCOR_TRUST *pInfo, // Returns a PCOR_TRUST (Use FreeM)
+ OUT DWORD *dwInfo) // Size of pInfo.
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+
+ GUID gV2 = COREE_POLICY_PROVIDER;
+ COR_POLICY_PROVIDER sCorPolicy;
+
+ WINTRUST_DATA sWTD;
+ WINTRUST_FILE_INFO sWTFI;
+
+ // Set up the COR trust provider
+ memset(&sCorPolicy, 0, sizeof(COR_POLICY_PROVIDER));
+ sCorPolicy.cbSize = sizeof(COR_POLICY_PROVIDER);
+
+ // Set up the winverify provider structures
+ memset(&sWTD, 0x00, sizeof(WINTRUST_DATA));
+ memset(&sWTFI, 0x00, sizeof(WINTRUST_FILE_INFO));
+
+ sWTFI.cbStruct = sizeof(WINTRUST_FILE_INFO);
+ sWTFI.hFile = hFile;
+ sWTFI.pcwszFilePath = pwsFileName;
+
+ sWTD.cbStruct = sizeof(WINTRUST_DATA);
+ sWTD.pPolicyCallbackData = &sCorPolicy; // Add in the cor trust information!!
+ if (dwFlags & COR_NOUI)
+ {
+ sWTD.dwUIChoice = WTD_UI_NONE; // No bad UI is overridden in COR TRUST provider
+ }
+ else
+ {
+ sWTD.dwUIChoice = WTD_UI_ALL; // No bad UI is overridden in COR TRUST provider
+ }
+ sWTD.dwUnionChoice = WTD_CHOICE_FILE;
+ sWTD.pFile = &sWTFI;
+
+ // Set the policies for the VM (we have stolen VMBased and use it like a flag)
+ if (dwFlags != 0)
+ sCorPolicy.VMBased = dwFlags;
+
+ LeaveRuntimeHolder holder((size_t)WinVerifyTrust);
+
+ // WinVerifyTrust calls mscorsecimpl.dll to do the policy check
+ hr = WinVerifyTrust(GetFocus(), &gV2, &sWTD);
+
+ *pInfo = sCorPolicy.pbCorTrust;
+ *dwInfo = sCorPolicy.cbCorTrust;
+
+ return hr;
+} // GetPublisher
+
+#endif // FEATURE_CAS_POLICY
+
+// ------------------------------------------------------------
+// PE file access
+// ------------------------------------------------------------
+
+// Note that most of these APIs are currently passed through
+// to the main image. However, in the near future they will
+// be rerouted to the native image in the prejitted case so
+// we can avoid using the original IL image.
+
+#endif //!DACCESS_COMPILE
+
+#ifdef FEATURE_PREJIT
+#ifndef DACCESS_COMPILE
+// ------------------------------------------------------------
+// Native image access
+// ------------------------------------------------------------
+
+void PEFile::SetNativeImage(PEImage *image)
+{
+ CONTRACT_VOID
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(!HasNativeImage());
+ STANDARD_VM_CHECK;
+ }
+ CONTRACT_END;
+
+ _ASSERTE(image != NULL);
+ PREFIX_ASSUME(image != NULL);
+
+ if (image->GetLoadedLayout()->GetBase() != image->GetLoadedLayout()->GetPreferredBase())
+ {
+ ExternalLog(LL_WARNING,
+ W("Native image loaded at base address") LFMT_ADDR
+ W("rather than preferred address:") LFMT_ADDR ,
+ DBG_ADDR(image->GetLoadedLayout()->GetBase()),
+ DBG_ADDR(image->GetLoadedLayout()->GetPreferredBase()));
+ }
+
+#ifdef FEATURE_TREAT_NI_AS_MSIL_DURING_DIAGNOSTICS
+ // In Apollo, first ask if we're supposed to be ignoring the prejitted code &
+ // structures in NGENd images. If so, bail now and do not set m_nativeImage. We've
+ // already set m_identity & m_openedILimage (possibly even pointing to the
+ // NGEN/Triton image), and will use those PEImages to find and JIT IL (even if they
+ // point to an NGENd/Tritonized image).
+ if (ShouldTreatNIAsMSIL())
+ RETURN;
+#endif
+
+ m_nativeImage = image;
+ m_nativeImage->AddRef();
+ m_nativeImage->Load();
+ m_nativeImage->AllocateLazyCOWPages();
+
+#if defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE)
+ static ConfigDWORD configNGenReserveForJumpStubs;
+ int percentReserveForJumpStubs = configNGenReserveForJumpStubs.val(CLRConfig::INTERNAL_NGenReserveForJumpStubs);
+ if (percentReserveForJumpStubs != 0)
+ {
+ PEImageLayout * pLayout = image->GetLoadedLayout();
+ ExecutionManager::GetEEJitManager()->EnsureJumpStubReserve((BYTE *)pLayout->GetBase(), pLayout->GetVirtualSize(),
+ percentReserveForJumpStubs * (pLayout->GetVirtualSize() / 100));
+ }
+#endif
+
+ ExternalLog(LL_INFO100, W("Attempting to use native image %s."), image->GetPath().GetUnicode());
+ RETURN;
+}
+
+void PEFile::ClearNativeImage()
+{
+ CONTRACT_VOID
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(HasNativeImage());
+ POSTCONDITION(!HasNativeImage());
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACT_END;
+
+ ExternalLog(LL_WARNING, "Discarding native image.");
+
+
+ MarkNativeImageInvalidIfOwned();
+
+ {
+ GCX_PREEMP();
+ SafeComHolderPreemp<IMDInternalImport> pOldImport=GetMDImportWithRef();
+ SimpleWriteLockHolder lock(m_pMetadataLock);
+
+ EX_TRY
+ {
+ ReleaseMetadataInterfaces(FALSE);
+ m_flags &= ~PEFILE_HAS_NATIVE_IMAGE_METADATA;
+ if (m_nativeImage)
+ m_nativeImage->Release();
+ m_nativeImage = NULL;
+ // Make sure our normal image is open
+ EnsureImageOpened();
+
+ // Reopen metadata from normal image
+ OpenMDImport();
+ }
+ EX_HOOK
+ {
+ RestoreMDImport(pOldImport);
+ }
+ EX_END_HOOK;
+ }
+
+ RETURN;
+}
+
+
+extern DWORD g_dwLogLevel;
+
+//===========================================================================================================
+// Encapsulates CLR and Fusion logging for runtime verification of native images.
+//===========================================================================================================
+static void RuntimeVerifyVLog(DWORD level, LoggableAssembly *pLogAsm, const WCHAR *fmt, va_list args)
+{
+ STANDARD_VM_CONTRACT;
+
+ BOOL fOutputToDebugger = (level == LL_ERROR && IsDebuggerPresent());
+ BOOL fOutputToLogging = LoggingOn(LF_ZAP, level);
+
+ StackSString message;
+ message.VPrintf(fmt, args);
+
+ if (fOutputToLogging)
+ {
+ SString displayString = pLogAsm->DisplayString();
+ LOG((LF_ZAP, level, "%s: \"%S\"\n", "ZAP", displayString.GetUnicode()));
+ LOG((LF_ZAP, level, "%S", message.GetUnicode()));
+ LOG((LF_ZAP, level, "\n"));
+ }
+
+ if (fOutputToDebugger)
+ {
+ SString displayString = pLogAsm->DisplayString();
+ WszOutputDebugString(W("CLR:("));
+ WszOutputDebugString(displayString.GetUnicode());
+ WszOutputDebugString(W(") "));
+ WszOutputDebugString(message);
+ WszOutputDebugString(W("\n"));
+ }
+
+#ifdef FEATURE_FUSION
+ IFusionBindLog *pFusionBindLog = pLogAsm->FusionBindLog();
+ if (pFusionBindLog)
+ {
+ pFusionBindLog->LogMessage(0, FUSION_BIND_LOG_CATEGORY_NGEN, message);
+
+ if (level == LL_ERROR) {
+ pFusionBindLog->SetResultCode(FUSION_BIND_LOG_CATEGORY_NGEN, E_FAIL);
+ pFusionBindLog->Flush(g_dwLogLevel, FUSION_BIND_LOG_CATEGORY_NGEN);
+ pFusionBindLog->Flush(g_dwLogLevel, FUSION_BIND_LOG_CATEGORY_DEFAULT);
+ }
+ }
+#endif //FEATURE_FUSION
+}
+
+
+//===========================================================================================================
+// Encapsulates CLR and Fusion logging for runtime verification of native images.
+//===========================================================================================================
+static void RuntimeVerifyLog(DWORD level, LoggableAssembly *pLogAsm, const WCHAR *fmt, ...)
+{
+ STANDARD_VM_CONTRACT;
+
+ // Avoid calling RuntimeVerifyVLog unless logging is on
+ if ( ((level == LL_ERROR) && IsDebuggerPresent())
+ || LoggingOn(LF_ZAP, level)
+#ifdef FEATURE_FUSION
+ || (pLogAsm->FusionBindLog() != NULL)
+#endif
+ )
+ {
+ va_list args;
+ va_start(args, fmt);
+
+ RuntimeVerifyVLog(level, pLogAsm, fmt, args);
+
+ va_end(args);
+ }
+}
+
+//==============================================================================
+
+static const LPCWSTR CorCompileRuntimeDllNames[NUM_RUNTIME_DLLS] =
+{
+#ifdef FEATURE_CORECLR
+ MAKEDLLNAME_W(W("coreclr")),
+#else
+ MAKEDLLNAME_W(W("CLR")),
+#endif
+ MAKEDLLNAME_W(W("clrjit"))
+};
+
+#if !defined(FEATURE_CORECLR) && !defined(CROSSGEN_COMPILE)
+static LPCWSTR s_ngenCompilerDllName = NULL;
+#endif //!FEATURE_CORECLR && !CROSSGEN_COMPILE
+
+LPCWSTR CorCompileGetRuntimeDllName(CorCompileRuntimeDlls id)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ SO_INTOLERANT;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+#if !defined(FEATURE_CORECLR) && !defined(CROSSGEN_COMPILE)
+ if (id == NGEN_COMPILER_INFO)
+ {
+ // The NGen compiler needs to be handled differently as it can be customized,
+ // unlike the other runtime DLLs.
+
+ if (s_ngenCompilerDllName == NULL)
+ {
+ // Check if there is an override for the compiler DLL
+ LPCWSTR ngenCompilerOverride = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_NGen_JitName);
+
+ if (ngenCompilerOverride == NULL)
+ {
+ s_ngenCompilerDllName = DEFAULT_NGEN_COMPILER_DLL_NAME;
+ }
+ else
+ {
+ if (wcsstr(ngenCompilerOverride, W(".dll")) == NULL)
+ {
+ EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE,
+ NGEN_COMPILER_OVERRIDE_KEY W(" should have a .DLL suffix"));
+ }
+
+ s_ngenCompilerDllName = ngenCompilerOverride;
+ }
+ }
+
+ return s_ngenCompilerDllName;
+ }
+#endif //!FEATURE_CORECLR && !CROSSGEN_COMPILE
+
+ return CorCompileRuntimeDllNames[id];
+}
+
+#ifndef CROSSGEN_COMPILE
+
+//==============================================================================
+// Will always return a valid HMODULE for CLR_INFO, but will return NULL for NGEN_COMPILER_INFO
+// if the DLL has not yet been loaded (it does not try to cause a load).
+
+// Gets set by IJitManager::LoadJit (yes, this breaks the abstraction boundary).
+HMODULE s_ngenCompilerDll = NULL;
+
+extern HMODULE CorCompileGetRuntimeDll(CorCompileRuntimeDlls id)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ SO_INTOLERANT;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+ // Currently special cased for every entry.
+#ifdef FEATURE_CORECLR
+ static_assert_no_msg(NUM_RUNTIME_DLLS == 2);
+ static_assert_no_msg(CORECLR_INFO == 0);
+#else // !FEATURE_CORECLR
+ static_assert_no_msg(NUM_RUNTIME_DLLS == 2);
+ static_assert_no_msg(CLR_INFO == 0);
+ static_assert_no_msg(NGEN_COMPILER_INFO == 1);
+#endif // else FEATURE_CORECLR
+
+ HMODULE hMod = NULL;
+
+ // Try to load the correct DLL
+ switch (id)
+ {
+#ifdef FEATURE_CORECLR
+ case CORECLR_INFO:
+ hMod = GetCLRModule();
+ break;
+#else // !FEATURE_CORECLR
+ case CLR_INFO:
+ hMod = GetCLRModule();
+ break;
+
+ case NGEN_COMPILER_INFO:
+ hMod = s_ngenCompilerDll;
+ break;
+#endif // else FEATURE_CORECLR
+
+ default:
+ COMPlusThrowNonLocalized(kExecutionEngineException,
+ W("Invalid runtime DLL ID"));
+ break;
+ }
+
+ return hMod;
+}
+#endif // CROSSGEN_COMPILE
+
+//===========================================================================================================
+// Helper for RuntimeVerifyNativeImageVersion(). Compares the loaded clr.dll and clrjit.dll's against
+// the ones the native image was compiled against.
+//===========================================================================================================
+static BOOL RuntimeVerifyNativeImageTimestamps(const CORCOMPILE_VERSION_INFO *info, LoggableAssembly *pLogAsm)
+{
+ STANDARD_VM_CONTRACT;
+
+#if !defined(CROSSGEN_COMPILE) && !defined(FEATURE_CORECLR)
+ //
+ // We will automatically fail any zap files which were compiled with different runtime dlls.
+ // This is so that we don't load bad ngen images after recompiling or patching the runtime.
+ //
+
+ for (DWORD index = 0; index < NUM_RUNTIME_DLLS; index++)
+ {
+ HMODULE hMod = CorCompileGetRuntimeDll((CorCompileRuntimeDlls)index);
+
+ if (hMod == NULL)
+ {
+ // Unless this is an NGen worker process, we don't want to load JIT compiler just to do a timestamp check.
+ // In an ideal case, all assemblies have native images, and JIT compiler never needs to be loaded at runtime.
+ // Loading JIT compiler just to check its timestamp would reduce the benefits of have native images.
+ // Since CLR and JIT are intended to be serviced together, the possibility of accidentally using native
+ // images created by an older JIT is very small, and is deemed an acceptable risk.
+ // Note that when multiple JIT compilers are used (e.g., clrjit.dll and compatjit.dll on x64 in .NET 4.6),
+ // they must all be in the same patch family.
+ if (!IsCompilationProcess())
+ continue;
+
+ // If we are doing ngen, then eagerly make sure all the system
+ // dependencies are loaded. Else ICorCompileInfo::CheckAssemblyZap()
+ // will not work correctly.
+
+ LPCWSTR wszDllName = CorCompileGetRuntimeDllName((CorCompileRuntimeDlls)index);
+ if (FAILED(g_pCLRRuntime->LoadLibrary(wszDllName, &hMod)))
+ {
+ EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Unable to load CLR DLL during ngen"));
+ }
+ }
+
+ _ASSERTE(hMod != NULL);
+
+ PEDecoder pe(hMod);
+
+ // Match NT header timestamp and checksum to test DLL identity
+
+ if ((info->runtimeDllInfo[index].timeStamp == pe.GetTimeDateStamp()
+ || info->runtimeDllInfo[index].timeStamp == 0)
+ && (info->runtimeDllInfo[index].virtualSize == pe.GetVirtualSize()
+ || info->runtimeDllInfo[index].virtualSize == 0))
+ {
+ continue;
+ }
+
+ {
+ // set "ComPlus_CheckNGenImageTimeStamp" to 0 to ignore time-stamp-checking
+ static ConfigDWORD checkNGenImageTimeStamp;
+ BOOL enforceCheck = checkNGenImageTimeStamp.val(CLRConfig::EXTERNAL_CheckNGenImageTimeStamp);
+
+ RuntimeVerifyLog(enforceCheck ? LL_ERROR : LL_WARNING,
+ pLogAsm,
+ W("Compiled with different CLR DLL (%s). Exact match expected."),
+ CorCompileGetRuntimeDllName((CorCompileRuntimeDlls)index));
+
+ if (enforceCheck)
+ return FALSE;
+ }
+ }
+#endif // !CROSSGEN_COMPILE && !FEATURE_CORECLR
+
+ return TRUE;
+}
+
+//===========================================================================================================
+// Validates that an NI matches the running CLR, OS, CPU, etc. This is the entrypoint used by the CLR loader.
+//
+//===========================================================================================================
+BOOL PEAssembly::CheckNativeImageVersion(PEImage *peimage)
+{
+ STANDARD_VM_CONTRACT;
+
+ //
+ // Get the zap version header. Note that modules will not have version
+ // headers - they add no additional versioning constraints from their
+ // assemblies.
+ //
+ PEImageLayoutHolder image=peimage->GetLayout(PEImageLayout::LAYOUT_ANY,PEImage::LAYOUT_CREATEIFNEEDED);
+
+ if (!image->HasNativeHeader())
+ return FALSE;
+
+ if (!image->CheckNativeHeaderVersion())
+ {
+#ifdef FEATURE_CORECLR
+ // Wrong native image version is fatal error on CoreCLR
+ ThrowHR(COR_E_NI_AND_RUNTIME_VERSION_MISMATCH);
+#else
+ return FALSE;
+#endif
+ }
+
+ CORCOMPILE_VERSION_INFO *info = image->GetNativeVersionInfo();
+ if (info == NULL)
+ return FALSE;
+
+ LoggablePEAssembly logAsm(this);
+ if (!RuntimeVerifyNativeImageVersion(info, &logAsm))
+ {
+#ifdef FEATURE_CORECLR
+ // Wrong native image version is fatal error on CoreCLR
+ ThrowHR(COR_E_NI_AND_RUNTIME_VERSION_MISMATCH);
+#else
+ return FALSE;
+#endif
+ }
+
+#ifdef FEATURE_CORECLR
+ CorCompileConfigFlags configFlags = PEFile::GetNativeImageConfigFlagsWithOverrides();
+
+ if (IsSystem())
+ {
+ // Require instrumented flags for mscorlib when collecting IBC data
+ CorCompileConfigFlags instrumentationConfigFlags = (CorCompileConfigFlags) (configFlags & CORCOMPILE_CONFIG_INSTRUMENTATION);
+ if ((info->wConfigFlags & instrumentationConfigFlags) != instrumentationConfigFlags)
+ {
+ ExternalLog(LL_ERROR, "Instrumented native image for System.Private.CoreLib.dll expected.");
+ ThrowHR(COR_E_NI_AND_RUNTIME_VERSION_MISMATCH);
+ }
+ }
+
+ // Otherwise, match regardless of the instrumentation flags
+ configFlags = (CorCompileConfigFlags) (configFlags & ~(CORCOMPILE_CONFIG_INSTRUMENTATION_NONE | CORCOMPILE_CONFIG_INSTRUMENTATION));
+
+ if ((info->wConfigFlags & configFlags) != configFlags)
+ {
+ return FALSE;
+ }
+#else
+ //
+ // Check image flavor. Skip this check in RuntimeVerifyNativeImageVersion called from fusion - fusion is responsible for choosing the right flavor.
+ //
+ if (!RuntimeVerifyNativeImageFlavor(info, &logAsm))
+ {
+ return FALSE;
+ }
+#endif
+
+ return TRUE;
+}
+
+#ifndef FEATURE_CORECLR
+//===========================================================================================================
+// Validates that an NI matches the required flavor (debug, instrumented, etc.)
+//
+//===========================================================================================================
+BOOL RuntimeVerifyNativeImageFlavor(const CORCOMPILE_VERSION_INFO *info, LoggableAssembly *pLogAsm)
+{
+ STANDARD_VM_CONTRACT;
+
+ CorCompileConfigFlags configFlags = PEFile::GetNativeImageConfigFlagsWithOverrides();
+
+ if ((info->wConfigFlags & configFlags) != configFlags)
+ return FALSE;
+
+ return TRUE;
+}
+#endif
+
+//===========================================================================================================
+// Validates that an NI matches the running CLR, OS, CPU, etc.
+//
+// For historial reasons, some versions of the runtime perform this check at native bind time (preferrred),
+// while others check at CLR load time.
+//
+// This is the common funnel for both versions and is agnostic to whether the "assembly" is represented
+// by a CLR object or Fusion object.
+//===========================================================================================================
+BOOL RuntimeVerifyNativeImageVersion(const CORCOMPILE_VERSION_INFO *info, LoggableAssembly *pLogAsm)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (!RuntimeVerifyNativeImageTimestamps(info, pLogAsm))
+ return FALSE;
+
+ //
+ // Check that the EE version numbers are the same.
+ //
+
+ if (info->wVersionMajor != VER_MAJORVERSION
+ || info->wVersionMinor != VER_MINORVERSION
+ || info->wVersionBuildNumber != VER_PRODUCTBUILD
+ || info->wVersionPrivateBuildNumber != VER_PRODUCTBUILD_QFE)
+ {
+ RuntimeVerifyLog(LL_ERROR, pLogAsm, W("CLR version recorded in native image doesn't match the current CLR."));
+ return FALSE;
+ }
+
+ //
+ // Check checked/free status
+ //
+
+ if (info->wBuild !=
+#if _DEBUG
+ CORCOMPILE_BUILD_CHECKED
+#else
+ CORCOMPILE_BUILD_FREE
+#endif
+ )
+ {
+ RuntimeVerifyLog(LL_ERROR, pLogAsm, W("Checked/free mismatch with native image."));
+ return FALSE;
+ }
+
+ //
+ // Check processor
+ //
+
+ if (info->wMachine != IMAGE_FILE_MACHINE_NATIVE_NI)
+ {
+ RuntimeVerifyLog(LL_ERROR, pLogAsm, W("Processor type recorded in native image doesn't match this machine's processor."));
+ return FALSE;
+ }
+
+#ifndef CROSSGEN_COMPILE
+ //
+ // Check the processor specific ID
+ //
+
+ CORINFO_CPU cpuInfo;
+ GetSpecificCpuInfo(&cpuInfo);
+
+ if (!IsCompatibleCpuInfo(&cpuInfo, &info->cpuInfo))
+ {
+ RuntimeVerifyLog(LL_ERROR, pLogAsm, W("Required CPU features recorded in native image don't match this machine's processor."));
+ return FALSE;
+ }
+#endif // CROSSGEN_COMPILE
+
+#if defined(_TARGET_AMD64_) && !defined(FEATURE_CORECLR)
+ //
+ // Check the right JIT compiler
+ //
+
+ bool nativeImageBuiltWithRyuJit = ((info->wCodegenFlags & CORCOMPILE_CODEGEN_USE_RYUJIT) != 0);
+ if (UseRyuJit() != nativeImageBuiltWithRyuJit)
+ {
+ RuntimeVerifyLog(LL_ERROR, pLogAsm, W("JIT compiler used to generate native image doesn't match current JIT compiler."));
+ return FALSE;
+ }
+#endif
+
+ //
+ // The zap is up to date.
+ //
+
+ RuntimeVerifyLog(LL_INFO100, pLogAsm, W("Native image has correct version information."));
+ return TRUE;
+}
+
+#endif // !DACCESS_COMPILE
+
+/* static */
+CorCompileConfigFlags PEFile::GetNativeImageConfigFlags(BOOL fForceDebug/*=FALSE*/,
+ BOOL fForceProfiling/*=FALSE*/,
+ BOOL fForceInstrument/*=FALSE*/)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ CorCompileConfigFlags result = (CorCompileConfigFlags)0;
+
+ // Debugging
+
+#ifdef DEBUGGING_SUPPORTED
+ // if these have been set, the take precedence over anything else
+ if (s_NGENDebugFlags)
+ {
+ if ((s_NGENDebugFlags & CORCOMPILE_CONFIG_DEBUG_NONE) != 0)
+ {
+ result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_DEBUG_NONE);
+ }
+ else
+ {
+ if ((s_NGENDebugFlags & CORCOMPILE_CONFIG_DEBUG) != 0)
+ {
+ result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_DEBUG);
+ }
+ }
+ }
+ else
+#endif // DEBUGGING_SUPPORTED
+ {
+ if (fForceDebug)
+ {
+ result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_DEBUG);
+ }
+ else
+ {
+ result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_DEBUG_DEFAULT);
+ }
+ }
+
+ // Profiling
+
+#ifdef PROFILING_SUPPORTED
+ if (fForceProfiling || CORProfilerUseProfileImages())
+ {
+ result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_PROFILING);
+
+ result = (CorCompileConfigFlags) (result & ~(CORCOMPILE_CONFIG_DEBUG_NONE|
+ CORCOMPILE_CONFIG_DEBUG|
+ CORCOMPILE_CONFIG_DEBUG_DEFAULT));
+ }
+ else
+#endif //PROFILING_SUPPORTED
+ result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_PROFILING_NONE);
+
+ // Instrumentation
+#ifndef DACCESS_COMPILE
+ BOOL instrumented = (!IsCompilationProcess() && g_pConfig->GetZapBBInstr());
+#else
+ BOOL instrumented = FALSE;
+#endif
+ if (instrumented || fForceInstrument)
+ {
+ result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_INSTRUMENTATION);
+ }
+ else
+ {
+ result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_INSTRUMENTATION_NONE);
+ }
+
+ // NOTE: Right now we are not taking instrumentation into account when binding.
+
+ return result;
+}
+
+CorCompileConfigFlags PEFile::GetNativeImageConfigFlagsWithOverrides()
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ BOOL fForceDebug, fForceProfiling, fForceInstrument;
+ SystemDomain::GetCompilationOverrides(&fForceDebug,
+ &fForceProfiling,
+ &fForceInstrument);
+ return PEFile::GetNativeImageConfigFlags(fForceDebug,
+ fForceProfiling,
+ fForceInstrument);
+}
+
+#ifndef DACCESS_COMPILE
+
+
+
+//===========================================================================================================
+// Validates that a hard-dep matches the a parent NI's compile-time hard-dep.
+//
+// For historial reasons, some versions of the runtime perform this check at native bind time (preferrred),
+// while others check at CLR load time.
+//
+// This is the common funnel for both versions and is agnostic to whether the "assembly" is represented
+// by a CLR object or Fusion object.
+//
+//===========================================================================================================
+BOOL RuntimeVerifyNativeImageDependency(const CORCOMPILE_NGEN_SIGNATURE &ngenSigExpected,
+ const CORCOMPILE_VERSION_INFO *pActual,
+ LoggableAssembly *pLogAsm)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (ngenSigExpected != pActual->signature)
+ {
+ // Signature did not match
+ SString displayString = pLogAsm->DisplayString();
+ RuntimeVerifyLog(LL_ERROR,
+ pLogAsm,
+ W("Rejecting native image because native image dependency %s ")
+ W("had a different identity than expected"),
+ displayString.GetUnicode());
+#if (defined FEATURE_PREJIT) && (defined FEATURE_FUSION)
+ if (pLogAsm->FusionBindLog())
+ {
+ if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, TRACE_LEVEL_INFORMATION, CLR_PRIVATEFUSION_KEYWORD))
+ {
+ pLogAsm->FusionBindLog()->ETWTraceLogMessage(ETW::BinderLog::BinderStructs::NGEN_BIND_DEPENDENCY_HAS_DIFFERENT_IDENTITY, pLogAsm->FusionAssemblyName());
+ }
+ }
+#endif
+
+ return FALSE;
+ }
+ return TRUE;
+}
+// Wrapper function for use by parts of the runtime that actually have a CORCOMPILE_DEPENDENCY to work with.
+BOOL RuntimeVerifyNativeImageDependency(const CORCOMPILE_DEPENDENCY *pExpected,
+ const CORCOMPILE_VERSION_INFO *pActual,
+ LoggableAssembly *pLogAsm)
+{
+ WRAPPER_NO_CONTRACT;
+
+ return RuntimeVerifyNativeImageDependency(pExpected->signNativeImage,
+ pActual,
+ pLogAsm);
+}
+
+#endif // !DACCESS_COMPILE
+
+#ifdef DEBUGGING_SUPPORTED
+//
+// Called through ICorDebugAppDomain2::SetDesiredNGENCompilerFlags to specify
+// which kinds of ngen'd images fusion should load wrt debugging support
+// Overrides any previous settings
+//
+void PEFile::SetNGENDebugFlags(BOOL fAllowOpt)
+{
+ CONTRACTL
+ {
+ GC_NOTRIGGER;
+ NOTHROW;
+ MODE_ANY;
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+
+ if (fAllowOpt)
+ s_NGENDebugFlags = CORCOMPILE_CONFIG_DEBUG_NONE;
+ else
+ s_NGENDebugFlags = CORCOMPILE_CONFIG_DEBUG;
+ }
+
+//
+// Called through ICorDebugAppDomain2::GetDesiredNGENCompilerFlags to determine
+// which kinds of ngen'd images fusion should load wrt debugging support
+//
+void PEFile::GetNGENDebugFlags(BOOL *fAllowOpt)
+{
+ CONTRACTL
+ {
+ GC_NOTRIGGER;
+ NOTHROW;
+ MODE_ANY;
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+
+ CorCompileConfigFlags configFlags = PEFile::GetNativeImageConfigFlagsWithOverrides();
+
+ *fAllowOpt = ((configFlags & CORCOMPILE_CONFIG_DEBUG) == 0);
+}
+#endif // DEBUGGING_SUPPORTED
+
+
+
+#ifndef DACCESS_COMPILE
+#ifdef FEATURE_TREAT_NI_AS_MSIL_DURING_DIAGNOSTICS
+
+//---------------------------------------------------------------------------------------
+//
+// Used in Apollo, this method determines whether profiling or debugging has requested
+// the runtime to provide debuggable / profileable code. In other CLR builds, this would
+// normally result in requiring the appropriate NGEN scenario be loaded (/Debug or
+// /Profile) and to JIT if unavailable. In Apollo, however, these NGEN scenarios are
+// never available, and even MSIL assemblies are often not available. So this function
+// tells its caller to use the NGENd assembly as if it were an MSIL assembly--ignore the
+// prejitted code and prebaked structures, and just JIT code and load classes from
+// scratch.
+//
+// Return Value:
+// nonzero iff NGENd images should be treated as MSIL images.
+//
+
+// static
+BOOL PEFile::ShouldTreatNIAsMSIL()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // Never use fragile native image content during ReadyToRun compilation. It would
+ // produces non-version resilient images because of wrong cached values for
+ // MethodTable::IsLayoutFixedInCurrentVersionBubble, etc.
+ if (IsReadyToRunCompilation())
+ return TRUE;
+
+ // Ask profiling API & config vars whether NGENd images should be avoided
+ // completely.
+ if (!NGENImagesAllowed())
+ return TRUE;
+
+ // Ask profiling and debugging if they're requesting us to use ngen /Debug or
+ // /Profile images (which aren't available under Apollo)
+
+ CorCompileConfigFlags configFlags = PEFile::GetNativeImageConfigFlagsWithOverrides();
+
+ if ((configFlags & (CORCOMPILE_CONFIG_DEBUG | CORCOMPILE_CONFIG_PROFILING)) != 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+#endif // FEATURE_TREAT_NI_AS_MSIL_DURING_DIAGNOSTICS
+
+#endif //!DACCESS_COMPILE
+#endif // FEATURE_PREJIT
+
+#ifndef DACCESS_COMPILE
+
+// ------------------------------------------------------------
+// Resource access
+// ------------------------------------------------------------
+
+void PEFile::GetEmbeddedResource(DWORD dwOffset, DWORD *cbResource, PBYTE *pbInMemoryResource)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(ThrowOutOfMemory(););
+ }
+ CONTRACTL_END;
+
+ // NOTE: it's not clear whether to load this from m_image or m_loadedImage.
+ // m_loadedImage is probably preferable, but this may be called by security
+ // before the image is loaded.
+
+ PEImage *image;
+
+#ifdef FEATURE_PREJIT
+ if (m_nativeImage != NULL)
+ image = m_nativeImage;
+ else
+#endif
+ {
+ EnsureImageOpened();
+ image = GetILimage();
+ }
+
+ PEImageLayoutHolder theImage(image->GetLayout(PEImageLayout::LAYOUT_ANY,PEImage::LAYOUT_CREATEIFNEEDED));
+ if (!theImage->CheckResource(dwOffset))
+ ThrowHR(COR_E_BADIMAGEFORMAT);
+
+ COUNT_T size;
+ const void *resource = theImage->GetResource(dwOffset, &size);
+
+ *cbResource = size;
+ *pbInMemoryResource = (PBYTE) resource;
+}
+
+// ------------------------------------------------------------
+// File loading
+// ------------------------------------------------------------
+
+PEAssembly *
+PEFile::LoadAssembly(
+ mdAssemblyRef kAssemblyRef,
+ IMDInternalImport * pImport, // = NULL
+ LPCUTF8 szWinRtTypeNamespace, // = NULL
+ LPCUTF8 szWinRtTypeClassName) // = NULL
+{
+ CONTRACT(PEAssembly *)
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ POSTCONDITION(CheckPointer(RETVAL));
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACT_END;
+
+ if (pImport == NULL)
+ pImport = GetPersistentMDImport();
+
+ if (((TypeFromToken(kAssemblyRef) != mdtAssembly) &&
+ (TypeFromToken(kAssemblyRef) != mdtAssemblyRef)) ||
+ (!pImport->IsValidToken(kAssemblyRef)))
+ {
+ ThrowHR(COR_E_BADIMAGEFORMAT);
+ }
+
+ AssemblySpec spec;
+
+ spec.InitializeSpec(kAssemblyRef, pImport, GetAppDomain()->FindAssembly(GetAssembly()), IsIntrospectionOnly());
+ if (szWinRtTypeClassName != NULL)
+ spec.SetWindowsRuntimeType(szWinRtTypeNamespace, szWinRtTypeClassName);
+
+ RETURN GetAppDomain()->BindAssemblySpec(&spec, TRUE, IsIntrospectionOnly());
+}
+
+// ------------------------------------------------------------
+// Logging
+// ------------------------------------------------------------
+#ifdef FEATURE_PREJIT
+void PEFile::ExternalLog(DWORD facility, DWORD level, const WCHAR *fmt, ...)
+{
+ WRAPPER_NO_CONTRACT;
+
+ va_list args;
+ va_start(args, fmt);
+
+ ExternalVLog(facility, level, fmt, args);
+
+ va_end(args);
+}
+
+void PEFile::ExternalLog(DWORD level, const WCHAR *fmt, ...)
+{
+ WRAPPER_NO_CONTRACT;
+
+ va_list args;
+ va_start(args, fmt);
+
+ ExternalVLog(LF_ZAP, level, fmt, args);
+
+ va_end(args);
+}
+
+void PEFile::ExternalLog(DWORD level, const char *msg)
+{
+ WRAPPER_NO_CONTRACT;
+
+ // It is OK to use %S here. We know that msg is ASCII-only.
+ ExternalLog(level, W("%S"), msg);
+}
+
+void PEFile::ExternalVLog(DWORD facility, DWORD level, const WCHAR *fmt, va_list args)
+{
+ CONTRACT_VOID
+ {
+ THROWS;
+ GC_TRIGGERS;
+ }
+ CONTRACT_END;
+
+ BOOL fOutputToDebugger = (level == LL_ERROR && IsDebuggerPresent());
+ BOOL fOutputToLogging = LoggingOn(facility, level);
+
+ if (!fOutputToDebugger && !fOutputToLogging)
+ return;
+
+ StackSString message;
+ message.VPrintf(fmt, args);
+
+ if (fOutputToLogging)
+ {
+ if (GetMDImport() != NULL)
+ LOG((facility, level, "%s: \"%s\"\n", (facility == LF_ZAP ? "ZAP" : "LOADER"), GetSimpleName()));
+ else
+ LOG((facility, level, "%s: \"%S\"\n", (facility == LF_ZAP ? "ZAP" : "LOADER"), ((const WCHAR *)GetPath())));
+
+ LOG((facility, level, "%S", message.GetUnicode()));
+ LOG((facility, level, "\n"));
+ }
+
+ if (fOutputToDebugger)
+ {
+ WszOutputDebugString(W("CLR:("));
+
+ StackSString codebase;
+ GetCodeBaseOrName(codebase);
+ WszOutputDebugString(codebase);
+
+ WszOutputDebugString(W(") "));
+
+ WszOutputDebugString(message);
+ WszOutputDebugString(W("\n"));
+ }
+
+ RETURN;
+}
+
+void PEFile::FlushExternalLog()
+{
+ LIMITED_METHOD_CONTRACT;
+}
+#endif
+
+BOOL PEFile::GetResource(LPCSTR szName, DWORD *cbResource,
+ PBYTE *pbInMemoryResource, DomainAssembly** pAssemblyRef,
+ LPCSTR *szFileName, DWORD *dwLocation,
+ StackCrawlMark *pStackMark, BOOL fSkipSecurityCheck,
+ BOOL fSkipRaiseResolveEvent, DomainAssembly* pDomainAssembly, AppDomain* pAppDomain)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ WRAPPER(GC_TRIGGERS);
+ }
+ CONTRACTL_END;
+
+
+ mdToken mdLinkRef;
+ DWORD dwResourceFlags;
+ DWORD dwOffset;
+ mdManifestResource mdResource;
+ Assembly* pAssembly = NULL;
+ PEFile* pPEFile = NULL;
+ ReleaseHolder<IMDInternalImport> pImport (GetMDImportWithRef());
+ if (SUCCEEDED(pImport->FindManifestResourceByName(szName, &mdResource)))
+ {
+ pPEFile = this;
+ IfFailThrow(pImport->GetManifestResourceProps(
+ mdResource,
+ NULL, //&szName,
+ &mdLinkRef,
+ &dwOffset,
+ &dwResourceFlags));
+ }
+ else
+ {
+ if (fSkipRaiseResolveEvent || pAppDomain == NULL)
+ return FALSE;
+
+ DomainAssembly* pParentAssembly = GetAppDomain()->FindAssembly(GetAssembly());
+ pAssembly = pAppDomain->RaiseResourceResolveEvent(pParentAssembly, szName);
+ if (pAssembly == NULL)
+ return FALSE;
+
+ pDomainAssembly = pAssembly->GetDomainAssembly(pAppDomain);
+ pPEFile = pDomainAssembly->GetFile();
+
+ if (FAILED(pAssembly->GetManifestImport()->FindManifestResourceByName(
+ szName,
+ &mdResource)))
+ {
+ return FALSE;
+ }
+
+ if (dwLocation != 0)
+ {
+ if (pAssemblyRef != NULL)
+ *pAssemblyRef = pDomainAssembly;
+
+ *dwLocation = *dwLocation | 2; // ResourceLocation.containedInAnotherAssembly
+ }
+ IfFailThrow(pPEFile->GetPersistentMDImport()->GetManifestResourceProps(
+ mdResource,
+ NULL, //&szName,
+ &mdLinkRef,
+ &dwOffset,
+ &dwResourceFlags));
+ }
+
+
+ switch(TypeFromToken(mdLinkRef)) {
+ case mdtAssemblyRef:
+ {
+ if (pDomainAssembly == NULL)
+ return FALSE;
+
+ AssemblySpec spec;
+ spec.InitializeSpec(mdLinkRef, GetPersistentMDImport(), pDomainAssembly, pDomainAssembly->GetFile()->IsIntrospectionOnly());
+ pDomainAssembly = spec.LoadDomainAssembly(FILE_LOADED);
+
+ if (dwLocation) {
+ if (pAssemblyRef)
+ *pAssemblyRef = pDomainAssembly;
+
+ *dwLocation = *dwLocation | 2; // ResourceLocation.containedInAnotherAssembly
+ }
+
+ return pDomainAssembly->GetResource(szName,
+ cbResource,
+ pbInMemoryResource,
+ pAssemblyRef,
+ szFileName,
+ dwLocation,
+ pStackMark,
+ fSkipSecurityCheck,
+ fSkipRaiseResolveEvent);
+ }
+
+ case mdtFile:
+ if (mdLinkRef == mdFileNil)
+ {
+ // The resource is embedded in the manifest file
+
+#ifndef CROSSGEN_COMPILE
+ if (!IsMrPublic(dwResourceFlags) && pStackMark && !fSkipSecurityCheck)
+ {
+ Assembly *pCallersAssembly = SystemDomain::GetCallersAssembly(pStackMark);
+
+ if (pCallersAssembly && // full trust for interop
+ (!pCallersAssembly->GetManifestFile()->Equals(this)))
+ {
+ RefSecContext sCtx(AccessCheckOptions::kMemberAccess);
+
+ AccessCheckOptions accessCheckOptions(
+ AccessCheckOptions::kMemberAccess, /*accessCheckType*/
+ NULL, /*pAccessContext*/
+ FALSE, /*throwIfTargetIsInaccessible*/
+ (MethodTable *) NULL /*pTargetMT*/
+ );
+
+ // SL: return TRUE only if the caller is critical
+ // Desktop: return TRUE only if demanding MemberAccess succeeds
+ if (!accessCheckOptions.DemandMemberAccessOrFail(&sCtx, NULL, TRUE /*visibilityCheck*/))
+ return FALSE;
+ }
+ }
+#endif // CROSSGEN_COMPILE
+
+ if (dwLocation) {
+ *dwLocation = *dwLocation | 5; // ResourceLocation.embedded |
+
+ // ResourceLocation.containedInManifestFile
+ return TRUE;
+ }
+
+ pPEFile->GetEmbeddedResource(dwOffset, cbResource, pbInMemoryResource);
+
+ return TRUE;
+ }
+#ifdef FEATURE_MULTIMODULE_ASSEMBLIES
+ // The resource is either linked or embedded in a non-manifest-containing file
+ if (pDomainAssembly == NULL)
+ return FALSE;
+
+ return pDomainAssembly->GetModuleResource(mdLinkRef, szName, cbResource,
+ pbInMemoryResource, szFileName,
+ dwLocation, IsMrPublic(dwResourceFlags),
+ pStackMark, fSkipSecurityCheck);
+#else
+ return FALSE;
+#endif // FEATURE_MULTIMODULE_ASSEMBLIES
+
+ default:
+ ThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN_IN_MANIFESTRES);
+ }
+}
+
+void PEFile::GetPEKindAndMachine(DWORD* pdwKind, DWORD* pdwMachine)
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (IsResource() || IsDynamic())
+ {
+ if (pdwKind)
+ *pdwKind = 0;
+ if (pdwMachine)
+ *pdwMachine = 0;
+ return;
+ }
+
+#ifdef FEATURE_PREJIT
+ if (IsNativeLoaded())
+ {
+ CONSISTENCY_CHECK(HasNativeImage());
+
+ m_nativeImage->GetNativeILPEKindAndMachine(pdwKind, pdwMachine);
+ return;
+ }
+#ifndef DACCESS_COMPILE
+ if (!HasOpenedILimage())
+ {
+ //don't want to touch the IL image unless we already have
+ ReleaseHolder<PEImage> pNativeImage = GetNativeImageWithRef();
+ if (pNativeImage)
+ {
+ pNativeImage->GetNativeILPEKindAndMachine(pdwKind, pdwMachine);
+ return;
+ }
+ }
+#endif // DACCESS_COMPILE
+#endif // FEATURE_PREJIT
+
+ GetILimage()->GetPEKindAndMachine(pdwKind, pdwMachine);
+ return;
+}
+
+ULONG PEFile::GetILImageTimeDateStamp()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+#ifdef FEATURE_PREJIT
+ if (IsNativeLoaded())
+ {
+ CONSISTENCY_CHECK(HasNativeImage());
+
+ // The IL image's time stamp is copied to the native image.
+ CORCOMPILE_VERSION_INFO* pVersionInfo = GetLoadedNative()->GetNativeVersionInfoMaybeNull();
+ if (pVersionInfo == NULL)
+ {
+ return 0;
+ }
+ else
+ {
+ return pVersionInfo->sourceAssembly.timeStamp;
+ }
+ }
+#endif // FEATURE_PREJIT
+
+ return GetLoadedIL()->GetTimeDateStamp();
+}
+
+#ifdef FEATURE_CAS_POLICY
+
+//---------------------------------------------------------------------------------------
+//
+// Get a SafePEFileHandle for this PEFile
+//
+
+SAFEHANDLE PEFile::GetSafeHandle()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ SAFEHANDLE objSafeHandle = NULL;
+
+ GCPROTECT_BEGIN(objSafeHandle);
+
+ objSafeHandle = (SAFEHANDLE)AllocateObject(MscorlibBinder::GetClass(CLASS__SAFE_PEFILE_HANDLE));
+ CallDefaultConstructor(objSafeHandle);
+
+ this->AddRef();
+ objSafeHandle->SetHandle(this);
+
+ GCPROTECT_END();
+
+ return objSafeHandle;
+}
+
+#endif // FEATURE_CAS_POLICY
+
+// ================================================================================
+// PEAssembly class - a PEFile which represents an assembly
+// ================================================================================
+
+// Statics initialization.
+/* static */
+void PEAssembly::Attach()
+{
+ STANDARD_VM_CONTRACT;
+}
+
+#ifdef FEATURE_FUSION
+PEAssembly::PEAssembly(PEImage *image,
+ IMetaDataEmit *pEmit,
+ IAssembly *pIAssembly,
+ IBindResult *pNativeFusionAssembly,
+ PEImage *pPEImageNI,
+ IFusionBindLog *pFusionLog,
+ IHostAssembly *pIHostAssembly,
+ PEFile *creator,
+ BOOL system,
+ BOOL introspectionOnly/*=FALSE*/,
+ ICLRPrivAssembly * pHostAssembly)
+ : PEFile(image, FALSE),
+ m_creator(NULL),
+ m_pFusionAssemblyName(NULL),
+ m_pFusionAssembly(NULL),
+ m_pFusionLog(NULL),
+ m_bFusionLogEnabled(TRUE),
+ m_pIHostAssembly(NULL),
+ m_pNativeAssemblyLocation(NULL),
+ m_pNativeImageClosure(NULL),
+ m_fStrongNameBypassed(FALSE)
+{
+ CONTRACTL
+ {
+ CONSTRUCTOR_CHECK;
+ PRECONDITION(CheckPointer(image, NULL_OK));
+ PRECONDITION(CheckPointer(pEmit, NULL_OK));
+ PRECONDITION(image != NULL || pEmit != NULL);
+ PRECONDITION(CheckPointer(pIAssembly, NULL_OK));
+ PRECONDITION(CheckPointer(pFusionLog, NULL_OK));
+ PRECONDITION(CheckPointer(pIHostAssembly, NULL_OK));
+ PRECONDITION(CheckPointer(creator, NULL_OK));
+ STANDARD_VM_CHECK;
+ }
+ CONTRACTL_END;
+
+ if (introspectionOnly)
+ {
+ if (!system) // Implementation restriction: mscorlib.dll cannot be loaded as introspection. The architecture depends on there being exactly one mscorlib.
+ {
+ m_flags |= PEFILE_INTROSPECTIONONLY;
+#ifdef FEATURE_PREJIT
+ SetCannotUseNativeImage();
+#endif // FEATURE_PREJIT
+ }
+ }
+
+ if (pIAssembly)
+ {
+ m_pFusionAssembly = pIAssembly;
+ pIAssembly->AddRef();
+
+ IfFailThrow(pIAssembly->GetAssemblyNameDef(&m_pFusionAssemblyName));
+ }
+ else if (pIHostAssembly)
+ {
+ m_flags |= PEFILE_ISTREAM;
+#ifdef FEATURE_PREJIT
+ m_fCanUseNativeImage = FALSE;
+#endif // FEATURE_PREJIT
+
+ m_pIHostAssembly = pIHostAssembly;
+ pIHostAssembly->AddRef();
+
+ IfFailThrow(pIHostAssembly->GetAssemblyNameDef(&m_pFusionAssemblyName));
+ }
+
+ if (pFusionLog)
+ {
+ m_pFusionLog = pFusionLog;
+ pFusionLog->AddRef();
+ }
+
+ if (creator)
+ {
+ m_creator = creator;
+ creator->AddRef();
+ }
+
+ m_flags |= PEFILE_ASSEMBLY;
+ if (system)
+ m_flags |= PEFILE_SYSTEM;
+
+#ifdef FEATURE_PREJIT
+ // Find the native image
+ if (pIAssembly)
+ {
+ if (pNativeFusionAssembly != NULL)
+ SetNativeImage(pNativeFusionAssembly);
+ }
+ // Only one of pNativeFusionAssembly and pPEImageNI may be set.
+ _ASSERTE(!(pNativeFusionAssembly && pPEImageNI));
+
+ if (pPEImageNI != NULL)
+ this->PEFile::SetNativeImage(pPEImageNI);
+#endif // FEATURE_PREJIT
+
+ // If we have no native image, we require a mapping for the file.
+ if (!HasNativeImage() || !IsILOnly())
+ EnsureImageOpened();
+
+ // Open metadata eagerly to minimize failure windows
+ if (pEmit == NULL)
+ OpenMDImport_Unsafe(); //constructor, cannot race with anything
+ else
+ {
+ _ASSERTE(!m_bHasPersistentMDImport);
+ IfFailThrow(GetMetaDataInternalInterfaceFromPublic(pEmit, IID_IMDInternalImport,
+ (void **)&m_pMDImport));
+ m_pEmitter = pEmit;
+ pEmit->AddRef();
+ m_bHasPersistentMDImport=TRUE;
+ m_MDImportIsRW_Debugger_Use_Only = TRUE;
+ }
+
+ // m_pMDImport can be external
+ // Make sure this is an assembly
+ if (!m_pMDImport->IsValidToken(TokenFromRid(1, mdtAssembly)))
+ ThrowHR(COR_E_ASSEMBLYEXPECTED);
+
+ // Make sure we perform security checks after we've obtained IMDInternalImport interface
+ DoLoadSignatureChecks();
+
+ // Verify name eagerly
+ LPCUTF8 szName = GetSimpleName();
+ if (!*szName)
+ {
+ ThrowHR(COR_E_BADIMAGEFORMAT, BFA_EMPTY_ASSEMDEF_NAME);
+ }
+
+#ifdef FEATURE_PREJIT
+ if (IsResource() || IsDynamic())
+ m_fCanUseNativeImage = FALSE;
+#endif // FEATURE_PREJIT
+
+ if (m_pFusionAssembly)
+ {
+ m_loadContext = m_pFusionAssembly->GetFusionLoadContext();
+ m_pFusionAssembly->GetAssemblyLocation(&m_dwLocationFlags);
+ }
+ else if (pHostAssembly != nullptr)
+ {
+ m_loadContext = LOADCTX_TYPE_HOSTED;
+ m_dwLocationFlags = ASMLOC_UNKNOWN;
+ m_pHostAssembly = clr::SafeAddRef(pHostAssembly); // Should use SetHostAssembly(pHostAssembly) here
+ }
+ else
+ {
+ m_loadContext = LOADCTX_TYPE_UNKNOWN;
+ m_dwLocationFlags = ASMLOC_UNKNOWN;
+ }
+
+ TESTHOOKCALL(CompletedNativeImageBind(image,szName,HasNativeImage()));
+
+#if _DEBUG
+ GetCodeBaseOrName(m_debugName);
+ m_debugName.Normalize();
+ m_pDebugName = m_debugName;
+#endif
+}
+
+#else // FEATURE_FUSION
+
+PEAssembly::PEAssembly(
+ CoreBindResult* pBindResultInfo,
+ IMetaDataEmit* pEmit,
+ PEFile *creator,
+ BOOL system,
+ BOOL introspectionOnly/*=FALSE*/,
+ PEImage * pPEImageIL /*= NULL*/,
+ PEImage * pPEImageNI /*= NULL*/,
+ ICLRPrivAssembly * pHostAssembly /*= NULL*/)
+
+ : PEFile(pBindResultInfo ? (pBindResultInfo->GetPEImage() ? pBindResultInfo->GetPEImage() :
+ (pBindResultInfo->HasNativeImage() ? pBindResultInfo->GetNativeImage() : NULL)
+ ): pPEImageIL? pPEImageIL:(pPEImageNI? pPEImageNI:NULL), FALSE),
+ m_creator(clr::SafeAddRef(creator)),
+ m_bIsFromGAC(FALSE),
+ m_bIsOnTpaList(FALSE)
+#ifdef FEATURE_CORECLR
+ ,m_fProfileAssembly(0)
+#else
+ ,m_fStrongNameBypassed(FALSE)
+#endif
+{
+ CONTRACTL
+ {
+ CONSTRUCTOR_CHECK;
+ PRECONDITION(CheckPointer(pEmit, NULL_OK));
+ PRECONDITION(CheckPointer(creator, NULL_OK));
+ PRECONDITION(pBindResultInfo == NULL || (pPEImageIL == NULL && pPEImageNI == NULL));
+ STANDARD_VM_CHECK;
+ }
+ CONTRACTL_END;
+
+ if (introspectionOnly)
+ {
+ if (!system) // Implementation restriction: mscorlib.dll cannot be loaded as introspection. The architecture depends on there being exactly one mscorlib.
+ {
+ m_flags |= PEFILE_INTROSPECTIONONLY;
+ }
+ }
+
+ m_flags |= PEFILE_ASSEMBLY;
+ if (system)
+ m_flags |= PEFILE_SYSTEM;
+
+ // We check the precondition above that either pBindResultInfo is null or both pPEImageIL and pPEImageNI are,
+ // so we'll only get a max of one native image passed in.
+ if (pPEImageNI != NULL)
+ {
+ SetNativeImage(pPEImageNI);
+ }
+
+#ifdef FEATURE_PREJIT
+ if (pBindResultInfo && pBindResultInfo->HasNativeImage())
+ SetNativeImage(pBindResultInfo->GetNativeImage());
+#endif
+
+ // If we have no native image, we require a mapping for the file.
+ if (!HasNativeImage() || !IsILOnly())
+ EnsureImageOpened();
+
+ // Initialize the status of the assembly being in the GAC, or being part of the TPA list, before
+ // we start to do work (like strong name verification) that relies on those states to be valid.
+ if(pBindResultInfo != nullptr)
+ {
+ m_bIsFromGAC = pBindResultInfo->IsFromGAC();
+ m_bIsOnTpaList = pBindResultInfo->IsOnTpaList();
+ }
+
+ // Check security related stuff
+ VerifyStrongName();
+
+ // Open metadata eagerly to minimize failure windows
+ if (pEmit == NULL)
+ OpenMDImport_Unsafe(); //constructor, cannot race with anything
+ else
+ {
+ _ASSERTE(!m_bHasPersistentMDImport);
+ IfFailThrow(GetMetaDataInternalInterfaceFromPublic(pEmit, IID_IMDInternalImport,
+ (void **)&m_pMDImport));
+ m_pEmitter = pEmit;
+ pEmit->AddRef();
+ m_bHasPersistentMDImport=TRUE;
+ m_MDImportIsRW_Debugger_Use_Only = TRUE;
+ }
+
+ // m_pMDImport can be external
+ // Make sure this is an assembly
+ if (!m_pMDImport->IsValidToken(TokenFromRid(1, mdtAssembly)))
+ ThrowHR(COR_E_ASSEMBLYEXPECTED);
+
+ // Verify name eagerly
+ LPCUTF8 szName = GetSimpleName();
+ if (!*szName)
+ {
+ ThrowHR(COR_E_BADIMAGEFORMAT, BFA_EMPTY_ASSEMDEF_NAME);
+ }
+
+ // Set the host assembly and binding context as the AssemblySpec initialization
+ // for CoreCLR will expect to have it set.
+ if (pHostAssembly != nullptr)
+ {
+ m_pHostAssembly = clr::SafeAddRef(pHostAssembly);
+ }
+
+ if(pBindResultInfo != nullptr)
+ {
+ // Cannot have both pHostAssembly and a coreclr based bind
+ _ASSERTE(pHostAssembly == nullptr);
+ pBindResultInfo->GetBindAssembly(&m_pHostAssembly);
+ }
+
+#if _DEBUG
+ GetCodeBaseOrName(m_debugName);
+ m_debugName.Normalize();
+ m_pDebugName = m_debugName;
+
+ AssemblySpec spec;
+ spec.InitializeSpec(this);
+
+ spec.GetFileOrDisplayName(ASM_DISPLAYF_VERSION |
+ ASM_DISPLAYF_CULTURE |
+ ASM_DISPLAYF_PUBLIC_KEY_TOKEN,
+ m_sTextualIdentity);
+#endif
+}
+#endif // FEATURE_FUSION
+
+
+#ifdef FEATURE_FUSION
+
+PEAssembly *PEAssembly::Open(
+ PEAssembly *pParentAssembly,
+ PEImage *pPEImageIL,
+ BOOL isIntrospectionOnly)
+{
+ STANDARD_VM_CONTRACT;
+ PEAssembly * pPEAssembly = new PEAssembly(
+ pPEImageIL, // PEImage
+ nullptr, // IMetaDataEmit
+ nullptr, // IAssembly
+ nullptr, // IBindResult pNativeFusionAssembly
+ nullptr, // PEImage *pNIImage
+ nullptr, // IFusionBindLog
+ nullptr, // IHostAssembly
+ pParentAssembly, // creator
+ FALSE, // isSystem
+ isIntrospectionOnly, // isIntrospectionOnly
+ NULL);
+
+ return pPEAssembly;
+}
+
+PEAssembly *PEAssembly::Open(
+ PEAssembly * pParent,
+ PEImage * pPEImageIL,
+ PEImage * pPEImageNI,
+ ICLRPrivAssembly * pHostAssembly,
+ BOOL fIsIntrospectionOnly)
+{
+ STANDARD_VM_CONTRACT;
+ PEAssembly * pPEAssembly = new PEAssembly(
+ pPEImageIL, // PEImage
+ nullptr, // IMetaDataEmit
+ nullptr, // IAssembly
+ nullptr, // IBindResult pNativeFusionAssembly
+ pPEImageNI, // Native Image PEImage
+ nullptr, // IFusionBindLog
+ nullptr, // IHostAssembly
+ pParent, // creator
+ FALSE, // isSystem
+ fIsIntrospectionOnly,
+ pHostAssembly);
+
+ return pPEAssembly;
+}
+
+#else //FEATURE_FUSION
+
+PEAssembly *PEAssembly::Open(
+ PEAssembly * pParent,
+ PEImage * pPEImageIL,
+ PEImage * pPEImageNI,
+ ICLRPrivAssembly * pHostAssembly,
+ BOOL fIsIntrospectionOnly)
+{
+ STANDARD_VM_CONTRACT;
+
+ PEAssembly * pPEAssembly = new PEAssembly(
+ nullptr, // BindResult
+ nullptr, // IMetaDataEmit
+ pParent, // PEFile creator
+ FALSE, // isSystem
+ fIsIntrospectionOnly,
+ pPEImageIL,
+ pPEImageNI,
+ pHostAssembly);
+
+ return pPEAssembly;
+}
+
+#endif // FEATURE_FUSION
+
+PEAssembly::~PEAssembly()
+{
+ CONTRACTL
+ {
+ DESTRUCTOR_CHECK;
+ NOTHROW;
+ GC_TRIGGERS; // Fusion uses crsts on AddRef/Release
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ GCX_PREEMP();
+#ifdef FEATURE_FUSION
+ if (m_pFusionAssemblyName != NULL)
+ m_pFusionAssemblyName->Release();
+ if (m_pFusionAssembly != NULL)
+ m_pFusionAssembly->Release();
+ if (m_pIHostAssembly != NULL)
+ m_pIHostAssembly->Release();
+ if (m_pNativeAssemblyLocation != NULL)
+ {
+ m_pNativeAssemblyLocation->Release();
+ }
+ if (m_pNativeImageClosure!=NULL)
+ m_pNativeImageClosure->Release();
+ if (m_pFusionLog != NULL)
+ m_pFusionLog->Release();
+#endif // FEATURE_FUSION
+ if (m_creator != NULL)
+ m_creator->Release();
+
+}
+
+#ifndef DACCESS_COMPILE
+void PEAssembly::ReleaseIL()
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ GCX_PREEMP();
+#ifdef FEATURE_FUSION
+ if (m_pFusionAssemblyName != NULL)
+ {
+ m_pFusionAssemblyName->Release();
+ m_pFusionAssemblyName=NULL;
+ }
+ if (m_pFusionAssembly != NULL)
+ {
+ m_pFusionAssembly->Release();
+ m_pFusionAssembly=NULL;
+ }
+ if (m_pIHostAssembly != NULL)
+ {
+ m_pIHostAssembly->Release();
+ m_pIHostAssembly=NULL;
+ }
+ if (m_pNativeAssemblyLocation != NULL)
+ {
+ m_pNativeAssemblyLocation->Release();
+ m_pNativeAssemblyLocation=NULL;
+ }
+ _ASSERTE(m_pNativeImageClosure==NULL);
+
+ if (m_pFusionLog != NULL)
+ {
+ m_pFusionLog->Release();
+ m_pFusionLog=NULL;
+ }
+#endif // FEATURE_FUSION
+ if (m_creator != NULL)
+ {
+ m_creator->Release();
+ m_creator=NULL;
+ }
+
+ PEFile::ReleaseIL();
+}
+#endif
+
+/* static */
+
+#ifdef FEATURE_FUSION
+PEAssembly *PEAssembly::OpenSystem(IApplicationContext * pAppCtx)
+#else
+PEAssembly *PEAssembly::OpenSystem(IUnknown * pAppCtx)
+#endif
+{
+ STANDARD_VM_CONTRACT;
+
+ PEAssembly *result = NULL;
+
+ EX_TRY
+ {
+ result = DoOpenSystem(pAppCtx);
+ }
+ EX_HOOK
+ {
+ Exception *ex = GET_EXCEPTION();
+
+ // Rethrow non-transient exceptions as file load exceptions with proper
+ // context
+
+ if (!ex->IsTransient())
+ EEFileLoadException::Throw(SystemDomain::System()->BaseLibrary(), ex->GetHR(), ex);
+ }
+ EX_END_HOOK;
+ return result;
+}
+
+/* static */
+#ifdef FEATURE_FUSION
+PEAssembly *PEAssembly::DoOpenSystem(IApplicationContext * pAppCtx)
+#else
+PEAssembly *PEAssembly::DoOpenSystem(IUnknown * pAppCtx)
+#endif
+{
+ CONTRACT(PEAssembly *)
+ {
+ POSTCONDITION(CheckPointer(RETVAL));
+ STANDARD_VM_CHECK;
+ }
+ CONTRACT_END;
+
+#ifdef FEATURE_FUSION
+ SafeComHolder<IAssemblyName> pName;
+ IfFailThrow(CreateAssemblyNameObject(&pName, W("mscorlib"), 0, NULL));
+
+ UINT64 publicKeyValue = I64(CONCAT_MACRO(0x, VER_ECMA_PUBLICKEY));
+ BYTE publicKeyToken[8] =
+ {
+ (BYTE) (publicKeyValue>>56),
+ (BYTE) (publicKeyValue>>48),
+ (BYTE) (publicKeyValue>>40),
+ (BYTE) (publicKeyValue>>32),
+ (BYTE) (publicKeyValue>>24),
+ (BYTE) (publicKeyValue>>16),
+ (BYTE) (publicKeyValue>>8),
+ (BYTE) (publicKeyValue),
+ };
+
+ IfFailThrow(pName->SetProperty(ASM_NAME_PUBLIC_KEY_TOKEN, publicKeyToken, sizeof(publicKeyToken)));
+
+ USHORT version = VER_ASSEMBLYMAJORVERSION;
+ IfFailThrow(pName->SetProperty(ASM_NAME_MAJOR_VERSION, &version, sizeof(version)));
+ version = VER_ASSEMBLYMINORVERSION;
+ IfFailThrow(pName->SetProperty(ASM_NAME_MINOR_VERSION, &version, sizeof(version)));
+ version = VER_ASSEMBLYBUILD;
+ IfFailThrow(pName->SetProperty(ASM_NAME_BUILD_NUMBER, &version, sizeof(version)));
+ version = VER_ASSEMBLYBUILD_QFE;
+ IfFailThrow(pName->SetProperty(ASM_NAME_REVISION_NUMBER, &version, sizeof(version)));
+
+ IfFailThrow(pName->SetProperty(ASM_NAME_CULTURE, W(""), sizeof(WCHAR)));
+
+#ifdef FEATURE_PREJIT
+#ifdef PROFILING_SUPPORTED
+ if (NGENImagesAllowed())
+ {
+ // Binding flags, zap string
+ CorCompileConfigFlags configFlags = PEFile::GetNativeImageConfigFlagsWithOverrides();
+ IfFailThrow(pName->SetProperty(ASM_NAME_CONFIG_MASK, &configFlags, sizeof(configFlags)));
+
+ LPCWSTR configString = g_pConfig->ZapSet();
+ IfFailThrow(pName->SetProperty(ASM_NAME_CUSTOM, (PVOID)configString,
+ (DWORD) (wcslen(configString)+1)*sizeof(WCHAR)));
+
+ // @TODO: Need some fuslogvw logging here
+ }
+#endif //PROFILING_SUPPORTED
+#endif // FEATURE_PREJIT
+
+ SafeComHolder<IAssembly> pIAssembly;
+ SafeComHolder<IBindResult> pNativeFusionAssembly;
+ SafeComHolder<IFusionBindLog> pFusionLog;
+
+ {
+ ETWOnStartup (FusionBinding_V1, FusionBindingEnd_V1);
+ IfFailThrow(BindToSystem(pName, SystemDomain::System()->SystemDirectory(), NULL, pAppCtx, &pIAssembly, &pNativeFusionAssembly, &pFusionLog));
+ }
+
+ StackSString path;
+ FusionBind::GetAssemblyManifestModulePath(pIAssembly, path);
+
+ // Open the image with no required mapping. This will be
+ // promoted to a real open if we don't have a native image.
+ PEImageHolder image (PEImage::OpenImage(path));
+
+ PEAssembly* pPEAssembly = new PEAssembly(image, NULL, pIAssembly,pNativeFusionAssembly, NULL, pFusionLog, NULL, NULL, TRUE, FALSE);
+
+#ifdef FEATURE_APPX_BINDER
+ if (AppX::IsAppXProcess())
+ {
+ // Since mscorlib is loaded as a special case, create and assign an ICLRPrivAssembly for the new PEAssembly here.
+ CLRPrivBinderAppX * pBinder = CLRPrivBinderAppX::GetOrCreateBinder();
+ CLRPrivBinderFusion * pFusionBinder = pBinder->GetFusionBinder();
+
+ pFusionBinder->BindMscorlib(pPEAssembly);
+ }
+#endif
+
+ RETURN pPEAssembly;
+#else // FEATURE_FUSION
+ ETWOnStartup (FusionBinding_V1, FusionBindingEnd_V1);
+ CoreBindResult bindResult;
+ ReleaseHolder<ICLRPrivAssembly> pPrivAsm;
+ IfFailThrow(CCoreCLRBinderHelper::BindToSystem(&pPrivAsm, !IsCompilationProcess() || g_fAllowNativeImages));
+ if(pPrivAsm != NULL)
+ {
+ bindResult.Init(pPrivAsm, TRUE, TRUE);
+ }
+
+ RETURN new PEAssembly(&bindResult, NULL, NULL, TRUE, FALSE);
+#endif // FEATURE_FUSION
+}
+
+#ifdef FEATURE_FUSION
+/* static */
+PEAssembly *PEAssembly::Open(IAssembly *pIAssembly,
+ IBindResult *pNativeFusionAssembly,
+ IFusionBindLog *pFusionLog/*=NULL*/,
+ BOOL isSystemAssembly/*=FALSE*/,
+ BOOL isIntrospectionOnly/*=FALSE*/)
+{
+ STANDARD_VM_CONTRACT;
+
+ PEAssembly *result = NULL;
+ EX_TRY
+ {
+ result = DoOpen(pIAssembly, pNativeFusionAssembly, pFusionLog, isSystemAssembly, isIntrospectionOnly);
+ }
+ EX_HOOK
+ {
+ Exception *ex = GET_EXCEPTION();
+
+ // Rethrow non-transient exceptions as file load exceptions with proper
+ // context
+ if (!ex->IsTransient())
+ EEFileLoadException::Throw(pIAssembly, NULL, ex->GetHR(), ex);
+ }
+ EX_END_HOOK;
+
+ return result;
+}
+
+// Thread stress
+class DoOpenIAssemblyStress : APIThreadStress
+{
+public:
+ IAssembly *pIAssembly;
+ IBindResult *pNativeFusionAssembly;
+ IFusionBindLog *pFusionLog;
+ DoOpenIAssemblyStress(IAssembly *pIAssembly, IBindResult *pNativeFusionAssembly, IFusionBindLog *pFusionLog)
+ : pIAssembly(pIAssembly), pNativeFusionAssembly(pNativeFusionAssembly),pFusionLog(pFusionLog) {LIMITED_METHOD_CONTRACT;}
+ void Invoke()
+ {
+ WRAPPER_NO_CONTRACT;
+ PEAssemblyHolder result (PEAssembly::Open(pIAssembly, pNativeFusionAssembly, pFusionLog, FALSE, FALSE));
+ }
+};
+
+/* static */
+PEAssembly *PEAssembly::DoOpen(IAssembly *pIAssembly,
+ IBindResult *pNativeFusionAssembly,
+ IFusionBindLog *pFusionLog,
+ BOOL isSystemAssembly,
+ BOOL isIntrospectionOnly/*=FALSE*/)
+{
+ CONTRACT(PEAssembly *)
+ {
+ PRECONDITION(CheckPointer(pIAssembly));
+ POSTCONDITION(CheckPointer(RETVAL));
+ STANDARD_VM_CHECK;
+ }
+ CONTRACT_END;
+
+ DoOpenIAssemblyStress ts(pIAssembly,pNativeFusionAssembly,pFusionLog);
+
+ PEImageHolder image;
+
+ StackSString path;
+ FusionBind::GetAssemblyManifestModulePath(pIAssembly, path);
+
+ // Open the image with no required mapping. This will be
+ // promoted to a real open if we don't have a native image.
+ image = PEImage::OpenImage(path, MDInternalImport_NoCache); // "identity" does not need to be cached
+
+ PEAssemblyHolder assembly (new PEAssembly(image, NULL, pIAssembly, pNativeFusionAssembly, NULL, pFusionLog,
+ NULL, NULL, isSystemAssembly, isIntrospectionOnly));
+
+ RETURN assembly.Extract();
+}
+
+/* static */
+PEAssembly *PEAssembly::Open(IHostAssembly *pIHostAssembly, BOOL isSystemAssembly, BOOL isIntrospectionOnly)
+{
+ STANDARD_VM_CONTRACT;
+
+ PEAssembly *result = NULL;
+
+ EX_TRY
+ {
+ result = DoOpen(pIHostAssembly, isSystemAssembly, isIntrospectionOnly);
+ }
+ EX_HOOK
+ {
+ Exception *ex = GET_EXCEPTION();
+
+ // Rethrow non-transient exceptions as file load exceptions with proper
+ // context
+
+ if (!ex->IsTransient())
+ EEFileLoadException::Throw(NULL, pIHostAssembly, ex->GetHR(), ex);
+ }
+ EX_END_HOOK;
+ return result;
+}
+
+// Thread stress
+class DoOpenIHostAssemblyStress : APIThreadStress
+{
+public:
+ IHostAssembly *pIHostAssembly;
+ DoOpenIHostAssemblyStress(IHostAssembly *pIHostAssembly) :
+ pIHostAssembly(pIHostAssembly) {LIMITED_METHOD_CONTRACT;}
+ void Invoke()
+ {
+ WRAPPER_NO_CONTRACT;
+ PEAssemblyHolder result (PEAssembly::Open(pIHostAssembly, FALSE, FALSE));
+ }
+};
+
+/* static */
+PEAssembly *PEAssembly::DoOpen(IHostAssembly *pIHostAssembly, BOOL isSystemAssembly,
+ BOOL isIntrospectionOnly)
+{
+ CONTRACT(PEAssembly *)
+ {
+ PRECONDITION(CheckPointer(pIHostAssembly));
+ POSTCONDITION(CheckPointer(RETVAL));
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACT_END;
+
+ DoOpenIHostAssemblyStress ts(pIHostAssembly);
+
+ UINT64 AssemblyId;
+ IfFailThrow(pIHostAssembly->GetAssemblyId(&AssemblyId));
+
+ PEImageHolder image(PEImage::FindById(AssemblyId, 0));
+
+ PEAssemblyHolder assembly (new PEAssembly(image, NULL, NULL, NULL, NULL, NULL,
+ pIHostAssembly, NULL, isSystemAssembly, isIntrospectionOnly));
+
+ RETURN assembly.Extract();
+}
+#endif // FEATURE_FUSION
+
+#ifndef CROSSGEN_COMPILE
+/* static */
+PEAssembly *PEAssembly::OpenMemory(PEAssembly *pParentAssembly,
+ const void *flat, COUNT_T size,
+ BOOL isIntrospectionOnly/*=FALSE*/,
+ CLRPrivBinderLoadFile* pBinderToUse)
+{
+ STANDARD_VM_CONTRACT;
+
+ PEAssembly *result = NULL;
+
+ EX_TRY
+ {
+ result = DoOpenMemory(pParentAssembly, flat, size, isIntrospectionOnly, pBinderToUse);
+ }
+ EX_HOOK
+ {
+ Exception *ex = GET_EXCEPTION();
+
+ // Rethrow non-transient exceptions as file load exceptions with proper
+ // context
+
+ if (!ex->IsTransient())
+ EEFileLoadException::Throw(pParentAssembly, flat, size, ex->GetHR(), ex);
+ }
+ EX_END_HOOK;
+
+ return result;
+}
+
+
+// Thread stress
+
+class DoOpenFlatStress : APIThreadStress
+{
+public:
+ PEAssembly *pParentAssembly;
+ const void *flat;
+ COUNT_T size;
+ DoOpenFlatStress(PEAssembly *pParentAssembly, const void *flat, COUNT_T size)
+ : pParentAssembly(pParentAssembly), flat(flat), size(size) {LIMITED_METHOD_CONTRACT;}
+ void Invoke()
+ {
+ WRAPPER_NO_CONTRACT;
+ PEAssemblyHolder result(PEAssembly::OpenMemory(pParentAssembly, flat, size, FALSE));
+ }
+};
+
+/* static */
+PEAssembly *PEAssembly::DoOpenMemory(
+ PEAssembly *pParentAssembly,
+ const void *flat,
+ COUNT_T size,
+ BOOL isIntrospectionOnly,
+ CLRPrivBinderLoadFile* pBinderToUse)
+{
+ CONTRACT(PEAssembly *)
+ {
+ PRECONDITION(CheckPointer(flat));
+ PRECONDITION(CheckOverflow(flat, size));
+ PRECONDITION(CheckPointer(pParentAssembly));
+ STANDARD_VM_CHECK;
+ POSTCONDITION(CheckPointer(RETVAL));
+ }
+ CONTRACT_END;
+
+ // Thread stress
+ DoOpenFlatStress ts(pParentAssembly, flat, size);
+
+ // Note that we must have a flat image stashed away for two reasons.
+ // First, we need a private copy of the data which we can verify
+ // before doing the mapping. And secondly, we can only compute
+ // the strong name hash on a flat image.
+
+ PEImageHolder image(PEImage::LoadFlat(flat, size));
+
+ // Need to verify that this is a CLR assembly
+ if (!image->CheckILFormat())
+ ThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL);
+
+#if !defined(FEATURE_CORECLR)
+ if(pBinderToUse != NULL && !isIntrospectionOnly)
+ {
+ ReleaseHolder<ICLRPrivAssembly> pAsm;
+ ReleaseHolder<IAssemblyName> pAssemblyName;
+ IfFailThrow(pBinderToUse->BindAssemblyExplicit(image, &pAssemblyName, &pAsm));
+ PEAssembly* pFile = nullptr;
+ IfFailThrow(GetAppDomain()->BindHostedPrivAssembly(pParentAssembly, pAsm, pAssemblyName, &pFile));
+ _ASSERTE(pFile);
+ RETURN pFile;
+ }
+#endif // !FEATURE_CORECLR
+
+#ifdef FEATURE_FUSION
+ RETURN new PEAssembly(image, NULL, NULL, NULL, NULL, NULL, NULL, pParentAssembly, FALSE, isIntrospectionOnly);
+#else
+ CoreBindResult bindResult;
+ ReleaseHolder<ICLRPrivAssembly> assembly;
+ IfFailThrow(CCoreCLRBinderHelper::GetAssemblyFromImage(image, NULL, &assembly));
+ bindResult.Init(assembly,FALSE,FALSE);
+
+ RETURN new PEAssembly(&bindResult, NULL, pParentAssembly, FALSE, isIntrospectionOnly);
+#endif
+}
+#endif // !CROSSGEN_COMPILE
+
+#if defined(FEATURE_MIXEDMODE) && !defined(CROSSGEN_COMPILE)
+// Use for main exe loading
+// This is also used for "spontaneous" (IJW) dll loading where
+// we need to deliver DllMain callbacks, but we should eliminate this case
+
+/* static */
+PEAssembly *PEAssembly::OpenHMODULE(HMODULE hMod,
+ IAssembly *pFusionAssembly,
+ IBindResult *pNativeFusionAssembly,
+ IFusionBindLog *pFusionLog/*=NULL*/,
+ BOOL isIntrospectionOnly/*=FALSE*/)
+{
+ STANDARD_VM_CONTRACT;
+
+ PEAssembly *result = NULL;
+
+ ETWOnStartup (OpenHModule_V1, OpenHModuleEnd_V1);
+
+ EX_TRY
+ {
+ result = DoOpenHMODULE(hMod, pFusionAssembly, pNativeFusionAssembly, pFusionLog, isIntrospectionOnly);
+ }
+ EX_HOOK
+ {
+ Exception *ex = GET_EXCEPTION();
+
+ // Rethrow non-transient exceptions as file load exceptions with proper
+ // context
+ if (!ex->IsTransient())
+ EEFileLoadException::Throw(pFusionAssembly, NULL, ex->GetHR(), ex);
+ }
+ EX_END_HOOK;
+ return result;
+}
+
+// Thread stress
+class DoOpenHMODULEStress : APIThreadStress
+{
+public:
+ HMODULE hMod;
+ IAssembly *pFusionAssembly;
+ IBindResult *pNativeFusionAssembly;
+ IFusionBindLog *pFusionLog;
+ DoOpenHMODULEStress(HMODULE hMod, IAssembly *pFusionAssembly, IBindResult *pNativeFusionAssembly, IFusionBindLog *pFusionLog)
+ : hMod(hMod), pFusionAssembly(pFusionAssembly), pNativeFusionAssembly(pNativeFusionAssembly),pFusionLog(pFusionLog) {LIMITED_METHOD_CONTRACT;}
+ void Invoke()
+ {
+ WRAPPER_NO_CONTRACT;
+ PEAssemblyHolder result(PEAssembly::OpenHMODULE(hMod, pFusionAssembly,pNativeFusionAssembly, pFusionLog, FALSE));
+ }
+};
+
+/* static */
+PEAssembly *PEAssembly::DoOpenHMODULE(HMODULE hMod,
+ IAssembly *pFusionAssembly,
+ IBindResult *pNativeFusionAssembly,
+ IFusionBindLog *pFusionLog,
+ BOOL isIntrospectionOnly/*=FALSE*/)
+{
+ CONTRACT(PEAssembly *)
+ {
+ PRECONDITION(CheckPointer(hMod));
+ PRECONDITION(CheckPointer(pFusionAssembly));
+ PRECONDITION(CheckPointer(pNativeFusionAssembly,NULL_OK));
+ POSTCONDITION(CheckPointer(RETVAL));
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACT_END;
+
+ DoOpenHMODULEStress ts(hMod, pFusionAssembly, pNativeFusionAssembly, pFusionLog);
+
+ PEImageHolder image(PEImage::LoadImage(hMod));
+
+ RETURN new PEAssembly(image, NULL, pFusionAssembly, pNativeFusionAssembly, NULL, pFusionLog, NULL, NULL, FALSE, isIntrospectionOnly);
+}
+#endif // FEATURE_MIXEDMODE && !CROSSGEN_COMPILE
+
+
+#ifndef FEATURE_FUSION
+PEAssembly* PEAssembly::Open(CoreBindResult* pBindResult,
+ BOOL isSystem, BOOL isIntrospectionOnly)
+{
+
+ return new PEAssembly(pBindResult,NULL,NULL,isSystem,isIntrospectionOnly);
+
+};
+#endif
+
+/* static */
+PEAssembly *PEAssembly::Create(PEAssembly *pParentAssembly,
+ IMetaDataAssemblyEmit *pAssemblyEmit,
+ BOOL bIsIntrospectionOnly)
+{
+ CONTRACT(PEAssembly *)
+ {
+ PRECONDITION(CheckPointer(pParentAssembly));
+ PRECONDITION(CheckPointer(pAssemblyEmit));
+ STANDARD_VM_CHECK;
+ POSTCONDITION(CheckPointer(RETVAL));
+ }
+ CONTRACT_END;
+
+ // Set up the metadata pointers in the PEAssembly. (This is the only identity
+ // we have.)
+ SafeComHolder<IMetaDataEmit> pEmit;
+ pAssemblyEmit->QueryInterface(IID_IMetaDataEmit, (void **)&pEmit);
+#ifdef FEATURE_FUSION
+ ReleaseHolder<ICLRPrivAssembly> pPrivAssembly;
+ if (pParentAssembly->HasHostAssembly())
+ {
+ // Dynamic assemblies in AppX use their parent's ICLRPrivAssembly as the binding context.
+ pPrivAssembly = clr::SafeAddRef(new CLRPrivBinderUtil::CLRPrivBinderAsAssemblyWrapper(
+ pParentAssembly->GetHostAssembly()));
+ }
+
+ PEAssemblyHolder pFile(new PEAssembly(
+ NULL, pEmit, NULL, NULL, NULL, NULL, NULL, pParentAssembly,
+ FALSE, bIsIntrospectionOnly,
+ pPrivAssembly));
+#else
+ PEAssemblyHolder pFile(new PEAssembly(NULL, pEmit, pParentAssembly, FALSE, bIsIntrospectionOnly));
+#endif
+ RETURN pFile.Extract();
+}
+
+
+#ifdef FEATURE_PREJIT
+
+#ifdef FEATURE_FUSION
+BOOL PEAssembly::HasEqualNativeClosure(DomainAssembly * pDomainAssembly)
+{
+ CONTRACTL
+ {
+ GC_TRIGGERS;
+ THROWS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pDomainAssembly));
+ }
+ CONTRACTL_END;
+ if (IsSystem())
+ return TRUE;
+ HRESULT hr = S_OK;
+
+
+ if (m_pNativeImageClosure == NULL)
+ return FALSE;
+
+ // ensure theclosures are walked
+ IAssemblyBindingClosure * pClosure = pDomainAssembly->GetAssemblyBindingClosure(LEVEL_COMPLETE);
+ _ASSERTE(pClosure != NULL);
+
+ if (m_pNativeImageClosure->HasBeenWalked(LEVEL_COMPLETE) != S_OK )
+ {
+ GCX_COOP();
+
+ ENTER_DOMAIN_PTR(SystemDomain::System()->DefaultDomain(),ADV_DEFAULTAD);
+ {
+ GCX_PREEMP();
+ IfFailThrow(m_pNativeImageClosure->EnsureWalked(GetFusionAssembly(),GetAppDomain()->GetFusionContext(),LEVEL_COMPLETE));
+ }
+ END_DOMAIN_TRANSITION;
+ }
+
+
+ hr = pClosure->IsEqual(m_pNativeImageClosure);
+ IfFailThrow(hr);
+ return (hr == S_OK);
+}
+#endif //FEATURE_FUSION
+
+#ifdef FEATURE_FUSION
+void PEAssembly::SetNativeImage(IBindResult *pNativeFusionAssembly)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ STANDARD_VM_CHECK;
+ }
+ CONTRACTL_END;
+
+ StackSString path;
+ WCHAR pwzPath[MAX_LONGPATH];
+ DWORD dwCCPath = MAX_LONGPATH;
+ ReleaseHolder<IAssemblyLocation> pIAssemblyLocation;
+
+ IfFailThrow(pNativeFusionAssembly->GetAssemblyLocation(&pIAssemblyLocation));
+ IfFailThrow(pIAssemblyLocation->GetPath(pwzPath, &dwCCPath));
+ path.Set(pwzPath);
+
+ PEImageHolder image(PEImage::OpenImage(path));
+ image->Load();
+
+ // For desktop dev11, this verification is now done at native binding time.
+ _ASSERTE(CheckNativeImageVersion(image));
+
+ PEFile::SetNativeImage(image);
+ IfFailThrow(pNativeFusionAssembly->GetAssemblyLocation(&m_pNativeAssemblyLocation));
+}
+#else //FEATURE_FUSION
+void PEAssembly::SetNativeImage(PEImage * image)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ STANDARD_VM_CHECK;
+ }
+ CONTRACTL_END;
+
+ image->Load();
+
+ if (CheckNativeImageVersion(image))
+ {
+ PEFile::SetNativeImage(image);
+#if 0
+ //Enable this code if you want to make sure we never touch the flat layout in the presence of the
+ //ngen image.
+//#if defined(_DEBUG)
+ //find all the layouts in the il image and make sure we never touch them.
+ unsigned ignored = 0;
+ PTR_PEImageLayout layout = m_ILimage->GetLayout(PEImageLayout::LAYOUT_FLAT, 0);
+ if (layout != NULL)
+ {
+ //cache a bunch of PE metadata in the PEDecoder
+ m_ILimage->CheckILFormat();
+
+ //we also need some of metadata (for the public key), so cache this too
+ DWORD verifyOutputFlags;
+ m_ILimage->VerifyStrongName(&verifyOutputFlags);
+ //fudge this by a few pages to make sure we can still mess with the PE headers
+ const size_t fudgeSize = 4096 * 4;
+ ClrVirtualProtect((void*)(((char *)layout->GetBase()) + fudgeSize),
+ layout->GetSize() - fudgeSize, 0, &ignored);
+ layout->Release();
+ }
+#endif
+ }
+ else
+ {
+ ExternalLog(LL_WARNING, "Native image is not correct version.");
+ }
+}
+#endif //FEATURE_FUSION
+
+#ifdef FEATURE_FUSION
+void PEAssembly::ClearNativeImage()
+{
+ CONTRACT_VOID
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(HasNativeImage());
+ POSTCONDITION(!HasNativeImage());
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACT_END;
+
+ PEFile::ClearNativeImage();
+
+ if (m_pNativeAssemblyLocation != NULL)
+ m_pNativeAssemblyLocation->Release();
+ m_pNativeAssemblyLocation = NULL;
+ if (m_pNativeImageClosure != NULL)
+ m_pNativeImageClosure->Release();
+ m_pNativeImageClosure = NULL;
+ RETURN;
+}
+#endif //FEATURE_FUSION
+#endif // FEATURE_PREJIT
+
+
+#ifdef FEATURE_FUSION
+BOOL PEAssembly::IsBindingCodeBase()
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+ if (m_pIHostAssembly != NULL)
+ return FALSE;
+
+ if (m_pFusionAssembly == NULL)
+ return (!GetPath().IsEmpty());
+
+ if (m_dwLocationFlags == ASMLOC_UNKNOWN)
+ return FALSE;
+
+ return ((m_dwLocationFlags & ASMLOC_CODEBASE_HINT) != 0);
+}
+
+BOOL PEAssembly::IsSourceGAC()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ if ((m_pIHostAssembly != NULL) || (m_pFusionAssembly == NULL))
+ {
+ return FALSE;
+ }
+
+ return ((m_dwLocationFlags & ASMLOC_LOCATION_MASK) == ASMLOC_GAC);
+}
+
+BOOL PEAssembly::IsSourceDownloadCache()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ if ((m_pIHostAssembly != NULL) || (m_pFusionAssembly == NULL))
+ {
+ return FALSE;
+ }
+
+ return ((m_dwLocationFlags & ASMLOC_LOCATION_MASK) == ASMLOC_DOWNLOAD_CACHE);
+}
+
+#else // FEATURE_FUSION
+BOOL PEAssembly::IsSourceGAC()
+{
+ WRAPPER_NO_CONTRACT;
+ return m_bIsFromGAC;
+};
+
+#endif // FEATURE_FUSION
+
+#endif // #ifndef DACCESS_COMPILE
+
+#ifdef FEATURE_FUSION
+BOOL PEAssembly::IsContextLoad()
+{
+ LIMITED_METHOD_CONTRACT;
+ if ((m_pIHostAssembly != NULL) || (m_pFusionAssembly == NULL))
+ {
+ return FALSE;
+ }
+ return (IsSystem() || (m_loadContext == LOADCTX_TYPE_DEFAULT));
+}
+
+LOADCTX_TYPE PEAssembly::GetLoadContext()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return m_loadContext;
+}
+
+DWORD PEAssembly::GetLocationFlags()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return m_dwLocationFlags;
+}
+
+#endif
+
+
+#ifndef DACCESS_COMPILE
+
+#ifdef FEATURE_FUSION
+PEKIND PEAssembly::GetFusionProcessorArchitecture()
+{
+ CONTRACTL
+ {
+ THROWS;
+ MODE_ANY;
+ GC_TRIGGERS;
+ }
+ CONTRACTL_END;
+
+ PEImage * pImage = NULL;
+
+#ifdef FEATURE_PREJIT
+ pImage = m_nativeImage;
+#endif
+
+ if (pImage == NULL)
+ pImage = GetILimage();
+
+ return pImage->GetFusionProcessorArchitecture();
+}
+
+IAssemblyName * PEAssembly::GetFusionAssemblyName()
+{
+ CONTRACT(IAssemblyName *)
+ {
+ INSTANCE_CHECK;
+ POSTCONDITION(CheckPointer(RETVAL));
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACT_END;
+
+ if (m_pFusionAssemblyName == NULL)
+ {
+ AssemblySpec spec;
+ spec.InitializeSpec(this);
+ PEImage * pImage = GetILimage();
+
+#ifdef FEATURE_PREJIT
+ if ((pImage != NULL) && !pImage->MDImportLoaded())
+ pImage = m_nativeImage;
+#endif
+
+ if (pImage != NULL)
+ {
+ spec.SetPEKIND(pImage->GetFusionProcessorArchitecture());
+ }
+
+ GCX_PREEMP();
+
+ IfFailThrow(spec.CreateFusionName(&m_pFusionAssemblyName, FALSE));
+ }
+
+ RETURN m_pFusionAssemblyName;
+}
+
+// This version of GetFusionAssemlyName that can be used to return the reference in a
+// NOTHROW/NOTRIGGER fashion. This is useful for scenarios where you dont want to invoke the THROWS/GCTRIGGERS
+// version when you know the name would have been created and is available.
+IAssemblyName * PEAssembly::GetFusionAssemblyNameNoCreate()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return m_pFusionAssemblyName;
+}
+
+IAssembly *PEAssembly::GetFusionAssembly()
+{
+ CONTRACT(IAssembly *)
+ {
+ INSTANCE_CHECK;
+ POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACT_END;
+
+ RETURN m_pFusionAssembly;
+}
+
+IHostAssembly *PEAssembly::GetIHostAssembly()
+{
+ CONTRACT(IHostAssembly *)
+ {
+ INSTANCE_CHECK;
+ POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACT_END;
+
+ RETURN m_pIHostAssembly;
+}
+
+IAssemblyLocation *PEAssembly::GetNativeAssemblyLocation()
+{
+ CONTRACT(IAssemblyLocation *)
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(HasNativeImage());
+ POSTCONDITION(CheckPointer(RETVAL));
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACT_END;
+
+ RETURN m_pNativeAssemblyLocation;
+}
+#endif // FEATURE_FUSION
+
+// ------------------------------------------------------------
+// Hash support
+// ------------------------------------------------------------
+
+void PEAssembly::VerifyStrongName()
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+ // If we've already done the signature checks, we don't need to do them again.
+ if (m_fStrongNameVerified)
+ {
+ return;
+ }
+
+#ifdef FEATURE_FUSION
+ // System and dynamic assemblies don't need hash checks
+ if (IsSystem() || IsDynamic())
+#else
+ // Without FUSION/GAC, we need to verify SN on all assemblies, except dynamic assemblies.
+ if (IsDynamic())
+#endif
+ {
+
+ m_flags |= PEFILE_SKIP_MODULE_HASH_CHECKS;
+ m_fStrongNameVerified = TRUE;
+ return;
+ }
+
+ // Next, verify the strong name, if necessary
+#ifdef FEATURE_FUSION
+ // See if the assembly comes from a secure location
+ IAssembly *pFusionAssembly = GetAssembly()->GetFusionAssembly();
+ if (pFusionAssembly)
+ {
+ DWORD dwLocation;
+ IfFailThrow(pFusionAssembly->GetAssemblyLocation(&dwLocation));
+
+ switch (dwLocation & ASMLOC_LOCATION_MASK)
+ {
+ case ASMLOC_GAC:
+ case ASMLOC_DOWNLOAD_CACHE:
+ case ASMLOC_DEV_OVERRIDE:
+ // Assemblies from the GAC or download cache have
+ // already been verified by Fusion.
+ m_flags |= PEFILE_SKIP_MODULE_HASH_CHECKS;
+ m_fStrongNameVerified = TRUE;
+ return;
+
+ case ASMLOC_RUN_FROM_SOURCE:
+ case ASMLOC_UNKNOWN:
+ // For now, just verify these every time, we need to
+ // cache the fact that at least one verification has
+ // been performed (if strong name policy permits
+ // caching of verification results)
+ break;
+
+ default:
+ UNREACHABLE();
+ }
+ }
+#endif
+
+ // Check format of image. Note we must delay this until after the GAC status has been
+ // checked, to handle the case where we are not loading m_image.
+ EnsureImageOpened();
+
+#if !defined(FEATURE_CORECLR) && !defined(CROSSGEN_COMPILE)
+ if (IsWindowsRuntime())
+ {
+ // Winmd files are always loaded in full trust.
+ m_flags |= PEFILE_SKIP_MODULE_HASH_CHECKS;
+ m_fStrongNameVerified = TRUE;
+ return;
+ }
+#endif
+
+#if defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
+ if (m_nativeImage == NULL && !GetILimage()->IsTrustedNativeImage())
+#else
+ if (!GetILimage()->IsTrustedNativeImage())
+#endif
+ {
+ if (!GetILimage()->CheckILFormat())
+ ThrowHR(COR_E_BADIMAGEFORMAT);
+ }
+
+#if defined(CROSSGEN_COMPILE) && !defined(FEATURE_CORECLR)
+ // Do not validate strong name signature during CrossGen. This is necessary
+ // to make build-lab scenarios to work.
+ if (IsCompilationProcess())
+ {
+ m_flags |= PEFILE_SKIP_MODULE_HASH_CHECKS;
+ }
+ else
+#endif
+ // Check the strong name if present.
+ if (IsIntrospectionOnly())
+ {
+ // For introspection assemblies, we don't need to check strong names and we don't
+ // need to do module hash checks.
+ m_flags |= PEFILE_SKIP_MODULE_HASH_CHECKS;
+ }
+#if !defined(FEATURE_CORECLR)
+ //We do this to early out for WinMD files that are unsigned but have NI images as well.
+ else if (!HasStrongNameSignature())
+ {
+#ifdef FEATURE_CAS_POLICY
+ // We only check module hashes if there is a strong name or Authenticode signature
+ if (m_certificate == NULL)
+ {
+ m_flags |= PEFILE_SKIP_MODULE_HASH_CHECKS;
+ }
+#endif
+ }
+#endif // !defined(FEATURE_CORECLR)
+ else
+ {
+#ifdef FEATURE_CORECLR
+ // Runtime policy on CoreCLR is to skip verification of ALL assemblies
+ m_flags |= PEFILE_SKIP_MODULE_HASH_CHECKS;
+ m_fStrongNameVerified = TRUE;
+#else
+ DWORD verifyOutputFlags = 0;
+ HRESULT hr = GetILimage()->VerifyStrongName(&verifyOutputFlags);
+
+ if (SUCCEEDED(hr))
+ {
+ // Strong name verified or delay sign OK'ed.
+ // We will skip verification of modules in the delay signed case.
+
+ if ((verifyOutputFlags & SN_OUTFLAG_WAS_VERIFIED) == 0)
+ m_flags |= PEFILE_SKIP_MODULE_HASH_CHECKS;
+ }
+ else
+ {
+ // Strong name missing or error. Throw in the latter case.
+ if (hr != CORSEC_E_MISSING_STRONGNAME)
+ ThrowHR(hr);
+
+#ifdef FEATURE_CAS_POLICY
+ // Since we are not strong named, don't check module hashes.
+ // (Unless we have a security certificate, in which case check anyway.)
+
+ if (m_certificate == NULL)
+ m_flags |= PEFILE_SKIP_MODULE_HASH_CHECKS;
+#endif
+ }
+
+#endif // FEATURE_CORECLR
+ }
+
+ m_fStrongNameVerified = TRUE;
+}
+
+#ifdef FEATURE_CORECLR
+BOOL PEAssembly::IsProfileAssembly()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ //
+ // For now, cache the result of the check below. This cache should be removed once/if the check below
+ // becomes cheap (e.g. does not access metadata anymore).
+ //
+ if (VolatileLoadWithoutBarrier(&m_fProfileAssembly) != 0)
+ {
+ return m_fProfileAssembly > 0;
+ }
+
+ //
+ // In order to be a platform (profile) assembly, you must be from a trusted location (TPA list)
+ // If we are binding by TPA list and this assembly is on it, IsSourceGAC is true => Assembly is Profile
+ // If the assembly is a WinMD, it is automatically trusted since all WinMD scenarios are full trust scenarios.
+ //
+ // The check for Silverlight strongname platform assemblies is legacy backdoor. It was introduced by accidental abstraction leak
+ // from the old Silverlight binder, people took advantage of it and we cannot easily get rid of it now. See DevDiv #710462.
+ //
+ BOOL bProfileAssembly = IsSourceGAC() && (IsSystem() || m_bIsOnTpaList);
+
+ m_fProfileAssembly = bProfileAssembly ? 1 : -1;
+ return bProfileAssembly;
+}
+#endif // FEATURE_CORECLR
+
+// ------------------------------------------------------------
+// Descriptive strings
+// ------------------------------------------------------------
+
+// Effective path is the path of nearest parent (creator) assembly which has a nonempty path.
+
+const SString &PEAssembly::GetEffectivePath()
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ PEAssembly *pAssembly = this;
+
+ while (pAssembly->m_identity == NULL
+ || pAssembly->m_identity->GetPath().IsEmpty())
+ {
+ if (pAssembly->m_creator)
+ pAssembly = pAssembly->m_creator->GetAssembly();
+ else // Unmanaged exe which loads byte[]/IStream assemblies
+ return SString::Empty();
+ }
+
+ return pAssembly->m_identity->GetPath();
+}
+
+
+// Codebase is the fusion codebase or path for the assembly. It is in URL format.
+// Note this may be obtained from the parent PEFile if we don't have a path or fusion
+// assembly.
+//
+// fCopiedName means to get the "shadow copied" path rather than the original path, if applicable
+void PEAssembly::GetCodeBase(SString &result, BOOL fCopiedName/*=FALSE*/)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+#ifdef FEATURE_FUSION
+ // For a copied name, we always use the actual file path rather than the fusion info
+ if (!fCopiedName && m_pFusionAssembly)
+ {
+ if ( ((m_dwLocationFlags & ASMLOC_LOCATION_MASK) == ASMLOC_RUN_FROM_SOURCE) ||
+ ((m_dwLocationFlags & ASMLOC_LOCATION_MASK) == ASMLOC_DOWNLOAD_CACHE) )
+ {
+ // Assemblies in the download cache or run from source should have
+ // a proper codebase set in them.
+ FusionBind::GetAssemblyNameStringProperty(GetFusionAssemblyName(),
+ ASM_NAME_CODEBASE_URL,
+ result);
+ return;
+ }
+ }
+ else if (m_pIHostAssembly)
+ {
+ FusionBind::GetAssemblyNameStringProperty(GetFusionAssemblyName(),
+ ASM_NAME_CODEBASE_URL,
+ result);
+ return;
+ }
+#endif
+
+ // All other cases use the file path.
+ result.Set(GetEffectivePath());
+ if (!result.IsEmpty())
+ PathToUrl(result);
+}
+
+/* static */
+void PEAssembly::PathToUrl(SString &string)
+{
+ CONTRACTL
+ {
+ PRECONDITION(PEImage::CheckCanonicalFullPath(string));
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+ SString::Iterator i = string.Begin();
+
+#if !defined(PLATFORM_UNIX)
+ if (i[0] == W('\\'))
+ {
+ // Network path
+ string.Insert(i, SL("file://"));
+ string.Skip(i, SL("file://"));
+ }
+ else
+ {
+ // Disk path
+ string.Insert(i, SL("file:///"));
+ string.Skip(i, SL("file:///"));
+ }
+#else
+ // Unix doesn't have a distinction between a network or a local path
+ _ASSERTE( i[0] == W('\\') || i[0] == W('/'));
+ SString sss(SString::Literal, W("file://"));
+ string.Insert(i, sss);
+ string.Skip(i, sss);
+#endif
+
+ while (string.Find(i, W('\\')))
+ {
+ string.Replace(i, W('/'));
+ }
+}
+
+void PEAssembly::UrlToPath(SString &string)
+{
+ CONTRACT_VOID
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ CONTRACT_END;
+
+ SString::Iterator i = string.Begin();
+
+ SString sss2(SString::Literal, W("file://"));
+#if !defined(PLATFORM_UNIX)
+ SString sss3(SString::Literal, W("file:///"));
+ if (string.MatchCaseInsensitive(i, sss3))
+ string.Delete(i, 8);
+ else
+#endif
+ if (string.MatchCaseInsensitive(i, sss2))
+ string.Delete(i, 7);
+
+ while (string.Find(i, W('/')))
+ {
+ string.Replace(i, W('\\'));
+ }
+
+ RETURN;
+}
+
+BOOL PEAssembly::FindLastPathSeparator(const SString &path, SString::Iterator &i)
+{
+#ifdef PLATFORM_UNIX
+ SString::Iterator slash = i;
+ SString::Iterator backSlash = i;
+ BOOL foundSlash = path.FindBack(slash, '/');
+ BOOL foundBackSlash = path.FindBack(backSlash, '\\');
+ if (!foundSlash && !foundBackSlash)
+ return FALSE;
+ else if (foundSlash && !foundBackSlash)
+ i = slash;
+ else if (!foundSlash && foundBackSlash)
+ i = backSlash;
+ else
+ i = (backSlash > slash) ? backSlash : slash;
+ return TRUE;
+#else
+ return path.FindBack(i, '\\');
+#endif //PLATFORM_UNIX
+}
+
+
+// ------------------------------------------------------------
+// Logging
+// ------------------------------------------------------------
+#ifdef FEATURE_PREJIT
+void PEAssembly::ExternalVLog(DWORD facility, DWORD level, const WCHAR *fmt, va_list args)
+{
+ CONTRACT_VOID
+ {
+ THROWS;
+ GC_TRIGGERS;
+ }
+ CONTRACT_END;
+
+ PEFile::ExternalVLog(facility, level, fmt, args);
+
+#ifdef FEATURE_FUSION
+ if (FusionLoggingEnabled())
+ {
+ DWORD dwLogCategory = (facility == LF_ZAP ? FUSION_BIND_LOG_CATEGORY_NGEN : FUSION_BIND_LOG_CATEGORY_DEFAULT);
+
+ StackSString message;
+ message.VPrintf(fmt, args);
+ m_pFusionLog->LogMessage(0, dwLogCategory, message);
+
+ if (level == LL_ERROR) {
+ m_pFusionLog->SetResultCode(dwLogCategory, E_FAIL);
+ FlushExternalLog();
+ }
+ }
+#endif //FEATURE_FUSION
+
+ RETURN;
+}
+
+void PEAssembly::FlushExternalLog()
+{
+ CONTRACT_VOID
+ {
+ THROWS;
+ GC_TRIGGERS;
+ }
+ CONTRACT_END;
+
+#ifdef FEATURE_FUSION
+ if (FusionLoggingEnabled()) {
+ m_pFusionLog->Flush(g_dwLogLevel, FUSION_BIND_LOG_CATEGORY_NGEN);
+ m_pFusionLog->Flush(g_dwLogLevel, FUSION_BIND_LOG_CATEGORY_DEFAULT);
+ }
+#endif //FEATURE_FUSION
+
+ RETURN;
+}
+#endif //FEATURE_PREJIT
+// ------------------------------------------------------------
+// Metadata access
+// ------------------------------------------------------------
+
+HRESULT PEFile::GetVersion(USHORT *pMajor, USHORT *pMinor, USHORT *pBuild, USHORT *pRevision)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(CheckPointer(pMajor, NULL_OK));
+ PRECONDITION(CheckPointer(pMinor, NULL_OK));
+ PRECONDITION(CheckPointer(pBuild, NULL_OK));
+ PRECONDITION(CheckPointer(pRevision, NULL_OK));
+ NOTHROW;
+ WRAPPER(GC_TRIGGERS);
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ AssemblyMetaDataInternal md;
+ HRESULT hr = S_OK;;
+ if (m_bHasPersistentMDImport)
+ {
+ _ASSERTE(GetPersistentMDImport()->IsValidToken(TokenFromRid(1, mdtAssembly)));
+ IfFailRet(GetPersistentMDImport()->GetAssemblyProps(TokenFromRid(1, mdtAssembly), NULL, NULL, NULL, NULL, &md, NULL));
+ }
+ else
+ {
+ ReleaseHolder<IMDInternalImport> pImport(GetMDImportWithRef());
+ _ASSERTE(pImport->IsValidToken(TokenFromRid(1, mdtAssembly)));
+ IfFailRet(pImport->GetAssemblyProps(TokenFromRid(1, mdtAssembly), NULL, NULL, NULL, NULL, &md, NULL));
+ }
+
+ if (pMajor != NULL)
+ *pMajor = md.usMajorVersion;
+ if (pMinor != NULL)
+ *pMinor = md.usMinorVersion;
+ if (pBuild != NULL)
+ *pBuild = md.usBuildNumber;
+ if (pRevision != NULL)
+ *pRevision = md.usRevisionNumber;
+
+ return hr;
+}
+
+#ifdef FEATURE_MULTIMODULE_ASSEMBLIES
+// ================================================================================
+// PEModule class - a PEFile which represents a satellite module
+// ================================================================================
+
+PEModule::PEModule(PEImage *image, PEAssembly *assembly, mdFile token, IMetaDataEmit *pEmit)
+ : PEFile(image),
+ m_assembly(NULL),
+ m_token(token),
+ m_bIsResource(-1)
+{
+ CONTRACTL
+ {
+ PRECONDITION(CheckPointer(image, NULL_OK));
+ PRECONDITION(CheckPointer(assembly));
+ PRECONDITION(!IsNilToken(token));
+ PRECONDITION(CheckPointer(pEmit, NULL_OK));
+ PRECONDITION(image != NULL || pEmit != NULL);
+ CONSTRUCTOR_CHECK;
+ STANDARD_VM_CHECK;
+ }
+ CONTRACTL_END;
+
+ DWORD flags;
+
+ // get only the data which is required, here - flags
+ // this helps avoid unnecessary memory touches
+ IfFailThrow(assembly->GetPersistentMDImport()->GetFileProps(token, NULL, NULL, NULL, &flags));
+
+ if (image != NULL)
+ {
+ if (IsFfContainsMetaData(flags) && !image->CheckILFormat())
+ ThrowHR(COR_E_BADIMAGEFORMAT);
+
+ if (assembly->IsIStream())
+ {
+ m_flags |= PEFILE_ISTREAM;
+#ifdef FEATURE_PREJIT
+ m_fCanUseNativeImage = FALSE;
+#endif
+ }
+ }
+
+ assembly->AddRef();
+
+ m_assembly = assembly;
+
+ m_flags |= PEFILE_MODULE;
+ if (assembly->IsSystem())
+ {
+ m_flags |= PEFILE_SYSTEM;
+ }
+ else
+ {
+ if (assembly->IsIntrospectionOnly())
+ {
+ m_flags |= PEFILE_INTROSPECTIONONLY;
+#ifdef FEATURE_PREJIT
+ SetCannotUseNativeImage();
+#endif
+ }
+ }
+
+
+ // Verify module format. Note that some things have already happened:
+ // - Fusion has verified the name matches the metadata
+ // - PEimage has performed PE file format validation
+
+ if (assembly->NeedsModuleHashChecks())
+ {
+ ULONG size;
+ const void *hash;
+ IfFailThrow(assembly->GetPersistentMDImport()->GetFileProps(token, NULL, &hash, &size, NULL));
+
+ if (!CheckHash(assembly->GetHashAlgId(), hash, size))
+ ThrowHR(COR_E_MODULE_HASH_CHECK_FAILED);
+ }
+
+#if defined(FEATURE_PREJIT) && !defined(CROSSGEN_COMPILE)
+ // Find the native image
+ if (IsFfContainsMetaData(flags)
+ && m_fCanUseNativeImage
+ && assembly->HasNativeImage()
+ && assembly->GetFusionAssembly() != NULL)
+ {
+ IAssemblyLocation *pIAssemblyLocation = assembly->GetNativeAssemblyLocation();
+
+ WCHAR wzPath[MAX_LONGPATH];
+ WCHAR *pwzTemp = NULL;
+ DWORD dwCCPath = MAX_LONGPATH;
+ SString path;
+ SString moduleName(SString::Utf8, GetSimpleName());
+
+ // Compute the module path from the manifest module path
+ IfFailThrow(pIAssemblyLocation->GetPath(wzPath, &dwCCPath));
+ pwzTemp = PathFindFileName(wzPath);
+ *pwzTemp = (WCHAR) 0x00;
+
+ // <TODO>@todo: GetAppDomain????</TODO>
+ path.Set(wzPath);
+ path.Append((LPCWSTR) moduleName);
+
+ SetNativeImage(path);
+ }
+#endif // FEATURE_PREJIT && !CROSSGEN_COMPILE
+
+#if _DEBUG
+ GetCodeBaseOrName(m_debugName);
+ m_pDebugName = m_debugName;
+#endif
+
+ if (IsFfContainsMetaData(flags))
+ {
+ if (image != NULL)
+ {
+ OpenMDImport_Unsafe(); //constructor. cannot race with anything
+ }
+ else
+ {
+ _ASSERTE(!m_bHasPersistentMDImport);
+ IfFailThrow(GetMetaDataInternalInterfaceFromPublic(pEmit, IID_IMDInternalImport,
+ (void **)&m_pMDImport));
+ m_pEmitter = pEmit;
+ pEmit->AddRef();
+ m_bHasPersistentMDImport=TRUE;
+ m_MDImportIsRW_Debugger_Use_Only = TRUE;
+ }
+
+ // Fusion probably checks this, but we need to check this ourselves if
+ // this file didn't come from Fusion
+ if (!m_pMDImport->IsValidToken(m_pMDImport->GetModuleFromScope()))
+ COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
+ }
+ else
+ {
+ // Go ahead and "load" image since it is essentially a noop, but will enable
+ // more operations on the module earlier in the loading process.
+ LoadLibrary();
+ }
+#ifdef FEATURE_PREJIT
+ if (IsResource() || IsDynamic())
+ m_fCanUseNativeImage = FALSE;
+#endif
+}
+
+PEModule::~PEModule()
+{
+ CONTRACTL
+ {
+ DESTRUCTOR_CHECK;
+ NOTHROW;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ m_assembly->Release();
+}
+
+/* static */
+PEModule *PEModule::Open(PEAssembly *assembly, mdFile token,
+ const SString &fileName)
+{
+ STANDARD_VM_CONTRACT;
+
+ PEModule *result = NULL;
+
+ EX_TRY
+ {
+ result = DoOpen(assembly, token, fileName);
+ }
+ EX_HOOK
+ {
+ Exception *ex = GET_EXCEPTION();
+
+ // Rethrow non-transient exceptions as file load exceptions with proper
+ // context
+
+ if (!ex->IsTransient())
+ EEFileLoadException::Throw(fileName, ex->GetHR(), ex);
+ }
+ EX_END_HOOK;
+
+ return result;
+}
+// Thread stress
+class DoOpenPathStress : APIThreadStress
+{
+public:
+ PEAssembly *assembly;
+ mdFile token;
+ const SString &fileName;
+ DoOpenPathStress(PEAssembly *assembly, mdFile token,
+ const SString &fileName)
+ : assembly(assembly), token(token), fileName(fileName)
+ {
+ WRAPPER_NO_CONTRACT;
+ fileName.Normalize();
+ }
+ void Invoke()
+ {
+ WRAPPER_NO_CONTRACT;
+ PEModuleHolder result(PEModule::Open(assembly, token, fileName));
+ }
+};
+
+/* static */
+PEModule *PEModule::DoOpen(PEAssembly *assembly, mdFile token,
+ const SString &fileName)
+{
+ CONTRACT(PEModule *)
+ {
+ PRECONDITION(CheckPointer(assembly));
+ PRECONDITION(CheckValue(fileName));
+ PRECONDITION(!IsNilToken(token));
+ PRECONDITION(!fileName.IsEmpty());
+ POSTCONDITION(CheckPointer(RETVAL));
+ STANDARD_VM_CHECK;
+ }
+ CONTRACT_END;
+
+ DoOpenPathStress ts(assembly, token, fileName);
+
+ // If this is a resource module, we must explicitly request a flat mapping
+ DWORD flags;
+ IfFailThrow(assembly->GetPersistentMDImport()->GetFileProps(token, NULL, NULL, NULL, &flags));
+
+ PEImageHolder image;
+#ifdef FEATURE_FUSION
+ if (assembly->IsIStream())
+ {
+ SafeComHolder<IHostAssemblyModuleImport> pModuleImport;
+ IfFailThrow(assembly->GetIHostAssembly()->GetModuleByName(fileName, &pModuleImport));
+
+ SafeComHolder<IStream> pIStream;
+ IfFailThrow(pModuleImport->GetModuleStream(&pIStream));
+
+ DWORD dwModuleId;
+ IfFailThrow(pModuleImport->GetModuleId(&dwModuleId));
+ image = PEImage::OpenImage(pIStream, assembly->m_identity->m_StreamAsmId,
+ dwModuleId, (flags & ffContainsNoMetaData));
+ }
+ else
+#endif
+ {
+ image = PEImage::OpenImage(fileName);
+ }
+
+ if (flags & ffContainsNoMetaData)
+ image->LoadNoMetaData(assembly->IsIntrospectionOnly());
+
+ PEModuleHolder module(new PEModule(image, assembly, token, NULL));
+
+ RETURN module.Extract();
+}
+
+/* static */
+PEModule *PEModule::OpenMemory(PEAssembly *assembly, mdFile token,
+ const void *flat, COUNT_T size)
+{
+ STANDARD_VM_CONTRACT;
+
+ PEModule *result = NULL;
+
+ EX_TRY
+ {
+ result = DoOpenMemory(assembly, token, flat, size);
+ }
+ EX_HOOK
+ {
+ Exception *ex = GET_EXCEPTION();
+
+ // Rethrow non-transient exceptions as file load exceptions with proper
+ // context
+ if (!ex->IsTransient())
+ EEFileLoadException::Throw(assembly, flat, size, ex->GetHR(), ex);
+ }
+ EX_END_HOOK;
+ return result;
+}
+
+// Thread stress
+class DoOpenTokenStress : APIThreadStress
+{
+public:
+ PEAssembly *assembly;
+ mdFile token;
+ const void *flat;
+ COUNT_T size;
+ DoOpenTokenStress(PEAssembly *assembly, mdFile token,
+ const void *flat, COUNT_T size)
+ : assembly(assembly), token(token), flat(flat), size(size) {LIMITED_METHOD_CONTRACT;}
+ void Invoke()
+ {
+ WRAPPER_NO_CONTRACT;
+ PEModuleHolder result(PEModule::OpenMemory(assembly, token, flat, size));
+ }
+};
+
+// REVIEW: do we need to know the creator module which emitted the module (separately
+// from the assembly parent) for security reasons?
+/* static */
+PEModule *PEModule::DoOpenMemory(PEAssembly *assembly, mdFile token,
+ const void *flat, COUNT_T size)
+{
+ CONTRACT(PEModule *)
+ {
+ PRECONDITION(CheckPointer(assembly));
+ PRECONDITION(!IsNilToken(token));
+ PRECONDITION(CheckPointer(flat));
+ POSTCONDITION(CheckPointer(RETVAL));
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACT_END;
+
+ DoOpenTokenStress ts(assembly, token, flat, size);
+
+ PEImageHolder image(PEImage::LoadFlat(flat, size));
+
+ RETURN new PEModule(image, assembly, token, NULL);
+}
+
+/* static */
+PEModule *PEModule::Create(PEAssembly *assembly, mdFile token, IMetaDataEmit *pEmit)
+{
+ CONTRACT(PEModule *)
+ {
+ PRECONDITION(CheckPointer(assembly));
+ PRECONDITION(!IsNilToken(token));
+ STANDARD_VM_CHECK;
+ POSTCONDITION(CheckPointer(RETVAL));
+ }
+ CONTRACT_END;
+
+ RETURN new PEModule(NULL, assembly, token, pEmit);
+}
+
+// ------------------------------------------------------------
+// Logging
+// ------------------------------------------------------------
+#ifdef FEATURE_PREJIT
+void PEModule::ExternalVLog(DWORD facility, DWORD level, const WCHAR *fmt, va_list args)
+{
+ CONTRACT_VOID
+ {
+ THROWS;
+ GC_TRIGGERS;
+ }
+ CONTRACT_END;
+
+ m_assembly->ExternalVLog(facility, level, fmt, args);
+
+ RETURN;
+}
+
+void PEModule::FlushExternalLog()
+{
+ CONTRACT_VOID
+ {
+ THROWS;
+ GC_TRIGGERS;
+ }
+ CONTRACT_END;
+
+ m_assembly->FlushExternalLog();
+
+ RETURN;
+}
+
+// ------------------------------------------------------------
+// Loader support routines
+// ------------------------------------------------------------
+void PEModule::SetNativeImage(const SString &fullPath)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(CheckValue(fullPath));
+ PRECONDITION(!fullPath.IsEmpty());
+ STANDARD_VM_CHECK;
+ }
+ CONTRACTL_END;
+
+ PEImageHolder image(PEImage::OpenImage(fullPath));
+ image->Load();
+
+ PEFile::SetNativeImage(image);
+}
+#endif // FEATURE_PREJIT
+
+#endif // FEATURE_MULTIMODULE_ASSEMBLIES
+
+
+void PEFile::EnsureImageOpened()
+{
+ WRAPPER_NO_CONTRACT;
+ if (IsDynamic())
+ return;
+#ifdef FEATURE_PREJIT
+ if(HasNativeImage())
+ m_nativeImage->GetLayout(PEImageLayout::LAYOUT_ANY,PEImage::LAYOUT_CREATEIFNEEDED)->Release();
+ else
+#endif
+ GetILimage()->GetLayout(PEImageLayout::LAYOUT_ANY,PEImage::LAYOUT_CREATEIFNEEDED)->Release();
+}
+
+#endif // #ifndef DACCESS_COMPILE
+
+#ifdef DACCESS_COMPILE
+
+void
+PEFile::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
+{
+ WRAPPER_NO_CONTRACT;
+ SUPPORTS_DAC;
+
+ // sizeof(PEFile) == 0xb8
+ DAC_ENUM_VTHIS();
+ EMEM_OUT(("MEM: %p PEFile\n", dac_cast<TADDR>(this)));
+
+#ifdef _DEBUG
+ // Not a big deal if it's NULL or fails.
+ m_debugName.EnumMemoryRegions(flags);
+#endif
+
+ if (m_identity.IsValid())
+ {
+ m_identity->EnumMemoryRegions(flags);
+ }
+ if (GetILimage().IsValid())
+ {
+ GetILimage()->EnumMemoryRegions(flags);
+ }
+#ifdef FEATURE_PREJIT
+ if (m_nativeImage.IsValid())
+ {
+ m_nativeImage->EnumMemoryRegions(flags);
+ DacEnumHostDPtrMem(m_nativeImage->GetLoadedLayout()->GetNativeVersionInfo());
+ }
+#endif
+}
+
+void
+PEAssembly::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
+{
+ WRAPPER_NO_CONTRACT;
+
+ PEFile::EnumMemoryRegions(flags);
+
+ if (m_creator.IsValid())
+ {
+ m_creator->EnumMemoryRegions(flags);
+ }
+}
+
+#ifdef FEATURE_MULTIMODULE_ASSEMBLIES
+void
+PEModule::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
+{
+ WRAPPER_NO_CONTRACT;
+
+ PEFile::EnumMemoryRegions(flags);
+
+ if (m_assembly.IsValid())
+ {
+ m_assembly->EnumMemoryRegions(flags);
+ }
+}
+#endif // FEATURE_MULTIMODULE_ASSEMBLIES
+#endif // #ifdef DACCESS_COMPILE
+
+
+//-------------------------------------------------------------------------------
+// Make best-case effort to obtain an image name for use in an error message.
+//
+// This routine must expect to be called before the this object is fully loaded.
+// It can return an empty if the name isn't available or the object isn't initialized
+// enough to get a name, but it mustn't crash.
+//-------------------------------------------------------------------------------
+LPCWSTR PEFile::GetPathForErrorMessages()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ INJECT_FAULT(COMPlusThrowOM(););
+ SUPPORTS_DAC_HOST_ONLY;
+ }
+ CONTRACTL_END
+
+ if (!IsDynamic())
+ {
+ return m_identity->GetPathForErrorMessages();
+ }
+ else
+ {
+ return W("");
+ }
+}
+
+#ifndef FEATURE_CORECLR
+BOOL PEAssembly::IsReportedToUsageLog()
+{
+ LIMITED_METHOD_CONTRACT;
+ BOOL fReported = TRUE;
+
+ if (!IsDynamic())
+ fReported = m_identity->IsReportedToUsageLog();
+
+ return fReported;
+}
+
+void PEAssembly::SetReportedToUsageLog()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ if (!IsDynamic())
+ m_identity->SetReportedToUsageLog();
+}
+#endif // !FEATURE_CORECLR
+
+#ifdef DACCESS_COMPILE
+TADDR PEFile::GetMDInternalRWAddress()
+{
+ if (!m_MDImportIsRW_Debugger_Use_Only)
+ return 0;
+ else
+ {
+ // This line of code is a bit scary, but it is correct for now at least...
+ // 1) We are using 'm_pMDImport_Use_Accessor' directly, and not the accessor. The field is
+ // named this way to prevent debugger code that wants a host implementation of IMDInternalImport
+ // from accidentally trying to use this pointer. This pointer is a target pointer, not
+ // a host pointer. However in this function we do want the target pointer, so the usage is
+ // accurate.
+ // 2) ASSUMPTION: We are assuming that the only valid implementation of RW metadata is
+ // MDInternalRW. If that ever changes we would need some way to disambiguate, and
+ // probably this entire code path would need to be redesigned.
+ // 3) ASSUMPTION: We are assuming that no pointer adjustment is required to convert between
+ // IMDInternalImport*, IMDInternalImportENC* and MDInternalRW*. Ideally I was hoping to do this with a
+ // static_cast<> but the compiler complains that the ENC<->RW is an unrelated conversion.
+ return (TADDR) m_pMDImport_UseAccessor;
+ }
+}
+#endif
+
+// Returns the ICLRPrivBinder* instance associated with the PEFile
+PTR_ICLRPrivBinder PEFile::GetBindingContext()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ PTR_ICLRPrivBinder pBindingContext = NULL;
+
+#if defined(FEATURE_CORECLR)
+ // Mscorlib is always bound in context of the TPA Binder. However, since it gets loaded and published
+ // during EEStartup *before* TPAbinder is initialized, we dont have a binding context to publish against.
+ // Thus, we will always return NULL for its binding context.
+ if (!IsSystem())
+#endif // defined(FEATURE_CORECLR)
+ {
+ pBindingContext = dac_cast<PTR_ICLRPrivBinder>(GetHostAssembly());
+ }
+
+ return pBindingContext;
+}