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
17CHECK 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 !defined(FEATURE_PREJIT)
38 CHECK(IsILOnly());
39#endif
40
41 if (IsILOnly() && !HasReadyToRunHeader())
42 CHECK(CheckILOnly());
43
44 if (HasNativeHeader())
45 CHECK(CheckNativeHeader());
46
47 CHECK(CheckWillCreateGuardPage());
48 }
49 }
50
51 CHECK_OK;
52}
53
54CHECK PEDecoder::CheckNTFormat() const
55{
56 CONTRACT_CHECK
57 {
58 INSTANCE_CHECK;
59 NOTHROW;
60 GC_NOTRIGGER;
61 PRECONDITION(HasContents());
62 }
63 CONTRACT_CHECK_END;
64
65 CHECK(CheckFormat());
66 CHECK(HasNTHeaders());
67
68 CHECK_OK;
69}
70
71CHECK PEDecoder::CheckCORFormat() const
72{
73 CONTRACT_CHECK
74 {
75 INSTANCE_CHECK;
76 NOTHROW;
77 GC_NOTRIGGER;
78 PRECONDITION(HasContents());
79 }
80 CONTRACT_CHECK_END;
81
82 CHECK(CheckFormat());
83 CHECK(HasNTHeaders());
84 CHECK(HasCorHeader());
85
86 CHECK_OK;
87}
88
89
90CHECK PEDecoder::CheckILFormat() const
91{
92 CONTRACT_CHECK
93 {
94 INSTANCE_CHECK;
95 NOTHROW;
96 GC_NOTRIGGER;
97 PRECONDITION(HasContents());
98 }
99 CONTRACT_CHECK_END;
100
101 CHECK(CheckFormat());
102 CHECK(HasNTHeaders());
103 CHECK(HasCorHeader());
104 CHECK(!HasNativeHeader());
105
106 CHECK_OK;
107}
108
109
110CHECK PEDecoder::CheckILOnlyFormat() const
111{
112 CONTRACT_CHECK
113 {
114 INSTANCE_CHECK;
115 NOTHROW;
116 GC_NOTRIGGER;
117 PRECONDITION(HasContents());
118 }
119 CONTRACT_CHECK_END;
120
121 CHECK(CheckFormat());
122 CHECK(HasNTHeaders());
123 CHECK(HasCorHeader());
124 CHECK(IsILOnly());
125 CHECK(!HasNativeHeader());
126
127 CHECK_OK;
128}
129
130CHECK PEDecoder::CheckNativeFormat() const
131{
132 CONTRACT_CHECK
133 {
134 INSTANCE_CHECK;
135 NOTHROW;
136 GC_NOTRIGGER;
137 PRECONDITION(HasContents());
138 }
139 CONTRACT_CHECK_END;
140
141#ifdef FEATURE_PREJIT
142 CHECK(CheckFormat());
143 CHECK(HasNTHeaders());
144 CHECK(HasCorHeader());
145 CHECK(!IsILOnly());
146 CHECK(HasNativeHeader());
147#else // FEATURE_PREJIT
148 CHECK(false);
149#endif // FEATURE_PREJIT
150
151 CHECK_OK;
152}
153
154BOOL PEDecoder::HasNTHeaders() const
155{
156 CONTRACT(BOOL)
157 {
158 INSTANCE_CHECK;
159 NOTHROW;
160 GC_NOTRIGGER;
161 SUPPORTS_DAC;
162 PRECONDITION(HasContents());
163 SO_TOLERANT;
164 }
165 CONTRACT_END;
166
167 // Check for a valid DOS header
168
169 if (m_size < sizeof(IMAGE_DOS_HEADER))
170 RETURN FALSE;
171
172 IMAGE_DOS_HEADER* pDOS = PTR_IMAGE_DOS_HEADER(m_base);
173
174 {
175 if (pDOS->e_magic != VAL16(IMAGE_DOS_SIGNATURE)
176 || (DWORD) pDOS->e_lfanew == VAL32(0))
177 {
178 RETURN FALSE;
179 }
180
181 // Check for integer overflow
182 S_SIZE_T cbNTHeaderEnd(S_SIZE_T(static_cast<SIZE_T>(VAL32(pDOS->e_lfanew))) +
183 S_SIZE_T(sizeof(IMAGE_NT_HEADERS)));
184 if (cbNTHeaderEnd.IsOverflow())
185 {
186 RETURN FALSE;
187 }
188
189 // Now check for a valid NT header
190 if (m_size < cbNTHeaderEnd.Value())
191 {
192 RETURN FALSE;
193 }
194 }
195
196 IMAGE_NT_HEADERS *pNT = PTR_IMAGE_NT_HEADERS(m_base + VAL32(pDOS->e_lfanew));
197
198 if (pNT->Signature != VAL32(IMAGE_NT_SIGNATURE))
199 RETURN FALSE;
200
201 if (pNT->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC))
202 {
203 if (pNT->FileHeader.SizeOfOptionalHeader != VAL16(sizeof(IMAGE_OPTIONAL_HEADER32)))
204 RETURN FALSE;
205 }
206 else if (pNT->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR64_MAGIC))
207 {
208 // on 64 bit we can promote this
209 if (pNT->FileHeader.SizeOfOptionalHeader != VAL16(sizeof(IMAGE_OPTIONAL_HEADER64)))
210 RETURN FALSE;
211
212 // Check for integer overflow
213 S_SIZE_T cbNTHeaderEnd(S_SIZE_T(static_cast<SIZE_T>(VAL32(pDOS->e_lfanew))) +
214 S_SIZE_T(sizeof(IMAGE_NT_HEADERS64)));
215
216 if (cbNTHeaderEnd.IsOverflow())
217 {
218 RETURN FALSE;
219 }
220
221 // Now check for a valid NT header
222 if (m_size < cbNTHeaderEnd.Value())
223 {
224 RETURN FALSE;
225 }
226
227 }
228 else
229 RETURN FALSE;
230
231 // Go ahead and cache NT header since we already found it.
232 const_cast<PEDecoder *>(this)->m_pNTHeaders = dac_cast<PTR_IMAGE_NT_HEADERS>(pNT);
233
234 RETURN TRUE;
235}
236
237CHECK PEDecoder::CheckNTHeaders() const
238{
239 CONTRACT_CHECK
240 {
241 INSTANCE_CHECK;
242 NOTHROW;
243 GC_NOTRIGGER;
244 SUPPORTS_DAC;
245 PRECONDITION(HasContents());
246 SO_TOLERANT;
247 }
248 CONTRACT_CHECK_END;
249
250 // Only check once per file
251 if (m_flags & FLAG_NT_CHECKED)
252 CHECK_OK;
253
254 CHECK(HasNTHeaders());
255
256 IMAGE_NT_HEADERS *pNT = FindNTHeaders();
257
258 CHECK((pNT->FileHeader.Characteristics & VAL16(IMAGE_FILE_SYSTEM)) == 0);
259
260 CHECK(CheckAlignment(VAL32(pNT->OptionalHeader.FileAlignment)));
261 CHECK(CheckAlignment(VAL32(pNT->OptionalHeader.SectionAlignment)));
262
263 CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.FileAlignment), 512));
264 CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.SectionAlignment), VAL32(pNT->OptionalHeader.FileAlignment)));
265
266 CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.SizeOfImage), VAL32(pNT->OptionalHeader.SectionAlignment)));
267 CHECK(CheckAligned((UINT)VAL32(pNT->OptionalHeader.SizeOfHeaders), VAL32(pNT->OptionalHeader.FileAlignment)));
268
269 // Data directories will be validated later on.
270 PTR_IMAGE_DATA_DIRECTORY pDataDirectories = NULL;
271
272 if (Has32BitNTHeaders())
273 {
274 IMAGE_NT_HEADERS32* pNT32=GetNTHeaders32();
275 CHECK(CheckAligned(VAL32(pNT32->OptionalHeader.ImageBase), 0x10000));
276 CHECK((VAL32(pNT32->OptionalHeader.SizeOfStackCommit) <= VAL32(pNT32->OptionalHeader.SizeOfStackReserve)));
277 CHECK((VAL32(pNT32->OptionalHeader.SizeOfHeapCommit) <= VAL32(pNT32->OptionalHeader.SizeOfHeapReserve)));
278 pDataDirectories = dac_cast<PTR_IMAGE_DATA_DIRECTORY>(
279 dac_cast<TADDR>(pNT32) + offsetof(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory));
280 }
281 else
282 {
283 IMAGE_NT_HEADERS64* pNT64=GetNTHeaders64();
284 CHECK(CheckAligned(VAL64(pNT64->OptionalHeader.ImageBase), 0x10000));
285 CHECK((VAL64(pNT64->OptionalHeader.SizeOfStackCommit) <= VAL64(pNT64->OptionalHeader.SizeOfStackReserve)));
286 CHECK((VAL64(pNT64->OptionalHeader.SizeOfHeapCommit) <= VAL64(pNT64->OptionalHeader.SizeOfHeapReserve)));
287 pDataDirectories = dac_cast<PTR_IMAGE_DATA_DIRECTORY>(
288 dac_cast<TADDR>(pNT64) + offsetof(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory));
289 }
290
291 // @todo: this is a bit awkward here, it would be better to make this assertion on
292 // PEDecoder instantiation. However, we don't necessarily have the NT headers there (in fact
293 // they might not exist.)
294
295 if (IsMapped())
296 {
297 // Ideally we would require the layout address to honor the section alignment constraints.
298 // However, we do have 8K aligned IL only images which we load on 32 bit platforms. In this
299 // case, we can only guarantee OS page alignment (which after all, is good enough.)
300 CHECK(CheckAligned(m_base, GetOsPageSize()));
301 }
302
303 // @todo: check NumberOfSections for overflow of SizeOfHeaders
304
305 UINT32 currentAddress = 0;
306 UINT32 currentOffset = 0;
307
308 CHECK(CheckSection(currentAddress, 0, VAL32(pNT->OptionalHeader.SizeOfHeaders),
309 currentOffset, 0, VAL32(pNT->OptionalHeader.SizeOfHeaders)));
310
311 currentAddress=currentOffset=VAL32(pNT->OptionalHeader.SizeOfHeaders);
312
313 PTR_IMAGE_SECTION_HEADER section = FindFirstSection(pNT);
314 PTR_IMAGE_SECTION_HEADER sectionEnd = section + VAL16(pNT->FileHeader.NumberOfSections);
315
316 CHECK(sectionEnd >= section);
317
318
319 while (section < sectionEnd)
320 {
321
322 //
323 // NOTE: the if condition is becuase of a design issue in the CLR and OS loader's remapping
324 // of PE32 headers to PE32+. Because IMAGE_NT_HEADERS64 is bigger than IMAGE_NT_HEADERS32,
325 // the remapping will expand this part of the header and push out the following
326 // IMAGE_SECTION_HEADER entries. When IMAGE_DOS_HEADER::e_lfanew is large enough (size is
327 // proportional to the number of tools used to produce the inputs to the C++ linker, and
328 // has become larger when producing some WinMD files) this can push the last section header
329 // beyond the boundary set by IMAGE_NT_HEADERS::OptionalHeader.SizeOfHeaders (e.g., this
330 // was recently seen where the unaligned size of the headers was 0x1f8 and SizeOfHeaders was
331 // 0x200, and the header remapping resulted in new headers size of 0x208). To compensate
332 // for this issue (it would be quite difficult to fix in the remapping code; see Dev11 430008)
333 // we assume that when the image is mapped that the needed validation has already been done.
334 //
335
336 if (!IsMapped())
337 {
338 CHECK(CheckBounds(dac_cast<PTR_CVOID>(pNT),VAL32(pNT->OptionalHeader.SizeOfHeaders),
339 section,sizeof(IMAGE_SECTION_HEADER)));
340 }
341
342 // Check flags
343 // Only allow a small list of characteristics
344 CHECK(!(section->Characteristics &
345 ~(VAL32((IMAGE_SCN_CNT_CODE |
346 IMAGE_SCN_CNT_INITIALIZED_DATA |
347 IMAGE_SCN_CNT_UNINITIALIZED_DATA|
348 IMAGE_SCN_MEM_DISCARDABLE |
349 IMAGE_SCN_MEM_NOT_CACHED |
350 IMAGE_SCN_MEM_NOT_PAGED |
351 IMAGE_SCN_MEM_EXECUTE |
352 IMAGE_SCN_MEM_READ |
353 IMAGE_SCN_MEM_WRITE |
354 // allow shared sections for all images for now.
355 // we'll constrain this in CheckILOnly
356 IMAGE_SCN_MEM_SHARED)))));
357
358 // we should not allow writable code sections, check if both flags are set
359 CHECK((section->Characteristics & VAL32((IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_WRITE))) !=
360 VAL32((IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_WRITE)));
361
362 CHECK(CheckSection(currentAddress, VAL32(section->VirtualAddress), VAL32(section->Misc.VirtualSize),
363 currentOffset, VAL32(section->PointerToRawData), VAL32(section->SizeOfRawData)));
364
365 currentAddress = VAL32(section->VirtualAddress)
366 + AlignUp((UINT)VAL32(section->Misc.VirtualSize), (UINT)VAL32(pNT->OptionalHeader.SectionAlignment));
367 currentOffset = VAL32(section->PointerToRawData) + VAL32(section->SizeOfRawData);
368
369 section++;
370 }
371
372 // Now check that the COR data directory is either NULL, or exists entirely in one section.
373 {
374 PTR_IMAGE_DATA_DIRECTORY pCORDataDir = pDataDirectories + IMAGE_DIRECTORY_ENTRY_COMHEADER;
375 CHECK(CheckRva(VAL32(pCORDataDir->VirtualAddress), VAL32(pCORDataDir->Size), 0, NULL_OK));
376 }
377
378 // @todo: verify directory entries
379
380 const_cast<PEDecoder *>(this)->m_flags |= FLAG_NT_CHECKED;
381
382 CHECK_OK;
383}
384
385CHECK PEDecoder::CheckSection(COUNT_T previousAddressEnd, COUNT_T addressStart, COUNT_T addressSize,
386 COUNT_T previousOffsetEnd, COUNT_T offsetStart, COUNT_T offsetSize) const
387{
388 CONTRACT_CHECK
389 {
390 INSTANCE_CHECK;
391 PRECONDITION(HasNTHeaders());
392 NOTHROW;
393 GC_NOTRIGGER;
394 SUPPORTS_DAC;
395 SO_TOLERANT;
396 }
397 CONTRACT_CHECK_END;
398
399 // Fetch the NT header
400 IMAGE_NT_HEADERS *pNT = FindNTHeaders();
401
402 // OS will zero pad a mapped file up to file alignment size - some images rely on this
403 // COUNT_T alignedSize = AlignUp(m_size, VAL32(pNT->OptionalHeader.FileAlignment));
404 COUNT_T alignedSize = IsMapped() ? AlignUp(m_size, VAL32(pNT->OptionalHeader.FileAlignment)) : m_size;
405
406 // Check to make sure that our memory is big enough to cover the stated range.
407 // Note that this check is only required if we have a non-flat image.
408 if (IsMapped())
409 CHECK(alignedSize >= VAL32(pNT->OptionalHeader.SizeOfImage));
410
411 // Check expected alignments
412 CHECK(CheckAligned(addressStart, VAL32(pNT->OptionalHeader.SectionAlignment)));
413 CHECK(CheckAligned(offsetStart, VAL32(pNT->OptionalHeader.FileAlignment)));
414 CHECK(CheckAligned(offsetSize, VAL32(pNT->OptionalHeader.FileAlignment)));
415
416 // addressSize is typically not aligned, so we align it for purposes of checks.
417 COUNT_T alignedAddressSize = AlignUp(addressSize, VAL32(pNT->OptionalHeader.SectionAlignment));
418 CHECK(addressSize <= alignedAddressSize);
419
420 // Check overflow
421 CHECK(CheckOverflow(addressStart, alignedAddressSize));
422 CHECK(CheckOverflow(offsetStart, offsetSize));
423
424 // Make sure we don't overlap the previous section
425 CHECK(addressStart >= previousAddressEnd
426 && (offsetSize == 0
427 || offsetStart >= previousOffsetEnd));
428
429 // Make sure we don't overrun the end of the mapped image
430 CHECK(addressStart + alignedAddressSize <= VAL32(pNT->OptionalHeader.SizeOfImage));
431
432 // Make sure we don't overrun the end of the file (only relevant if we're not mapped, otherwise
433 // we don't know the file size, as it's not declared in the headers.)
434 if (!IsMapped())
435 CHECK(offsetStart + offsetSize <= alignedSize);
436
437 // Make sure the data doesn't overrun the virtual address space
438 CHECK(offsetSize <= alignedAddressSize);
439
440 CHECK_OK;
441}
442
443BOOL PEDecoder::HasWriteableSections() const
444{
445 CONTRACT_CHECK
446 {
447 INSTANCE_CHECK;
448 PRECONDITION(CheckNTHeaders());
449 PRECONDITION(CheckFormat());
450 NOTHROW;
451 GC_NOTRIGGER;
452 SUPPORTS_DAC;
453 SO_TOLERANT;
454 }
455 CONTRACT_CHECK_END;
456
457 PTR_IMAGE_SECTION_HEADER pSection = FindFirstSection();
458 _ASSERTE(pSection != NULL);
459
460 PTR_IMAGE_SECTION_HEADER pSectionEnd = pSection + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
461
462 while (pSection < pSectionEnd)
463 {
464 if ((pSection->Characteristics & VAL32(IMAGE_SCN_MEM_WRITE)) != 0)
465 {
466 return TRUE;
467 }
468
469 pSection++;
470 }
471
472 return FALSE;
473}
474
475CHECK PEDecoder::CheckDirectoryEntry(int entry, int forbiddenFlags, IsNullOK ok) const
476{
477 CONTRACT_CHECK
478 {
479 INSTANCE_CHECK;
480 PRECONDITION(CheckNTHeaders());
481 PRECONDITION(entry < IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
482 PRECONDITION(HasDirectoryEntry(entry));
483 NOTHROW;
484 GC_NOTRIGGER;
485 SO_TOLERANT;
486 }
487 CONTRACT_CHECK_END;
488
489 CHECK(CheckDirectory(GetDirectoryEntry(entry), forbiddenFlags, ok));
490
491 CHECK_OK;
492}
493
494CHECK PEDecoder::CheckDirectory(IMAGE_DATA_DIRECTORY *pDir, int forbiddenFlags, IsNullOK ok) const
495{
496 CONTRACT_CHECK
497 {
498 INSTANCE_CHECK;
499 PRECONDITION(CheckNTHeaders());
500 PRECONDITION(CheckPointer(pDir));
501 NOTHROW;
502 GC_NOTRIGGER;
503 SUPPORTS_DAC;
504 SO_TOLERANT;
505 }
506 CONTRACT_CHECK_END;
507
508 CHECK(CheckRva(VAL32(pDir->VirtualAddress), VAL32(pDir->Size), forbiddenFlags, ok));
509
510 CHECK_OK;
511}
512
513CHECK PEDecoder::CheckRva(RVA rva, COUNT_T size, int forbiddenFlags, IsNullOK ok) const
514{
515 CONTRACT_CHECK
516 {
517 INSTANCE_CHECK;
518 NOTHROW;
519 GC_NOTRIGGER;
520 SUPPORTS_DAC;
521 SO_TOLERANT;
522 }
523 CONTRACT_CHECK_END;
524
525 if (rva == 0)
526 {
527 CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
528 CHECK(size == 0);
529 }
530 else
531 {
532 IMAGE_SECTION_HEADER *section = RvaToSection(rva);
533
534 CHECK(section != NULL);
535
536 CHECK(CheckBounds(VAL32(section->VirtualAddress),
537 // AlignUp((UINT)VAL32(section->Misc.VirtualSize), (UINT)VAL32(FindNTHeaders()->OptionalHeader.SectionAlignment)),
538 (UINT)VAL32(section->Misc.VirtualSize),
539 rva, size));
540 if(!IsMapped())
541 {
542 CHECK(CheckBounds(VAL32(section->VirtualAddress), VAL32(section->SizeOfRawData), rva, size));
543 }
544
545 if (forbiddenFlags!=0)
546 CHECK((section->Characteristics & VAL32(forbiddenFlags))==0);
547 }
548
549 CHECK_OK;
550}
551
552CHECK PEDecoder::CheckRva(RVA rva, IsNullOK ok) const
553{
554 CONTRACT_CHECK
555 {
556 INSTANCE_CHECK;
557 NOTHROW;
558 GC_NOTRIGGER;
559 SUPPORTS_DAC;
560 SO_TOLERANT;
561 }
562 CONTRACT_CHECK_END;
563
564 if (rva == 0)
565 CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
566 else
567 CHECK(RvaToSection(rva) != NULL);
568
569 CHECK_OK;
570}
571
572CHECK PEDecoder::CheckOffset(COUNT_T fileOffset, COUNT_T size, IsNullOK ok) const
573{
574 CONTRACT_CHECK
575 {
576 INSTANCE_CHECK;
577 PRECONDITION(CheckNTHeaders());
578 NOTHROW;
579 GC_NOTRIGGER;
580 }
581 CONTRACT_CHECK_END;
582
583 if (fileOffset == 0)
584 {
585 CHECK_MSG(ok == NULL_OK, "zero fileOffset illegal");
586 CHECK(size == 0);
587 }
588 else
589 {
590 IMAGE_SECTION_HEADER *section = OffsetToSection(fileOffset);
591
592 CHECK(section != NULL);
593
594 CHECK(CheckBounds(section->PointerToRawData, section->SizeOfRawData,
595 fileOffset, size));
596 }
597
598 CHECK_OK;
599}
600
601CHECK PEDecoder::CheckOffset(COUNT_T fileOffset, IsNullOK ok) const
602{
603 CONTRACT_CHECK
604 {
605 INSTANCE_CHECK;
606 PRECONDITION(CheckNTHeaders());
607 NOTHROW;
608 GC_NOTRIGGER;
609 }
610 CONTRACT_CHECK_END;
611
612 if (fileOffset == NULL)
613 CHECK_MSG(ok == NULL_OK, "Null pointer illegal");
614 else
615 {
616 CHECK(OffsetToSection(fileOffset) != NULL);
617 }
618
619 CHECK_OK;
620}
621
622CHECK PEDecoder::CheckData(const void *data, COUNT_T size, IsNullOK ok) const
623{
624 CONTRACT_CHECK
625 {
626 INSTANCE_CHECK;
627 PRECONDITION(CheckNTHeaders());
628 NOTHROW;
629 GC_NOTRIGGER;
630 }
631 CONTRACT_CHECK_END;
632
633 if (data == NULL)
634 {
635 CHECK_MSG(ok == NULL_OK, "NULL pointer illegal");
636 CHECK(size == 0);
637 }
638 else
639 {
640 CHECK(CheckUnderflow(data, m_base));
641 CHECK((UINT_PTR) (((BYTE *) data) - ((BYTE *) m_base)) <= COUNT_T_MAX);
642
643 if (IsMapped())
644 CHECK(CheckRva((COUNT_T) ((BYTE *) data - (BYTE *) m_base), size));
645 else
646 CHECK(CheckOffset((COUNT_T) ((BYTE *) data - (BYTE *) m_base), size));
647 }
648
649 CHECK_OK;
650}
651
652CHECK PEDecoder::CheckData(const void *data, IsNullOK ok) const
653{
654 CONTRACT_CHECK
655 {
656 INSTANCE_CHECK;
657 PRECONDITION(CheckNTHeaders());
658 NOTHROW;
659 GC_NOTRIGGER;
660 }
661 CONTRACT_CHECK_END;
662
663 if (data == NULL)
664 CHECK_MSG(ok == NULL_OK, "Null pointer illegal");
665 else
666 {
667 CHECK(CheckUnderflow(data, m_base));
668 CHECK((UINT_PTR) (((BYTE *) data) - ((BYTE *) m_base)) <= COUNT_T_MAX);
669
670 if (IsMapped())
671 CHECK(CheckRva((COUNT_T) ((BYTE *) data - (BYTE *) m_base)));
672 else
673 CHECK(CheckOffset((COUNT_T) ((BYTE *) data - (BYTE *) m_base)));
674 }
675
676 CHECK_OK;
677}
678
679CHECK PEDecoder::CheckInternalAddress(SIZE_T address, IsNullOK ok) const
680{
681 CONTRACT_CHECK
682 {
683 INSTANCE_CHECK;
684 PRECONDITION(CheckNTHeaders());
685 NOTHROW;
686 GC_NOTRIGGER;
687 SO_TOLERANT;
688 }
689 CONTRACT_CHECK_END;
690
691 if (address == 0)
692 CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
693 else
694 CHECK(RvaToSection(InternalAddressToRva(address)) != NULL);
695
696 CHECK_OK;
697}
698
699CHECK PEDecoder::CheckInternalAddress(SIZE_T address, COUNT_T size, IsNullOK ok) const
700{
701 CONTRACT_CHECK
702 {
703 INSTANCE_CHECK;
704 PRECONDITION(CheckNTHeaders());
705 NOTHROW;
706 GC_NOTRIGGER;
707 SO_TOLERANT;
708 }
709 CONTRACT_CHECK_END;
710
711 if (address == 0)
712 {
713 CHECK_MSG(ok == NULL_OK, "Zero RVA illegal");
714 CHECK(size == 0);
715 }
716 else
717 {
718 CHECK(CheckRva(InternalAddressToRva(address), size));
719 }
720
721 CHECK_OK;
722}
723
724RVA PEDecoder::InternalAddressToRva(SIZE_T address) const
725{
726 CONTRACT(RVA)
727 {
728 INSTANCE_CHECK;
729 PRECONDITION(CheckNTHeaders());
730 NOTHROW;
731 GC_NOTRIGGER;
732 POSTCONDITION(CheckRva(RETVAL));
733 SO_TOLERANT;
734 }
735 CONTRACT_END;
736
737 if (m_flags & FLAG_RELOCATED)
738 {
739 // Address has been fixed up
740 RETURN (RVA) ((BYTE *) address - (BYTE *) m_base);
741 }
742 else
743 {
744 // Address has not been fixed up
745 RETURN (RVA) (address - (SIZE_T) GetPreferredBase());
746 }
747}
748
749// Returns a pointer to the named section or NULL if not found.
750// The name should include the starting "." as well.
751IMAGE_SECTION_HEADER *PEDecoder::FindSection(LPCSTR sectionName) const
752{
753 CONTRACT(IMAGE_SECTION_HEADER *)
754 {
755 INSTANCE_CHECK;
756 PRECONDITION(CheckNTHeaders());
757 PRECONDITION(sectionName != NULL);
758 NOTHROW;
759 GC_NOTRIGGER;
760 CANNOT_TAKE_LOCK;
761 SO_TOLERANT;
762 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
763 }
764 CONTRACT_END;
765
766 // Ensure that the section name length is valid
767 SIZE_T iSectionNameLength = strlen(sectionName);
768 if ((iSectionNameLength < 1) || (iSectionNameLength > IMAGE_SIZEOF_SHORT_NAME))
769 {
770 _ASSERTE(!"Invalid section name!");
771 RETURN NULL;
772 }
773
774 // Get the start and ends of the sections
775 PTR_IMAGE_SECTION_HEADER pSection = FindFirstSection(FindNTHeaders());
776 _ASSERTE(pSection != NULL);
777 PTR_IMAGE_SECTION_HEADER pSectionEnd = pSection + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
778 _ASSERTE(pSectionEnd != NULL);
779
780 BOOL fFoundSection = FALSE;
781
782 // Loop thru the sections and see if we got the section we are interested in
783 while (pSection < pSectionEnd)
784 {
785 // Is this the section we are looking for?
786 if (strncmp(sectionName, (char*)pSection->Name, iSectionNameLength) == 0)
787 {
788 // We found our section - break out of the loop
789 fFoundSection = TRUE;
790 break;
791 }
792
793 // Move to the next section
794 pSection++;
795 }
796
797 if (TRUE == fFoundSection)
798 RETURN pSection;
799 else
800 RETURN NULL;
801}
802
803IMAGE_SECTION_HEADER *PEDecoder::RvaToSection(RVA rva) const
804{
805 CONTRACT(IMAGE_SECTION_HEADER *)
806 {
807 INSTANCE_CHECK;
808 NOTHROW;
809 GC_NOTRIGGER;
810 CANNOT_TAKE_LOCK;
811 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
812 SUPPORTS_DAC;
813 SO_TOLERANT;
814 }
815 CONTRACT_END;
816
817 PTR_IMAGE_SECTION_HEADER section = dac_cast<PTR_IMAGE_SECTION_HEADER>(FindFirstSection(FindNTHeaders()));
818 PTR_IMAGE_SECTION_HEADER sectionEnd = section + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
819
820 while (section < sectionEnd)
821 {
822 if (rva < (VAL32(section->VirtualAddress)
823 + AlignUp((UINT)VAL32(section->Misc.VirtualSize), (UINT)VAL32(FindNTHeaders()->OptionalHeader.SectionAlignment))))
824 {
825 if (rva < VAL32(section->VirtualAddress))
826 RETURN NULL;
827 else
828 {
829 RETURN section;
830 }
831 }
832
833 section++;
834 }
835
836 RETURN NULL;
837}
838
839IMAGE_SECTION_HEADER *PEDecoder::OffsetToSection(COUNT_T fileOffset) const
840{
841 CONTRACT(IMAGE_SECTION_HEADER *)
842 {
843 INSTANCE_CHECK;
844 PRECONDITION(CheckNTHeaders());
845 NOTHROW;
846 GC_NOTRIGGER;
847 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
848 SUPPORTS_DAC;
849 SO_TOLERANT;
850 }
851 CONTRACT_END;
852
853 PTR_IMAGE_SECTION_HEADER section = dac_cast<PTR_IMAGE_SECTION_HEADER>(FindFirstSection(FindNTHeaders()));
854 PTR_IMAGE_SECTION_HEADER sectionEnd = section + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
855
856 while (section < sectionEnd)
857 {
858 if (fileOffset < section->PointerToRawData + section->SizeOfRawData)
859 {
860 if (fileOffset < section->PointerToRawData)
861 RETURN NULL;
862 else
863 RETURN section;
864 }
865
866 section++;
867 }
868
869 RETURN NULL;
870}
871
872TADDR PEDecoder::GetRvaData(RVA rva, IsNullOK ok /*= NULL_NOT_OK*/) const
873{
874 CONTRACT(TADDR)
875 {
876 INSTANCE_CHECK;
877 PRECONDITION(CheckNTHeaders());
878 PRECONDITION(CheckRva(rva, NULL_OK));
879 NOTHROW;
880 GC_NOTRIGGER;
881 SO_TOLERANT;
882 CANNOT_TAKE_LOCK;
883 SUPPORTS_DAC;
884 }
885 CONTRACT_END;
886
887 if ((rva == 0)&&(ok == NULL_NOT_OK))
888 RETURN NULL;
889
890 RVA offset;
891 if (IsMapped())
892 offset = rva;
893 else
894 {
895 // !!! check for case where rva is in padded portion of segment
896 offset = RvaToOffset(rva);
897 }
898
899 RETURN( m_base + offset );
900}
901
902RVA PEDecoder::GetDataRva(const TADDR data) const
903{
904 CONTRACT(RVA)
905 {
906 INSTANCE_CHECK;
907 PRECONDITION(CheckNTHeaders());
908 PRECONDITION(CheckData((void *)data, NULL_OK));
909 NOTHROW;
910 GC_NOTRIGGER;
911 SUPPORTS_DAC;
912 }
913 CONTRACT_END;
914
915 if (data == NULL)
916 RETURN 0;
917
918 COUNT_T offset = (COUNT_T) (data - m_base);
919 if (IsMapped())
920 RETURN offset;
921 else
922 RETURN OffsetToRva(offset);
923}
924
925BOOL PEDecoder::PointerInPE(PTR_CVOID data) const
926{
927 CONTRACTL
928 {
929 INSTANCE_CHECK;
930 NOTHROW;
931 GC_NOTRIGGER;
932 FORBID_FAULT;
933 SO_TOLERANT;
934 SUPPORTS_DAC;
935 }
936 CONTRACTL_END;
937
938 TADDR taddrData = dac_cast<TADDR>(data);
939 TADDR taddrBase = dac_cast<TADDR>(m_base);
940
941 if (this->IsMapped())
942 {
943 return taddrBase <= taddrData && taddrData < taddrBase + GetVirtualSize();
944 }
945 else
946 {
947 return taddrBase <= taddrData && taddrData < taddrBase + GetSize();
948 }
949}
950
951TADDR PEDecoder::GetOffsetData(COUNT_T fileOffset, IsNullOK ok /*= NULL_NOT_OK*/) const
952{
953 CONTRACT(TADDR)
954 {
955 INSTANCE_CHECK;
956 PRECONDITION(CheckNTHeaders());
957 PRECONDITION(CheckOffset(fileOffset, NULL_OK));
958 NOTHROW;
959 GC_NOTRIGGER;
960 }
961 CONTRACT_END;
962
963 if ((fileOffset == 0)&&(ok == NULL_NOT_OK))
964 RETURN NULL;
965
966 RETURN GetRvaData(OffsetToRva(fileOffset));
967}
968
969//-------------------------------------------------------------------------------
970// Lifted from "..\md\inc\mdfileformat.h"
971// (cannot #include it here because it references lot of other stuff)
972#define STORAGE_MAGIC_SIG 0x424A5342 // BSJB
973struct STORAGESIGNATURE
974{
975 ULONG lSignature; // "Magic" signature.
976 USHORT iMajorVer; // Major file version.
977 USHORT iMinorVer; // Minor file version.
978 ULONG iExtraData; // Offset to next structure of information
979 ULONG iVersionString; // Length of version string
980};
981typedef STORAGESIGNATURE UNALIGNED * PSTORAGESIGNATURE;
982typedef DPTR(STORAGESIGNATURE UNALIGNED) PTR_STORAGESIGNATURE;
983
984
985struct STORAGEHEADER
986{
987 BYTE fFlags; // STGHDR_xxx flags.
988 BYTE pad;
989 USHORT iStreams; // How many streams are there.
990};
991typedef STORAGEHEADER UNALIGNED * PSTORAGEHEADER;
992typedef DPTR(STORAGEHEADER UNALIGNED) PTR_STORAGEHEADER;
993
994
995struct STORAGESTREAM
996{
997 ULONG iOffset; // Offset in file for this stream.
998 ULONG iSize; // Size of the file.
999 char rcName[32]; // Start of name, null terminated.
1000};
1001typedef STORAGESTREAM UNALIGNED * PSTORAGESTREAM;
1002typedef DPTR(STORAGESTREAM UNALIGNED) PTR_STORAGESTREAM;
1003
1004
1005// if the stream's name is shorter than 32 bytes (incl.zero terminator),
1006// the size of storage stream header is less than sizeof(STORAGESTREAM)
1007// and is padded to 4-byte alignment
1008inline PTR_STORAGESTREAM NextStorageStream(PTR_STORAGESTREAM pSS)
1009{
1010 CONTRACTL
1011 {
1012 NOTHROW;
1013 GC_NOTRIGGER;
1014 SO_TOLERANT;
1015 CANNOT_TAKE_LOCK;
1016 }
1017 CONTRACTL_END;
1018
1019 SUPPORTS_DAC;
1020 TADDR pc = dac_cast<TADDR>(pSS);
1021 pc += (sizeof(STORAGESTREAM) - 32 /*sizeof(STORAGESTREAM::rcName)*/ + strlen(pSS->rcName)+1+3)&~3;
1022 return PTR_STORAGESTREAM(pc);
1023}
1024//-------------------------------------------------------------------------------
1025
1026
1027CHECK PEDecoder::CheckCorHeader() const
1028{
1029 CONTRACT_CHECK
1030 {
1031 INSTANCE_CHECK;
1032 NOTHROW;
1033 GC_NOTRIGGER;
1034 SUPPORTS_DAC;
1035 SO_TOLERANT;
1036 }
1037 CONTRACT_CHECK_END;
1038
1039 if (m_flags & FLAG_COR_CHECKED)
1040 CHECK_OK;
1041
1042 CHECK(CheckNTHeaders());
1043
1044 CHECK(HasCorHeader());
1045
1046 IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_COMHEADER);
1047
1048 CHECK(CheckDirectory(pDir, IMAGE_SCN_MEM_WRITE, NULL_NOT_OK));
1049
1050 CHECK(VAL32(pDir->Size) >= sizeof(IMAGE_COR20_HEADER));
1051
1052 IMAGE_SECTION_HEADER *section = RvaToSection(VAL32(pDir->VirtualAddress));
1053 CHECK(section != NULL);
1054 CHECK((section->Characteristics & VAL32(IMAGE_SCN_MEM_READ))!=0);
1055
1056 CHECK(CheckRva(VAL32(pDir->VirtualAddress), sizeof(IMAGE_COR20_HEADER)));
1057
1058 IMAGE_COR20_HEADER *pCor = GetCorHeader();
1059
1060 //CHECK(((ULONGLONG)pCor & 0x3)==0);
1061
1062 // If the file is COM+ 1.0, which by definition has nothing the runtime can
1063 // use, or if the file requires a newer version of this engine than us,
1064 // it cannot be run by this engine.
1065 CHECK(VAL16(pCor->MajorRuntimeVersion) > 1 && VAL16(pCor->MajorRuntimeVersion) <= COR_VERSION_MAJOR);
1066
1067 CHECK(CheckDirectory(&pCor->MetaData, IMAGE_SCN_MEM_WRITE, HasNativeHeader() ? NULL_OK : NULL_NOT_OK));
1068 CHECK(CheckDirectory(&pCor->Resources, IMAGE_SCN_MEM_WRITE, NULL_OK));
1069 CHECK(CheckDirectory(&pCor->StrongNameSignature, IMAGE_SCN_MEM_WRITE, NULL_OK));
1070 CHECK(CheckDirectory(&pCor->CodeManagerTable, IMAGE_SCN_MEM_WRITE, NULL_OK));
1071 CHECK(CheckDirectory(&pCor->VTableFixups, 0, NULL_OK));
1072 CHECK(CheckDirectory(&pCor->ExportAddressTableJumps, 0, NULL_OK));
1073 CHECK(CheckDirectory(&pCor->ManagedNativeHeader, 0, NULL_OK));
1074
1075 CHECK(VAL32(pCor->cb) >= offsetof(IMAGE_COR20_HEADER, ManagedNativeHeader) + sizeof(IMAGE_DATA_DIRECTORY));
1076
1077 DWORD validBits = COMIMAGE_FLAGS_ILONLY
1078 | COMIMAGE_FLAGS_32BITREQUIRED
1079 | COMIMAGE_FLAGS_TRACKDEBUGDATA
1080 | COMIMAGE_FLAGS_STRONGNAMESIGNED
1081 | COMIMAGE_FLAGS_NATIVE_ENTRYPOINT
1082 | COMIMAGE_FLAGS_IL_LIBRARY
1083 | COMIMAGE_FLAGS_32BITPREFERRED;
1084
1085 CHECK((pCor->Flags&VAL32(~validBits)) == 0);
1086
1087 // Pure IL images should not have VTable fixups or EAT jumps
1088 if (IsILOnly())
1089 {
1090 CHECK(pCor->VTableFixups.Size == VAL32(0));
1091 CHECK(pCor->ExportAddressTableJumps.Size == VAL32(0));
1092 CHECK(!(pCor->Flags & VAL32(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT)));
1093 //@TODO: If not an exe, check that EntryPointToken is mdNil
1094 }
1095 else
1096 {
1097 if (pCor->Flags & VAL32(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT))
1098 {
1099 CHECK(CheckRva(VAL32(IMAGE_COR20_HEADER_FIELD(*pCor,EntryPointToken))));
1100 }
1101 }
1102
1103 // Strong name signed images should have a signature
1104 if (IsStrongNameSigned())
1105 CHECK(HasStrongNameSignature());
1106
1107 // IL library files (really a misnomer - these are native images or ReadyToRun images)
1108 // only they can have a native image header
1109 if ((pCor->Flags&VAL32(COMIMAGE_FLAGS_IL_LIBRARY)) == 0)
1110 {
1111 CHECK(VAL32(pCor->ManagedNativeHeader.Size) == 0);
1112 }
1113
1114 // Metadata header checks
1115 IMAGE_DATA_DIRECTORY *pDirMD = &pCor->MetaData;
1116 COUNT_T ctMD = (COUNT_T)VAL32(pDirMD->Size);
1117 TADDR pcMD = (TADDR)GetDirectoryData(pDirMD);
1118
1119 if(pcMD != NULL)
1120 {
1121 // Storage signature checks
1122 CHECK(ctMD >= sizeof(STORAGESIGNATURE));
1123 PTR_STORAGESIGNATURE pStorageSig = PTR_STORAGESIGNATURE((TADDR)pcMD);
1124 COUNT_T ctMDStreamSize = ctMD; // Store MetaData stream size for later usage
1125
1126
1127 CHECK(VAL32(pStorageSig->lSignature) == STORAGE_MAGIC_SIG);
1128 COUNT_T ctSSig;
1129 CHECK(ClrSafeInt<COUNT_T>::addition(sizeof(STORAGESIGNATURE), (COUNT_T)VAL32(pStorageSig->iVersionString), ctSSig));
1130 CHECK(ctMD > ctSSig);
1131
1132 // Storage header checks
1133 pcMD += ctSSig;
1134
1135 PTR_STORAGEHEADER pSHdr = PTR_STORAGEHEADER((TADDR)pcMD);
1136
1137
1138 ctMD -= ctSSig;
1139 CHECK(ctMD >= sizeof(STORAGEHEADER));
1140 pcMD = dac_cast<TADDR>(pSHdr) + sizeof(STORAGEHEADER);
1141 ctMD -= sizeof(STORAGEHEADER);
1142 WORD nStreams = VAL16(pSHdr->iStreams);
1143
1144 // Storage streams checks (pcMD is a target pointer, so watch out)
1145 PTR_STORAGESTREAM pStr = PTR_STORAGESTREAM((TADDR)pcMD);
1146 PTR_STORAGESTREAM pSSOutOfRange =
1147 PTR_STORAGESTREAM((TADDR)(pcMD + ctMD));
1148 size_t namelen;
1149 WORD iStr;
1150 PTR_STORAGESTREAM pSS;
1151 for(iStr = 1, pSS = pStr; iStr <= nStreams; iStr++)
1152 {
1153 CHECK(pSS < pSSOutOfRange);
1154 CHECK(pSS + 1 <= pSSOutOfRange);
1155
1156 for(namelen=0; (namelen<32)&&(pSS->rcName[namelen]!=0); namelen++);
1157 CHECK((0 < namelen)&&(namelen < 32));
1158
1159 // Is it ngen image?
1160 if (!HasNativeHeader())
1161 {
1162 // Forbid HOT_MODEL_STREAM for non-ngen images
1163 CHECK(strcmp(pSS->rcName, HOT_MODEL_STREAM_A) != 0);
1164 }
1165
1166 pcMD = dac_cast<TADDR>(NextStorageStream(pSS));
1167 ctMD -= (COUNT_T)(pcMD - dac_cast<TADDR>(pSS));
1168
1169 pSS = PTR_STORAGESTREAM((TADDR)pcMD);
1170 }
1171
1172 // At this moment, pcMD is pointing past the last stream header
1173 // and ctMD contains total size left for streams per se
1174 // Now, check the offsets and sizes of streams
1175 COUNT_T ctStreamsBegin = (COUNT_T)(pcMD - dac_cast<TADDR>(pStorageSig)); // min.possible offset
1176 COUNT_T ctSS, ctSSbegin, ctSSend = 0;
1177 for(iStr = 1, pSS = pStr; iStr <= nStreams; iStr++,pSS = NextStorageStream(pSS))
1178 {
1179 ctSSbegin = (COUNT_T)VAL32(pSS->iOffset);
1180 CHECK(ctStreamsBegin <= ctSSbegin);
1181 CHECK(ctSSbegin < ctMDStreamSize);
1182
1183 ctSS = (COUNT_T)VAL32(pSS->iSize);
1184 CHECK(ctMD >= ctSS);
1185 CHECK(ClrSafeInt<COUNT_T>::addition(ctSSbegin, ctSS, ctSSend));
1186 CHECK(ctSSend <= ctMDStreamSize);
1187 ctMD -= ctSS;
1188
1189 // Check stream overlap
1190 PTR_STORAGESTREAM pSSprior;
1191 for(pSSprior=pStr; pSSprior < pSS; pSSprior = NextStorageStream(pSSprior))
1192 {
1193 COUNT_T ctSSprior_end = 0;
1194 CHECK(ClrSafeInt<COUNT_T>::addition((COUNT_T)VAL32(pSSprior->iOffset), (COUNT_T)VAL32(pSSprior->iSize), ctSSprior_end));
1195 CHECK((ctSSbegin >= ctSSprior_end)||(ctSSend <= (COUNT_T)VAL32(pSSprior->iOffset)));
1196 }
1197 }
1198 } //end if(pcMD != NULL)
1199
1200 const_cast<PEDecoder *>(this)->m_flags |= FLAG_COR_CHECKED;
1201
1202 CHECK_OK;
1203}
1204
1205
1206
1207// This function exists to provide compatibility between two different native image
1208// (NGEN) formats. In particular, the manifest metadata blob and the full metadata
1209// blob swapped locations from 3.5RTM to 3.5SP1. The logic here is to look at the
1210// runtime version embedded in the native image, to determine which format it is.
1211IMAGE_DATA_DIRECTORY *PEDecoder::GetMetaDataHelper(METADATA_SECTION_TYPE type) const
1212{
1213 CONTRACT(IMAGE_DATA_DIRECTORY *)
1214 {
1215 INSTANCE_CHECK;
1216 PRECONDITION(CheckCorHeader());
1217#ifdef FEATURE_PREJIT
1218 PRECONDITION(type == METADATA_SECTION_FULL || type == METADATA_SECTION_MANIFEST);
1219 PRECONDITION(type != METADATA_SECTION_MANIFEST || HasNativeHeader());
1220#else // FEATURE_PREJIT
1221 PRECONDITION(type == METADATA_SECTION_FULL);
1222#endif // FEATURE_PREJIT
1223 NOTHROW;
1224 GC_NOTRIGGER;
1225 SUPPORTS_DAC;
1226 }
1227 CONTRACT_END;
1228
1229 IMAGE_DATA_DIRECTORY *pDirRet = &GetCorHeader()->MetaData;
1230
1231#ifdef FEATURE_PREJIT
1232 // For backward compatibility reasons, we must be able to locate the metadata in all v2 native images as
1233 // well as current version of native images. This is needed by mdbg.exe for SxS debugging scenarios.
1234 // Specifically, mdbg.exe can be used to debug v2 managed applications, and need to be able to find
1235 // metadata in v2 native images. Therefore, the location of the data we need to locate the metadata must
1236 // never be moved. Here are some asserts to ensure that.
1237 // IMAGE_COR20_HEADER should be stable since it is defined in ECMA. Verify a coupld of fields we use:
1238 _ASSERTE(offsetof(IMAGE_COR20_HEADER, MetaData) == 8);
1239 _ASSERTE(offsetof(IMAGE_COR20_HEADER, ManagedNativeHeader) == 64);
1240 // We use a couple of fields in CORCOMPILE_HEADER.
1241 _ASSERTE(offsetof(CORCOMPILE_HEADER, VersionInfo) == 40);
1242 _ASSERTE(offsetof(CORCOMPILE_HEADER, ManifestMetaData) == 88);
1243 // And we use four version fields in CORCOMPILE_VERSION_INFO.
1244 _ASSERTE(offsetof(CORCOMPILE_VERSION_INFO, wVersionMajor) == 4);
1245 _ASSERTE(offsetof(CORCOMPILE_VERSION_INFO, wVersionMinor) == 6);
1246 _ASSERTE(offsetof(CORCOMPILE_VERSION_INFO, wVersionBuildNumber) == 8);
1247 _ASSERTE(offsetof(CORCOMPILE_VERSION_INFO, wVersionPrivateBuildNumber) == 10);
1248
1249 // Visual Studio took dependency on crossgen /CreatePDB returning COR_E_NI_AND_RUNTIME_VERSION_MISMATCH
1250 // when crossgen and the native image come from different runtimes. In order to reach error path that returns
1251 // COR_E_NI_AND_RUNTIME_VERSION_MISMATCH in this case, size of CORCOMPILE_HEADER has to remain constant,
1252 // and the offset of PEKind and Machine fields inside CORCOMPILE_HEADER also have to remain constant, to pass earlier
1253 // checks that lead to different error codes. See Windows Phone Blue Bug #45406 for details.
1254 _ASSERTE(sizeof(CORCOMPILE_HEADER) == 160 + sizeof(TADDR));
1255 _ASSERTE(offsetof(CORCOMPILE_HEADER, PEKind) == 108 + sizeof(TADDR));
1256 _ASSERTE(offsetof(CORCOMPILE_HEADER, Machine) == 116 + sizeof(TADDR));
1257
1258 // Handle NGEN format; otherwise, there is only one MetaData section in the
1259 // COR_HEADER and so the value of pDirRet is correct
1260 if (HasNativeHeader())
1261 {
1262
1263 if (type == METADATA_SECTION_MANIFEST)
1264 pDirRet = &GetNativeHeader()->ManifestMetaData;
1265
1266
1267 }
1268
1269#endif // FEATURE_PREJIT
1270
1271 RETURN pDirRet;
1272}
1273
1274PTR_CVOID PEDecoder::GetMetadata(COUNT_T *pSize) const
1275{
1276 CONTRACT(PTR_CVOID)
1277 {
1278 INSTANCE_CHECK;
1279 PRECONDITION(CheckCorHeader());
1280 PRECONDITION(CheckPointer(pSize, NULL_OK));
1281 NOTHROW;
1282 GC_NOTRIGGER;
1283 SUPPORTS_DAC;
1284 }
1285 CONTRACT_END;
1286
1287 IMAGE_DATA_DIRECTORY *pDir = GetMetaDataHelper(METADATA_SECTION_FULL);
1288
1289 if (pSize != NULL)
1290 *pSize = VAL32(pDir->Size);
1291
1292 RETURN dac_cast<PTR_VOID>(GetDirectoryData(pDir));
1293}
1294
1295const void *PEDecoder::GetResources(COUNT_T *pSize) const
1296{
1297 CONTRACT(const void *)
1298 {
1299 INSTANCE_CHECK;
1300 PRECONDITION(CheckCorHeader());
1301 PRECONDITION(CheckPointer(pSize, NULL_OK));
1302 NOTHROW;
1303 GC_NOTRIGGER;
1304 }
1305 CONTRACT_END;
1306
1307 IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->Resources;
1308
1309 if (pSize != NULL)
1310 *pSize = VAL32(pDir->Size);
1311
1312 RETURN (void *)GetDirectoryData(pDir);
1313}
1314
1315CHECK PEDecoder::CheckResource(COUNT_T offset) const
1316{
1317 CONTRACT_CHECK
1318 {
1319 INSTANCE_CHECK;
1320 NOTHROW;
1321 GC_NOTRIGGER;
1322 PRECONDITION(CheckCorHeader());
1323 }
1324 CONTRACT_CHECK_END;
1325
1326 IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->Resources;
1327
1328 CHECK(CheckOverflow(VAL32(pDir->VirtualAddress), offset));
1329
1330 RVA rva = VAL32(pDir->VirtualAddress) + offset;
1331
1332 // Make sure we have at least enough data for a length
1333 CHECK(CheckRva(rva, sizeof(DWORD)));
1334
1335 // Make sure resource is within resource section
1336 CHECK(CheckBounds(VAL32(pDir->VirtualAddress), VAL32(pDir->Size),
1337 rva + sizeof(DWORD), GET_UNALIGNED_VAL32((LPVOID)GetRvaData(rva))));
1338
1339 CHECK_OK;
1340}
1341
1342const void *PEDecoder::GetResource(COUNT_T offset, COUNT_T *pSize) const
1343{
1344 CONTRACT(const void *)
1345 {
1346 INSTANCE_CHECK;
1347 PRECONDITION(CheckCorHeader());
1348 PRECONDITION(CheckPointer(pSize, NULL_OK));
1349 NOTHROW;
1350 GC_NOTRIGGER;
1351 }
1352 CONTRACT_END;
1353
1354 IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->Resources;
1355
1356 // 403571: Prefix complained correctly about need to always perform rva check
1357 if (CheckResource(offset) == FALSE)
1358 return NULL;
1359
1360 void * resourceBlob = (void *)GetRvaData(VAL32(pDir->VirtualAddress) + offset);
1361 // Holds if CheckResource(offset) == TRUE
1362 PREFIX_ASSUME(resourceBlob != NULL);
1363
1364 if (pSize != NULL)
1365 *pSize = GET_UNALIGNED_VAL32(resourceBlob);
1366
1367 RETURN (const void *) ((BYTE*)resourceBlob+sizeof(DWORD));
1368}
1369
1370BOOL PEDecoder::HasManagedEntryPoint() const
1371{
1372 CONTRACTL {
1373 INSTANCE_CHECK;
1374 PRECONDITION(CheckCorHeader());
1375 NOTHROW;
1376 GC_NOTRIGGER;
1377 } CONTRACTL_END;
1378
1379 ULONG flags = GetCorHeader()->Flags;
1380 return (!(flags & VAL32(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT)) &&
1381 (!IsNilToken(GetEntryPointToken())));
1382}
1383
1384ULONG PEDecoder::GetEntryPointToken() const
1385{
1386 CONTRACT(ULONG)
1387 {
1388 INSTANCE_CHECK;
1389 PRECONDITION(CheckCorHeader());
1390 NOTHROW;
1391 GC_NOTRIGGER;
1392 }
1393 CONTRACT_END;
1394
1395 RETURN VAL32(IMAGE_COR20_HEADER_FIELD(*GetCorHeader(), EntryPointToken));
1396}
1397
1398IMAGE_COR_VTABLEFIXUP *PEDecoder::GetVTableFixups(COUNT_T *pCount) const
1399{
1400 CONTRACT(IMAGE_COR_VTABLEFIXUP *)
1401 {
1402 INSTANCE_CHECK;
1403 PRECONDITION(CheckCorHeader());
1404 NOTHROW;
1405 GC_NOTRIGGER;
1406 }
1407 CONTRACT_END;
1408 IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->VTableFixups;
1409
1410 if (pCount != NULL)
1411 *pCount = VAL32(pDir->Size)/sizeof(IMAGE_COR_VTABLEFIXUP);
1412
1413 RETURN PTR_IMAGE_COR_VTABLEFIXUP(GetDirectoryData(pDir));
1414}
1415
1416CHECK PEDecoder::CheckILOnly() const
1417{
1418 CONTRACT_CHECK
1419 {
1420 INSTANCE_CHECK;
1421 NOTHROW;
1422 GC_NOTRIGGER;
1423 }
1424 CONTRACT_CHECK_END;
1425
1426 if (m_flags & FLAG_IL_ONLY_CHECKED)
1427 CHECK_OK;
1428
1429 CHECK(CheckCorHeader());
1430
1431
1432 // Allow only verifiable directories.
1433
1434 static int s_allowedBitmap =
1435 ((1 << (IMAGE_DIRECTORY_ENTRY_IMPORT )) |
1436 (1 << (IMAGE_DIRECTORY_ENTRY_RESOURCE )) |
1437 (1 << (IMAGE_DIRECTORY_ENTRY_SECURITY )) |
1438 (1 << (IMAGE_DIRECTORY_ENTRY_BASERELOC)) |
1439 (1 << (IMAGE_DIRECTORY_ENTRY_DEBUG )) |
1440 (1 << (IMAGE_DIRECTORY_ENTRY_IAT )) |
1441 (1 << (IMAGE_DIRECTORY_ENTRY_COMHEADER)));
1442
1443
1444
1445
1446 for (UINT32 entry=0; entry<GetNumberOfRvaAndSizes(); ++entry)
1447 {
1448 if (Has32BitNTHeaders())
1449 CheckBounds(dac_cast<PTR_CVOID>(&GetNTHeaders32()->OptionalHeader),
1450 GetNTHeaders32()->FileHeader.SizeOfOptionalHeader,
1451 dac_cast<PTR_CVOID>(GetNTHeaders32()->OptionalHeader.DataDirectory + entry),
1452 sizeof(IMAGE_DATA_DIRECTORY));
1453 else
1454 CheckBounds(dac_cast<PTR_CVOID>(&GetNTHeaders64()->OptionalHeader),
1455 GetNTHeaders32()->FileHeader.SizeOfOptionalHeader,
1456 dac_cast<PTR_CVOID>(GetNTHeaders64()->OptionalHeader.DataDirectory + entry),
1457 sizeof(IMAGE_DATA_DIRECTORY));
1458
1459 if (HasDirectoryEntry(entry))
1460 {
1461 CHECK((s_allowedBitmap & (1 << entry)) != 0);
1462 if (entry!=IMAGE_DIRECTORY_ENTRY_SECURITY) //ignored by OS loader
1463 CHECK(CheckDirectoryEntry(entry,IMAGE_SCN_MEM_SHARED,NULL_NOT_OK));
1464 }
1465 }
1466 if (HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT) ||
1467 HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC) ||
1468 FindNTHeaders()->OptionalHeader.AddressOfEntryPoint != 0)
1469 {
1470 // When the image is LoadLibrary'd, we whack the import, IAT directories and the entrypoint. We have to relax
1471 // the verification for mapped images. Ideally, we would only do it for a post-LoadLibrary image.
1472 if (!IsMapped() || (HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT) || HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC)))
1473 {
1474 CHECK(CheckILOnlyImportDlls());
1475 CHECK(CheckILOnlyBaseRelocations());
1476 }
1477
1478#ifdef _TARGET_X86_
1479 if (!IsMapped())
1480 {
1481 CHECK(CheckILOnlyEntryPoint());
1482 }
1483#endif
1484 }
1485
1486 // Check some section characteristics
1487 IMAGE_NT_HEADERS *pNT = FindNTHeaders();
1488 IMAGE_SECTION_HEADER *section = FindFirstSection(pNT);
1489 IMAGE_SECTION_HEADER *sectionEnd = section + VAL16(pNT->FileHeader.NumberOfSections);
1490 while (section < sectionEnd)
1491 {
1492 // Don't allow shared sections for IL-only images
1493 CHECK(!(section->Characteristics & IMAGE_SCN_MEM_SHARED));
1494
1495 // Be sure that we have some access to the section. Note that this test assumes that
1496 // execute or write permissions will also let us read the section. If that is found to be an
1497 // incorrect assumption, this will need to be modified.
1498 CHECK((section->Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) != 0);
1499 section++;
1500 }
1501
1502 // For EXE, check that OptionalHeader.Win32VersionValue is zero. When this value is non-zero, GetVersionEx
1503 // returns PE supplied values, rather than native OS values; the runtime relies on knowing the actual
1504 // OS version.
1505 if (!IsDll())
1506 {
1507 CHECK(GetWin32VersionValue() == 0);
1508 }
1509
1510
1511 const_cast<PEDecoder *>(this)->m_flags |= FLAG_IL_ONLY_CHECKED;
1512
1513 CHECK_OK;
1514}
1515
1516
1517CHECK PEDecoder::CheckILOnlyImportDlls() const
1518{
1519 CONTRACT_CHECK
1520 {
1521 INSTANCE_CHECK;
1522 PRECONDITION(CheckNTHeaders());
1523 NOTHROW;
1524 GC_NOTRIGGER;
1525 }
1526 CONTRACT_CHECK_END;
1527
1528 // The only allowed DLL Imports are MscorEE.dll:_CorExeMain,_CorDllMain
1529
1530#ifdef _WIN64
1531 // On win64, when the image is LoadLibrary'd, we whack the import and IAT directories. We have to relax
1532 // the verification for mapped images. Ideally, we would only do it for a post-LoadLibrary image.
1533 if (IsMapped() && !HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT))
1534 CHECK_OK;
1535#endif
1536
1537 CHECK(HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT));
1538 CHECK(CheckDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_SCN_MEM_WRITE));
1539
1540 // Get the import directory entry
1541 PIMAGE_DATA_DIRECTORY pDirEntryImport = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT);
1542 CHECK(pDirEntryImport != NULL);
1543 PREFIX_ASSUME(pDirEntryImport != NULL);
1544
1545 // There should be space for 2 entries. (mscoree and NULL)
1546 CHECK(VAL32(pDirEntryImport->Size) >= (2 * sizeof(IMAGE_IMPORT_DESCRIPTOR)));
1547
1548 // Get the import data
1549 PIMAGE_IMPORT_DESCRIPTOR pID = (PIMAGE_IMPORT_DESCRIPTOR) GetDirectoryData(pDirEntryImport);
1550 CHECK(pID != NULL);
1551 PREFIX_ASSUME(pID != NULL);
1552
1553 // Entry 0: ILT, Name, IAT must be be non-null. Forwarder, DateTime should be NULL.
1554 CHECK( IMAGE_IMPORT_DESC_FIELD(pID[0], Characteristics) != 0
1555 && pID[0].TimeDateStamp == 0
1556 && (pID[0].ForwarderChain == 0 || pID[0].ForwarderChain == static_cast<ULONG>(-1))
1557 && pID[0].Name != 0
1558 && pID[0].FirstThunk != 0);
1559
1560 // Entry 1: must be all nulls.
1561 CHECK( IMAGE_IMPORT_DESC_FIELD(pID[1], Characteristics) == 0
1562 && pID[1].TimeDateStamp == 0
1563 && pID[1].ForwarderChain == 0
1564 && pID[1].Name == 0
1565 && pID[1].FirstThunk == 0);
1566
1567 // Ensure the RVA of the name plus its length is valid for this image
1568 UINT nameRVA = VAL32(pID[0].Name);
1569 CHECK(CheckRva(nameRVA, (COUNT_T) sizeof("mscoree.dll")));
1570
1571 // Make sure the name is equal to mscoree
1572 CHECK(SString::_stricmp( (char *)GetRvaData(nameRVA), "mscoree.dll") == 0);
1573
1574 // Check the Hint/Name table.
1575 CHECK(CheckILOnlyImportByNameTable(VAL32(IMAGE_IMPORT_DESC_FIELD(pID[0], OriginalFirstThunk))));
1576
1577 // The IAT needs to be checked only for size.
1578 CHECK(CheckRva(VAL32(pID[0].FirstThunk), 2*sizeof(UINT32)));
1579
1580 CHECK_OK;
1581}
1582
1583CHECK PEDecoder::CheckILOnlyImportByNameTable(RVA rva) const
1584{
1585 CONTRACT_CHECK
1586 {
1587 INSTANCE_CHECK;
1588 PRECONDITION(CheckNTHeaders());
1589 NOTHROW;
1590 GC_NOTRIGGER;
1591 }
1592 CONTRACT_CHECK_END;
1593
1594 // Check if we have enough space to hold 2 DWORDS
1595 CHECK(CheckRva(rva, 2*sizeof(UINT32)));
1596
1597 UINT32 UNALIGNED *pImportArray = (UINT32 UNALIGNED *) GetRvaData(rva);
1598
1599 CHECK(GET_UNALIGNED_VAL32(&pImportArray[0]) != 0);
1600 CHECK(GET_UNALIGNED_VAL32(&pImportArray[1]) == 0);
1601
1602 UINT32 importRVA = GET_UNALIGNED_VAL32(&pImportArray[0]);
1603
1604 // First bit Set implies Ordinal lookup
1605 CHECK((importRVA & 0x80000000) == 0);
1606
1607#define DLL_NAME "_CorDllMain"
1608#define EXE_NAME "_CorExeMain"
1609
1610 static_assert_no_msg(sizeof(DLL_NAME) == sizeof(EXE_NAME));
1611
1612 // Check if we have enough space to hold 2 bytes +
1613 // _CorExeMain or _CorDllMain and a NULL char
1614 CHECK(CheckRva(importRVA, offsetof(IMAGE_IMPORT_BY_NAME, Name) + sizeof(DLL_NAME)));
1615
1616 IMAGE_IMPORT_BY_NAME *import = (IMAGE_IMPORT_BY_NAME*) GetRvaData(importRVA);
1617
1618 CHECK(SString::_stricmp((char *) import->Name, DLL_NAME) == 0 || _stricmp((char *) import->Name, EXE_NAME) == 0);
1619
1620 CHECK_OK;
1621}
1622
1623#ifdef _TARGET_X86_
1624// jmp dword ptr ds:[XXXX]
1625#define JMP_DWORD_PTR_DS_OPCODE { 0xFF, 0x25 }
1626#define JMP_DWORD_PTR_DS_OPCODE_SIZE 2 // Size of opcode
1627#define JMP_SIZE 6 // Size of opcode + operand
1628#endif
1629
1630CHECK PEDecoder::CheckILOnlyBaseRelocations() const
1631{
1632 CONTRACT_CHECK
1633 {
1634 INSTANCE_CHECK;
1635 PRECONDITION(CheckNTHeaders());
1636 NOTHROW;
1637 GC_NOTRIGGER;
1638 }
1639 CONTRACT_CHECK_END;
1640
1641 if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC))
1642 {
1643 // We require base relocs for dlls.
1644 CHECK(!IsDll());
1645
1646 CHECK((FindNTHeaders()->FileHeader.Characteristics & VAL16(IMAGE_FILE_RELOCS_STRIPPED)) != 0);
1647 }
1648 else
1649 {
1650 CHECK((FindNTHeaders()->FileHeader.Characteristics & VAL16(IMAGE_FILE_RELOCS_STRIPPED)) == 0);
1651
1652 CHECK(CheckDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC, IMAGE_SCN_MEM_WRITE));
1653
1654 IMAGE_DATA_DIRECTORY *pRelocDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_BASERELOC);
1655
1656 IMAGE_SECTION_HEADER *section = RvaToSection(VAL32(pRelocDir->VirtualAddress));
1657 CHECK(section != NULL);
1658 CHECK((section->Characteristics & VAL32(IMAGE_SCN_MEM_READ))!=0);
1659
1660 IMAGE_BASE_RELOCATION *pReloc = (IMAGE_BASE_RELOCATION *)
1661 GetRvaData(VAL32(pRelocDir->VirtualAddress));
1662
1663 // 403569: PREfix correctly complained about pReloc being possibly NULL
1664 CHECK(pReloc != NULL);
1665 CHECK(VAL32(pReloc->SizeOfBlock) == VAL32(pRelocDir->Size));
1666
1667 UINT16 *pRelocEntry = (UINT16 *) (pReloc + 1);
1668 UINT16 *pRelocEntryEnd = (UINT16 *) ((BYTE *) pReloc + VAL32(pReloc->SizeOfBlock));
1669 if(FindNTHeaders()->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_IA64))
1670 {
1671 // Exactly 2 Reloc records, both IMAGE_REL_BASED_DIR64
1672 CHECK(VAL32(pReloc->SizeOfBlock) >= (sizeof(IMAGE_BASE_RELOCATION)+2*sizeof(UINT16)));
1673 CHECK((VAL16(pRelocEntry[0]) & 0xF000) == (IMAGE_REL_BASED_DIR64 << 12));
1674 pRelocEntry++;
1675 CHECK((VAL16(pRelocEntry[0]) & 0xF000) == (IMAGE_REL_BASED_DIR64 << 12));
1676 }
1677 else
1678 {
1679 // Only one Reloc record is expected
1680 CHECK(VAL32(pReloc->SizeOfBlock) >= (sizeof(IMAGE_BASE_RELOCATION)+sizeof(UINT16)));
1681 if(FindNTHeaders()->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_AMD64))
1682 CHECK((VAL16(pRelocEntry[0]) & 0xF000) == (IMAGE_REL_BASED_DIR64 << 12));
1683 else
1684 CHECK((VAL16(pRelocEntry[0]) & 0xF000) == (IMAGE_REL_BASED_HIGHLOW << 12));
1685 }
1686
1687 while (++pRelocEntry < pRelocEntryEnd)
1688 {
1689 // NULL padding entries are allowed
1690 CHECK((VAL16(pRelocEntry[0]) & 0xF000) == IMAGE_REL_BASED_ABSOLUTE);
1691 }
1692 }
1693
1694 CHECK_OK;
1695}
1696
1697#ifdef _TARGET_X86_
1698CHECK PEDecoder::CheckILOnlyEntryPoint() const
1699{
1700 CONTRACT_CHECK
1701 {
1702 INSTANCE_CHECK;
1703 PRECONDITION(CheckNTHeaders());
1704 NOTHROW;
1705 GC_NOTRIGGER;
1706 }
1707 CONTRACT_CHECK_END;
1708
1709 CHECK(FindNTHeaders()->OptionalHeader.AddressOfEntryPoint != 0);
1710
1711 if(FindNTHeaders()->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_I386))
1712 {
1713 // EntryPoint should be a jmp dword ptr ds:[XXXX] instruction.
1714 // XXXX should be RVA of the first and only entry in the IAT.
1715
1716 CHECK(CheckRva(VAL32(FindNTHeaders()->OptionalHeader.AddressOfEntryPoint), JMP_SIZE));
1717
1718 BYTE *stub = (BYTE *) GetRvaData(VAL32(FindNTHeaders()->OptionalHeader.AddressOfEntryPoint));
1719
1720 static const BYTE s_DllOrExeMain[] = JMP_DWORD_PTR_DS_OPCODE;
1721
1722 // 403570: prefix complained about stub being possibly NULL.
1723 // Unsure here. PREFIX_ASSUME might be also correct as indices are
1724 // verified in the above CHECK statement.
1725 CHECK(stub != NULL);
1726 CHECK(memcmp(stub, s_DllOrExeMain, JMP_DWORD_PTR_DS_OPCODE_SIZE) == 0);
1727
1728 // Verify target of jump - it should be first entry in the IAT.
1729
1730 PIMAGE_IMPORT_DESCRIPTOR pID =
1731 (PIMAGE_IMPORT_DESCRIPTOR) GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_IMPORT);
1732
1733 UINT32 va = * (UINT32 *) (stub + JMP_DWORD_PTR_DS_OPCODE_SIZE);
1734
1735 CHECK(VAL32(pID[0].FirstThunk) == (va - (SIZE_T) GetPreferredBase()));
1736 }
1737
1738 CHECK_OK;
1739}
1740#endif // _TARGET_X86_
1741
1742#ifndef DACCESS_COMPILE
1743
1744void PEDecoder::LayoutILOnly(void *base, BOOL allowFullPE) const
1745{
1746 CONTRACT_VOID
1747 {
1748 INSTANCE_CHECK;
1749 PRECONDITION(allowFullPE || CheckILOnlyFormat());
1750 PRECONDITION(CheckZeroedMemory(base, VAL32(FindNTHeaders()->OptionalHeader.SizeOfImage)));
1751 // Ideally we would require the layout address to honor the section alignment constraints.
1752 // However, we do have 8K aligned IL only images which we load on 32 bit platforms. In this
1753 // case, we can only guarantee OS page alignment (which after all, is good enough.)
1754 PRECONDITION(CheckAligned((SIZE_T)base, GetOsPageSize()));
1755 THROWS;
1756 GC_NOTRIGGER;
1757 }
1758 CONTRACT_END;
1759
1760 // We're going to copy everything first, and write protect what we need to later.
1761
1762 // First, copy headers
1763 CopyMemory(base, (void *)m_base, VAL32(FindNTHeaders()->OptionalHeader.SizeOfHeaders));
1764
1765 // Now, copy all sections to appropriate virtual address
1766
1767 IMAGE_SECTION_HEADER *sectionStart = IMAGE_FIRST_SECTION(FindNTHeaders());
1768 IMAGE_SECTION_HEADER *sectionEnd = sectionStart + VAL16(FindNTHeaders()->FileHeader.NumberOfSections);
1769
1770 IMAGE_SECTION_HEADER *section = sectionStart;
1771 while (section < sectionEnd)
1772 {
1773 // Raw data may be less than section size if tail is zero, but may be more since VirtualSize is
1774 // not padded.
1775 DWORD size = min(VAL32(section->SizeOfRawData), VAL32(section->Misc.VirtualSize));
1776
1777 CopyMemory((BYTE *) base + VAL32(section->VirtualAddress), (BYTE *) m_base + VAL32(section->PointerToRawData), size);
1778
1779 // Note that our memory is zeroed already, so no need to initialize any tail.
1780
1781 section++;
1782 }
1783
1784 // Apply write protection to copied headers
1785 DWORD oldProtection;
1786 if (!ClrVirtualProtect((void *) base, VAL32(FindNTHeaders()->OptionalHeader.SizeOfHeaders),
1787 PAGE_READONLY, &oldProtection))
1788 ThrowLastError();
1789
1790 // Finally, apply proper protection to copied sections
1791 section = sectionStart;
1792 while (section < sectionEnd)
1793 {
1794 // Add appropriate page protection.
1795 if ((section->Characteristics & VAL32(IMAGE_SCN_MEM_WRITE)) == 0)
1796 {
1797 if (!ClrVirtualProtect((void *) ((BYTE *)base + VAL32(section->VirtualAddress)),
1798 VAL32(section->Misc.VirtualSize),
1799 PAGE_READONLY, &oldProtection))
1800 ThrowLastError();
1801 }
1802
1803 section++;
1804 }
1805
1806 RETURN;
1807}
1808
1809#endif // #ifndef DACCESS_COMPILE
1810
1811#ifndef FEATURE_PAL
1812void * PEDecoder::GetWin32Resource(LPCWSTR lpName, LPCWSTR lpType, COUNT_T *pSize /*=NULL*/) const
1813{
1814 CONTRACTL {
1815 INSTANCE_CHECK;
1816 PRECONDITION(IsMapped());
1817 NOTHROW;
1818 GC_NOTRIGGER;
1819 } CONTRACTL_END;
1820
1821 if (pSize != NULL)
1822 *pSize = 0;
1823
1824 HMODULE hModule = (HMODULE) dac_cast<TADDR>(GetBase());
1825
1826 // Use the Win32 functions to decode the resources
1827
1828 HRSRC hResource = WszFindResourceEx(hModule, lpType, lpName, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
1829 if (!hResource)
1830 return NULL;
1831
1832 HGLOBAL hLoadedResource = ::LoadResource(hModule, hResource);
1833 if (!hLoadedResource)
1834 return NULL;
1835
1836 PVOID pResource = ::LockResource(hLoadedResource);
1837 if (!pResource)
1838 return NULL;
1839
1840 if (pSize != NULL)
1841 *pSize = ::SizeofResource(hModule, hResource);
1842
1843 return pResource;
1844}
1845#endif // FEATURE_PAL
1846
1847BOOL PEDecoder::HasNativeHeader() const
1848{
1849 CONTRACT(BOOL)
1850 {
1851 INSTANCE_CHECK;
1852 NOTHROW;
1853 GC_NOTRIGGER;
1854 SUPPORTS_DAC;
1855 SO_TOLERANT;
1856 }
1857 CONTRACT_END;
1858
1859#ifdef FEATURE_PREJIT
1860 // Pretend that ready-to-run images do not have native header
1861 RETURN (GetCorHeader() && ((GetCorHeader()->Flags & VAL32(COMIMAGE_FLAGS_IL_LIBRARY)) != 0) && !HasReadyToRunHeader());
1862#else
1863 RETURN FALSE;
1864#endif
1865}
1866
1867CHECK PEDecoder::CheckNativeHeader() const
1868{
1869 CONTRACT_CHECK
1870 {
1871 NOTHROW;
1872 GC_NOTRIGGER;
1873 SUPPORTS_DAC;
1874 SO_TOLERANT;
1875 }
1876 CONTRACT_CHECK_END;
1877
1878#ifdef FEATURE_PREJIT
1879 if (m_flags & FLAG_NATIVE_CHECKED)
1880 CHECK_OK;
1881
1882 CHECK(CheckCorHeader());
1883
1884 CHECK(HasNativeHeader());
1885
1886 IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->ManagedNativeHeader;
1887
1888 CHECK(CheckDirectory(pDir));
1889 CHECK(VAL32(pDir->Size) == sizeof(CORCOMPILE_HEADER));
1890
1891#if 0
1892 // We want to be sure to not trigger these checks when loading a native
1893 // image in a retail build
1894
1895 // And we do not want to trigger these checks in debug builds either to avoid debug/retail behavior
1896 // differences.
1897
1898 PTR_CORCOMPILE_HEADER pHeader = PTR_CORCOMPILE_HEADER((TADDR)GetDirectoryData(pDir));
1899
1900 CHECK(CheckDirectory(&pHeader->EEInfoTable));
1901 CHECK(pHeader->EEInfoTable.Size == sizeof(CORCOMPILE_EE_INFO_TABLE));
1902
1903 CHECK(CheckDirectory(&pHeader->HelperTable, 0, NULL_OK));
1904 // @todo: verify helper table size
1905
1906 CHECK(CheckDirectory(&pHeader->ImportSections, 0, NULL_OK));
1907 // @todo verify import sections
1908
1909 CHECK(CheckDirectory(&pHeader->ImportTable, 0, NULL_OK));
1910 // @todo verify import table
1911
1912 CHECK(CheckDirectory(&pHeader->VersionInfo, 0, NULL_OK)); // no version header for precompiled netmodules
1913 CHECK(pHeader->VersionInfo.Size == 0
1914 || (pHeader->VersionInfo.Size == sizeof(CORCOMPILE_VERSION_INFO) &&
1915 // Sanity check that we are not just pointing to zeroed-out memory
1916 ((CORCOMPILE_VERSION_INFO*)PTR_READ(GetDirectoryData(&pHeader->VersionInfo), sizeof(CORCOMPILE_VERSION_INFO)))->wOSMajorVersion != 0));
1917
1918 CHECK(CheckDirectory(&pHeader->Dependencies, 0, NULL_OK)); // no version header for precompiled netmodules
1919 CHECK(pHeader->Dependencies.Size % sizeof(CORCOMPILE_DEPENDENCY) == 0);
1920
1921 CHECK(CheckDirectory(&pHeader->DebugMap, 0, NULL_OK));
1922 CHECK(pHeader->DebugMap.Size % sizeof(CORCOMPILE_DEBUG_RID_ENTRY) == 0);
1923
1924 // GetPersistedModuleImage()
1925 CHECK(CheckDirectory(&pHeader->ModuleImage));
1926 CHECK(pHeader->ModuleImage.Size > 0); // sizeof(Module) if we knew it here
1927
1928 CHECK(CheckDirectory(&pHeader->CodeManagerTable));
1929 CHECK(pHeader->CodeManagerTable.Size == sizeof(CORCOMPILE_CODE_MANAGER_ENTRY));
1930
1931 PTR_CORCOMPILE_CODE_MANAGER_ENTRY pEntry = PTR_CORCOMPILE_CODE_MANAGER_ENTRY((TADDR)GetDirectoryData(&pHeader->CodeManagerTable));
1932 CHECK(CheckDirectory(&pEntry->HotCode, IMAGE_SCN_MEM_WRITE, NULL_OK));
1933 CHECK(CheckDirectory(&pEntry->Code, IMAGE_SCN_MEM_WRITE, NULL_OK));
1934 CHECK(CheckDirectory(&pEntry->ColdCode, IMAGE_SCN_MEM_WRITE, NULL_OK));
1935
1936 CHECK(CheckDirectory(&pHeader->ProfileDataList, 0, NULL_OK));
1937 CHECK(pHeader->ProfileDataList.Size >= sizeof(CORCOMPILE_METHOD_PROFILE_LIST)
1938 || pHeader->ProfileDataList.Size == 0);
1939
1940#endif
1941
1942 const_cast<PEDecoder *>(this)->m_flags |= FLAG_NATIVE_CHECKED;
1943
1944#else // FEATURE_PREJIT
1945 CHECK(false);
1946#endif // FEATURE_PREJIT
1947
1948 CHECK_OK;
1949}
1950
1951READYTORUN_HEADER * PEDecoder::FindReadyToRunHeader() const
1952{
1953 CONTRACTL
1954 {
1955 NOTHROW;
1956 GC_NOTRIGGER;
1957 SUPPORTS_DAC;
1958 SO_TOLERANT;
1959 }
1960 CONTRACTL_END;
1961
1962 IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->ManagedNativeHeader;
1963
1964 if (VAL32(pDir->Size) >= sizeof(READYTORUN_HEADER) && CheckDirectory(pDir))
1965 {
1966 PTR_READYTORUN_HEADER pHeader = PTR_READYTORUN_HEADER((TADDR)GetDirectoryData(pDir));
1967 if (pHeader->Signature == READYTORUN_SIGNATURE)
1968 {
1969 const_cast<PEDecoder *>(this)->m_pReadyToRunHeader = pHeader;
1970 return pHeader;
1971 }
1972 }
1973
1974 const_cast<PEDecoder *>(this)->m_flags |= FLAG_HAS_NO_READYTORUN_HEADER;
1975 return NULL;
1976}
1977
1978//
1979// code:PEDecoder::CheckILMethod and code:PEDecoder::ComputeILMethodSize really belong to
1980// file:..\inc\corhlpr.cpp. Unfortunately, corhlpr.cpp is public header file that cannot be
1981// properly DACized and have other dependencies on the rest of the CLR.
1982//
1983
1984typedef DPTR(COR_ILMETHOD_TINY) PTR_COR_ILMETHOD_TINY;
1985typedef DPTR(COR_ILMETHOD_FAT) PTR_COR_ILMETHOD_FAT;
1986typedef DPTR(COR_ILMETHOD_SECT_SMALL) PTR_COR_ILMETHOD_SECT_SMALL;
1987typedef DPTR(COR_ILMETHOD_SECT_FAT) PTR_COR_ILMETHOD_SECT_FAT;
1988
1989CHECK PEDecoder::CheckILMethod(RVA rva)
1990{
1991 CONTRACT_CHECK
1992 {
1993 INSTANCE_CHECK;
1994 NOTHROW;
1995 GC_NOTRIGGER;
1996 }
1997 CONTRACT_CHECK_END;
1998
1999 //
2000 // Incrementaly validate that the entire IL method body is within the bounds of the image
2001 //
2002
2003 // We need to have at least the tiny header
2004 CHECK(CheckRva(rva, sizeof(IMAGE_COR_ILMETHOD_TINY)));
2005
2006 TADDR pIL = GetRvaData(rva);
2007
2008 PTR_COR_ILMETHOD_TINY pMethodTiny = PTR_COR_ILMETHOD_TINY(pIL);
2009
2010 if (pMethodTiny->IsTiny())
2011 {
2012 // Tiny header has no optional sections - we are done.
2013 CHECK(CheckRva(rva, sizeof(IMAGE_COR_ILMETHOD_TINY) + pMethodTiny->GetCodeSize()));
2014 CHECK_OK;
2015 }
2016
2017 //
2018 // Fat header
2019 //
2020
2021 CHECK(CheckRva(rva, sizeof(IMAGE_COR_ILMETHOD_FAT)));
2022
2023 PTR_COR_ILMETHOD_FAT pMethodFat = PTR_COR_ILMETHOD_FAT(pIL);
2024
2025 CHECK(pMethodFat->IsFat());
2026
2027 S_UINT32 codeEnd = S_UINT32(4) * S_UINT32(pMethodFat->GetSize()) + S_UINT32(pMethodFat->GetCodeSize());
2028 CHECK(!codeEnd.IsOverflow());
2029
2030 // Check minimal size of the header
2031 CHECK(pMethodFat->GetSize() >= (sizeof(COR_ILMETHOD_FAT) / 4));
2032
2033 CHECK(CheckRva(rva, codeEnd.Value()));
2034
2035 if (!pMethodFat->More())
2036 {
2037 CHECK_OK;
2038 }
2039
2040 // DACized copy of code:COR_ILMETHOD_FAT::GetSect
2041 TADDR pSect = AlignUp(pIL + codeEnd.Value(), 4);
2042
2043 //
2044 // Optional sections following the code
2045 //
2046
2047 for (;;)
2048 {
2049 CHECK(CheckRva(rva, UINT32(pSect - pIL) + sizeof(IMAGE_COR_ILMETHOD_SECT_SMALL)));
2050
2051 PTR_COR_ILMETHOD_SECT_SMALL pSectSmall = PTR_COR_ILMETHOD_SECT_SMALL(pSect);
2052
2053 UINT32 sectSize;
2054
2055 if (pSectSmall->IsSmall())
2056 {
2057 sectSize = pSectSmall->DataSize;
2058
2059 // Workaround for bug in shipped compilers - see comment in code:COR_ILMETHOD_SECT::DataSize
2060 if ((pSectSmall->Kind & CorILMethod_Sect_KindMask) == CorILMethod_Sect_EHTable)
2061 sectSize = COR_ILMETHOD_SECT_EH_SMALL::Size(sectSize / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL));
2062 }
2063 else
2064 {
2065 CHECK(CheckRva(rva, UINT32(pSect - pIL) + sizeof(IMAGE_COR_ILMETHOD_SECT_FAT)));
2066
2067 PTR_COR_ILMETHOD_SECT_FAT pSectFat = PTR_COR_ILMETHOD_SECT_FAT(pSect);
2068
2069 sectSize = pSectFat->GetDataSize();
2070
2071 // Workaround for bug in shipped compilers - see comment in code:COR_ILMETHOD_SECT::DataSize
2072 if ((pSectSmall->Kind & CorILMethod_Sect_KindMask) == CorILMethod_Sect_EHTable)
2073 sectSize = COR_ILMETHOD_SECT_EH_FAT::Size(sectSize / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT));
2074 }
2075
2076 // Section has to be non-empty to avoid infinite loop below
2077 CHECK(sectSize > 0);
2078
2079 S_UINT32 sectEnd = S_UINT32(UINT32(pSect - pIL)) + S_UINT32(sectSize);
2080 CHECK(!sectEnd.IsOverflow());
2081
2082 CHECK(CheckRva(rva, sectEnd.Value()));
2083
2084 if (!pSectSmall->More())
2085 {
2086 CHECK_OK;
2087 }
2088
2089 // DACized copy of code:COR_ILMETHOD_FAT::Next
2090 pSect = AlignUp(pIL + sectEnd.Value(), 4);
2091 }
2092}
2093
2094//
2095// Compute size of IL blob. Assumes that the IL is within the bounds of the image - make sure
2096// to call code:PEDecoder::CheckILMethod before calling this method.
2097//
2098// code:PEDecoder::ComputeILMethodSize is DACized duplicate of code:COR_ILMETHOD_DECODER::GetOnDiskSize.
2099// code:MethodDesc::GetILHeader contains debug-only check that ensures that both implementations
2100// are in sync.
2101//
2102
2103SIZE_T PEDecoder::ComputeILMethodSize(TADDR pIL)
2104{
2105 CONTRACTL {
2106 NOTHROW;
2107 GC_NOTRIGGER;
2108 SUPPORTS_DAC;
2109 } CONTRACTL_END;
2110
2111 //
2112 // Mirror flow of code:PEDecoder::CheckILMethod, except for the range checks
2113 //
2114
2115 PTR_COR_ILMETHOD_TINY pMethodTiny = PTR_COR_ILMETHOD_TINY(pIL);
2116
2117 if (pMethodTiny->IsTiny())
2118 {
2119 return sizeof(IMAGE_COR_ILMETHOD_TINY) + pMethodTiny->GetCodeSize();
2120 }
2121
2122 PTR_COR_ILMETHOD_FAT pMethodFat = PTR_COR_ILMETHOD_FAT(pIL);
2123
2124 UINT32 codeEnd = 4 * pMethodFat->GetSize() + pMethodFat->GetCodeSize();
2125
2126 if (!pMethodFat->More())
2127 {
2128 return codeEnd;
2129 }
2130
2131 // DACized copy of code:COR_ILMETHOD_FAT::GetSect
2132 TADDR pSect = AlignUp(pIL + codeEnd, 4);
2133
2134 for (;;)
2135 {
2136 PTR_COR_ILMETHOD_SECT_SMALL pSectSmall = PTR_COR_ILMETHOD_SECT_SMALL(pSect);
2137
2138 UINT32 sectSize;
2139
2140 if (pSectSmall->IsSmall())
2141 {
2142 sectSize = pSectSmall->DataSize;
2143
2144 // Workaround for bug in shipped compilers - see comment in code:COR_ILMETHOD_SECT::DataSize
2145 if ((pSectSmall->Kind & CorILMethod_Sect_KindMask) == CorILMethod_Sect_EHTable)
2146 sectSize = COR_ILMETHOD_SECT_EH_SMALL::Size(sectSize / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL));
2147 }
2148 else
2149 {
2150 PTR_COR_ILMETHOD_SECT_FAT pSectFat = PTR_COR_ILMETHOD_SECT_FAT(pSect);
2151
2152 sectSize = pSectFat->GetDataSize();
2153
2154 // Workaround for bug in shipped compilers - see comment in code:COR_ILMETHOD_SECT::DataSize
2155 if ((pSectSmall->Kind & CorILMethod_Sect_KindMask) == CorILMethod_Sect_EHTable)
2156 sectSize = COR_ILMETHOD_SECT_EH_FAT::Size(sectSize / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT));
2157 }
2158
2159 UINT32 sectEnd = UINT32(pSect - pIL) + sectSize;
2160
2161 if (!pSectSmall->More() || (sectSize == 0))
2162 {
2163 return sectEnd;
2164 }
2165
2166 // DACized copy of code:COR_ILMETHOD_FAT::Next
2167 pSect = AlignUp(pIL + sectEnd, 4);
2168 }
2169}
2170
2171//
2172// GetDebugDirectoryEntry - return the debug directory entry at the specified index
2173//
2174// Arguments:
2175// index The 0-based index of the entry to return. Usually this is just 0,
2176// but there can be multiple debug directory entries in a PE file.
2177//
2178// Return value:
2179// A pointer to the IMAGE_DEBUG_DIRECTORY in the PE file for the specified index,
2180// or NULL if it doesn't exist.
2181//
2182// Note that callers on untrusted input are required to validate the debug directory
2183// first by calling CheckDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG) (possibly
2184// indirectly via one of the CheckILOnly* functions).
2185//
2186PTR_IMAGE_DEBUG_DIRECTORY PEDecoder::GetDebugDirectoryEntry(UINT index) const
2187{
2188 CONTRACT(PTR_IMAGE_DEBUG_DIRECTORY)
2189 {
2190 INSTANCE_CHECK;
2191 PRECONDITION(CheckNTHeaders());
2192 NOTHROW;
2193 GC_NOTRIGGER;
2194 SUPPORTS_DAC;
2195 }
2196 CONTRACT_END;
2197
2198 if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG))
2199 {
2200 RETURN NULL;
2201 }
2202
2203 // Get a pointer to the contents and size of the debug directory
2204 // Also validates (in CHK builds) that this is all within one section, which the
2205 // caller should have already validated if they don't trust the context of this PE file.
2206 COUNT_T cbDebugDir;
2207 TADDR taDebugDir = GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_DEBUG, &cbDebugDir);
2208
2209 // Check if the specified directory entry exists (based on the size of the directory)
2210 // Note that the directory size should be an even multiple of the entry size, but we
2211 // just round-down because we need to be resiliant (without asserting) to corrupted /
2212 // fuzzed PE files.
2213 UINT cNumEntries = cbDebugDir / sizeof(IMAGE_DEBUG_DIRECTORY);
2214 if (index >= cNumEntries)
2215 {
2216 RETURN NULL; // index out of range
2217 }
2218
2219 // Get the debug directory entry at the specified index.
2220 PTR_IMAGE_DEBUG_DIRECTORY pDebugEntry = dac_cast<PTR_IMAGE_DEBUG_DIRECTORY>(taDebugDir);
2221 pDebugEntry += index; // offset from the first entry to the requested entry
2222 RETURN pDebugEntry;
2223}
2224
2225
2226#ifdef FEATURE_PREJIT
2227
2228CORCOMPILE_EE_INFO_TABLE *PEDecoder::GetNativeEEInfoTable() const
2229{
2230 CONTRACT(CORCOMPILE_EE_INFO_TABLE *)
2231 {
2232 PRECONDITION(CheckNativeHeader());
2233 NOTHROW;
2234 GC_NOTRIGGER;
2235 POSTCONDITION(CheckPointer(RETVAL));
2236 }
2237 CONTRACT_END;
2238
2239 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->EEInfoTable;
2240
2241 // 403523: PREFIX correctly complained here. Fixed GetDirectoryData.
2242 RETURN PTR_CORCOMPILE_EE_INFO_TABLE(GetDirectoryData(pDir));
2243}
2244
2245
2246void *PEDecoder::GetNativeHelperTable(COUNT_T *pSize) const
2247{
2248 CONTRACT(void *)
2249 {
2250 PRECONDITION(CheckNativeHeader());
2251 NOTHROW;
2252 GC_NOTRIGGER;
2253 }
2254 CONTRACT_END;
2255
2256 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->HelperTable;
2257
2258 if (pSize != NULL)
2259 *pSize = VAL32(pDir->Size);
2260
2261 RETURN (void *)GetDirectoryData(pDir);
2262}
2263
2264CORCOMPILE_VERSION_INFO *PEDecoder::GetNativeVersionInfoMaybeNull(bool skipCheckNativeHeader) const
2265{
2266 CONTRACT(CORCOMPILE_VERSION_INFO *)
2267 {
2268 PRECONDITION(skipCheckNativeHeader || CheckNativeHeader());
2269 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2270 NOTHROW;
2271 GC_NOTRIGGER;
2272 SUPPORTS_DAC;
2273 }
2274 CONTRACT_END;
2275
2276 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->VersionInfo;
2277
2278 RETURN PTR_CORCOMPILE_VERSION_INFO(GetDirectoryData(pDir));
2279}
2280
2281CORCOMPILE_VERSION_INFO *PEDecoder::GetNativeVersionInfo() const
2282{
2283 CONTRACT(CORCOMPILE_VERSION_INFO *)
2284 {
2285 POSTCONDITION(CheckPointer(RETVAL));
2286 NOTHROW;
2287 GC_NOTRIGGER;
2288 SUPPORTS_DAC;
2289 }
2290 CONTRACT_END;
2291
2292 RETURN GetNativeVersionInfoMaybeNull();
2293}
2294
2295BOOL PEDecoder::HasNativeDebugMap() const
2296{
2297 CONTRACT(BOOL)
2298 {
2299 PRECONDITION(CheckNativeHeader());
2300 INSTANCE_CHECK;
2301 NOTHROW;
2302 GC_NOTRIGGER;
2303 SUPPORTS_DAC;
2304 }
2305 CONTRACT_END;
2306
2307 // 403522: Prefix complained correctly here.
2308 CORCOMPILE_HEADER *pNativeHeader = GetNativeHeader();
2309 if (!pNativeHeader)
2310 RETURN FALSE;
2311 else
2312 RETURN (VAL32(pNativeHeader->DebugMap.VirtualAddress) != 0);
2313}
2314
2315TADDR PEDecoder::GetNativeDebugMap(COUNT_T *pSize) const
2316{
2317 CONTRACT(TADDR)
2318 {
2319 PRECONDITION(CheckNativeHeader());
2320 PRECONDITION(CheckPointer(pSize, NULL_OK));
2321 NOTHROW;
2322 GC_NOTRIGGER;
2323 SUPPORTS_DAC;
2324 }
2325 CONTRACT_END;
2326
2327 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->DebugMap;
2328
2329 if (pSize != NULL)
2330 *pSize = VAL32(pDir->Size);
2331
2332 RETURN (GetDirectoryData(pDir));
2333}
2334
2335Module *PEDecoder::GetPersistedModuleImage(COUNT_T *pSize) const
2336{
2337 CONTRACT(Module *)
2338 {
2339 PRECONDITION(CheckNativeHeader());
2340 PRECONDITION(CheckPointer(pSize, NULL_OK));
2341 POSTCONDITION(CheckPointer(RETVAL));
2342 NOTHROW;
2343 GC_NOTRIGGER;
2344 }
2345 CONTRACT_END;
2346
2347 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->ModuleImage;
2348
2349 if (pSize != NULL)
2350 *pSize = VAL32(pDir->Size);
2351
2352 RETURN (Module *) GetDirectoryData(pDir);
2353}
2354
2355CHECK PEDecoder::CheckNativeHeaderVersion() const
2356{
2357 CONTRACT_CHECK
2358 {
2359 PRECONDITION(CheckNativeHeader());
2360 NOTHROW;
2361 GC_NOTRIGGER;
2362 }
2363 CONTRACT_CHECK_END;
2364
2365 IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->ManagedNativeHeader;
2366 CHECK(VAL32(pDir->Size) == sizeof(CORCOMPILE_HEADER));
2367
2368 CORCOMPILE_HEADER *pNativeHeader = GetNativeHeader();
2369 CHECK(pNativeHeader->Signature == CORCOMPILE_SIGNATURE);
2370 CHECK(pNativeHeader->MajorVersion == CORCOMPILE_MAJOR_VERSION);
2371 CHECK(pNativeHeader->MinorVersion == CORCOMPILE_MINOR_VERSION);
2372
2373 CHECK_OK;
2374}
2375
2376CORCOMPILE_CODE_MANAGER_ENTRY *PEDecoder::GetNativeCodeManagerTable() const
2377{
2378 CONTRACT(CORCOMPILE_CODE_MANAGER_ENTRY *)
2379 {
2380 PRECONDITION(CheckNativeHeader());
2381 POSTCONDITION(CheckPointer(RETVAL));
2382 SUPPORTS_DAC;
2383 NOTHROW;
2384 GC_NOTRIGGER;
2385 SO_TOLERANT;
2386 }
2387 CONTRACT_END;
2388
2389 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->CodeManagerTable;
2390
2391 RETURN PTR_CORCOMPILE_CODE_MANAGER_ENTRY(GetDirectoryData(pDir));
2392}
2393
2394PCODE PEDecoder::GetNativeHotCode(COUNT_T * pSize) const
2395{
2396 CONTRACT(PCODE)
2397 {
2398 PRECONDITION(CheckNativeHeader());
2399 PRECONDITION(CheckPointer(pSize, NULL_OK));
2400 SUPPORTS_DAC;
2401 NOTHROW;
2402 GC_NOTRIGGER;
2403 SO_TOLERANT;
2404 }
2405 CONTRACT_END;
2406
2407 IMAGE_DATA_DIRECTORY *pDir = &GetNativeCodeManagerTable()->HotCode;
2408
2409 if (pSize != NULL)
2410 *pSize = VAL32(pDir->Size);
2411
2412 RETURN GetDirectoryData(pDir);
2413}
2414
2415PCODE PEDecoder::GetNativeCode(COUNT_T * pSize) const
2416{
2417 CONTRACT(PCODE)
2418 {
2419 PRECONDITION(CheckNativeHeader());
2420 PRECONDITION(CheckPointer(pSize, NULL_OK));
2421 SUPPORTS_DAC;
2422 NOTHROW;
2423 GC_NOTRIGGER;
2424 SO_TOLERANT;
2425 }
2426 CONTRACT_END;
2427
2428 IMAGE_DATA_DIRECTORY *pDir = &GetNativeCodeManagerTable()->Code;
2429
2430 if (pSize != NULL)
2431 *pSize = VAL32(pDir->Size);
2432
2433 RETURN GetDirectoryData(pDir);
2434}
2435
2436PCODE PEDecoder::GetNativeColdCode(COUNT_T * pSize) const
2437{
2438 CONTRACT(PCODE)
2439 {
2440 PRECONDITION(CheckNativeHeader());
2441 PRECONDITION(CheckPointer(pSize, NULL_OK));
2442 NOTHROW;
2443 GC_NOTRIGGER;
2444 SUPPORTS_DAC;
2445 }
2446 CONTRACT_END;
2447
2448 IMAGE_DATA_DIRECTORY *pDir = &GetNativeCodeManagerTable()->ColdCode;
2449
2450 if (pSize != NULL)
2451 *pSize = VAL32(pDir->Size);
2452
2453 RETURN GetDirectoryData(pDir);
2454}
2455
2456
2457CORCOMPILE_METHOD_PROFILE_LIST *PEDecoder::GetNativeProfileDataList(COUNT_T * pSize) const
2458{
2459 CONTRACT(CORCOMPILE_METHOD_PROFILE_LIST *)
2460 {
2461 PRECONDITION(CheckNativeHeader());
2462 PRECONDITION(CheckPointer(pSize, NULL_OK));
2463 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2464 NOTHROW;
2465 GC_NOTRIGGER;
2466 }
2467 CONTRACT_END;
2468
2469 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->ProfileDataList;
2470
2471 if (pSize != NULL)
2472 *pSize = VAL32(pDir->Size);
2473
2474 RETURN PTR_CORCOMPILE_METHOD_PROFILE_LIST(GetDirectoryData(pDir));
2475}
2476
2477
2478
2479PTR_CVOID PEDecoder::GetNativeManifestMetadata(COUNT_T *pSize) const
2480{
2481 CONTRACT(PTR_CVOID)
2482 {
2483 INSTANCE_CHECK;
2484 PRECONDITION(CheckNativeHeader());
2485 POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); // TBD - may not store metadata for IJW
2486 NOTHROW;
2487 GC_NOTRIGGER;
2488 }
2489 CONTRACT_END;
2490
2491 IMAGE_DATA_DIRECTORY *pDir = GetMetaDataHelper(METADATA_SECTION_MANIFEST);
2492
2493 if (pSize != NULL)
2494 *pSize = VAL32(pDir->Size);
2495
2496 RETURN dac_cast<PTR_VOID>(GetDirectoryData(pDir));
2497}
2498
2499PTR_CORCOMPILE_IMPORT_SECTION PEDecoder::GetNativeImportSections(COUNT_T *pCount) const
2500{
2501 CONTRACT(PTR_CORCOMPILE_IMPORT_SECTION)
2502 {
2503 PRECONDITION(CheckNativeHeader());
2504 NOTHROW;
2505 GC_NOTRIGGER;
2506 }
2507 CONTRACT_END;
2508
2509 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->ImportSections;
2510
2511 if (pCount != NULL)
2512 *pCount = VAL32(pDir->Size) / sizeof(CORCOMPILE_IMPORT_SECTION);
2513
2514 RETURN dac_cast<PTR_CORCOMPILE_IMPORT_SECTION>(GetDirectoryData(pDir));
2515}
2516
2517PTR_CORCOMPILE_IMPORT_SECTION PEDecoder::GetNativeImportSectionFromIndex(COUNT_T index) const
2518{
2519 CONTRACT(PTR_CORCOMPILE_IMPORT_SECTION)
2520 {
2521 PRECONDITION(CheckNativeHeader());
2522 NOTHROW;
2523 GC_NOTRIGGER;
2524 }
2525 CONTRACT_END;
2526
2527 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->ImportSections;
2528
2529 _ASSERTE(VAL32(pDir->Size) % sizeof(CORCOMPILE_IMPORT_SECTION) == 0);
2530 _ASSERTE(index * sizeof(CORCOMPILE_IMPORT_SECTION) < VAL32(pDir->Size));
2531
2532 RETURN dac_cast<PTR_CORCOMPILE_IMPORT_SECTION>(GetDirectoryData(pDir)) + index;
2533}
2534
2535PTR_CORCOMPILE_IMPORT_SECTION PEDecoder::GetNativeImportSectionForRVA(RVA rva) const
2536{
2537 CONTRACT(PTR_CORCOMPILE_IMPORT_SECTION)
2538 {
2539 PRECONDITION(CheckNativeHeader());
2540 NOTHROW;
2541 GC_NOTRIGGER;
2542 }
2543 CONTRACT_END;
2544
2545 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->ImportSections;
2546
2547 _ASSERTE(VAL32(pDir->Size) % sizeof(CORCOMPILE_IMPORT_SECTION) == 0);
2548
2549 PTR_CORCOMPILE_IMPORT_SECTION pSections = dac_cast<PTR_CORCOMPILE_IMPORT_SECTION>(GetDirectoryData(pDir));
2550 PTR_CORCOMPILE_IMPORT_SECTION pEnd = dac_cast<PTR_CORCOMPILE_IMPORT_SECTION>(dac_cast<TADDR>(pSections) + VAL32(pDir->Size));
2551
2552 for (PTR_CORCOMPILE_IMPORT_SECTION pSection = pSections; pSection < pEnd; pSection++)
2553 {
2554 if (rva >= VAL32(pSection->Section.VirtualAddress) && rva < VAL32(pSection->Section.VirtualAddress) + VAL32(pSection->Section.Size))
2555 RETURN pSection;
2556 }
2557
2558 RETURN NULL;
2559}
2560
2561TADDR PEDecoder::GetStubsTable(COUNT_T *pSize) const
2562{
2563 CONTRACTL {
2564 INSTANCE_CHECK;
2565 PRECONDITION(CheckNativeHeader());
2566 NOTHROW;
2567 GC_NOTRIGGER;
2568 } CONTRACTL_END;
2569
2570 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->StubsData;
2571
2572 if (pSize != NULL)
2573 *pSize = VAL32(pDir->Size);
2574
2575 return (GetDirectoryData(pDir));
2576}
2577
2578TADDR PEDecoder::GetVirtualSectionsTable(COUNT_T *pSize) const
2579{
2580 CONTRACTL {
2581 INSTANCE_CHECK;
2582 PRECONDITION(CheckNativeHeader());
2583 NOTHROW;
2584 GC_NOTRIGGER;
2585 } CONTRACTL_END;
2586
2587 IMAGE_DATA_DIRECTORY *pDir = &GetNativeHeader()->VirtualSectionsTable;
2588
2589 if (pSize != NULL)
2590 *pSize = VAL32(pDir->Size);
2591
2592 return (GetDirectoryData(pDir));
2593}
2594
2595#endif // FEATURE_PREJIT
2596
2597// Get the SizeOfStackReserve and SizeOfStackCommit from the PE file that was used to create
2598// the calling process (.exe file).
2599void PEDecoder::GetEXEStackSizes(SIZE_T *PE_SizeOfStackReserve, SIZE_T *PE_SizeOfStackCommit) const
2600{
2601 CONTRACTL {
2602 PRECONDITION(!IsDll()); // This routine should only be called for EXE files.
2603 NOTHROW;
2604 GC_NOTRIGGER;
2605 } CONTRACTL_END;
2606
2607 * PE_SizeOfStackReserve = GetSizeOfStackReserve();
2608 * PE_SizeOfStackCommit = GetSizeOfStackCommit();
2609}
2610
2611CHECK PEDecoder::CheckWillCreateGuardPage() const
2612{
2613 CONTRACT_CHECK
2614 {
2615 PRECONDITION(CheckNTHeaders());
2616 NOTHROW;
2617 GC_NOTRIGGER;
2618 }
2619 CONTRACT_CHECK_END;
2620
2621 if (!IsDll())
2622 {
2623 SIZE_T sizeReservedStack = 0;
2624 SIZE_T sizeCommitedStack = 0;
2625
2626 GetEXEStackSizes(&sizeReservedStack, &sizeCommitedStack);
2627
2628 CHECK(ThreadWillCreateGuardPage(sizeReservedStack, sizeCommitedStack));
2629
2630 }
2631
2632 CHECK_OK;
2633}
2634
2635BOOL PEDecoder::HasNativeEntryPoint() const
2636{
2637 CONTRACTL {
2638 INSTANCE_CHECK;
2639 NOTHROW;
2640 GC_NOTRIGGER;
2641 PRECONDITION(CheckCorHeader());
2642 } CONTRACTL_END;
2643
2644 ULONG flags = GetCorHeader()->Flags;
2645 return ((flags & VAL32(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT)) &&
2646 (IMAGE_COR20_HEADER_FIELD(*GetCorHeader(), EntryPointToken) != VAL32(0)));
2647}
2648
2649void *PEDecoder::GetNativeEntryPoint() const
2650{
2651 CONTRACT (void *) {
2652 INSTANCE_CHECK;
2653 NOTHROW;
2654 GC_NOTRIGGER;
2655 PRECONDITION(CheckCorHeader());
2656 PRECONDITION(HasNativeEntryPoint());
2657 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2658 } CONTRACT_END;
2659
2660 RETURN ((void *) GetRvaData((RVA)VAL32(IMAGE_COR20_HEADER_FIELD(*GetCorHeader(), EntryPointToken))));
2661}
2662
2663#ifdef DACCESS_COMPILE
2664
2665void
2666PEDecoder::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
2667 bool enumThis)
2668{
2669 SUPPORTS_DAC;
2670 if (enumThis)
2671 {
2672 DAC_ENUM_DTHIS();
2673 }
2674
2675 DacEnumMemoryRegion((TADDR)m_base, sizeof(IMAGE_DOS_HEADER));
2676 m_pNTHeaders.EnumMem();
2677 m_pCorHeader.EnumMem();
2678 m_pNativeHeader.EnumMem();
2679 m_pReadyToRunHeader.EnumMem();
2680
2681 if (HasNTHeaders())
2682 {
2683 // resource file does not have NT Header.
2684 //
2685 // we also need to write out section header.
2686 DacEnumMemoryRegion(dac_cast<TADDR>(FindFirstSection()), sizeof(IMAGE_SECTION_HEADER) * GetNumberOfSections());
2687 }
2688}
2689
2690#endif // #ifdef DACCESS_COMPILE
2691
2692// --------------------------------------------------------------------------------
2693
2694#ifdef _DEBUG
2695
2696// This is a stress mode to force DLLs to be relocated.
2697// This is particularly useful for hardbinding of ngen images as we
2698// embed pointers into other hardbound ngen dependencies.
2699
2700BOOL PEDecoder::GetForceRelocs()
2701{
2702 WRAPPER_NO_CONTRACT;
2703
2704 static ConfigDWORD forceRelocs;
2705 return (forceRelocs.val(CLRConfig::INTERNAL_ForceRelocs) != 0);
2706}
2707
2708BOOL PEDecoder::ForceRelocForDLL(LPCWSTR lpFileName)
2709{
2710 // Use static contracts to avoid recursion, as the dynamic contracts
2711 // do WszLoadLibrary(MSCOREE_SHIM_W).
2712#ifdef _DEBUG
2713 STATIC_CONTRACT_NOTHROW; \
2714 ANNOTATION_DEBUG_ONLY; \
2715 STATIC_CONTRACT_CANNOT_TAKE_LOCK; \
2716 ANNOTATION_FN_SO_NOT_MAINLINE;
2717#endif
2718
2719#if defined(DACCESS_COMPILE) || defined(FEATURE_PAL)
2720 return TRUE;
2721#else
2722
2723 CONTRACT_VIOLATION(SOToleranceViolation);
2724
2725 // Contracts in ConfigDWORD do WszLoadLibrary(MSCOREE_SHIM_W).
2726 // This check prevents recursion.
2727 if (wcsstr(lpFileName, MSCOREE_SHIM_W) != 0)
2728 return TRUE;
2729
2730 if (!GetForceRelocs())
2731 return TRUE;
2732
2733 BOOL fSuccess = FALSE;
2734 PBYTE hndle = NULL;
2735 PEDecoder pe;
2736 void* pPreferredBase;
2737 COUNT_T nVirtualSize;
2738
2739 HANDLE hFile = WszCreateFile(lpFileName,
2740 GENERIC_READ,
2741 FILE_SHARE_READ,
2742 NULL,
2743 OPEN_EXISTING,
2744 FILE_FLAG_SEQUENTIAL_SCAN,
2745 NULL);
2746 if (hFile == INVALID_HANDLE_VALUE)
2747 goto ErrExit;
2748
2749 HANDLE hMap = WszCreateFileMapping(hFile,
2750 NULL,
2751 SEC_IMAGE | PAGE_READONLY,
2752 0,
2753 0,
2754 NULL);
2755 CloseHandle(hFile);
2756
2757 if (hMap == NULL)
2758 goto ErrExit;
2759
2760 hndle = (PBYTE)MapViewOfFile(hMap,
2761 FILE_MAP_READ,
2762 0,
2763 0,
2764 0);
2765 CloseHandle(hMap);
2766
2767 if (!hndle)
2768 goto ErrExit;
2769
2770 pe.Init(hndle);
2771
2772 pPreferredBase = (void*)pe.GetPreferredBase();
2773 nVirtualSize = pe.GetVirtualSize();
2774
2775 UnmapViewOfFile(hndle);
2776 hndle = NULL;
2777
2778 // Reserve the space so nobody can use it. A potential bug is likely to
2779 // result in a plain AV this way. It is not a good idea to use the original
2780 // mapping for the reservation since since it would lock the file on the disk.
2781 if (!ClrVirtualAlloc(pPreferredBase, nVirtualSize, MEM_RESERVE, PAGE_NOACCESS))
2782 goto ErrExit;
2783
2784 fSuccess = TRUE;
2785
2786ErrExit:
2787 if (hndle != NULL)
2788 UnmapViewOfFile(hndle);
2789
2790 return fSuccess;
2791
2792#endif // DACCESS_COMPILE || FEATURE_PAL
2793}
2794
2795#endif // _DEBUG
2796
2797//
2798// MethodSectionIterator class is used to iterate hot (or) cold method section in an ngen image.
2799// Also used to iterate over jitted methods in the code heap
2800//
2801MethodSectionIterator::MethodSectionIterator(const void *code, SIZE_T codeSize,
2802 const void *codeTable, SIZE_T codeTableSize)
2803{
2804 //For DAC builds,we'll read the table one DWORD at a time. Note that m_code IS
2805 //NOT a host pointer.
2806 m_codeTableStart = PTR_DWORD(TADDR(codeTable));
2807 m_codeTable = m_codeTableStart;
2808 _ASSERTE((codeTableSize % sizeof(DWORD)) == 0);
2809 m_codeTableEnd = m_codeTableStart + (codeTableSize / sizeof(DWORD));
2810 m_code = (BYTE *) code;
2811 m_current = NULL;
2812
2813
2814 if (m_codeTable < m_codeTableEnd)
2815 {
2816 m_dword = *m_codeTable++;
2817 m_index = 0;
2818 }
2819 else
2820 {
2821 m_index = NIBBLES_PER_DWORD;
2822 }
2823}
2824
2825BOOL MethodSectionIterator::Next()
2826{
2827 while (m_codeTable < m_codeTableEnd || m_index < (int)NIBBLES_PER_DWORD)
2828 {
2829 while (m_index++ < (int)NIBBLES_PER_DWORD)
2830 {
2831 int nibble = (m_dword & HIGHEST_NIBBLE_MASK)>>HIGHEST_NIBBLE_BIT;
2832 m_dword <<= NIBBLE_SIZE;
2833
2834 if (nibble != 0)
2835 {
2836 // We have found a method start
2837 m_current = m_code + ((nibble-1)*CODE_ALIGN);
2838 m_code += BYTES_PER_BUCKET;
2839 return TRUE;
2840 }
2841
2842 m_code += BYTES_PER_BUCKET;
2843 }
2844
2845 if (m_codeTable < m_codeTableEnd)
2846 {
2847 m_dword = *m_codeTable++;
2848 m_index = 0;
2849 }
2850 }
2851 return FALSE;
2852}
2853