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 // --------------------------------------------------------------------------------
8 // --------------------------------------------------------------------------------
13 #include "pedecoder.h"
15 #include "nibblemapmacros.h"
17 CHECK PEDecoder::CheckFormat() const
31 CHECK(CheckNTHeaders());
35 CHECK(CheckCorHeader());
40 if (HasNativeHeader())
41 CHECK(CheckNativeHeader());
43 CHECK(CheckWillCreateGuardPage());
50 CHECK PEDecoder::CheckNTFormat() const
57 PRECONDITION(HasContents());
62 CHECK(HasNTHeaders());
67 CHECK PEDecoder::CheckCORFormat() const
74 PRECONDITION(HasContents());
79 CHECK(HasNTHeaders());
80 CHECK(HasCorHeader());
86 CHECK PEDecoder::CheckILFormat() const
93 PRECONDITION(HasContents());
98 CHECK(HasNTHeaders());
99 CHECK(HasCorHeader());
100 CHECK(!HasNativeHeader());
106 CHECK PEDecoder::CheckILOnlyFormat() const
113 PRECONDITION(HasContents());
117 CHECK(CheckFormat());
118 CHECK(HasNTHeaders());
119 CHECK(HasCorHeader());
121 CHECK(!HasNativeHeader());
126 CHECK PEDecoder::CheckNativeFormat() const
133 PRECONDITION(HasContents());
137 #ifdef FEATURE_PREJIT
138 CHECK(CheckFormat());
139 CHECK(HasNTHeaders());
140 CHECK(HasCorHeader());
142 CHECK(HasNativeHeader());
143 #else // FEATURE_PREJIT
145 #endif // FEATURE_PREJIT
150 BOOL PEDecoder::HasNTHeaders() const
158 PRECONDITION(HasContents());
162 // Check for a valid DOS header
164 if (m_size < sizeof(IMAGE_DOS_HEADER))
167 IMAGE_DOS_HEADER* pDOS = PTR_IMAGE_DOS_HEADER(m_base);
170 if (pDOS->e_magic != VAL16(IMAGE_DOS_SIGNATURE)
171 || (DWORD) pDOS->e_lfanew == VAL32(0))
176 // Check for integer overflow
177 S_SIZE_T cbNTHeaderEnd(S_SIZE_T(static_cast<SIZE_T>(VAL32(pDOS->e_lfanew))) +
178 S_SIZE_T(sizeof(IMAGE_NT_HEADERS)));
179 if (cbNTHeaderEnd.IsOverflow())
184 // Now check for a valid NT header
185 if (m_size < cbNTHeaderEnd.Value())
191 IMAGE_NT_HEADERS *pNT = PTR_IMAGE_NT_HEADERS(m_base + VAL32(pDOS->e_lfanew));
193 if (pNT->Signature != VAL32(IMAGE_NT_SIGNATURE))
196 if (pNT->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC))
198 if (pNT->FileHeader.SizeOfOptionalHeader != VAL16(sizeof(IMAGE_OPTIONAL_HEADER32)))
201 else if (pNT->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR64_MAGIC))
203 // on 64 bit we can promote this
204 if (pNT->FileHeader.SizeOfOptionalHeader != VAL16(sizeof(IMAGE_OPTIONAL_HEADER64)))
207 // Check for integer overflow
208 S_SIZE_T cbNTHeaderEnd(S_SIZE_T(static_cast<SIZE_T>(VAL32(pDOS->e_lfanew))) +
209 S_SIZE_T(sizeof(IMAGE_NT_HEADERS64)));
211 if (cbNTHeaderEnd.IsOverflow())
216 // Now check for a valid NT header
217 if (m_size < cbNTHeaderEnd.Value())
226 // Go ahead and cache NT header since we already found it.
227 const_cast<PEDecoder *>(this)->m_pNTHeaders = dac_cast<PTR_IMAGE_NT_HEADERS>(pNT);
232 CHECK PEDecoder::CheckNTHeaders() const
240 PRECONDITION(HasContents());
244 // Only check once per file
245 if (m_flags & FLAG_NT_CHECKED)
248 CHECK(HasNTHeaders());
250 IMAGE_NT_HEADERS *pNT = FindNTHeaders();
252 CHECK((pNT->FileHeader.Characteristics & VAL16(IMAGE_FILE_SYSTEM)) == 0);
254 CHECK(CheckAlignment(VAL32(pNT->OptionalHeader.FileAlignment)));
255 CHECK(CheckAlignment(VAL32(pNT->OptionalHeader.SectionAlignment)));
257 CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.FileAlignment), 512));
258 CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.SectionAlignment), VAL32(pNT->OptionalHeader.FileAlignment)));
260 CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.SizeOfImage), VAL32(pNT->OptionalHeader.SectionAlignment)));
261 CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.SizeOfHeaders), VAL32(pNT->OptionalHeader.FileAlignment)));
263 // Data directories will be validated later on.
264 PTR_IMAGE_DATA_DIRECTORY pDataDirectories = NULL;
266 if (Has32BitNTHeaders())
268 IMAGE_NT_HEADERS32* pNT32=GetNTHeaders32();
269 CHECK(CheckAligned(VAL32(pNT32->OptionalHeader.ImageBase), 0x10000));
270 CHECK((VAL32(pNT32->OptionalHeader.SizeOfStackCommit) <= VAL32(pNT32->OptionalHeader.SizeOfStackReserve)));
271 CHECK((VAL32(pNT32->OptionalHeader.SizeOfHeapCommit) <= VAL32(pNT32->OptionalHeader.SizeOfHeapReserve)));
272 pDataDirectories = dac_cast<PTR_IMAGE_DATA_DIRECTORY>(
273 dac_cast<TADDR>(pNT32) + offsetof(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory));
277 IMAGE_NT_HEADERS64* pNT64=GetNTHeaders64();
278 CHECK(CheckAligned(VAL64(pNT64->OptionalHeader.ImageBase), 0x10000));
279 CHECK((VAL64(pNT64->OptionalHeader.SizeOfStackCommit) <= VAL64(pNT64->OptionalHeader.SizeOfStackReserve)));
280 CHECK((VAL64(pNT64->OptionalHeader.SizeOfHeapCommit) <= VAL64(pNT64->OptionalHeader.SizeOfHeapReserve)));
281 pDataDirectories = dac_cast<PTR_IMAGE_DATA_DIRECTORY>(
282 dac_cast<TADDR>(pNT64) + offsetof(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory));
285 // @todo: this is a bit awkward here, it would be better to make this assertion on
286 // PEDecoder instantiation. However, we don't necessarily have the NT headers there (in fact
287 // they might not exist.)
291 // Ideally we would require the layout address to honor the section alignment constraints.
292 // However, we do have 8K aligned IL only images which we load on 32 bit platforms. In this
293 // case, we can only guarantee OS page alignment (which after all, is good enough.)
294 CHECK(CheckAligned(m_base, GetOsPageSize()));
297 // @todo: check NumberOfSections for overflow of SizeOfHeaders
299 UINT32 currentAddress = 0;
300 UINT32 currentOffset = 0;
302 CHECK(CheckSection(currentAddress, 0, VAL32(pNT->OptionalHeader.SizeOfHeaders),
303 currentOffset, 0, VAL32(pNT->OptionalHeader.SizeOfHeaders)));
305 currentAddress=currentOffset=VAL32(pNT->OptionalHeader.SizeOfHeaders);
307 PTR_IMAGE_SECTION_HEADER section = FindFirstSection(pNT);
308 PTR_IMAGE_SECTION_HEADER sectionEnd = section + VAL16(pNT->FileHeader.NumberOfSections);
310 CHECK(sectionEnd >= section);
313 while (section < sectionEnd)
317 // NOTE: the if condition is becuase of a design issue in the CLR and OS loader's remapping
318 // of PE32 headers to PE32+. Because IMAGE_NT_HEADERS64 is bigger than IMAGE_NT_HEADERS32,
319 // the remapping will expand this part of the header and push out the following
320 // IMAGE_SECTION_HEADER entries. When IMAGE_DOS_HEADER::e_lfanew is large enough (size is
321 // proportional to the number of tools used to produce the inputs to the C++ linker, and
322 // has become larger when producing some WinMD files) this can push the last section header
323 // beyond the boundary set by IMAGE_NT_HEADERS::OptionalHeader.SizeOfHeaders (e.g., this
324 // was recently seen where the unaligned size of the headers was 0x1f8 and SizeOfHeaders was
325 // 0x200, and the header remapping resulted in new headers size of 0x208). To compensate
326 // for this issue (it would be quite difficult to fix in the remapping code; see Dev11 430008)
327 // we assume that when the image is mapped that the needed validation has already been done.
332 CHECK(CheckBounds(dac_cast<PTR_CVOID>(pNT),VAL32(pNT->OptionalHeader.SizeOfHeaders),
333 section,sizeof(IMAGE_SECTION_HEADER)));
337 // Only allow a small list of characteristics
338 CHECK(!(section->Characteristics &
339 ~(VAL32((IMAGE_SCN_CNT_CODE |
340 IMAGE_SCN_CNT_INITIALIZED_DATA |
341 IMAGE_SCN_CNT_UNINITIALIZED_DATA|
342 IMAGE_SCN_MEM_DISCARDABLE |
343 IMAGE_SCN_MEM_NOT_CACHED |
344 IMAGE_SCN_MEM_NOT_PAGED |
345 IMAGE_SCN_MEM_EXECUTE |
347 IMAGE_SCN_MEM_WRITE |
348 // allow shared sections for all images for now.
349 // we'll constrain this in CheckILOnly
350 IMAGE_SCN_MEM_SHARED)))));
352 // we should not allow writable code sections, check if both flags are set
353 CHECK((section->Characteristics & VAL32((IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_WRITE))) !=
354 VAL32((IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_WRITE)));
356 CHECK(CheckSection(currentAddress, VAL32(section->VirtualAddress), VAL32(section->Misc.VirtualSize),
357 currentOffset, VAL32(section->PointerToRawData), VAL32(section->SizeOfRawData)));
359 currentAddress = VAL32(section->VirtualAddress)
360 + AlignUp((UINT)VAL32(section->Misc.VirtualSize), (UINT)VAL32(pNT->OptionalHeader.SectionAlignment));
361 currentOffset = VAL32(section->PointerToRawData) + VAL32(section->SizeOfRawData);
366 // Now check that the COR data directory is either NULL, or exists entirely in one section.
368 PTR_IMAGE_DATA_DIRECTORY pCORDataDir = pDataDirectories + IMAGE_DIRECTORY_ENTRY_COMHEADER;
369 CHECK(CheckRva(VAL32(pCORDataDir->VirtualAddress), VAL32(pCORDataDir->Size), 0, NULL_OK));
372 // @todo: verify directory entries
374 const_cast<PEDecoder *>(this)->m_flags |= FLAG_NT_CHECKED;
379 CHECK PEDecoder::CheckSection(COUNT_T previousAddressEnd, COUNT_T addressStart, COUNT_T addressSize,
380 COUNT_T previousOffsetEnd, COUNT_T offsetStart, COUNT_T offsetSize) const
385 PRECONDITION(HasNTHeaders());
392 // Fetch the NT header
393 IMAGE_NT_HEADERS *pNT = FindNTHeaders();
395 // OS will zero pad a mapped file up to file alignment size - some images rely on this
396 // COUNT_T alignedSize = AlignUp(m_size, VAL32(pNT->OptionalHeader.FileAlignment));
397 COUNT_T alignedSize = IsMapped() ? AlignUp(m_size, VAL32(pNT->OptionalHeader.FileAlignment)) : m_size;
399 // Check to make sure that our memory is big enough to cover the stated range.
400 // Note that this check is only required if we have a non-flat image.
402 CHECK(alignedSize >= VAL32(pNT->OptionalHeader.SizeOfImage));
404 // Check expected alignments
405 CHECK(CheckAligned(addressStart, VAL32(pNT->OptionalHeader.SectionAlignment)));
406 CHECK(CheckAligned(offsetStart, VAL32(pNT->OptionalHeader.FileAlignment)));
407 CHECK(CheckAligned(offsetSize, VAL32(pNT->OptionalHeader.FileAlignment)));
409 // addressSize is typically not aligned, so we align it for purposes of checks.
410 COUNT_T alignedAddressSize = AlignUp(addressSize, VAL32(pNT->OptionalHeader.SectionAlignment));
411 CHECK(addressSize <= alignedAddressSize);
414 CHECK(CheckOverflow(addressStart, alignedAddressSize));
415 CHECK(CheckOverflow(offsetStart, offsetSize));
417 // Make sure we don't overlap the previous section
418 CHECK(addressStart >= previousAddressEnd
420 || offsetStart >= previousOffsetEnd));
422 // Make sure we don't overrun the end of the mapped image
423 CHECK(addressStart + alignedAddressSize <= VAL32(pNT->OptionalHeader.SizeOfImage));
425 // Make sure we don't overrun the end of the file (only relevant if we're not mapped, otherwise
426 // we don't know the file size, as it's not declared in the headers.)
428 CHECK(offsetStart + offsetSize <= alignedSize);
430 // Make sure the data doesn't overrun the virtual address space
431 CHECK(offsetSize <= alignedAddressSize);
436 BOOL PEDecoder::HasWriteableSections() const
441 PRECONDITION(CheckNTHeaders());
442 PRECONDITION(CheckFormat());
449 PTR_IMAGE_SECTION_HEADER pSection = FindFirstSection();
450 _ASSERTE(pSection != NULL);
452 PTR_IMAGE_SECTION_HEADER pSectionEnd = pSection + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
454 while (pSection < pSectionEnd)
456 if ((pSection->Characteristics & VAL32(IMAGE_SCN_MEM_WRITE)) != 0)
467 CHECK PEDecoder::CheckDirectoryEntry(int entry, int forbiddenFlags, IsNullOK ok) const
472 PRECONDITION(CheckNTHeaders());
473 PRECONDITION(entry < IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
474 PRECONDITION(HasDirectoryEntry(entry));
480 CHECK(CheckDirectory(GetDirectoryEntry(entry), forbiddenFlags, ok));
485 CHECK PEDecoder::CheckDirectory(IMAGE_DATA_DIRECTORY *pDir, int forbiddenFlags, IsNullOK ok) const
490 PRECONDITION(CheckNTHeaders());
491 PRECONDITION(CheckPointer(pDir));
498 CHECK(CheckRva(VAL32(pDir->VirtualAddress), VAL32(pDir->Size), forbiddenFlags, ok));
503 CHECK PEDecoder::CheckRva(RVA rva, COUNT_T size, int forbiddenFlags, IsNullOK ok) const
516 CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
521 IMAGE_SECTION_HEADER *section = RvaToSection(rva);
523 CHECK(section != NULL);
525 CHECK(CheckBounds(VAL32(section->VirtualAddress),
526 // AlignUp((UINT)VAL32(section->Misc.VirtualSize), (UINT)VAL32(FindNTHeaders()->OptionalHeader.SectionAlignment)),
527 (UINT)VAL32(section->Misc.VirtualSize),
531 CHECK(CheckBounds(VAL32(section->VirtualAddress), VAL32(section->SizeOfRawData), rva, size));
534 if (forbiddenFlags!=0)
535 CHECK((section->Characteristics & VAL32(forbiddenFlags))==0);
541 CHECK PEDecoder::CheckRva(RVA rva, IsNullOK ok) const
553 CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
555 CHECK(RvaToSection(rva) != NULL);
560 CHECK PEDecoder::CheckOffset(COUNT_T fileOffset, COUNT_T size, IsNullOK ok) const
565 PRECONDITION(CheckNTHeaders());
573 CHECK_MSG(ok == NULL_OK, "zero fileOffset illegal");
578 IMAGE_SECTION_HEADER *section = OffsetToSection(fileOffset);
580 CHECK(section != NULL);
582 CHECK(CheckBounds(section->PointerToRawData, section->SizeOfRawData,
589 CHECK PEDecoder::CheckOffset(COUNT_T fileOffset, IsNullOK ok) const
594 PRECONDITION(CheckNTHeaders());
600 if (fileOffset == NULL)
601 CHECK_MSG(ok == NULL_OK, "Null pointer illegal");
604 CHECK(OffsetToSection(fileOffset) != NULL);
610 CHECK PEDecoder::CheckData(const void *data, COUNT_T size, IsNullOK ok) const
615 PRECONDITION(CheckNTHeaders());
623 CHECK_MSG(ok == NULL_OK, "NULL pointer illegal");
628 CHECK(CheckUnderflow(data, m_base));
629 CHECK((UINT_PTR) (((BYTE *) data) - ((BYTE *) m_base)) <= COUNT_T_MAX);
632 CHECK(CheckRva((COUNT_T) ((BYTE *) data - (BYTE *) m_base), size));
634 CHECK(CheckOffset((COUNT_T) ((BYTE *) data - (BYTE *) m_base), size));
640 CHECK PEDecoder::CheckData(const void *data, IsNullOK ok) const
645 PRECONDITION(CheckNTHeaders());
652 CHECK_MSG(ok == NULL_OK, "Null pointer illegal");
655 CHECK(CheckUnderflow(data, m_base));
656 CHECK((UINT_PTR) (((BYTE *) data) - ((BYTE *) m_base)) <= COUNT_T_MAX);
659 CHECK(CheckRva((COUNT_T) ((BYTE *) data - (BYTE *) m_base)));
661 CHECK(CheckOffset((COUNT_T) ((BYTE *) data - (BYTE *) m_base)));
667 CHECK PEDecoder::CheckInternalAddress(SIZE_T address, IsNullOK ok) const
672 PRECONDITION(CheckNTHeaders());
679 CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
681 CHECK(RvaToSection(InternalAddressToRva(address)) != NULL);
686 CHECK PEDecoder::CheckInternalAddress(SIZE_T address, COUNT_T size, IsNullOK ok) const
691 PRECONDITION(CheckNTHeaders());
699 CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
704 CHECK(CheckRva(InternalAddressToRva(address), size));
710 RVA PEDecoder::InternalAddressToRva(SIZE_T address) const
715 PRECONDITION(CheckNTHeaders());
718 POSTCONDITION(CheckRva(RETVAL));
722 if (m_flags & FLAG_RELOCATED)
724 // Address has been fixed up
725 RETURN (RVA) ((BYTE *) address - (BYTE *) m_base);
729 // Address has not been fixed up
730 RETURN (RVA) (address - (SIZE_T) GetPreferredBase());
734 // Returns a pointer to the named section or NULL if not found.
735 // The name should include the starting "." as well.
736 IMAGE_SECTION_HEADER *PEDecoder::FindSection(LPCSTR sectionName) const
738 CONTRACT(IMAGE_SECTION_HEADER *)
741 PRECONDITION(CheckNTHeaders());
742 PRECONDITION(sectionName != NULL);
746 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
750 // Ensure that the section name length is valid
751 SIZE_T iSectionNameLength = strlen(sectionName);
752 if ((iSectionNameLength < 1) || (iSectionNameLength > IMAGE_SIZEOF_SHORT_NAME))
754 _ASSERTE(!"Invalid section name!");
758 // Get the start and ends of the sections
759 PTR_IMAGE_SECTION_HEADER pSection = FindFirstSection(FindNTHeaders());
760 _ASSERTE(pSection != NULL);
761 PTR_IMAGE_SECTION_HEADER pSectionEnd = pSection + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
762 _ASSERTE(pSectionEnd != NULL);
764 BOOL fFoundSection = FALSE;
766 // Loop thru the sections and see if we got the section we are interested in
767 while (pSection < pSectionEnd)
769 // Is this the section we are looking for?
770 if (strncmp(sectionName, (char*)pSection->Name, iSectionNameLength) == 0)
772 // We found our section - break out of the loop
773 fFoundSection = TRUE;
777 // Move to the next section
781 if (TRUE == fFoundSection)
787 IMAGE_SECTION_HEADER *PEDecoder::RvaToSection(RVA rva) const
789 CONTRACT(IMAGE_SECTION_HEADER *)
795 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
800 PTR_IMAGE_SECTION_HEADER section = dac_cast<PTR_IMAGE_SECTION_HEADER>(FindFirstSection(FindNTHeaders()));
801 PTR_IMAGE_SECTION_HEADER sectionEnd = section + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
803 while (section < sectionEnd)
805 if (rva < (VAL32(section->VirtualAddress)
806 + AlignUp((UINT)VAL32(section->Misc.VirtualSize), (UINT)VAL32(FindNTHeaders()->OptionalHeader.SectionAlignment))))
808 if (rva < VAL32(section->VirtualAddress))
822 IMAGE_SECTION_HEADER *PEDecoder::OffsetToSection(COUNT_T fileOffset) const
824 CONTRACT(IMAGE_SECTION_HEADER *)
827 PRECONDITION(CheckNTHeaders());
830 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
835 PTR_IMAGE_SECTION_HEADER section = dac_cast<PTR_IMAGE_SECTION_HEADER>(FindFirstSection(FindNTHeaders()));
836 PTR_IMAGE_SECTION_HEADER sectionEnd = section + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
838 while (section < sectionEnd)
840 if (fileOffset < section->PointerToRawData + section->SizeOfRawData)
842 if (fileOffset < section->PointerToRawData)
854 TADDR PEDecoder::GetRvaData(RVA rva, IsNullOK ok /*= NULL_NOT_OK*/) const
859 PRECONDITION(CheckNTHeaders());
860 PRECONDITION(CheckRva(rva, NULL_OK));
868 if ((rva == 0)&&(ok == NULL_NOT_OK))
876 // !!! check for case where rva is in padded portion of segment
877 offset = RvaToOffset(rva);
880 RETURN( m_base + offset );
883 RVA PEDecoder::GetDataRva(const TADDR data) const
888 PRECONDITION(CheckNTHeaders());
889 PRECONDITION(CheckData((void *)data, NULL_OK));
899 COUNT_T offset = (COUNT_T) (data - m_base);
903 RETURN OffsetToRva(offset);
906 BOOL PEDecoder::PointerInPE(PTR_CVOID data) const
918 TADDR taddrData = dac_cast<TADDR>(data);
919 TADDR taddrBase = dac_cast<TADDR>(m_base);
921 if (this->IsMapped())
923 return taddrBase <= taddrData && taddrData < taddrBase + GetVirtualSize();
927 return taddrBase <= taddrData && taddrData < taddrBase + GetSize();
931 TADDR PEDecoder::GetOffsetData(COUNT_T fileOffset, IsNullOK ok /*= NULL_NOT_OK*/) const
936 PRECONDITION(CheckNTHeaders());
937 PRECONDITION(CheckOffset(fileOffset, NULL_OK));
943 if ((fileOffset == 0)&&(ok == NULL_NOT_OK))
946 RETURN GetRvaData(OffsetToRva(fileOffset));
949 //-------------------------------------------------------------------------------
950 // Lifted from "..\md\inc\mdfileformat.h"
951 // (cannot #include it here because it references lot of other stuff)
952 #define STORAGE_MAGIC_SIG 0x424A5342 // BSJB
953 struct STORAGESIGNATURE
955 ULONG lSignature; // "Magic" signature.
956 USHORT iMajorVer; // Major file version.
957 USHORT iMinorVer; // Minor file version.
958 ULONG iExtraData; // Offset to next structure of information
959 ULONG iVersionString; // Length of version string
961 typedef STORAGESIGNATURE UNALIGNED * PSTORAGESIGNATURE;
962 typedef DPTR(STORAGESIGNATURE UNALIGNED) PTR_STORAGESIGNATURE;
967 BYTE fFlags; // STGHDR_xxx flags.
969 USHORT iStreams; // How many streams are there.
971 typedef STORAGEHEADER UNALIGNED * PSTORAGEHEADER;
972 typedef DPTR(STORAGEHEADER UNALIGNED) PTR_STORAGEHEADER;
977 ULONG iOffset; // Offset in file for this stream.
978 ULONG iSize; // Size of the file.
979 char rcName[32]; // Start of name, null terminated.
981 typedef STORAGESTREAM UNALIGNED * PSTORAGESTREAM;
982 typedef DPTR(STORAGESTREAM UNALIGNED) PTR_STORAGESTREAM;
985 // if the stream's name is shorter than 32 bytes (incl.zero terminator),
986 // the size of storage stream header is less than sizeof(STORAGESTREAM)
987 // and is padded to 4-byte alignment
988 inline PTR_STORAGESTREAM NextStorageStream(PTR_STORAGESTREAM pSS)
999 TADDR pc = dac_cast<TADDR>(pSS);
1000 pc += (sizeof(STORAGESTREAM) - 32 /*sizeof(STORAGESTREAM::rcName)*/ + strlen(pSS->rcName)+1+3)&~3;
1001 return PTR_STORAGESTREAM(pc);
1003 //-------------------------------------------------------------------------------
1006 CHECK PEDecoder::CheckCorHeader() const
1017 if (m_flags & FLAG_COR_CHECKED)
1020 CHECK(CheckNTHeaders());
1022 CHECK(HasCorHeader());
1024 IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_COMHEADER);
1026 CHECK(CheckDirectory(pDir, IMAGE_SCN_MEM_WRITE, NULL_NOT_OK));
1028 CHECK(VAL32(pDir->Size) >= sizeof(IMAGE_COR20_HEADER));
1030 IMAGE_SECTION_HEADER *section = RvaToSection(VAL32(pDir->VirtualAddress));
1031 CHECK(section != NULL);
1032 CHECK((section->Characteristics & VAL32(IMAGE_SCN_MEM_READ))!=0);
1034 CHECK(CheckRva(VAL32(pDir->VirtualAddress), sizeof(IMAGE_COR20_HEADER)));
1036 IMAGE_COR20_HEADER *pCor = GetCorHeader();
1038 //CHECK(((ULONGLONG)pCor & 0x3)==0);
1040 // If the file is COM+ 1.0, which by definition has nothing the runtime can
1041 // use, or if the file requires a newer version of this engine than us,
1042 // it cannot be run by this engine.
1043 CHECK(VAL16(pCor->MajorRuntimeVersion) > 1 && VAL16(pCor->MajorRuntimeVersion) <= COR_VERSION_MAJOR);
1045 CHECK(CheckDirectory(&pCor->MetaData, IMAGE_SCN_MEM_WRITE, HasNativeHeader() ? NULL_OK : NULL_NOT_OK));
1046 CHECK(CheckDirectory(&pCor->Resources, IMAGE_SCN_MEM_WRITE, NULL_OK));
1047 CHECK(CheckDirectory(&pCor->StrongNameSignature, IMAGE_SCN_MEM_WRITE, NULL_OK));
1048 CHECK(CheckDirectory(&pCor->CodeManagerTable, IMAGE_SCN_MEM_WRITE, NULL_OK));
1049 CHECK(CheckDirectory(&pCor->VTableFixups, 0, NULL_OK));
1050 CHECK(CheckDirectory(&pCor->ExportAddressTableJumps, 0, NULL_OK));
1051 CHECK(CheckDirectory(&pCor->ManagedNativeHeader, 0, NULL_OK));
1053 CHECK(VAL32(pCor->cb) >= offsetof(IMAGE_COR20_HEADER, ManagedNativeHeader) + sizeof(IMAGE_DATA_DIRECTORY));
1055 DWORD validBits = COMIMAGE_FLAGS_ILONLY
1056 | COMIMAGE_FLAGS_32BITREQUIRED
1057 | COMIMAGE_FLAGS_TRACKDEBUGDATA
1058 | COMIMAGE_FLAGS_STRONGNAMESIGNED
1059 | COMIMAGE_FLAGS_NATIVE_ENTRYPOINT
1060 | COMIMAGE_FLAGS_IL_LIBRARY
1061 | COMIMAGE_FLAGS_32BITPREFERRED;
1063 CHECK((pCor->Flags&VAL32(~validBits)) == 0);
1065 // Pure IL images should not have VTable fixups or EAT jumps
1068 CHECK(pCor->VTableFixups.Size == VAL32(0));
1069 CHECK(pCor->ExportAddressTableJumps.Size == VAL32(0));
1070 CHECK(!(pCor->Flags & VAL32(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT)));
1071 //@TODO: If not an exe, check that EntryPointToken is mdNil
1075 if (pCor->Flags & VAL32(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT))
1077 CHECK(CheckRva(VAL32(IMAGE_COR20_HEADER_FIELD(*pCor,EntryPointToken))));
1081 // Strong name signed images should have a signature
1082 if (IsStrongNameSigned())
1083 CHECK(HasStrongNameSignature());
1085 // IL library files (really a misnomer - these are native images or ReadyToRun images)
1086 // only they can have a native image header
1087 if ((pCor->Flags&VAL32(COMIMAGE_FLAGS_IL_LIBRARY)) == 0)
1089 CHECK(VAL32(pCor->ManagedNativeHeader.Size) == 0);
1092 // Metadata header checks
1093 IMAGE_DATA_DIRECTORY *pDirMD = &pCor->MetaData;
1094 COUNT_T ctMD = (COUNT_T)VAL32(pDirMD->Size);
1095 TADDR pcMD = (TADDR)GetDirectoryData(pDirMD);
1099 // Storage signature checks
1100 CHECK(ctMD >= sizeof(STORAGESIGNATURE));
1101 PTR_STORAGESIGNATURE pStorageSig = PTR_STORAGESIGNATURE((TADDR)pcMD);
1102 COUNT_T ctMDStreamSize = ctMD; // Store MetaData stream size for later usage
1105 CHECK(VAL32(pStorageSig->lSignature) == STORAGE_MAGIC_SIG);
1107 CHECK(ClrSafeInt<COUNT_T>::addition(sizeof(STORAGESIGNATURE), (COUNT_T)VAL32(pStorageSig->iVersionString), ctSSig));
1108 CHECK(ctMD > ctSSig);
1110 // Storage header checks
1113 PTR_STORAGEHEADER pSHdr = PTR_STORAGEHEADER((TADDR)pcMD);
1117 CHECK(ctMD >= sizeof(STORAGEHEADER));
1118 pcMD = dac_cast<TADDR>(pSHdr) + sizeof(STORAGEHEADER);
1119 ctMD -= sizeof(STORAGEHEADER);
1120 WORD nStreams = VAL16(pSHdr->iStreams);
1122 // Storage streams checks (pcMD is a target pointer, so watch out)
1123 PTR_STORAGESTREAM pStr = PTR_STORAGESTREAM((TADDR)pcMD);
1124 PTR_STORAGESTREAM pSSOutOfRange =
1125 PTR_STORAGESTREAM((TADDR)(pcMD + ctMD));
1128 PTR_STORAGESTREAM pSS;
1129 for(iStr = 1, pSS = pStr; iStr <= nStreams; iStr++)
1131 CHECK(pSS < pSSOutOfRange);
1132 CHECK(pSS + 1 <= pSSOutOfRange);
1134 for(namelen=0; (namelen<32)&&(pSS->rcName[namelen]!=0); namelen++);
1135 CHECK((0 < namelen)&&(namelen < 32));
1137 // Is it ngen image?
1138 if (!HasNativeHeader())
1140 // Forbid HOT_MODEL_STREAM for non-ngen images
1141 CHECK(strcmp(pSS->rcName, HOT_MODEL_STREAM_A) != 0);
1144 pcMD = dac_cast<TADDR>(NextStorageStream(pSS));
1145 ctMD -= (COUNT_T)(pcMD - dac_cast<TADDR>(pSS));
1147 pSS = PTR_STORAGESTREAM((TADDR)pcMD);
1150 // At this moment, pcMD is pointing past the last stream header
1151 // and ctMD contains total size left for streams per se
1152 // Now, check the offsets and sizes of streams
1153 COUNT_T ctStreamsBegin = (COUNT_T)(pcMD - dac_cast<TADDR>(pStorageSig)); // min.possible offset
1154 COUNT_T ctSS, ctSSbegin, ctSSend = 0;
1155 for(iStr = 1, pSS = pStr; iStr <= nStreams; iStr++,pSS = NextStorageStream(pSS))
1157 ctSSbegin = (COUNT_T)VAL32(pSS->iOffset);
1158 CHECK(ctStreamsBegin <= ctSSbegin);
1159 CHECK(ctSSbegin < ctMDStreamSize);
1161 ctSS = (COUNT_T)VAL32(pSS->iSize);
1162 CHECK(ctMD >= ctSS);
1163 CHECK(ClrSafeInt<COUNT_T>::addition(ctSSbegin, ctSS, ctSSend));
1164 CHECK(ctSSend <= ctMDStreamSize);
1167 // Check stream overlap
1168 PTR_STORAGESTREAM pSSprior;
1169 for(pSSprior=pStr; pSSprior < pSS; pSSprior = NextStorageStream(pSSprior))
1171 COUNT_T ctSSprior_end = 0;
1172 CHECK(ClrSafeInt<COUNT_T>::addition((COUNT_T)VAL32(pSSprior->iOffset), (COUNT_T)VAL32(pSSprior->iSize), ctSSprior_end));
1173 CHECK((ctSSbegin >= ctSSprior_end)||(ctSSend <= (COUNT_T)VAL32(pSSprior->iOffset)));
1176 } //end if(pcMD != NULL)
1178 const_cast<PEDecoder *>(this)->m_flags |= FLAG_COR_CHECKED;
1185 // This function exists to provide compatibility between two different native image
1186 // (NGEN) formats. In particular, the manifest metadata blob and the full metadata
1187 // blob swapped locations from 3.5RTM to 3.5SP1. The logic here is to look at the
1188 // runtime version embedded in the native image, to determine which format it is.
1189 IMAGE_DATA_DIRECTORY *PEDecoder::GetMetaDataHelper(METADATA_SECTION_TYPE type) const
1191 CONTRACT(IMAGE_DATA_DIRECTORY *)
1194 PRECONDITION(CheckCorHeader());
1195 #ifdef FEATURE_PREJIT
1196 PRECONDITION(type == METADATA_SECTION_FULL || type == METADATA_SECTION_MANIFEST);
1197 PRECONDITION(type != METADATA_SECTION_MANIFEST || HasNativeHeader());
1198 #else // FEATURE_PREJIT
1199 PRECONDITION(type == METADATA_SECTION_FULL);
1200 #endif // FEATURE_PREJIT
1207 IMAGE_DATA_DIRECTORY *pDirRet = &GetCorHeader()->MetaData;
1209 #ifdef FEATURE_PREJIT
1210 // For backward compatibility reasons, we must be able to locate the metadata in all v2 native images as
1211 // well as current version of native images. This is needed by mdbg.exe for SxS debugging scenarios.
1212 // Specifically, mdbg.exe can be used to debug v2 managed applications, and need to be able to find
1213 // metadata in v2 native images. Therefore, the location of the data we need to locate the metadata must
1214 // never be moved. Here are some asserts to ensure that.
1215 // IMAGE_COR20_HEADER should be stable since it is defined in ECMA. Verify a coupld of fields we use:
1216 _ASSERTE(offsetof(IMAGE_COR20_HEADER, MetaData) == 8);
1217 _ASSERTE(offsetof(IMAGE_COR20_HEADER, ManagedNativeHeader) == 64);
1218 // We use a couple of fields in CORCOMPILE_HEADER.
1219 _ASSERTE(offsetof(CORCOMPILE_HEADER, VersionInfo) == 40);
1220 _ASSERTE(offsetof(CORCOMPILE_HEADER, ManifestMetaData) == 88);
1221 // And we use four version fields in CORCOMPILE_VERSION_INFO.
1222 _ASSERTE(offsetof(CORCOMPILE_VERSION_INFO, wVersionMajor) == 4);
1223 _ASSERTE(offsetof(CORCOMPILE_VERSION_INFO, wVersionMinor) == 6);
1224 _ASSERTE(offsetof(CORCOMPILE_VERSION_INFO, wVersionBuildNumber) == 8);
1225 _ASSERTE(offsetof(CORCOMPILE_VERSION_INFO, wVersionPrivateBuildNumber) == 10);
1227 // Visual Studio took dependency on crossgen /CreatePDB returning COR_E_NI_AND_RUNTIME_VERSION_MISMATCH
1228 // when crossgen and the native image come from different runtimes. In order to reach error path that returns
1229 // COR_E_NI_AND_RUNTIME_VERSION_MISMATCH in this case, size of CORCOMPILE_HEADER has to remain constant,
1230 // and the offset of PEKind and Machine fields inside CORCOMPILE_HEADER also have to remain constant, to pass earlier
1231 // checks that lead to different error codes. See Windows Phone Blue Bug #45406 for details.
1232 _ASSERTE(sizeof(CORCOMPILE_HEADER) == 160 + sizeof(TADDR));
1233 _ASSERTE(offsetof(CORCOMPILE_HEADER, PEKind) == 108 + sizeof(TADDR));
1234 _ASSERTE(offsetof(CORCOMPILE_HEADER, Machine) == 116 + sizeof(TADDR));
1236 // Handle NGEN format; otherwise, there is only one MetaData section in the
1237 // COR_HEADER and so the value of pDirRet is correct
1238 if (HasNativeHeader())
1241 if (type == METADATA_SECTION_MANIFEST)
1242 pDirRet = &GetNativeHeader()->ManifestMetaData;
1247 #endif // FEATURE_PREJIT
1252 PTR_CVOID PEDecoder::GetMetadata(COUNT_T *pSize) const
1257 PRECONDITION(CheckCorHeader());
1258 PRECONDITION(CheckPointer(pSize, NULL_OK));
1265 IMAGE_DATA_DIRECTORY *pDir = GetMetaDataHelper(METADATA_SECTION_FULL);
1268 *pSize = VAL32(pDir->Size);
1270 RETURN dac_cast<PTR_VOID>(GetDirectoryData(pDir));
1273 const void *PEDecoder::GetResources(COUNT_T *pSize) const
1275 CONTRACT(const void *)
1278 PRECONDITION(CheckCorHeader());
1279 PRECONDITION(CheckPointer(pSize, NULL_OK));
1285 IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->Resources;
1288 *pSize = VAL32(pDir->Size);
1290 RETURN (void *)GetDirectoryData(pDir);
1293 CHECK PEDecoder::CheckResource(COUNT_T offset) const
1300 PRECONDITION(CheckCorHeader());
1304 IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->Resources;
1306 CHECK(CheckOverflow(VAL32(pDir->VirtualAddress), offset));
1308 RVA rva = VAL32(pDir->VirtualAddress) + offset;
1310 // Make sure we have at least enough data for a length
1311 CHECK(CheckRva(rva, sizeof(DWORD)));
1313 // Make sure resource is within resource section
1314 CHECK(CheckBounds(VAL32(pDir->VirtualAddress), VAL32(pDir->Size),
1315 rva + sizeof(DWORD), GET_UNALIGNED_VAL32((LPVOID)GetRvaData(rva))));
1320 const void *PEDecoder::GetResource(COUNT_T offset, COUNT_T *pSize) const
1322 CONTRACT(const void *)
1325 PRECONDITION(CheckCorHeader());
1326 PRECONDITION(CheckPointer(pSize, NULL_OK));
1332 IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->Resources;
1334 // 403571: Prefix complained correctly about need to always perform rva check
1335 if (CheckResource(offset) == FALSE)
1338 void * resourceBlob = (void *)GetRvaData(VAL32(pDir->VirtualAddress) + offset);
1339 // Holds if CheckResource(offset) == TRUE
1340 PREFIX_ASSUME(resourceBlob != NULL);
1343 *pSize = GET_UNALIGNED_VAL32(resourceBlob);
1345 RETURN (const void *) ((BYTE*)resourceBlob+sizeof(DWORD));
1348 BOOL PEDecoder::HasManagedEntryPoint() const
1352 PRECONDITION(CheckCorHeader());
1357 ULONG flags = GetCorHeader()->Flags;
1358 return (!(flags & VAL32(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT)) &&
1359 (!IsNilToken(GetEntryPointToken())));
1362 ULONG PEDecoder::GetEntryPointToken() const
1367 PRECONDITION(CheckCorHeader());
1373 RETURN VAL32(IMAGE_COR20_HEADER_FIELD(*GetCorHeader(), EntryPointToken));
1376 IMAGE_COR_VTABLEFIXUP *PEDecoder::GetVTableFixups(COUNT_T *pCount) const
1378 CONTRACT(IMAGE_COR_VTABLEFIXUP *)
1381 PRECONDITION(CheckCorHeader());
1386 IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->VTableFixups;
1389 *pCount = VAL32(pDir->Size)/sizeof(IMAGE_COR_VTABLEFIXUP);
1391 RETURN PTR_IMAGE_COR_VTABLEFIXUP(GetDirectoryData(pDir));
1394 CHECK PEDecoder::CheckILOnly() const
1404 if (m_flags & FLAG_IL_ONLY_CHECKED)
1407 CHECK(CheckCorHeader());
1409 if (HasReadyToRunHeader())
1411 // Pretend R2R images are IL-only
1412 const_cast<PEDecoder *>(this)->m_flags |= FLAG_IL_ONLY_CHECKED;
1416 // Allow only verifiable directories.
1418 static int s_allowedBitmap =
1419 ((1 << (IMAGE_DIRECTORY_ENTRY_IMPORT )) |
1420 (1 << (IMAGE_DIRECTORY_ENTRY_RESOURCE )) |
1421 (1 << (IMAGE_DIRECTORY_ENTRY_SECURITY )) |
1422 (1 << (IMAGE_DIRECTORY_ENTRY_BASERELOC)) |
1423 (1 << (IMAGE_DIRECTORY_ENTRY_DEBUG )) |
1424 (1 << (IMAGE_DIRECTORY_ENTRY_IAT )) |
1425 (1 << (IMAGE_DIRECTORY_ENTRY_COMHEADER)));
1430 for (UINT32 entry=0; entry<GetNumberOfRvaAndSizes(); ++entry)
1432 if (Has32BitNTHeaders())
1433 CheckBounds(dac_cast<PTR_CVOID>(&GetNTHeaders32()->OptionalHeader),
1434 GetNTHeaders32()->FileHeader.SizeOfOptionalHeader,
1435 dac_cast<PTR_CVOID>(GetNTHeaders32()->OptionalHeader.DataDirectory + entry),
1436 sizeof(IMAGE_DATA_DIRECTORY));
1438 CheckBounds(dac_cast<PTR_CVOID>(&GetNTHeaders64()->OptionalHeader),
1439 GetNTHeaders32()->FileHeader.SizeOfOptionalHeader,
1440 dac_cast<PTR_CVOID>(GetNTHeaders64()->OptionalHeader.DataDirectory + entry),
1441 sizeof(IMAGE_DATA_DIRECTORY));
1443 if (HasDirectoryEntry(entry))
1445 CHECK((s_allowedBitmap & (1 << entry)) != 0);
1446 if (entry!=IMAGE_DIRECTORY_ENTRY_SECURITY) //ignored by OS loader
1447 CHECK(CheckDirectoryEntry(entry,IMAGE_SCN_MEM_SHARED,NULL_NOT_OK));
1450 if (HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT) ||
1451 HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC) ||
1452 FindNTHeaders()->OptionalHeader.AddressOfEntryPoint != 0)
1454 // When the image is LoadLibrary'd, we whack the import, IAT directories and the entrypoint. We have to relax
1455 // the verification for mapped images. Ideally, we would only do it for a post-LoadLibrary image.
1456 if (!IsMapped() || (HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT) || HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC)))
1458 CHECK(CheckILOnlyImportDlls());
1459 CHECK(CheckILOnlyBaseRelocations());
1465 CHECK(CheckILOnlyEntryPoint());
1470 // Check some section characteristics
1471 IMAGE_NT_HEADERS *pNT = FindNTHeaders();
1472 IMAGE_SECTION_HEADER *section = FindFirstSection(pNT);
1473 IMAGE_SECTION_HEADER *sectionEnd = section + VAL16(pNT->FileHeader.NumberOfSections);
1474 while (section < sectionEnd)
1476 // Don't allow shared sections for IL-only images
1477 CHECK(!(section->Characteristics & IMAGE_SCN_MEM_SHARED));
1479 // Be sure that we have some access to the section. Note that this test assumes that
1480 // execute or write permissions will also let us read the section. If that is found to be an
1481 // incorrect assumption, this will need to be modified.
1482 CHECK((section->Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) != 0);
1486 // For EXE, check that OptionalHeader.Win32VersionValue is zero. When this value is non-zero, GetVersionEx
1487 // returns PE supplied values, rather than native OS values; the runtime relies on knowing the actual
1491 CHECK(GetWin32VersionValue() == 0);
1495 const_cast<PEDecoder *>(this)->m_flags |= FLAG_IL_ONLY_CHECKED;
1501 CHECK PEDecoder::CheckILOnlyImportDlls() const
1506 PRECONDITION(CheckNTHeaders());
1512 // The only allowed DLL Imports are MscorEE.dll:_CorExeMain,_CorDllMain
1515 // On win64, when the image is LoadLibrary'd, we whack the import and IAT directories. We have to relax
1516 // the verification for mapped images. Ideally, we would only do it for a post-LoadLibrary image.
1517 if (IsMapped() && !HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT))
1521 CHECK(HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT));
1522 CHECK(CheckDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_SCN_MEM_WRITE));
1524 // Get the import directory entry
1525 PIMAGE_DATA_DIRECTORY pDirEntryImport = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT);
1526 CHECK(pDirEntryImport != NULL);
1527 PREFIX_ASSUME(pDirEntryImport != NULL);
1529 // There should be space for 2 entries. (mscoree and NULL)
1530 CHECK(VAL32(pDirEntryImport->Size) >= (2 * sizeof(IMAGE_IMPORT_DESCRIPTOR)));
1532 // Get the import data
1533 PIMAGE_IMPORT_DESCRIPTOR pID = (PIMAGE_IMPORT_DESCRIPTOR) GetDirectoryData(pDirEntryImport);
1535 PREFIX_ASSUME(pID != NULL);
1537 // Entry 0: ILT, Name, IAT must be be non-null. Forwarder, DateTime should be NULL.
1538 CHECK( IMAGE_IMPORT_DESC_FIELD(pID[0], Characteristics) != 0
1539 && pID[0].TimeDateStamp == 0
1540 && (pID[0].ForwarderChain == 0 || pID[0].ForwarderChain == static_cast<ULONG>(-1))
1542 && pID[0].FirstThunk != 0);
1544 // Entry 1: must be all nulls.
1545 CHECK( IMAGE_IMPORT_DESC_FIELD(pID[1], Characteristics) == 0
1546 && pID[1].TimeDateStamp == 0
1547 && pID[1].ForwarderChain == 0
1549 && pID[1].FirstThunk == 0);
1551 // Ensure the RVA of the name plus its length is valid for this image
1552 UINT nameRVA = VAL32(pID[0].Name);
1553 CHECK(CheckRva(nameRVA, (COUNT_T) sizeof("mscoree.dll")));
1555 // Make sure the name is equal to mscoree
1556 CHECK(SString::_stricmp( (char *)GetRvaData(nameRVA), "mscoree.dll") == 0);
1558 // Check the Hint/Name table.
1559 CHECK(CheckILOnlyImportByNameTable(VAL32(IMAGE_IMPORT_DESC_FIELD(pID[0], OriginalFirstThunk))));
1561 // The IAT needs to be checked only for size.
1562 CHECK(CheckRva(VAL32(pID[0].FirstThunk), 2*sizeof(UINT32)));
1567 CHECK PEDecoder::CheckILOnlyImportByNameTable(RVA rva) const
1572 PRECONDITION(CheckNTHeaders());
1578 // Check if we have enough space to hold 2 DWORDS
1579 CHECK(CheckRva(rva, 2*sizeof(UINT32)));
1581 UINT32 UNALIGNED *pImportArray = (UINT32 UNALIGNED *) GetRvaData(rva);
1583 CHECK(GET_UNALIGNED_VAL32(&pImportArray[0]) != 0);
1584 CHECK(GET_UNALIGNED_VAL32(&pImportArray[1]) == 0);
1586 UINT32 importRVA = GET_UNALIGNED_VAL32(&pImportArray[0]);
1588 // First bit Set implies Ordinal lookup
1589 CHECK((importRVA & 0x80000000) == 0);
1591 #define DLL_NAME "_CorDllMain"
1592 #define EXE_NAME "_CorExeMain"
1594 static_assert_no_msg(sizeof(DLL_NAME) == sizeof(EXE_NAME));
1596 // Check if we have enough space to hold 2 bytes +
1597 // _CorExeMain or _CorDllMain and a NULL char
1598 CHECK(CheckRva(importRVA, offsetof(IMAGE_IMPORT_BY_NAME, Name) + sizeof(DLL_NAME)));
1600 IMAGE_IMPORT_BY_NAME *import = (IMAGE_IMPORT_BY_NAME*) GetRvaData(importRVA);
1602 CHECK(SString::_stricmp((char *) import->Name, DLL_NAME) == 0 || _stricmp((char *) import->Name, EXE_NAME) == 0);
1608 // jmp dword ptr ds:[XXXX]
1609 #define JMP_DWORD_PTR_DS_OPCODE { 0xFF, 0x25 }
1610 #define JMP_DWORD_PTR_DS_OPCODE_SIZE 2 // Size of opcode
1611 #define JMP_SIZE 6 // Size of opcode + operand
1614 CHECK PEDecoder::CheckILOnlyBaseRelocations() const
1619 PRECONDITION(CheckNTHeaders());
1625 if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC))
1627 // We require base relocs for dlls.
1630 CHECK((FindNTHeaders()->FileHeader.Characteristics & VAL16(IMAGE_FILE_RELOCS_STRIPPED)) != 0);
1634 CHECK((FindNTHeaders()->FileHeader.Characteristics & VAL16(IMAGE_FILE_RELOCS_STRIPPED)) == 0);
1636 CHECK(CheckDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC, IMAGE_SCN_MEM_WRITE));
1638 IMAGE_DATA_DIRECTORY *pRelocDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC);
1640 IMAGE_SECTION_HEADER *section = RvaToSection(VAL32(pRelocDir->VirtualAddress));
1641 CHECK(section != NULL);
1642 CHECK((section->Characteristics & VAL32(IMAGE_SCN_MEM_READ))!=0);
1644 IMAGE_BASE_RELOCATION *pReloc = (IMAGE_BASE_RELOCATION *)
1645 GetRvaData(VAL32(pRelocDir->VirtualAddress));
1647 // 403569: PREfix correctly complained about pReloc being possibly NULL
1648 CHECK(pReloc != NULL);
1649 CHECK(VAL32(pReloc->SizeOfBlock) == VAL32(pRelocDir->Size));
1651 UINT16 *pRelocEntry = (UINT16 *) (pReloc + 1);
1652 UINT16 *pRelocEntryEnd = (UINT16 *) ((BYTE *) pReloc + VAL32(pReloc->SizeOfBlock));
1653 if(FindNTHeaders()->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_IA64))
1655 // Exactly 2 Reloc records, both IMAGE_REL_BASED_DIR64
1656 CHECK(VAL32(pReloc->SizeOfBlock) >= (sizeof(IMAGE_BASE_RELOCATION)+2*sizeof(UINT16)));
1657 CHECK((VAL16(pRelocEntry[0]) & 0xF000) == (IMAGE_REL_BASED_DIR64 << 12));
1659 CHECK((VAL16(pRelocEntry[0]) & 0xF000) == (IMAGE_REL_BASED_DIR64 << 12));
1663 // Only one Reloc record is expected
1664 CHECK(VAL32(pReloc->SizeOfBlock) >= (sizeof(IMAGE_BASE_RELOCATION)+sizeof(UINT16)));
1665 if(FindNTHeaders()->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_AMD64))
1666 CHECK((VAL16(pRelocEntry[0]) & 0xF000) == (IMAGE_REL_BASED_DIR64 << 12));
1668 CHECK((VAL16(pRelocEntry[0]) & 0xF000) == (IMAGE_REL_BASED_HIGHLOW << 12));
1671 while (++pRelocEntry < pRelocEntryEnd)
1673 // NULL padding entries are allowed
1674 CHECK((VAL16(pRelocEntry[0]) & 0xF000) == IMAGE_REL_BASED_ABSOLUTE);
1682 CHECK PEDecoder::CheckILOnlyEntryPoint() const
1687 PRECONDITION(CheckNTHeaders());
1693 CHECK(FindNTHeaders()->OptionalHeader.AddressOfEntryPoint != 0);
1695 if(FindNTHeaders()->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_I386))
1697 // EntryPoint should be a jmp dword ptr ds:[XXXX] instruction.
1698 // XXXX should be RVA of the first and only entry in the IAT.
1700 CHECK(CheckRva(VAL32(FindNTHeaders()->OptionalHeader.AddressOfEntryPoint), JMP_SIZE));
1702 BYTE *stub = (BYTE *) GetRvaData(VAL32(FindNTHeaders()->OptionalHeader.AddressOfEntryPoint));
1704 static const BYTE s_DllOrExeMain[] = JMP_DWORD_PTR_DS_OPCODE;
1706 // 403570: prefix complained about stub being possibly NULL.
1707 // Unsure here. PREFIX_ASSUME might be also correct as indices are
1708 // verified in the above CHECK statement.
1709 CHECK(stub != NULL);
1710 CHECK(memcmp(stub, s_DllOrExeMain, JMP_DWORD_PTR_DS_OPCODE_SIZE) == 0);
1712 // Verify target of jump - it should be first entry in the IAT.
1714 PIMAGE_IMPORT_DESCRIPTOR pID =
1715 (PIMAGE_IMPORT_DESCRIPTOR) GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_IMPORT);
1717 UINT32 va = * (UINT32 *) (stub + JMP_DWORD_PTR_DS_OPCODE_SIZE);
1719 CHECK(VAL32(pID[0].FirstThunk) == (va - (SIZE_T) GetPreferredBase()));
1724 #endif // _TARGET_X86_
1726 #ifndef DACCESS_COMPILE
1728 void PEDecoder::LayoutILOnly(void *base, BOOL allowFullPE) const
1733 PRECONDITION(allowFullPE || CheckILOnlyFormat());
1734 PRECONDITION(CheckZeroedMemory(base, VAL32(FindNTHeaders()->OptionalHeader.SizeOfImage)));
1735 // Ideally we would require the layout address to honor the section alignment constraints.
1736 // However, we do have 8K aligned IL only images which we load on 32 bit platforms. In this
1737 // case, we can only guarantee OS page alignment (which after all, is good enough.)
1738 PRECONDITION(CheckAligned((SIZE_T)base, GetOsPageSize()));
1744 // We're going to copy everything first, and write protect what we need to later.
1746 // First, copy headers
1747 CopyMemory(base, (void *)m_base, VAL32(FindNTHeaders()->OptionalHeader.SizeOfHeaders));
1749 // Now, copy all sections to appropriate virtual address
1751 IMAGE_SECTION_HEADER *sectionStart = IMAGE_FIRST_SECTION(FindNTHeaders());
1752 IMAGE_SECTION_HEADER *sectionEnd = sectionStart + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
1754 IMAGE_SECTION_HEADER *section = sectionStart;
1755 while (section < sectionEnd)
1757 // Raw data may be less than section size if tail is zero, but may be more since VirtualSize is
1759 DWORD size = min(VAL32(section->SizeOfRawData), VAL32(section->Misc.VirtualSize));
1761 CopyMemory((BYTE *) base + VAL32(section->VirtualAddress), (BYTE *) m_base + VAL32(section->PointerToRawData), size);
1763 // Note that our memory is zeroed already, so no need to initialize any tail.
1768 // Apply write protection to copied headers
1769 DWORD oldProtection;
1770 if (!ClrVirtualProtect((void *) base, VAL32(FindNTHeaders()->OptionalHeader.SizeOfHeaders),
1771 PAGE_READONLY, &oldProtection))
1774 // Finally, apply proper protection to copied sections
1775 section = sectionStart;
1776 while (section < sectionEnd)
1778 // Add appropriate page protection.
1779 if ((section->Characteristics & VAL32(IMAGE_SCN_MEM_WRITE)) == 0)
1781 if (!ClrVirtualProtect((void *) ((BYTE *)base + VAL32(section->VirtualAddress)),
1782 VAL32(section->Misc.VirtualSize),
1783 PAGE_READONLY, &oldProtection))
1793 #endif // #ifndef DACCESS_COMPILE
1795 bool ReadResourceDirectoryHeader(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, DWORD rva, IMAGE_RESOURCE_DIRECTORY_ENTRY** ppDirectoryEntries, IMAGE_RESOURCE_DIRECTORY **ppResourceDirectory)
1797 if (!pDecoder->CheckRva(rva, sizeof(IMAGE_RESOURCE_DIRECTORY)))
1802 *ppResourceDirectory = (IMAGE_RESOURCE_DIRECTORY *)pDecoder->GetRvaData(rva);
1804 // Check to see if entire resource directory is accessible
1805 if (!pDecoder->CheckRva(rva + sizeof(IMAGE_RESOURCE_DIRECTORY),
1806 (sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) * (*ppResourceDirectory)->NumberOfNamedEntries) +
1807 (sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) * (*ppResourceDirectory)->NumberOfIdEntries)))
1812 *ppDirectoryEntries = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)pDecoder->GetRvaData(rva + sizeof(IMAGE_RESOURCE_DIRECTORY));
1816 bool ReadNameFromResourceDirectoryEntry(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, IMAGE_RESOURCE_DIRECTORY_ENTRY* pDirectoryEntries, DWORD iEntry, DWORD *pNameUInt, WCHAR **pNameStr)
1821 if (!IS_INTRESOURCE(pDirectoryEntries[iEntry].Name))
1823 DWORD entryName = pDirectoryEntries[iEntry].Name;
1824 if (!(entryName & IMAGE_RESOURCE_NAME_IS_STRING))
1826 DWORD entryNameRva = (entryName & ~IMAGE_RESOURCE_NAME_IS_STRING) + rvaOfResourceSection;
1828 if (!pDecoder->CheckRva(entryNameRva, sizeof(WORD)))
1831 size_t entryNameLen = *(WORD*)pDecoder->GetRvaData(entryNameRva);
1832 if (!pDecoder->CheckRva(entryNameRva, (COUNT_T)(sizeof(WORD) * (1 + entryNameLen))))
1834 *pNameStr = new(nothrow) WCHAR[entryNameLen + 1];
1835 if ((*pNameStr) == NULL)
1837 memcpy((*pNameStr), (WCHAR*)pDecoder->GetRvaData(entryNameRva + sizeof(WORD)), entryNameLen * sizeof(WCHAR));
1838 (*pNameStr)[entryNameLen] = 0;
1842 DWORD name = pDirectoryEntries[iEntry].Name;
1843 if (!IS_INTRESOURCE(name))
1852 DWORD ReadResourceDirectory(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, DWORD rva, LPCWSTR name, BOOL *pisDirectory)
1854 *pisDirectory = FALSE;
1856 IMAGE_RESOURCE_DIRECTORY* pResourceDirectory;
1857 IMAGE_RESOURCE_DIRECTORY_ENTRY* pDirectoryEntries;
1858 if (!ReadResourceDirectoryHeader(pDecoder, rvaOfResourceSection, rva, &pDirectoryEntries, &pResourceDirectory))
1863 // A fast implementation of resource lookup uses a binary search, but our needs are simple, and a linear search
1864 // is easier to prove correct, so do that instead.
1865 DWORD iEntryCount = (DWORD)pResourceDirectory->NumberOfNamedEntries + (DWORD)pResourceDirectory->NumberOfIdEntries;
1867 for (DWORD iEntry = 0; iEntry < iEntryCount; iEntry++)
1869 BOOL foundEntry = FALSE;
1871 if (IS_INTRESOURCE(name))
1874 if (pDirectoryEntries[iEntry].Name == (DWORD)(SIZE_T)name)
1880 DWORD entryName = pDirectoryEntries[iEntry].Name;
1881 if (!(entryName & IMAGE_RESOURCE_NAME_IS_STRING))
1884 DWORD entryNameRva = (entryName & ~IMAGE_RESOURCE_NAME_IS_STRING) + rvaOfResourceSection;
1886 if (!pDecoder->CheckRva(entryNameRva, sizeof(WORD)))
1889 size_t entryNameLen = *(WORD*)pDecoder->GetRvaData(entryNameRva);
1890 if (wcslen(name) != entryNameLen)
1893 if (!pDecoder->CheckRva(entryNameRva, (COUNT_T)(sizeof(WORD) * (1 + entryNameLen))))
1896 if (memcmp((WCHAR*)pDecoder->GetRvaData(entryNameRva + sizeof(WORD)), name, entryNameLen * sizeof(WCHAR)) == 0)
1903 *pisDirectory = !!(pDirectoryEntries[iEntry].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY);
1904 DWORD offsetToData = pDirectoryEntries[iEntry].OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY;
1905 DWORD dataRva = rvaOfResourceSection + offsetToData;
1912 DWORD ReadResourceDataEntry(const PEDecoder *pDecoder, DWORD rva, COUNT_T *pSize)
1916 if (!pDecoder->CheckRva(rva, sizeof(IMAGE_RESOURCE_DATA_ENTRY)))
1921 IMAGE_RESOURCE_DATA_ENTRY *pDataEntry = (IMAGE_RESOURCE_DATA_ENTRY *)pDecoder->GetRvaData(rva);
1922 *pSize = pDataEntry->Size;
1923 return pDataEntry->OffsetToData;
1926 void * PEDecoder::GetWin32Resource(LPCWSTR lpName, LPCWSTR lpType, COUNT_T *pSize /*=NULL*/) const
1930 PRECONDITION(IsMapped());
1935 COUNT_T sizeUnused = 0; // Use this variable if pSize is null
1937 pSize = &sizeUnused;
1941 if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
1944 COUNT_T resourceDataSize = 0;
1945 IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
1947 if (pDir->VirtualAddress == 0)
1950 BOOL isDirectory = FALSE;
1951 DWORD nameTableRva = ReadResourceDirectory(this, pDir->VirtualAddress, pDir->VirtualAddress, lpType, &isDirectory);
1956 if (nameTableRva == 0)
1959 DWORD languageTableRva = ReadResourceDirectory(this, pDir->VirtualAddress, nameTableRva, lpName, &isDirectory);
1963 if (languageTableRva == 0)
1966 // This api is designed to find resources with LANGID = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)
1967 // This translates to LANGID 0 as the initial lookup point, which is sufficient for the needs of this api at this time
1968 // (FindResource in the Windows api implements a large number of fallback paths which this api does not implement)
1970 DWORD resourceDataEntryRva = ReadResourceDirectory(this, pDir->VirtualAddress, languageTableRva, 0, &isDirectory);
1971 if (isDirectory) // This must not be a resource directory itself
1974 if (resourceDataEntryRva == 0)
1977 DWORD resourceDataRva = ReadResourceDataEntry(this, resourceDataEntryRva, pSize);
1978 if (!CheckRva(resourceDataRva, *pSize))
1984 return (void*)GetRvaData(resourceDataRva);
1987 typedef bool (*PEDecoder_EnumerateResourceTableFunction)(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context);
1989 struct ResourceEnumerateNamesState
1991 PEDecoder_ResourceNamesCallbackFunction namesCallback;
1992 PEDecoder_ResourceCallbackFunction langIDcallback;
1996 PEDecoder_EnumerateResourceTableFunction callbackPerName;
1997 PEDecoder_EnumerateResourceTableFunction callbackPerLangID;
2000 struct ResourceEnumerateTypesState
2002 PEDecoder_ResourceTypesCallbackFunction callback;
2007 bool EnumerateWin32ResourceTable(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, DWORD rvaOfResourceTable, PEDecoder_EnumerateResourceTableFunction resourceTableEnumerator, void *context)
2009 IMAGE_RESOURCE_DIRECTORY* pResourceDirectory;
2010 IMAGE_RESOURCE_DIRECTORY_ENTRY* pDirectoryEntries;
2011 if (!ReadResourceDirectoryHeader(pDecoder, rvaOfResourceSection, rvaOfResourceTable, &pDirectoryEntries, &pResourceDirectory))
2016 DWORD iEntryCount = (DWORD)pResourceDirectory->NumberOfNamedEntries + (DWORD)pResourceDirectory->NumberOfIdEntries;
2018 for (DWORD iEntry = 0; iEntry < iEntryCount; iEntry++)
2021 NewArrayHolder<WCHAR> nameString;
2022 if (!ReadNameFromResourceDirectoryEntry(pDecoder, rvaOfResourceSection, pDirectoryEntries, iEntry, &nameUInt, &nameString))
2025 LPCWSTR name = MAKEINTRESOURCEW(nameUInt);
2026 if (nameString != NULL)
2027 name = &nameString[0];
2029 bool isDirectory = !!(pDirectoryEntries[iEntry].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY);
2030 DWORD offsetToData = pDirectoryEntries[iEntry].OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY;
2031 DWORD dataRva = rvaOfResourceSection + offsetToData;
2033 if (!resourceTableEnumerator(pDecoder, rvaOfResourceSection, isDirectory, name, dataRva, context))
2040 bool DoesResourceNameMatch(LPCWSTR nameA, LPCWSTR nameB)
2042 bool foundEntry = false;
2044 if (IS_INTRESOURCE(nameA))
2052 // name is a string.
2054 // Check for name enumerated is an id. If so, it doesn't match, skip to next.
2055 if (IS_INTRESOURCE(nameB))
2058 foundEntry = !wcscmp(nameB, nameA);
2064 bool EnumerateLangIDs(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
2066 ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
2070 // Only LangIDs are permitted here
2071 if (!IS_INTRESOURCE(name))
2078 DWORD resourceDataRva = ReadResourceDataEntry(pDecoder, dataRVA, &cbData);
2079 if (!pDecoder->CheckRva(resourceDataRva, cbData))
2084 BYTE *pData = (BYTE*)pDecoder->GetRvaData(resourceDataRva);
2086 return state->langIDcallback(state->nameName, state->nameType, (DWORD)(uintptr_t)name, pData, cbData, state->context);
2090 bool EnumerateNames(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
2092 ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
2096 state->nameName = name;
2097 return state->namesCallback(state->nameName, state->nameType, state->context);
2100 bool EnumerateNamesForLangID(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
2102 ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
2106 bool foundEntry = DoesResourceNameMatch(state->nameName, name);
2109 return EnumerateWin32ResourceTable(pDecoder, rvaOfResourceSection, dataRVA, state->callbackPerLangID, context);
2111 return true; // Keep scanning
2115 bool EnumerateTypes(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
2117 ResourceEnumerateTypesState *state = (ResourceEnumerateTypesState*)context;
2121 state->nameType = name;
2122 return state->callback(name, state->context);
2125 bool EnumerateTypesForNames(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
2127 ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
2131 bool foundEntry = DoesResourceNameMatch(state->nameType, name);
2134 return EnumerateWin32ResourceTable(pDecoder, rvaOfResourceSection, dataRVA, state->callbackPerName, context);
2136 return true; // Keep scanning
2140 bool PEDecoder::EnumerateWin32ResourceTypes(PEDecoder_ResourceTypesCallbackFunction callback, void* context) const
2142 if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
2145 COUNT_T resourceDataSize = 0;
2146 IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
2148 if (pDir->VirtualAddress == 0)
2151 DWORD rvaOfResourceSection = pDir->VirtualAddress;
2153 ResourceEnumerateTypesState state;
2154 state.context = context;
2155 state.callback = callback;
2157 return EnumerateWin32ResourceTable(this, rvaOfResourceSection, rvaOfResourceSection, EnumerateTypes, &state);
2160 bool PEDecoder::EnumerateWin32ResourceNames(LPCWSTR lpType, PEDecoder_ResourceNamesCallbackFunction callback, void* context) const
2162 if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
2165 COUNT_T resourceDataSize = 0;
2166 IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
2168 if (pDir->VirtualAddress == 0)
2171 DWORD rvaOfResourceSection = pDir->VirtualAddress;
2173 ResourceEnumerateNamesState state;
2174 state.context = context;
2175 state.namesCallback = callback;
2176 state.langIDcallback = NULL;
2177 state.nameType = lpType;
2178 state.nameName = NULL;
2179 state.callbackPerName = EnumerateNames;
2180 state.callbackPerLangID = NULL;
2182 return EnumerateWin32ResourceTable(this, rvaOfResourceSection, rvaOfResourceSection, EnumerateTypesForNames, &state);
2185 bool PEDecoder::EnumerateWin32Resources(LPCWSTR lpName, LPCWSTR lpType, PEDecoder_ResourceCallbackFunction callback, void* context) const
2187 if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
2190 COUNT_T resourceDataSize = 0;
2191 IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
2193 if (pDir->VirtualAddress == 0)
2196 DWORD rvaOfResourceSection = pDir->VirtualAddress;
2198 ResourceEnumerateNamesState state;
2199 state.context = context;
2200 state.namesCallback = NULL;
2201 state.langIDcallback = callback;
2202 state.nameType = lpType;
2203 state.nameName = lpName;
2204 state.callbackPerName = EnumerateNamesForLangID;
2205 state.callbackPerLangID = EnumerateLangIDs;
2207 return EnumerateWin32ResourceTable(this, rvaOfResourceSection, rvaOfResourceSection, EnumerateTypesForNames, &state);
2210 BOOL PEDecoder::HasNativeHeader() const
2221 #ifdef FEATURE_PREJIT
2222 // Pretend that ready-to-run images do not have native header
2223 RETURN (GetCorHeader() && ((GetCorHeader()->Flags & VAL32(COMIMAGE_FLAGS_IL_LIBRARY)) != 0) && !HasReadyToRunHeader());
2229 CHECK PEDecoder::CheckNativeHeader() const
2239 #ifdef FEATURE_PREJIT
2240 if (m_flags & FLAG_NATIVE_CHECKED)
2243 CHECK(CheckCorHeader());
2245 CHECK(HasNativeHeader());
2247 IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->ManagedNativeHeader;
2249 CHECK(CheckDirectory(pDir));
2250 CHECK(VAL32(pDir->Size) == sizeof(CORCOMPILE_HEADER));
2253 // We want to be sure to not trigger these checks when loading a native
2254 // image in a retail build
2256 // And we do not want to trigger these checks in debug builds either to avoid debug/retail behavior
2259 PTR_CORCOMPILE_HEADER pHeader = PTR_CORCOMPILE_HEADER((TADDR)GetDirectoryData(pDir));
2261 CHECK(CheckDirectory(&pHeader->EEInfoTable));
2262 CHECK(pHeader->EEInfoTable.Size == sizeof(CORCOMPILE_EE_INFO_TABLE));
2264 CHECK(CheckDirectory(&pHeader->HelperTable, 0, NULL_OK));
2265 // @todo: verify helper table size
2267 CHECK(CheckDirectory(&pHeader->ImportSections, 0, NULL_OK));
2268 // @todo verify import sections
2270 CHECK(CheckDirectory(&pHeader->ImportTable, 0, NULL_OK));
2271 // @todo verify import table
2273 CHECK(CheckDirectory(&pHeader->VersionInfo, 0, NULL_OK)); // no version header for precompiled netmodules
2274 CHECK(pHeader->VersionInfo.Size == 0
2275 || (pHeader->VersionInfo.Size == sizeof(CORCOMPILE_VERSION_INFO) &&
2276 // Sanity check that we are not just pointing to zeroed-out memory
2277 ((CORCOMPILE_VERSION_INFO*)PTR_READ(GetDirectoryData(&pHeader->VersionInfo), sizeof(CORCOMPILE_VERSION_INFO)))->wOSMajorVersion != 0));
2279 CHECK(CheckDirectory(&pHeader->Dependencies, 0, NULL_OK)); // no version header for precompiled netmodules
2280 CHECK(pHeader->Dependencies.Size % sizeof(CORCOMPILE_DEPENDENCY) == 0);
2282 CHECK(CheckDirectory(&pHeader->DebugMap, 0, NULL_OK));
2283 CHECK(pHeader->DebugMap.Size % sizeof(CORCOMPILE_DEBUG_RID_ENTRY) == 0);
2285 // GetPersistedModuleImage()
2286 CHECK(CheckDirectory(&pHeader->ModuleImage));
2287 CHECK(pHeader->ModuleImage.Size > 0); // sizeof(Module) if we knew it here
2289 CHECK(CheckDirectory(&pHeader->CodeManagerTable));
2290 CHECK(pHeader->CodeManagerTable.Size == sizeof(CORCOMPILE_CODE_MANAGER_ENTRY));
2292 PTR_CORCOMPILE_CODE_MANAGER_ENTRY pEntry = PTR_CORCOMPILE_CODE_MANAGER_ENTRY((TADDR)GetDirectoryData(&pHeader->CodeManagerTable));
2293 CHECK(CheckDirectory(&pEntry->HotCode, IMAGE_SCN_MEM_WRITE, NULL_OK));
2294 CHECK(CheckDirectory(&pEntry->Code, IMAGE_SCN_MEM_WRITE, NULL_OK));
2295 CHECK(CheckDirectory(&pEntry->ColdCode, IMAGE_SCN_MEM_WRITE, NULL_OK));
2297 CHECK(CheckDirectory(&pHeader->ProfileDataList, 0, NULL_OK));
2298 CHECK(pHeader->ProfileDataList.Size >= sizeof(CORCOMPILE_METHOD_PROFILE_LIST)
2299 || pHeader->ProfileDataList.Size == 0);
2303 const_cast<PEDecoder *>(this)->m_flags |= FLAG_NATIVE_CHECKED;
2305 #else // FEATURE_PREJIT
2307 #endif // FEATURE_PREJIT
2312 READYTORUN_HEADER * PEDecoder::FindReadyToRunHeader() const
2322 IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->ManagedNativeHeader;
2324 if (VAL32(pDir->Size) >= sizeof(READYTORUN_HEADER) && CheckDirectory(pDir))
2326 PTR_READYTORUN_HEADER pHeader = PTR_READYTORUN_HEADER((TADDR)GetDirectoryData(pDir));
2327 if (pHeader->Signature == READYTORUN_SIGNATURE)
2329 const_cast<PEDecoder *>(this)->m_pReadyToRunHeader = pHeader;
2334 const_cast<PEDecoder *>(this)->m_flags |= FLAG_HAS_NO_READYTORUN_HEADER;
2339 // code:PEDecoder::CheckILMethod and code:PEDecoder::ComputeILMethodSize really belong to
2340 // file:..\inc\corhlpr.cpp. Unfortunately, corhlpr.cpp is public header file that cannot be
2341 // properly DACized and have other dependencies on the rest of the CLR.
2344 typedef DPTR(COR_ILMETHOD_TINY) PTR_COR_ILMETHOD_TINY;
2345 typedef DPTR(COR_ILMETHOD_FAT) PTR_COR_ILMETHOD_FAT;
2346 typedef DPTR(COR_ILMETHOD_SECT_SMALL) PTR_COR_ILMETHOD_SECT_SMALL;
2347 typedef DPTR(COR_ILMETHOD_SECT_FAT) PTR_COR_ILMETHOD_SECT_FAT;
2349 CHECK PEDecoder::CheckILMethod(RVA rva)
2360 // Incrementaly validate that the entire IL method body is within the bounds of the image
2363 // We need to have at least the tiny header
2364 CHECK(CheckRva(rva, sizeof(IMAGE_COR_ILMETHOD_TINY)));
2366 TADDR pIL = GetRvaData(rva);
2368 PTR_COR_ILMETHOD_TINY pMethodTiny = PTR_COR_ILMETHOD_TINY(pIL);
2370 if (pMethodTiny->IsTiny())
2372 // Tiny header has no optional sections - we are done.
2373 CHECK(CheckRva(rva, sizeof(IMAGE_COR_ILMETHOD_TINY) + pMethodTiny->GetCodeSize()));
2381 CHECK(CheckRva(rva, sizeof(IMAGE_COR_ILMETHOD_FAT)));
2383 PTR_COR_ILMETHOD_FAT pMethodFat = PTR_COR_ILMETHOD_FAT(pIL);
2385 CHECK(pMethodFat->IsFat());
2387 S_UINT32 codeEnd = S_UINT32(4) * S_UINT32(pMethodFat->GetSize()) + S_UINT32(pMethodFat->GetCodeSize());
2388 CHECK(!codeEnd.IsOverflow());
2390 // Check minimal size of the header
2391 CHECK(pMethodFat->GetSize() >= (sizeof(COR_ILMETHOD_FAT) / 4));
2393 CHECK(CheckRva(rva, codeEnd.Value()));
2395 if (!pMethodFat->More())
2400 // DACized copy of code:COR_ILMETHOD_FAT::GetSect
2401 TADDR pSect = AlignUp(pIL + codeEnd.Value(), 4);
2404 // Optional sections following the code
2409 CHECK(CheckRva(rva, UINT32(pSect - pIL) + sizeof(IMAGE_COR_ILMETHOD_SECT_SMALL)));
2411 PTR_COR_ILMETHOD_SECT_SMALL pSectSmall = PTR_COR_ILMETHOD_SECT_SMALL(pSect);
2415 if (pSectSmall->IsSmall())
2417 sectSize = pSectSmall->DataSize;
2419 // Workaround for bug in shipped compilers - see comment in code:COR_ILMETHOD_SECT::DataSize
2420 if ((pSectSmall->Kind & CorILMethod_Sect_KindMask) == CorILMethod_Sect_EHTable)
2421 sectSize = COR_ILMETHOD_SECT_EH_SMALL::Size(sectSize / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL));
2425 CHECK(CheckRva(rva, UINT32(pSect - pIL) + sizeof(IMAGE_COR_ILMETHOD_SECT_FAT)));
2427 PTR_COR_ILMETHOD_SECT_FAT pSectFat = PTR_COR_ILMETHOD_SECT_FAT(pSect);
2429 sectSize = pSectFat->GetDataSize();
2431 // Workaround for bug in shipped compilers - see comment in code:COR_ILMETHOD_SECT::DataSize
2432 if ((pSectSmall->Kind & CorILMethod_Sect_KindMask) == CorILMethod_Sect_EHTable)
2433 sectSize = COR_ILMETHOD_SECT_EH_FAT::Size(sectSize / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT));
2436 // Section has to be non-empty to avoid infinite loop below
2437 CHECK(sectSize > 0);
2439 S_UINT32 sectEnd = S_UINT32(UINT32(pSect - pIL)) + S_UINT32(sectSize);
2440 CHECK(!sectEnd.IsOverflow());
2442 CHECK(CheckRva(rva, sectEnd.Value()));
2444 if (!pSectSmall->More())
2449 // DACized copy of code:COR_ILMETHOD_FAT::Next
2450 pSect = AlignUp(pIL + sectEnd.Value(), 4);
2455 // Compute size of IL blob. Assumes that the IL is within the bounds of the image - make sure
2456 // to call code:PEDecoder::CheckILMethod before calling this method.
2458 // code:PEDecoder::ComputeILMethodSize is DACized duplicate of code:COR_ILMETHOD_DECODER::GetOnDiskSize.
2459 // code:MethodDesc::GetILHeader contains debug-only check that ensures that both implementations
2463 SIZE_T PEDecoder::ComputeILMethodSize(TADDR pIL)
2472 // Mirror flow of code:PEDecoder::CheckILMethod, except for the range checks
2475 PTR_COR_ILMETHOD_TINY pMethodTiny = PTR_COR_ILMETHOD_TINY(pIL);
2477 if (pMethodTiny->IsTiny())
2479 return sizeof(IMAGE_COR_ILMETHOD_TINY) + pMethodTiny->GetCodeSize();
2482 PTR_COR_ILMETHOD_FAT pMethodFat = PTR_COR_ILMETHOD_FAT(pIL);
2484 UINT32 codeEnd = 4 * pMethodFat->GetSize() + pMethodFat->GetCodeSize();
2486 if (!pMethodFat->More())
2491 // DACized copy of code:COR_ILMETHOD_FAT::GetSect
2492 TADDR pSect = AlignUp(pIL + codeEnd, 4);
2496 PTR_COR_ILMETHOD_SECT_SMALL pSectSmall = PTR_COR_ILMETHOD_SECT_SMALL(pSect);
2500 if (pSectSmall->IsSmall())
2502 sectSize = pSectSmall->DataSize;
2504 // Workaround for bug in shipped compilers - see comment in code:COR_ILMETHOD_SECT::DataSize
2505 if ((pSectSmall->Kind & CorILMethod_Sect_KindMask) == CorILMethod_Sect_EHTable)
2506 sectSize = COR_ILMETHOD_SECT_EH_SMALL::Size(sectSize / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL));
2510 PTR_COR_ILMETHOD_SECT_FAT pSectFat = PTR_COR_ILMETHOD_SECT_FAT(pSect);
2512 sectSize = pSectFat->GetDataSize();
2514 // Workaround for bug in shipped compilers - see comment in code:COR_ILMETHOD_SECT::DataSize
2515 if ((pSectSmall->Kind & CorILMethod_Sect_KindMask) == CorILMethod_Sect_EHTable)
2516 sectSize = COR_ILMETHOD_SECT_EH_FAT::Size(sectSize / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT));
2519 UINT32 sectEnd = UINT32(pSect - pIL) + sectSize;
2521 if (!pSectSmall->More() || (sectSize == 0))
2526 // DACized copy of code:COR_ILMETHOD_FAT::Next
2527 pSect = AlignUp(pIL + sectEnd, 4);
2532 // GetDebugDirectoryEntry - return the debug directory entry at the specified index
2535 // index The 0-based index of the entry to return. Usually this is just 0,
2536 // but there can be multiple debug directory entries in a PE file.
2539 // A pointer to the IMAGE_DEBUG_DIRECTORY in the PE file for the specified index,
2540 // or NULL if it doesn't exist.
2542 // Note that callers on untrusted input are required to validate the debug directory
2543 // first by calling CheckDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG) (possibly
2544 // indirectly via one of the CheckILOnly* functions).
2546 PTR_IMAGE_DEBUG_DIRECTORY PEDecoder::GetDebugDirectoryEntry(UINT index) const
2548 CONTRACT(PTR_IMAGE_DEBUG_DIRECTORY)
2551 PRECONDITION(CheckNTHeaders());
2558 if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG))
2563 // Get a pointer to the contents and size of the debug directory
2564 // Also validates (in CHK builds) that this is all within one section, which the
2565 // caller should have already validated if they don't trust the context of this PE file.
2567 TADDR taDebugDir = GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_DEBUG, &cbDebugDir);
2569 // Check if the specified directory entry exists (based on the size of the directory)
2570 // Note that the directory size should be an even multiple of the entry size, but we
2571 // just round-down because we need to be resiliant (without asserting) to corrupted /
2573 UINT cNumEntries = cbDebugDir / sizeof(IMAGE_DEBUG_DIRECTORY);
2574 if (index >= cNumEntries)
2576 RETURN NULL; // index out of range
2579 // Get the debug directory entry at the specified index.
2580 PTR_IMAGE_DEBUG_DIRECTORY pDebugEntry = dac_cast<PTR_IMAGE_DEBUG_DIRECTORY>(taDebugDir);
2581 pDebugEntry += index; // offset from the first entry to the requested entry
2586 #ifdef FEATURE_PREJIT
2588 CORCOMPILE_EE_INFO_TABLE *PEDecoder::GetNativeEEInfoTable() const
2590 CONTRACT(CORCOMPILE_EE_INFO_TABLE *)
2592 PRECONDITION(CheckNativeHeader());
2595 POSTCONDITION(CheckPointer(RETVAL));
2599 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->EEInfoTable;
2601 // 403523: PREFIX correctly complained here. Fixed GetDirectoryData.
2602 RETURN PTR_CORCOMPILE_EE_INFO_TABLE(GetDirectoryData(pDir));
2606 void *PEDecoder::GetNativeHelperTable(COUNT_T *pSize) const
2610 PRECONDITION(CheckNativeHeader());
2616 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->HelperTable;
2619 *pSize = VAL32(pDir->Size);
2621 RETURN (void *)GetDirectoryData(pDir);
2624 CORCOMPILE_VERSION_INFO *PEDecoder::GetNativeVersionInfoMaybeNull(bool skipCheckNativeHeader) const
2626 CONTRACT(CORCOMPILE_VERSION_INFO *)
2628 PRECONDITION(skipCheckNativeHeader || CheckNativeHeader());
2629 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2636 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->VersionInfo;
2638 RETURN PTR_CORCOMPILE_VERSION_INFO(GetDirectoryData(pDir));
2641 CORCOMPILE_VERSION_INFO *PEDecoder::GetNativeVersionInfo() const
2643 CONTRACT(CORCOMPILE_VERSION_INFO *)
2645 POSTCONDITION(CheckPointer(RETVAL));
2652 RETURN GetNativeVersionInfoMaybeNull();
2655 BOOL PEDecoder::HasNativeDebugMap() const
2659 PRECONDITION(CheckNativeHeader());
2667 // 403522: Prefix complained correctly here.
2668 CORCOMPILE_HEADER *pNativeHeader = GetNativeHeader();
2672 RETURN (VAL32(pNativeHeader->DebugMap.VirtualAddress) != 0);
2675 TADDR PEDecoder::GetNativeDebugMap(COUNT_T *pSize) const
2679 PRECONDITION(CheckNativeHeader());
2680 PRECONDITION(CheckPointer(pSize, NULL_OK));
2687 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->DebugMap;
2690 *pSize = VAL32(pDir->Size);
2692 RETURN (GetDirectoryData(pDir));
2695 Module *PEDecoder::GetPersistedModuleImage(COUNT_T *pSize) const
2699 PRECONDITION(CheckNativeHeader());
2700 PRECONDITION(CheckPointer(pSize, NULL_OK));
2701 POSTCONDITION(CheckPointer(RETVAL));
2707 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->ModuleImage;
2710 *pSize = VAL32(pDir->Size);
2712 RETURN (Module *) GetDirectoryData(pDir);
2715 CHECK PEDecoder::CheckNativeHeaderVersion() const
2719 PRECONDITION(CheckNativeHeader());
2725 IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->ManagedNativeHeader;
2726 CHECK(VAL32(pDir->Size) == sizeof(CORCOMPILE_HEADER));
2728 CORCOMPILE_HEADER *pNativeHeader = GetNativeHeader();
2729 CHECK(pNativeHeader->Signature == CORCOMPILE_SIGNATURE);
2730 CHECK(pNativeHeader->MajorVersion == CORCOMPILE_MAJOR_VERSION);
2731 CHECK(pNativeHeader->MinorVersion == CORCOMPILE_MINOR_VERSION);
2736 CORCOMPILE_CODE_MANAGER_ENTRY *PEDecoder::GetNativeCodeManagerTable() const
2738 CONTRACT(CORCOMPILE_CODE_MANAGER_ENTRY *)
2740 PRECONDITION(CheckNativeHeader());
2741 POSTCONDITION(CheckPointer(RETVAL));
2748 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->CodeManagerTable;
2750 RETURN PTR_CORCOMPILE_CODE_MANAGER_ENTRY(GetDirectoryData(pDir));
2753 PCODE PEDecoder::GetNativeHotCode(COUNT_T * pSize) const
2757 PRECONDITION(CheckNativeHeader());
2758 PRECONDITION(CheckPointer(pSize, NULL_OK));
2765 IMAGE_DATA_DIRECTORY *pDir = &GetNativeCodeManagerTable()->HotCode;
2768 *pSize = VAL32(pDir->Size);
2770 RETURN GetDirectoryData(pDir);
2773 PCODE PEDecoder::GetNativeCode(COUNT_T * pSize) const
2777 PRECONDITION(CheckNativeHeader());
2778 PRECONDITION(CheckPointer(pSize, NULL_OK));
2785 IMAGE_DATA_DIRECTORY *pDir = &GetNativeCodeManagerTable()->Code;
2788 *pSize = VAL32(pDir->Size);
2790 RETURN GetDirectoryData(pDir);
2793 PCODE PEDecoder::GetNativeColdCode(COUNT_T * pSize) const
2797 PRECONDITION(CheckNativeHeader());
2798 PRECONDITION(CheckPointer(pSize, NULL_OK));
2805 IMAGE_DATA_DIRECTORY *pDir = &GetNativeCodeManagerTable()->ColdCode;
2808 *pSize = VAL32(pDir->Size);
2810 RETURN GetDirectoryData(pDir);
2814 CORCOMPILE_METHOD_PROFILE_LIST *PEDecoder::GetNativeProfileDataList(COUNT_T * pSize) const
2816 CONTRACT(CORCOMPILE_METHOD_PROFILE_LIST *)
2818 PRECONDITION(CheckNativeHeader());
2819 PRECONDITION(CheckPointer(pSize, NULL_OK));
2820 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2826 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->ProfileDataList;
2829 *pSize = VAL32(pDir->Size);
2831 RETURN PTR_CORCOMPILE_METHOD_PROFILE_LIST(GetDirectoryData(pDir));
2834 #endif // FEATURE_PREJIT
2836 PTR_CVOID PEDecoder::GetNativeManifestMetadata(COUNT_T *pSize) const
2841 PRECONDITION(HasReadyToRunHeader() || CheckNativeHeader());
2842 POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); // TBD - may not store metadata for IJW
2848 IMAGE_DATA_DIRECTORY *pDir = NULL;
2849 #ifdef FEATURE_PREJIT
2850 if (!HasReadyToRunHeader())
2852 pDir = GetMetaDataHelper(METADATA_SECTION_MANIFEST);
2857 READYTORUN_HEADER * pHeader = GetReadyToRunHeader();
2859 PTR_READYTORUN_SECTION pSections = dac_cast<PTR_READYTORUN_SECTION>(dac_cast<TADDR>(pHeader) + sizeof(READYTORUN_HEADER));
2860 for (DWORD i = 0; i < pHeader->NumberOfSections; i++)
2862 // Verify that section types are sorted
2863 _ASSERTE(i == 0 || (pSections[i - 1].Type < pSections[i].Type));
2865 READYTORUN_SECTION * pSection = pSections + i;
2866 if (pSection->Type == READYTORUN_SECTION_MANIFEST_METADATA)
2868 // Set pDir to the address of the manifest metadata section
2869 pDir = &pSection->Section;
2874 // ReadyToRun file without large version bubble support doesn't have the READYTORUN_SECTION_MANIFEST_METADATA
2887 *pSize = VAL32(pDir->Size);
2889 RETURN dac_cast<PTR_VOID>(GetDirectoryData(pDir));
2892 #ifdef FEATURE_PREJIT
2894 PTR_CORCOMPILE_IMPORT_SECTION PEDecoder::GetNativeImportSections(COUNT_T *pCount) const
2896 CONTRACT(PTR_CORCOMPILE_IMPORT_SECTION)
2898 PRECONDITION(CheckNativeHeader());
2904 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->ImportSections;
2907 *pCount = VAL32(pDir->Size) / sizeof(CORCOMPILE_IMPORT_SECTION);
2909 RETURN dac_cast<PTR_CORCOMPILE_IMPORT_SECTION>(GetDirectoryData(pDir));
2912 PTR_CORCOMPILE_IMPORT_SECTION PEDecoder::GetNativeImportSectionFromIndex(COUNT_T index) const
2914 CONTRACT(PTR_CORCOMPILE_IMPORT_SECTION)
2916 PRECONDITION(CheckNativeHeader());
2922 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->ImportSections;
2924 _ASSERTE(VAL32(pDir->Size) % sizeof(CORCOMPILE_IMPORT_SECTION) == 0);
2925 _ASSERTE(index * sizeof(CORCOMPILE_IMPORT_SECTION) < VAL32(pDir->Size));
2927 RETURN dac_cast<PTR_CORCOMPILE_IMPORT_SECTION>(GetDirectoryData(pDir)) + index;
2930 PTR_CORCOMPILE_IMPORT_SECTION PEDecoder::GetNativeImportSectionForRVA(RVA rva) const
2932 CONTRACT(PTR_CORCOMPILE_IMPORT_SECTION)
2934 PRECONDITION(CheckNativeHeader());
2940 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->ImportSections;
2942 _ASSERTE(VAL32(pDir->Size) % sizeof(CORCOMPILE_IMPORT_SECTION) == 0);
2944 PTR_CORCOMPILE_IMPORT_SECTION pSections = dac_cast<PTR_CORCOMPILE_IMPORT_SECTION>(GetDirectoryData(pDir));
2945 PTR_CORCOMPILE_IMPORT_SECTION pEnd = dac_cast<PTR_CORCOMPILE_IMPORT_SECTION>(dac_cast<TADDR>(pSections) + VAL32(pDir->Size));
2947 for (PTR_CORCOMPILE_IMPORT_SECTION pSection = pSections; pSection < pEnd; pSection++)
2949 if (rva >= VAL32(pSection->Section.VirtualAddress) && rva < VAL32(pSection->Section.VirtualAddress) + VAL32(pSection->Section.Size))
2956 TADDR PEDecoder::GetStubsTable(COUNT_T *pSize) const
2960 PRECONDITION(CheckNativeHeader());
2965 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->StubsData;
2968 *pSize = VAL32(pDir->Size);
2970 return (GetDirectoryData(pDir));
2973 TADDR PEDecoder::GetVirtualSectionsTable(COUNT_T *pSize) const
2977 PRECONDITION(CheckNativeHeader());
2982 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->VirtualSectionsTable;
2985 *pSize = VAL32(pDir->Size);
2987 return (GetDirectoryData(pDir));
2990 #endif // FEATURE_PREJIT
2992 // Get the SizeOfStackReserve and SizeOfStackCommit from the PE file that was used to create
2993 // the calling process (.exe file).
2994 void PEDecoder::GetEXEStackSizes(SIZE_T *PE_SizeOfStackReserve, SIZE_T *PE_SizeOfStackCommit) const
2997 PRECONDITION(!IsDll()); // This routine should only be called for EXE files.
3002 * PE_SizeOfStackReserve = GetSizeOfStackReserve();
3003 * PE_SizeOfStackCommit = GetSizeOfStackCommit();
3006 CHECK PEDecoder::CheckWillCreateGuardPage() const
3010 PRECONDITION(CheckNTHeaders());
3018 SIZE_T sizeReservedStack = 0;
3019 SIZE_T sizeCommitedStack = 0;
3021 GetEXEStackSizes(&sizeReservedStack, &sizeCommitedStack);
3023 CHECK(ThreadWillCreateGuardPage(sizeReservedStack, sizeCommitedStack));
3030 BOOL PEDecoder::HasNativeEntryPoint() const
3036 PRECONDITION(CheckCorHeader());
3039 ULONG flags = GetCorHeader()->Flags;
3040 return ((flags & VAL32(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT)) &&
3041 (IMAGE_COR20_HEADER_FIELD(*GetCorHeader(), EntryPointToken) != VAL32(0)));
3044 void *PEDecoder::GetNativeEntryPoint() const
3050 PRECONDITION(CheckCorHeader());
3051 PRECONDITION(HasNativeEntryPoint());
3052 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
3055 RETURN ((void *) GetRvaData((RVA)VAL32(IMAGE_COR20_HEADER_FIELD(*GetCorHeader(), EntryPointToken))));
3058 #ifdef DACCESS_COMPILE
3061 PEDecoder::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
3070 DacEnumMemoryRegion((TADDR)m_base, sizeof(IMAGE_DOS_HEADER));
3071 m_pNTHeaders.EnumMem();
3072 m_pCorHeader.EnumMem();
3073 m_pNativeHeader.EnumMem();
3074 m_pReadyToRunHeader.EnumMem();
3078 // resource file does not have NT Header.
3080 // we also need to write out section header.
3081 DacEnumMemoryRegion(dac_cast<TADDR>(FindFirstSection()), sizeof(IMAGE_SECTION_HEADER) * GetNumberOfSections());
3085 #endif // #ifdef DACCESS_COMPILE
3087 // --------------------------------------------------------------------------------
3091 // This is a stress mode to force DLLs to be relocated.
3092 // This is particularly useful for hardbinding of ngen images as we
3093 // embed pointers into other hardbound ngen dependencies.
3095 BOOL PEDecoder::GetForceRelocs()
3097 WRAPPER_NO_CONTRACT;
3099 static ConfigDWORD forceRelocs;
3100 return (forceRelocs.val(CLRConfig::INTERNAL_ForceRelocs) != 0);
3103 BOOL PEDecoder::ForceRelocForDLL(LPCWSTR lpFileName)
3105 // Use static contracts to avoid recursion, as the dynamic contracts
3106 // do WszLoadLibrary(MSCOREE_SHIM_W).
3108 STATIC_CONTRACT_NOTHROW; \
3109 ANNOTATION_DEBUG_ONLY; \
3110 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
3113 #if defined(DACCESS_COMPILE) || defined(FEATURE_PAL)
3117 // Contracts in ConfigDWORD do WszLoadLibrary(MSCOREE_SHIM_W).
3118 // This check prevents recursion.
3119 if (wcsstr(lpFileName, MSCOREE_SHIM_W) != 0)
3122 if (!GetForceRelocs())
3125 BOOL fSuccess = FALSE;
3128 void* pPreferredBase;
3129 COUNT_T nVirtualSize;
3131 HANDLE hFile = WszCreateFile(lpFileName,
3136 FILE_FLAG_SEQUENTIAL_SCAN,
3138 if (hFile == INVALID_HANDLE_VALUE)
3141 HANDLE hMap = WszCreateFileMapping(hFile,
3143 SEC_IMAGE | PAGE_READONLY,
3152 hndle = (PBYTE)MapViewOfFile(hMap,
3164 pPreferredBase = (void*)pe.GetPreferredBase();
3165 nVirtualSize = pe.GetVirtualSize();
3167 UnmapViewOfFile(hndle);
3170 // Reserve the space so nobody can use it. A potential bug is likely to
3171 // result in a plain AV this way. It is not a good idea to use the original
3172 // mapping for the reservation since since it would lock the file on the disk.
3173 if (!ClrVirtualAlloc(pPreferredBase, nVirtualSize, MEM_RESERVE, PAGE_NOACCESS))
3180 UnmapViewOfFile(hndle);
3184 #endif // DACCESS_COMPILE || FEATURE_PAL
3190 // MethodSectionIterator class is used to iterate hot (or) cold method section in an ngen image.
3191 // Also used to iterate over jitted methods in the code heap
3193 MethodSectionIterator::MethodSectionIterator(const void *code, SIZE_T codeSize,
3194 const void *codeTable, SIZE_T codeTableSize)
3196 //For DAC builds,we'll read the table one DWORD at a time. Note that m_code IS
3197 //NOT a host pointer.
3198 m_codeTableStart = PTR_DWORD(TADDR(codeTable));
3199 m_codeTable = m_codeTableStart;
3200 _ASSERTE((codeTableSize % sizeof(DWORD)) == 0);
3201 m_codeTableEnd = m_codeTableStart + (codeTableSize / sizeof(DWORD));
3202 m_code = (BYTE *) code;
3206 if (m_codeTable < m_codeTableEnd)
3208 m_dword = *m_codeTable++;
3213 m_index = NIBBLES_PER_DWORD;
3217 BOOL MethodSectionIterator::Next()
3219 while (m_codeTable < m_codeTableEnd || m_index < (int)NIBBLES_PER_DWORD)
3221 while (m_index++ < (int)NIBBLES_PER_DWORD)
3223 int nibble = (m_dword & HIGHEST_NIBBLE_MASK)>>HIGHEST_NIBBLE_BIT;
3224 m_dword <<= NIBBLE_SIZE;
3228 // We have found a method start
3229 m_current = m_code + ((nibble-1)*CODE_ALIGN);
3230 m_code += BYTES_PER_BUCKET;
3234 m_code += BYTES_PER_BUCKET;
3237 if (m_codeTable < m_codeTableEnd)
3239 m_dword = *m_codeTable++;