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//
6// CoreAssemblySpec.cpp
7//
8
9
10//
11// CoreCLR specific implementation of AssemblySpec and BaseAssemblySpec
12// ============================================================
13
14#include "common.h"
15#include "peimage.h"
16#include "appdomain.inl"
17#include <peimage.h>
18#include "peimagelayout.inl"
19#include "domainfile.h"
20#include "holder.h"
21#include "../binder/inc/assemblybinder.hpp"
22
23#ifdef FEATURE_PREJIT
24#include "compile.h"
25#endif
26
27
28#include "../binder/inc/textualidentityparser.hpp"
29#include "../binder/inc/assemblyidentity.hpp"
30#include "../binder/inc/assembly.hpp"
31#include "../binder/inc/assemblyname.hpp"
32#include "../binder/inc/fusionassemblyname.hpp"
33
34#include "../binder/inc/coreclrbindercommon.h"
35#include "../binder/inc/applicationcontext.hpp"
36#ifndef DACCESS_COMPILE
37
38STDAPI BinderGetImagePath(PEImage *pPEImage,
39 SString &imagePath)
40{
41 HRESULT hr = S_OK;
42
43 _ASSERTE(pPEImage != NULL);
44
45 imagePath.Set(pPEImage->GetPath());
46 return hr;
47}
48
49STDAPI BinderAddRefPEImage(PEImage *pPEImage)
50{
51 HRESULT hr = S_OK;
52
53 if (pPEImage != NULL)
54 {
55 pPEImage->AddRef();
56 }
57
58 return hr;
59}
60
61STDAPI BinderReleasePEImage(PEImage *pPEImage)
62{
63 HRESULT hr = S_OK;
64
65 if (pPEImage != NULL)
66 {
67 pPEImage->Release();
68 }
69
70 return hr;
71}
72
73STDAPI BinderGetDisplayName(PEAssembly *pAssembly,
74 SString &displayName)
75{
76 HRESULT hr = S_OK;
77
78 if (pAssembly != NULL)
79 {
80 pAssembly->GetDisplayName(displayName, ASM_DISPLAYF_FULL);
81 }
82
83 return hr;
84}
85
86
87
88static VOID ThrowLoadError(AssemblySpec * pSpec, HRESULT hr)
89{
90 CONTRACTL
91 {
92 THROWS;
93 MODE_ANY;
94 GC_TRIGGERS;
95 }
96 CONTRACTL_END;
97
98 StackSString name;
99 pSpec->GetFileOrDisplayName(0, name);
100 EEFileLoadException::Throw(name, hr);
101}
102
103// See code:BINDER_SPACE::AssemblyBinder::GetAssembly for info on fNgenExplicitBind
104// and fExplicitBindToNativeImage, and see code:CEECompileInfo::LoadAssemblyByPath
105// for an example of how they're used.
106VOID AssemblySpec::Bind(AppDomain *pAppDomain,
107 BOOL fThrowOnFileNotFound,
108 CoreBindResult *pResult,
109 BOOL fNgenExplicitBind /* = FALSE */,
110 BOOL fExplicitBindToNativeImage /* = FALSE */)
111{
112 CONTRACTL
113 {
114 INSTANCE_CHECK;
115 STANDARD_VM_CHECK;
116 PRECONDITION(CheckPointer(pResult));
117 PRECONDITION(CheckPointer(pAppDomain));
118 PRECONDITION(IsMscorlib() == FALSE); // This should never be called for MSCORLIB (explicit loading)
119 }
120 CONTRACTL_END;
121
122 ReleaseHolder<BINDER_SPACE::Assembly> result;
123 HRESULT hr=S_OK;
124
125 SString assemblyDisplayName;
126
127 pResult->Reset();
128
129 if (m_wszCodeBase==NULL)
130 {
131 GetFileOrDisplayName(0, assemblyDisplayName);
132 }
133
134 // Have a default binding context setup
135 ICLRPrivBinder *pBinder = GetBindingContextFromParentAssembly(pAppDomain);
136
137 // Get the reference to the TPABinder context
138 CLRPrivBinderCoreCLR *pTPABinder = pAppDomain->GetTPABinderContext();
139
140 ReleaseHolder<ICLRPrivAssembly> pPrivAsm;
141 _ASSERTE(pBinder != NULL);
142
143 if (m_wszCodeBase==NULL && IsMscorlibSatellite())
144 {
145 StackSString sSystemDirectory(SystemDomain::System()->SystemDirectory());
146 StackSString tmpString;
147 StackSString sSimpleName;
148 StackSString sCultureName;
149
150 tmpString.SetUTF8(m_pAssemblyName);
151 tmpString.ConvertToUnicode(sSimpleName);
152
153 tmpString.Clear();
154 if ((m_context.szLocale != NULL) && (m_context.szLocale[0] != 0))
155 {
156 tmpString.SetUTF8(m_context.szLocale);
157 tmpString.ConvertToUnicode(sCultureName);
158 }
159
160 hr = CCoreCLRBinderHelper::BindToSystemSatellite(sSystemDirectory, sSimpleName, sCultureName, &pPrivAsm);
161 }
162 else if(m_wszCodeBase==NULL)
163 {
164 // For name based binding these arguments shouldnt have been changed from default
165 _ASSERTE(!fNgenExplicitBind && !fExplicitBindToNativeImage);
166 SafeComHolder<IAssemblyName> pName;
167 hr = CreateAssemblyNameObject(&pName, assemblyDisplayName, CANOF_PARSE_DISPLAY_NAME, NULL);
168 if (SUCCEEDED(hr))
169 {
170 hr = pBinder->BindAssemblyByName(pName, &pPrivAsm);
171 }
172 }
173 else
174 {
175 hr = pTPABinder->Bind(assemblyDisplayName,
176 m_wszCodeBase,
177 GetParentAssembly()? GetParentAssembly()->GetFile():NULL,
178 fNgenExplicitBind,
179 fExplicitBindToNativeImage,
180 &pPrivAsm);
181 }
182
183 pResult->SetHRBindResult(hr);
184 if (SUCCEEDED(hr))
185 {
186 _ASSERTE(pPrivAsm != nullptr);
187
188 result = BINDER_SPACE::GetAssemblyFromPrivAssemblyFast(pPrivAsm.Extract());
189 _ASSERTE(result != nullptr);
190
191 pResult->Init(result);
192 }
193 else if (FAILED(hr) && (fThrowOnFileNotFound || (!Assembly::FileNotFound(hr))))
194 {
195 ThrowLoadError(this, hr);
196 }
197}
198
199
200STDAPI BinderAcquirePEImage(LPCWSTR wszAssemblyPath,
201 PEImage **ppPEImage,
202 PEImage **ppNativeImage,
203 BOOL fExplicitBindToNativeImage)
204{
205 HRESULT hr = S_OK;
206
207 _ASSERTE(ppPEImage != NULL);
208
209 EX_TRY
210 {
211 PEImageHolder pImage = NULL;
212 PEImageHolder pNativeImage = NULL;
213
214#ifdef FEATURE_PREJIT
215 // fExplicitBindToNativeImage is set on Phone when we bind to a list of native images and have no IL on device for an assembly
216 if (fExplicitBindToNativeImage)
217 {
218 pNativeImage = PEImage::OpenImage(wszAssemblyPath, MDInternalImport_TrustedNativeImage);
219
220 // Make sure that the IL image can be opened if the native image is not available.
221 hr=pNativeImage->TryOpenFile();
222 if (FAILED(hr))
223 {
224 goto Exit;
225 }
226 }
227 else
228#endif
229 {
230 pImage = PEImage::OpenImage(wszAssemblyPath, MDInternalImport_Default);
231
232 // Make sure that the IL image can be opened if the native image is not available.
233 hr=pImage->TryOpenFile();
234 if (FAILED(hr))
235 {
236 goto Exit;
237 }
238 }
239
240 if (pImage)
241 *ppPEImage = pImage.Extract();
242
243 if (ppNativeImage)
244 *ppNativeImage = pNativeImage.Extract();
245 }
246 EX_CATCH_HRESULT(hr);
247
248 Exit:
249 return hr;
250}
251
252STDAPI BinderHasNativeHeader(PEImage *pPEImage, BOOL* result)
253{
254 HRESULT hr = S_OK;
255
256 _ASSERTE(pPEImage != NULL);
257 _ASSERTE(result != NULL);
258
259 EX_TRY
260 {
261 *result = pPEImage->HasNativeHeader();
262 }
263 EX_CATCH_HRESULT(hr);
264
265 if (FAILED(hr))
266 {
267 *result = false;
268
269#if defined(FEATURE_PAL)
270 // PAL_LOADLoadPEFile may fail while loading IL masquerading as NI.
271 // This will result in a ThrowHR(E_FAIL). Suppress the error.
272 if(hr == E_FAIL)
273 {
274 hr = S_OK;
275 }
276#endif // defined(FEATURE_PAL)
277 }
278
279 return hr;
280}
281
282STDAPI BinderAcquireImport(PEImage *pPEImage,
283 IMDInternalImport **ppIAssemblyMetaDataImport,
284 DWORD *pdwPAFlags,
285 BOOL bNativeImage)
286{
287 HRESULT hr = S_OK;
288
289 _ASSERTE(pPEImage != NULL);
290 _ASSERTE(ppIAssemblyMetaDataImport != NULL);
291 _ASSERTE(pdwPAFlags != NULL);
292
293 EX_TRY
294 {
295 PEImageLayoutHolder pLayout(pPEImage->GetLayout(PEImageLayout::LAYOUT_ANY,PEImage::LAYOUT_CREATEIFNEEDED));
296
297 // CheckCorHeader includes check of NT headers too
298 if (!pLayout->CheckCorHeader())
299 IfFailGo(COR_E_ASSEMBLYEXPECTED);
300
301 if (!pLayout->CheckFormat())
302 IfFailGo(COR_E_BADIMAGEFORMAT);
303
304 if (bNativeImage && pPEImage->IsNativeILILOnly())
305 {
306 pPEImage->GetNativeILPEKindAndMachine(&pdwPAFlags[0], &pdwPAFlags[1]);
307 }
308 else
309 {
310 pPEImage->GetPEKindAndMachine(&pdwPAFlags[0], &pdwPAFlags[1]);
311 }
312
313 *ppIAssemblyMetaDataImport = pPEImage->GetMDImport();
314 if (!*ppIAssemblyMetaDataImport)
315 {
316 // Some native images don't contain metadata, to reduce size
317 if (!bNativeImage)
318 IfFailGo(COR_E_BADIMAGEFORMAT);
319 }
320 else
321 (*ppIAssemblyMetaDataImport)->AddRef();
322 }
323 EX_CATCH_HRESULT(hr);
324ErrExit:
325 return hr;
326}
327
328HRESULT BaseAssemblySpec::ParseName()
329{
330 CONTRACTL
331 {
332 INSTANCE_CHECK;
333 GC_TRIGGERS;
334 NOTHROW;
335 INJECT_FAULT(return E_OUTOFMEMORY;);
336 }
337 CONTRACTL_END;
338
339 if (!m_pAssemblyName)
340 return S_OK;
341
342 HRESULT hr = S_OK;
343
344 EX_TRY
345 {
346 NewHolder<BINDER_SPACE::AssemblyIdentityUTF8> pAssemblyIdentity;
347 AppDomain *pDomain = ::GetAppDomain();
348 _ASSERTE(pDomain);
349
350 BINDER_SPACE::ApplicationContext *pAppContext = NULL;
351 IUnknown *pIUnknownBinder = pDomain->GetFusionContext();
352
353 if (pIUnknownBinder != NULL)
354 {
355#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
356 if (pDomain->GetFusionContext() != pDomain->GetTPABinderContext())
357 {
358 pAppContext = (static_cast<CLRPrivBinderAssemblyLoadContext *>(static_cast<ICLRPrivBinder*>(pIUnknownBinder)))->GetAppContext();
359 }
360 else
361#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
362 {
363 pAppContext = (static_cast<CLRPrivBinderCoreCLR *>(pIUnknownBinder))->GetAppContext();
364 }
365 }
366
367 hr = CCoreCLRBinderHelper::GetAssemblyIdentity(m_pAssemblyName, pAppContext, pAssemblyIdentity);
368
369 if (FAILED(hr))
370 {
371 m_ownedFlags |= BAD_NAME_OWNED;
372 IfFailThrow(hr);
373 }
374
375 SetName(pAssemblyIdentity->GetSimpleNameUTF8());
376
377 if (pAssemblyIdentity->Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_VERSION))
378 {
379 m_context.usMajorVersion = (USHORT)pAssemblyIdentity->m_version.GetMajor();
380 m_context.usMinorVersion = (USHORT)pAssemblyIdentity->m_version.GetMinor();
381 m_context.usBuildNumber = (USHORT)pAssemblyIdentity->m_version.GetBuild();
382 m_context.usRevisionNumber = (USHORT)pAssemblyIdentity->m_version.GetRevision();
383 }
384
385 if (pAssemblyIdentity->Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CULTURE))
386 {
387 if (!pAssemblyIdentity->m_cultureOrLanguage.IsEmpty())
388 SetCulture(pAssemblyIdentity->GetCultureOrLanguageUTF8());
389 else
390 SetCulture("");
391 }
392
393 if (pAssemblyIdentity->
394 Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN) ||
395 pAssemblyIdentity->Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY))
396 {
397 m_pbPublicKeyOrToken = const_cast<BYTE *>(pAssemblyIdentity->GetPublicKeyOrTokenArray());
398 m_cbPublicKeyOrToken = pAssemblyIdentity->m_publicKeyOrTokenBLOB.GetSize();
399
400 if (pAssemblyIdentity->Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY))
401 {
402 m_dwFlags |= afPublicKey;
403 }
404 }
405 else if (pAssemblyIdentity->
406 Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL))
407 {
408 m_pbPublicKeyOrToken = const_cast<BYTE *>(pAssemblyIdentity->GetPublicKeyOrTokenArray());
409 m_cbPublicKeyOrToken = 0;
410 }
411 else
412 {
413 m_pbPublicKeyOrToken = NULL;
414 m_cbPublicKeyOrToken = 0;
415 }
416
417 if (pAssemblyIdentity->
418 Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE))
419 {
420 switch (pAssemblyIdentity->m_kProcessorArchitecture)
421 {
422 case peI386:
423 m_dwFlags |= afPA_x86;
424 break;
425 case peIA64:
426 m_dwFlags |= afPA_IA64;
427 break;
428 case peAMD64:
429 m_dwFlags |= afPA_AMD64;
430 break;
431 case peARM:
432 m_dwFlags |= afPA_ARM;
433 break;
434 case peMSIL:
435 m_dwFlags |= afPA_MSIL;
436 break;
437 default:
438 IfFailThrow(FUSION_E_INVALID_NAME);
439 }
440 }
441
442
443 if (pAssemblyIdentity->
444 Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE))
445 {
446 m_dwFlags |= afRetargetable;
447 }
448
449 if (pAssemblyIdentity->
450 Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE))
451 {
452 DWORD dwContentType = pAssemblyIdentity->m_kContentType;
453
454 _ASSERTE((dwContentType == AssemblyContentType_Default) || (dwContentType == AssemblyContentType_WindowsRuntime));
455 if (dwContentType == AssemblyContentType_WindowsRuntime)
456 {
457 m_dwFlags |= afContentType_WindowsRuntime;
458 }
459 }
460
461 CloneFields();
462 }
463 EX_CATCH_HRESULT(hr);
464
465 return hr;
466}
467
468#endif // DACCESS_COMPILE
469
470VOID BaseAssemblySpec::GetFileOrDisplayName(DWORD flags, SString &result) const
471{
472 CONTRACTL
473 {
474 INSTANCE_CHECK;
475 THROWS;
476 INJECT_FAULT(ThrowOutOfMemory());
477 PRECONDITION(CheckValue(result));
478 PRECONDITION(result.IsEmpty());
479 }
480 CONTRACTL_END;
481
482 if (m_wszCodeBase)
483 {
484 result.Set(m_wszCodeBase);
485 return;
486 }
487
488 if (flags==0)
489 flags=ASM_DISPLAYF_FULL;
490
491 BINDER_SPACE::AssemblyIdentity assemblyIdentity;
492 SString tmpString;
493
494 tmpString.SetUTF8(m_pAssemblyName);
495
496 if ((m_ownedFlags & BAD_NAME_OWNED) != 0)
497 {
498 // Can't do anything with a broken name
499 tmpString.ConvertToUnicode(result);
500 return;
501 }
502 else
503 {
504 tmpString.ConvertToUnicode(assemblyIdentity.m_simpleName);
505 assemblyIdentity.SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_SIMPLE_NAME);
506 }
507
508 if( flags & ASM_DISPLAYF_VERSION && m_context.usMajorVersion != 0xFFFF)
509 {
510 assemblyIdentity.m_version.SetFeatureVersion(m_context.usMajorVersion,
511 m_context.usMinorVersion);
512 assemblyIdentity.m_version.SetServiceVersion(m_context.usBuildNumber,
513 m_context.usRevisionNumber);
514 assemblyIdentity.SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_VERSION);
515 }
516
517 if(flags & ASM_DISPLAYF_CULTURE)
518 {
519 assemblyIdentity.SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CULTURE);
520 if ((m_context.szLocale != NULL) && (m_context.szLocale[0] != 0))
521 {
522 tmpString.SetUTF8(m_context.szLocale);
523 tmpString.ConvertToUnicode(assemblyIdentity.m_cultureOrLanguage);
524 }
525 }
526
527 if(flags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN)
528 {
529 if (m_cbPublicKeyOrToken)
530 {
531 assemblyIdentity.SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
532 if(IsAfPublicKeyToken(m_dwFlags))
533 {
534 assemblyIdentity.m_publicKeyOrTokenBLOB.Set(m_pbPublicKeyOrToken,
535 m_cbPublicKeyOrToken);
536 }
537 else
538 {
539 DWORD cbToken = 0;
540 StrongNameBufferHolder<BYTE> pbToken;
541
542 // Try to get the strong name
543 if (!StrongNameTokenFromPublicKey(m_pbPublicKeyOrToken,
544 m_cbPublicKeyOrToken,
545 &pbToken,
546 &cbToken))
547 {
548 // Throw an exception with details on what went wrong
549 COMPlusThrowHR(StrongNameErrorInfo());
550 }
551
552 assemblyIdentity.m_publicKeyOrTokenBLOB.Set(pbToken, cbToken);
553 }
554 }
555 else
556 {
557 assemblyIdentity.
558 SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL);
559 }
560 }
561
562 if ((flags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (m_dwFlags & afPA_Mask))
563 {
564 assemblyIdentity.
565 SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
566
567 if (m_dwFlags & afPA_MSIL)
568 assemblyIdentity.m_kProcessorArchitecture = peMSIL;
569 else if (m_dwFlags & afPA_x86)
570 assemblyIdentity.m_kProcessorArchitecture = peI386;
571 else if (m_dwFlags & afPA_IA64)
572 assemblyIdentity.m_kProcessorArchitecture = peIA64;
573 else if (m_dwFlags & afPA_AMD64)
574 assemblyIdentity.m_kProcessorArchitecture = peAMD64;
575 else if (m_dwFlags & afPA_ARM)
576 assemblyIdentity.m_kProcessorArchitecture = peARM;
577 }
578
579 if ((flags & ASM_DISPLAYF_RETARGET) && (m_dwFlags & afRetargetable))
580 {
581 assemblyIdentity.SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
582 }
583
584 if ((flags & ASM_DISPLAYF_CONTENT_TYPE) && (m_dwFlags & afContentType_Mask) == afContentType_WindowsRuntime)
585 {
586 assemblyIdentity.SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
587 assemblyIdentity.m_kContentType = AssemblyContentType_WindowsRuntime;
588 }
589
590 IfFailThrow(BINDER_SPACE::TextualIdentityParser::ToString(&assemblyIdentity,
591 assemblyIdentity.m_dwIdentityFlags,
592 result));
593}
594
595
596