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// DomainFile.cpp
6//
7
8// --------------------------------------------------------------------------------
9
10
11#include "common.h"
12
13// --------------------------------------------------------------------------------
14// Headers
15// --------------------------------------------------------------------------------
16
17#include <shlwapi.h>
18
19#include "invokeutil.h"
20#include "eeconfig.h"
21#include "dynamicmethod.h"
22#include "field.h"
23#include "dbginterface.h"
24#include "eventtrace.h"
25
26#ifdef FEATURE_PREJIT
27#include <corcompile.h>
28#include "compile.h"
29#endif // FEATURE_PREJIT
30
31#include "dllimportcallback.h"
32#include "peimagelayout.inl"
33
34#include "winrthelpers.h"
35
36#ifdef FEATURE_PERFMAP
37#include "perfmap.h"
38#endif // FEATURE_PERFMAP
39
40#ifndef DACCESS_COMPILE
41DomainFile::DomainFile(AppDomain *pDomain, PEFile *pFile)
42 : m_pDomain(pDomain),
43 m_pFile(pFile),
44 m_pOriginalFile(NULL),
45 m_pModule(NULL),
46 m_level(FILE_LOAD_CREATE),
47 m_pError(NULL),
48 m_notifyflags(NOT_NOTIFIED),
49 m_loading(TRUE),
50 m_pDynamicMethodTable(NULL),
51 m_pUMThunkHash(NULL),
52 m_bDisableActivationCheck(FALSE),
53 m_dwReasonForRejectingNativeImage(0)
54{
55 CONTRACTL
56 {
57 CONSTRUCTOR_CHECK;
58 THROWS; // From CreateHandle
59 GC_NOTRIGGER;
60 MODE_ANY;
61 FORBID_FAULT;
62 }
63 CONTRACTL_END;
64
65 m_hExposedModuleObject = NULL;
66 pFile->AddRef();
67}
68
69DomainFile::~DomainFile()
70{
71 CONTRACTL
72 {
73 DESTRUCTOR_CHECK;
74 NOTHROW;
75 GC_TRIGGERS;
76 MODE_ANY;
77 }
78 CONTRACTL_END;
79
80 m_pFile->Release();
81 if(m_pOriginalFile)
82 m_pOriginalFile->Release();
83 if (m_pDynamicMethodTable)
84 m_pDynamicMethodTable->Destroy();
85 delete m_pError;
86}
87
88#endif //!DACCESS_COMPILE
89
90LoaderAllocator * DomainFile::GetLoaderAllocator()
91{
92 CONTRACTL
93 {
94 NOTHROW;
95 GC_NOTRIGGER;
96 SO_TOLERANT;
97 MODE_ANY;
98 }
99 CONTRACTL_END;
100 Assembly *pAssembly = GetDomainAssembly()->GetAssembly();
101 if ((pAssembly != NULL) && (pAssembly->IsCollectible()))
102 {
103 return pAssembly->GetLoaderAllocator();
104 }
105 else
106 {
107 return this->GetAppDomain()->GetLoaderAllocator();
108 }
109}
110
111#ifndef DACCESS_COMPILE
112
113void DomainFile::ReleaseFiles()
114{
115 WRAPPER_NO_CONTRACT;
116 Module* pModule=GetCurrentModule();
117 if(pModule)
118 pModule->StartUnload();
119
120 if (m_pFile)
121 m_pFile->ReleaseIL();
122 if(m_pOriginalFile)
123 m_pOriginalFile->ReleaseIL();
124
125 if(pModule)
126 pModule->ReleaseILData();
127}
128
129BOOL DomainFile::TryEnsureActive()
130{
131 CONTRACT(BOOL)
132 {
133 INSTANCE_CHECK;
134 THROWS;
135 GC_TRIGGERS;
136 }
137 CONTRACT_END;
138
139 BOOL success = TRUE;
140
141 EX_TRY
142 {
143 EnsureActive();
144 }
145 EX_CATCH
146 {
147 success = FALSE;
148 }
149 EX_END_CATCH(RethrowTransientExceptions);
150
151 RETURN success;
152}
153
154// Optimization intended for EnsureLoadLevel only
155#include <optsmallperfcritical.h>
156void DomainFile::EnsureLoadLevel(FileLoadLevel targetLevel)
157{
158 CONTRACT_VOID
159 {
160 INSTANCE_CHECK;
161 THROWS;
162 GC_TRIGGERS;
163 }
164 CONTRACT_END;
165
166 TRIGGERSGC ();
167 if (IsLoading())
168 {
169 this->GetAppDomain()->LoadDomainFile(this, targetLevel);
170
171 // Enforce the loading requirement. Note that we may have a deadlock in which case we
172 // may be off by one which is OK. (At this point if we are short of targetLevel we know
173 // we have done so because of reentrancy contraints.)
174
175 RequireLoadLevel((FileLoadLevel)(targetLevel-1));
176 }
177 else
178 ThrowIfError(targetLevel);
179
180 RETURN;
181}
182#include <optdefault.h>
183
184void DomainFile::AttemptLoadLevel(FileLoadLevel targetLevel)
185{
186 CONTRACT_VOID
187 {
188 INSTANCE_CHECK;
189 THROWS;
190 GC_TRIGGERS;
191 }
192 CONTRACT_END;
193
194 if (IsLoading())
195 this->GetAppDomain()->LoadDomainFile(this, targetLevel);
196 else
197 ThrowIfError(targetLevel);
198
199 RETURN;
200}
201
202
203CHECK DomainFile::CheckLoadLevel(FileLoadLevel requiredLevel, BOOL deadlockOK)
204{
205 CONTRACTL
206 {
207 INSTANCE_CHECK;
208 NOTHROW;
209 GC_NOTRIGGER;
210 }
211 CONTRACTL_END;
212
213 if (deadlockOK)
214 {
215#ifndef CROSSGEN_COMPILE
216 // CheckLoading requires waiting on a host-breakable lock.
217 // Since this is only a checked-build assert and we've been
218 // living with it for a while, I'll leave it as is.
219 //@TODO: CHECK statements are *NOT* debug-only!!!
220 CONTRACT_VIOLATION(ThrowsViolation|GCViolation|TakesLockViolation);
221 CHECK(this->GetAppDomain()->CheckLoading(this, requiredLevel));
222#endif
223 }
224 else
225 {
226 CHECK_MSG(m_level >= requiredLevel,
227 "File not sufficiently loaded");
228 }
229
230 CHECK_OK;
231}
232
233
234
235void DomainFile::RequireLoadLevel(FileLoadLevel targetLevel)
236{
237 CONTRACT_VOID
238 {
239 INSTANCE_CHECK;
240 THROWS;
241 GC_TRIGGERS;
242 }
243 CONTRACT_END;
244
245 if (GetLoadLevel() < targetLevel)
246 {
247 ThrowIfError(targetLevel);
248 ThrowHR(MSEE_E_ASSEMBLYLOADINPROGRESS); // @todo: better exception
249 }
250
251 RETURN;
252}
253
254
255void DomainFile::SetError(Exception *ex)
256{
257 CONTRACT_VOID
258 {
259 PRECONDITION(!IsError());
260 PRECONDITION(ex != NULL);
261 INSTANCE_CHECK;
262 THROWS;
263 GC_TRIGGERS;
264 POSTCONDITION(IsError());
265 }
266 CONTRACT_END;
267
268 m_pError = new ExInfo(ex->DomainBoundClone());
269
270 GetCurrentModule()->NotifyEtwLoadFinished(ex->GetHR());
271
272 if (!IsProfilerNotified())
273 {
274 SetProfilerNotified();
275
276#ifdef PROFILING_SUPPORTED
277 if (GetCurrentModule() != NULL)
278 {
279 // Only send errors for non-shared assemblies; other assemblies might be successfully completed
280 // in another app domain later.
281 GetCurrentModule()->NotifyProfilerLoadFinished(ex->GetHR());
282 }
283#endif
284 }
285
286 RETURN;
287}
288
289void DomainFile::ThrowIfError(FileLoadLevel targetLevel)
290{
291 CONTRACT_VOID
292 {
293 INSTANCE_CHECK;
294 MODE_ANY;
295 THROWS;
296 GC_TRIGGERS;
297 }
298 CONTRACT_END;
299
300 if (m_level < targetLevel)
301 {
302 if (m_pError)
303 m_pError->Throw();
304 }
305
306 RETURN;
307}
308
309CHECK DomainFile::CheckNoError(FileLoadLevel targetLevel)
310{
311 LIMITED_METHOD_CONTRACT;
312 CHECK(m_level >= targetLevel
313 || !IsError());
314
315 CHECK_OK;
316}
317
318CHECK DomainFile::CheckLoaded()
319{
320 CONTRACTL
321 {
322 INSTANCE_CHECK;
323 NOTHROW;
324 GC_NOTRIGGER;
325 MODE_ANY;
326 }
327 CONTRACTL_END;
328
329 CHECK_MSG(CheckNoError(FILE_LOADED), "DomainFile load resulted in an error");
330
331 if (IsLoaded())
332 CHECK_OK;
333
334 // Mscorlib is allowed to run managed code much earlier than other
335 // assemblies for bootstrapping purposes. This is because it has no
336 // dependencies, security checks, and doesn't rely on loader notifications.
337
338 if (GetFile()->IsSystem())
339 CHECK_OK;
340
341 CHECK_MSG(GetFile()->CheckLoaded(), "PEFile has not been loaded");
342
343 CHECK_OK;
344}
345
346CHECK DomainFile::CheckActivated()
347{
348 CONTRACTL
349 {
350 INSTANCE_CHECK;
351 NOTHROW;
352 GC_NOTRIGGER;
353 MODE_ANY;
354 }
355 CONTRACTL_END;
356
357 CHECK_MSG(CheckNoError(FILE_ACTIVE), "DomainFile load resulted in an error");
358
359 if (IsActive())
360 CHECK_OK;
361
362 // Mscorlib is allowed to run managed code much earlier than other
363 // assemblies for bootstrapping purposes. This is because it has no
364 // dependencies, security checks, and doesn't rely on loader notifications.
365
366 if (GetFile()->IsSystem())
367 CHECK_OK;
368
369 CHECK_MSG(GetFile()->CheckLoaded(), "PEFile has not been loaded");
370 CHECK_MSG(IsLoaded(), "DomainFile has not been fully loaded");
371 CHECK_MSG(m_bDisableActivationCheck || CheckLoadLevel(FILE_ACTIVE), "File has not had execution verified");
372
373 CHECK_OK;
374}
375
376#endif //!DACCESS_COMPILE
377
378DomainAssembly *DomainFile::GetDomainAssembly()
379{
380 CONTRACTL
381 {
382 SUPPORTS_DAC;
383 NOTHROW;
384 GC_NOTRIGGER;
385 SO_TOLERANT;
386 }
387 CONTRACTL_END;
388
389 _ASSERTE(IsAssembly());
390 return (DomainAssembly *) this;
391}
392
393// Return true iff the debugger should get notifications about this assembly.
394//
395// Notes:
396// The debuggee may be stopped while a DomainAssmebly is being initialized. In this time window,
397// GetAssembly() may be NULL. If that's the case, this function has to return FALSE. Later on, when
398// the DomainAssembly is fully initialized, this function will return TRUE. This is the only scenario
399// where this function is mutable. In other words, a DomainAssembly can only change from being invisible
400// to visible, but NOT vice versa. Once a DomainAssmebly is fully initialized, this function should be
401// immutable for an instance of a module. That ensures that the debugger gets consistent
402// notifications about it. It this value mutates, than the debugger may miss relevant notifications.
403BOOL DomainAssembly::IsVisibleToDebugger()
404{
405 WRAPPER_NO_CONTRACT;
406 SUPPORTS_DAC;
407
408 return (GetAssembly() != NULL);
409}
410
411#ifndef DACCESS_COMPILE
412#ifdef FEATURE_PREJIT
413void DomainFile::ExternalLog(DWORD level, const WCHAR *fmt, ...)
414{
415 WRAPPER_NO_CONTRACT;
416
417 va_list args;
418 va_start(args, fmt);
419
420 GetOriginalFile()->ExternalVLog(LF_ZAP, level, fmt, args);
421
422 va_end(args);
423}
424
425void DomainFile::ExternalLog(DWORD level, const char *msg)
426{
427 WRAPPER_NO_CONTRACT;
428
429 GetOriginalFile()->ExternalLog(level, msg);
430}
431#endif
432
433#ifndef CROSSGEN_COMPILE
434//---------------------------------------------------------------------------------------
435//
436// Returns managed representation of the module (Module or ModuleBuilder).
437// Returns NULL if the managed scout was already collected (see code:LoaderAllocator#AssemblyPhases).
438//
439OBJECTREF DomainFile::GetExposedModuleObject()
440{
441 CONTRACTL
442 {
443 INSTANCE_CHECK;
444 THROWS;
445 MODE_COOPERATIVE;
446 GC_TRIGGERS;
447 }
448 CONTRACTL_END;
449
450 LoaderAllocator * pLoaderAllocator = GetLoaderAllocator();
451
452 if (m_hExposedModuleObject == NULL)
453 {
454 // Atomically create a handle
455 LOADERHANDLE handle = pLoaderAllocator->AllocateHandle(NULL);
456
457 FastInterlockCompareExchangePointer(&m_hExposedModuleObject, handle, static_cast<LOADERHANDLE>(NULL));
458 }
459
460 if (pLoaderAllocator->GetHandleValue(m_hExposedModuleObject) == NULL)
461 {
462 REFLECTMODULEBASEREF refClass = NULL;
463
464 // Will be TRUE only if LoaderAllocator managed object was already collected and therefore we should
465 // return NULL
466 BOOL fIsLoaderAllocatorCollected = FALSE;
467
468 GCPROTECT_BEGIN(refClass);
469
470 if (GetFile()->IsDynamic())
471 {
472 refClass = (REFLECTMODULEBASEREF) AllocateObject(MscorlibBinder::GetClass(CLASS__MODULE_BUILDER));
473 }
474 else
475 {
476 refClass = (REFLECTMODULEBASEREF) AllocateObject(MscorlibBinder::GetClass(CLASS__MODULE));
477 }
478 refClass->SetModule(m_pModule);
479
480 // Attach the reference to the assembly to keep the LoaderAllocator for this collectible type
481 // alive as long as a reference to the module is kept alive.
482 if (GetModule()->GetAssembly() != NULL)
483 {
484 OBJECTREF refAssembly = GetModule()->GetAssembly()->GetExposedObject();
485 if ((refAssembly == NULL) && GetModule()->GetAssembly()->IsCollectible())
486 {
487 fIsLoaderAllocatorCollected = TRUE;
488 }
489 refClass->SetAssembly(refAssembly);
490 }
491
492 pLoaderAllocator->CompareExchangeValueInHandle(m_hExposedModuleObject, (OBJECTREF)refClass, NULL);
493 GCPROTECT_END();
494
495 if (fIsLoaderAllocatorCollected)
496 { // The LoaderAllocator managed object was already collected, we cannot re-create it
497 // Note: We did not publish the allocated Module/ModuleBuilder object, it will get collected
498 // by GC
499 return NULL;
500 }
501 }
502
503 return pLoaderAllocator->GetHandleValue(m_hExposedModuleObject);
504} // DomainFile::GetExposedModuleObject
505#endif // CROSSGEN_COMPILE
506
507BOOL DomainFile::DoIncrementalLoad(FileLoadLevel level)
508{
509 STANDARD_VM_CONTRACT;
510
511 if (IsError())
512 return FALSE;
513
514 Thread *pThread;
515 pThread = GetThread();
516 _ASSERTE(pThread);
517 INTERIOR_STACK_PROBE_FOR(pThread, 8);
518
519 switch (level)
520 {
521 case FILE_LOAD_BEGIN:
522 Begin();
523 break;
524
525 case FILE_LOAD_FIND_NATIVE_IMAGE:
526#ifdef FEATURE_PREJIT
527 FindNativeImage();
528#endif
529 break;
530
531 case FILE_LOAD_VERIFY_NATIVE_IMAGE_DEPENDENCIES:
532#ifdef FEATURE_PREJIT
533 VerifyNativeImageDependencies();
534#endif
535 break;
536
537 case FILE_LOAD_ALLOCATE:
538 Allocate();
539 break;
540
541 case FILE_LOAD_ADD_DEPENDENCIES:
542 AddDependencies();
543 break;
544
545 case FILE_LOAD_PRE_LOADLIBRARY:
546 PreLoadLibrary();
547 break;
548
549 case FILE_LOAD_LOADLIBRARY:
550 LoadLibrary();
551 break;
552
553 case FILE_LOAD_POST_LOADLIBRARY:
554 PostLoadLibrary();
555 break;
556
557 case FILE_LOAD_EAGER_FIXUPS:
558 EagerFixups();
559 break;
560
561 case FILE_LOAD_VTABLE_FIXUPS:
562 VtableFixups();
563 break;
564
565 case FILE_LOAD_DELIVER_EVENTS:
566 DeliverSyncEvents();
567 break;
568
569 case FILE_LOADED:
570 FinishLoad();
571 break;
572
573 case FILE_LOAD_VERIFY_EXECUTION:
574 VerifyExecution();
575 break;
576
577 case FILE_ACTIVE:
578 Activate();
579 break;
580
581 default:
582 UNREACHABLE();
583 }
584
585 END_INTERIOR_STACK_PROBE;
586
587#ifdef FEATURE_MULTICOREJIT
588 {
589 Module * pModule = GetModule();
590
591 if (pModule != NULL) // Should not triggle assert when module is NULL
592 {
593 this->GetAppDomain()->GetMulticoreJitManager().RecordModuleLoad(pModule, level);
594 }
595 }
596#endif
597
598 return TRUE;
599}
600
601#ifdef FEATURE_PREJIT
602
603void DomainFile::VerifyNativeImageDependencies(bool verifyOnly)
604{
605 CONTRACTL
606 {
607 INSTANCE_CHECK;
608 STANDARD_VM_CHECK;
609 PRECONDITION(verifyOnly || (m_pDomain->GetDomainFileLoadLevel(this) ==
610 FILE_LOAD_FIND_NATIVE_IMAGE));
611 }
612 CONTRACTL_END;
613
614 // This function gets called multiple times. The first call is the real work.
615 // Subsequent calls are only to verify that everything still looks OK.
616 if (!verifyOnly)
617 ClearNativeImageStress();
618
619 if (!m_pFile->HasNativeImage())
620 {
621 CheckZapRequired();
622 return;
623 }
624
625 {
626 // Go through native dependencies & make sure they still have their prejit images after
627 // the security check.
628 // NOTE: we could theoretically do this without loading the dependencies, if we cache the
629 // COR_TRUST structures from the dependencies in the version information.
630 //
631 // Verify that all of our hard dependencies are loaded at the right base address.
632 // If not, abandon prejit image (or fix ours up)
633 // Also, if there are any hard dependencies, then our native image also needs to be
634 // loaded at the right base address
635
636 // Note: we will go through all of our dependencies, call Load on them, and check the base
637 // addresses & identity.
638 // It is important to note that all of those dependencies are also going to do the
639 // same thing, so we might conceivably check a base address as OK, and then have that image
640 // abandoned by that assembly during its VerifyNativeImageDependencies phase.
641 // However, we avoid this problem since the hard depedencies stored are a closure of the
642 // hard dependencies of an image. This effectively means that our check here is a superset
643 // of the check that the dependencies will perform. Even if we hit a dependency loop, we
644 // will still guarantee that we've examined all of our dependencies.
645
646 ReleaseHolder<PEImage> pNativeImage = m_pFile->GetNativeImageWithRef();
647 if(pNativeImage==NULL)
648 {
649 CheckZapRequired();
650 return;
651 }
652
653 PEImageLayout* pNativeLayout = pNativeImage->GetLoadedLayout();
654
655 // reuse same codepath for both manifest and non-manifest modules
656 ReleaseHolder<PEImage> pManifestNativeImage(NULL);
657
658 PEFile* pManifestFile = m_pFile;
659 PEImageLayout* pManifestNativeLayout = pNativeLayout;
660
661 if (!IsAssembly())
662 {
663 pManifestFile = GetDomainAssembly()->GetCurrentAssembly()
664 ->GetManifestModule()->GetFile();
665
666 pManifestNativeImage = pManifestFile->GetNativeImageWithRef();
667
668 if (pManifestNativeImage == NULL)
669 {
670 ExternalLog(LL_ERROR, "Rejecting native image because there is no "
671 "ngen image for manifest module. Check why the manifest module "
672 "does not have an ngen image");
673 m_dwReasonForRejectingNativeImage = ReasonForRejectingNativeImage_NoNiForManifestModule;
674 STRESS_LOG3(LF_ZAP,LL_INFO100,"Rejecting native file %p, because its manifest module %p has no NI - reason 0x%x\n",pNativeImage.GetValue(),pManifestFile,m_dwReasonForRejectingNativeImage);
675 goto NativeImageRejected;
676 }
677
678 return;
679 }
680
681 COUNT_T cDependencies;
682 CORCOMPILE_DEPENDENCY *pDependencies = pManifestNativeLayout->GetNativeDependencies(&cDependencies);
683
684 LOG((LF_ZAP, LL_INFO100, "ZAP: Checking native image dependencies for %S.\n",
685 pNativeImage->GetPath().GetUnicode()));
686
687 for (COUNT_T iDependency = 0; iDependency < cDependencies; iDependency++)
688 {
689 CORCOMPILE_DEPENDENCY *pDependency = &(pDependencies[iDependency]);
690
691 // Later, for domain neutral assemblies, we will also want to verify security policy
692 // in such cases, the prejit image should store the publisher info for the dependencies
693 // for us.
694
695 // If this is not a hard-bound dependency, then skip to the next dependency
696 if (pDependency->signNativeImage == INVALID_NGEN_SIGNATURE)
697 continue;
698
699
700 //
701 // CoreCLR hard binds to mscorlib.dll only. Avoid going through the full load.
702 //
703
704#ifdef _DEBUG
705 AssemblySpec name;
706 name.InitializeSpec(pDependency->dwAssemblyRef,
707 ((pManifestNativeImage != NULL) ? pManifestNativeImage : pNativeImage)->GetNativeMDImport(),
708 GetDomainAssembly());
709 _ASSERTE(name.IsMscorlib());
710#endif
711
712 PEAssembly * pDependencyFile = SystemDomain::SystemFile();
713
714
715 ReleaseHolder<PEImage> pDependencyNativeImage = pDependencyFile->GetNativeImageWithRef();
716 if (pDependencyNativeImage == NULL)
717 {
718 ExternalLog(LL_ERROR, W("Rejecting native image because dependency %s is not native"),
719 pDependencyFile->GetPath().GetUnicode());
720 m_dwReasonForRejectingNativeImage = ReasonForRejectingNativeImage_DependencyNotNative;
721 STRESS_LOG3(LF_ZAP,LL_INFO100,"Rejecting native file %p, because dependency %p is not NI - reason 0x%x\n",pNativeImage.GetValue(),pDependencyFile,m_dwReasonForRejectingNativeImage);
722 goto NativeImageRejected;
723 }
724
725 PTR_PEImageLayout pDependencyNativeLayout = pDependencyNativeImage->GetLoadedLayout();
726 // Assert that the native image signature is as expected
727 // Fusion will ensure this
728 CORCOMPILE_VERSION_INFO * pDependencyNativeVersion =
729 pDependencyNativeLayout->GetNativeVersionInfo();
730
731 if (!RuntimeVerifyNativeImageDependency(pDependency, pDependencyNativeVersion, pDependencyFile))
732 goto NativeImageRejected;
733 }
734 LOG((LF_ZAP, LL_INFO100, "ZAP: Native image dependencies for %S OK.\n",
735 pNativeImage->GetPath().GetUnicode()));
736
737 return;
738}
739
740NativeImageRejected:
741 m_pFile->ClearNativeImage();
742 m_pFile->SetCannotUseNativeImage();
743
744 CheckZapRequired();
745
746 return;
747}
748
749BOOL DomainFile::IsZapRequired()
750{
751 CONTRACTL
752 {
753 INSTANCE_CHECK;
754 THROWS;
755 GC_TRIGGERS;
756 MODE_ANY;
757 INJECT_FAULT(COMPlusThrowOM(););
758 }
759 CONTRACTL_END;
760
761 if (!m_pFile->HasMetadata() || !g_pConfig->RequireZap(GetSimpleName()))
762 return FALSE;
763
764#if defined(_DEBUG)
765 // If we're intentionally treating NIs as if they were MSIL assemblies, and the test
766 // is flexible enough to accept that (e.g., complus_zaprequired=2), then zaps are not
767 // required (i.e., it's ok for m_pFile->m_nativeImage to be NULL), but only if we
768 // loaded an actual NI to be treated as an IL assembly
769 if (PEFile::ShouldTreatNIAsMSIL())
770 {
771 // Since the RequireZap() call above returned true, we know that some level of
772 // zap requiredness was configured
773 _ASSERTE(g_pConfig->RequireZaps() != EEConfig::REQUIRE_ZAPS_NONE);
774
775 // If config uses this special value (2), zaps are not required, so long as
776 // we're using an actual NI as IL
777 if ((g_pConfig->RequireZaps() == EEConfig::REQUIRE_ZAPS_ALL_JIT_OK) &&
778 m_pFile->HasOpenedILimage() &&
779 m_pFile->GetOpenedILimage()->HasNativeHeader())
780 {
781 return FALSE;
782 }
783 }
784#endif // defined(_DEBUG)
785
786 // Does this look like a resource-only assembly? We assume an assembly is resource-only
787 // if it contains no TypeDef (other than the <Module> TypeDef) and no MethodDef.
788 // Note that pMD->GetCountWithTokenKind(mdtTypeDef) doesn't count the <Module> type.
789 IMDInternalImportHolder pMD = m_pFile->GetMDImport();
790 if (pMD->GetCountWithTokenKind(mdtTypeDef) == 0 && pMD->GetCountWithTokenKind(mdtMethodDef) == 0)
791 return FALSE;
792
793 DomainAssembly * pDomainAssembly = GetDomainAssembly();
794
795 // If the manifest module does not have an ngen image, the non-manifest
796 // modules cannot either
797 if (m_pFile->IsModule() && !pDomainAssembly->GetFile()->CanUseNativeImage())
798 m_pFile->SetCannotUseNativeImage();
799
800 // Some cases are not supported by design. They can never have a native image.
801 // So ignore such cases
802
803 if (!m_pFile->CanUseNativeImage() &&
804 g_pConfig->RequireZaps() == EEConfig::REQUIRE_ZAPS_SUPPORTED)
805 return FALSE;
806
807#ifdef FEATURE_NATIVE_IMAGE_GENERATION
808 if (IsCompilationProcess())
809 {
810 // Ignore the assembly being ngened.
811
812 bool fileIsBeingNGened = false;
813
814 if (this->GetAppDomain()->IsCompilationDomain())
815 {
816 Assembly * assemblyBeingNGened = this->GetAppDomain()->ToCompilationDomain()->GetTargetAssembly();
817 if (assemblyBeingNGened == NULL || assemblyBeingNGened == pDomainAssembly->GetCurrentAssembly())
818 fileIsBeingNGened = true;
819 }
820 else if (IsSystem())
821 {
822 // mscorlib gets loaded before the CompilationDomain gets created.
823 // However, we may be ngening mscorlib itself
824 fileIsBeingNGened = true;
825 }
826
827 if (fileIsBeingNGened)
828 return FALSE;
829 }
830#endif
831
832 return TRUE;
833}
834
835void DomainFile::CheckZapRequired()
836{
837 CONTRACTL
838 {
839 INSTANCE_CHECK;
840 THROWS;
841 GC_TRIGGERS;
842 MODE_ANY;
843 INJECT_FAULT(COMPlusThrowOM(););
844 }
845 CONTRACTL_END;
846
847 if (m_pFile->HasNativeImage() || !IsZapRequired())
848 return;
849
850#ifdef FEATURE_READYTORUN
851 if(m_pFile->GetLoaded()->HasReadyToRunHeader())
852 return;
853#endif
854
855 // Flush any log messages
856 GetFile()->FlushExternalLog();
857
858 StackSString ss;
859 ss.Printf("ZapRequire: Could not get native image for %s.\n"
860 "Use FusLogVw.exe to check the reason.",
861 GetSimpleName());
862
863#if defined(_DEBUG)
864 // Assert as some test may not check their error codes well. So throwing an
865 // exception may not cause a test failure (as it should).
866 StackScratchBuffer scratch;
867 DbgAssertDialog(__FILE__, __LINE__, (char*)ss.GetUTF8(scratch));
868#endif // defined(_DEBUG)
869
870 COMPlusThrowNonLocalized(kFileNotFoundException, ss.GetUnicode());
871}
872
873// Discarding an ngen image can cause problems. For more coverage,
874// this stress-mode discards ngen images even if not needed.
875
876void DomainFile::ClearNativeImageStress()
877{
878 WRAPPER_NO_CONTRACT;
879
880#ifdef _DEBUG
881 static ConfigDWORD clearNativeImageStress;
882 DWORD stressPercentage = clearNativeImageStress.val(CLRConfig::INTERNAL_clearNativeImageStress);
883 _ASSERTE(stressPercentage <= 100);
884 if (stressPercentage == 0 || !GetFile()->HasNativeImage())
885 return;
886
887 // Note that discarding a native image can affect dependencies. So its not enough
888 // to only check DomainFile::IsZapRequired() here.
889 if (g_pConfig->RequireZaps() != EEConfig::REQUIRE_ZAPS_NONE)
890 return;
891
892 // Its OK to ClearNativeImage even for a shared assembly, as the current PEFile will
893 // be discarded if we decide to share the assembly. However, we always use the same
894 // PEFile for the system assembly. So discarding the native image in the current
895 // AppDomain will actually affect the system assembly in the shared domain, and other
896 // appdomains may have already committed to using its ngen image.
897 if (GetFile()->IsSystem() && !this->GetAppDomain()->IsDefaultDomain())
898 return;
899
900 if (g_IBCLogger.InstrEnabled())
901 return;
902
903 ULONG hash = HashStringA(GetSimpleName());
904
905 // Hash in the FileLoadLevel so that we make a different decision for every level.
906 FileLoadLevel fileLoadLevel = m_pDomain->GetDomainFileLoadLevel(this);
907 hash ^= ULONG(fileLoadLevel);
908 // We do not discard native images after this level
909 _ASSERTE(fileLoadLevel < FILE_LOAD_VERIFY_NATIVE_IMAGE_DEPENDENCIES);
910
911 // Different app-domains should make different decisions
912 hash ^= HashString(this->GetAppDomain()->GetFriendlyName());
913
914#ifdef FEATURE_NATIVE_IMAGE_GENERATION
915 // Since DbgRandomOnHashAndExe() is not so random under ngen.exe, also
916 // factor in the module being compiled
917 if (this->GetAppDomain()->IsCompilationDomain())
918 {
919 Module * module = this->GetAppDomain()->ToCompilationDomain()->GetTargetModule();
920 // Has the target module been set yet?
921 if (module)
922 hash ^= HashStringA(module->GetSimpleName());
923 }
924#endif
925
926 if (DbgRandomOnHashAndExe(hash, float(stressPercentage)/100))
927 {
928 GetFile()->SetCannotUseNativeImage();
929 GetFile()->ClearNativeImage();
930 ExternalLog(LL_ERROR, "Rejecting native image for **clearNativeImageStress**");
931 }
932#endif
933}
934
935#endif // FEATURE_PREJIT
936
937void DomainFile::PreLoadLibrary()
938{
939 CONTRACTL
940 {
941 INSTANCE_CHECK;
942 STANDARD_VM_CHECK;
943 }
944 CONTRACTL_END;
945
946} // DomainFile::PreLoadLibrary
947
948// Note that this is the sole loading function which must be called OUTSIDE THE LOCK, since
949// it will potentially involve the OS loader lock.
950void DomainFile::LoadLibrary()
951{
952 CONTRACTL
953 {
954 INSTANCE_CHECK;
955 STANDARD_VM_CHECK;
956 }
957 CONTRACTL_END;
958
959 Thread::LoadingFileHolder holder(GetThread());
960 GetThread()->SetLoadingFile(this);
961 GetFile()->LoadLibrary();
962}
963
964void DomainFile::PostLoadLibrary()
965{
966 CONTRACTL
967 {
968 INSTANCE_CHECK;
969 // Note that GetFile()->LoadLibrary must be called before this OUTSIDE OF THE LOCKS
970 PRECONDITION(GetFile()->CheckLoaded());
971 STANDARD_VM_CHECK;
972 }
973 CONTRACTL_END;
974
975#ifdef FEATURE_PREJIT
976 if (GetFile()->HasNativeImage())
977 {
978 InsertIntoDomainFileWithNativeImageList();
979 }
980#endif
981#ifdef PROFILING_SUPPORTED
982 // After this point, it is possible to load types.
983 // We need to notify the profiler now because the profiler may need to inject methods into
984 // the module, and to do so reliably, it must have the chance to do so before
985 // any types are loaded from the module.
986 //
987 // In the past we only allowed injecting types/methods on non-NGEN images so notifying here
988 // worked ok, but for NGEN images this is pretty ugly. Rejitting often occurs in this callback,
989 // but then during fixup the results of LoadedMethodDesc iterator would change and we would
990 // need to re-iterate everything. Aside from Rejit other code often wasn't designed to handle
991 // running before Fixup. A concrete example VS recently hit, calling GetClassLayout using
992 // a MethodTable which doesn't need restore but its parent pointer isn't fixed up yet.
993 // We've already set the rules so that profilers can't modify the member list of types in NGEN images
994 // so it doesn't matter if types are pre-loaded. We only need the guarantee that code for the
995 // loaded types won't execute yet. For NGEN images we deliver the load notification in
996 // FILE_LOAD_DELIVER_EVENTS.
997 if (!GetFile()->HasNativeImage())
998 {
999 if (!IsProfilerNotified())
1000 {
1001 SetProfilerNotified();
1002 GetCurrentModule()->NotifyProfilerLoadFinished(S_OK);
1003 }
1004 }
1005
1006#endif
1007}
1008
1009void DomainFile::AddDependencies()
1010{
1011 STANDARD_VM_CONTRACT;
1012
1013#ifdef FEATURE_PREJIT
1014
1015 //
1016 // CoreCLR hard binds to mscorlib.dll only. No need to track hardbound dependencies.
1017 //
1018
1019#endif // FEATURE_PREJIT
1020}
1021
1022void DomainFile::EagerFixups()
1023{
1024 WRAPPER_NO_CONTRACT;
1025
1026#ifdef FEATURE_PREJIT
1027 if (GetCurrentModule()->HasNativeImage())
1028 {
1029 GetCurrentModule()->RunEagerFixups();
1030 }
1031#ifdef FEATURE_READYTORUN
1032 else
1033 if (GetCurrentModule()->IsReadyToRun())
1034 {
1035#ifndef CROSSGEN_COMPILE
1036 GetCurrentModule()->RunEagerFixups();
1037#endif
1038
1039 PEImageLayout * pLayout = GetCurrentModule()->GetReadyToRunInfo()->GetImage();
1040
1041 TADDR base = dac_cast<TADDR>(pLayout->GetBase());
1042
1043 ExecutionManager::AddCodeRange(base, base + (TADDR)pLayout->GetVirtualSize(),
1044 ExecutionManager::GetReadyToRunJitManager(),
1045 RangeSection::RANGE_SECTION_READYTORUN,
1046 GetCurrentModule() /* (void *)pLayout */);
1047 }
1048#endif // FEATURE_READYTORUN
1049
1050#endif // FEATURE_PREJIT
1051}
1052
1053void DomainFile::VtableFixups()
1054{
1055 WRAPPER_NO_CONTRACT;
1056
1057#if !defined(CROSSGEN_COMPILE)
1058 if (!GetCurrentModule()->IsResource())
1059 GetCurrentModule()->FixupVTables();
1060#endif // !CROSSGEN_COMPILE
1061}
1062
1063void DomainFile::FinishLoad()
1064{
1065 CONTRACTL
1066 {
1067 INSTANCE_CHECK;
1068 STANDARD_VM_CHECK;
1069 }
1070 CONTRACTL_END;
1071
1072#ifdef FEATURE_PREJIT
1073
1074 if (m_pFile->HasNativeImage())
1075 {
1076
1077 LOG((LF_ZAP, LL_INFO10, "Using native image %S.\n", m_pFile->GetPersistentNativeImage()->GetPath().GetUnicode()));
1078 ExternalLog(LL_INFO10, "Native image successfully used.");
1079
1080 // Inform metadata that it has been loaded from a native image
1081 // (and so there was an opportunity to check for or fix inconsistencies in the original IL metadata)
1082 m_pFile->GetMDImport()->SetVerifiedByTrustedSource(TRUE);
1083 }
1084
1085 // Are we absolutely required to use a native image?
1086 CheckZapRequired();
1087
1088#if defined(FEATURE_COMINTEROP)
1089 // If this is a winmd file, ensure that the ngen reference namespace is loadable.
1090 // This is necessary as on the phone we don't check ngen image dependencies, and thus we can get in a situation
1091 // where a winmd is loaded as a dependency of an ngen image, but the type used to build cross module references
1092 // in winmd files isn't loaded.
1093 if (GetFile()->AsAssembly()->IsWindowsRuntime() && GetFile()->HasHostAssembly())
1094 {
1095 IMDInternalImport *pImport = GetFile()->GetPersistentMDImport();
1096 LPCSTR szNameSpace;
1097 LPCSTR szTypeName;
1098 // It does not make sense to pass the file name to recieve fake type name for empty WinMDs, because we would use the name
1099 // for binding in next call to BindAssemblySpec which would fail for fake WinRT type name
1100 // We will throw/return the error instead and the caller will recognize it and react to it by not creating the ngen image -
1101 // see code:Zapper::ComputeDependenciesInCurrentDomain
1102 if (SUCCEEDED(::GetFirstWinRTTypeDef(pImport, &szNameSpace, &szTypeName, NULL, NULL)))
1103 {
1104 // Build assembly spec to describe binding to that WinRT type.
1105 AssemblySpec spec;
1106 IfFailThrow(spec.Init("WindowsRuntimeAssemblyName, ContentType=WindowsRuntime"));
1107 spec.SetWindowsRuntimeType(szNameSpace, szTypeName);
1108
1109 // Bind to assembly using the CLRPriv binder infrastructure. (All WinRT loads are done through CLRPriv binders
1110 ReleaseHolder<IAssemblyName> pAssemblyName;
1111 IfFailThrow(spec.CreateFusionName(&pAssemblyName, FALSE, TRUE));
1112 ReleaseHolder<ICLRPrivAssembly> pPrivAssembly;
1113 IfFailThrow(GetFile()->GetHostAssembly()->BindAssemblyByName(pAssemblyName, &pPrivAssembly));
1114
1115 // Verify that we found this. If this invariant doesn't hold, then the ngen images that reference this winmd are be invalid.
1116 // ALSO, this winmd file is invalid as it doesn't follow spec about how it is distributed.
1117 if (GetAppDomain()->FindAssembly(pPrivAssembly) != this)
1118 {
1119 ThrowHR(COR_E_BADIMAGEFORMAT);
1120 }
1121 }
1122 }
1123#endif //defined(FEATURE_COMINTEROP)
1124#endif // FEATURE_PREJIT
1125
1126 // Flush any log messages
1127#ifdef FEATURE_PREJIT
1128 GetFile()->FlushExternalLog();
1129#endif
1130 // Must set this a bit prematurely for the DAC stuff to work
1131 m_level = FILE_LOADED;
1132
1133 // Now the DAC can find this module by enumerating assemblies in a domain.
1134 DACNotify::DoModuleLoadNotification(m_pModule);
1135
1136#if defined(DEBUGGING_SUPPORTED) && !defined(DACCESS_COMPILE)
1137 if (IsDebuggerNotified() && (g_pDebugInterface != NULL))
1138 {
1139 // We already notified dbgapi that this module was loading (via LoadModule()).
1140 // Now let the dbgapi know the module has reached FILE_LOADED, so it can do any
1141 // processing that needs to wait until this stage (e.g., binding breakpoints in
1142 // NGENd generics).
1143 g_pDebugInterface->LoadModuleFinished(m_pModule, m_pDomain);
1144 }
1145#endif // defined(DEBUGGING_SUPPORTED) && !defined(DACCESS_COMPILE)
1146
1147 // Set a bit to indicate that the module has been loaded in some domain, and therefore
1148 // typeloads can involve types from this module. (Used for candidate instantiations.)
1149 GetModule()->SetIsReadyForTypeLoad();
1150
1151#ifdef FEATURE_PERFMAP
1152 // Notify the perfmap of the IL image load.
1153 PerfMap::LogImageLoad(m_pFile);
1154#endif
1155}
1156
1157void DomainFile::VerifyExecution()
1158{
1159 CONTRACT_VOID
1160 {
1161 INSTANCE_CHECK;
1162 PRECONDITION(IsLoaded());
1163 STANDARD_VM_CHECK;
1164 }
1165 CONTRACT_END;
1166
1167 if(GetFile()->PassiveDomainOnly())
1168 {
1169 // Remove path - location must be hidden for security purposes
1170 LPCWSTR path=GetFile()->GetPath();
1171 LPCWSTR pStart = wcsrchr(path, '\\');
1172 if (pStart != NULL)
1173 pStart++;
1174 else
1175 pStart = path;
1176 COMPlusThrow(kInvalidOperationException, IDS_EE_CODEEXECUTION_ASSEMBLY_FOR_PASSIVE_DOMAIN_ONLY,pStart);
1177 }
1178
1179 RETURN;
1180}
1181
1182void DomainFile::Activate()
1183{
1184 CONTRACT_VOID
1185 {
1186 INSTANCE_CHECK;
1187 PRECONDITION(IsLoaded());
1188 STANDARD_VM_CHECK;
1189 }
1190 CONTRACT_END;
1191
1192 // If we are a module, ensure we've activated the assembly first.
1193
1194 if (!IsAssembly())
1195 {
1196 GetDomainAssembly()->EnsureActive();
1197 }
1198 else
1199 {
1200 // We cannot execute any code in this assembly until we know what exception plan it is on.
1201 // At the point of an exception's stack-crawl it is too late because we cannot tolerate a GC.
1202 // See PossiblyUnwrapThrowable and its callers.
1203 _ASSERTE(GetLoadedModule() == GetDomainAssembly()->GetLoadedAssembly()->GetManifestModule());
1204 GetLoadedModule()->IsRuntimeWrapExceptions();
1205 }
1206
1207 // Now activate any dependencies.
1208 // This will typically cause reentrancy of course.
1209
1210#ifndef CROSSGEN_COMPILE
1211
1212 //
1213 // Now call the module constructor. Note that this might cause reentrancy;
1214 // this is fine and will be handled by the class cctor mechanism.
1215 //
1216
1217 MethodTable *pMT = m_pModule->GetGlobalMethodTable();
1218 if (pMT != NULL)
1219 {
1220 pMT->CheckRestore();
1221 m_bDisableActivationCheck=TRUE;
1222 pMT->CheckRunClassInitThrowing();
1223 }
1224#ifdef _DEBUG
1225 if (g_pConfig->ExpandModulesOnLoad())
1226 {
1227 m_pModule->ExpandAll();
1228 }
1229#endif //_DEBUG
1230
1231#endif // CROSSGEN_COMPILE
1232
1233 RETURN;
1234}
1235
1236#ifdef FEATURE_PREJIT
1237DomainFile *DomainFile::FindNextDomainFileWithNativeImage()
1238{
1239 LIMITED_METHOD_CONTRACT;
1240 return m_pNextDomainFileWithNativeImage;
1241}
1242
1243void DomainFile::InsertIntoDomainFileWithNativeImageList()
1244{
1245 LIMITED_METHOD_CONTRACT;
1246
1247 while (true)
1248 {
1249 DomainFile *pLastDomainFileFoundWithNativeImage = m_pDomain->m_pDomainFileWithNativeImageList;
1250 m_pNextDomainFileWithNativeImage = pLastDomainFileFoundWithNativeImage;
1251 if (pLastDomainFileFoundWithNativeImage == InterlockedCompareExchangeT(&m_pDomain->m_pDomainFileWithNativeImageList, this, pLastDomainFileFoundWithNativeImage))
1252 break;
1253 }
1254}
1255#endif
1256
1257//--------------------------------------------------------------------------------
1258// DomainAssembly
1259//--------------------------------------------------------------------------------
1260
1261DomainAssembly::DomainAssembly(AppDomain *pDomain, PEFile *pFile, LoaderAllocator *pLoaderAllocator)
1262 : DomainFile(pDomain, pFile),
1263 m_pAssembly(NULL),
1264 m_debuggerFlags(DACF_NONE),
1265 m_fDebuggerUnloadStarted(FALSE),
1266 m_fCollectible(pLoaderAllocator->IsCollectible()),
1267 m_fHostAssemblyPublished(false),
1268 m_pLoaderAllocator(pLoaderAllocator),
1269 m_NextDomainAssemblyInSameALC(NULL)
1270{
1271 CONTRACTL
1272 {
1273 CONSTRUCTOR_CHECK;
1274 STANDARD_VM_CHECK;
1275 INJECT_FAULT(COMPlusThrowOM(););
1276 }
1277 CONTRACTL_END;
1278
1279 pFile->ValidateForExecution();
1280
1281 // !!! backout
1282
1283 m_hExposedAssemblyObject = NULL;
1284
1285 SetupDebuggingConfig();
1286
1287 // Add a Module iterator entry for this assembly.
1288 IfFailThrow(m_Modules.Append(this));
1289}
1290
1291DomainAssembly::~DomainAssembly()
1292{
1293 CONTRACTL
1294 {
1295 DESTRUCTOR_CHECK;
1296 NOTHROW;
1297 GC_TRIGGERS;
1298 MODE_ANY;
1299 INJECT_FAULT(COMPlusThrowOM(););
1300 }
1301 CONTRACTL_END;
1302
1303 if (m_fHostAssemblyPublished)
1304 {
1305 // Remove association first.
1306 GetAppDomain()->UnPublishHostedAssembly(this);
1307 }
1308
1309 ModuleIterator i = IterateModules(kModIterIncludeLoading);
1310 while (i.Next())
1311 {
1312 if (i.GetDomainFile() != this)
1313 delete i.GetDomainFile();
1314 }
1315
1316 if (m_pAssembly != NULL)
1317 {
1318 delete m_pAssembly;
1319 }
1320}
1321
1322void DomainAssembly::ReleaseFiles()
1323{
1324 STANDARD_VM_CONTRACT;
1325
1326 if(m_pAssembly)
1327 m_pAssembly->StartUnload();
1328 ModuleIterator i = IterateModules(kModIterIncludeLoading);
1329 while (i.Next())
1330 {
1331 if (i.GetDomainFile() != this)
1332 i.GetDomainFile()->ReleaseFiles();
1333 }
1334
1335 DomainFile::ReleaseFiles();
1336}
1337
1338void DomainAssembly::SetAssembly(Assembly* pAssembly)
1339{
1340 STANDARD_VM_CONTRACT;
1341
1342 UpdatePEFile(pAssembly->GetManifestFile());
1343 _ASSERTE(pAssembly->GetManifestModule()->GetFile()==m_pFile);
1344 m_pAssembly = pAssembly;
1345 m_pModule = pAssembly->GetManifestModule();
1346
1347 pAssembly->SetDomainAssembly(this);
1348}
1349
1350
1351#ifndef CROSSGEN_COMPILE
1352//---------------------------------------------------------------------------------------
1353//
1354// Returns managed representation of the assembly (Assembly or AssemblyBuilder).
1355// Returns NULL if the managed scout was already collected (see code:LoaderAllocator#AssemblyPhases).
1356//
1357OBJECTREF DomainAssembly::GetExposedAssemblyObject()
1358{
1359 CONTRACTL
1360 {
1361 INSTANCE_CHECK;
1362 THROWS;
1363 MODE_COOPERATIVE;
1364 GC_TRIGGERS;
1365 }
1366 CONTRACTL_END;
1367
1368 LoaderAllocator * pLoaderAllocator = GetLoaderAllocator();
1369
1370 if (!pLoaderAllocator->IsManagedScoutAlive())
1371 { // We already collected the managed scout, so we cannot re-create any managed objects
1372 // Note: This is an optimization, as the managed scout can be collected right after this check
1373 return NULL;
1374 }
1375
1376 if (m_hExposedAssemblyObject == NULL)
1377 {
1378 // Atomically create a handle
1379
1380 LOADERHANDLE handle = pLoaderAllocator->AllocateHandle(NULL);
1381
1382 FastInterlockCompareExchangePointer(&m_hExposedAssemblyObject, handle, static_cast<LOADERHANDLE>(NULL));
1383 }
1384
1385 if (pLoaderAllocator->GetHandleValue(m_hExposedAssemblyObject) == NULL)
1386 {
1387 ASSEMBLYREF assemblyObj = NULL;
1388 MethodTable * pMT;
1389 if (GetFile()->IsDynamic())
1390 {
1391 // This is unnecessary because the managed InternalAssemblyBuilder object
1392 // should have already been created at the time of DefineDynamicAssembly
1393 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
1394 pMT = MscorlibBinder::GetClass(CLASS__INTERNAL_ASSEMBLY_BUILDER);
1395 }
1396 else
1397 {
1398 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
1399 pMT = MscorlibBinder::GetClass(CLASS__ASSEMBLY);
1400 }
1401
1402 // Will be TRUE only if LoaderAllocator managed object was already collected and therefore we should
1403 // return NULL
1404 BOOL fIsLoaderAllocatorCollected = FALSE;
1405
1406 // Create the assembly object
1407 GCPROTECT_BEGIN(assemblyObj);
1408 assemblyObj = (ASSEMBLYREF)AllocateObject(pMT);
1409
1410 assemblyObj->SetAssembly(this);
1411
1412 // Attach the reference to the assembly to keep the LoaderAllocator for this collectible type
1413 // alive as long as a reference to the assembly is kept alive.
1414 // Currently we overload the sync root field of the assembly to do so, but the overload is not necessary.
1415 if (GetAssembly() != NULL)
1416 {
1417 OBJECTREF refLA = GetAssembly()->GetLoaderAllocator()->GetExposedObject();
1418 if ((refLA == NULL) && GetAssembly()->GetLoaderAllocator()->IsCollectible())
1419 { // The managed LoaderAllocator object was collected
1420 fIsLoaderAllocatorCollected = TRUE;
1421 }
1422 assemblyObj->SetSyncRoot(refLA);
1423 }
1424
1425 if (!fIsLoaderAllocatorCollected)
1426 { // We should not expose this value in case the LoaderAllocator managed object was already
1427 // collected
1428 pLoaderAllocator->CompareExchangeValueInHandle(m_hExposedAssemblyObject, (OBJECTREF)assemblyObj, NULL);
1429 }
1430 GCPROTECT_END();
1431
1432 if (fIsLoaderAllocatorCollected)
1433 { // The LoaderAllocator managed object was already collected, we cannot re-create it
1434 // Note: We did not publish the allocated Assembly/AssmeblyBuilder object, it will get collected
1435 // by GC
1436 return NULL;
1437 }
1438 }
1439
1440 return pLoaderAllocator->GetHandleValue(m_hExposedAssemblyObject);
1441} // DomainAssembly::GetExposedAssemblyObject
1442#endif // CROSSGEN_COMPILE
1443
1444DomainFile* DomainAssembly::FindIJWModule(HMODULE hMod)
1445{
1446 CONTRACT (DomainFile*)
1447 {
1448 INSTANCE_CHECK;
1449 THROWS;
1450 GC_NOTRIGGER;
1451 MODE_ANY;
1452 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
1453 }
1454 CONTRACT_END;
1455
1456 ModuleIterator i = IterateModules(kModIterIncludeLoaded);
1457 while (i.Next())
1458 {
1459 PEFile *pFile = i.GetDomainFile()->GetFile();
1460
1461 if ( !pFile->IsResource()
1462 && !pFile->IsDynamic()
1463 && !pFile->IsILOnly()
1464 && pFile->GetIJWBase() == hMod)
1465 {
1466 RETURN i.GetDomainFile();
1467 }
1468 }
1469 RETURN NULL;
1470}
1471
1472
1473void DomainAssembly::Begin()
1474{
1475 STANDARD_VM_CONTRACT;
1476
1477 {
1478 AppDomain::LoadLockHolder lock(m_pDomain);
1479 m_pDomain->AddAssembly(this);
1480 }
1481 // Make it possible to find this DomainAssembly object from associated ICLRPrivAssembly.
1482 GetAppDomain()->PublishHostedAssembly(this);
1483 m_fHostAssemblyPublished = true;
1484}
1485
1486#ifdef FEATURE_PREJIT
1487void DomainAssembly::FindNativeImage()
1488{
1489 CONTRACTL
1490 {
1491 INSTANCE_CHECK;
1492 STANDARD_VM_CHECK;
1493 }
1494 CONTRACTL_END;
1495
1496 ClearNativeImageStress();
1497
1498 // We already have an image - we just need to do a few more checks
1499
1500 if (GetFile()->HasNativeImage())
1501 {
1502#if defined(_DEBUG)
1503 if (g_pConfig->ForbidZap(GetSimpleName()))
1504 {
1505 SString sbuf;
1506 StackScratchBuffer scratch;
1507 sbuf.Printf("COMPlus_NgenBind_ZapForbid violation: %s.", GetSimpleName());
1508 DbgAssertDialog(__FILE__, __LINE__, sbuf.GetUTF8(scratch));
1509 }
1510#endif
1511
1512 ReleaseHolder<PEImage> pNativeImage = GetFile()->GetNativeImageWithRef();
1513
1514 if (!CheckZapDependencyIdentities(pNativeImage))
1515 {
1516 m_dwReasonForRejectingNativeImage = ReasonForRejectingNativeImage_DependencyIdentityMismatch;
1517 STRESS_LOG2(LF_ZAP,LL_INFO100,"Rejecting native file %p, because dependency identity mismatch - reason 0x%x\n",pNativeImage.GetValue(),m_dwReasonForRejectingNativeImage);
1518 ExternalLog(LL_ERROR, "Rejecting native image because of identity mismatch "
1519 "with one or more of its assembly dependencies. The assembly needs "
1520 "to be ngenned again");
1521
1522 GetFile()->ClearNativeImage();
1523
1524 // Always throw exceptions when we throw the NI out
1525 ThrowHR(CLR_E_BIND_NI_DEP_IDENTITY_MISMATCH);
1526 }
1527 else
1528 {
1529 Module * pNativeModule = pNativeImage->GetLoadedLayout()->GetPersistedModuleImage();
1530 EnsureWritablePages(pNativeModule);
1531 PEFile ** ppNativeFile = (PEFile **) (PBYTE(pNativeModule) + Module::GetFileOffset());
1532
1533 PEAssembly * pFile = (PEAssembly *)FastInterlockCompareExchangePointer((void **)ppNativeFile, (void *)GetFile(), (void *)NULL);
1534 STRESS_LOG3(LF_ZAP,LL_INFO100,"Attempted to set new native file %p, old file was %p, location in the image=%p\n",GetFile(),pFile,ppNativeFile);
1535 if (pFile!=NULL)
1536 {
1537 // The non-shareable native image has already been used in this process by another Module.
1538 // We have to abandon the native image. (Note that it isn't enough to
1539 // just abandon the preload image, since the code in the file will
1540 // reference the image directly).
1541 m_dwReasonForRejectingNativeImage = ReasonForRejectingNativeImage_CannotShareNiAssemblyNotDomainNeutral;
1542 STRESS_LOG3(LF_ZAP,LL_INFO100,"Rejecting native file %p, because it is already used by file %p - reason 0x%x\n",GetFile(),pFile,m_dwReasonForRejectingNativeImage);
1543
1544 ExternalLog(LL_WARNING, "ZAP: An ngen image of an assembly which "
1545 "is not loaded as domain-neutral cannot be used in multiple appdomains "
1546 "- abandoning ngen image. The assembly will be JIT-compiled in "
1547 "the second appdomain. See System.LoaderOptimization.MultiDomain "
1548 "for information about domain-neutral loading.");
1549 GetFile()->ClearNativeImage();
1550
1551 // We only support a (non-shared) native image to be used from a single
1552 // AppDomain. Its not obvious if this is an implementation restriction,
1553 // or if this should fail DomainFile::CheckZapRequired().
1554 // We err on the side of conservativeness, so that multi-domain tests
1555 // do not blow up in CheckZapRequired()
1556 GetFile()->SetCannotUseNativeImage();
1557 }
1558 else
1559 {
1560 GetFile()->AddRef();
1561
1562 LOG((LF_ZAP, LL_INFO100, "ZAP: Found a candidate native image for %s\n", GetSimpleName()));
1563 }
1564 }
1565 }
1566
1567 if (!GetFile()->HasNativeImage())
1568 {
1569 //
1570 // Verify that the IL image is consistent with the NGen images loaded into appdomain
1571 //
1572
1573 AssemblySpec spec;
1574 spec.InitializeSpec(GetFile());
1575
1576 GUID mvid;
1577 GetFile()->GetMVID(&mvid);
1578
1579 GetAppDomain()->CheckForMismatchedNativeImages(&spec, &mvid);
1580 }
1581
1582 CheckZapRequired();
1583}
1584#endif // FEATURE_PREJIT
1585
1586void DomainAssembly::Allocate()
1587{
1588 CONTRACTL
1589 {
1590 INSTANCE_CHECK;
1591 STANDARD_VM_CHECK;
1592 INJECT_FAULT(COMPlusThrowOM(););
1593 }
1594 CONTRACTL_END;
1595
1596 AllocMemTracker amTracker;
1597 AllocMemTracker * pamTracker = &amTracker;
1598
1599 Assembly * pAssembly = m_pAssembly;
1600
1601 if (pAssembly==NULL)
1602 {
1603 //! If you decide to remove "if" do not remove this brace: order is important here - in the case of an exception,
1604 //! the Assembly holder must destruct before the AllocMemTracker declared above.
1605
1606 // We can now rely on the fact that our MDImport will not change so we can stop refcounting it.
1607 GetFile()->MakeMDImportPersistent();
1608
1609 NewHolder<Assembly> assemblyHolder(NULL);
1610
1611 assemblyHolder = pAssembly = Assembly::Create(m_pDomain, GetFile(), GetDebuggerInfoBits(), this->IsCollectible(), pamTracker, this->IsCollectible() ? this->GetLoaderAllocator() : NULL);
1612 assemblyHolder->SetIsTenured();
1613
1614 //@todo! This is too early to be calling SuppressRelease. The right place to call it is below after
1615 // the CANNOTTHROWCOMPLUSEXCEPTION. Right now, we have to do this to unblock OOM injection testing quickly
1616 // as doing the right thing is nontrivial.
1617 pamTracker->SuppressRelease();
1618 assemblyHolder.SuppressRelease();
1619 }
1620
1621#ifdef FEATURE_COMINTEROP
1622 // If we are in an AppX process we should prevent loading of PIA in the AppDomain.
1623 // This will ensure that we do not run into any compatibility issues in case a type has both a co-Class and a Winrt Class
1624 if (AppX::IsAppXProcess() && pAssembly->IsPIA())
1625 {
1626 COMPlusThrow(kNotSupportedException, W("NotSupported_PIAInAppxProcess"));
1627 }
1628#endif
1629
1630 SetAssembly(pAssembly);
1631
1632#ifdef FEATURE_PREJIT
1633 BOOL fInsertIntoAssemblySpecBindingCache = TRUE;
1634
1635 // Insert AssemblyDef details into AssemblySpecBindingCache if appropriate
1636
1637
1638 fInsertIntoAssemblySpecBindingCache = fInsertIntoAssemblySpecBindingCache && GetFile()->CanUseWithBindingCache();
1639
1640 if (fInsertIntoAssemblySpecBindingCache)
1641 {
1642 AssemblySpec specAssemblyDef;
1643 specAssemblyDef.InitializeSpec(GetFile());
1644 if (specAssemblyDef.IsStrongNamed() && specAssemblyDef.HasPublicKey())
1645 {
1646 specAssemblyDef.ConvertPublicKeyToToken();
1647 }
1648 m_pDomain->AddAssemblyToCache(&specAssemblyDef, this);
1649 }
1650#endif
1651} // DomainAssembly::Allocate
1652
1653void DomainAssembly::DeliverAsyncEvents()
1654{
1655 CONTRACTL
1656 {
1657 INSTANCE_CHECK;
1658 NOTHROW;
1659 GC_TRIGGERS;
1660 MODE_ANY;
1661 SO_INTOLERANT;
1662 }
1663 CONTRACTL_END;
1664
1665 OVERRIDE_LOAD_LEVEL_LIMIT(FILE_ACTIVE);
1666 m_pDomain->RaiseLoadingAssemblyEvent(this);
1667
1668}
1669
1670
1671void DomainAssembly::DeliverSyncEvents()
1672{
1673 CONTRACTL
1674 {
1675 INSTANCE_CHECK;
1676 STANDARD_VM_CHECK;
1677 }
1678 CONTRACTL_END;
1679
1680 GetCurrentModule()->NotifyEtwLoadFinished(S_OK);
1681
1682 // We may be notified from inside the loader lock if we are delivering IJW events, so keep track.
1683#ifdef PROFILING_SUPPORTED
1684 if (!IsProfilerNotified())
1685 {
1686 SetProfilerNotified();
1687 GetCurrentModule()->NotifyProfilerLoadFinished(S_OK);
1688 }
1689
1690#endif
1691#ifdef DEBUGGING_SUPPORTED
1692 GCX_COOP();
1693 if (!IsDebuggerNotified())
1694 {
1695 SetShouldNotifyDebugger();
1696
1697 // Still work to do even if no debugger is attached.
1698 NotifyDebuggerLoad(ATTACH_ASSEMBLY_LOAD, FALSE);
1699
1700 }
1701#endif // DEBUGGING_SUPPORTED
1702} // DomainAssembly::DeliverSyncEvents
1703
1704/*
1705 // The enum for dwLocation from managed code:
1706 public enum ResourceLocation
1707 {
1708 Embedded = 1,
1709 ContainedInAnotherAssembly = 2,
1710 ContainedInManifestFile = 4
1711 }
1712*/
1713
1714BOOL DomainAssembly::GetResource(LPCSTR szName, DWORD *cbResource,
1715 PBYTE *pbInMemoryResource, DomainAssembly** pAssemblyRef,
1716 LPCSTR *szFileName, DWORD *dwLocation,
1717 BOOL fSkipRaiseResolveEvent)
1718{
1719 CONTRACTL
1720 {
1721 INSTANCE_CHECK;
1722 THROWS;
1723 MODE_ANY;
1724 INJECT_FAULT(COMPlusThrowOM(););
1725 }
1726 CONTRACTL_END;
1727
1728 return GetFile()->GetResource( szName,
1729 cbResource,
1730 pbInMemoryResource,
1731 pAssemblyRef,
1732 szFileName,
1733 dwLocation,
1734 fSkipRaiseResolveEvent,
1735 this,
1736 this->m_pDomain );
1737}
1738
1739
1740#ifdef FEATURE_PREJIT
1741
1742// --------------------------------------------------------------------------------
1743// Remember the timestamp of the CLR DLLs used to compile the ngen image.
1744// These will be checked at runtime by PEFile::CheckNativeImageTimeStamp().
1745//
1746
1747void GetTimeStampsForNativeImage(CORCOMPILE_VERSION_INFO * pNativeVersionInfo)
1748{
1749 CONTRACTL
1750 {
1751 STANDARD_VM_CHECK;
1752 PRECONDITION(::GetAppDomain()->IsCompilationDomain());
1753 }
1754 CONTRACTL_END;
1755
1756 // Do not store runtime timestamps into NGen image for cross-platform NGen determinism
1757}
1758
1759//
1760// Which processor should ngen target?
1761// This is needed when ngen wants to target for "reach" if the ngen images will be
1762// used on other machines (the Operating System or the OEM build lab can do this).
1763// It can also be used to reduce the testing matrix
1764//
1765void GetNGenCpuInfo(CORINFO_CPU * cpuInfo)
1766{
1767 LIMITED_METHOD_CONTRACT;
1768
1769#ifdef _TARGET_X86_
1770
1771 static CORINFO_CPU ngenCpuInfo =
1772 {
1773 (CPU_X86_PENTIUM_PRO << 8), // dwCPUType
1774 0x00000000, // dwFeatures
1775 0 // dwExtendedFeatures
1776 };
1777
1778 // We always generate P3-compatible code on CoreCLR
1779 *cpuInfo = ngenCpuInfo;
1780
1781#else // _TARGET_X86_
1782 cpuInfo->dwCPUType = 0;
1783 cpuInfo->dwFeatures = 0;
1784 cpuInfo->dwExtendedFeatures = 0;
1785#endif // _TARGET_X86_
1786}
1787
1788// --------------------------------------------------------------------------------
1789
1790void DomainAssembly::GetCurrentVersionInfo(CORCOMPILE_VERSION_INFO *pNativeVersionInfo)
1791{
1792 CONTRACTL
1793 {
1794 INSTANCE_CHECK;
1795 STANDARD_VM_CHECK;
1796 }
1797 CONTRACTL_END;
1798
1799 // Clear memory so that we won't write random data into the zapped file
1800 ZeroMemory(pNativeVersionInfo, sizeof(CORCOMPILE_VERSION_INFO));
1801
1802 // Pick up any compilation directives for code flavor
1803
1804 BOOL fForceDebug, fForceProfiling, fForceInstrument;
1805 SystemDomain::GetCompilationOverrides(&fForceDebug,
1806 &fForceProfiling,
1807 &fForceInstrument);
1808
1809#ifndef FEATURE_PAL
1810 pNativeVersionInfo->wOSPlatformID = VER_PLATFORM_WIN32_NT;
1811#else
1812 pNativeVersionInfo->wOSPlatformID = VER_PLATFORM_UNIX;
1813#endif
1814
1815 // The native images should be OS-version agnostic. Do not store the actual OS version for determinism.
1816 // pNativeVersionInfo->wOSMajorVersion = (WORD) osInfo.dwMajorVersion;
1817 pNativeVersionInfo->wOSMajorVersion = 4;
1818
1819 pNativeVersionInfo->wMachine = IMAGE_FILE_MACHINE_NATIVE_NI;
1820
1821 pNativeVersionInfo->wVersionMajor = CLR_MAJOR_VERSION;
1822 pNativeVersionInfo->wVersionMinor = CLR_MINOR_VERSION;
1823 pNativeVersionInfo->wVersionBuildNumber = CLR_BUILD_VERSION;
1824 pNativeVersionInfo->wVersionPrivateBuildNumber = CLR_BUILD_VERSION_QFE;
1825
1826 GetNGenCpuInfo(&pNativeVersionInfo->cpuInfo);
1827
1828#if _DEBUG
1829 pNativeVersionInfo->wBuild = CORCOMPILE_BUILD_CHECKED;
1830#else
1831 pNativeVersionInfo->wBuild = CORCOMPILE_BUILD_FREE;
1832#endif
1833
1834#ifdef DEBUGGING_SUPPORTED
1835 if (fForceDebug || !CORDebuggerAllowJITOpts(GetDebuggerInfoBits()))
1836 {
1837 pNativeVersionInfo->wCodegenFlags |= CORCOMPILE_CODEGEN_DEBUGGING;
1838 pNativeVersionInfo->wConfigFlags |= CORCOMPILE_CONFIG_DEBUG;
1839 }
1840 else
1841#endif // DEBUGGING_SUPPORTED
1842 {
1843 pNativeVersionInfo->wConfigFlags |= CORCOMPILE_CONFIG_DEBUG_NONE;
1844 }
1845
1846#if defined (PROFILING_SUPPORTED_DATA) || defined(PROFILING_SUPPORTED)
1847 if (fForceProfiling || CORProfilerUseProfileImages())
1848 {
1849 pNativeVersionInfo->wCodegenFlags |= CORCOMPILE_CODEGEN_PROFILING;
1850 pNativeVersionInfo->wConfigFlags |= CORCOMPILE_CONFIG_PROFILING;
1851#ifdef DEBUGGING_SUPPORTED
1852 // Note that we have hardwired profiling to also imply optimized debugging
1853 // info. This cuts down on one permutation of prejit files.
1854 pNativeVersionInfo->wCodegenFlags &= ~CORCOMPILE_CODEGEN_DEBUGGING;
1855 pNativeVersionInfo->wConfigFlags &= ~(CORCOMPILE_CONFIG_DEBUG|
1856 CORCOMPILE_CONFIG_DEBUG_DEFAULT);
1857 pNativeVersionInfo->wConfigFlags |= CORCOMPILE_CONFIG_DEBUG_NONE;
1858#endif // DEBUGGING_SUPPORTED
1859 }
1860 else
1861#endif // PROFILING_SUPPORTED_DATA || PROFILING_SUPPORTED
1862 {
1863 pNativeVersionInfo->wConfigFlags |= CORCOMPILE_CONFIG_PROFILING_NONE;
1864 }
1865
1866#ifdef DEBUGGING_SUPPORTED
1867
1868 // Note the default assembly flags (from the custom attributes & INI file) , so we can
1869 // set determine whether or not the current settings
1870 // match the "default" setting or not.
1871
1872 // Note that the INI file settings are considered a part of the
1873 // assembly, even though they could theoretically change between
1874 // ngen time and runtime. It is just too expensive and awkward to
1875 // look up the INI file before binding to the native image at
1876 // runtime, so we effectively snapshot it at ngen time.
1877
1878 DWORD defaultFlags = ComputeDebuggingConfig();
1879
1880 if (CORDebuggerAllowJITOpts(defaultFlags))
1881 {
1882 // Default is optimized code
1883 if ((pNativeVersionInfo->wCodegenFlags & CORCOMPILE_CODEGEN_DEBUGGING) == 0)
1884 pNativeVersionInfo->wConfigFlags |= CORCOMPILE_CONFIG_DEBUG_DEFAULT;
1885 }
1886 else
1887 {
1888 // Default is non-optimized debuggable code
1889 if ((pNativeVersionInfo->wCodegenFlags & CORCOMPILE_CODEGEN_DEBUGGING) != 0)
1890 pNativeVersionInfo->wConfigFlags |= CORCOMPILE_CONFIG_DEBUG_DEFAULT;
1891 }
1892
1893#endif // DEBUGGING_SUPPORTED
1894
1895 if (fForceInstrument || GetAssembly()->IsInstrumented())
1896 {
1897 pNativeVersionInfo->wCodegenFlags |= CORCOMPILE_CODEGEN_PROF_INSTRUMENTING;
1898 pNativeVersionInfo->wConfigFlags |= CORCOMPILE_CONFIG_INSTRUMENTATION;
1899 }
1900 else
1901 {
1902 pNativeVersionInfo->wConfigFlags |= CORCOMPILE_CONFIG_INSTRUMENTATION_NONE;
1903 }
1904
1905
1906 GetTimeStampsForNativeImage(pNativeVersionInfo);
1907
1908 // Store signature of source assembly.
1909 GetOptimizedIdentitySignature(&pNativeVersionInfo->sourceAssembly);
1910
1911 // signature will is hash of the whole file. It is written by zapper.
1912 // IfFailThrow(CoCreateGuid(&pNativeVersionInfo->signature));
1913}
1914
1915void DomainAssembly::GetOptimizedIdentitySignature(CORCOMPILE_ASSEMBLY_SIGNATURE *pSignature)
1916{
1917 CONTRACTL
1918 {
1919 INSTANCE_CHECK;
1920 THROWS;
1921 GC_TRIGGERS;
1922 MODE_ANY;
1923 INJECT_FAULT(COMPlusThrowOM(););
1924 }
1925 CONTRACTL_END;
1926
1927 //
1928 // Write the MVID into the version header.
1929 //
1930
1931 //
1932 // If this assembly has skip verification permission, then we store its
1933 // mvid. If at load time the assembly still has skip verification
1934 // permission, then we can base the matches purely on mvid values and
1935 // skip the perf-heavy hashing of the file.
1936 //
1937
1938 //
1939 // The reason that we tell IsFullyTrusted to do a quick check
1940 // only is because that allows us make a determination for the most
1941 // common full trust scenarios (local machine) without actually
1942 // resolving policy and bringing in a whole list of assembly
1943 // dependencies.
1944 //
1945 ReleaseHolder<IMDInternalImport> scope (GetFile()->GetMDImportWithRef());
1946 IfFailThrow(scope->GetScopeProps(NULL, &pSignature->mvid));
1947
1948 // Use the NGen image if posssible. IL image does not even have to be present on CoreCLR.
1949 if (GetFile()->HasNativeImage())
1950 {
1951 PEImageHolder pNativeImage(GetFile()->GetNativeImageWithRef());
1952
1953 CORCOMPILE_VERSION_INFO* pVersionInfo = pNativeImage->GetLoadedLayout()->GetNativeVersionInfo();
1954 pSignature->timeStamp = pVersionInfo->sourceAssembly.timeStamp;
1955 pSignature->ilImageSize = pVersionInfo->sourceAssembly.ilImageSize;
1956
1957 return;
1958 }
1959
1960 // Write the time stamp
1961 PEImageLayoutHolder ilLayout(GetFile()->GetAnyILWithRef());
1962 pSignature->timeStamp = ilLayout->GetTimeDateStamp();
1963 pSignature->ilImageSize = ilLayout->GetVirtualSize();
1964}
1965
1966BOOL DomainAssembly::CheckZapDependencyIdentities(PEImage *pNativeImage)
1967{
1968 CONTRACTL
1969 {
1970 INSTANCE_CHECK;
1971 STANDARD_VM_CHECK;
1972 }
1973 CONTRACTL_END;
1974
1975 AssemblySpec spec;
1976 spec.InitializeSpec(this->GetFile());
1977
1978 // The assembly spec should have the binding context associated with it
1979 _ASSERTE(spec.GetBindingContext() || spec.IsAssemblySpecForMscorlib());
1980
1981 CORCOMPILE_VERSION_INFO *pVersionInfo = pNativeImage->GetLoadedLayout()->GetNativeVersionInfo();
1982
1983 // Check our own assembly first
1984 GetAppDomain()->CheckForMismatchedNativeImages(&spec, &pVersionInfo->sourceAssembly.mvid);
1985
1986 // Check MVID in metadata against MVID in CORCOMPILE_VERSION_INFO - important when metadata is loaded from IL instead of NI
1987 ReleaseHolder<IMDInternalImport> pImport(this->GetFile()->GetMDImportWithRef());
1988 GUID mvid;
1989 IfFailThrow(pImport->GetScopeProps(NULL, &mvid));
1990 GetAppDomain()->CheckForMismatchedNativeImages(&spec, &mvid);
1991
1992 // Now Check dependencies
1993 COUNT_T cDependencies;
1994 CORCOMPILE_DEPENDENCY *pDependencies = pNativeImage->GetLoadedLayout()->GetNativeDependencies(&cDependencies);
1995 CORCOMPILE_DEPENDENCY *pDependenciesEnd = pDependencies + cDependencies;
1996
1997 while (pDependencies < pDependenciesEnd)
1998 {
1999 if (pDependencies->dwAssemblyDef != mdAssemblyRefNil)
2000 {
2001 AssemblySpec name;
2002 name.InitializeSpec(pDependencies->dwAssemblyDef, pNativeImage->GetNativeMDImport(), this);
2003
2004 if (!name.IsAssemblySpecForMscorlib())
2005 {
2006 // We just initialized the assembly spec for the NI dependency. This will not have binding context
2007 // associated with it, so set it from that of the parent.
2008 _ASSERTE(!name.GetBindingContext());
2009 ICLRPrivBinder *pParentAssemblyBindingContext = name.GetBindingContextFromParentAssembly(name.GetAppDomain());
2010 _ASSERTE(pParentAssemblyBindingContext);
2011 name.SetBindingContext(pParentAssemblyBindingContext);
2012 }
2013
2014 GetAppDomain()->CheckForMismatchedNativeImages(&name, &pDependencies->signAssemblyDef.mvid);
2015 }
2016
2017 pDependencies++;
2018 }
2019
2020 return TRUE;
2021}
2022#endif // FEATURE_PREJIT
2023
2024
2025
2026
2027
2028// <TODO>@todo Find a better place for these</TODO>
2029#define DE_CUSTOM_VALUE_NAMESPACE "System.Diagnostics"
2030#define DE_DEBUGGABLE_ATTRIBUTE_NAME "DebuggableAttribute"
2031
2032// <TODO>@todo .INI file is a temporary workaround for Beta 1</TODO>
2033#define DE_INI_FILE_SECTION_NAME W(".NET Framework Debugging Control")
2034#define DE_INI_FILE_KEY_TRACK_INFO W("GenerateTrackingInfo")
2035#define DE_INI_FILE_KEY_ALLOW_JIT_OPTS W("AllowOptimize")
2036
2037DWORD DomainAssembly::ComputeDebuggingConfig()
2038{
2039 CONTRACTL
2040 {
2041 INSTANCE_CHECK;
2042 THROWS;
2043 WRAPPER(GC_TRIGGERS);
2044 MODE_ANY;
2045 INJECT_FAULT(COMPlusThrowOM(););
2046 }
2047 CONTRACTL_END;
2048
2049#ifdef DEBUGGING_SUPPORTED
2050 DWORD dacfFlags = DACF_ALLOW_JIT_OPTS;
2051
2052 if (GetDebuggingOverrides(&dacfFlags))
2053 {
2054 dacfFlags |= DACF_USER_OVERRIDE;
2055 }
2056 else
2057 {
2058 IfFailThrow(GetDebuggingCustomAttributes(&dacfFlags));
2059 }
2060
2061 return dacfFlags;
2062#else // !DEBUGGING_SUPPORTED
2063 return 0;
2064#endif // DEBUGGING_SUPPORTED
2065}
2066
2067void DomainAssembly::SetupDebuggingConfig(void)
2068{
2069 CONTRACTL
2070 {
2071 INSTANCE_CHECK;
2072 THROWS;
2073 WRAPPER(GC_TRIGGERS);
2074 MODE_ANY;
2075 INJECT_FAULT(COMPlusThrowOM(););
2076 }
2077 CONTRACTL_END;
2078
2079#ifdef DEBUGGING_SUPPORTED
2080 DWORD dacfFlags = ComputeDebuggingConfig();
2081
2082 SetDebuggerInfoBits((DebuggerAssemblyControlFlags)dacfFlags);
2083
2084 LOG((LF_CORDB, LL_INFO10, "Assembly %S: bits=0x%x\n", GetDebugName(), GetDebuggerInfoBits()));
2085#endif // DEBUGGING_SUPPORTED
2086}
2087
2088// The format for the (temporary) .INI file is:
2089
2090// [.NET Framework Debugging Control]
2091// GenerateTrackingInfo=<n> where n is 0 or 1
2092// AllowOptimize=<n> where n is 0 or 1
2093
2094// Where neither x nor y equal INVALID_INI_INT:
2095#define INVALID_INI_INT (0xFFFF)
2096
2097bool DomainAssembly::GetDebuggingOverrides(DWORD *pdwFlags)
2098{
2099 CONTRACTL
2100 {
2101 INSTANCE_CHECK;
2102 THROWS;
2103 GC_NOTRIGGER;
2104 MODE_ANY;
2105 INJECT_FAULT(COMPlusThrowOM(););
2106 }
2107 CONTRACTL_END;
2108
2109#if defined(DEBUGGING_SUPPORTED) && !defined(FEATURE_CORESYSTEM)
2110 // TODO FIX in V5.0
2111 // Any touch of the file system is relatively expensive even in the warm case.
2112 //
2113 // Ideally we remove the .INI feature completely (if we need something put it in the .exe.config file)
2114 //
2115 // However because of compatibility concerns, we won't do this until the next side-by-side release
2116 // In the mean time don't check in the case where we have already loaded the NGEN image, as the
2117 // JIT overrides don't mean anything in that case as we won't be jitting anyway.
2118 // This avoids doing these probes for framework DLLs right away.
2119 if (GetFile()->HasNativeImage())
2120 return false;
2121
2122 _ASSERTE(pdwFlags);
2123
2124 bool fHasBits = false;
2125 WCHAR *pFileName = NULL;
2126 HRESULT hr = S_OK;
2127 UINT cbExtOrValue = 4;
2128 WCHAR *pTail = NULL;
2129 size_t len = 0;
2130 WCHAR *lpFileName = NULL;
2131
2132 const WCHAR *wszFileName = GetFile()->GetPath();
2133
2134 if (wszFileName == NULL)
2135 {
2136 return false;
2137 }
2138
2139 // lpFileName is a copy of the original, and will be edited.
2140 CQuickBytes qb;
2141 len = wcslen(wszFileName);
2142 size_t cchlpFileName = (len + 1);
2143 lpFileName = (WCHAR*)qb.AllocThrows(cchlpFileName * sizeof(WCHAR));
2144 wcscpy_s(lpFileName, cchlpFileName, wszFileName);
2145
2146 pFileName = wcsrchr(lpFileName, W('\\'));
2147
2148 if (pFileName == NULL)
2149 {
2150 pFileName = lpFileName;
2151 }
2152
2153 if (*pFileName == W('\\'))
2154 {
2155 pFileName++; //move the pointer past the last '\'
2156 }
2157
2158 _ASSERTE(wcslen(W(".INI")) == cbExtOrValue);
2159
2160 if (pFileName == NULL || (pTail=wcsrchr(pFileName, W('.'))) == NULL || (wcslen(pTail)<cbExtOrValue))
2161 {
2162 return false;
2163 }
2164
2165 wcscpy_s(pTail, cchlpFileName - (pTail - lpFileName), W(".INI"));
2166
2167 // Win2K has a problem if multiple processes call GetPrivateProfile* on the same
2168 // non-existent .INI file simultaneously. The OS livelocks in the kernel (i.e.
2169 // outside of user space) and remains there at full CPU for several minutes. Then
2170 // it breaks out. Here is our work-around, while we pursue a fix in a future
2171 // version of the OS.
2172 if (WszGetFileAttributes(lpFileName) == INVALID_FILE_ATTRIBUTES)
2173 return false;
2174
2175 // Having modified the filename, we use the full path
2176 // to actually get the file.
2177 if ((cbExtOrValue=WszGetPrivateProfileInt(DE_INI_FILE_SECTION_NAME,
2178 DE_INI_FILE_KEY_TRACK_INFO,
2179 INVALID_INI_INT,
2180 lpFileName)) != INVALID_INI_INT)
2181 {
2182 if (cbExtOrValue != 0)
2183 {
2184 *pdwFlags |= DACF_OBSOLETE_TRACK_JIT_INFO;
2185 }
2186 else
2187 {
2188 *pdwFlags &= (~DACF_OBSOLETE_TRACK_JIT_INFO);
2189 }
2190
2191 fHasBits = true;
2192 }
2193
2194 if ((cbExtOrValue=WszGetPrivateProfileInt(DE_INI_FILE_SECTION_NAME,
2195 DE_INI_FILE_KEY_ALLOW_JIT_OPTS,
2196 INVALID_INI_INT,
2197 lpFileName)) != INVALID_INI_INT)
2198 {
2199 if (cbExtOrValue != 0)
2200 {
2201 *pdwFlags |= DACF_ALLOW_JIT_OPTS;
2202 }
2203 else
2204 {
2205 *pdwFlags &= (~DACF_ALLOW_JIT_OPTS);
2206 }
2207
2208 fHasBits = true;
2209 }
2210
2211 return fHasBits;
2212
2213#else // DEBUGGING_SUPPORTED && !FEATURE_CORESYSTEM
2214 return false;
2215#endif // DEBUGGING_SUPPORTED && !FEATURE_CORESYSTEM
2216}
2217
2218
2219// For right now, we only check to see if the DebuggableAttribute is present - later may add fields/properties to the
2220// attributes.
2221HRESULT DomainAssembly::GetDebuggingCustomAttributes(DWORD *pdwFlags)
2222{
2223 CONTRACTL
2224 {
2225 INSTANCE_CHECK;
2226 NOTHROW;
2227 WRAPPER(GC_TRIGGERS);
2228 MODE_ANY;
2229 FORBID_FAULT;
2230 PRECONDITION(CheckPointer(pdwFlags));
2231 }
2232 CONTRACTL_END;
2233
2234 HRESULT hr = S_OK;
2235
2236#ifdef FEATURE_PREJIT
2237 ReleaseHolder<PEImage> pNativeImage=GetFile()->GetNativeImageWithRef();
2238 if (pNativeImage)
2239 {
2240 CORCOMPILE_VERSION_INFO * pVersion = pNativeImage->GetLoadedLayout()->GetNativeVersionInfo();
2241 PREFIX_ASSUME(pVersion != NULL);
2242
2243 WORD codegen = pVersion->wCodegenFlags;
2244
2245 if (codegen & CORCOMPILE_CODEGEN_DEBUGGING)
2246 {
2247 *pdwFlags &= (~DACF_ALLOW_JIT_OPTS);
2248 }
2249 else
2250 {
2251 *pdwFlags |= DACF_ALLOW_JIT_OPTS;
2252 }
2253
2254 }
2255 else
2256#endif // FEATURE_PREJIT
2257 {
2258 ULONG size;
2259 BYTE *blob;
2260 mdModule mdMod;
2261 ReleaseHolder<IMDInternalImport> mdImport(GetFile()->GetMDImportWithRef());
2262 mdMod = mdImport->GetModuleFromScope();
2263 mdAssembly asTK = TokenFromRid(mdtAssembly, 1);
2264
2265 hr = mdImport->GetCustomAttributeByName(asTK,
2266 DE_CUSTOM_VALUE_NAMESPACE
2267 NAMESPACE_SEPARATOR_STR
2268 DE_DEBUGGABLE_ATTRIBUTE_NAME,
2269 (const void**)&blob,
2270 &size);
2271
2272 // If there is no custom value, then there is no entrypoint defined.
2273 if (!(FAILED(hr) || hr == S_FALSE))
2274 {
2275 // We're expecting a 6 or 8 byte blob:
2276 //
2277 // 1, 0, enable tracking, disable opts, 0, 0
2278 if ((size == 6) || (size == 8))
2279 {
2280 if (!((blob[0] == 1) && (blob[1] == 0)))
2281 {
2282 BAD_FORMAT_NOTHROW_ASSERT(!"Invalid blob format for custom attribute");
2283 return COR_E_BADIMAGEFORMAT;
2284 }
2285
2286 if (blob[2] & 0x1)
2287 {
2288 *pdwFlags |= DACF_OBSOLETE_TRACK_JIT_INFO;
2289 }
2290 else
2291 {
2292 *pdwFlags &= (~DACF_OBSOLETE_TRACK_JIT_INFO);
2293 }
2294
2295 if (blob[2] & 0x2)
2296 {
2297 *pdwFlags |= DACF_IGNORE_PDBS;
2298 }
2299 else
2300 {
2301 *pdwFlags &= (~DACF_IGNORE_PDBS);
2302 }
2303
2304
2305 // For compatibility, we enable optimizations if the tracking byte is zero,
2306 // even if disable opts is nonzero
2307 if (((blob[2] & 0x1) == 0) || (blob[3] == 0))
2308 {
2309 *pdwFlags |= DACF_ALLOW_JIT_OPTS;
2310 }
2311 else
2312 {
2313 *pdwFlags &= (~DACF_ALLOW_JIT_OPTS);
2314 }
2315
2316 LOG((LF_CORDB, LL_INFO10, "Assembly %S: has %s=%d,%d bits = 0x%x\n", GetDebugName(),
2317 DE_DEBUGGABLE_ATTRIBUTE_NAME,
2318 blob[2], blob[3], *pdwFlags));
2319 }
2320 }
2321 }
2322
2323 return hr;
2324}
2325
2326BOOL DomainAssembly::NotifyDebuggerLoad(int flags, BOOL attaching)
2327{
2328 WRAPPER_NO_CONTRACT;
2329
2330 BOOL result = FALSE;
2331
2332 if (!IsVisibleToDebugger())
2333 return FALSE;
2334
2335 // Debugger Attach is done totally out-of-process. Does not call code in-proc.
2336 _ASSERTE(!attaching);
2337
2338 // Make sure the debugger has been initialized. See code:Debugger::Startup.
2339 if (g_pDebugInterface == NULL)
2340 {
2341 _ASSERTE(!CORDebuggerAttached());
2342 return FALSE;
2343 }
2344
2345 // There is still work we need to do even when no debugger is attached.
2346
2347 if (flags & ATTACH_ASSEMBLY_LOAD)
2348 {
2349 if (ShouldNotifyDebugger())
2350 {
2351 g_pDebugInterface->LoadAssembly(this);
2352 }
2353 result = TRUE;
2354 }
2355
2356 DomainModuleIterator i = IterateModules(kModIterIncludeLoading);
2357 while (i.Next())
2358 {
2359 DomainFile * pDomainFile = i.GetDomainFile();
2360 if(pDomainFile->ShouldNotifyDebugger())
2361 {
2362 result = result ||
2363 pDomainFile->GetModule()->NotifyDebuggerLoad(this->GetAppDomain(), pDomainFile, flags, attaching);
2364 }
2365 }
2366 if( ShouldNotifyDebugger())
2367 {
2368 result|=m_pModule->NotifyDebuggerLoad(m_pDomain, this, ATTACH_MODULE_LOAD, attaching);
2369 SetDebuggerNotified();
2370 }
2371
2372
2373
2374 return result;
2375}
2376
2377void DomainAssembly::NotifyDebuggerUnload()
2378{
2379 LIMITED_METHOD_CONTRACT;
2380
2381 if (!IsVisibleToDebugger())
2382 return;
2383
2384 if (!this->GetAppDomain()->IsDebuggerAttached())
2385 return;
2386
2387 m_fDebuggerUnloadStarted = TRUE;
2388
2389 // Dispatch module unloads for all modules. Debugger is resilient in case we haven't dispatched
2390 // a previous load event (such as if debugger attached after the modules was loaded).
2391 DomainModuleIterator i = IterateModules(kModIterIncludeLoading);
2392 while (i.Next())
2393 {
2394 i.GetDomainFile()->GetModule()->NotifyDebuggerUnload(this->GetAppDomain());
2395 }
2396
2397 g_pDebugInterface->UnloadAssembly(this);
2398
2399}
2400
2401// This will enumerate for static GC refs (but not thread static GC refs)
2402
2403void DomainAssembly::EnumStaticGCRefs(promote_func* fn, ScanContext* sc)
2404{
2405 CONTRACT_VOID
2406 {
2407 NOTHROW;
2408 GC_NOTRIGGER;
2409 }
2410 CONTRACT_END;
2411
2412 _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
2413 GCHeapUtilities::IsServerHeap() &&
2414 IsGCSpecialThread());
2415
2416 DomainModuleIterator i = IterateModules(kModIterIncludeLoaded);
2417 while (i.Next())
2418 {
2419 DomainFile* pDomainFile = i.GetDomainFile();
2420
2421 if (pDomainFile->IsActive())
2422 {
2423 // We guarantee that at this point the module has it's DomainLocalModule set up
2424 // , as we create it while we load the module
2425 _ASSERTE(pDomainFile->GetLoadedModule()->GetDomainLocalModule(this->GetAppDomain()));
2426 pDomainFile->GetLoadedModule()->EnumRegularStaticGCRefs(this->GetAppDomain(), fn, sc);
2427
2428 // We current to do not iterate over the ThreadLocalModules that correspond
2429 // to this Module. The GC discovers thread statics through the handle table.
2430 }
2431 }
2432
2433 RETURN;
2434}
2435
2436
2437
2438
2439#endif // #ifndef DACCESS_COMPILE
2440
2441#ifdef DACCESS_COMPILE
2442
2443void
2444DomainFile::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2445{
2446 SUPPORTS_DAC;
2447
2448 //sizeof(DomainFile) == 0x60
2449 DAC_ENUM_VTHIS();
2450
2451 // Modules are needed for all minidumps, but they are enumerated elsewhere
2452 // so we don't need to duplicate effort; thus we do noting with m_pModule.
2453
2454 // For MiniDumpNormal, we only want the file name.
2455 if (m_pFile.IsValid())
2456 {
2457 m_pFile->EnumMemoryRegions(flags);
2458 }
2459
2460 if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE
2461 && m_pDomain.IsValid())
2462 {
2463 m_pDomain->EnumMemoryRegions(flags, true);
2464 }
2465}
2466
2467void
2468DomainAssembly::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2469{
2470 SUPPORTS_DAC;
2471
2472 //sizeof(DomainAssembly) == 0xe0
2473 DAC_ENUM_VTHIS();
2474 DomainFile::EnumMemoryRegions(flags);
2475
2476 // For minidumps without full memory, we need to always be able to iterate over m_Modules.
2477 m_Modules.EnumMemoryRegions(flags);
2478
2479 if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE)
2480 {
2481 if (m_pAssembly.IsValid())
2482 {
2483 m_pAssembly->EnumMemoryRegions(flags);
2484 }
2485 }
2486}
2487
2488
2489#endif // #ifdef DACCESS_COMPILE
2490
2491