forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpeimage.h
336 lines (268 loc) · 11 KB
/
peimage.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// --------------------------------------------------------------------------------
// PEImage.h
//
// --------------------------------------------------------------------------------
#ifndef PEIMAGE_H_
#define PEIMAGE_H_
// --------------------------------------------------------------------------------
// Required headers
// --------------------------------------------------------------------------------
#include "clrtypes.h"
#include "peimagelayout.h"
#include "sstring.h"
#include "holder.h"
#include <bundle.h>
class SimpleRWLock;
// --------------------------------------------------------------------------------
// Forward declarations
// --------------------------------------------------------------------------------
class Crst;
// --------------------------------------------------------------------------------
// PEImage is a PE file loaded into memory.
//
// The actual data is represented by PEImageLayout instances which are created on demand.
//
// Various PEImageLayouts can be classified into two kinds -
// - Flat - the same layout as on disk/array or
//
// - Loaded - PE sections are mapped into virtual addresses.
// PE relocations are applied.
// Native exception handlers are registered with OS (on Windows).
//
// Flat layouts are sufficient for operations that do not require running native code,
// Anything based on RVA, such as retrieving IL method bodies, is slightly less efficient,
// since RVA must be translated to file offsets by iterating through section headers.
// The additional cost is not very high though, since our PEs have only a few sections.
//
// Loaded layouts are functional supersets of Flat - anything that can be done with Flat
// can be done with Loaded.
//
// Running native code in the PE (i.e. R2R or IJW scenarios) requires Loaded layout.
// It is possible to execute R2R assembly from Flat layout in IL mode, but its R2R functionality
// will be disabled. When R2R is explicitly turned off, Flat is sufficient for any scenario with
// R2R assemblies.
// In a case of IJW, the PE must be loaded by the native loader to ensure that native dependencies
// are resolved.
//
// In some scenarios we create Loaded layouts by manually mapping images into memory.
// That is particularly true on Unix where we cannot rely on OS loader.
// Manual creation of layouts is limited to "IL only" images. This can be checked
// for via `PEDecoder::IsILOnlyImage`
// NOTE: historically, and somewhat confusingly, R2R PEs are considered IsILOnlyImage for this
// purpose. That is true even for composite R2R PEs that do not contain IL.
//
// A PEImage, depending on scenario, may end up creating both Flat and Loaded layouts,
// thus it has two slots - m_pLayouts[IMAGE_COUNT].
//
// m_pLayouts[IMAGE_FLAT]
// When initialized contains a layout that allows operations for which Flat layout is sufficient -
// i.e. reading metadata
//
// m_pLayouts[IMAGE_LOADED]
// When initialized contains a layout that allows loading/running code.
//
// The layouts can only be unloaded together with the owning PEImage, so if we have Flat and
// then need Loaded, we can only add one more. Thus we have two slots.
//
// Often the slots refer to the same layout though. That is because if we create Loaded before Flat,
// we put Loaded into both slots, since it is functionally a superset of Flat.
// Also for pure-IL assemblies Flat is sufficient for anything, so we may put Flat into both slots.
//
#define CV_SIGNATURE_RSDS 0x53445352
// CodeView RSDS debug information -> PDB 7.00
struct CV_INFO_PDB70
{
DWORD magic;
GUID signature; // unique identifier
DWORD age; // an always-incrementing value
char path[MAX_LONGPATH]; // zero terminated string with the name of the PDB file
};
typedef DPTR(class PEImage) PTR_PEImage;
class PEImage final
{
public:
// ------------------------------------------------------------
// Public API
// ------------------------------------------------------------
// initialize static data (i.e. locks, unique instance cache, etc..)
static void Startup();
~PEImage();
explicit PEImage(const WCHAR* path);
BOOL Equals(PEImage* pImage);
ULONG AddRef();
ULONG Release();
#ifndef DACCESS_COMPILE
static PTR_PEImage CreateFromByteArray(const BYTE* array, COUNT_T size);
#ifndef TARGET_UNIX
static PTR_PEImage CreateFromHMODULE(HMODULE hMod);
#endif // !TARGET_UNIX
static PTR_PEImage OpenImage(
LPCWSTR pPath,
MDInternalImportFlags flags = MDInternalImport_Default,
BundleFileLocation bundleFileLocation = BundleFileLocation::Invalid());
static PTR_PEImage FindByPath(LPCWSTR pPath, BOOL isInBundle);
void AddToHashMap();
#endif
BOOL IsOpened();
PTR_PEImageLayout GetOrCreateLayout(DWORD imageLayoutMask);
BOOL HasLoadedLayout();
PTR_PEImageLayout GetLoadedLayout();
PTR_PEImageLayout GetFlatLayout();
const SString& GetPath();
const SString& GetPathToLoad();
LPCWSTR GetPathForErrorMessages() { return GetPath(); }
BOOL IsFile();
BOOL IsInBundle() const;
INT64 GetOffset() const;
INT64 GetSize() const;
INT64 GetUncompressedSize() const;
HANDLE GetFileHandle();
HRESULT TryOpenFile(bool takeLock = false);
void GetMVID(GUID *pMvid);
BOOL HasV1Metadata();
IMDInternalImport* GetMDImport();
BOOL MDImportLoaded();
BOOL HasContents() ;
BOOL IsPtrInImage(PTR_CVOID data);
BOOL HasNTHeaders();
BOOL HasCorHeader();
BOOL HasReadyToRunHeader();
BOOL HasDirectoryEntry(int entry);
BOOL Has32BitNTHeaders();
void GetPEKindAndMachine(DWORD* pdwKind, DWORD* pdwMachine);
BOOL IsILOnly();
BOOL IsReferenceAssembly();
BOOL IsComponentAssembly();
PTR_CVOID GetNativeManifestMetadata(COUNT_T* pSize = NULL);
mdToken GetEntryPointToken();
DWORD GetCorHeaderFlags();
PTR_CVOID GetMetadata(COUNT_T* pSize = NULL);
// Check utilities
static CHECK CheckStartup();
static CHECK CheckCanonicalFullPath(const SString& path);
CHECK CheckFormat();
CHECK CheckILFormat();
CHECK CheckUniqueInstance();
void SetModuleFileNameHintForDAC();
#ifdef DACCESS_COMPILE
void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
#endif
const SString &GetModuleFileNameHintForDAC();
private:
#ifndef DACCESS_COMPILE
// Get or create the layout corresponding to the mask, with an AddRef
PTR_PEImageLayout GetOrCreateLayoutInternal(DWORD imageLayoutMask);
// Create the mapped layout
PTR_PEImageLayout CreateLoadedLayout(bool throwOnFailure);
// Create the flat layout
PTR_PEImageLayout CreateFlatLayout();
void SetLayout(DWORD dwLayout, PTR_PEImageLayout pLayout);
#endif
// Get an existing layout corresponding to the mask, no AddRef
PTR_PEImageLayout GetExistingLayoutInternal(DWORD imageLayoutMask);
void OpenMDImport();
// ------------------------------------------------------------
// Private routines
// ------------------------------------------------------------
void Init(BundleFileLocation bundleFileLocation);
struct PEImageLocator
{
LPCWSTR m_pPath;
BOOL m_bIsInBundle;
PEImageLocator(LPCWSTR pPath, BOOL bIsInBundle)
: m_pPath(pPath),
m_bIsInBundle(bIsInBundle)
{
}
PEImageLocator(PEImage * pImage)
: m_pPath(pImage->m_path.GetUnicode())
{
m_bIsInBundle = pImage->IsInBundle();
}
};
static BOOL CompareImage(UPTR image1, UPTR image2);
static BOOL CompareIJWDataBase(UPTR base, UPTR mapping);
public:
class IJWFixupData
{
private:
Crst m_lock;
void* m_base;
DWORD m_flags;
PTR_LoaderHeap m_DllThunkHeap;
// the fixup for the next iteration in FixupVTables
// we use it to make sure that we do not try to fix up the same entry twice
// if there was a pass that was aborted in the middle
COUNT_T m_iNextFixup;
COUNT_T m_iNextMethod;
enum {
e_FIXED_UP = 0x1
};
public:
IJWFixupData(void* pBase);
~IJWFixupData();
void* GetBase() { LIMITED_METHOD_CONTRACT; return m_base; }
Crst* GetLock() { LIMITED_METHOD_CONTRACT; return &m_lock; }
BOOL IsFixedUp() { LIMITED_METHOD_CONTRACT; return m_flags & e_FIXED_UP; }
void SetIsFixedUp() { LIMITED_METHOD_CONTRACT; m_flags |= e_FIXED_UP; }
PTR_LoaderHeap GetThunkHeap();
void MarkMethodFixedUp(COUNT_T iFixup, COUNT_T iMethod);
BOOL IsMethodFixedUp(COUNT_T iFixup, COUNT_T iMethod);
};
static IJWFixupData* GetIJWData(void* pBase);
static PTR_LoaderHeap GetDllThunkHeap(void* pBase);
static void UnloadIJWModule(void* pBase);
private:
// ------------------------------------------------------------
// Static fields
// ------------------------------------------------------------
static CrstStatic s_hashLock;
static PtrHashMap* s_Images;
//@TODO:workaround: Remove this when we have one PEImage per mapped image,
//@TODO:workaround: and move the lock there
// This is for IJW thunk initialization, as it is no longer guaranteed
// that the initialization will occur under the loader lock.
static CrstStatic s_ijwHashLock;
static PtrHashMap* s_ijwFixupDataHash;
// ------------------------------------------------------------
// Instance fields
// ------------------------------------------------------------
const SString m_path;
ULONG m_pathHash;
LONG m_refCount;
// means this is a unique (deduped) instance.
BOOL m_bInHashMap;
// If this image is located within a single-file bundle, the location within the bundle.
// If m_bundleFileLocation is valid, it takes precedence over m_path for loading.
BundleFileLocation m_bundleFileLocation;
// valid handle if we tried to open the file/path and succeeded.
HANDLE m_hFile;
DWORD m_dwPEKind;
DWORD m_dwMachine;
// This only used by DAC
// For assemblies loaded from a path or single-file bundle, this is the file name portion of the path
// For assemblies loaded from memory, this is the module file name from metadata
SString m_sModuleFileNameHintUsedByDac;
enum
{
IMAGE_FLAT=0,
IMAGE_LOADED=1,
IMAGE_COUNT=2
};
SimpleRWLock *m_pLayoutLock;
PTR_PEImageLayout m_pLayouts[IMAGE_COUNT];
IMDInternalImport* m_pMDImport;
};
FORCEINLINE void PEImageRelease(PEImage *i)
{
WRAPPER_NO_CONTRACT;
i->Release();
}
typedef Wrapper<PEImage *, DoNothing, PEImageRelease> PEImageHolder;
// ================================================================================
// Inline definitions
// ================================================================================
#include "peimage.inl"
#endif // PEIMAGE_H_