[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / utilcode / pedecoder.cpp
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 // PEDecoder.cpp
6 //
7
8 // --------------------------------------------------------------------------------
9
10 #include "stdafx.h"
11
12 #include "ex.h"
13 #include "pedecoder.h"
14 #include "mdcommon.h"
15 #include "nibblemapmacros.h"
16
17 CHECK PEDecoder::CheckFormat() const
18 {
19     CONTRACT_CHECK
20     {
21         INSTANCE_CHECK;
22         NOTHROW;
23         GC_NOTRIGGER;
24     }
25     CONTRACT_CHECK_END;
26
27     CHECK(HasContents());
28
29     if (HasNTHeaders())
30     {
31         CHECK(CheckNTHeaders());
32
33         if (HasCorHeader())
34         {
35             CHECK(CheckCorHeader());
36
37             if (IsILOnly())
38                 CHECK(CheckILOnly());
39
40             if (HasNativeHeader())
41                 CHECK(CheckNativeHeader());
42
43             CHECK(CheckWillCreateGuardPage());
44         }
45     }
46
47     CHECK_OK;
48 }
49
50 CHECK PEDecoder::CheckNTFormat() const
51 {
52     CONTRACT_CHECK
53     {
54         INSTANCE_CHECK;
55         NOTHROW;
56         GC_NOTRIGGER;
57         PRECONDITION(HasContents());
58     }
59     CONTRACT_CHECK_END;
60
61     CHECK(CheckFormat());
62     CHECK(HasNTHeaders());
63
64     CHECK_OK;
65 }
66
67 CHECK PEDecoder::CheckCORFormat() const
68 {
69     CONTRACT_CHECK
70     {
71         INSTANCE_CHECK;
72         NOTHROW;
73         GC_NOTRIGGER;
74         PRECONDITION(HasContents());
75     }
76     CONTRACT_CHECK_END;
77
78     CHECK(CheckFormat());
79     CHECK(HasNTHeaders());
80     CHECK(HasCorHeader());
81
82     CHECK_OK;
83 }
84
85
86 CHECK PEDecoder::CheckILFormat() const
87 {
88     CONTRACT_CHECK
89     {
90         INSTANCE_CHECK;
91         NOTHROW;
92         GC_NOTRIGGER;
93         PRECONDITION(HasContents());
94     }
95     CONTRACT_CHECK_END;
96
97     CHECK(CheckFormat());
98     CHECK(HasNTHeaders());
99     CHECK(HasCorHeader());
100     CHECK(!HasNativeHeader());
101
102     CHECK_OK;
103 }
104
105
106 CHECK PEDecoder::CheckILOnlyFormat() const
107 {
108     CONTRACT_CHECK
109     {
110         INSTANCE_CHECK;
111         NOTHROW;
112         GC_NOTRIGGER;
113         PRECONDITION(HasContents());
114     }
115     CONTRACT_CHECK_END;
116
117     CHECK(CheckFormat());
118     CHECK(HasNTHeaders());
119     CHECK(HasCorHeader());
120     CHECK(IsILOnly());
121     CHECK(!HasNativeHeader());
122
123     CHECK_OK;
124 }
125
126 CHECK PEDecoder::CheckNativeFormat() const
127 {
128     CONTRACT_CHECK
129     {
130         INSTANCE_CHECK;
131         NOTHROW;
132         GC_NOTRIGGER;
133         PRECONDITION(HasContents());
134     }
135     CONTRACT_CHECK_END;
136
137 #ifdef FEATURE_PREJIT
138     CHECK(CheckFormat());
139     CHECK(HasNTHeaders());
140     CHECK(HasCorHeader());
141     CHECK(!IsILOnly());
142     CHECK(HasNativeHeader());
143 #else // FEATURE_PREJIT
144     CHECK(false);
145 #endif // FEATURE_PREJIT
146
147     CHECK_OK;
148 }
149
150 BOOL PEDecoder::HasNTHeaders() const
151 {
152     CONTRACT(BOOL)
153     {
154         INSTANCE_CHECK;
155         NOTHROW;
156         GC_NOTRIGGER;
157         SUPPORTS_DAC;
158         PRECONDITION(HasContents());
159     }
160     CONTRACT_END;
161
162     // Check for a valid DOS header
163
164     if (m_size < sizeof(IMAGE_DOS_HEADER))
165         RETURN FALSE;
166
167     IMAGE_DOS_HEADER* pDOS = PTR_IMAGE_DOS_HEADER(m_base);
168
169     {
170         if (pDOS->e_magic != VAL16(IMAGE_DOS_SIGNATURE)
171             || (DWORD) pDOS->e_lfanew == VAL32(0))
172         {
173             RETURN FALSE;
174         }
175
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())
180         {
181             RETURN FALSE;
182         }
183
184         // Now check for a valid NT header
185         if (m_size < cbNTHeaderEnd.Value())
186         {
187             RETURN FALSE;
188         }
189     }
190
191     IMAGE_NT_HEADERS *pNT = PTR_IMAGE_NT_HEADERS(m_base + VAL32(pDOS->e_lfanew));
192
193     if (pNT->Signature != VAL32(IMAGE_NT_SIGNATURE))
194         RETURN FALSE;
195
196     if (pNT->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC))
197     {
198         if (pNT->FileHeader.SizeOfOptionalHeader != VAL16(sizeof(IMAGE_OPTIONAL_HEADER32)))
199             RETURN FALSE;
200     }
201     else if (pNT->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR64_MAGIC))
202     {
203         // on 64 bit we can promote this
204         if (pNT->FileHeader.SizeOfOptionalHeader != VAL16(sizeof(IMAGE_OPTIONAL_HEADER64)))
205             RETURN FALSE;
206
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)));
210
211         if (cbNTHeaderEnd.IsOverflow())
212         {
213             RETURN FALSE;
214     }
215
216         // Now check for a valid NT header
217         if (m_size < cbNTHeaderEnd.Value())
218         {
219             RETURN FALSE;
220         }
221
222     }
223     else
224         RETURN FALSE;
225
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);
228
229     RETURN TRUE;
230 }
231
232 CHECK PEDecoder::CheckNTHeaders() const
233 {
234     CONTRACT_CHECK
235     {
236         INSTANCE_CHECK;
237         NOTHROW;
238         GC_NOTRIGGER;
239         SUPPORTS_DAC;
240         PRECONDITION(HasContents());
241     }
242     CONTRACT_CHECK_END;
243
244     // Only check once per file
245     if (m_flags & FLAG_NT_CHECKED)
246         CHECK_OK;
247
248     CHECK(HasNTHeaders());
249
250     IMAGE_NT_HEADERS *pNT = FindNTHeaders();
251
252     CHECK((pNT->FileHeader.Characteristics & VAL16(IMAGE_FILE_SYSTEM)) == 0);
253
254     CHECK(CheckAlignment(VAL32(pNT->OptionalHeader.FileAlignment)));
255     CHECK(CheckAlignment(VAL32(pNT->OptionalHeader.SectionAlignment)));
256
257     CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.FileAlignment), 512));
258     CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.SectionAlignment), VAL32(pNT->OptionalHeader.FileAlignment)));
259
260     CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.SizeOfImage), VAL32(pNT->OptionalHeader.SectionAlignment)));
261     CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.SizeOfHeaders), VAL32(pNT->OptionalHeader.FileAlignment)));
262
263     // Data directories will be validated later on.
264     PTR_IMAGE_DATA_DIRECTORY pDataDirectories = NULL;
265
266     if (Has32BitNTHeaders())
267     {
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));
274     }
275     else
276     {
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));
283     }
284
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.)
288
289     if (IsMapped())
290     {
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()));
295     }
296
297     // @todo: check NumberOfSections for overflow of SizeOfHeaders
298
299     UINT32 currentAddress  = 0;
300     UINT32 currentOffset = 0;
301
302     CHECK(CheckSection(currentAddress, 0, VAL32(pNT->OptionalHeader.SizeOfHeaders),
303                        currentOffset, 0, VAL32(pNT->OptionalHeader.SizeOfHeaders)));
304
305     currentAddress=currentOffset=VAL32(pNT->OptionalHeader.SizeOfHeaders);
306
307     PTR_IMAGE_SECTION_HEADER section = FindFirstSection(pNT);
308     PTR_IMAGE_SECTION_HEADER sectionEnd = section + VAL16(pNT->FileHeader.NumberOfSections);
309
310     CHECK(sectionEnd >= section);
311
312
313     while (section < sectionEnd)
314     {
315
316         //
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.
328         // 
329
330         if (!IsMapped())
331         {
332             CHECK(CheckBounds(dac_cast<PTR_CVOID>(pNT),VAL32(pNT->OptionalHeader.SizeOfHeaders),
333                               section,sizeof(IMAGE_SECTION_HEADER)));
334         }
335
336         // Check flags
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           |
346                   IMAGE_SCN_MEM_READ              |
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)))));
351
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)));
355
356         CHECK(CheckSection(currentAddress, VAL32(section->VirtualAddress), VAL32(section->Misc.VirtualSize),
357                            currentOffset, VAL32(section->PointerToRawData), VAL32(section->SizeOfRawData)));
358
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);
362
363         section++;
364     }
365
366     // Now check that the COR data directory is either NULL, or exists entirely in one section.
367     {
368         PTR_IMAGE_DATA_DIRECTORY pCORDataDir = pDataDirectories + IMAGE_DIRECTORY_ENTRY_COMHEADER;
369         CHECK(CheckRva(VAL32(pCORDataDir->VirtualAddress), VAL32(pCORDataDir->Size), 0, NULL_OK));
370     }
371
372     // @todo: verify directory entries
373
374     const_cast<PEDecoder *>(this)->m_flags |= FLAG_NT_CHECKED;
375
376     CHECK_OK;
377 }
378
379 CHECK PEDecoder::CheckSection(COUNT_T previousAddressEnd, COUNT_T addressStart, COUNT_T addressSize,
380                               COUNT_T previousOffsetEnd, COUNT_T offsetStart, COUNT_T offsetSize) const
381 {
382     CONTRACT_CHECK
383     {
384         INSTANCE_CHECK;
385         PRECONDITION(HasNTHeaders());
386         NOTHROW;
387         GC_NOTRIGGER;
388         SUPPORTS_DAC;
389     }
390     CONTRACT_CHECK_END;
391
392     // Fetch the NT header
393     IMAGE_NT_HEADERS *pNT = FindNTHeaders();
394
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;
398
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.
401     if (IsMapped())
402         CHECK(alignedSize >= VAL32(pNT->OptionalHeader.SizeOfImage));
403
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)));
408
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);
412
413     // Check overflow
414     CHECK(CheckOverflow(addressStart, alignedAddressSize));
415     CHECK(CheckOverflow(offsetStart, offsetSize));
416
417     // Make sure we don't overlap the previous section
418     CHECK(addressStart >= previousAddressEnd
419           && (offsetSize == 0
420               || offsetStart >= previousOffsetEnd));
421
422     // Make sure we don't overrun the end of the mapped image
423     CHECK(addressStart + alignedAddressSize <= VAL32(pNT->OptionalHeader.SizeOfImage));
424
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.)
427     if (!IsMapped())
428         CHECK(offsetStart + offsetSize <= alignedSize);
429
430     // Make sure the data doesn't overrun the virtual address space
431     CHECK(offsetSize <= alignedAddressSize);
432
433     CHECK_OK;
434 }
435
436 BOOL PEDecoder::HasWriteableSections() const
437 {
438     CONTRACT_CHECK
439     {
440         INSTANCE_CHECK;
441         PRECONDITION(CheckNTHeaders());
442         PRECONDITION(CheckFormat());
443         NOTHROW;
444         GC_NOTRIGGER;
445         SUPPORTS_DAC;
446     }
447     CONTRACT_CHECK_END;
448
449     PTR_IMAGE_SECTION_HEADER pSection = FindFirstSection();
450     _ASSERTE(pSection != NULL);
451
452     PTR_IMAGE_SECTION_HEADER pSectionEnd = pSection + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
453
454     while (pSection < pSectionEnd)
455     {
456         if ((pSection->Characteristics & VAL32(IMAGE_SCN_MEM_WRITE)) != 0)
457         {
458             return TRUE;
459         }
460
461         pSection++;
462     }
463
464     return FALSE;
465 }
466
467 CHECK PEDecoder::CheckDirectoryEntry(int entry, int forbiddenFlags, IsNullOK ok) const
468 {
469     CONTRACT_CHECK
470     {
471         INSTANCE_CHECK;
472         PRECONDITION(CheckNTHeaders());
473         PRECONDITION(entry < IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
474         PRECONDITION(HasDirectoryEntry(entry));
475         NOTHROW;
476         GC_NOTRIGGER;
477     }
478     CONTRACT_CHECK_END;
479
480     CHECK(CheckDirectory(GetDirectoryEntry(entry), forbiddenFlags, ok));
481
482     CHECK_OK;
483 }
484
485 CHECK PEDecoder::CheckDirectory(IMAGE_DATA_DIRECTORY *pDir, int forbiddenFlags, IsNullOK ok) const
486 {
487     CONTRACT_CHECK
488     {
489         INSTANCE_CHECK;
490         PRECONDITION(CheckNTHeaders());
491         PRECONDITION(CheckPointer(pDir));
492         NOTHROW;
493         GC_NOTRIGGER;
494         SUPPORTS_DAC;
495     }
496     CONTRACT_CHECK_END;
497
498     CHECK(CheckRva(VAL32(pDir->VirtualAddress), VAL32(pDir->Size), forbiddenFlags, ok));
499
500     CHECK_OK;
501 }
502
503 CHECK PEDecoder::CheckRva(RVA rva, COUNT_T size, int forbiddenFlags, IsNullOK ok) const
504 {
505     CONTRACT_CHECK
506     {
507         INSTANCE_CHECK;
508         NOTHROW;
509         GC_NOTRIGGER;
510         SUPPORTS_DAC;
511     }
512     CONTRACT_CHECK_END;
513
514     if (rva == 0)
515     {
516         CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
517         CHECK(size == 0);
518     }
519     else
520     {
521         IMAGE_SECTION_HEADER *section = RvaToSection(rva);
522
523         CHECK(section != NULL);
524
525         CHECK(CheckBounds(VAL32(section->VirtualAddress),
526                           // AlignUp((UINT)VAL32(section->Misc.VirtualSize), (UINT)VAL32(FindNTHeaders()->OptionalHeader.SectionAlignment)),
527                           (UINT)VAL32(section->Misc.VirtualSize),
528                           rva, size));
529         if(!IsMapped())
530         {
531             CHECK(CheckBounds(VAL32(section->VirtualAddress), VAL32(section->SizeOfRawData), rva, size));
532         }
533
534         if (forbiddenFlags!=0)
535             CHECK((section->Characteristics & VAL32(forbiddenFlags))==0);
536     }
537
538     CHECK_OK;
539 }
540
541 CHECK PEDecoder::CheckRva(RVA rva, IsNullOK ok) const
542 {
543     CONTRACT_CHECK
544     {
545         INSTANCE_CHECK;
546         NOTHROW;
547         GC_NOTRIGGER;
548         SUPPORTS_DAC;
549     }
550     CONTRACT_CHECK_END;
551
552     if (rva == 0)
553         CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
554     else
555         CHECK(RvaToSection(rva) != NULL);
556
557     CHECK_OK;
558 }
559
560 CHECK PEDecoder::CheckOffset(COUNT_T fileOffset, COUNT_T size, IsNullOK ok) const
561 {
562     CONTRACT_CHECK
563     {
564         INSTANCE_CHECK;
565         PRECONDITION(CheckNTHeaders());
566         NOTHROW;
567         GC_NOTRIGGER;
568     }
569     CONTRACT_CHECK_END;
570
571     if (fileOffset == 0)
572     {
573         CHECK_MSG(ok == NULL_OK, "zero fileOffset illegal");
574         CHECK(size == 0);
575     }
576     else
577     {
578         IMAGE_SECTION_HEADER *section = OffsetToSection(fileOffset);
579
580         CHECK(section != NULL);
581
582         CHECK(CheckBounds(section->PointerToRawData, section->SizeOfRawData,
583                           fileOffset, size));
584     }
585
586     CHECK_OK;
587 }
588
589 CHECK PEDecoder::CheckOffset(COUNT_T fileOffset, IsNullOK ok) const
590 {
591     CONTRACT_CHECK
592     {
593         INSTANCE_CHECK;
594         PRECONDITION(CheckNTHeaders());
595         NOTHROW;
596         GC_NOTRIGGER;
597     }
598     CONTRACT_CHECK_END;
599
600     if (fileOffset == NULL)
601         CHECK_MSG(ok == NULL_OK, "Null pointer illegal");
602     else
603     {
604         CHECK(OffsetToSection(fileOffset) != NULL);
605     }
606
607     CHECK_OK;
608 }
609
610 CHECK PEDecoder::CheckData(const void *data, COUNT_T size, IsNullOK ok) const
611 {
612     CONTRACT_CHECK
613     {
614         INSTANCE_CHECK;
615         PRECONDITION(CheckNTHeaders());
616         NOTHROW;
617         GC_NOTRIGGER;
618     }
619     CONTRACT_CHECK_END;
620
621     if (data == NULL)
622     {
623         CHECK_MSG(ok == NULL_OK, "NULL pointer illegal");
624         CHECK(size == 0);
625     }
626     else
627     {
628         CHECK(CheckUnderflow(data, m_base));
629         CHECK((UINT_PTR) (((BYTE *) data) - ((BYTE *) m_base)) <= COUNT_T_MAX);
630
631         if (IsMapped())
632             CHECK(CheckRva((COUNT_T) ((BYTE *) data - (BYTE *) m_base), size));
633         else
634             CHECK(CheckOffset((COUNT_T) ((BYTE *) data - (BYTE *) m_base), size));
635     }
636
637     CHECK_OK;
638 }
639
640 CHECK PEDecoder::CheckData(const void *data, IsNullOK ok) const
641 {
642     CONTRACT_CHECK
643     {
644         INSTANCE_CHECK;
645         PRECONDITION(CheckNTHeaders());
646         NOTHROW;
647         GC_NOTRIGGER;
648     }
649     CONTRACT_CHECK_END;
650
651     if (data == NULL)
652         CHECK_MSG(ok == NULL_OK, "Null pointer illegal");
653     else
654     {
655         CHECK(CheckUnderflow(data, m_base));
656         CHECK((UINT_PTR) (((BYTE *) data) - ((BYTE *) m_base)) <= COUNT_T_MAX);
657
658         if (IsMapped())
659             CHECK(CheckRva((COUNT_T) ((BYTE *) data - (BYTE *) m_base)));
660         else
661             CHECK(CheckOffset((COUNT_T) ((BYTE *) data - (BYTE *) m_base)));
662     }
663
664     CHECK_OK;
665 }
666
667 CHECK PEDecoder::CheckInternalAddress(SIZE_T address, IsNullOK ok) const
668 {
669     CONTRACT_CHECK
670     {
671         INSTANCE_CHECK;
672         PRECONDITION(CheckNTHeaders());
673         NOTHROW;
674         GC_NOTRIGGER;
675     }
676     CONTRACT_CHECK_END;
677
678     if (address == 0)
679         CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
680     else
681         CHECK(RvaToSection(InternalAddressToRva(address)) != NULL);
682
683     CHECK_OK;
684 }
685
686 CHECK PEDecoder::CheckInternalAddress(SIZE_T address, COUNT_T size, IsNullOK ok) const
687 {
688     CONTRACT_CHECK
689     {
690         INSTANCE_CHECK;
691         PRECONDITION(CheckNTHeaders());
692         NOTHROW;
693         GC_NOTRIGGER;
694     }
695     CONTRACT_CHECK_END;
696
697     if (address == 0)
698     {
699         CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
700         CHECK(size == 0);
701     }
702     else
703     {
704         CHECK(CheckRva(InternalAddressToRva(address), size));
705     }
706
707     CHECK_OK;
708 }
709
710 RVA PEDecoder::InternalAddressToRva(SIZE_T address) const
711 {
712     CONTRACT(RVA)
713     {
714         INSTANCE_CHECK;
715         PRECONDITION(CheckNTHeaders());
716         NOTHROW;
717         GC_NOTRIGGER;
718         POSTCONDITION(CheckRva(RETVAL));
719     }
720     CONTRACT_END;
721
722     if (m_flags & FLAG_RELOCATED)
723     {
724         // Address has been fixed up
725         RETURN (RVA) ((BYTE *) address - (BYTE *) m_base);
726     }
727     else
728     {
729         // Address has not been fixed up
730         RETURN (RVA) (address - (SIZE_T) GetPreferredBase());
731     }
732 }
733
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
737 {
738     CONTRACT(IMAGE_SECTION_HEADER *)
739     {
740         INSTANCE_CHECK;
741         PRECONDITION(CheckNTHeaders());
742         PRECONDITION(sectionName != NULL);
743         NOTHROW;
744         GC_NOTRIGGER;
745         CANNOT_TAKE_LOCK;
746         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
747     }
748     CONTRACT_END;
749
750     // Ensure that the section name length is valid
751     SIZE_T iSectionNameLength = strlen(sectionName);
752     if ((iSectionNameLength < 1) || (iSectionNameLength > IMAGE_SIZEOF_SHORT_NAME))
753     {
754         _ASSERTE(!"Invalid section name!");
755         RETURN NULL;
756     }
757
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);
763
764     BOOL fFoundSection = FALSE;
765
766     // Loop thru the sections and see if we got the section we are interested in
767     while (pSection < pSectionEnd)
768     {
769         // Is this the section we are looking for?
770         if (strncmp(sectionName, (char*)pSection->Name, iSectionNameLength) == 0)
771         {
772             // We found our section - break out of the loop
773             fFoundSection = TRUE;
774             break;
775         }
776
777         // Move to the next section
778         pSection++;
779      }
780
781     if (TRUE == fFoundSection)
782         RETURN pSection;
783     else
784         RETURN NULL;
785 }
786
787 IMAGE_SECTION_HEADER *PEDecoder::RvaToSection(RVA rva) const
788 {
789     CONTRACT(IMAGE_SECTION_HEADER *)
790     {
791         INSTANCE_CHECK;
792         NOTHROW;
793         GC_NOTRIGGER;
794         CANNOT_TAKE_LOCK;
795         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
796         SUPPORTS_DAC;
797     }
798     CONTRACT_END;
799
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);
802
803     while (section < sectionEnd)
804     {
805         if (rva < (VAL32(section->VirtualAddress)
806                    + AlignUp((UINT)VAL32(section->Misc.VirtualSize), (UINT)VAL32(FindNTHeaders()->OptionalHeader.SectionAlignment))))
807         {
808             if (rva < VAL32(section->VirtualAddress))
809                 RETURN NULL;
810             else
811             {
812                 RETURN section;
813             }
814         }
815
816         section++;
817     }
818
819     RETURN NULL;
820 }
821
822 IMAGE_SECTION_HEADER *PEDecoder::OffsetToSection(COUNT_T fileOffset) const
823 {
824     CONTRACT(IMAGE_SECTION_HEADER *)
825     {
826         INSTANCE_CHECK;
827         PRECONDITION(CheckNTHeaders());
828         NOTHROW;
829         GC_NOTRIGGER;
830         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
831         SUPPORTS_DAC;
832     }
833     CONTRACT_END;
834
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);
837
838     while (section < sectionEnd)
839     {
840         if (fileOffset < section->PointerToRawData + section->SizeOfRawData)
841         {
842             if (fileOffset < section->PointerToRawData)
843                 RETURN NULL;
844             else
845                 RETURN section;
846         }
847
848         section++;
849     }
850
851     RETURN NULL;
852 }
853
854 TADDR PEDecoder::GetRvaData(RVA rva, IsNullOK ok /*= NULL_NOT_OK*/) const
855 {
856     CONTRACT(TADDR)
857     {
858         INSTANCE_CHECK;
859         PRECONDITION(CheckNTHeaders());
860         PRECONDITION(CheckRva(rva, NULL_OK));
861         NOTHROW;
862         GC_NOTRIGGER;
863         CANNOT_TAKE_LOCK;
864         SUPPORTS_DAC;
865     }
866     CONTRACT_END;
867
868     if ((rva == 0)&&(ok == NULL_NOT_OK))
869         RETURN NULL;
870
871     RVA offset;
872     if (IsMapped())
873         offset = rva;
874     else
875     {
876         // !!! check for case where rva is in padded portion of segment
877         offset = RvaToOffset(rva);
878     }
879
880     RETURN( m_base + offset );
881 }
882
883 RVA PEDecoder::GetDataRva(const TADDR data) const
884 {
885     CONTRACT(RVA)
886     {
887         INSTANCE_CHECK;
888         PRECONDITION(CheckNTHeaders());
889         PRECONDITION(CheckData((void *)data, NULL_OK));
890         NOTHROW;
891         GC_NOTRIGGER;
892         SUPPORTS_DAC;
893     }
894     CONTRACT_END;
895
896     if (data == NULL)
897         RETURN 0;
898
899     COUNT_T offset = (COUNT_T) (data - m_base);
900     if (IsMapped())
901         RETURN offset;
902     else
903         RETURN OffsetToRva(offset);
904 }
905
906 BOOL PEDecoder::PointerInPE(PTR_CVOID data) const
907 {
908     CONTRACTL
909     {
910         INSTANCE_CHECK;
911         NOTHROW;
912         GC_NOTRIGGER;
913         FORBID_FAULT;
914         SUPPORTS_DAC;
915     }
916     CONTRACTL_END;
917
918     TADDR taddrData = dac_cast<TADDR>(data);
919     TADDR taddrBase = dac_cast<TADDR>(m_base);
920
921     if (this->IsMapped())
922     {
923         return taddrBase <= taddrData  && taddrData  < taddrBase + GetVirtualSize();
924     }
925     else
926     {
927         return taddrBase <= taddrData  && taddrData < taddrBase + GetSize();
928     }
929 }
930
931 TADDR PEDecoder::GetOffsetData(COUNT_T fileOffset, IsNullOK ok /*= NULL_NOT_OK*/) const
932 {
933     CONTRACT(TADDR)
934     {
935         INSTANCE_CHECK;
936         PRECONDITION(CheckNTHeaders());
937         PRECONDITION(CheckOffset(fileOffset, NULL_OK));
938         NOTHROW;
939         GC_NOTRIGGER;
940     }
941     CONTRACT_END;
942
943     if ((fileOffset == 0)&&(ok == NULL_NOT_OK))
944         RETURN NULL;
945
946     RETURN GetRvaData(OffsetToRva(fileOffset));
947 }
948
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
954 {
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
960 };
961 typedef STORAGESIGNATURE UNALIGNED * PSTORAGESIGNATURE;
962 typedef DPTR(STORAGESIGNATURE UNALIGNED) PTR_STORAGESIGNATURE;
963
964
965 struct STORAGEHEADER
966 {
967     BYTE        fFlags;                 // STGHDR_xxx flags.
968     BYTE        pad;
969     USHORT      iStreams;               // How many streams are there.
970 };
971 typedef STORAGEHEADER UNALIGNED * PSTORAGEHEADER;
972 typedef DPTR(STORAGEHEADER UNALIGNED) PTR_STORAGEHEADER;
973
974
975 struct STORAGESTREAM
976 {
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.
980 };
981 typedef STORAGESTREAM UNALIGNED * PSTORAGESTREAM;
982 typedef DPTR(STORAGESTREAM UNALIGNED) PTR_STORAGESTREAM;
983
984
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)
989 {
990     CONTRACTL
991     {
992         NOTHROW;
993         GC_NOTRIGGER;
994         CANNOT_TAKE_LOCK;
995     }
996     CONTRACTL_END;
997
998     SUPPORTS_DAC;
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);
1002 }
1003 //-------------------------------------------------------------------------------
1004
1005
1006 CHECK PEDecoder::CheckCorHeader() const
1007 {
1008     CONTRACT_CHECK
1009     {
1010         INSTANCE_CHECK;
1011         NOTHROW;
1012         GC_NOTRIGGER;
1013         SUPPORTS_DAC;
1014     }
1015     CONTRACT_CHECK_END;
1016
1017     if (m_flags & FLAG_COR_CHECKED)
1018         CHECK_OK;
1019
1020     CHECK(CheckNTHeaders());
1021
1022     CHECK(HasCorHeader());
1023
1024     IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_COMHEADER);
1025
1026     CHECK(CheckDirectory(pDir, IMAGE_SCN_MEM_WRITE, NULL_NOT_OK));
1027
1028     CHECK(VAL32(pDir->Size) >= sizeof(IMAGE_COR20_HEADER));
1029
1030     IMAGE_SECTION_HEADER *section = RvaToSection(VAL32(pDir->VirtualAddress));
1031     CHECK(section != NULL);
1032     CHECK((section->Characteristics & VAL32(IMAGE_SCN_MEM_READ))!=0);
1033
1034     CHECK(CheckRva(VAL32(pDir->VirtualAddress), sizeof(IMAGE_COR20_HEADER)));
1035
1036     IMAGE_COR20_HEADER *pCor = GetCorHeader();
1037
1038     //CHECK(((ULONGLONG)pCor & 0x3)==0);
1039
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);
1044
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));
1052
1053     CHECK(VAL32(pCor->cb) >= offsetof(IMAGE_COR20_HEADER, ManagedNativeHeader) + sizeof(IMAGE_DATA_DIRECTORY));
1054
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;
1062
1063     CHECK((pCor->Flags&VAL32(~validBits)) == 0);
1064
1065     // Pure IL images should not have VTable fixups or EAT jumps
1066     if (IsILOnly())
1067     {
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
1072     }
1073     else
1074     {
1075         if (pCor->Flags & VAL32(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT))
1076         {
1077             CHECK(CheckRva(VAL32(IMAGE_COR20_HEADER_FIELD(*pCor,EntryPointToken))));
1078         }
1079     }
1080
1081     // Strong name signed images should have a signature
1082     if (IsStrongNameSigned())
1083         CHECK(HasStrongNameSignature());
1084
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)
1088     {
1089         CHECK(VAL32(pCor->ManagedNativeHeader.Size) == 0);
1090     }
1091
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);
1096
1097     if(pcMD != NULL)
1098     {
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
1103
1104
1105         CHECK(VAL32(pStorageSig->lSignature) == STORAGE_MAGIC_SIG);
1106         COUNT_T ctSSig;
1107         CHECK(ClrSafeInt<COUNT_T>::addition(sizeof(STORAGESIGNATURE), (COUNT_T)VAL32(pStorageSig->iVersionString), ctSSig));
1108         CHECK(ctMD > ctSSig);
1109
1110         // Storage header checks
1111         pcMD += ctSSig;
1112
1113         PTR_STORAGEHEADER pSHdr = PTR_STORAGEHEADER((TADDR)pcMD);
1114
1115
1116         ctMD -= ctSSig;
1117         CHECK(ctMD >= sizeof(STORAGEHEADER));
1118         pcMD = dac_cast<TADDR>(pSHdr) + sizeof(STORAGEHEADER);
1119         ctMD -= sizeof(STORAGEHEADER);
1120         WORD nStreams = VAL16(pSHdr->iStreams);
1121
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));
1126         size_t namelen;
1127         WORD iStr;
1128         PTR_STORAGESTREAM pSS;
1129         for(iStr = 1, pSS = pStr; iStr <= nStreams; iStr++)
1130         {
1131             CHECK(pSS < pSSOutOfRange);
1132             CHECK(pSS + 1 <= pSSOutOfRange);
1133
1134             for(namelen=0; (namelen<32)&&(pSS->rcName[namelen]!=0); namelen++);
1135             CHECK((0 < namelen)&&(namelen < 32));
1136
1137             // Is it ngen image?
1138             if (!HasNativeHeader())
1139             {
1140                 // Forbid HOT_MODEL_STREAM for non-ngen images
1141                 CHECK(strcmp(pSS->rcName, HOT_MODEL_STREAM_A) != 0);
1142             }
1143
1144             pcMD = dac_cast<TADDR>(NextStorageStream(pSS));
1145             ctMD -= (COUNT_T)(pcMD - dac_cast<TADDR>(pSS));
1146
1147             pSS = PTR_STORAGESTREAM((TADDR)pcMD);
1148         }
1149
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))
1156         {
1157             ctSSbegin = (COUNT_T)VAL32(pSS->iOffset);
1158             CHECK(ctStreamsBegin <= ctSSbegin);
1159             CHECK(ctSSbegin < ctMDStreamSize);
1160
1161             ctSS = (COUNT_T)VAL32(pSS->iSize);
1162             CHECK(ctMD >= ctSS);
1163             CHECK(ClrSafeInt<COUNT_T>::addition(ctSSbegin, ctSS, ctSSend));
1164             CHECK(ctSSend <= ctMDStreamSize);
1165             ctMD -= ctSS;
1166
1167             // Check stream overlap
1168             PTR_STORAGESTREAM pSSprior;
1169             for(pSSprior=pStr; pSSprior < pSS; pSSprior = NextStorageStream(pSSprior))
1170             {
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)));
1174             }
1175         }
1176     }  //end if(pcMD != NULL)
1177
1178     const_cast<PEDecoder *>(this)->m_flags |= FLAG_COR_CHECKED;
1179
1180     CHECK_OK;
1181 }
1182
1183
1184
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
1190 {
1191     CONTRACT(IMAGE_DATA_DIRECTORY *)
1192     {
1193         INSTANCE_CHECK;
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
1201         NOTHROW;
1202         GC_NOTRIGGER;
1203         SUPPORTS_DAC;
1204     }
1205     CONTRACT_END;
1206
1207     IMAGE_DATA_DIRECTORY *pDirRet = &GetCorHeader()->MetaData;
1208
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);
1226
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));
1235
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())
1239     {
1240
1241         if (type == METADATA_SECTION_MANIFEST)
1242             pDirRet = &GetNativeHeader()->ManifestMetaData;
1243
1244
1245     }
1246
1247 #endif // FEATURE_PREJIT
1248
1249     RETURN pDirRet;
1250 }
1251
1252 PTR_CVOID PEDecoder::GetMetadata(COUNT_T *pSize) const
1253 {
1254     CONTRACT(PTR_CVOID)
1255     {
1256         INSTANCE_CHECK;
1257         PRECONDITION(CheckCorHeader());
1258         PRECONDITION(CheckPointer(pSize, NULL_OK));
1259         NOTHROW;
1260         GC_NOTRIGGER;
1261         SUPPORTS_DAC;
1262     }
1263     CONTRACT_END;
1264
1265     IMAGE_DATA_DIRECTORY *pDir = GetMetaDataHelper(METADATA_SECTION_FULL);
1266
1267     if (pSize != NULL)
1268         *pSize = VAL32(pDir->Size);
1269
1270     RETURN dac_cast<PTR_VOID>(GetDirectoryData(pDir));
1271 }
1272
1273 const void *PEDecoder::GetResources(COUNT_T *pSize) const
1274 {
1275     CONTRACT(const void *)
1276     {
1277         INSTANCE_CHECK;
1278         PRECONDITION(CheckCorHeader());
1279         PRECONDITION(CheckPointer(pSize, NULL_OK));
1280         NOTHROW;
1281         GC_NOTRIGGER;
1282     }
1283     CONTRACT_END;
1284
1285     IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->Resources;
1286
1287     if (pSize != NULL)
1288         *pSize = VAL32(pDir->Size);
1289
1290     RETURN (void *)GetDirectoryData(pDir);
1291 }
1292
1293 CHECK PEDecoder::CheckResource(COUNT_T offset) const
1294 {
1295     CONTRACT_CHECK
1296     {
1297         INSTANCE_CHECK;
1298         NOTHROW;
1299         GC_NOTRIGGER;
1300         PRECONDITION(CheckCorHeader());
1301     }
1302     CONTRACT_CHECK_END;
1303
1304     IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->Resources;
1305
1306     CHECK(CheckOverflow(VAL32(pDir->VirtualAddress), offset));
1307
1308     RVA rva = VAL32(pDir->VirtualAddress) + offset;
1309
1310     // Make sure we have at least enough data for a length
1311     CHECK(CheckRva(rva, sizeof(DWORD)));
1312
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))));
1316
1317     CHECK_OK;
1318 }
1319
1320 const void *PEDecoder::GetResource(COUNT_T offset, COUNT_T *pSize) const
1321 {
1322     CONTRACT(const void *)
1323     {
1324         INSTANCE_CHECK;
1325         PRECONDITION(CheckCorHeader());
1326         PRECONDITION(CheckPointer(pSize, NULL_OK));
1327         NOTHROW;
1328         GC_NOTRIGGER;
1329     }
1330     CONTRACT_END;
1331
1332     IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->Resources;
1333
1334     // 403571: Prefix complained correctly about need to always perform rva check
1335     if (CheckResource(offset) == FALSE)
1336         return NULL;
1337
1338     void * resourceBlob = (void *)GetRvaData(VAL32(pDir->VirtualAddress) + offset);
1339     // Holds if CheckResource(offset) == TRUE
1340     PREFIX_ASSUME(resourceBlob != NULL);
1341
1342      if (pSize != NULL)
1343         *pSize = GET_UNALIGNED_VAL32(resourceBlob);
1344
1345     RETURN (const void *) ((BYTE*)resourceBlob+sizeof(DWORD));
1346 }
1347
1348 BOOL PEDecoder::HasManagedEntryPoint() const
1349 {
1350     CONTRACTL {
1351         INSTANCE_CHECK;
1352         PRECONDITION(CheckCorHeader());
1353         NOTHROW;
1354         GC_NOTRIGGER;
1355     } CONTRACTL_END;
1356
1357     ULONG flags = GetCorHeader()->Flags;
1358     return (!(flags & VAL32(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT)) &&
1359             (!IsNilToken(GetEntryPointToken())));
1360 }
1361
1362 ULONG PEDecoder::GetEntryPointToken() const
1363 {
1364     CONTRACT(ULONG)
1365     {
1366         INSTANCE_CHECK;
1367         PRECONDITION(CheckCorHeader());
1368         NOTHROW;
1369         GC_NOTRIGGER;
1370     }
1371     CONTRACT_END;
1372
1373     RETURN VAL32(IMAGE_COR20_HEADER_FIELD(*GetCorHeader(), EntryPointToken));
1374 }
1375
1376 IMAGE_COR_VTABLEFIXUP *PEDecoder::GetVTableFixups(COUNT_T *pCount) const
1377 {
1378     CONTRACT(IMAGE_COR_VTABLEFIXUP *)
1379     {
1380         INSTANCE_CHECK;
1381         PRECONDITION(CheckCorHeader());
1382         NOTHROW;
1383         GC_NOTRIGGER;
1384     }
1385     CONTRACT_END;
1386     IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->VTableFixups;
1387
1388     if (pCount != NULL)
1389         *pCount = VAL32(pDir->Size)/sizeof(IMAGE_COR_VTABLEFIXUP);
1390
1391     RETURN PTR_IMAGE_COR_VTABLEFIXUP(GetDirectoryData(pDir));
1392 }
1393
1394 CHECK PEDecoder::CheckILOnly() const
1395 {
1396     CONTRACT_CHECK
1397     {
1398         INSTANCE_CHECK;
1399         NOTHROW;
1400         GC_NOTRIGGER;
1401     }
1402     CONTRACT_CHECK_END;
1403
1404     if (m_flags & FLAG_IL_ONLY_CHECKED)
1405         CHECK_OK;
1406
1407     CHECK(CheckCorHeader());
1408
1409     if (HasReadyToRunHeader())
1410     {
1411         // Pretend R2R images are IL-only 
1412         const_cast<PEDecoder *>(this)->m_flags |= FLAG_IL_ONLY_CHECKED;
1413         CHECK_OK;
1414     }
1415
1416     // Allow only verifiable directories.
1417
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)));
1426
1427
1428
1429
1430     for (UINT32 entry=0; entry<GetNumberOfRvaAndSizes(); ++entry)
1431     {
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));
1437         else
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));
1442
1443         if (HasDirectoryEntry(entry))
1444         {
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));
1448         }
1449     }
1450     if (HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT) ||
1451         HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC) ||
1452         FindNTHeaders()->OptionalHeader.AddressOfEntryPoint != 0)
1453     {
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)))
1457         {
1458             CHECK(CheckILOnlyImportDlls());
1459             CHECK(CheckILOnlyBaseRelocations());
1460         }
1461
1462 #ifdef _TARGET_X86_
1463         if (!IsMapped())
1464         {
1465             CHECK(CheckILOnlyEntryPoint());
1466         }
1467 #endif
1468     }
1469
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)
1475     {
1476         // Don't allow shared sections for IL-only images
1477         CHECK(!(section->Characteristics & IMAGE_SCN_MEM_SHARED));
1478
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);
1483         section++;
1484     }
1485
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
1488     //  OS version.
1489     if (!IsDll())
1490     {
1491         CHECK(GetWin32VersionValue() == 0);
1492     }
1493
1494
1495     const_cast<PEDecoder *>(this)->m_flags |= FLAG_IL_ONLY_CHECKED;
1496
1497     CHECK_OK;
1498 }
1499
1500
1501 CHECK PEDecoder::CheckILOnlyImportDlls() const
1502 {
1503     CONTRACT_CHECK
1504     {
1505         INSTANCE_CHECK;
1506         PRECONDITION(CheckNTHeaders());
1507         NOTHROW;
1508         GC_NOTRIGGER;
1509     }
1510     CONTRACT_CHECK_END;
1511
1512     // The only allowed DLL Imports are MscorEE.dll:_CorExeMain,_CorDllMain
1513
1514 #ifdef _WIN64
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))
1518         CHECK_OK;
1519 #endif
1520
1521     CHECK(HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT));
1522     CHECK(CheckDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_SCN_MEM_WRITE));
1523
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);
1528
1529     // There should be space for 2 entries. (mscoree and NULL)
1530     CHECK(VAL32(pDirEntryImport->Size) >= (2 * sizeof(IMAGE_IMPORT_DESCRIPTOR)));
1531
1532     // Get the import data
1533     PIMAGE_IMPORT_DESCRIPTOR pID = (PIMAGE_IMPORT_DESCRIPTOR) GetDirectoryData(pDirEntryImport);
1534     CHECK(pID != NULL);
1535     PREFIX_ASSUME(pID != NULL);
1536
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))
1541         && pID[0].Name != 0
1542         && pID[0].FirstThunk != 0);
1543
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
1548         && pID[1].Name == 0
1549         && pID[1].FirstThunk == 0);
1550
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")));
1554
1555     // Make sure the name is equal to mscoree
1556     CHECK(SString::_stricmp( (char *)GetRvaData(nameRVA), "mscoree.dll") == 0);
1557
1558     // Check the Hint/Name table.
1559     CHECK(CheckILOnlyImportByNameTable(VAL32(IMAGE_IMPORT_DESC_FIELD(pID[0], OriginalFirstThunk))));
1560
1561     // The IAT needs to be checked only for size.
1562     CHECK(CheckRva(VAL32(pID[0].FirstThunk), 2*sizeof(UINT32)));
1563
1564     CHECK_OK;
1565 }
1566
1567 CHECK PEDecoder::CheckILOnlyImportByNameTable(RVA rva) const
1568 {
1569     CONTRACT_CHECK
1570     {
1571         INSTANCE_CHECK;
1572         PRECONDITION(CheckNTHeaders());
1573         NOTHROW;
1574         GC_NOTRIGGER;
1575     }
1576     CONTRACT_CHECK_END;
1577
1578     // Check if we have enough space to hold 2 DWORDS
1579     CHECK(CheckRva(rva, 2*sizeof(UINT32)));
1580
1581     UINT32 UNALIGNED *pImportArray = (UINT32 UNALIGNED *) GetRvaData(rva);
1582
1583     CHECK(GET_UNALIGNED_VAL32(&pImportArray[0]) != 0);
1584     CHECK(GET_UNALIGNED_VAL32(&pImportArray[1]) == 0);
1585
1586     UINT32 importRVA = GET_UNALIGNED_VAL32(&pImportArray[0]);
1587
1588     // First bit Set implies Ordinal lookup
1589     CHECK((importRVA & 0x80000000) == 0);
1590
1591 #define DLL_NAME "_CorDllMain"
1592 #define EXE_NAME "_CorExeMain"
1593
1594     static_assert_no_msg(sizeof(DLL_NAME) == sizeof(EXE_NAME));
1595
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)));
1599
1600     IMAGE_IMPORT_BY_NAME *import = (IMAGE_IMPORT_BY_NAME*) GetRvaData(importRVA);
1601
1602     CHECK(SString::_stricmp((char *) import->Name, DLL_NAME) == 0 || _stricmp((char *) import->Name, EXE_NAME) == 0);
1603
1604     CHECK_OK;
1605 }
1606
1607 #ifdef _TARGET_X86_
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
1612 #endif
1613
1614 CHECK PEDecoder::CheckILOnlyBaseRelocations() const
1615 {
1616     CONTRACT_CHECK
1617     {
1618         INSTANCE_CHECK;
1619         PRECONDITION(CheckNTHeaders());
1620         NOTHROW;
1621         GC_NOTRIGGER;
1622     }
1623     CONTRACT_CHECK_END;
1624
1625     if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC))
1626     {
1627         // We require base relocs for dlls.
1628         CHECK(!IsDll());
1629
1630         CHECK((FindNTHeaders()->FileHeader.Characteristics & VAL16(IMAGE_FILE_RELOCS_STRIPPED)) != 0);
1631     }
1632     else
1633     {
1634         CHECK((FindNTHeaders()->FileHeader.Characteristics & VAL16(IMAGE_FILE_RELOCS_STRIPPED)) == 0);
1635
1636         CHECK(CheckDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC, IMAGE_SCN_MEM_WRITE));
1637
1638         IMAGE_DATA_DIRECTORY *pRelocDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC);
1639
1640         IMAGE_SECTION_HEADER *section = RvaToSection(VAL32(pRelocDir->VirtualAddress));
1641         CHECK(section != NULL);
1642         CHECK((section->Characteristics & VAL32(IMAGE_SCN_MEM_READ))!=0);
1643
1644         IMAGE_BASE_RELOCATION *pReloc = (IMAGE_BASE_RELOCATION *)
1645           GetRvaData(VAL32(pRelocDir->VirtualAddress));
1646
1647         // 403569: PREfix correctly complained about pReloc being possibly NULL
1648         CHECK(pReloc != NULL);
1649         CHECK(VAL32(pReloc->SizeOfBlock) == VAL32(pRelocDir->Size));
1650
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))
1654         {
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));
1658             pRelocEntry++;
1659             CHECK((VAL16(pRelocEntry[0]) & 0xF000) == (IMAGE_REL_BASED_DIR64 << 12));
1660         }
1661         else
1662         {
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));
1667             else
1668                 CHECK((VAL16(pRelocEntry[0]) & 0xF000) == (IMAGE_REL_BASED_HIGHLOW << 12));
1669         }
1670
1671         while (++pRelocEntry < pRelocEntryEnd)
1672         {
1673             // NULL padding entries are allowed
1674             CHECK((VAL16(pRelocEntry[0]) & 0xF000) == IMAGE_REL_BASED_ABSOLUTE);
1675         }
1676     }
1677
1678     CHECK_OK;
1679 }
1680
1681 #ifdef _TARGET_X86_
1682 CHECK PEDecoder::CheckILOnlyEntryPoint() const
1683 {
1684     CONTRACT_CHECK
1685     {
1686         INSTANCE_CHECK;
1687         PRECONDITION(CheckNTHeaders());
1688         NOTHROW;
1689         GC_NOTRIGGER;
1690     }
1691     CONTRACT_CHECK_END;
1692
1693     CHECK(FindNTHeaders()->OptionalHeader.AddressOfEntryPoint != 0);
1694
1695     if(FindNTHeaders()->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_I386))
1696     {
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.
1699
1700         CHECK(CheckRva(VAL32(FindNTHeaders()->OptionalHeader.AddressOfEntryPoint), JMP_SIZE));
1701
1702         BYTE *stub = (BYTE *) GetRvaData(VAL32(FindNTHeaders()->OptionalHeader.AddressOfEntryPoint));
1703
1704         static const BYTE s_DllOrExeMain[] = JMP_DWORD_PTR_DS_OPCODE;
1705
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);
1711
1712         // Verify target of jump - it should be first entry in the IAT.
1713
1714         PIMAGE_IMPORT_DESCRIPTOR pID =
1715             (PIMAGE_IMPORT_DESCRIPTOR) GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_IMPORT);
1716
1717         UINT32 va = * (UINT32 *) (stub + JMP_DWORD_PTR_DS_OPCODE_SIZE);
1718
1719         CHECK(VAL32(pID[0].FirstThunk) == (va - (SIZE_T) GetPreferredBase()));
1720     }
1721
1722     CHECK_OK;
1723 }
1724 #endif // _TARGET_X86_
1725
1726 #ifndef DACCESS_COMPILE
1727
1728 void PEDecoder::LayoutILOnly(void *base, BOOL allowFullPE) const
1729 {
1730     CONTRACT_VOID
1731     {
1732         INSTANCE_CHECK;
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()));
1739         THROWS;
1740         GC_NOTRIGGER;
1741     }
1742     CONTRACT_END;
1743
1744     // We're going to copy everything first, and write protect what we need to later.
1745
1746     // First, copy headers
1747     CopyMemory(base, (void *)m_base, VAL32(FindNTHeaders()->OptionalHeader.SizeOfHeaders));
1748
1749     // Now, copy all sections to appropriate virtual address
1750
1751     IMAGE_SECTION_HEADER *sectionStart = IMAGE_FIRST_SECTION(FindNTHeaders());
1752     IMAGE_SECTION_HEADER *sectionEnd = sectionStart + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
1753
1754     IMAGE_SECTION_HEADER *section = sectionStart;
1755     while (section < sectionEnd)
1756     {
1757         // Raw data may be less than section size if tail is zero, but may be more since VirtualSize is
1758         // not padded.
1759         DWORD size = min(VAL32(section->SizeOfRawData), VAL32(section->Misc.VirtualSize));
1760
1761         CopyMemory((BYTE *) base + VAL32(section->VirtualAddress), (BYTE *) m_base + VAL32(section->PointerToRawData), size);
1762
1763         // Note that our memory is zeroed already, so no need to initialize any tail.
1764
1765         section++;
1766     }
1767
1768     // Apply write protection to copied headers
1769     DWORD oldProtection;
1770     if (!ClrVirtualProtect((void *) base, VAL32(FindNTHeaders()->OptionalHeader.SizeOfHeaders),
1771                            PAGE_READONLY, &oldProtection))
1772         ThrowLastError();
1773
1774     // Finally, apply proper protection to copied sections
1775     section = sectionStart;
1776     while (section < sectionEnd)
1777     {
1778         // Add appropriate page protection.
1779         if ((section->Characteristics & VAL32(IMAGE_SCN_MEM_WRITE)) == 0)
1780         {
1781             if (!ClrVirtualProtect((void *) ((BYTE *)base + VAL32(section->VirtualAddress)),
1782                                    VAL32(section->Misc.VirtualSize),
1783                                    PAGE_READONLY, &oldProtection))
1784                 ThrowLastError();
1785         }
1786
1787         section++;
1788     }
1789
1790     RETURN;
1791 }
1792
1793 #endif // #ifndef DACCESS_COMPILE
1794
1795 bool ReadResourceDirectoryHeader(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, DWORD rva, IMAGE_RESOURCE_DIRECTORY_ENTRY** ppDirectoryEntries, IMAGE_RESOURCE_DIRECTORY **ppResourceDirectory)
1796 {
1797     if (!pDecoder->CheckRva(rva, sizeof(IMAGE_RESOURCE_DIRECTORY)))
1798     {
1799         return false;
1800     }
1801
1802     *ppResourceDirectory = (IMAGE_RESOURCE_DIRECTORY *)pDecoder->GetRvaData(rva);
1803
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)))
1808     {
1809         return false;
1810     }
1811
1812     *ppDirectoryEntries = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)pDecoder->GetRvaData(rva + sizeof(IMAGE_RESOURCE_DIRECTORY));
1813     return true;
1814 }
1815
1816 bool ReadNameFromResourceDirectoryEntry(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, IMAGE_RESOURCE_DIRECTORY_ENTRY* pDirectoryEntries, DWORD iEntry, DWORD *pNameUInt, WCHAR **pNameStr)
1817 {
1818     *pNameStr = NULL;
1819     *pNameUInt = 0;
1820
1821     if (!IS_INTRESOURCE(pDirectoryEntries[iEntry].Name))
1822     {
1823         DWORD entryName = pDirectoryEntries[iEntry].Name;
1824         if (!(entryName & IMAGE_RESOURCE_NAME_IS_STRING))
1825             return false;
1826         DWORD entryNameRva = (entryName & ~IMAGE_RESOURCE_NAME_IS_STRING) + rvaOfResourceSection;
1827
1828         if (!pDecoder->CheckRva(entryNameRva, sizeof(WORD)))
1829             return false;
1830
1831         size_t entryNameLen = *(WORD*)pDecoder->GetRvaData(entryNameRva);
1832         if (!pDecoder->CheckRva(entryNameRva, (COUNT_T)(sizeof(WORD) * (1 + entryNameLen))))
1833             return false;
1834         *pNameStr = new(nothrow) WCHAR[entryNameLen + 1];
1835         if ((*pNameStr) == NULL)
1836             return false;
1837         memcpy((*pNameStr), (WCHAR*)pDecoder->GetRvaData(entryNameRva + sizeof(WORD)), entryNameLen * sizeof(WCHAR));
1838         (*pNameStr)[entryNameLen] = 0;
1839     }
1840     else
1841     {
1842         DWORD name = pDirectoryEntries[iEntry].Name;
1843         if (!IS_INTRESOURCE(name))
1844             return false;
1845         
1846         *pNameUInt = name;
1847     }
1848
1849     return true;
1850 }
1851
1852 DWORD ReadResourceDirectory(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, DWORD rva, LPCWSTR name, BOOL *pisDirectory)
1853 {
1854     *pisDirectory = FALSE;
1855
1856     IMAGE_RESOURCE_DIRECTORY* pResourceDirectory;
1857     IMAGE_RESOURCE_DIRECTORY_ENTRY* pDirectoryEntries;
1858     if (!ReadResourceDirectoryHeader(pDecoder, rvaOfResourceSection, rva, &pDirectoryEntries, &pResourceDirectory))
1859     {
1860         return 0;
1861     }
1862
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;
1866
1867     for (DWORD iEntry = 0; iEntry < iEntryCount; iEntry++)
1868     {
1869         BOOL foundEntry = FALSE;
1870
1871         if (IS_INTRESOURCE(name))
1872         {
1873             // name is id
1874             if (pDirectoryEntries[iEntry].Name == (DWORD)(SIZE_T)name)
1875                 foundEntry = TRUE;
1876         }
1877         else
1878         {
1879             // name is string
1880             DWORD entryName = pDirectoryEntries[iEntry].Name;
1881             if (!(entryName & IMAGE_RESOURCE_NAME_IS_STRING))
1882                 continue;
1883             
1884             DWORD entryNameRva = (entryName & ~IMAGE_RESOURCE_NAME_IS_STRING) + rvaOfResourceSection;
1885
1886             if (!pDecoder->CheckRva(entryNameRva, sizeof(WORD)))
1887                 return 0;
1888
1889             size_t entryNameLen = *(WORD*)pDecoder->GetRvaData(entryNameRva);
1890             if (wcslen(name) != entryNameLen)
1891                 continue;
1892
1893             if (!pDecoder->CheckRva(entryNameRva, (COUNT_T)(sizeof(WORD) * (1 + entryNameLen))))
1894                 return 0;
1895             
1896             if (memcmp((WCHAR*)pDecoder->GetRvaData(entryNameRva + sizeof(WORD)), name, entryNameLen * sizeof(WCHAR)) == 0)
1897                 foundEntry = TRUE;
1898         }
1899
1900         if (!foundEntry)
1901             continue;
1902
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;
1906         return dataRva;
1907     }
1908
1909     return 0;
1910 }
1911
1912 DWORD ReadResourceDataEntry(const PEDecoder *pDecoder, DWORD rva, COUNT_T *pSize)
1913 {
1914     *pSize = 0;
1915
1916     if (!pDecoder->CheckRva(rva, sizeof(IMAGE_RESOURCE_DATA_ENTRY)))
1917     {
1918         return 0;
1919     }
1920
1921     IMAGE_RESOURCE_DATA_ENTRY *pDataEntry = (IMAGE_RESOURCE_DATA_ENTRY *)pDecoder->GetRvaData(rva);
1922     *pSize = pDataEntry->Size;
1923     return pDataEntry->OffsetToData;
1924 }
1925
1926 void * PEDecoder::GetWin32Resource(LPCWSTR lpName, LPCWSTR lpType, COUNT_T *pSize /*=NULL*/) const
1927 {
1928     CONTRACTL {
1929         INSTANCE_CHECK;
1930         PRECONDITION(IsMapped());
1931         NOTHROW;
1932         GC_NOTRIGGER;
1933     } CONTRACTL_END;
1934
1935     COUNT_T sizeUnused = 0; // Use this variable if pSize is null
1936     if (pSize == NULL)
1937         pSize = &sizeUnused;
1938
1939     *pSize = 0;
1940
1941     if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
1942         return NULL;
1943
1944     COUNT_T resourceDataSize = 0;
1945     IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
1946
1947     if (pDir->VirtualAddress == 0)
1948         return NULL;
1949
1950     BOOL isDirectory = FALSE;
1951     DWORD nameTableRva = ReadResourceDirectory(this, pDir->VirtualAddress, pDir->VirtualAddress, lpType, &isDirectory);
1952
1953     if (!isDirectory)
1954         return NULL;
1955     
1956     if (nameTableRva == 0)
1957         return NULL;
1958
1959     DWORD languageTableRva = ReadResourceDirectory(this, pDir->VirtualAddress, nameTableRva, lpName, &isDirectory);
1960     if (!isDirectory)
1961         return NULL;
1962
1963     if (languageTableRva == 0)
1964         return NULL;
1965
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)
1969
1970     DWORD resourceDataEntryRva = ReadResourceDirectory(this, pDir->VirtualAddress, languageTableRva, 0, &isDirectory);
1971     if (isDirectory) // This must not be a resource directory itself
1972         return NULL;
1973
1974     if (resourceDataEntryRva == 0)
1975         return NULL;
1976
1977     DWORD resourceDataRva = ReadResourceDataEntry(this, resourceDataEntryRva, pSize);
1978     if (!CheckRva(resourceDataRva, *pSize))
1979     {
1980         *pSize = 0;
1981         return NULL;
1982     }
1983
1984     return (void*)GetRvaData(resourceDataRva);
1985 }
1986
1987 typedef bool (*PEDecoder_EnumerateResourceTableFunction)(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context);
1988
1989 struct ResourceEnumerateNamesState
1990 {
1991     PEDecoder_ResourceNamesCallbackFunction namesCallback;
1992     PEDecoder_ResourceCallbackFunction langIDcallback;
1993     void *context;
1994     LPCWSTR nameType;
1995     LPCWSTR nameName;
1996     PEDecoder_EnumerateResourceTableFunction callbackPerName;
1997     PEDecoder_EnumerateResourceTableFunction callbackPerLangID;
1998 };
1999
2000 struct ResourceEnumerateTypesState
2001 {
2002     PEDecoder_ResourceTypesCallbackFunction callback;
2003     void *context;
2004     LPCWSTR nameType;
2005 };
2006
2007 bool EnumerateWin32ResourceTable(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, DWORD rvaOfResourceTable, PEDecoder_EnumerateResourceTableFunction resourceTableEnumerator, void *context)
2008 {
2009     IMAGE_RESOURCE_DIRECTORY* pResourceDirectory;
2010     IMAGE_RESOURCE_DIRECTORY_ENTRY* pDirectoryEntries;
2011     if (!ReadResourceDirectoryHeader(pDecoder, rvaOfResourceSection, rvaOfResourceTable, &pDirectoryEntries, &pResourceDirectory))
2012     {
2013         return false;
2014     }
2015
2016     DWORD iEntryCount = (DWORD)pResourceDirectory->NumberOfNamedEntries + (DWORD)pResourceDirectory->NumberOfIdEntries;
2017
2018     for (DWORD iEntry = 0; iEntry < iEntryCount; iEntry++)
2019     {
2020         DWORD nameUInt;
2021         NewArrayHolder<WCHAR> nameString;
2022         if (!ReadNameFromResourceDirectoryEntry(pDecoder, rvaOfResourceSection, pDirectoryEntries, iEntry, &nameUInt, &nameString))
2023             return false;
2024
2025         LPCWSTR name = MAKEINTRESOURCEW(nameUInt);
2026         if (nameString != NULL)
2027             name = &nameString[0];
2028
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;
2032
2033         if (!resourceTableEnumerator(pDecoder, rvaOfResourceSection, isDirectory, name, dataRva, context))
2034             return false;
2035     }
2036
2037     return true;
2038 }
2039
2040 bool DoesResourceNameMatch(LPCWSTR nameA, LPCWSTR nameB)
2041 {
2042     bool foundEntry = false;
2043
2044     if (IS_INTRESOURCE(nameA))
2045     {
2046         // name is id
2047         if (nameA == nameB)
2048             foundEntry = true;
2049     }
2050     else
2051     {
2052         // name is a string. 
2053
2054         // Check for name enumerated is an id. If so, it doesn't match, skip to next.
2055         if (IS_INTRESOURCE(nameB))
2056             return false;
2057         else
2058             foundEntry = !wcscmp(nameB, nameA);
2059     }
2060
2061     return foundEntry;
2062 }
2063
2064 bool EnumerateLangIDs(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
2065 {
2066     ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
2067     if (isDirectory)
2068         return false;
2069
2070     // Only LangIDs are permitted here
2071     if (!IS_INTRESOURCE(name))
2072         return false;
2073
2074     if (dataRVA == 0)
2075         return false;
2076
2077     COUNT_T cbData;
2078     DWORD resourceDataRva = ReadResourceDataEntry(pDecoder, dataRVA, &cbData);
2079     if (!pDecoder->CheckRva(resourceDataRva, cbData))
2080     {
2081         return false;
2082     }
2083
2084     BYTE *pData = (BYTE*)pDecoder->GetRvaData(resourceDataRva);
2085
2086     return state->langIDcallback(state->nameName, state->nameType, (DWORD)(uintptr_t)name, pData, cbData, state->context);
2087 }
2088
2089
2090 bool EnumerateNames(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
2091 {
2092     ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
2093     if (!isDirectory)
2094         return false;
2095
2096     state->nameName = name;
2097     return state->namesCallback(state->nameName, state->nameType, state->context);
2098 }
2099
2100 bool EnumerateNamesForLangID(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
2101 {
2102     ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
2103     if (!isDirectory)
2104         return false;
2105
2106     bool foundEntry = DoesResourceNameMatch(state->nameName, name);
2107
2108     if (foundEntry)
2109         return EnumerateWin32ResourceTable(pDecoder, rvaOfResourceSection, dataRVA, state->callbackPerLangID, context);
2110     else
2111         return true; // Keep scanning
2112 }
2113
2114
2115 bool EnumerateTypes(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
2116 {
2117     ResourceEnumerateTypesState *state = (ResourceEnumerateTypesState*)context;
2118     if (!isDirectory)
2119         return false;
2120
2121     state->nameType = name;
2122     return state->callback(name, state->context);
2123 }
2124
2125 bool EnumerateTypesForNames(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
2126 {
2127     ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
2128     if (!isDirectory)
2129         return false;
2130
2131     bool foundEntry = DoesResourceNameMatch(state->nameType, name);
2132
2133     if (foundEntry)
2134         return EnumerateWin32ResourceTable(pDecoder, rvaOfResourceSection, dataRVA, state->callbackPerName, context);
2135     else
2136         return true; // Keep scanning
2137 }
2138
2139
2140 bool PEDecoder::EnumerateWin32ResourceTypes(PEDecoder_ResourceTypesCallbackFunction callback, void* context) const
2141 {
2142     if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
2143         return true;
2144
2145     COUNT_T resourceDataSize = 0;
2146     IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
2147
2148     if (pDir->VirtualAddress == 0)
2149         return true;
2150
2151     DWORD rvaOfResourceSection = pDir->VirtualAddress;
2152
2153     ResourceEnumerateTypesState state;
2154     state.context = context;
2155     state.callback = callback;
2156
2157     return EnumerateWin32ResourceTable(this, rvaOfResourceSection, rvaOfResourceSection, EnumerateTypes, &state);
2158 }
2159
2160 bool PEDecoder::EnumerateWin32ResourceNames(LPCWSTR lpType, PEDecoder_ResourceNamesCallbackFunction callback, void* context) const
2161 {
2162     if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
2163         return true;
2164
2165     COUNT_T resourceDataSize = 0;
2166     IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
2167
2168     if (pDir->VirtualAddress == 0)
2169         return true;
2170
2171     DWORD rvaOfResourceSection = pDir->VirtualAddress;
2172
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;
2181
2182     return EnumerateWin32ResourceTable(this, rvaOfResourceSection, rvaOfResourceSection, EnumerateTypesForNames, &state);
2183 }
2184
2185 bool PEDecoder::EnumerateWin32Resources(LPCWSTR lpName, LPCWSTR lpType, PEDecoder_ResourceCallbackFunction callback, void* context) const
2186 {
2187     if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
2188         return true;
2189
2190     COUNT_T resourceDataSize = 0;
2191     IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
2192
2193     if (pDir->VirtualAddress == 0)
2194         return true;
2195
2196     DWORD rvaOfResourceSection = pDir->VirtualAddress;
2197
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;
2206
2207     return EnumerateWin32ResourceTable(this, rvaOfResourceSection, rvaOfResourceSection, EnumerateTypesForNames, &state);
2208 }
2209
2210 BOOL PEDecoder::HasNativeHeader() const
2211 {
2212     CONTRACT(BOOL)
2213     {
2214         INSTANCE_CHECK;
2215         NOTHROW;
2216         GC_NOTRIGGER;
2217         SUPPORTS_DAC;
2218     }
2219     CONTRACT_END;
2220
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());
2224 #else
2225     RETURN FALSE;
2226 #endif
2227 }
2228
2229 CHECK PEDecoder::CheckNativeHeader() const
2230 {
2231     CONTRACT_CHECK
2232     {
2233         NOTHROW;
2234         GC_NOTRIGGER;
2235         SUPPORTS_DAC;
2236     }
2237     CONTRACT_CHECK_END;
2238
2239 #ifdef FEATURE_PREJIT
2240     if (m_flags & FLAG_NATIVE_CHECKED)
2241         CHECK_OK;
2242
2243     CHECK(CheckCorHeader());
2244
2245     CHECK(HasNativeHeader());
2246
2247     IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->ManagedNativeHeader;
2248
2249     CHECK(CheckDirectory(pDir));
2250     CHECK(VAL32(pDir->Size) == sizeof(CORCOMPILE_HEADER));
2251
2252 #if 0
2253     // We want to be sure to not trigger these checks when loading a native
2254     // image in a retail build
2255
2256     // And we do not want to trigger these checks in debug builds either to avoid debug/retail behavior
2257     // differences.
2258
2259     PTR_CORCOMPILE_HEADER pHeader = PTR_CORCOMPILE_HEADER((TADDR)GetDirectoryData(pDir));
2260
2261     CHECK(CheckDirectory(&pHeader->EEInfoTable));
2262     CHECK(pHeader->EEInfoTable.Size == sizeof(CORCOMPILE_EE_INFO_TABLE));
2263
2264     CHECK(CheckDirectory(&pHeader->HelperTable, 0, NULL_OK));
2265     // @todo: verify helper table size
2266
2267     CHECK(CheckDirectory(&pHeader->ImportSections, 0, NULL_OK));
2268     // @todo verify import sections
2269
2270     CHECK(CheckDirectory(&pHeader->ImportTable, 0, NULL_OK));
2271     // @todo verify import table
2272
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));
2278
2279     CHECK(CheckDirectory(&pHeader->Dependencies, 0, NULL_OK)); // no version header for precompiled netmodules
2280     CHECK(pHeader->Dependencies.Size % sizeof(CORCOMPILE_DEPENDENCY) == 0);
2281
2282     CHECK(CheckDirectory(&pHeader->DebugMap, 0, NULL_OK));
2283     CHECK(pHeader->DebugMap.Size % sizeof(CORCOMPILE_DEBUG_RID_ENTRY) == 0);
2284
2285     // GetPersistedModuleImage()
2286     CHECK(CheckDirectory(&pHeader->ModuleImage));
2287     CHECK(pHeader->ModuleImage.Size > 0); // sizeof(Module) if we knew it here
2288
2289     CHECK(CheckDirectory(&pHeader->CodeManagerTable));
2290     CHECK(pHeader->CodeManagerTable.Size == sizeof(CORCOMPILE_CODE_MANAGER_ENTRY));
2291
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));
2296
2297     CHECK(CheckDirectory(&pHeader->ProfileDataList, 0, NULL_OK));
2298     CHECK(pHeader->ProfileDataList.Size >= sizeof(CORCOMPILE_METHOD_PROFILE_LIST)
2299           || pHeader->ProfileDataList.Size == 0);
2300
2301 #endif
2302
2303     const_cast<PEDecoder *>(this)->m_flags |= FLAG_NATIVE_CHECKED;
2304
2305 #else // FEATURE_PREJIT
2306     CHECK(false);
2307 #endif // FEATURE_PREJIT
2308
2309     CHECK_OK;
2310 }
2311
2312 READYTORUN_HEADER * PEDecoder::FindReadyToRunHeader() const
2313 {
2314     CONTRACTL
2315     {
2316         NOTHROW;
2317         GC_NOTRIGGER;
2318         SUPPORTS_DAC;
2319     }
2320     CONTRACTL_END;
2321
2322     IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->ManagedNativeHeader;
2323
2324     if (VAL32(pDir->Size) >= sizeof(READYTORUN_HEADER) && CheckDirectory(pDir))
2325     {
2326         PTR_READYTORUN_HEADER pHeader = PTR_READYTORUN_HEADER((TADDR)GetDirectoryData(pDir));
2327         if (pHeader->Signature == READYTORUN_SIGNATURE)
2328         {
2329             const_cast<PEDecoder *>(this)->m_pReadyToRunHeader = pHeader;
2330             return pHeader;
2331         }
2332     }
2333
2334     const_cast<PEDecoder *>(this)->m_flags |= FLAG_HAS_NO_READYTORUN_HEADER;
2335     return NULL;
2336 }
2337
2338 //
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.
2342 //
2343
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;
2348
2349 CHECK PEDecoder::CheckILMethod(RVA rva)
2350 {
2351     CONTRACT_CHECK
2352     {
2353         INSTANCE_CHECK;
2354         NOTHROW;
2355         GC_NOTRIGGER;
2356     }
2357     CONTRACT_CHECK_END;
2358
2359     //
2360     // Incrementaly validate that the entire IL method body is within the bounds of the image
2361     //
2362
2363     // We need to have at least the tiny header
2364     CHECK(CheckRva(rva, sizeof(IMAGE_COR_ILMETHOD_TINY)));
2365
2366     TADDR pIL = GetRvaData(rva);
2367
2368     PTR_COR_ILMETHOD_TINY pMethodTiny = PTR_COR_ILMETHOD_TINY(pIL);
2369
2370     if (pMethodTiny->IsTiny())
2371     {
2372         // Tiny header has no optional sections - we are done.
2373         CHECK(CheckRva(rva, sizeof(IMAGE_COR_ILMETHOD_TINY) + pMethodTiny->GetCodeSize()));
2374         CHECK_OK;
2375     }
2376
2377     //
2378     // Fat header
2379     //
2380
2381     CHECK(CheckRva(rva, sizeof(IMAGE_COR_ILMETHOD_FAT)));
2382
2383     PTR_COR_ILMETHOD_FAT pMethodFat = PTR_COR_ILMETHOD_FAT(pIL);
2384
2385     CHECK(pMethodFat->IsFat());
2386
2387     S_UINT32 codeEnd = S_UINT32(4) * S_UINT32(pMethodFat->GetSize()) + S_UINT32(pMethodFat->GetCodeSize());
2388     CHECK(!codeEnd.IsOverflow());
2389
2390     // Check minimal size of the header
2391     CHECK(pMethodFat->GetSize() >= (sizeof(COR_ILMETHOD_FAT) / 4));
2392
2393     CHECK(CheckRva(rva, codeEnd.Value()));
2394
2395     if (!pMethodFat->More())
2396     {
2397         CHECK_OK;
2398     }
2399
2400     // DACized copy of code:COR_ILMETHOD_FAT::GetSect
2401     TADDR pSect = AlignUp(pIL + codeEnd.Value(), 4);
2402
2403     //
2404     // Optional sections following the code
2405     //
2406
2407     for (;;)
2408     {
2409         CHECK(CheckRva(rva, UINT32(pSect - pIL) + sizeof(IMAGE_COR_ILMETHOD_SECT_SMALL)));
2410
2411         PTR_COR_ILMETHOD_SECT_SMALL pSectSmall = PTR_COR_ILMETHOD_SECT_SMALL(pSect);
2412
2413         UINT32 sectSize;
2414
2415         if (pSectSmall->IsSmall())
2416         {
2417             sectSize = pSectSmall->DataSize;
2418
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));
2422         }
2423         else
2424         {
2425             CHECK(CheckRva(rva, UINT32(pSect - pIL) + sizeof(IMAGE_COR_ILMETHOD_SECT_FAT)));
2426
2427             PTR_COR_ILMETHOD_SECT_FAT pSectFat = PTR_COR_ILMETHOD_SECT_FAT(pSect);
2428
2429             sectSize = pSectFat->GetDataSize();
2430
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));
2434         }
2435
2436         // Section has to be non-empty to avoid infinite loop below
2437         CHECK(sectSize > 0);
2438
2439         S_UINT32 sectEnd = S_UINT32(UINT32(pSect - pIL)) + S_UINT32(sectSize);
2440         CHECK(!sectEnd.IsOverflow());
2441
2442         CHECK(CheckRva(rva, sectEnd.Value()));
2443
2444         if (!pSectSmall->More())
2445         {
2446             CHECK_OK;
2447         }
2448
2449         // DACized copy of code:COR_ILMETHOD_FAT::Next
2450         pSect = AlignUp(pIL + sectEnd.Value(), 4);
2451     }
2452 }
2453
2454 //
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.
2457 //
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
2460 // are in sync.
2461 //
2462
2463 SIZE_T PEDecoder::ComputeILMethodSize(TADDR pIL)
2464 {
2465     CONTRACTL {
2466         NOTHROW;
2467         GC_NOTRIGGER;
2468         SUPPORTS_DAC;
2469     } CONTRACTL_END;
2470
2471     //
2472     // Mirror flow of code:PEDecoder::CheckILMethod, except for the range checks
2473     //
2474
2475     PTR_COR_ILMETHOD_TINY pMethodTiny = PTR_COR_ILMETHOD_TINY(pIL);
2476
2477     if (pMethodTiny->IsTiny())
2478     {
2479         return sizeof(IMAGE_COR_ILMETHOD_TINY) + pMethodTiny->GetCodeSize();
2480     }
2481
2482     PTR_COR_ILMETHOD_FAT pMethodFat = PTR_COR_ILMETHOD_FAT(pIL);
2483
2484     UINT32 codeEnd = 4 * pMethodFat->GetSize() + pMethodFat->GetCodeSize();
2485
2486     if (!pMethodFat->More())
2487     {
2488         return codeEnd;
2489     }
2490
2491     // DACized copy of code:COR_ILMETHOD_FAT::GetSect
2492     TADDR pSect = AlignUp(pIL + codeEnd, 4);
2493
2494     for (;;)
2495     {
2496         PTR_COR_ILMETHOD_SECT_SMALL pSectSmall = PTR_COR_ILMETHOD_SECT_SMALL(pSect);
2497
2498         UINT32 sectSize;
2499
2500         if (pSectSmall->IsSmall())
2501         {
2502             sectSize = pSectSmall->DataSize;
2503
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));
2507         }
2508         else
2509         {
2510             PTR_COR_ILMETHOD_SECT_FAT pSectFat = PTR_COR_ILMETHOD_SECT_FAT(pSect);
2511
2512             sectSize = pSectFat->GetDataSize();
2513
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));
2517         }
2518
2519         UINT32 sectEnd = UINT32(pSect - pIL) + sectSize;
2520
2521         if (!pSectSmall->More() || (sectSize == 0))
2522         {
2523             return sectEnd;
2524         }
2525
2526         // DACized copy of code:COR_ILMETHOD_FAT::Next
2527         pSect = AlignUp(pIL + sectEnd, 4);
2528     }
2529 }
2530
2531 //
2532 // GetDebugDirectoryEntry - return the debug directory entry at the specified index
2533 //
2534 // Arguments:
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.
2537 //
2538 // Return value:
2539 //   A pointer to the IMAGE_DEBUG_DIRECTORY in the PE file for the specified index,
2540 //   or NULL if it doesn't exist.
2541 //
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).
2545 //
2546 PTR_IMAGE_DEBUG_DIRECTORY PEDecoder::GetDebugDirectoryEntry(UINT index) const
2547 {
2548     CONTRACT(PTR_IMAGE_DEBUG_DIRECTORY)
2549     {
2550         INSTANCE_CHECK;
2551         PRECONDITION(CheckNTHeaders());
2552         NOTHROW;
2553         GC_NOTRIGGER;
2554         SUPPORTS_DAC;
2555     }
2556     CONTRACT_END;
2557
2558     if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG))
2559     {
2560         RETURN NULL;
2561     }
2562
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.
2566     COUNT_T cbDebugDir;
2567     TADDR taDebugDir = GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_DEBUG, &cbDebugDir);
2568
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 /
2572     // fuzzed PE files.
2573     UINT cNumEntries = cbDebugDir / sizeof(IMAGE_DEBUG_DIRECTORY);
2574     if (index >= cNumEntries)
2575     {
2576         RETURN NULL;    // index out of range
2577     }
2578
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
2582     RETURN pDebugEntry;
2583 }
2584
2585
2586 #ifdef FEATURE_PREJIT
2587
2588 CORCOMPILE_EE_INFO_TABLE *PEDecoder::GetNativeEEInfoTable() const
2589 {
2590     CONTRACT(CORCOMPILE_EE_INFO_TABLE *)
2591     {
2592         PRECONDITION(CheckNativeHeader());
2593         NOTHROW;
2594         GC_NOTRIGGER;
2595         POSTCONDITION(CheckPointer(RETVAL));
2596     }
2597     CONTRACT_END;
2598
2599     IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->EEInfoTable;
2600
2601     // 403523: PREFIX correctly complained here. Fixed GetDirectoryData.
2602     RETURN PTR_CORCOMPILE_EE_INFO_TABLE(GetDirectoryData(pDir));
2603 }
2604
2605
2606 void *PEDecoder::GetNativeHelperTable(COUNT_T *pSize) const
2607 {
2608     CONTRACT(void *)
2609     {
2610         PRECONDITION(CheckNativeHeader());
2611         NOTHROW;
2612         GC_NOTRIGGER;
2613     }
2614     CONTRACT_END;
2615
2616     IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->HelperTable;
2617
2618     if (pSize != NULL)
2619         *pSize = VAL32(pDir->Size);
2620
2621     RETURN (void *)GetDirectoryData(pDir);
2622 }
2623
2624 CORCOMPILE_VERSION_INFO *PEDecoder::GetNativeVersionInfoMaybeNull(bool skipCheckNativeHeader) const
2625 {
2626     CONTRACT(CORCOMPILE_VERSION_INFO *)
2627     {
2628         PRECONDITION(skipCheckNativeHeader || CheckNativeHeader());
2629         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2630         NOTHROW;
2631         GC_NOTRIGGER;
2632         SUPPORTS_DAC;
2633     }
2634     CONTRACT_END;
2635
2636     IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->VersionInfo;
2637
2638     RETURN PTR_CORCOMPILE_VERSION_INFO(GetDirectoryData(pDir));
2639 }
2640
2641 CORCOMPILE_VERSION_INFO *PEDecoder::GetNativeVersionInfo() const
2642 {
2643     CONTRACT(CORCOMPILE_VERSION_INFO *)
2644     {
2645         POSTCONDITION(CheckPointer(RETVAL));
2646         NOTHROW;
2647         GC_NOTRIGGER;
2648         SUPPORTS_DAC;
2649     }
2650     CONTRACT_END;
2651
2652     RETURN GetNativeVersionInfoMaybeNull();
2653 }
2654
2655 BOOL PEDecoder::HasNativeDebugMap() const
2656 {
2657     CONTRACT(BOOL)
2658     {
2659         PRECONDITION(CheckNativeHeader());
2660         INSTANCE_CHECK;
2661         NOTHROW;
2662         GC_NOTRIGGER;
2663         SUPPORTS_DAC;
2664     }
2665     CONTRACT_END;
2666
2667     // 403522: Prefix complained correctly here.
2668     CORCOMPILE_HEADER *pNativeHeader = GetNativeHeader();
2669     if (!pNativeHeader)
2670         RETURN FALSE;
2671     else
2672         RETURN (VAL32(pNativeHeader->DebugMap.VirtualAddress) != 0);
2673 }
2674
2675 TADDR PEDecoder::GetNativeDebugMap(COUNT_T *pSize) const
2676 {
2677     CONTRACT(TADDR)
2678     {
2679         PRECONDITION(CheckNativeHeader());
2680         PRECONDITION(CheckPointer(pSize, NULL_OK));
2681         NOTHROW;
2682         GC_NOTRIGGER;
2683         SUPPORTS_DAC;
2684     }
2685     CONTRACT_END;
2686
2687     IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->DebugMap;
2688
2689     if (pSize != NULL)
2690         *pSize = VAL32(pDir->Size);
2691
2692     RETURN (GetDirectoryData(pDir));
2693 }
2694
2695 Module *PEDecoder::GetPersistedModuleImage(COUNT_T *pSize) const
2696 {
2697     CONTRACT(Module *)
2698     {
2699         PRECONDITION(CheckNativeHeader());
2700         PRECONDITION(CheckPointer(pSize, NULL_OK));
2701         POSTCONDITION(CheckPointer(RETVAL));
2702         NOTHROW;
2703         GC_NOTRIGGER;
2704     }
2705     CONTRACT_END;
2706
2707     IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->ModuleImage;
2708
2709     if (pSize != NULL)
2710         *pSize = VAL32(pDir->Size);
2711
2712     RETURN (Module *) GetDirectoryData(pDir);
2713 }
2714
2715 CHECK PEDecoder::CheckNativeHeaderVersion() const
2716 {
2717     CONTRACT_CHECK
2718     {
2719         PRECONDITION(CheckNativeHeader());
2720         NOTHROW;
2721         GC_NOTRIGGER;
2722     }
2723     CONTRACT_CHECK_END;
2724
2725     IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->ManagedNativeHeader;
2726     CHECK(VAL32(pDir->Size) == sizeof(CORCOMPILE_HEADER));
2727
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);
2732
2733     CHECK_OK;
2734 }
2735
2736 CORCOMPILE_CODE_MANAGER_ENTRY *PEDecoder::GetNativeCodeManagerTable() const
2737 {
2738     CONTRACT(CORCOMPILE_CODE_MANAGER_ENTRY *)
2739     {
2740         PRECONDITION(CheckNativeHeader());
2741         POSTCONDITION(CheckPointer(RETVAL));
2742         SUPPORTS_DAC;
2743         NOTHROW;
2744         GC_NOTRIGGER;
2745     }
2746     CONTRACT_END;
2747
2748     IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->CodeManagerTable;
2749
2750     RETURN PTR_CORCOMPILE_CODE_MANAGER_ENTRY(GetDirectoryData(pDir));
2751 }
2752
2753 PCODE PEDecoder::GetNativeHotCode(COUNT_T * pSize) const
2754 {
2755     CONTRACT(PCODE)
2756     {
2757         PRECONDITION(CheckNativeHeader());
2758         PRECONDITION(CheckPointer(pSize, NULL_OK));
2759         SUPPORTS_DAC;
2760         NOTHROW;
2761         GC_NOTRIGGER;
2762     }
2763     CONTRACT_END;
2764
2765     IMAGE_DATA_DIRECTORY *pDir = &GetNativeCodeManagerTable()->HotCode;
2766
2767     if (pSize != NULL)
2768         *pSize = VAL32(pDir->Size);
2769
2770     RETURN GetDirectoryData(pDir);
2771 }
2772
2773 PCODE PEDecoder::GetNativeCode(COUNT_T * pSize) const
2774 {
2775     CONTRACT(PCODE)
2776     {
2777         PRECONDITION(CheckNativeHeader());
2778         PRECONDITION(CheckPointer(pSize, NULL_OK));
2779         SUPPORTS_DAC;
2780         NOTHROW;
2781         GC_NOTRIGGER;
2782     }
2783     CONTRACT_END;
2784
2785     IMAGE_DATA_DIRECTORY *pDir = &GetNativeCodeManagerTable()->Code;
2786
2787     if (pSize != NULL)
2788         *pSize = VAL32(pDir->Size);
2789
2790     RETURN GetDirectoryData(pDir);
2791 }
2792
2793 PCODE PEDecoder::GetNativeColdCode(COUNT_T * pSize) const
2794 {
2795     CONTRACT(PCODE)
2796     {
2797         PRECONDITION(CheckNativeHeader());
2798         PRECONDITION(CheckPointer(pSize, NULL_OK));
2799         NOTHROW;
2800         GC_NOTRIGGER;
2801         SUPPORTS_DAC;
2802     }
2803     CONTRACT_END;
2804
2805     IMAGE_DATA_DIRECTORY *pDir = &GetNativeCodeManagerTable()->ColdCode;
2806
2807     if (pSize != NULL)
2808         *pSize = VAL32(pDir->Size);
2809
2810     RETURN GetDirectoryData(pDir);
2811 }
2812
2813
2814 CORCOMPILE_METHOD_PROFILE_LIST *PEDecoder::GetNativeProfileDataList(COUNT_T * pSize) const
2815 {
2816     CONTRACT(CORCOMPILE_METHOD_PROFILE_LIST *)
2817     {
2818         PRECONDITION(CheckNativeHeader());
2819         PRECONDITION(CheckPointer(pSize, NULL_OK));
2820         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2821         NOTHROW;
2822         GC_NOTRIGGER;
2823     }
2824     CONTRACT_END;
2825
2826     IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->ProfileDataList;
2827
2828     if (pSize != NULL)
2829         *pSize = VAL32(pDir->Size);
2830
2831     RETURN PTR_CORCOMPILE_METHOD_PROFILE_LIST(GetDirectoryData(pDir));
2832 }
2833
2834 #endif // FEATURE_PREJIT
2835
2836 PTR_CVOID PEDecoder::GetNativeManifestMetadata(COUNT_T *pSize) const
2837 {
2838     CONTRACT(PTR_CVOID)
2839     {
2840         INSTANCE_CHECK;
2841         PRECONDITION(HasReadyToRunHeader() || CheckNativeHeader());
2842         POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); // TBD - may not store metadata for IJW
2843         NOTHROW;
2844         GC_NOTRIGGER;
2845     }
2846     CONTRACT_END;
2847     
2848     IMAGE_DATA_DIRECTORY *pDir = NULL;
2849 #ifdef FEATURE_PREJIT
2850     if (!HasReadyToRunHeader())
2851     {
2852         pDir = GetMetaDataHelper(METADATA_SECTION_MANIFEST);
2853     }
2854     else
2855 #endif
2856     {
2857         READYTORUN_HEADER * pHeader = GetReadyToRunHeader();
2858
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++)
2861         {
2862             // Verify that section types are sorted
2863             _ASSERTE(i == 0 || (pSections[i - 1].Type < pSections[i].Type));
2864
2865             READYTORUN_SECTION * pSection = pSections + i;
2866             if (pSection->Type == READYTORUN_SECTION_MANIFEST_METADATA)
2867             {
2868                 // Set pDir to the address of the manifest metadata section
2869                 pDir = &pSection->Section;
2870                 break;
2871             }
2872         }
2873
2874         // ReadyToRun file without large version bubble support doesn't have the READYTORUN_SECTION_MANIFEST_METADATA
2875         if (pDir == NULL)
2876         {
2877             if (pSize != NULL)
2878             {
2879                 *pSize = 0;
2880             }
2881
2882             RETURN NULL;
2883         }
2884     }
2885
2886     if (pSize != NULL)
2887         *pSize = VAL32(pDir->Size);
2888
2889     RETURN dac_cast<PTR_VOID>(GetDirectoryData(pDir));
2890 }
2891
2892 #ifdef FEATURE_PREJIT
2893
2894 PTR_CORCOMPILE_IMPORT_SECTION PEDecoder::GetNativeImportSections(COUNT_T *pCount) const
2895 {
2896     CONTRACT(PTR_CORCOMPILE_IMPORT_SECTION)
2897     {
2898         PRECONDITION(CheckNativeHeader());
2899         NOTHROW;
2900         GC_NOTRIGGER;
2901     }
2902     CONTRACT_END;
2903
2904     IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->ImportSections;
2905
2906     if (pCount != NULL)
2907         *pCount = VAL32(pDir->Size) / sizeof(CORCOMPILE_IMPORT_SECTION);
2908
2909     RETURN dac_cast<PTR_CORCOMPILE_IMPORT_SECTION>(GetDirectoryData(pDir));
2910 }
2911
2912 PTR_CORCOMPILE_IMPORT_SECTION PEDecoder::GetNativeImportSectionFromIndex(COUNT_T index) const
2913 {
2914     CONTRACT(PTR_CORCOMPILE_IMPORT_SECTION)
2915     {
2916         PRECONDITION(CheckNativeHeader());
2917         NOTHROW;
2918         GC_NOTRIGGER;
2919     }
2920     CONTRACT_END;
2921
2922     IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->ImportSections;
2923
2924     _ASSERTE(VAL32(pDir->Size) % sizeof(CORCOMPILE_IMPORT_SECTION) == 0);
2925     _ASSERTE(index * sizeof(CORCOMPILE_IMPORT_SECTION) < VAL32(pDir->Size));
2926
2927     RETURN dac_cast<PTR_CORCOMPILE_IMPORT_SECTION>(GetDirectoryData(pDir)) + index;
2928 }
2929
2930 PTR_CORCOMPILE_IMPORT_SECTION PEDecoder::GetNativeImportSectionForRVA(RVA rva) const
2931 {
2932     CONTRACT(PTR_CORCOMPILE_IMPORT_SECTION)
2933     {
2934         PRECONDITION(CheckNativeHeader());
2935         NOTHROW;
2936         GC_NOTRIGGER;
2937     }
2938     CONTRACT_END;
2939
2940     IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->ImportSections;
2941
2942     _ASSERTE(VAL32(pDir->Size) % sizeof(CORCOMPILE_IMPORT_SECTION) == 0);
2943
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));
2946
2947     for (PTR_CORCOMPILE_IMPORT_SECTION pSection = pSections; pSection < pEnd; pSection++)
2948     {
2949         if (rva >= VAL32(pSection->Section.VirtualAddress) && rva < VAL32(pSection->Section.VirtualAddress) + VAL32(pSection->Section.Size))
2950             RETURN pSection;
2951     }
2952
2953     RETURN NULL;
2954 }
2955
2956 TADDR PEDecoder::GetStubsTable(COUNT_T *pSize) const
2957 {
2958     CONTRACTL {
2959         INSTANCE_CHECK;
2960         PRECONDITION(CheckNativeHeader());
2961         NOTHROW;
2962         GC_NOTRIGGER;
2963     } CONTRACTL_END;
2964
2965     IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->StubsData;
2966
2967     if (pSize != NULL)
2968         *pSize = VAL32(pDir->Size);
2969
2970     return (GetDirectoryData(pDir));
2971 }
2972
2973 TADDR PEDecoder::GetVirtualSectionsTable(COUNT_T *pSize) const
2974 {
2975     CONTRACTL {
2976         INSTANCE_CHECK;
2977         PRECONDITION(CheckNativeHeader());
2978         NOTHROW;
2979         GC_NOTRIGGER;
2980     } CONTRACTL_END;
2981
2982     IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->VirtualSectionsTable;
2983
2984     if (pSize != NULL)
2985         *pSize = VAL32(pDir->Size);
2986
2987     return (GetDirectoryData(pDir));
2988 }
2989
2990 #endif // FEATURE_PREJIT
2991
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
2995 {
2996     CONTRACTL {
2997         PRECONDITION(!IsDll()); // This routine should only be called for EXE files.
2998         NOTHROW;
2999         GC_NOTRIGGER;
3000     } CONTRACTL_END;
3001
3002     * PE_SizeOfStackReserve = GetSizeOfStackReserve();
3003     * PE_SizeOfStackCommit  = GetSizeOfStackCommit();
3004 }
3005
3006 CHECK PEDecoder::CheckWillCreateGuardPage() const
3007 {
3008     CONTRACT_CHECK
3009     {
3010         PRECONDITION(CheckNTHeaders());
3011         NOTHROW;
3012         GC_NOTRIGGER;
3013     }
3014     CONTRACT_CHECK_END;
3015
3016     if (!IsDll())
3017     {
3018         SIZE_T sizeReservedStack = 0;
3019         SIZE_T sizeCommitedStack = 0;
3020
3021         GetEXEStackSizes(&sizeReservedStack, &sizeCommitedStack);
3022
3023         CHECK(ThreadWillCreateGuardPage(sizeReservedStack, sizeCommitedStack));
3024
3025     }
3026
3027     CHECK_OK;
3028 }
3029
3030 BOOL PEDecoder::HasNativeEntryPoint() const
3031 {
3032     CONTRACTL {
3033         INSTANCE_CHECK;
3034         NOTHROW;
3035         GC_NOTRIGGER;
3036         PRECONDITION(CheckCorHeader());
3037     } CONTRACTL_END;
3038
3039     ULONG flags = GetCorHeader()->Flags;
3040     return ((flags & VAL32(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT)) &&
3041             (IMAGE_COR20_HEADER_FIELD(*GetCorHeader(), EntryPointToken) != VAL32(0)));
3042 }
3043
3044 void *PEDecoder::GetNativeEntryPoint() const
3045 {
3046     CONTRACT (void *) {
3047         INSTANCE_CHECK;
3048         NOTHROW;
3049         GC_NOTRIGGER;
3050         PRECONDITION(CheckCorHeader());
3051         PRECONDITION(HasNativeEntryPoint());
3052         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
3053     } CONTRACT_END;
3054
3055     RETURN ((void *) GetRvaData((RVA)VAL32(IMAGE_COR20_HEADER_FIELD(*GetCorHeader(), EntryPointToken))));
3056 }
3057
3058 #ifdef DACCESS_COMPILE
3059
3060 void
3061 PEDecoder::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
3062                              bool enumThis)
3063 {
3064     SUPPORTS_DAC;
3065     if (enumThis)
3066     {
3067         DAC_ENUM_DTHIS();
3068     }
3069
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();
3075
3076     if (HasNTHeaders())
3077     {
3078         // resource file does not have NT Header.
3079         //
3080         // we also need to write out section header.
3081         DacEnumMemoryRegion(dac_cast<TADDR>(FindFirstSection()), sizeof(IMAGE_SECTION_HEADER) * GetNumberOfSections());
3082     }
3083 }
3084
3085 #endif // #ifdef DACCESS_COMPILE
3086
3087 // --------------------------------------------------------------------------------
3088
3089 #ifdef _DEBUG
3090
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.
3094
3095 BOOL PEDecoder::GetForceRelocs()
3096 {
3097     WRAPPER_NO_CONTRACT;
3098
3099     static ConfigDWORD forceRelocs;
3100     return (forceRelocs.val(CLRConfig::INTERNAL_ForceRelocs) != 0);
3101 }
3102
3103 BOOL PEDecoder::ForceRelocForDLL(LPCWSTR lpFileName)
3104 {
3105     // Use static contracts to avoid recursion, as the dynamic contracts
3106     // do WszLoadLibrary(MSCOREE_SHIM_W).
3107 #ifdef _DEBUG
3108                 STATIC_CONTRACT_NOTHROW;                                        \
3109                 ANNOTATION_DEBUG_ONLY;                                          \
3110                 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
3111 #endif
3112
3113 #if defined(DACCESS_COMPILE) || defined(FEATURE_PAL)
3114     return TRUE;
3115 #else
3116
3117     // Contracts in ConfigDWORD do WszLoadLibrary(MSCOREE_SHIM_W).
3118     // This check prevents recursion.
3119     if (wcsstr(lpFileName, MSCOREE_SHIM_W) != 0)
3120         return TRUE;
3121
3122     if (!GetForceRelocs())
3123         return TRUE;
3124
3125     BOOL fSuccess = FALSE;
3126     PBYTE hndle = NULL;
3127     PEDecoder pe;
3128     void* pPreferredBase;
3129     COUNT_T nVirtualSize;
3130
3131     HANDLE hFile = WszCreateFile(lpFileName,
3132                                  GENERIC_READ,
3133                                  FILE_SHARE_READ,
3134                                  NULL,
3135                                  OPEN_EXISTING,
3136                                  FILE_FLAG_SEQUENTIAL_SCAN,
3137                                  NULL);
3138     if (hFile == INVALID_HANDLE_VALUE)
3139         goto ErrExit;
3140
3141     HANDLE hMap = WszCreateFileMapping(hFile,
3142                                        NULL,
3143                                        SEC_IMAGE | PAGE_READONLY,
3144                                        0,
3145                                        0,
3146                                        NULL);
3147     CloseHandle(hFile);
3148
3149     if (hMap == NULL)
3150         goto ErrExit;
3151
3152     hndle = (PBYTE)MapViewOfFile(hMap,
3153                                        FILE_MAP_READ,
3154                                        0,
3155                                        0,
3156                                        0);
3157     CloseHandle(hMap);
3158
3159     if (!hndle)
3160         goto ErrExit;
3161
3162     pe.Init(hndle);
3163
3164     pPreferredBase = (void*)pe.GetPreferredBase();
3165     nVirtualSize = pe.GetVirtualSize();
3166
3167     UnmapViewOfFile(hndle);
3168     hndle = NULL;
3169
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))
3174         goto ErrExit;
3175
3176     fSuccess = TRUE;
3177
3178 ErrExit:
3179     if (hndle != NULL)
3180         UnmapViewOfFile(hndle);
3181
3182     return fSuccess;
3183
3184 #endif // DACCESS_COMPILE || FEATURE_PAL
3185 }
3186
3187 #endif // _DEBUG
3188
3189 //
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
3192 //
3193 MethodSectionIterator::MethodSectionIterator(const void *code, SIZE_T codeSize,
3194                                              const void *codeTable, SIZE_T codeTableSize)
3195 {
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;
3203     m_current = NULL;
3204
3205
3206     if (m_codeTable < m_codeTableEnd)
3207     {
3208         m_dword = *m_codeTable++;
3209         m_index = 0;
3210     }
3211     else
3212     {
3213         m_index = NIBBLES_PER_DWORD;
3214     }
3215 }
3216
3217 BOOL MethodSectionIterator::Next()
3218 {
3219     while (m_codeTable < m_codeTableEnd || m_index < (int)NIBBLES_PER_DWORD)
3220     {
3221         while (m_index++ < (int)NIBBLES_PER_DWORD)
3222         {
3223             int nibble = (m_dword & HIGHEST_NIBBLE_MASK)>>HIGHEST_NIBBLE_BIT;
3224             m_dword <<= NIBBLE_SIZE;
3225
3226             if (nibble != 0)
3227             {
3228                 // We have found a method start
3229                 m_current = m_code + ((nibble-1)*CODE_ALIGN);
3230                 m_code += BYTES_PER_BUCKET;
3231                 return TRUE;
3232             }
3233
3234             m_code += BYTES_PER_BUCKET;
3235         }
3236
3237         if (m_codeTable < m_codeTableEnd)
3238         {
3239             m_dword = *m_codeTable++;
3240             m_index = 0;
3241         }
3242     }
3243     return FALSE;
3244 }