Update mcs/class/System.Core/System/TimeZoneInfo.cs
[mono.git] / mcs / class / IKVM.Reflection / Reader / PEReader.cs
1 /*
2   Copyright (C) 2009 Jeroen Frijters
3
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely, subject to the following restrictions:
11
12   1. The origin of this software must not be misrepresented; you must not
13      claim that you wrote the original software. If you use this software
14      in a product, an acknowledgment in the product documentation would be
15      appreciated but is not required.
16   2. Altered source versions must be plainly marked as such, and must not be
17      misrepresented as being the original software.
18   3. This notice may not be removed or altered from any source distribution.
19
20   Jeroen Frijters
21   jeroen@frijters.net
22   
23 */
24 using System;
25 using BYTE = System.Byte;
26 using WORD = System.UInt16;
27 using DWORD = System.UInt32;
28 using ULONGLONG = System.UInt64;
29 using System.IO;
30
31 namespace IKVM.Reflection.Reader
32 {
33         sealed class MSDOS_HEADER
34         {
35                 internal const WORD MAGIC_MZ = 0x5A4D;
36
37                 internal WORD signature;        // 'MZ'
38                 // skip 58 bytes
39                 internal DWORD peSignatureOffset;
40         }
41
42         sealed class IMAGE_NT_HEADERS
43         {
44                 public const DWORD MAGIC_SIGNATURE = 0x00004550;        // "PE\0\0"
45
46                 public DWORD Signature;
47                 public IMAGE_FILE_HEADER FileHeader = new IMAGE_FILE_HEADER();
48                 public IMAGE_OPTIONAL_HEADER OptionalHeader = new IMAGE_OPTIONAL_HEADER();
49
50                 internal void Read(BinaryReader br)
51                 {
52                         Signature = br.ReadUInt32();
53                         if (Signature != IMAGE_NT_HEADERS.MAGIC_SIGNATURE)
54                         {
55                                 throw new BadImageFormatException();
56                         }
57                         FileHeader.Read(br);
58                         OptionalHeader.Read(br);
59                 }
60         }
61
62         sealed class IMAGE_FILE_HEADER
63         {
64                 public const WORD IMAGE_FILE_MACHINE_I386 = 0x014c;
65                 public const WORD IMAGE_FILE_MACHINE_IA64 = 0x0200;
66                 public const WORD IMAGE_FILE_MACHINE_AMD64 = 0x8664;
67
68                 public const WORD IMAGE_FILE_32BIT_MACHINE = 0x0100;
69                 public const WORD IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002;
70                 public const WORD IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020;
71                 public const WORD IMAGE_FILE_DLL = 0x2000;
72
73                 public WORD Machine;
74                 public WORD NumberOfSections;
75                 public DWORD TimeDateStamp;
76                 public DWORD PointerToSymbolTable;
77                 public DWORD NumberOfSymbols;
78                 public WORD SizeOfOptionalHeader;
79                 public WORD Characteristics;
80
81                 internal void Read(BinaryReader br)
82                 {
83                         Machine = br.ReadUInt16();
84                         NumberOfSections = br.ReadUInt16();
85                         TimeDateStamp = br.ReadUInt32();
86                         PointerToSymbolTable = br.ReadUInt32();
87                         NumberOfSymbols = br.ReadUInt32();
88                         SizeOfOptionalHeader = br.ReadUInt16();
89                         Characteristics = br.ReadUInt16();
90                 }
91         }
92
93         sealed class IMAGE_OPTIONAL_HEADER
94         {
95                 public const WORD IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
96                 public const WORD IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
97
98                 public const WORD IMAGE_SUBSYSTEM_WINDOWS_GUI = 2;
99                 public const WORD IMAGE_SUBSYSTEM_WINDOWS_CUI = 3;
100
101                 public WORD Magic;
102                 public BYTE MajorLinkerVersion;
103                 public BYTE MinorLinkerVersion;
104                 public DWORD SizeOfCode;
105                 public DWORD SizeOfInitializedData;
106                 public DWORD SizeOfUninitializedData;
107                 public DWORD AddressOfEntryPoint;
108                 public DWORD BaseOfCode;
109                 public DWORD BaseOfData;
110                 public ULONGLONG ImageBase;
111                 public DWORD SectionAlignment;
112                 public DWORD FileAlignment;
113                 public WORD MajorOperatingSystemVersion;
114                 public WORD MinorOperatingSystemVersion;
115                 public WORD MajorImageVersion;
116                 public WORD MinorImageVersion;
117                 public WORD MajorSubsystemVersion;
118                 public WORD MinorSubsystemVersion;
119                 public DWORD Win32VersionValue;
120                 public DWORD SizeOfImage;
121                 public DWORD SizeOfHeaders;
122                 public DWORD CheckSum;
123                 public WORD Subsystem;
124                 public WORD DllCharacteristics;
125                 public ULONGLONG SizeOfStackReserve;
126                 public ULONGLONG SizeOfStackCommit;
127                 public ULONGLONG SizeOfHeapReserve;
128                 public ULONGLONG SizeOfHeapCommit;
129                 public DWORD LoaderFlags;
130                 public DWORD NumberOfRvaAndSizes;
131                 public IMAGE_DATA_DIRECTORY[] DataDirectory;
132
133                 internal void Read(BinaryReader br)
134                 {
135                         Magic = br.ReadUInt16();
136                         if (Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC && Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
137                         {
138                                 throw new BadImageFormatException();
139                         }
140                         MajorLinkerVersion = br.ReadByte();
141                         MinorLinkerVersion = br.ReadByte();
142                         SizeOfCode = br.ReadUInt32();
143                         SizeOfInitializedData = br.ReadUInt32();
144                         SizeOfUninitializedData = br.ReadUInt32();
145                         AddressOfEntryPoint = br.ReadUInt32();
146                         BaseOfCode = br.ReadUInt32();
147                         if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
148                         {
149                                 BaseOfData = br.ReadUInt32();
150                                 ImageBase = br.ReadUInt32();
151                         }
152                         else
153                         {
154                                 ImageBase = br.ReadUInt64();
155                         }
156                         SectionAlignment = br.ReadUInt32();
157                         FileAlignment = br.ReadUInt32();
158                         MajorOperatingSystemVersion = br.ReadUInt16();
159                         MinorOperatingSystemVersion = br.ReadUInt16();
160                         MajorImageVersion = br.ReadUInt16();
161                         MinorImageVersion = br.ReadUInt16();
162                         MajorSubsystemVersion = br.ReadUInt16();
163                         MinorSubsystemVersion = br.ReadUInt16();
164                         Win32VersionValue = br.ReadUInt32();
165                         SizeOfImage = br.ReadUInt32();
166                         SizeOfHeaders = br.ReadUInt32();
167                         CheckSum = br.ReadUInt32();
168                         Subsystem = br.ReadUInt16();
169                         DllCharacteristics = br.ReadUInt16();
170                         if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
171                         {
172                                 SizeOfStackReserve = br.ReadUInt32();
173                                 SizeOfStackCommit = br.ReadUInt32();
174                                 SizeOfHeapReserve = br.ReadUInt32();
175                                 SizeOfHeapCommit = br.ReadUInt32();
176                         }
177                         else
178                         {
179                                 SizeOfStackReserve = br.ReadUInt64();
180                                 SizeOfStackCommit = br.ReadUInt64();
181                                 SizeOfHeapReserve = br.ReadUInt64();
182                                 SizeOfHeapCommit = br.ReadUInt64();
183                         }
184                         LoaderFlags = br.ReadUInt32();
185                         NumberOfRvaAndSizes = br.ReadUInt32();
186                         DataDirectory = new IMAGE_DATA_DIRECTORY[NumberOfRvaAndSizes];
187                         for (uint i = 0; i < NumberOfRvaAndSizes; i++)
188                         {
189                                 DataDirectory[i] = new IMAGE_DATA_DIRECTORY();
190                                 DataDirectory[i].Read(br);
191                         }
192                 }
193         }
194
195         struct IMAGE_DATA_DIRECTORY
196         {
197                 public DWORD VirtualAddress;
198                 public DWORD Size;
199
200                 internal void Read(BinaryReader br)
201                 {
202                         VirtualAddress = br.ReadUInt32();
203                         Size = br.ReadUInt32();
204                 }
205
206                 internal void Write(IKVM.Reflection.Writer.MetadataWriter mw)
207                 {
208                         mw.Write(VirtualAddress);
209                         mw.Write(Size);
210                 }
211         }
212
213         class SectionHeader
214         {
215                 public const DWORD IMAGE_SCN_CNT_CODE = 0x00000020;
216                 public const DWORD IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040;
217                 public const DWORD IMAGE_SCN_MEM_DISCARDABLE = 0x02000000;
218                 public const DWORD IMAGE_SCN_MEM_EXECUTE = 0x20000000;
219                 public const DWORD IMAGE_SCN_MEM_READ = 0x40000000;
220                 public const DWORD IMAGE_SCN_MEM_WRITE = 0x80000000;
221
222                 public string Name;             // 8 byte UTF8 encoded 0-padded
223                 public DWORD VirtualSize;
224                 public DWORD VirtualAddress;
225                 public DWORD SizeOfRawData;
226                 public DWORD PointerToRawData;
227                 public DWORD PointerToRelocations;
228                 public DWORD PointerToLinenumbers;
229                 public WORD NumberOfRelocations;
230                 public WORD NumberOfLinenumbers;
231                 public DWORD Characteristics;
232
233                 internal void Read(BinaryReader br)
234                 {
235                         char[] name = new char[8];
236                         int len = 8;
237                         for (int i = 0; i < 8; i++)
238                         {
239                                 byte b = br.ReadByte();
240                                 name[i] = (char)b;
241                                 if (b == 0 && len == 8)
242                                 {
243                                         len = i;
244                                 }
245                         }
246                         Name = new String(name, 0, len);
247                         VirtualSize = br.ReadUInt32();
248                         VirtualAddress = br.ReadUInt32();
249                         SizeOfRawData = br.ReadUInt32();
250                         PointerToRawData = br.ReadUInt32();
251                         PointerToRelocations = br.ReadUInt32();
252                         PointerToLinenumbers = br.ReadUInt32();
253                         NumberOfRelocations = br.ReadUInt16();
254                         NumberOfLinenumbers = br.ReadUInt16();
255                         Characteristics = br.ReadUInt32();
256                 }
257         }
258
259         sealed class PEReader
260         {
261                 private MSDOS_HEADER msdos = new MSDOS_HEADER();
262                 private IMAGE_NT_HEADERS headers = new IMAGE_NT_HEADERS();
263                 private SectionHeader[] sections;
264
265                 internal void Read(BinaryReader br)
266                 {
267                         msdos.signature = br.ReadUInt16();
268                         br.BaseStream.Seek(58, SeekOrigin.Current);
269                         msdos.peSignatureOffset = br.ReadUInt32();
270
271                         if (msdos.signature != MSDOS_HEADER.MAGIC_MZ)
272                         {
273                                 throw new BadImageFormatException();
274                         }
275
276                         br.BaseStream.Seek(msdos.peSignatureOffset, SeekOrigin.Begin);
277                         headers.Read(br);
278                         sections = new SectionHeader[headers.FileHeader.NumberOfSections];
279                         for (int i = 0; i < sections.Length; i++)
280                         {
281                                 sections[i] = new SectionHeader();
282                                 sections[i].Read(br);
283                         }
284                 }
285
286                 internal IMAGE_FILE_HEADER FileHeader
287                 {
288                         get { return headers.FileHeader; }
289                 }
290
291                 internal IMAGE_OPTIONAL_HEADER OptionalHeader
292                 {
293                         get { return headers.OptionalHeader; }
294                 }
295
296                 internal DWORD GetComDescriptorVirtualAddress()
297                 {
298                         return headers.OptionalHeader.DataDirectory[14].VirtualAddress;
299                 }
300
301                 internal void GetDataDirectoryEntry(int index, out int rva, out int length)
302                 {
303                         rva = (int)headers.OptionalHeader.DataDirectory[index].VirtualAddress;
304                         length = (int)headers.OptionalHeader.DataDirectory[index].Size;
305                 }
306
307                 internal long RvaToFileOffset(DWORD rva)
308                 {
309                         for (int i = 0; i < sections.Length; i++)
310                         {
311                                 if (rva >= sections[i].VirtualAddress && rva < sections[i].VirtualAddress + sections[i].VirtualSize)
312                                 {
313                                         return sections[i].PointerToRawData + rva - sections[i].VirtualAddress;
314                                 }
315                         }
316                         throw new BadImageFormatException();
317                 }
318
319                 internal bool GetSectionInfo(int rva, out string name, out int characteristics)
320                 {
321                         for (int i = 0; i < sections.Length; i++)
322                         {
323                                 if (rva >= sections[i].VirtualAddress && rva < sections[i].VirtualAddress + sections[i].VirtualSize)
324                                 {
325                                         name = sections[i].Name;
326                                         characteristics = (int)sections[i].Characteristics;
327                                         return true;
328                                 }
329                         }
330                         name = null;
331                         characteristics = 0;
332                         return false;
333                 }
334         }
335 }