1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4// --------------------------------------------------------------------------------
5// PEFile.cpp
6//
7
8// --------------------------------------------------------------------------------
9
10
11#include "common.h"
12#include "pefile.h"
13#include "strongname.h"
14#include "eecontract.h"
15#include "apithreadstress.h"
16#include "eeconfig.h"
17#include "product_version.h"
18#include "eventtrace.h"
19#include "dbginterface.h"
20#include "peimagelayout.inl"
21#include "dlwrap.h"
22#include "invokeutil.h"
23#ifdef FEATURE_PREJIT
24#include "compile.h"
25#endif
26#include "strongnameinternal.h"
27
28#include "../binder/inc/applicationcontext.hpp"
29
30#include "clrprivbinderutil.h"
31#include "../binder/inc/coreclrbindercommon.h"
32
33
34#ifdef FEATURE_PREJIT
35#include "compile.h"
36
37#ifdef DEBUGGING_SUPPORTED
38SVAL_IMPL_INIT(DWORD, PEFile, s_NGENDebugFlags, 0);
39#endif
40#endif
41
42#include "sha1.h"
43
44
45#ifndef DACCESS_COMPILE
46
47// ================================================================================
48// PEFile class - this is an abstract base class for PEModule and PEAssembly
49// <TODO>@todo: rename TargetFile</TODO>
50// ================================================================================
51
52PEFile::PEFile(PEImage *identity, BOOL fCheckAuthenticodeSignature/*=TRUE*/) :
53#if _DEBUG
54 m_pDebugName(NULL),
55#endif
56 m_identity(NULL),
57 m_openedILimage(NULL),
58#ifdef FEATURE_PREJIT
59 m_nativeImage(NULL),
60 m_fCanUseNativeImage(TRUE),
61#endif
62 m_MDImportIsRW_Debugger_Use_Only(FALSE),
63 m_bHasPersistentMDImport(FALSE),
64 m_pMDImport(NULL),
65 m_pImporter(NULL),
66 m_pEmitter(NULL),
67 m_pMetadataLock(::new SimpleRWLock(PREEMPTIVE, LOCK_TYPE_DEFAULT)),
68 m_refCount(1),
69 m_flags(0),
70 m_pHostAssembly(nullptr),
71 m_pFallbackLoadContextBinder(nullptr)
72{
73 CONTRACTL
74 {
75 CONSTRUCTOR_CHECK;
76 THROWS;
77 GC_TRIGGERS;
78 MODE_ANY;
79 }
80 CONTRACTL_END;
81
82 if (identity)
83 {
84 identity->AddRef();
85 m_identity = identity;
86
87 if(identity->IsOpened())
88 {
89 //already opened, prepopulate
90 identity->AddRef();
91 m_openedILimage = identity;
92 }
93 }
94
95
96}
97
98
99
100PEFile::~PEFile()
101{
102 CONTRACTL
103 {
104 DESTRUCTOR_CHECK;
105 NOTHROW;
106 GC_TRIGGERS;
107 MODE_ANY;
108 }
109 CONTRACTL_END;
110
111 ReleaseMetadataInterfaces(TRUE);
112
113#ifdef FEATURE_PREJIT
114 if (m_nativeImage != NULL)
115 {
116 MarkNativeImageInvalidIfOwned();
117
118 m_nativeImage->Release();
119 }
120#endif //FEATURE_PREJIT
121
122
123 if (m_openedILimage != NULL)
124 m_openedILimage->Release();
125 if (m_identity != NULL)
126 m_identity->Release();
127 if (m_pMetadataLock)
128 delete m_pMetadataLock;
129
130 if (m_pHostAssembly != NULL)
131 {
132 m_pHostAssembly->Release();
133 }
134}
135
136#ifndef DACCESS_COMPILE
137void PEFile::ReleaseIL()
138{
139 WRAPPER_NO_CONTRACT;
140 if (m_openedILimage!=NULL )
141 {
142 ReleaseMetadataInterfaces(TRUE, TRUE);
143 if (m_identity != NULL)
144 {
145 m_identity->Release();
146 m_identity=NULL;
147 }
148 m_openedILimage->Release();
149 m_openedILimage = NULL;
150 }
151}
152#endif
153
154/* static */
155PEFile *PEFile::Open(PEImage *image)
156{
157 CONTRACT(PEFile *)
158 {
159 PRECONDITION(image != NULL);
160 PRECONDITION(image->CheckFormat());
161 POSTCONDITION(RETVAL != NULL);
162 POSTCONDITION(!RETVAL->IsModule());
163 POSTCONDITION(!RETVAL->IsAssembly());
164 THROWS;
165 GC_TRIGGERS;
166 MODE_ANY;
167 INJECT_FAULT(COMPlusThrowOM(););
168 }
169 CONTRACT_END;
170
171 PEFile *pFile = new PEFile(image, FALSE);
172
173 if (image->HasNTHeaders() && image->HasCorHeader())
174 pFile->OpenMDImport_Unsafe(); //no one else can see the object yet
175
176#if _DEBUG
177 pFile->m_debugName = image->GetPath();
178 pFile->m_debugName.Normalize();
179 pFile->m_pDebugName = pFile->m_debugName;
180#endif
181
182 RETURN pFile;
183}
184
185// ------------------------------------------------------------
186// Loader support routines
187// ------------------------------------------------------------
188
189template<class T> void CoTaskFree(T *p)
190{
191 if (p != NULL)
192 {
193 p->T::~T();
194
195 CoTaskMemFree(p);
196 }
197}
198
199
200NEW_WRAPPER_TEMPLATE1(CoTaskNewHolder, CoTaskFree<_TYPE>);
201
202
203//-----------------------------------------------------------------------------------------------------
204// Catch attempts to load x64 assemblies on x86, etc.
205//-----------------------------------------------------------------------------------------------------
206static void ValidatePEFileMachineType(PEFile *peFile)
207{
208 STANDARD_VM_CONTRACT;
209
210 if (peFile->IsDynamic())
211 return; // PEFiles for ReflectionEmit assemblies don't cache the machine type.
212
213 if (peFile->IsResource())
214 return; // PEFiles for resource assemblies don't cache the machine type.
215
216 if (peFile->HasNativeImage())
217 return; // If it passed the native binder, no need to do the check again esp. at the risk of inviting an IL page-in.
218
219 DWORD peKind;
220 DWORD actualMachineType;
221 peFile->GetPEKindAndMachine(&peKind, &actualMachineType);
222
223 if (actualMachineType == IMAGE_FILE_MACHINE_I386 && ((peKind & (peILonly | pe32BitRequired)) == peILonly))
224 return; // Image is marked CPU-agnostic.
225
226 if (actualMachineType != IMAGE_FILE_MACHINE_NATIVE && actualMachineType != IMAGE_FILE_MACHINE_NATIVE_NI)
227 {
228#ifdef _TARGET_AMD64_
229 // 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
230 // 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.
231 //
232 // 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.
233 // Or to put it another way, this #ifdef makes the (4.5 only) ValidatePEFileMachineType() a NOP for x64, hence preserving 4.0 compatibility.
234 if (actualMachineType == IMAGE_FILE_MACHINE_I386 || actualMachineType == IMAGE_FILE_MACHINE_IA64)
235 return;
236#endif // _WIN64_
237
238 // Image has required machine that doesn't match the CLR.
239 StackSString name;
240 if (peFile->IsAssembly())
241 ((PEAssembly*)peFile)->GetDisplayName(name);
242 else
243 name = StackSString(SString::Utf8, peFile->GetSimpleName());
244
245 COMPlusThrow(kBadImageFormatException, IDS_CLASSLOAD_WRONGCPU, name.GetUnicode());
246 }
247
248 return; // If we got here, all is good.
249}
250
251void PEFile::LoadLibrary(BOOL allowNativeSkip/*=TRUE*/) // if allowNativeSkip==FALSE force IL image load
252{
253 CONTRACT_VOID
254 {
255 INSTANCE_CHECK;
256 POSTCONDITION(CheckLoaded());
257 STANDARD_VM_CHECK;
258 }
259 CONTRACT_END;
260
261 // Catch attempts to load x64 assemblies on x86, etc.
262 ValidatePEFileMachineType(this);
263
264 // See if we've already loaded it.
265 if (CheckLoaded(allowNativeSkip))
266 {
267 RETURN;
268 }
269
270 // Note that we may be racing other threads here, in the case of domain neutral files
271
272 // Resource images are always flat.
273 if (IsResource())
274 {
275 GetILimage()->LoadNoMetaData();
276 RETURN;
277 }
278
279#if !defined(_TARGET_64BIT_)
280 if (!HasNativeImage() && !GetILimage()->Has32BitNTHeaders())
281 {
282 // Tried to load 64-bit assembly on 32-bit platform.
283 EEFileLoadException::Throw(this, COR_E_BADIMAGEFORMAT, NULL);
284 }
285#endif
286
287 // We need contents now
288 if (!HasNativeImage())
289 {
290 EnsureImageOpened();
291 }
292
293#ifdef FEATURE_PREJIT
294 // For on-disk Dlls, we can call LoadLibrary
295 if (IsDll() && !((HasNativeImage()?m_nativeImage:GetILimage())->GetPath().IsEmpty()))
296 {
297 // Note that we may get a DllMain notification inside here.
298 if (allowNativeSkip && HasNativeImage())
299 {
300 m_nativeImage->Load();
301 if(!m_nativeImage->IsNativeILILOnly())
302 GetILimage()->Load(); // For IJW we have to load IL also...
303 }
304 else
305 GetILimage()->Load();
306 }
307 else
308#endif // FEATURE_PREJIT
309 {
310
311 // Since we couldn't call LoadLibrary, we must be an IL only image
312 // or the image may still contain unfixed up stuff
313 // Note that we make an exception for CompilationDomains, since PEImage
314 // will map non-ILOnly images in a compilation domain.
315 if (!GetILimage()->IsILOnly() && !GetAppDomain()->IsCompilationDomain())
316 {
317 if (!GetILimage()->HasV1Metadata())
318 ThrowHR(COR_E_FIXUPSINEXE); // <TODO>@todo: better error</TODO>
319 }
320
321
322
323 // If we are already mapped, we can just use the current image.
324#ifdef FEATURE_PREJIT
325 if (allowNativeSkip && HasNativeImage())
326 {
327 m_nativeImage->LoadFromMapped();
328
329 if( !m_nativeImage->IsNativeILILOnly())
330 GetILimage()->LoadFromMapped(); // For IJW we have to load IL also...
331 }
332 else
333#endif
334 {
335 if (GetILimage()->IsFile())
336 {
337#ifdef PLATFORM_UNIX
338 if (GetILimage()->IsILOnly())
339 {
340 GetILimage()->Load();
341 }
342 else
343#endif // PLATFORM_UNIX
344 {
345 GetILimage()->LoadFromMapped();
346 }
347 }
348 else
349 {
350 GetILimage()->LoadNoFile();
351 }
352 }
353 }
354
355
356 RETURN;
357}
358
359void PEFile::SetLoadedHMODULE(HMODULE hMod)
360{
361 CONTRACT_VOID
362 {
363 INSTANCE_CHECK;
364 PRECONDITION(CheckPointer(hMod));
365 POSTCONDITION(CheckLoaded());
366 THROWS;
367 GC_TRIGGERS;
368 MODE_ANY;
369 INJECT_FAULT(COMPlusThrowOM(););
370 }
371 CONTRACT_END;
372
373 // See if the image is an internal PEImage.
374 GetILimage()->SetLoadedHMODULE(hMod);
375
376 RETURN;
377}
378
379/* static */
380void PEFile::DefineEmitScope(
381 GUID iid,
382 void **ppEmit)
383{
384 CONTRACT_VOID
385 {
386 PRECONDITION(CheckPointer(ppEmit));
387 POSTCONDITION(CheckPointer(*ppEmit));
388 THROWS;
389 GC_TRIGGERS;
390 MODE_ANY;
391 INJECT_FAULT(COMPlusThrowOM(););
392 }
393 CONTRACT_END;
394
395 SafeComHolder<IMetaDataDispenserEx> pDispenser;
396
397 // Get the Dispenser interface.
398 MetaDataGetDispenser(
399 CLSID_CorMetaDataDispenser,
400 IID_IMetaDataDispenserEx,
401 (void **)&pDispenser);
402 if (pDispenser == NULL)
403 {
404 ThrowOutOfMemory();
405 }
406
407 // Set the option on the dispenser turn on duplicate check for TypeDef and moduleRef
408 VARIANT varOption;
409 V_VT(&varOption) = VT_UI4;
410 V_I4(&varOption) = MDDupDefault | MDDupTypeDef | MDDupModuleRef | MDDupExportedType | MDDupAssemblyRef | MDDupPermission | MDDupFile;
411 IfFailThrow(pDispenser->SetOption(MetaDataCheckDuplicatesFor, &varOption));
412
413 // Set minimal MetaData size
414 V_VT(&varOption) = VT_UI4;
415 V_I4(&varOption) = MDInitialSizeMinimal;
416 IfFailThrow(pDispenser->SetOption(MetaDataInitialSize, &varOption));
417
418 // turn on the thread safety!
419 V_I4(&varOption) = MDThreadSafetyOn;
420 IfFailThrow(pDispenser->SetOption(MetaDataThreadSafetyOptions, &varOption));
421
422 IfFailThrow(pDispenser->DefineScope(CLSID_CorMetaDataRuntime, 0, iid, (IUnknown **)ppEmit));
423
424 RETURN;
425} // PEFile::DefineEmitScope
426
427// ------------------------------------------------------------
428// Identity
429// ------------------------------------------------------------
430
431BOOL PEFile::Equals(PEFile *pFile)
432{
433 CONTRACTL
434 {
435 INSTANCE_CHECK;
436 PRECONDITION(CheckPointer(pFile));
437 GC_NOTRIGGER;
438 NOTHROW;
439 CANNOT_TAKE_LOCK;
440 MODE_ANY;
441 }
442 CONTRACTL_END;
443
444 // Same object is equal
445 if (pFile == this)
446 return TRUE;
447
448 // Different host assemblies cannot be equal unless they are associated with the same host binder
449 // It's ok if only one has a host binder because multiple threads can race to load the same assembly
450 // and that may cause temporary candidate PEAssembly objects that never get bound to a host assembly
451 // because another thread beats it; the losing thread will pick up the PEAssembly in the cache.
452 if (pFile->HasHostAssembly() && this->HasHostAssembly())
453 {
454 UINT_PTR fileBinderId = 0;
455 if (FAILED(pFile->GetHostAssembly()->GetBinderID(&fileBinderId)))
456 return FALSE;
457
458 UINT_PTR thisBinderId = 0;
459 if (FAILED(this->GetHostAssembly()->GetBinderID(&thisBinderId)))
460 return FALSE;
461
462 if (fileBinderId != thisBinderId)
463 return FALSE;
464
465 }
466
467 // Same identity is equal
468 if (m_identity != NULL && pFile->m_identity != NULL
469 && m_identity->Equals(pFile->m_identity))
470 return TRUE;
471
472 // Same image is equal
473 if (m_openedILimage != NULL && pFile->m_openedILimage != NULL
474 && m_openedILimage->Equals(pFile->m_openedILimage))
475 return TRUE;
476
477 return FALSE;
478}
479
480BOOL PEFile::Equals(PEImage *pImage)
481{
482 CONTRACTL
483 {
484 INSTANCE_CHECK;
485 PRECONDITION(CheckPointer(pImage));
486 GC_NOTRIGGER;
487 NOTHROW;
488 MODE_ANY;
489 }
490 CONTRACTL_END;
491
492 // Same object is equal
493 if (pImage == m_identity || pImage == m_openedILimage)
494 return TRUE;
495
496#ifdef FEATURE_PREJIT
497 if(pImage == m_nativeImage)
498 return TRUE;
499#endif
500 // Same identity is equal
501 if (m_identity != NULL
502 && m_identity->Equals(pImage))
503 return TRUE;
504
505 // Same image is equal
506 if (m_openedILimage != NULL
507 && m_openedILimage->Equals(pImage))
508 return TRUE;
509
510
511 return FALSE;
512}
513
514// ------------------------------------------------------------
515// Descriptive strings
516// ------------------------------------------------------------
517
518void PEFile::GetCodeBaseOrName(SString &result)
519{
520 CONTRACTL
521 {
522 INSTANCE_CHECK;
523 THROWS;
524 GC_TRIGGERS;
525 MODE_ANY;
526 INJECT_FAULT(COMPlusThrowOM(););
527 }
528 CONTRACTL_END;
529
530 if (m_identity != NULL && !m_identity->GetPath().IsEmpty())
531 {
532 result.Set(m_identity->GetPath());
533 }
534 else if (IsAssembly())
535 {
536 ((PEAssembly*)this)->GetCodeBase(result);
537 }
538 else
539 result.SetUTF8(GetSimpleName());
540}
541
542
543// ------------------------------------------------------------
544// Checks
545// ------------------------------------------------------------
546
547
548
549CHECK PEFile::CheckLoaded(BOOL bAllowNativeSkip/*=TRUE*/)
550{
551 CONTRACT_CHECK
552 {
553 INSTANCE_CHECK;
554 NOTHROW;
555 GC_NOTRIGGER;
556 SO_TOLERANT;
557 MODE_ANY;
558 }
559 CONTRACT_CHECK_END;
560
561 CHECK(IsLoaded(bAllowNativeSkip)
562 // We are allowed to skip LoadLibrary in most cases for ngen'ed IL only images
563 || (bAllowNativeSkip && HasNativeImage() && IsILOnly()));
564
565 CHECK_OK;
566}
567
568
569// ------------------------------------------------------------
570// Metadata access
571// ------------------------------------------------------------
572
573PTR_CVOID PEFile::GetMetadata(COUNT_T *pSize)
574{
575 CONTRACT(PTR_CVOID)
576 {
577 INSTANCE_CHECK;
578 POSTCONDITION(CheckPointer(pSize, NULL_OK));
579 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
580 THROWS;
581 GC_TRIGGERS;
582 MODE_ANY;
583 SUPPORTS_DAC;
584 }
585 CONTRACT_END;
586
587#ifdef FEATURE_PREJIT
588 if (HasNativeImageMetadata())
589 {
590 RETURN m_nativeImage->GetMetadata(pSize);
591 }
592#endif
593
594 if (IsDynamic()
595 || !GetILimage()->HasNTHeaders()
596 || !GetILimage()->HasCorHeader())
597 {
598 if (pSize != NULL)
599 *pSize = 0;
600 RETURN NULL;
601 }
602 else
603 {
604 RETURN GetILimage()->GetMetadata(pSize);
605 }
606}
607#endif // #ifndef DACCESS_COMPILE
608
609PTR_CVOID PEFile::GetLoadedMetadata(COUNT_T *pSize)
610{
611 CONTRACT(PTR_CVOID)
612 {
613 INSTANCE_CHECK;
614 POSTCONDITION(CheckPointer(pSize, NULL_OK));
615 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
616 NOTHROW;
617 GC_NOTRIGGER;
618 MODE_ANY;
619 SUPPORTS_DAC;
620 }
621 CONTRACT_END;
622
623#ifdef FEATURE_PREJIT
624 if (HasNativeImageMetadata())
625 {
626 RETURN GetLoadedNative()->GetMetadata(pSize);
627 }
628#endif
629
630 if (!HasLoadedIL()
631 || !GetLoadedIL()->HasNTHeaders()
632 || !GetLoadedIL()->HasCorHeader())
633 {
634 if (pSize != NULL)
635 *pSize = 0;
636 RETURN NULL;
637 }
638 else
639 {
640 RETURN GetLoadedIL()->GetMetadata(pSize);
641 }
642}
643
644TADDR PEFile::GetIL(RVA il)
645{
646 CONTRACT(TADDR)
647 {
648 INSTANCE_CHECK;
649 PRECONDITION(il != 0);
650 PRECONDITION(!IsDynamic());
651 PRECONDITION(!IsResource());
652#ifndef DACCESS_COMPILE
653 PRECONDITION(CheckLoaded());
654#endif
655 POSTCONDITION(RETVAL != NULL);
656 THROWS;
657 GC_NOTRIGGER;
658 MODE_ANY;
659 SUPPORTS_DAC;
660 }
661 CONTRACT_END;
662
663 PEImageLayout *image = NULL;
664
665#ifdef FEATURE_PREJIT
666 // Note it is important to get the IL from the native image if
667 // available, since we are using the metadata from the native image
668 // which has different IL rva's.
669 if (HasNativeImageMetadata())
670 {
671 image = GetLoadedNative();
672
673#ifndef DACCESS_COMPILE
674 // NGen images are trusted to be well-formed.
675 _ASSERTE(image->CheckILMethod(il));
676#endif
677 }
678 else
679#endif // FEATURE_PREJIT
680 {
681 image = GetLoadedIL();
682
683#ifndef DACCESS_COMPILE
684 // Verify that the IL blob is valid before giving it out
685 if (!image->CheckILMethod(il))
686 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL_RANGE);
687#endif
688 }
689
690 RETURN image->GetRvaData(il);
691}
692
693#ifndef DACCESS_COMPILE
694
695void PEFile::OpenImporter()
696{
697 CONTRACTL
698 {
699 INSTANCE_CHECK;
700 THROWS;
701 GC_NOTRIGGER;
702 MODE_ANY;
703 INJECT_FAULT(COMPlusThrowOM(););
704 }
705 CONTRACTL_END;
706
707 // Make sure internal MD is in RW format.
708 ConvertMDInternalToReadWrite();
709
710 IMetaDataImport2 *pIMDImport = NULL;
711 IfFailThrow(GetMetaDataPublicInterfaceFromInternal((void*)GetPersistentMDImport(),
712 IID_IMetaDataImport2,
713 (void **)&pIMDImport));
714
715 // Atomically swap it into the field (release it if we lose the race)
716 if (FastInterlockCompareExchangePointer(&m_pImporter, pIMDImport, NULL) != NULL)
717 pIMDImport->Release();
718}
719
720void PEFile::ConvertMDInternalToReadWrite()
721{
722 CONTRACTL
723 {
724 INSTANCE_CHECK;
725 THROWS;
726 GC_NOTRIGGER;
727 MODE_ANY;
728 INJECT_FAULT(EX_THROW(EEMessageException, (E_OUTOFMEMORY)););
729 }
730 CONTRACTL_END;
731
732 IMDInternalImport *pOld; // Old (current RO) value of internal import.
733 IMDInternalImport *pNew = NULL; // New (RW) value of internal import.
734
735 // Take a local copy of *ppImport. This may be a pointer to an RO
736 // or to an RW MDInternalXX.
737 pOld = m_pMDImport;
738 IMetaDataImport *pIMDImport = m_pImporter;
739 if (pIMDImport != NULL)
740 {
741 HRESULT hr = GetMetaDataInternalInterfaceFromPublic(pIMDImport, IID_IMDInternalImport, (void **)&pNew);
742 if (FAILED(hr))
743 {
744 EX_THROW(EEMessageException, (hr));
745 }
746 if (pNew == pOld)
747 {
748 pNew->Release();
749 return;
750 }
751 }
752 else
753 {
754 // If an RO, convert to an RW, return S_OK. If already RW, no conversion
755 // needed, return S_FALSE.
756 HRESULT hr = ConvertMDInternalImport(pOld, &pNew);
757
758 if (FAILED(hr))
759 {
760 EX_THROW(EEMessageException, (hr));
761 }
762
763 // If no conversion took place, don't change pointers.
764 if (hr == S_FALSE)
765 return;
766 }
767
768 // Swap the pointers in a thread safe manner. If the contents of *ppImport
769 // equals pOld then no other thread got here first, and the old contents are
770 // replaced with pNew. The old contents are returned.
771 _ASSERTE(m_bHasPersistentMDImport);
772 if (FastInterlockCompareExchangePointer(&m_pMDImport, pNew, pOld) == pOld)
773 {
774 //if the debugger queries, it will now see that we have RW metadata
775 m_MDImportIsRW_Debugger_Use_Only = TRUE;
776
777 // Swapped -- get the metadata to hang onto the old Internal import.
778 HRESULT hr=m_pMDImport->SetUserContextData(pOld);
779 _ASSERTE(SUCCEEDED(hr)||!"Leaking old MDImport");
780 IfFailThrow(hr);
781 }
782 else
783 { // Some other thread finished first. Just free the results of this conversion.
784 pNew->Release();
785 }
786}
787
788void PEFile::ConvertMetadataToRWForEnC()
789{
790 CONTRACTL
791 {
792 THROWS;
793 GC_NOTRIGGER;
794 SO_INTOLERANT;
795 MODE_ANY;
796 }
797 CONTRACTL_END;
798
799 // This should only ever be called on EnC capable files.
800 // One can check this using Module::IsEditAndContinueCapable().
801
802 // This should only be called if we're debugging, stopped, and on the helper thread.
803 _ASSERTE(CORDebuggerAttached());
804 _ASSERTE((g_pDebugInterface != NULL) && g_pDebugInterface->ThisIsHelperThread());
805 _ASSERTE((g_pDebugInterface != NULL) && g_pDebugInterface->IsStopped());
806
807 // Convert the metadata to RW for Edit and Continue, properly replacing the metadata import interface pointer and
808 // properly preserving the old importer. This will be called before the EnC system tries to apply a delta to the module's
809 // metadata. ConvertMDInternalToReadWrite() does that quite nicely for us.
810 ConvertMDInternalToReadWrite();
811}
812
813void PEFile::OpenMDImport_Unsafe()
814{
815 CONTRACTL
816 {
817 INSTANCE_CHECK;
818 THROWS;
819 GC_TRIGGERS;
820 MODE_ANY;
821 INJECT_FAULT(COMPlusThrowOM(););
822 }
823 CONTRACTL_END;
824
825 if (m_pMDImport != NULL)
826 return;
827#ifdef FEATURE_PREJIT
828 if (m_nativeImage != NULL
829 && m_nativeImage->GetMDImport() != NULL
830 )
831 {
832 // Use native image for metadata
833 m_flags |= PEFILE_HAS_NATIVE_IMAGE_METADATA;
834 m_pMDImport=m_nativeImage->GetMDImport();
835 }
836 else
837#endif
838 {
839#ifdef FEATURE_PREJIT
840 m_flags &= ~PEFILE_HAS_NATIVE_IMAGE_METADATA;
841#endif
842 if (!IsDynamic()
843 && GetILimage()->HasNTHeaders()
844 && GetILimage()->HasCorHeader())
845 {
846 m_pMDImport=GetILimage()->GetMDImport();
847 }
848 else
849 ThrowHR(COR_E_BADIMAGEFORMAT);
850
851 m_bHasPersistentMDImport=TRUE;
852 }
853 _ASSERTE(m_pMDImport);
854 m_pMDImport->AddRef();
855}
856
857void PEFile::OpenEmitter()
858{
859 CONTRACTL
860 {
861 INSTANCE_CHECK;
862 THROWS;
863 GC_NOTRIGGER;
864 MODE_ANY;
865 INJECT_FAULT(COMPlusThrowOM(););
866 }
867 CONTRACTL_END;
868
869 // Make sure internal MD is in RW format.
870 ConvertMDInternalToReadWrite();
871
872 IMetaDataEmit *pIMDEmit = NULL;
873 IfFailThrow(GetMetaDataPublicInterfaceFromInternal((void*)GetPersistentMDImport(),
874 IID_IMetaDataEmit,
875 (void **)&pIMDEmit));
876
877 // Atomically swap it into the field (release it if we lose the race)
878 if (FastInterlockCompareExchangePointer(&m_pEmitter, pIMDEmit, NULL) != NULL)
879 pIMDEmit->Release();
880}
881
882
883void PEFile::ReleaseMetadataInterfaces(BOOL bDestructor, BOOL bKeepNativeData/*=FALSE*/)
884{
885 CONTRACTL
886 {
887 INSTANCE_CHECK;
888 NOTHROW;
889 GC_NOTRIGGER;
890 MODE_ANY;
891 PRECONDITION(bDestructor||m_pMetadataLock->IsWriterLock());
892 }
893 CONTRACTL_END;
894 _ASSERTE(bDestructor || !m_bHasPersistentMDImport);
895
896 if (m_pImporter != NULL)
897 {
898 m_pImporter->Release();
899 m_pImporter = NULL;
900 }
901 if (m_pEmitter != NULL)
902 {
903 m_pEmitter->Release();
904 m_pEmitter = NULL;
905 }
906
907 if (m_pMDImport != NULL && (!bKeepNativeData || !HasNativeImage()))
908 {
909 m_pMDImport->Release();
910 m_pMDImport=NULL;
911 }
912}
913
914
915// ------------------------------------------------------------
916// PE file access
917// ------------------------------------------------------------
918
919// Note that most of these APIs are currently passed through
920// to the main image. However, in the near future they will
921// be rerouted to the native image in the prejitted case so
922// we can avoid using the original IL image.
923
924#endif //!DACCESS_COMPILE
925
926#ifdef FEATURE_PREJIT
927#ifndef DACCESS_COMPILE
928// ------------------------------------------------------------
929// Native image access
930// ------------------------------------------------------------
931
932void PEFile::SetNativeImage(PEImage *image)
933{
934 CONTRACT_VOID
935 {
936 INSTANCE_CHECK;
937 PRECONDITION(!HasNativeImage());
938 STANDARD_VM_CHECK;
939 }
940 CONTRACT_END;
941
942 _ASSERTE(image != NULL);
943 PREFIX_ASSUME(image != NULL);
944
945 if (image->GetLoadedLayout()->GetBase() != image->GetLoadedLayout()->GetPreferredBase())
946 {
947 ExternalLog(LL_WARNING,
948 W("Native image loaded at base address") LFMT_ADDR
949 W("rather than preferred address:") LFMT_ADDR ,
950 DBG_ADDR(image->GetLoadedLayout()->GetBase()),
951 DBG_ADDR(image->GetLoadedLayout()->GetPreferredBase()));
952 }
953
954 // First ask if we're supposed to be ignoring the prejitted code &
955 // structures in NGENd images. If so, bail now and do not set m_nativeImage. We've
956 // already set m_identity & m_openedILimage), and will use those PEImages to find
957 // and JIT IL.
958 if (ShouldTreatNIAsMSIL())
959 RETURN;
960
961 m_nativeImage = image;
962 m_nativeImage->AddRef();
963 m_nativeImage->Load();
964 m_nativeImage->AllocateLazyCOWPages();
965
966#if defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE)
967 static ConfigDWORD configNGenReserveForJumpStubs;
968 int percentReserveForJumpStubs = configNGenReserveForJumpStubs.val(CLRConfig::INTERNAL_NGenReserveForJumpStubs);
969 if (percentReserveForJumpStubs != 0)
970 {
971 PEImageLayout * pLayout = image->GetLoadedLayout();
972 ExecutionManager::GetEEJitManager()->EnsureJumpStubReserve((BYTE *)pLayout->GetBase(), pLayout->GetVirtualSize(),
973 percentReserveForJumpStubs * (pLayout->GetVirtualSize() / 100));
974 }
975#endif
976
977 ExternalLog(LL_INFO100, W("Attempting to use native image %s."), image->GetPath().GetUnicode());
978 RETURN;
979}
980
981void PEFile::ClearNativeImage()
982{
983 CONTRACT_VOID
984 {
985 INSTANCE_CHECK;
986 PRECONDITION(HasNativeImage());
987 POSTCONDITION(!HasNativeImage());
988 THROWS;
989 GC_TRIGGERS;
990 MODE_ANY;
991 INJECT_FAULT(COMPlusThrowOM(););
992 }
993 CONTRACT_END;
994
995 ExternalLog(LL_WARNING, "Discarding native image.");
996
997
998 MarkNativeImageInvalidIfOwned();
999
1000 {
1001 GCX_PREEMP();
1002 SafeComHolderPreemp<IMDInternalImport> pOldImport=GetMDImportWithRef();
1003 SimpleWriteLockHolder lock(m_pMetadataLock);
1004
1005 EX_TRY
1006 {
1007 ReleaseMetadataInterfaces(FALSE);
1008 m_flags &= ~PEFILE_HAS_NATIVE_IMAGE_METADATA;
1009 if (m_nativeImage)
1010 m_nativeImage->Release();
1011 m_nativeImage = NULL;
1012 // Make sure our normal image is open
1013 EnsureImageOpened();
1014
1015 // Reopen metadata from normal image
1016 OpenMDImport();
1017 }
1018 EX_HOOK
1019 {
1020 RestoreMDImport(pOldImport);
1021 }
1022 EX_END_HOOK;
1023 }
1024
1025 RETURN;
1026}
1027
1028
1029extern DWORD g_dwLogLevel;
1030
1031//===========================================================================================================
1032// Encapsulates CLR and Fusion logging for runtime verification of native images.
1033//===========================================================================================================
1034static void RuntimeVerifyVLog(DWORD level, PEAssembly *pLogAsm, const WCHAR *fmt, va_list args)
1035{
1036 STANDARD_VM_CONTRACT;
1037
1038 BOOL fOutputToDebugger = (level == LL_ERROR && IsDebuggerPresent());
1039 BOOL fOutputToLogging = LoggingOn(LF_ZAP, level);
1040
1041 StackSString message;
1042 message.VPrintf(fmt, args);
1043
1044 if (fOutputToLogging)
1045 {
1046 SString displayString = pLogAsm->GetPath();
1047 LOG((LF_ZAP, level, "%s: \"%S\"\n", "ZAP", displayString.GetUnicode()));
1048 LOG((LF_ZAP, level, "%S", message.GetUnicode()));
1049 LOG((LF_ZAP, level, "\n"));
1050 }
1051
1052 if (fOutputToDebugger)
1053 {
1054 SString displayString = pLogAsm->GetPath();
1055 WszOutputDebugString(W("CLR:("));
1056 WszOutputDebugString(displayString.GetUnicode());
1057 WszOutputDebugString(W(") "));
1058 WszOutputDebugString(message);
1059 WszOutputDebugString(W("\n"));
1060 }
1061
1062}
1063
1064
1065//===========================================================================================================
1066// Encapsulates CLR and Fusion logging for runtime verification of native images.
1067//===========================================================================================================
1068static void RuntimeVerifyLog(DWORD level, PEAssembly *pLogAsm, const WCHAR *fmt, ...)
1069{
1070 STANDARD_VM_CONTRACT;
1071
1072 // Avoid calling RuntimeVerifyVLog unless logging is on
1073 if ( ((level == LL_ERROR) && IsDebuggerPresent())
1074 || LoggingOn(LF_ZAP, level)
1075 )
1076 {
1077 va_list args;
1078 va_start(args, fmt);
1079
1080 RuntimeVerifyVLog(level, pLogAsm, fmt, args);
1081
1082 va_end(args);
1083 }
1084}
1085
1086//==============================================================================
1087
1088static const LPCWSTR CorCompileRuntimeDllNames[NUM_RUNTIME_DLLS] =
1089{
1090 MAKEDLLNAME_W(W("coreclr")),
1091 MAKEDLLNAME_W(W("clrjit"))
1092};
1093
1094
1095LPCWSTR CorCompileGetRuntimeDllName(CorCompileRuntimeDlls id)
1096{
1097 CONTRACTL
1098 {
1099 THROWS;
1100 GC_TRIGGERS;
1101 MODE_ANY;
1102 SO_INTOLERANT;
1103 INJECT_FAULT(COMPlusThrowOM(););
1104 }
1105 CONTRACTL_END;
1106
1107
1108 return CorCompileRuntimeDllNames[id];
1109}
1110
1111#ifndef CROSSGEN_COMPILE
1112
1113//==============================================================================
1114// Will always return a valid HMODULE for CLR_INFO, but will return NULL for NGEN_COMPILER_INFO
1115// if the DLL has not yet been loaded (it does not try to cause a load).
1116
1117// Gets set by IJitManager::LoadJit (yes, this breaks the abstraction boundary).
1118HMODULE s_ngenCompilerDll = NULL;
1119
1120extern HMODULE CorCompileGetRuntimeDll(CorCompileRuntimeDlls id)
1121{
1122 CONTRACTL
1123 {
1124 THROWS;
1125 GC_NOTRIGGER;
1126 MODE_ANY;
1127 SO_INTOLERANT;
1128 INJECT_FAULT(COMPlusThrowOM(););
1129 }
1130 CONTRACTL_END;
1131
1132 // Currently special cased for every entry.
1133 static_assert_no_msg(NUM_RUNTIME_DLLS == 2);
1134 static_assert_no_msg(CORECLR_INFO == 0);
1135
1136 HMODULE hMod = NULL;
1137
1138 // Try to load the correct DLL
1139 switch (id)
1140 {
1141 case CORECLR_INFO:
1142 hMod = GetCLRModule();
1143 break;
1144
1145 default:
1146 COMPlusThrowNonLocalized(kExecutionEngineException,
1147 W("Invalid runtime DLL ID"));
1148 break;
1149 }
1150
1151 return hMod;
1152}
1153#endif // CROSSGEN_COMPILE
1154
1155//===========================================================================================================
1156// Validates that an NI matches the running CLR, OS, CPU, etc.
1157//
1158// For historial reasons, some versions of the runtime perform this check at native bind time (preferrred),
1159// while others check at CLR load time.
1160//
1161// This is the common funnel for both versions and is agnostic to whether the "assembly" is represented
1162// by a CLR object or Fusion object.
1163//===========================================================================================================
1164BOOL RuntimeVerifyNativeImageVersion(const CORCOMPILE_VERSION_INFO *info, PEAssembly *pLogAsm)
1165{
1166 STANDARD_VM_CONTRACT;
1167
1168 //
1169 // Check that the EE version numbers are the same.
1170 //
1171
1172 if (info->wVersionMajor != CLR_MAJOR_VERSION
1173 || info->wVersionMinor != CLR_MINOR_VERSION
1174 || info->wVersionBuildNumber != CLR_BUILD_VERSION
1175 || info->wVersionPrivateBuildNumber != CLR_BUILD_VERSION_QFE)
1176 {
1177 RuntimeVerifyLog(LL_ERROR, pLogAsm, W("CLR version recorded in native image doesn't match the current CLR."));
1178 return FALSE;
1179 }
1180
1181 //
1182 // Check checked/free status
1183 //
1184
1185 if (info->wBuild !=
1186#if _DEBUG
1187 CORCOMPILE_BUILD_CHECKED
1188#else
1189 CORCOMPILE_BUILD_FREE
1190#endif
1191 )
1192 {
1193 RuntimeVerifyLog(LL_ERROR, pLogAsm, W("Checked/free mismatch with native image."));
1194 return FALSE;
1195 }
1196
1197 //
1198 // Check processor
1199 //
1200
1201 if (info->wMachine != IMAGE_FILE_MACHINE_NATIVE_NI)
1202 {
1203 RuntimeVerifyLog(LL_ERROR, pLogAsm, W("Processor type recorded in native image doesn't match this machine's processor."));
1204 return FALSE;
1205 }
1206
1207#ifndef CROSSGEN_COMPILE
1208 //
1209 // Check the processor specific ID
1210 //
1211
1212 CORINFO_CPU cpuInfo;
1213 GetSpecificCpuInfo(&cpuInfo);
1214
1215 if (!IsCompatibleCpuInfo(&cpuInfo, &info->cpuInfo))
1216 {
1217 RuntimeVerifyLog(LL_ERROR, pLogAsm, W("Required CPU features recorded in native image don't match this machine's processor."));
1218 return FALSE;
1219 }
1220#endif // CROSSGEN_COMPILE
1221
1222
1223 //
1224 // The zap is up to date.
1225 //
1226
1227 RuntimeVerifyLog(LL_INFO100, pLogAsm, W("Native image has correct version information."));
1228 return TRUE;
1229}
1230
1231//===========================================================================================================
1232// Validates that an NI matches the running CLR, OS, CPU, etc. This is the entrypoint used by the CLR loader.
1233//
1234//===========================================================================================================
1235BOOL PEAssembly::CheckNativeImageVersion(PEImage *peimage)
1236{
1237 STANDARD_VM_CONTRACT;
1238
1239 //
1240 // Get the zap version header. Note that modules will not have version
1241 // headers - they add no additional versioning constraints from their
1242 // assemblies.
1243 //
1244 PEImageLayoutHolder image = peimage->GetLayout(PEImageLayout::LAYOUT_ANY, PEImage::LAYOUT_CREATEIFNEEDED);
1245
1246 if (!image->HasNativeHeader())
1247 return FALSE;
1248
1249 if (!image->CheckNativeHeaderVersion())
1250 {
1251 // Wrong native image version is fatal error on CoreCLR
1252 ThrowHR(COR_E_NI_AND_RUNTIME_VERSION_MISMATCH);
1253 }
1254
1255 CORCOMPILE_VERSION_INFO *info = image->GetNativeVersionInfo();
1256 if (info == NULL)
1257 return FALSE;
1258
1259 if (!RuntimeVerifyNativeImageVersion(info, this))
1260 {
1261 // Wrong native image version is fatal error on CoreCLR
1262 ThrowHR(COR_E_NI_AND_RUNTIME_VERSION_MISMATCH);
1263 }
1264
1265 CorCompileConfigFlags configFlags = PEFile::GetNativeImageConfigFlagsWithOverrides();
1266
1267 // Otherwise, match regardless of the instrumentation flags
1268 configFlags = (CorCompileConfigFlags)(configFlags & ~(CORCOMPILE_CONFIG_INSTRUMENTATION_NONE | CORCOMPILE_CONFIG_INSTRUMENTATION));
1269
1270 if ((info->wConfigFlags & configFlags) != configFlags)
1271 {
1272 return FALSE;
1273 }
1274
1275 return TRUE;
1276}
1277
1278#endif // !DACCESS_COMPILE
1279
1280/* static */
1281CorCompileConfigFlags PEFile::GetNativeImageConfigFlags(BOOL fForceDebug/*=FALSE*/,
1282 BOOL fForceProfiling/*=FALSE*/,
1283 BOOL fForceInstrument/*=FALSE*/)
1284{
1285 LIMITED_METHOD_DAC_CONTRACT;
1286
1287 CorCompileConfigFlags result = (CorCompileConfigFlags)0;
1288
1289 // Debugging
1290
1291#ifdef DEBUGGING_SUPPORTED
1292 // if these have been set, the take precedence over anything else
1293 if (s_NGENDebugFlags)
1294 {
1295 if ((s_NGENDebugFlags & CORCOMPILE_CONFIG_DEBUG_NONE) != 0)
1296 {
1297 result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_DEBUG_NONE);
1298 }
1299 else
1300 {
1301 if ((s_NGENDebugFlags & CORCOMPILE_CONFIG_DEBUG) != 0)
1302 {
1303 result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_DEBUG);
1304 }
1305 }
1306 }
1307 else
1308#endif // DEBUGGING_SUPPORTED
1309 {
1310 if (fForceDebug)
1311 {
1312 result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_DEBUG);
1313 }
1314 else
1315 {
1316 result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_DEBUG_DEFAULT);
1317 }
1318 }
1319
1320 // Profiling
1321
1322#ifdef PROFILING_SUPPORTED
1323 if (fForceProfiling || CORProfilerUseProfileImages())
1324 {
1325 result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_PROFILING);
1326
1327 result = (CorCompileConfigFlags) (result & ~(CORCOMPILE_CONFIG_DEBUG_NONE|
1328 CORCOMPILE_CONFIG_DEBUG|
1329 CORCOMPILE_CONFIG_DEBUG_DEFAULT));
1330 }
1331 else
1332#endif //PROFILING_SUPPORTED
1333 result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_PROFILING_NONE);
1334
1335 // Instrumentation
1336#ifndef DACCESS_COMPILE
1337 BOOL instrumented = (!IsCompilationProcess() && g_pConfig->GetZapBBInstr());
1338#else
1339 BOOL instrumented = FALSE;
1340#endif
1341 if (instrumented || fForceInstrument)
1342 {
1343 result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_INSTRUMENTATION);
1344 }
1345 else
1346 {
1347 result = (CorCompileConfigFlags) (result|CORCOMPILE_CONFIG_INSTRUMENTATION_NONE);
1348 }
1349
1350 // NOTE: Right now we are not taking instrumentation into account when binding.
1351
1352 return result;
1353}
1354
1355CorCompileConfigFlags PEFile::GetNativeImageConfigFlagsWithOverrides()
1356{
1357 LIMITED_METHOD_DAC_CONTRACT;
1358
1359 BOOL fForceDebug, fForceProfiling, fForceInstrument;
1360 SystemDomain::GetCompilationOverrides(&fForceDebug,
1361 &fForceProfiling,
1362 &fForceInstrument);
1363 return PEFile::GetNativeImageConfigFlags(fForceDebug,
1364 fForceProfiling,
1365 fForceInstrument);
1366}
1367
1368#ifndef DACCESS_COMPILE
1369
1370
1371
1372//===========================================================================================================
1373// Validates that a hard-dep matches the a parent NI's compile-time hard-dep.
1374//
1375// For historial reasons, some versions of the runtime perform this check at native bind time (preferrred),
1376// while others check at CLR load time.
1377//
1378// This is the common funnel for both versions and is agnostic to whether the "assembly" is represented
1379// by a CLR object or Fusion object.
1380//
1381//===========================================================================================================
1382BOOL RuntimeVerifyNativeImageDependency(const CORCOMPILE_NGEN_SIGNATURE &ngenSigExpected,
1383 const CORCOMPILE_VERSION_INFO *pActual,
1384 PEAssembly *pLogAsm)
1385{
1386 STANDARD_VM_CONTRACT;
1387
1388 if (ngenSigExpected != pActual->signature)
1389 {
1390 // Signature did not match
1391 SString displayString = pLogAsm->GetPath();
1392 RuntimeVerifyLog(LL_ERROR,
1393 pLogAsm,
1394 W("Rejecting native image because native image dependency %s ")
1395 W("had a different identity than expected"),
1396 displayString.GetUnicode());
1397
1398 return FALSE;
1399 }
1400 return TRUE;
1401}
1402// Wrapper function for use by parts of the runtime that actually have a CORCOMPILE_DEPENDENCY to work with.
1403BOOL RuntimeVerifyNativeImageDependency(const CORCOMPILE_DEPENDENCY *pExpected,
1404 const CORCOMPILE_VERSION_INFO *pActual,
1405 PEAssembly *pLogAsm)
1406{
1407 WRAPPER_NO_CONTRACT;
1408
1409 return RuntimeVerifyNativeImageDependency(pExpected->signNativeImage,
1410 pActual,
1411 pLogAsm);
1412}
1413
1414#endif // !DACCESS_COMPILE
1415
1416#ifdef DEBUGGING_SUPPORTED
1417//
1418// Called through ICorDebugAppDomain2::SetDesiredNGENCompilerFlags to specify
1419// which kinds of ngen'd images fusion should load wrt debugging support
1420// Overrides any previous settings
1421//
1422void PEFile::SetNGENDebugFlags(BOOL fAllowOpt)
1423{
1424 CONTRACTL
1425 {
1426 GC_NOTRIGGER;
1427 NOTHROW;
1428 MODE_ANY;
1429 SUPPORTS_DAC;
1430 }
1431 CONTRACTL_END;
1432
1433 if (fAllowOpt)
1434 s_NGENDebugFlags = CORCOMPILE_CONFIG_DEBUG_NONE;
1435 else
1436 s_NGENDebugFlags = CORCOMPILE_CONFIG_DEBUG;
1437 }
1438
1439//
1440// Called through ICorDebugAppDomain2::GetDesiredNGENCompilerFlags to determine
1441// which kinds of ngen'd images fusion should load wrt debugging support
1442//
1443void PEFile::GetNGENDebugFlags(BOOL *fAllowOpt)
1444{
1445 CONTRACTL
1446 {
1447 GC_NOTRIGGER;
1448 NOTHROW;
1449 MODE_ANY;
1450 SUPPORTS_DAC;
1451 }
1452 CONTRACTL_END;
1453
1454 CorCompileConfigFlags configFlags = PEFile::GetNativeImageConfigFlagsWithOverrides();
1455
1456 *fAllowOpt = ((configFlags & CORCOMPILE_CONFIG_DEBUG) == 0);
1457}
1458#endif // DEBUGGING_SUPPORTED
1459
1460
1461
1462#ifndef DACCESS_COMPILE
1463
1464//---------------------------------------------------------------------------------------
1465//
1466// Used in Apollo, this method determines whether profiling or debugging has requested
1467// the runtime to provide debuggable / profileable code. In other CLR builds, this would
1468// normally result in requiring the appropriate NGEN scenario be loaded (/Debug or
1469// /Profile) and to JIT if unavailable. In Apollo, however, these NGEN scenarios are
1470// never available, and even MSIL assemblies are often not available. So this function
1471// tells its caller to use the NGENd assembly as if it were an MSIL assembly--ignore the
1472// prejitted code and prebaked structures, and just JIT code and load classes from
1473// scratch.
1474//
1475// Return Value:
1476// nonzero iff NGENd images should be treated as MSIL images.
1477//
1478
1479// static
1480BOOL PEFile::ShouldTreatNIAsMSIL()
1481{
1482 LIMITED_METHOD_CONTRACT;
1483
1484 // Never use fragile native image content during ReadyToRun compilation. It would
1485 // produces non-version resilient images because of wrong cached values for
1486 // MethodTable::IsLayoutFixedInCurrentVersionBubble, etc.
1487 if (IsReadyToRunCompilation())
1488 return TRUE;
1489
1490 // Ask profiling API & config vars whether NGENd images should be avoided
1491 // completely.
1492 if (!NGENImagesAllowed())
1493 return TRUE;
1494
1495 // Ask profiling and debugging if they're requesting us to use ngen /Debug or
1496 // /Profile images (which aren't available under Apollo)
1497
1498 CorCompileConfigFlags configFlags = PEFile::GetNativeImageConfigFlagsWithOverrides();
1499
1500 if ((configFlags & (CORCOMPILE_CONFIG_DEBUG | CORCOMPILE_CONFIG_PROFILING)) != 0)
1501 return TRUE;
1502
1503 return FALSE;
1504}
1505
1506#endif //!DACCESS_COMPILE
1507#endif // FEATURE_PREJIT
1508
1509#ifndef DACCESS_COMPILE
1510
1511// ------------------------------------------------------------
1512// Resource access
1513// ------------------------------------------------------------
1514
1515void PEFile::GetEmbeddedResource(DWORD dwOffset, DWORD *cbResource, PBYTE *pbInMemoryResource)
1516{
1517 CONTRACTL
1518 {
1519 INSTANCE_CHECK;
1520 THROWS;
1521 GC_TRIGGERS;
1522 MODE_ANY;
1523 INJECT_FAULT(ThrowOutOfMemory(););
1524 }
1525 CONTRACTL_END;
1526
1527 // NOTE: it's not clear whether to load this from m_image or m_loadedImage.
1528 // m_loadedImage is probably preferable, but this may be called by security
1529 // before the image is loaded.
1530
1531 PEImage *image;
1532
1533#ifdef FEATURE_PREJIT
1534 if (m_nativeImage != NULL)
1535 image = m_nativeImage;
1536 else
1537#endif
1538 {
1539 EnsureImageOpened();
1540 image = GetILimage();
1541 }
1542
1543 PEImageLayoutHolder theImage(image->GetLayout(PEImageLayout::LAYOUT_ANY,PEImage::LAYOUT_CREATEIFNEEDED));
1544 if (!theImage->CheckResource(dwOffset))
1545 ThrowHR(COR_E_BADIMAGEFORMAT);
1546
1547 COUNT_T size;
1548 const void *resource = theImage->GetResource(dwOffset, &size);
1549
1550 *cbResource = size;
1551 *pbInMemoryResource = (PBYTE) resource;
1552}
1553
1554// ------------------------------------------------------------
1555// File loading
1556// ------------------------------------------------------------
1557
1558PEAssembly *
1559PEFile::LoadAssembly(
1560 mdAssemblyRef kAssemblyRef,
1561 IMDInternalImport * pImport, // = NULL
1562 LPCUTF8 szWinRtTypeNamespace, // = NULL
1563 LPCUTF8 szWinRtTypeClassName) // = NULL
1564{
1565 CONTRACT(PEAssembly *)
1566 {
1567 INSTANCE_CHECK;
1568 THROWS;
1569 GC_TRIGGERS;
1570 MODE_ANY;
1571 POSTCONDITION(CheckPointer(RETVAL));
1572 INJECT_FAULT(COMPlusThrowOM(););
1573 }
1574 CONTRACT_END;
1575
1576 if (pImport == NULL)
1577 pImport = GetPersistentMDImport();
1578
1579 if (((TypeFromToken(kAssemblyRef) != mdtAssembly) &&
1580 (TypeFromToken(kAssemblyRef) != mdtAssemblyRef)) ||
1581 (!pImport->IsValidToken(kAssemblyRef)))
1582 {
1583 ThrowHR(COR_E_BADIMAGEFORMAT);
1584 }
1585
1586 AssemblySpec spec;
1587
1588 spec.InitializeSpec(kAssemblyRef, pImport, GetAppDomain()->FindAssembly(GetAssembly()));
1589 if (szWinRtTypeClassName != NULL)
1590 spec.SetWindowsRuntimeType(szWinRtTypeNamespace, szWinRtTypeClassName);
1591
1592 RETURN GetAppDomain()->BindAssemblySpec(&spec, TRUE);
1593}
1594
1595// ------------------------------------------------------------
1596// Logging
1597// ------------------------------------------------------------
1598#ifdef FEATURE_PREJIT
1599void PEFile::ExternalLog(DWORD facility, DWORD level, const WCHAR *fmt, ...)
1600{
1601 WRAPPER_NO_CONTRACT;
1602
1603 va_list args;
1604 va_start(args, fmt);
1605
1606 ExternalVLog(facility, level, fmt, args);
1607
1608 va_end(args);
1609}
1610
1611void PEFile::ExternalLog(DWORD level, const WCHAR *fmt, ...)
1612{
1613 WRAPPER_NO_CONTRACT;
1614
1615 va_list args;
1616 va_start(args, fmt);
1617
1618 ExternalVLog(LF_ZAP, level, fmt, args);
1619
1620 va_end(args);
1621}
1622
1623void PEFile::ExternalLog(DWORD level, const char *msg)
1624{
1625 WRAPPER_NO_CONTRACT;
1626
1627 // It is OK to use %S here. We know that msg is ASCII-only.
1628 ExternalLog(level, W("%S"), msg);
1629}
1630
1631void PEFile::ExternalVLog(DWORD facility, DWORD level, const WCHAR *fmt, va_list args)
1632{
1633 CONTRACT_VOID
1634 {
1635 THROWS;
1636 GC_TRIGGERS;
1637 }
1638 CONTRACT_END;
1639
1640 BOOL fOutputToDebugger = (level == LL_ERROR && IsDebuggerPresent());
1641 BOOL fOutputToLogging = LoggingOn(facility, level);
1642
1643 if (!fOutputToDebugger && !fOutputToLogging)
1644 return;
1645
1646 StackSString message;
1647 message.VPrintf(fmt, args);
1648
1649 if (fOutputToLogging)
1650 {
1651 if (GetMDImport() != NULL)
1652 LOG((facility, level, "%s: \"%s\"\n", (facility == LF_ZAP ? "ZAP" : "LOADER"), GetSimpleName()));
1653 else
1654 LOG((facility, level, "%s: \"%S\"\n", (facility == LF_ZAP ? "ZAP" : "LOADER"), ((const WCHAR *)GetPath())));
1655
1656 LOG((facility, level, "%S", message.GetUnicode()));
1657 LOG((facility, level, "\n"));
1658 }
1659
1660 if (fOutputToDebugger)
1661 {
1662 WszOutputDebugString(W("CLR:("));
1663
1664 StackSString codebase;
1665 GetCodeBaseOrName(codebase);
1666 WszOutputDebugString(codebase);
1667
1668 WszOutputDebugString(W(") "));
1669
1670 WszOutputDebugString(message);
1671 WszOutputDebugString(W("\n"));
1672 }
1673
1674 RETURN;
1675}
1676
1677void PEFile::FlushExternalLog()
1678{
1679 LIMITED_METHOD_CONTRACT;
1680}
1681#endif
1682
1683BOOL PEFile::GetResource(LPCSTR szName, DWORD *cbResource,
1684 PBYTE *pbInMemoryResource, DomainAssembly** pAssemblyRef,
1685 LPCSTR *szFileName, DWORD *dwLocation,
1686 BOOL fSkipRaiseResolveEvent, DomainAssembly* pDomainAssembly, AppDomain* pAppDomain)
1687{
1688 CONTRACTL
1689 {
1690 INSTANCE_CHECK;
1691 THROWS;
1692 MODE_ANY;
1693 INJECT_FAULT(COMPlusThrowOM(););
1694 WRAPPER(GC_TRIGGERS);
1695 }
1696 CONTRACTL_END;
1697
1698
1699 mdToken mdLinkRef;
1700 DWORD dwResourceFlags;
1701 DWORD dwOffset;
1702 mdManifestResource mdResource;
1703 Assembly* pAssembly = NULL;
1704 PEFile* pPEFile = NULL;
1705 ReleaseHolder<IMDInternalImport> pImport (GetMDImportWithRef());
1706 if (SUCCEEDED(pImport->FindManifestResourceByName(szName, &mdResource)))
1707 {
1708 pPEFile = this;
1709 IfFailThrow(pImport->GetManifestResourceProps(
1710 mdResource,
1711 NULL, //&szName,
1712 &mdLinkRef,
1713 &dwOffset,
1714 &dwResourceFlags));
1715 }
1716 else
1717 {
1718 if (fSkipRaiseResolveEvent || pAppDomain == NULL)
1719 return FALSE;
1720
1721 DomainAssembly* pParentAssembly = GetAppDomain()->FindAssembly(GetAssembly());
1722 pAssembly = pAppDomain->RaiseResourceResolveEvent(pParentAssembly, szName);
1723 if (pAssembly == NULL)
1724 return FALSE;
1725
1726 pDomainAssembly = pAssembly->GetDomainAssembly(pAppDomain);
1727 pPEFile = pDomainAssembly->GetFile();
1728
1729 if (FAILED(pAssembly->GetManifestImport()->FindManifestResourceByName(
1730 szName,
1731 &mdResource)))
1732 {
1733 return FALSE;
1734 }
1735
1736 if (dwLocation != 0)
1737 {
1738 if (pAssemblyRef != NULL)
1739 *pAssemblyRef = pDomainAssembly;
1740
1741 *dwLocation = *dwLocation | 2; // ResourceLocation.containedInAnotherAssembly
1742 }
1743 IfFailThrow(pPEFile->GetPersistentMDImport()->GetManifestResourceProps(
1744 mdResource,
1745 NULL, //&szName,
1746 &mdLinkRef,
1747 &dwOffset,
1748 &dwResourceFlags));
1749 }
1750
1751
1752 switch(TypeFromToken(mdLinkRef)) {
1753 case mdtAssemblyRef:
1754 {
1755 if (pDomainAssembly == NULL)
1756 return FALSE;
1757
1758 AssemblySpec spec;
1759 spec.InitializeSpec(mdLinkRef, GetPersistentMDImport(), pDomainAssembly);
1760 pDomainAssembly = spec.LoadDomainAssembly(FILE_LOADED);
1761
1762 if (dwLocation) {
1763 if (pAssemblyRef)
1764 *pAssemblyRef = pDomainAssembly;
1765
1766 *dwLocation = *dwLocation | 2; // ResourceLocation.containedInAnotherAssembly
1767 }
1768
1769 return pDomainAssembly->GetResource(szName,
1770 cbResource,
1771 pbInMemoryResource,
1772 pAssemblyRef,
1773 szFileName,
1774 dwLocation,
1775 fSkipRaiseResolveEvent);
1776 }
1777
1778 case mdtFile:
1779 if (mdLinkRef == mdFileNil)
1780 {
1781 // The resource is embedded in the manifest file
1782
1783 if (dwLocation) {
1784 *dwLocation = *dwLocation | 5; // ResourceLocation.embedded |
1785
1786 // ResourceLocation.containedInManifestFile
1787 return TRUE;
1788 }
1789
1790 pPEFile->GetEmbeddedResource(dwOffset, cbResource, pbInMemoryResource);
1791
1792 return TRUE;
1793 }
1794 return FALSE;
1795
1796 default:
1797 ThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN_IN_MANIFESTRES);
1798 }
1799}
1800
1801void PEFile::GetPEKindAndMachine(DWORD* pdwKind, DWORD* pdwMachine)
1802{
1803 WRAPPER_NO_CONTRACT;
1804
1805 if (IsResource() || IsDynamic())
1806 {
1807 if (pdwKind)
1808 *pdwKind = 0;
1809 if (pdwMachine)
1810 *pdwMachine = 0;
1811 return;
1812 }
1813
1814#ifdef FEATURE_PREJIT
1815 if (IsNativeLoaded())
1816 {
1817 CONSISTENCY_CHECK(HasNativeImage());
1818
1819 m_nativeImage->GetNativeILPEKindAndMachine(pdwKind, pdwMachine);
1820 return;
1821 }
1822#ifndef DACCESS_COMPILE
1823 if (!HasOpenedILimage())
1824 {
1825 //don't want to touch the IL image unless we already have
1826 ReleaseHolder<PEImage> pNativeImage = GetNativeImageWithRef();
1827 if (pNativeImage)
1828 {
1829 pNativeImage->GetNativeILPEKindAndMachine(pdwKind, pdwMachine);
1830 return;
1831 }
1832 }
1833#endif // DACCESS_COMPILE
1834#endif // FEATURE_PREJIT
1835
1836 GetILimage()->GetPEKindAndMachine(pdwKind, pdwMachine);
1837 return;
1838}
1839
1840ULONG PEFile::GetILImageTimeDateStamp()
1841{
1842 CONTRACTL
1843 {
1844 NOTHROW;
1845 GC_NOTRIGGER;
1846 MODE_ANY;
1847 }
1848 CONTRACTL_END;
1849
1850#ifdef FEATURE_PREJIT
1851 if (IsNativeLoaded())
1852 {
1853 CONSISTENCY_CHECK(HasNativeImage());
1854
1855 // The IL image's time stamp is copied to the native image.
1856 CORCOMPILE_VERSION_INFO* pVersionInfo = GetLoadedNative()->GetNativeVersionInfoMaybeNull();
1857 if (pVersionInfo == NULL)
1858 {
1859 return 0;
1860 }
1861 else
1862 {
1863 return pVersionInfo->sourceAssembly.timeStamp;
1864 }
1865 }
1866#endif // FEATURE_PREJIT
1867
1868 return GetLoadedIL()->GetTimeDateStamp();
1869}
1870
1871
1872// ================================================================================
1873// PEAssembly class - a PEFile which represents an assembly
1874// ================================================================================
1875
1876// Statics initialization.
1877/* static */
1878void PEAssembly::Attach()
1879{
1880 STANDARD_VM_CONTRACT;
1881}
1882
1883
1884PEAssembly::PEAssembly(
1885 CoreBindResult* pBindResultInfo,
1886 IMetaDataEmit* pEmit,
1887 PEFile *creator,
1888 BOOL system,
1889 PEImage * pPEImageIL /*= NULL*/,
1890 PEImage * pPEImageNI /*= NULL*/,
1891 ICLRPrivAssembly * pHostAssembly /*= NULL*/)
1892
1893 : PEFile(pBindResultInfo ? (pBindResultInfo->GetPEImage() ? pBindResultInfo->GetPEImage() :
1894 (pBindResultInfo->HasNativeImage() ? pBindResultInfo->GetNativeImage() : NULL)
1895 ): pPEImageIL? pPEImageIL:(pPEImageNI? pPEImageNI:NULL), FALSE),
1896 m_creator(clr::SafeAddRef(creator))
1897{
1898 CONTRACTL
1899 {
1900 CONSTRUCTOR_CHECK;
1901 PRECONDITION(CheckPointer(pEmit, NULL_OK));
1902 PRECONDITION(CheckPointer(creator, NULL_OK));
1903 PRECONDITION(pBindResultInfo == NULL || (pPEImageIL == NULL && pPEImageNI == NULL));
1904 STANDARD_VM_CHECK;
1905 }
1906 CONTRACTL_END;
1907
1908 m_flags |= PEFILE_ASSEMBLY;
1909 if (system)
1910 m_flags |= PEFILE_SYSTEM;
1911
1912 // We check the precondition above that either pBindResultInfo is null or both pPEImageIL and pPEImageNI are,
1913 // so we'll only get a max of one native image passed in.
1914 if (pPEImageNI != NULL)
1915 {
1916 SetNativeImage(pPEImageNI);
1917 }
1918
1919#ifdef FEATURE_PREJIT
1920 if (pBindResultInfo && pBindResultInfo->HasNativeImage())
1921 SetNativeImage(pBindResultInfo->GetNativeImage());
1922#endif
1923
1924 // If we have no native image, we require a mapping for the file.
1925 if (!HasNativeImage() || !IsILOnly())
1926 EnsureImageOpened();
1927
1928 // Open metadata eagerly to minimize failure windows
1929 if (pEmit == NULL)
1930 OpenMDImport_Unsafe(); //constructor, cannot race with anything
1931 else
1932 {
1933 _ASSERTE(!m_bHasPersistentMDImport);
1934 IfFailThrow(GetMetaDataInternalInterfaceFromPublic(pEmit, IID_IMDInternalImport,
1935 (void **)&m_pMDImport));
1936 m_pEmitter = pEmit;
1937 pEmit->AddRef();
1938 m_bHasPersistentMDImport=TRUE;
1939 m_MDImportIsRW_Debugger_Use_Only = TRUE;
1940 }
1941
1942 // m_pMDImport can be external
1943 // Make sure this is an assembly
1944 if (!m_pMDImport->IsValidToken(TokenFromRid(1, mdtAssembly)))
1945 ThrowHR(COR_E_ASSEMBLYEXPECTED);
1946
1947 // Verify name eagerly
1948 LPCUTF8 szName = GetSimpleName();
1949 if (!*szName)
1950 {
1951 ThrowHR(COR_E_BADIMAGEFORMAT, BFA_EMPTY_ASSEMDEF_NAME);
1952 }
1953
1954 // Set the host assembly and binding context as the AssemblySpec initialization
1955 // for CoreCLR will expect to have it set.
1956 if (pHostAssembly != nullptr)
1957 {
1958 m_pHostAssembly = clr::SafeAddRef(pHostAssembly);
1959 }
1960
1961 if(pBindResultInfo != nullptr)
1962 {
1963 // Cannot have both pHostAssembly and a coreclr based bind
1964 _ASSERTE(pHostAssembly == nullptr);
1965 pBindResultInfo->GetBindAssembly(&m_pHostAssembly);
1966 }
1967
1968#if _DEBUG
1969 GetCodeBaseOrName(m_debugName);
1970 m_debugName.Normalize();
1971 m_pDebugName = m_debugName;
1972
1973 AssemblySpec spec;
1974 spec.InitializeSpec(this);
1975
1976 spec.GetFileOrDisplayName(ASM_DISPLAYF_VERSION |
1977 ASM_DISPLAYF_CULTURE |
1978 ASM_DISPLAYF_PUBLIC_KEY_TOKEN,
1979 m_sTextualIdentity);
1980#endif
1981}
1982
1983
1984
1985PEAssembly *PEAssembly::Open(
1986 PEAssembly * pParent,
1987 PEImage * pPEImageIL,
1988 PEImage * pPEImageNI,
1989 ICLRPrivAssembly * pHostAssembly)
1990{
1991 STANDARD_VM_CONTRACT;
1992
1993 PEAssembly * pPEAssembly = new PEAssembly(
1994 nullptr, // BindResult
1995 nullptr, // IMetaDataEmit
1996 pParent, // PEFile creator
1997 FALSE, // isSystem
1998 pPEImageIL,
1999 pPEImageNI,
2000 pHostAssembly);
2001
2002 return pPEAssembly;
2003}
2004
2005
2006PEAssembly::~PEAssembly()
2007{
2008 CONTRACTL
2009 {
2010 DESTRUCTOR_CHECK;
2011 NOTHROW;
2012 GC_TRIGGERS; // Fusion uses crsts on AddRef/Release
2013 MODE_ANY;
2014 }
2015 CONTRACTL_END;
2016
2017 GCX_PREEMP();
2018 if (m_creator != NULL)
2019 m_creator->Release();
2020
2021}
2022
2023#ifndef DACCESS_COMPILE
2024void PEAssembly::ReleaseIL()
2025{
2026 CONTRACTL
2027 {
2028 INSTANCE_CHECK;
2029 NOTHROW;
2030 GC_TRIGGERS;
2031 MODE_ANY;
2032 }
2033 CONTRACTL_END;
2034
2035 GCX_PREEMP();
2036 if (m_creator != NULL)
2037 {
2038 m_creator->Release();
2039 m_creator=NULL;
2040 }
2041
2042 PEFile::ReleaseIL();
2043}
2044#endif
2045
2046/* static */
2047
2048PEAssembly *PEAssembly::OpenSystem(IUnknown * pAppCtx)
2049{
2050 STANDARD_VM_CONTRACT;
2051
2052 PEAssembly *result = NULL;
2053
2054 EX_TRY
2055 {
2056 result = DoOpenSystem(pAppCtx);
2057 }
2058 EX_HOOK
2059 {
2060 Exception *ex = GET_EXCEPTION();
2061
2062 // Rethrow non-transient exceptions as file load exceptions with proper
2063 // context
2064
2065 if (!ex->IsTransient())
2066 EEFileLoadException::Throw(SystemDomain::System()->BaseLibrary(), ex->GetHR(), ex);
2067 }
2068 EX_END_HOOK;
2069 return result;
2070}
2071
2072/* static */
2073PEAssembly *PEAssembly::DoOpenSystem(IUnknown * pAppCtx)
2074{
2075 CONTRACT(PEAssembly *)
2076 {
2077 POSTCONDITION(CheckPointer(RETVAL));
2078 STANDARD_VM_CHECK;
2079 }
2080 CONTRACT_END;
2081
2082 ETWOnStartup (FusionBinding_V1, FusionBindingEnd_V1);
2083 CoreBindResult bindResult;
2084 ReleaseHolder<ICLRPrivAssembly> pPrivAsm;
2085 IfFailThrow(CCoreCLRBinderHelper::BindToSystem(&pPrivAsm, !IsCompilationProcess() || g_fAllowNativeImages));
2086 if(pPrivAsm != NULL)
2087 {
2088 bindResult.Init(pPrivAsm);
2089 }
2090
2091 RETURN new PEAssembly(&bindResult, NULL, NULL, TRUE, FALSE);
2092}
2093
2094
2095#ifndef CROSSGEN_COMPILE
2096/* static */
2097PEAssembly *PEAssembly::OpenMemory(PEAssembly *pParentAssembly,
2098 const void *flat, COUNT_T size)
2099{
2100 STANDARD_VM_CONTRACT;
2101
2102 PEAssembly *result = NULL;
2103
2104 EX_TRY
2105 {
2106 result = DoOpenMemory(pParentAssembly, flat, size);
2107 }
2108 EX_HOOK
2109 {
2110 Exception *ex = GET_EXCEPTION();
2111
2112 // Rethrow non-transient exceptions as file load exceptions with proper
2113 // context
2114
2115 if (!ex->IsTransient())
2116 EEFileLoadException::Throw(pParentAssembly, flat, size, ex->GetHR(), ex);
2117 }
2118 EX_END_HOOK;
2119
2120 return result;
2121}
2122
2123
2124// Thread stress
2125
2126class DoOpenFlatStress : APIThreadStress
2127{
2128public:
2129 PEAssembly *pParentAssembly;
2130 const void *flat;
2131 COUNT_T size;
2132 DoOpenFlatStress(PEAssembly *pParentAssembly, const void *flat, COUNT_T size)
2133 : pParentAssembly(pParentAssembly), flat(flat), size(size) {LIMITED_METHOD_CONTRACT;}
2134 void Invoke()
2135 {
2136 WRAPPER_NO_CONTRACT;
2137 PEAssemblyHolder result(PEAssembly::OpenMemory(pParentAssembly, flat, size));
2138 }
2139};
2140
2141/* static */
2142PEAssembly *PEAssembly::DoOpenMemory(
2143 PEAssembly *pParentAssembly,
2144 const void *flat,
2145 COUNT_T size)
2146{
2147 CONTRACT(PEAssembly *)
2148 {
2149 PRECONDITION(CheckPointer(flat));
2150 PRECONDITION(CheckOverflow(flat, size));
2151 PRECONDITION(CheckPointer(pParentAssembly));
2152 STANDARD_VM_CHECK;
2153 POSTCONDITION(CheckPointer(RETVAL));
2154 }
2155 CONTRACT_END;
2156
2157 // Thread stress
2158 DoOpenFlatStress ts(pParentAssembly, flat, size);
2159
2160 // Note that we must have a flat image stashed away for two reasons.
2161 // First, we need a private copy of the data which we can verify
2162 // before doing the mapping. And secondly, we can only compute
2163 // the strong name hash on a flat image.
2164
2165 PEImageHolder image(PEImage::LoadFlat(flat, size));
2166
2167 // Need to verify that this is a CLR assembly
2168 if (!image->CheckILFormat())
2169 ThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL);
2170
2171
2172 CoreBindResult bindResult;
2173 ReleaseHolder<ICLRPrivAssembly> assembly;
2174 IfFailThrow(CCoreCLRBinderHelper::GetAssemblyFromImage(image, NULL, &assembly));
2175 bindResult.Init(assembly);
2176
2177 RETURN new PEAssembly(&bindResult, NULL, pParentAssembly, FALSE);
2178}
2179#endif // !CROSSGEN_COMPILE
2180
2181
2182
2183PEAssembly* PEAssembly::Open(CoreBindResult* pBindResult,
2184 BOOL isSystem)
2185{
2186
2187 return new PEAssembly(pBindResult,NULL,NULL,isSystem);
2188
2189};
2190
2191/* static */
2192PEAssembly *PEAssembly::Create(PEAssembly *pParentAssembly,
2193 IMetaDataAssemblyEmit *pAssemblyEmit)
2194{
2195 CONTRACT(PEAssembly *)
2196 {
2197 PRECONDITION(CheckPointer(pParentAssembly));
2198 PRECONDITION(CheckPointer(pAssemblyEmit));
2199 STANDARD_VM_CHECK;
2200 POSTCONDITION(CheckPointer(RETVAL));
2201 }
2202 CONTRACT_END;
2203
2204 // Set up the metadata pointers in the PEAssembly. (This is the only identity
2205 // we have.)
2206 SafeComHolder<IMetaDataEmit> pEmit;
2207 pAssemblyEmit->QueryInterface(IID_IMetaDataEmit, (void **)&pEmit);
2208 PEAssemblyHolder pFile(new PEAssembly(NULL, pEmit, pParentAssembly, FALSE));
2209 RETURN pFile.Extract();
2210}
2211
2212
2213#ifdef FEATURE_PREJIT
2214
2215
2216void PEAssembly::SetNativeImage(PEImage * image)
2217{
2218 CONTRACTL
2219 {
2220 INSTANCE_CHECK;
2221 STANDARD_VM_CHECK;
2222 }
2223 CONTRACTL_END;
2224
2225 image->Load();
2226
2227 if (CheckNativeImageVersion(image))
2228 {
2229 PEFile::SetNativeImage(image);
2230#if 0
2231 //Enable this code if you want to make sure we never touch the flat layout in the presence of the
2232 //ngen image.
2233//#if defined(_DEBUG)
2234 //find all the layouts in the il image and make sure we never touch them.
2235 unsigned ignored = 0;
2236 PTR_PEImageLayout layout = m_ILimage->GetLayout(PEImageLayout::LAYOUT_FLAT, 0);
2237 if (layout != NULL)
2238 {
2239 //cache a bunch of PE metadata in the PEDecoder
2240 m_ILimage->CheckILFormat();
2241
2242 //fudge this by a few pages to make sure we can still mess with the PE headers
2243 const size_t fudgeSize = 4096 * 4;
2244 ClrVirtualProtect((void*)(((char *)layout->GetBase()) + fudgeSize),
2245 layout->GetSize() - fudgeSize, 0, &ignored);
2246 layout->Release();
2247 }
2248#endif
2249 }
2250 else
2251 {
2252 ExternalLog(LL_WARNING, "Native image is not correct version.");
2253 }
2254}
2255
2256#endif // FEATURE_PREJIT
2257
2258#endif // #ifndef DACCESS_COMPILE
2259
2260
2261
2262#ifndef DACCESS_COMPILE
2263
2264// ------------------------------------------------------------
2265// Descriptive strings
2266// ------------------------------------------------------------
2267
2268// Effective path is the path of nearest parent (creator) assembly which has a nonempty path.
2269
2270const SString &PEAssembly::GetEffectivePath()
2271{
2272 CONTRACTL
2273 {
2274 INSTANCE_CHECK;
2275 NOTHROW;
2276 GC_NOTRIGGER;
2277 MODE_ANY;
2278 }
2279 CONTRACTL_END;
2280
2281 PEAssembly *pAssembly = this;
2282
2283 while (pAssembly->m_identity == NULL
2284 || pAssembly->m_identity->GetPath().IsEmpty())
2285 {
2286 if (pAssembly->m_creator)
2287 pAssembly = pAssembly->m_creator->GetAssembly();
2288 else // Unmanaged exe which loads byte[]/IStream assemblies
2289 return SString::Empty();
2290 }
2291
2292 return pAssembly->m_identity->GetPath();
2293}
2294
2295
2296// Codebase is the fusion codebase or path for the assembly. It is in URL format.
2297// Note this may be obtained from the parent PEFile if we don't have a path or fusion
2298// assembly.
2299//
2300// fCopiedName means to get the "shadow copied" path rather than the original path, if applicable
2301void PEAssembly::GetCodeBase(SString &result, BOOL fCopiedName/*=FALSE*/)
2302{
2303 CONTRACTL
2304 {
2305 INSTANCE_CHECK;
2306 THROWS;
2307 GC_TRIGGERS;
2308 MODE_ANY;
2309 INJECT_FAULT(COMPlusThrowOM(););
2310 }
2311 CONTRACTL_END;
2312
2313 // All other cases use the file path.
2314 result.Set(GetEffectivePath());
2315 if (!result.IsEmpty())
2316 PathToUrl(result);
2317}
2318
2319/* static */
2320void PEAssembly::PathToUrl(SString &string)
2321{
2322 CONTRACTL
2323 {
2324 PRECONDITION(PEImage::CheckCanonicalFullPath(string));
2325 THROWS;
2326 GC_NOTRIGGER;
2327 MODE_ANY;
2328 INJECT_FAULT(COMPlusThrowOM(););
2329 }
2330 CONTRACTL_END;
2331
2332 SString::Iterator i = string.Begin();
2333
2334#if !defined(PLATFORM_UNIX)
2335 if (i[0] == W('\\'))
2336 {
2337 // Network path
2338 string.Insert(i, SL("file://"));
2339 string.Skip(i, SL("file://"));
2340 }
2341 else
2342 {
2343 // Disk path
2344 string.Insert(i, SL("file:///"));
2345 string.Skip(i, SL("file:///"));
2346 }
2347#else
2348 // Unix doesn't have a distinction between a network or a local path
2349 _ASSERTE( i[0] == W('\\') || i[0] == W('/'));
2350 SString sss(SString::Literal, W("file://"));
2351 string.Insert(i, sss);
2352 string.Skip(i, sss);
2353#endif
2354
2355 while (string.Find(i, W('\\')))
2356 {
2357 string.Replace(i, W('/'));
2358 }
2359}
2360
2361void PEAssembly::UrlToPath(SString &string)
2362{
2363 CONTRACT_VOID
2364 {
2365 THROWS;
2366 GC_NOTRIGGER;
2367 }
2368 CONTRACT_END;
2369
2370 SString::Iterator i = string.Begin();
2371
2372 SString sss2(SString::Literal, W("file://"));
2373#if !defined(PLATFORM_UNIX)
2374 SString sss3(SString::Literal, W("file:///"));
2375 if (string.MatchCaseInsensitive(i, sss3))
2376 string.Delete(i, 8);
2377 else
2378#endif
2379 if (string.MatchCaseInsensitive(i, sss2))
2380 string.Delete(i, 7);
2381
2382 while (string.Find(i, W('/')))
2383 {
2384 string.Replace(i, W('\\'));
2385 }
2386
2387 RETURN;
2388}
2389
2390BOOL PEAssembly::FindLastPathSeparator(const SString &path, SString::Iterator &i)
2391{
2392#ifdef PLATFORM_UNIX
2393 SString::Iterator slash = i;
2394 SString::Iterator backSlash = i;
2395 BOOL foundSlash = path.FindBack(slash, '/');
2396 BOOL foundBackSlash = path.FindBack(backSlash, '\\');
2397 if (!foundSlash && !foundBackSlash)
2398 return FALSE;
2399 else if (foundSlash && !foundBackSlash)
2400 i = slash;
2401 else if (!foundSlash && foundBackSlash)
2402 i = backSlash;
2403 else
2404 i = (backSlash > slash) ? backSlash : slash;
2405 return TRUE;
2406#else
2407 return path.FindBack(i, '\\');
2408#endif //PLATFORM_UNIX
2409}
2410
2411
2412// ------------------------------------------------------------
2413// Logging
2414// ------------------------------------------------------------
2415#ifdef FEATURE_PREJIT
2416void PEAssembly::ExternalVLog(DWORD facility, DWORD level, const WCHAR *fmt, va_list args)
2417{
2418 CONTRACT_VOID
2419 {
2420 THROWS;
2421 GC_TRIGGERS;
2422 }
2423 CONTRACT_END;
2424
2425 PEFile::ExternalVLog(facility, level, fmt, args);
2426
2427
2428 RETURN;
2429}
2430
2431void PEAssembly::FlushExternalLog()
2432{
2433 CONTRACT_VOID
2434 {
2435 THROWS;
2436 GC_TRIGGERS;
2437 }
2438 CONTRACT_END;
2439
2440
2441 RETURN;
2442}
2443#endif //FEATURE_PREJIT
2444// ------------------------------------------------------------
2445// Metadata access
2446// ------------------------------------------------------------
2447
2448HRESULT PEFile::GetVersion(USHORT *pMajor, USHORT *pMinor, USHORT *pBuild, USHORT *pRevision)
2449{
2450 CONTRACTL
2451 {
2452 INSTANCE_CHECK;
2453 PRECONDITION(CheckPointer(pMajor, NULL_OK));
2454 PRECONDITION(CheckPointer(pMinor, NULL_OK));
2455 PRECONDITION(CheckPointer(pBuild, NULL_OK));
2456 PRECONDITION(CheckPointer(pRevision, NULL_OK));
2457 NOTHROW;
2458 WRAPPER(GC_TRIGGERS);
2459 MODE_ANY;
2460 }
2461 CONTRACTL_END;
2462
2463 AssemblyMetaDataInternal md;
2464 HRESULT hr = S_OK;;
2465 if (m_bHasPersistentMDImport)
2466 {
2467 _ASSERTE(GetPersistentMDImport()->IsValidToken(TokenFromRid(1, mdtAssembly)));
2468 IfFailRet(GetPersistentMDImport()->GetAssemblyProps(TokenFromRid(1, mdtAssembly), NULL, NULL, NULL, NULL, &md, NULL));
2469 }
2470 else
2471 {
2472 ReleaseHolder<IMDInternalImport> pImport(GetMDImportWithRef());
2473 _ASSERTE(pImport->IsValidToken(TokenFromRid(1, mdtAssembly)));
2474 IfFailRet(pImport->GetAssemblyProps(TokenFromRid(1, mdtAssembly), NULL, NULL, NULL, NULL, &md, NULL));
2475 }
2476
2477 if (pMajor != NULL)
2478 *pMajor = md.usMajorVersion;
2479 if (pMinor != NULL)
2480 *pMinor = md.usMinorVersion;
2481 if (pBuild != NULL)
2482 *pBuild = md.usBuildNumber;
2483 if (pRevision != NULL)
2484 *pRevision = md.usRevisionNumber;
2485
2486 return hr;
2487}
2488
2489
2490
2491void PEFile::EnsureImageOpened()
2492{
2493 WRAPPER_NO_CONTRACT;
2494 if (IsDynamic())
2495 return;
2496#ifdef FEATURE_PREJIT
2497 if(HasNativeImage())
2498 m_nativeImage->GetLayout(PEImageLayout::LAYOUT_ANY,PEImage::LAYOUT_CREATEIFNEEDED)->Release();
2499 else
2500#endif
2501 GetILimage()->GetLayout(PEImageLayout::LAYOUT_ANY,PEImage::LAYOUT_CREATEIFNEEDED)->Release();
2502}
2503
2504#endif // #ifndef DACCESS_COMPILE
2505
2506#ifdef DACCESS_COMPILE
2507
2508void
2509PEFile::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2510{
2511 WRAPPER_NO_CONTRACT;
2512 SUPPORTS_DAC;
2513
2514 // sizeof(PEFile) == 0xb8
2515 DAC_ENUM_VTHIS();
2516 EMEM_OUT(("MEM: %p PEFile\n", dac_cast<TADDR>(this)));
2517
2518#ifdef _DEBUG
2519 // Not a big deal if it's NULL or fails.
2520 m_debugName.EnumMemoryRegions(flags);
2521#endif
2522
2523 if (m_identity.IsValid())
2524 {
2525 m_identity->EnumMemoryRegions(flags);
2526 }
2527 if (GetILimage().IsValid())
2528 {
2529 GetILimage()->EnumMemoryRegions(flags);
2530 }
2531#ifdef FEATURE_PREJIT
2532 if (m_nativeImage.IsValid())
2533 {
2534 m_nativeImage->EnumMemoryRegions(flags);
2535 DacEnumHostDPtrMem(m_nativeImage->GetLoadedLayout()->GetNativeVersionInfo());
2536 }
2537#endif
2538}
2539
2540void
2541PEAssembly::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2542{
2543 WRAPPER_NO_CONTRACT;
2544
2545 PEFile::EnumMemoryRegions(flags);
2546
2547 if (m_creator.IsValid())
2548 {
2549 m_creator->EnumMemoryRegions(flags);
2550 }
2551}
2552
2553#endif // #ifdef DACCESS_COMPILE
2554
2555
2556//-------------------------------------------------------------------------------
2557// Make best-case effort to obtain an image name for use in an error message.
2558//
2559// This routine must expect to be called before the this object is fully loaded.
2560// It can return an empty if the name isn't available or the object isn't initialized
2561// enough to get a name, but it mustn't crash.
2562//-------------------------------------------------------------------------------
2563LPCWSTR PEFile::GetPathForErrorMessages()
2564{
2565 CONTRACTL
2566 {
2567 THROWS;
2568 GC_TRIGGERS;
2569 INJECT_FAULT(COMPlusThrowOM(););
2570 SUPPORTS_DAC_HOST_ONLY;
2571 }
2572 CONTRACTL_END
2573
2574 if (!IsDynamic())
2575 {
2576 return m_identity->GetPathForErrorMessages();
2577 }
2578 else
2579 {
2580 return W("");
2581 }
2582}
2583
2584
2585#ifdef DACCESS_COMPILE
2586TADDR PEFile::GetMDInternalRWAddress()
2587{
2588 if (!m_MDImportIsRW_Debugger_Use_Only)
2589 return 0;
2590 else
2591 {
2592 // This line of code is a bit scary, but it is correct for now at least...
2593 // 1) We are using 'm_pMDImport_Use_Accessor' directly, and not the accessor. The field is
2594 // named this way to prevent debugger code that wants a host implementation of IMDInternalImport
2595 // from accidentally trying to use this pointer. This pointer is a target pointer, not
2596 // a host pointer. However in this function we do want the target pointer, so the usage is
2597 // accurate.
2598 // 2) ASSUMPTION: We are assuming that the only valid implementation of RW metadata is
2599 // MDInternalRW. If that ever changes we would need some way to disambiguate, and
2600 // probably this entire code path would need to be redesigned.
2601 // 3) ASSUMPTION: We are assuming that no pointer adjustment is required to convert between
2602 // IMDInternalImport*, IMDInternalImportENC* and MDInternalRW*. Ideally I was hoping to do this with a
2603 // static_cast<> but the compiler complains that the ENC<->RW is an unrelated conversion.
2604 return (TADDR) m_pMDImport_UseAccessor;
2605 }
2606}
2607#endif
2608
2609// Returns the ICLRPrivBinder* instance associated with the PEFile
2610PTR_ICLRPrivBinder PEFile::GetBindingContext()
2611{
2612 LIMITED_METHOD_CONTRACT;
2613
2614 PTR_ICLRPrivBinder pBindingContext = NULL;
2615
2616 // CoreLibrary is always bound in context of the TPA Binder. However, since it gets loaded and published
2617 // during EEStartup *before* DefaultContext Binder (aka TPAbinder) is initialized, we dont have a binding context to publish against.
2618 // Thus, we will always return NULL for its binding context.
2619 if (!IsSystem())
2620 {
2621 pBindingContext = dac_cast<PTR_ICLRPrivBinder>(GetHostAssembly());
2622 if (!pBindingContext)
2623 {
2624 // If we do not have any binding context, check if we are dealing with
2625 // a dynamically emitted assembly and if so, use its fallback load context
2626 // binder reference.
2627 if (IsDynamic())
2628 {
2629 pBindingContext = GetFallbackLoadContextBinder();
2630 }
2631 }
2632 }
2633
2634 return pBindingContext;
2635}
2636