IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
ModuleReader.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2009-2013 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*/
24using System;
25using System.Collections.Generic;
26using System.IO;
27using System.Reflection.Metadata;
28using System.Reflection.Metadata.Ecma335;
29using System.Text;
30
32
34{
35
36 sealed class ModuleReader : Module
37 {
38
39 sealed class LazyForwardedType
40 {
41
42 readonly int index;
43 Type type;
44
49 internal LazyForwardedType(int index)
50 {
51 this.index = index;
52 }
53
54 internal Type GetType(ModuleReader module)
55 {
56 // guard against circular type forwarding
57 if (type == MarkerType.LazyResolveInProgress)
58 {
59 var typeName = module.GetTypeName(module.ExportedTypeTable.records[index].TypeNamespace, module.ExportedTypeTable.records[index].TypeName);
60 return module.Universe.GetMissingTypeOrThrow(module, module, null, typeName).SetCyclicTypeForwarder();
61 }
62 else if (type == null)
63 {
64 type = MarkerType.LazyResolveInProgress;
65 type = module.ResolveExportedType(index);
66 }
67
68 return type;
69 }
70
71 }
72
73 readonly Stream stream;
74 readonly string location;
75 Assembly assembly;
76 readonly PEReader peFile = new PEReader();
77 readonly CliHeader cliHeader = new CliHeader();
78 string imageRuntimeVersion;
79 int metadataStreamVersion;
80 byte[] stringHeap;
81 byte[] blobHeap;
82 byte[] guidHeap;
83 uint userStringHeapOffset;
84 uint userStringHeapSize;
85 byte[] lazyUserStringHeap;
86 TypeDefImpl[] typeDefs;
87 TypeDefImpl moduleType;
88 Assembly[] assemblyRefs;
89 Type[] typeRefs;
90 Type[] typeSpecs;
91 FieldInfo[] fields;
92 MethodBase[] methods;
93 MemberInfo[] memberRefs;
94 Dictionary<StringHandle, string> strings = new Dictionary<StringHandle, string>();
95 Dictionary<TypeName, Type> types = new Dictionary<TypeName, Type>();
96 Dictionary<TypeName, LazyForwardedType> forwardedTypes = new Dictionary<TypeName, LazyForwardedType>();
97
106 internal ModuleReader(AssemblyReader assembly, Universe universe, Stream stream, string location, bool mapped) :
107 base(universe)
108 {
109 this.stream = universe != null && universe.MetadataOnly ? null : stream;
110 this.location = location;
111 Read(stream, mapped);
112
113 if (assembly == null && AssemblyTable.records.Length != 0)
114 assembly = new AssemblyReader(location, this);
115
116 this.assembly = assembly;
117 }
118
119 void Read(Stream stream, bool mapped)
120 {
121 var br = new BinaryReader(stream);
122 peFile.Read(br, mapped);
123 stream.Seek(peFile.RvaToFileOffset(peFile.GetComDescriptorVirtualAddress()), SeekOrigin.Begin);
124 cliHeader.Read(br);
125
126 stream.Seek(peFile.RvaToFileOffset(cliHeader.MetaData.VirtualAddress), SeekOrigin.Begin);
127 foreach (var sh in ReadStreamHeaders(br, out imageRuntimeVersion))
128 {
129 switch (sh.Name)
130 {
131 case "#Strings":
132 stringHeap = ReadHeap(stream, sh.Offset, sh.Size);
133 break;
134 case "#Blob":
135 blobHeap = ReadHeap(stream, sh.Offset, sh.Size);
136 break;
137 case "#US":
138 userStringHeapOffset = sh.Offset;
139 userStringHeapSize = sh.Size;
140 break;
141 case "#GUID":
142 guidHeap = ReadHeap(stream, sh.Offset, sh.Size);
143 break;
144 case "#~":
145 case "#-":
146 stream.Seek(peFile.RvaToFileOffset(cliHeader.MetaData.VirtualAddress + sh.Offset), SeekOrigin.Begin);
147 ReadTables(br);
148 break;
149 default:
150 // we ignore unknown streams, because the CLR does so too
151 // (and some obfuscators add bogus streams)
152 break;
153 }
154 }
155 }
156
157 internal void SetAssembly(Assembly assembly)
158 {
159 this.assembly = assembly;
160 }
161
162 static StreamHeader[] ReadStreamHeaders(BinaryReader br, out string version)
163 {
164 var signature = br.ReadUInt32();
165 if (signature != 0x424A5342)
166 throw new BadImageFormatException("Invalid metadata signature");
167
168 /*ushort MajorVersion =*/
169 br.ReadUInt16();
170 /*ushort MinorVersion =*/
171 br.ReadUInt16();
172 /*uint Reserved =*/
173 br.ReadUInt32();
174 var Length = br.ReadUInt32();
175 var buf = br.ReadBytes((int)Length);
176 version = Encoding.UTF8.GetString(buf).TrimEnd('\u0000');
177 /*ushort Flags =*/
178 br.ReadUInt16();
179
180 var streams = br.ReadUInt16();
181 var streamHeaders = new StreamHeader[streams];
182 for (int i = 0; i < streamHeaders.Length; i++)
183 {
184 streamHeaders[i] = new StreamHeader();
185 streamHeaders[i].Read(br);
186 }
187
188 return streamHeaders;
189 }
190
191 void ReadTables(BinaryReader br)
192 {
193 var tables = GetTables();
194
195 /*uint Reserved0 =*/
196 br.ReadUInt32();
197 var majorVersion = br.ReadByte();
198 var minorVersion = br.ReadByte();
199 metadataStreamVersion = majorVersion << 16 | minorVersion;
200 var heapSizes = br.ReadByte();
201 /*byte Reserved7 =*/
202 br.ReadByte();
203
204 ulong valid = br.ReadUInt64();
205 ulong sorted = br.ReadUInt64();
206 for (int i = 0; i < 64; i++)
207 {
208 if ((valid & (1UL << i)) != 0)
209 {
210 tables[i].Sorted = (sorted & (1UL << i)) != 0;
211 tables[i].RowCount = br.ReadInt32();
212 }
213 }
214
215 var mr = new MetadataReader(this, br.BaseStream, heapSizes);
216 for (int i = 0; i < 64; i++)
217 if ((valid & (1UL << i)) != 0)
218 tables[i].Read(mr);
219
220 if (ParamPtrTable.RowCount != 0)
221 throw new NotImplementedException("ParamPtr table support has not yet been implemented.");
222 }
223
224 byte[] ReadHeap(Stream stream, uint offset, uint size)
225 {
226 var buf = new byte[size];
227 stream.Seek(peFile.RvaToFileOffset(cliHeader.MetaData.VirtualAddress + offset), SeekOrigin.Begin);
228
229 for (var pos = 0; pos < buf.Length;)
230 {
231 var read = stream.Read(buf, pos, buf.Length - pos);
232 if (read == 0)
233 throw new BadImageFormatException();
234
235 pos += read;
236 }
237
238 return buf;
239 }
240
241 internal void SeekRVA(int rva)
242 {
243 GetStream().Seek(peFile.RvaToFileOffset((uint)rva), SeekOrigin.Begin);
244 }
245
246 internal Stream GetStream()
247 {
248 return stream ?? throw new InvalidOperationException("Operation not available when UniverseOptions.MetadataOnly is enabled.");
249 }
250
251 internal override void GetTypesImpl(List<Type> list)
252 {
253 PopulateTypeDef();
254
255 foreach (var type in typeDefs)
256 if (type != moduleType)
257 list.Add(type);
258 }
259
260 void PopulateTypeDef()
261 {
262 if (typeDefs == null)
263 {
264 typeDefs = new TypeDefImpl[TypeDefTable.records.Length];
265 for (int i = 0; i < typeDefs.Length; i++)
266 {
267 var type = new TypeDefImpl(this, i);
268 typeDefs[i] = type;
269 if (type.IsModulePseudoType)
270 moduleType = type;
271 else if (!type.IsNestedByFlags)
272 types.Add(type.TypeName, type);
273 }
274
275 // add forwarded types to forwardedTypes dictionary (because Module.GetType(string) should return them)
276 for (int i = 0; i < ExportedTypeTable.records.Length; i++)
277 {
278 int implementation = ExportedTypeTable.records[i].Implementation;
279 if (implementation >> 24 == AssemblyRefTable.Index)
280 {
281 var typeName = GetTypeName(ExportedTypeTable.records[i].TypeNamespace, ExportedTypeTable.records[i].TypeName);
282 forwardedTypes.Add(typeName, new LazyForwardedType(i));
283 }
284 }
285 }
286 }
287
288 internal override string GetString(StringHandle handle)
289 {
290 if (handle.IsNil)
291 return null;
292
293 if (!strings.TryGetValue(handle, out var str))
294 {
295 int len = 0;
296 while (stringHeap[MetadataTokens.GetHeapOffset(handle) + len] != 0)
297 len++;
298
299 str = Encoding.UTF8.GetString(stringHeap, MetadataTokens.GetHeapOffset(handle), len);
300 strings.Add(handle, str);
301 }
302
303 return str;
304 }
305
306 static int ReadCompressedUInt(byte[] buffer, ref int offset)
307 {
308 var b1 = buffer[offset++];
309 if (b1 <= 0x7F)
310 {
311 return b1;
312 }
313 else if ((b1 & 0xC0) == 0x80)
314 {
315 var b2 = buffer[offset++];
316 return ((b1 & 0x3F) << 8) | b2;
317 }
318 else
319 {
320 var b2 = buffer[offset++];
321 var b3 = buffer[offset++];
322 var b4 = buffer[offset++];
323 return ((b1 & 0x3F) << 24) + (b2 << 16) + (b3 << 8) + b4;
324 }
325 }
326
327 internal byte[] GetBlobCopy(BlobHandle handle)
328 {
329 var idx = MetadataTokens.GetHeapOffset(handle);
330 var len = ReadCompressedUInt(blobHeap, ref idx);
331 var buf = new byte[len];
332 Buffer.BlockCopy(blobHeap, idx, buf, 0, len);
333 return buf;
334 }
335
336 internal override ByteReader GetBlobReader(BlobHandle handle)
337 {
338 return ByteReader.FromBlob(blobHeap, handle);
339 }
340
341 public override string ResolveString(int metadataToken)
342 {
343 if ((metadataToken >> 24) != 0x70)
344 throw TokenOutOfRangeException(metadataToken);
345
346 var h = MetadataTokens.StringHandle(metadataToken);
347
348 if (strings.TryGetValue(h, out var str) == false)
349 {
350 lazyUserStringHeap ??= ReadHeap(GetStream(), userStringHeapOffset, userStringHeapSize);
351
352 var index = metadataToken & 0xFFFFFF;
353 var len = ReadCompressedUInt(lazyUserStringHeap, ref index) & ~1;
354 var sb = new StringBuilder(len / 2);
355 for (int i = 0; i < len; i += 2)
356 {
357 var ch = (char)(lazyUserStringHeap[index + i] | lazyUserStringHeap[index + i + 1] << 8);
358 sb.Append(ch);
359 }
360
361 str = sb.ToString();
362 strings.Add(h, str);
363 }
364
365 return str;
366 }
367
368 internal override Type ResolveType(int metadataToken, IGenericContext context)
369 {
370 int index = (metadataToken & 0xFFFFFF) - 1;
371 if (index < 0)
372 throw TokenOutOfRangeException(metadataToken);
373
374 if ((metadataToken >> 24) == TypeDefTable.Index && index < TypeDefTable.RowCount)
375 {
376 PopulateTypeDef();
377 return typeDefs[index];
378 }
379
380 if ((metadataToken >> 24) == TypeRefTable.Index && index < TypeRefTable.RowCount)
381 {
382 typeRefs ??= new Type[TypeRefTable.records.Length];
383
384 if (typeRefs[index] == null)
385 {
386 var scope = TypeRefTable.records[index].ResolutionScope;
387 switch (scope >> 24)
388 {
389 case AssemblyRefTable.Index:
390 {
391 var assembly = ResolveAssemblyRef((scope & 0xFFFFFF) - 1);
392 var typeName = GetTypeName(TypeRefTable.records[index].TypeNamespace, TypeRefTable.records[index].TypeName);
393 typeRefs[index] = assembly.ResolveType(this, typeName);
394 break;
395 }
396 case TypeRefTable.Index:
397 {
398 var outer = ResolveType(scope, null);
399 var typeName = GetTypeName(TypeRefTable.records[index].TypeNamespace, TypeRefTable.records[index].TypeName);
400 typeRefs[index] = outer.ResolveNestedType(this, typeName);
401 break;
402 }
403 case ModuleTable.Index:
404 case ModuleRefTable.Index:
405 {
406 Module module;
407
408 if (scope >> 24 == ModuleTable.Index)
409 {
410 if (scope == 0 || scope == 1)
411 module = this;
412 else
413 throw new NotImplementedException("self reference scope?");
414 }
415 else
416 {
417 module = ResolveModuleRef(ModuleRefTable.records[(scope & 0xFFFFFF) - 1]);
418 }
419
420 var typeName = GetTypeName(TypeRefTable.records[index].TypeNamespace, TypeRefTable.records[index].TypeName);
421 typeRefs[index] = module.FindType(typeName) ?? module.Universe.GetMissingTypeOrThrow(this, module, null, typeName);
422 break;
423 }
424 default:
425 throw new NotImplementedException("ResolutionScope = " + scope.ToString("X"));
426 }
427 }
428
429 return typeRefs[index];
430 }
431
432 if ((metadataToken >> 24) == TypeSpecTable.Index && index < TypeSpecTable.RowCount)
433 {
434 typeSpecs ??= new Type[TypeSpecTable.records.Length];
435
436 var type = typeSpecs[index];
437 if (type == null)
438 {
439 var tc = context == null ? null : new TrackingGenericContext(context);
440 typeSpecs[index] = MarkerType.LazyResolveInProgress;
441
442 try
443 {
444 type = Signature.ReadTypeSpec(this, ByteReader.FromBlob(blobHeap, TypeSpecTable.records[index]), tc);
445 }
446 finally
447 {
448 typeSpecs[index] = null;
449 }
450
451 if (tc == null || !tc.IsUsed)
452 typeSpecs[index] = type;
453 }
454 else if (type == MarkerType.LazyResolveInProgress)
455 {
456 if (Universe.MissingMemberResolution)
457 {
458 return Universe
459 .GetMissingTypeOrThrow(this, this, null, new TypeName(null, "Cyclic TypeSpec " + metadataToken.ToString("X")))
460 .SetCyclicTypeSpec()
461 .SetMetadataTokenForMissing(metadataToken, 0);
462 }
463
464 throw new BadImageFormatException("Cyclic TypeSpec " + metadataToken.ToString("X"));
465 }
466
467 return type;
468 }
469
470 throw TokenOutOfRangeException(metadataToken);
471 }
472
473 Module ResolveModuleRef(StringHandle moduleNameIndex)
474 {
475 var moduleName = GetString(moduleNameIndex);
476 return assembly.GetModule(moduleName) ?? throw new FileNotFoundException(moduleName);
477 }
478
479 sealed class TrackingGenericContext : IGenericContext
480 {
481
482 readonly IGenericContext context;
483 bool used;
484
489 internal TrackingGenericContext(IGenericContext context)
490 {
491 this.context = context;
492 }
493
494 internal bool IsUsed
495 {
496 get { return used; }
497 }
498
499 public Type GetGenericTypeArgument(int index)
500 {
501 used = true;
502 return context.GetGenericTypeArgument(index);
503 }
504
505 public Type GetGenericMethodArgument(int index)
506 {
507 used = true;
508 return context.GetGenericMethodArgument(index);
509 }
510
511 }
512
513 TypeName GetTypeName(StringHandle typeNamespace, StringHandle typeName)
514 {
515 return new TypeName(GetString(typeNamespace), GetString(typeName));
516 }
517
518 internal Assembly ResolveAssemblyRef(int index)
519 {
520 assemblyRefs ??= new Assembly[AssemblyRefTable.RowCount];
521 assemblyRefs[index] ??= ResolveAssemblyRefImpl(ref AssemblyRefTable.records[index]);
522 return assemblyRefs[index];
523 }
524
525 Assembly ResolveAssemblyRefImpl(ref AssemblyRefTable.Record rec)
526 {
527 const int PublicKey = 0x0001;
528
529 var name = AssemblyName.GetFullName(
530 GetString(rec.Name),
531 rec.MajorVersion,
532 rec.MinorVersion,
533 rec.BuildNumber,
534 rec.RevisionNumber,
535 rec.Culture.IsNil ? "neutral" : GetString(rec.Culture),
536 rec.PublicKeyOrToken.IsNil ? Array.Empty<byte>() : (rec.Flags & PublicKey) == 0 ? GetBlobCopy(rec.PublicKeyOrToken) : AssemblyName.ComputePublicKeyToken(GetBlobCopy(rec.PublicKeyOrToken)),
537 rec.Flags);
538
539 return Universe.Load(name, this, true);
540 }
541
542 public override Guid ModuleVersionId => GuidFromSpan(guidHeap.AsSpan(16 * (MetadataTokens.GetHeapOffset(ModuleTable.records[0].Mvid) - 1), 16));
543
549 static Guid GuidFromSpan(ReadOnlySpan<byte> b)
550 {
551#if NETFRAMEWORK
552 var _a = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
553 var _b = (short)((b[5] << 8) | b[4]);
554 var _c = (short)((b[7] << 8) | b[6]);
555 var _d = b[8];
556 var _e = b[9];
557 var _f = b[10];
558 var _g = b[11];
559 var _h = b[12];
560 var _i = b[13];
561 var _j = b[14];
562 var _k = b[15];
563 return new Guid(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k);
564#else
565 return new Guid(b);
566#endif
567 }
568
569 public override string FullyQualifiedName => location ?? "<Unknown>";
570
571 public override string Name => location == null ? "<Unknown>" : Path.GetFileName(location);
572
573 public override Assembly Assembly => assembly;
574
575 internal override Type FindType(TypeName typeName)
576 {
577 PopulateTypeDef();
578
579 if (!types.TryGetValue(typeName, out var type))
580 if (forwardedTypes.TryGetValue(typeName, out var fw))
581 return fw.GetType(this);
582
583 return type;
584 }
585
586 internal override Type FindTypeIgnoreCase(TypeName lowerCaseName)
587 {
588 PopulateTypeDef();
589
590 foreach (var type in types.Values)
591 if (type.TypeName.ToLowerInvariant() == lowerCaseName)
592 return type;
593
594 foreach (var name in forwardedTypes.Keys)
595 if (name.ToLowerInvariant() == lowerCaseName)
596 return forwardedTypes[name].GetType(this);
597
598 return null;
599 }
600
601 Exception TokenOutOfRangeException(int metadataToken)
602 {
603 return new ArgumentOutOfRangeException("metadataToken", String.Format("Token 0x{0:x8} is not valid in the scope of module {1}.", metadataToken, this.Name));
604 }
605
606 public override MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
607 {
608 switch (metadataToken >> 24)
609 {
610 case FieldTable.Index:
611 return ResolveField(metadataToken, genericTypeArguments, genericMethodArguments);
612 case MemberRefTable.Index:
613 int index = (metadataToken & 0xFFFFFF) - 1;
614 if (index < 0 || index >= MemberRefTable.RowCount)
615 goto default;
616
617 return GetMemberRef(index, genericTypeArguments, genericMethodArguments);
618 case MethodDefTable.Index:
619 case MethodSpecTable.Index:
620 return ResolveMethod(metadataToken, genericTypeArguments, genericMethodArguments);
621 case TypeRefTable.Index:
622 case TypeDefTable.Index:
623 case TypeSpecTable.Index:
624 return ResolveType(metadataToken, genericTypeArguments, genericMethodArguments);
625 default:
626 throw TokenOutOfRangeException(metadataToken);
627 }
628 }
629
630 internal FieldInfo GetFieldAt(TypeDefImpl owner, int index)
631 {
632 fields ??= new FieldInfo[FieldTable.records.Length];
633 fields[index] ??= new FieldDefImpl(this, owner ?? FindFieldOwner(index), index);
634 return fields[index];
635 }
636
637 public override FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
638 {
639 int index = (metadataToken & 0xFFFFFF) - 1;
640 if (index < 0)
641 {
642 throw TokenOutOfRangeException(metadataToken);
643 }
644 else if ((metadataToken >> 24) == FieldTable.Index && index < FieldTable.RowCount)
645 {
646 return GetFieldAt(null, index);
647 }
648 else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRefTable.RowCount)
649 {
650 var field = GetMemberRef(index, genericTypeArguments, genericMethodArguments) as FieldInfo;
651 if (field != null)
652 return field;
653
654 throw new ArgumentException(String.Format("Token 0x{0:x8} is not a valid FieldInfo token in the scope of module {1}.", metadataToken, this.Name), "metadataToken");
655 }
656 else
657 {
658 throw TokenOutOfRangeException(metadataToken);
659 }
660 }
661
662 TypeDefImpl FindFieldOwner(int fieldIndex)
663 {
664 // TODO use binary search?
665 for (int i = 0; i < TypeDefTable.records.Length; i++)
666 {
667 var field = TypeDefTable.records[i].FieldList - 1;
668 var end = TypeDefTable.records.Length > i + 1 ? TypeDefTable.records[i + 1].FieldList - 1 : FieldTable.records.Length;
669 if (field <= fieldIndex && fieldIndex < end)
670 {
671 PopulateTypeDef();
672 return typeDefs[i];
673 }
674 }
675
676 throw new InvalidOperationException();
677 }
678
679 internal MethodBase GetMethodAt(TypeDefImpl owner, int index)
680 {
681 methods ??= new MethodBase[MethodDefTable.records.Length];
682 if (methods[index] == null)
683 {
684 var method = new MethodDefImpl(this, owner ?? FindMethodOwner(index), index);
685 methods[index] = method.IsConstructor ? new ConstructorInfoImpl(method) : (MethodBase)method;
686 }
687
688 return methods[index];
689 }
690
691 public override MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
692 {
693 int index = (metadataToken & 0xFFFFFF) - 1;
694 if (index < 0)
695 {
696 throw TokenOutOfRangeException(metadataToken);
697 }
698 else if ((metadataToken >> 24) == MethodDefTable.Index && index < MethodDefTable.RowCount)
699 {
700 return GetMethodAt(null, index);
701 }
702 else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRefTable.RowCount)
703 {
704 var method = GetMemberRef(index, genericTypeArguments, genericMethodArguments) as MethodBase;
705 if (method != null)
706 return method;
707
708 throw new ArgumentException(String.Format("Token 0x{0:x8} is not a valid MethodBase token in the scope of module {1}.", metadataToken, this.Name), "metadataToken");
709 }
710 else if ((metadataToken >> 24) == MethodSpecTable.Index && index < MethodSpecTable.RowCount)
711 {
712 var method = (MethodInfo)ResolveMethod(MethodSpecTable.records[index].Method, genericTypeArguments, genericMethodArguments);
713 var instantiation = ByteReader.FromBlob(blobHeap, MethodSpecTable.records[index].Instantiation);
714 return method.MakeGenericMethod(Signature.ReadMethodSpec(this, instantiation, new GenericContext(genericTypeArguments, genericMethodArguments)));
715 }
716 else
717 {
718 throw TokenOutOfRangeException(metadataToken);
719 }
720 }
721
722 public override Type[] __ResolveOptionalParameterTypes(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments, out CustomModifiers[] customModifiers)
723 {
724 int index = (metadataToken & 0xFFFFFF) - 1;
725 if (index < 0)
726 {
727 throw TokenOutOfRangeException(metadataToken);
728 }
729 else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRefTable.RowCount)
730 {
731 var sig = MemberRefTable.records[index].Signature;
732 return Signature.ReadOptionalParameterTypes(this, GetBlobReader(sig), new GenericContext(genericTypeArguments, genericMethodArguments), out customModifiers);
733 }
734 else if ((metadataToken >> 24) == MethodDefTable.Index && index < MethodDefTable.RowCount)
735 {
736 // for convenience, we support passing a MethodDef token as well, because in some places
737 // it makes sense to have a vararg method that is referred to by its methoddef (e.g. ldftn).
738 // Note that MethodSpec doesn't make sense, because generic methods cannot be vararg.
739 customModifiers = Array.Empty<CustomModifiers>();
740 return Type.EmptyTypes;
741 }
742 else
743 {
744 throw TokenOutOfRangeException(metadataToken);
745 }
746 }
747
748 public override CustomModifiers __ResolveTypeSpecCustomModifiers(int typeSpecToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
749 {
750 int index = (typeSpecToken & 0xFFFFFF) - 1;
751 if (typeSpecToken >> 24 != TypeSpecTable.Index || index < 0 || index >= TypeSpecTable.RowCount)
752 throw TokenOutOfRangeException(typeSpecToken);
753
754 return CustomModifiers.Read(this, ByteReader.FromBlob(blobHeap, TypeSpecTable.records[index]), new GenericContext(genericTypeArguments, genericMethodArguments));
755 }
756
757 public override string ScopeName
758 {
759 get { return GetString(ModuleTable.records[0].Name); }
760 }
761
762 TypeDefImpl FindMethodOwner(int methodIndex)
763 {
764 // TODO use binary search?
765 for (int i = 0; i < TypeDefTable.records.Length; i++)
766 {
767 int method = TypeDefTable.records[i].MethodList - 1;
768 int end = TypeDefTable.records.Length > i + 1 ? TypeDefTable.records[i + 1].MethodList - 1 : MethodDefTable.records.Length;
769 if (method <= methodIndex && methodIndex < end)
770 {
771 PopulateTypeDef();
772 return typeDefs[i];
773 }
774 }
775
776 throw new InvalidOperationException();
777 }
778
779 MemberInfo GetMemberRef(int index, Type[] genericTypeArguments, Type[] genericMethodArguments)
780 {
781 memberRefs ??= new MemberInfo[MemberRefTable.records.Length];
782
783 if (memberRefs[index] == null)
784 {
785 var owner = MemberRefTable.records[index].Class;
786 var sig = MemberRefTable.records[index].Signature;
787 var name = GetString(MemberRefTable.records[index].Name);
788 switch (owner >> 24)
789 {
790 case MethodDefTable.Index:
791 return GetMethodAt(null, (owner & 0xFFFFFF) - 1);
792 case ModuleRefTable.Index:
793 memberRefs[index] = ResolveTypeMemberRef(ResolveModuleType(owner), name, ByteReader.FromBlob(blobHeap, sig));
794 break;
795 case TypeDefTable.Index:
796 case TypeRefTable.Index:
797 memberRefs[index] = ResolveTypeMemberRef(ResolveType(owner), name, ByteReader.FromBlob(blobHeap, sig));
798 break;
799 case TypeSpecTable.Index:
800 {
801 var type = ResolveType(owner, genericTypeArguments, genericMethodArguments);
802 if (type.IsArray)
803 {
804 var methodSig = MethodSignature.ReadSig(this, ByteReader.FromBlob(blobHeap, sig), new GenericContext(genericTypeArguments, genericMethodArguments));
805 return type.FindMethod(name, methodSig) ?? Universe.GetMissingMethodOrThrow(this, type, name, methodSig);
806 }
807 else if (type.IsConstructedGenericType)
808 {
809 var member = ResolveTypeMemberRef(type.GetGenericTypeDefinition(), name, ByteReader.FromBlob(blobHeap, sig));
810 var mb = member as MethodBase;
811 if (mb != null)
812 member = mb.BindTypeParameters(type);
813
814 var fi = member as FieldInfo;
815 if (fi != null)
816 member = fi.BindTypeParameters(type);
817
818 return member;
819 }
820 else
821 {
822 return ResolveTypeMemberRef(type, name, ByteReader.FromBlob(blobHeap, sig));
823 }
824 }
825 default:
826 throw new BadImageFormatException();
827 }
828 }
829
830 return memberRefs[index];
831 }
832
833 Type ResolveModuleType(int token)
834 {
835 int index = (token & 0xFFFFFF) - 1;
836 var name = GetString(ModuleRefTable.records[index]);
837 var module = assembly.GetModule(name);
838 if (module == null || module.IsResource())
839 throw new BadImageFormatException();
840
841 return module.GetModuleType();
842 }
843
844 MemberInfo ResolveTypeMemberRef(Type type, string name, ByteReader sig)
845 {
846 if (sig.PeekByte() == Signature.FIELD)
847 {
848 var org = type;
849 var fieldSig = FieldSignature.ReadSig(this, sig, type);
850 var field = type.FindField(name, fieldSig);
851 if (field == null && Universe.MissingMemberResolution)
852 return Universe.GetMissingFieldOrThrow(this, type, name, fieldSig);
853
854 while (field == null && (type = type.BaseType) != null)
855 field = type.FindField(name, fieldSig);
856
857 if (field != null)
858 return field;
859
860 throw new MissingFieldException(org.ToString(), name);
861 }
862 else
863 {
864 var org = type;
865 var methodSig = MethodSignature.ReadSig(this, sig, type);
866 var method = type.FindMethod(name, methodSig);
867 if (method == null && Universe.MissingMemberResolution)
868 return Universe.GetMissingMethodOrThrow(this, type, name, methodSig);
869
870 while (method == null && (type = type.BaseType) != null)
871 method = type.FindMethod(name, methodSig);
872
873 if (method != null)
874 return method;
875
876 throw new MissingMethodException(org.ToString(), name);
877 }
878 }
879
880 internal ByteReader GetStandAloneSig(int index)
881 {
882 return ByteReader.FromBlob(blobHeap, StandAloneSigTable.records[index]);
883 }
884
885 public override byte[] ResolveSignature(int metadataToken)
886 {
887 int index = (metadataToken & 0xFFFFFF) - 1;
888 if ((metadataToken >> 24) == StandAloneSigTable.Index && index >= 0 && index < StandAloneSigTable.RowCount)
889 {
890 var br = GetStandAloneSig(index);
891 return br.ReadBytes(br.Length);
892 }
893 else
894 {
895 throw TokenOutOfRangeException(metadataToken);
896 }
897 }
898
899 public override __StandAloneMethodSig __ResolveStandAloneMethodSig(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
900 {
901 int index = (metadataToken & 0xFFFFFF) - 1;
902 if ((metadataToken >> 24) == StandAloneSigTable.Index && index >= 0 && index < StandAloneSigTable.RowCount)
903 return MethodSignature.ReadStandAloneMethodSig(this, GetStandAloneSig(index), new GenericContext(genericTypeArguments, genericMethodArguments));
904 else
905 throw TokenOutOfRangeException(metadataToken);
906 }
907
908 internal MethodInfo GetEntryPoint()
909 {
910 if (cliHeader.EntryPointToken != 0 && (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) == 0)
911 return (MethodInfo)ResolveMethod((int)cliHeader.EntryPointToken);
912
913 return null;
914 }
915
916 internal string[] GetManifestResourceNames()
917 {
918 var names = new string[ManifestResourceTable.records.Length];
919 for (int i = 0; i < ManifestResourceTable.records.Length; i++)
920 names[i] = GetString(ManifestResourceTable.records[i].Name);
921
922 return names;
923 }
924
925 internal ManifestResourceInfo GetManifestResourceInfo(string resourceName)
926 {
927 for (int i = 0; i < ManifestResourceTable.records.Length; i++)
928 {
929 if (resourceName == GetString(ManifestResourceTable.records[i].Name))
930 {
931 var info = new ManifestResourceInfo(this, i);
932 var asm = info.ReferencedAssembly;
933 if (asm != null && !asm.__IsMissing && asm.GetManifestResourceInfo(resourceName) == null)
934 return null;
935
936 return info;
937 }
938 }
939
940 return null;
941 }
942
943 internal Stream GetManifestResourceStream(string resourceName)
944 {
945 for (int i = 0; i < ManifestResourceTable.records.Length; i++)
946 {
947 if (resourceName == GetString(ManifestResourceTable.records[i].Name))
948 {
949 if (ManifestResourceTable.records[i].Implementation != 0x26000000)
950 {
951 var info = new ManifestResourceInfo(this, i);
952 switch (ManifestResourceTable.records[i].Implementation >> 24)
953 {
954 case FileTable.Index:
955 var fileName = Path.Combine(Path.GetDirectoryName(location), info.FileName);
956 if (System.IO.File.Exists(fileName))
957 {
958 // note that, like System.Reflection, we return null for zero length files and
959 // ManifestResource.Offset is ignored
960 var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete);
961 if (fs.Length == 0)
962 {
963 fs.Dispose();
964 return null;
965 }
966
967 return fs;
968 }
969
970 return null;
971 case AssemblyRefTable.Index:
972 var asm = info.ReferencedAssembly;
973 if (asm.__IsMissing)
974 return null;
975
976 return asm.GetManifestResourceStream(resourceName);
977 default:
978 throw new BadImageFormatException();
979 }
980 }
981 SeekRVA((int)cliHeader.Resources.VirtualAddress + ManifestResourceTable.records[i].Offset);
982 var br = new BinaryReader(stream);
983 var length = br.ReadInt32();
984 return new MemoryStream(br.ReadBytes(length));
985 }
986 }
987
988 return null;
989 }
990
991 public override AssemblyName[] __GetReferencedAssemblies()
992 {
993 var list = new List<AssemblyName>();
994 for (int i = 0; i < AssemblyRefTable.records.Length; i++)
995 {
996 var name = new AssemblyName();
997 name.Name = GetString(AssemblyRefTable.records[i].Name);
998 name.Version = new Version(
999 AssemblyRefTable.records[i].MajorVersion,
1000 AssemblyRefTable.records[i].MinorVersion,
1001 AssemblyRefTable.records[i].BuildNumber,
1002 AssemblyRefTable.records[i].RevisionNumber);
1003
1004 if (AssemblyRefTable.records[i].PublicKeyOrToken.IsNil == false)
1005 {
1006 byte[] keyOrToken = GetBlobCopy(AssemblyRefTable.records[i].PublicKeyOrToken);
1007 const int PublicKey = 0x0001;
1008 if ((AssemblyRefTable.records[i].Flags & PublicKey) != 0)
1009 name.SetPublicKey(keyOrToken);
1010 else
1011 name.SetPublicKeyToken(keyOrToken);
1012 }
1013 else
1014 {
1015 name.SetPublicKeyToken(Array.Empty<byte>());
1016 }
1017
1018 if (AssemblyRefTable.records[i].Culture.IsNil == false)
1019 name.CultureName = GetString(AssemblyRefTable.records[i].Culture);
1020 else
1021 name.CultureName = "";
1022
1023 if (AssemblyRefTable.records[i].HashValue.IsNil == false)
1024 name.hash = GetBlobCopy(AssemblyRefTable.records[i].HashValue);
1025
1026 name.RawFlags = (AssemblyNameFlags)AssemblyRefTable.records[i].Flags;
1027 list.Add(name);
1028 }
1029
1030 return list.ToArray();
1031 }
1032
1033 public override void __ResolveReferencedAssemblies(Assembly[] assemblies)
1034 {
1035 assemblyRefs ??= new Assembly[AssemblyRefTable.RowCount];
1036
1037 for (int i = 0; i < assemblies.Length; i++)
1038 if (assemblyRefs[i] == null)
1039 assemblyRefs[i] = assemblies[i];
1040 }
1041
1042 public override string[] __GetReferencedModules()
1043 {
1044 var arr = new string[this.ModuleRefTable.RowCount];
1045 for (int i = 0; i < arr.Length; i++)
1046 arr[i] = GetString(ModuleRefTable.records[i]);
1047
1048 return arr;
1049 }
1050
1051 public override Type[] __GetReferencedTypes()
1052 {
1053 var arr = new Type[TypeRefTable.RowCount];
1054 for (int i = 0; i < arr.Length; i++)
1055 arr[i] = ResolveType((TypeRefTable.Index << 24) + i + 1);
1056
1057 return arr;
1058 }
1059
1060 public override Type[] __GetExportedTypes()
1061 {
1062 var arr = new Type[ExportedTypeTable.RowCount];
1063 for (int i = 0; i < arr.Length; i++)
1064 arr[i] = ResolveExportedType(i);
1065
1066 return arr;
1067 }
1068
1069 private Type ResolveExportedType(int index)
1070 {
1071 var typeName = GetTypeName(ExportedTypeTable.records[index].TypeNamespace, ExportedTypeTable.records[index].TypeName);
1072 var implementation = ExportedTypeTable.records[index].Implementation;
1073 var token = ExportedTypeTable.records[index].TypeDefId;
1074 var flags = ExportedTypeTable.records[index].Flags;
1075 switch (implementation >> 24)
1076 {
1077 case AssemblyRefTable.Index:
1078 return ResolveAssemblyRef((implementation & 0xFFFFFF) - 1).ResolveType(this, typeName).SetMetadataTokenForMissing(token, flags);
1079 case ExportedTypeTable.Index:
1080 return ResolveExportedType((implementation & 0xFFFFFF) - 1).ResolveNestedType(this, typeName).SetMetadataTokenForMissing(token, flags);
1081 case FileTable.Index:
1082 Module module = assembly.GetModule(GetString(FileTable.records[(implementation & 0xFFFFFF) - 1].Name));
1083 return module.FindType(typeName) ?? module.Universe.GetMissingTypeOrThrow(this, module, null, typeName).SetMetadataTokenForMissing(token, flags);
1084 default:
1085 throw new BadImageFormatException();
1086 }
1087 }
1088
1089 internal override Type GetModuleType()
1090 {
1091 PopulateTypeDef();
1092 return moduleType;
1093 }
1094
1095 public override string __ImageRuntimeVersion
1096 {
1097 get { return imageRuntimeVersion; }
1098 }
1099
1100 public override int MDStreamVersion
1101 {
1102 get { return metadataStreamVersion; }
1103 }
1104
1105 public override void __GetDataDirectoryEntry(int index, out int rva, out int length)
1106 {
1107 peFile.GetDataDirectoryEntry(index, out rva, out length);
1108 }
1109
1110 public override long __RelativeVirtualAddressToFileOffset(int rva)
1111 {
1112 return peFile.RvaToFileOffset((uint)rva);
1113 }
1114
1115 public override bool __GetSectionInfo(int rva, out string name, out int characteristics, out int virtualAddress, out int virtualSize, out int pointerToRawData, out int sizeOfRawData)
1116 {
1117 return peFile.GetSectionInfo(rva, out name, out characteristics, out virtualAddress, out virtualSize, out pointerToRawData, out sizeOfRawData);
1118 }
1119
1120 public override int __ReadDataFromRVA(int rva, byte[] data, int offset, int length)
1121 {
1122 SeekRVA(rva);
1123
1124 var totalBytesRead = 0;
1125 while (length > 0)
1126 {
1127 var read = stream.Read(data, offset, length);
1128 if (read == 0)
1129 break; // C++ assemblies can have fields that have an RVA that lies outside of the file
1130
1131 offset += read;
1132 length -= read;
1133 totalBytesRead += read;
1134 }
1135
1136 return totalBytesRead;
1137 }
1138
1139 public override void GetPEKind(out PortableExecutableKinds peKind, out ImageFileMachine machine)
1140 {
1141 peKind = 0;
1142 if ((cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_ILONLY) != 0)
1143 peKind |= PortableExecutableKinds.ILOnly;
1144
1145 switch (cliHeader.Flags & (CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED))
1146 {
1147 case CliHeader.COMIMAGE_FLAGS_32BITREQUIRED:
1148 peKind |= PortableExecutableKinds.Required32Bit;
1149 break;
1150 case CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED:
1151 peKind |= PortableExecutableKinds.Preferred32Bit;
1152 break;
1153 default:
1154 // COMIMAGE_FLAGS_32BITPREFERRED by itself is illegal, so we ignore it
1155 // (not setting any flag is ok)
1156 break;
1157 }
1158
1159 if (peFile.OptionalHeader.Magic == IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC)
1160 peKind |= PortableExecutableKinds.PE32Plus;
1161
1162 machine = (ImageFileMachine)peFile.FileHeader.Machine;
1163 }
1164
1165 public override int __Subsystem
1166 {
1167 get { return peFile.OptionalHeader.Subsystem; }
1168 }
1169
1170 public override IList<CustomAttributeData> __GetPlaceholderAssemblyCustomAttributes(bool multiple, bool security)
1171 {
1172 TypeName typeName;
1173 switch ((multiple ? 1 : 0) + (security ? 2 : 0))
1174 {
1175 case 0:
1176 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHere");
1177 break;
1178 case 1:
1179 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereM");
1180 break;
1181 case 2:
1182 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereS");
1183 break;
1184 case 3:
1185 default:
1186 typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereSM");
1187 break;
1188 }
1189
1190 var list = new List<CustomAttributeData>();
1191 for (int i = 0; i < CustomAttributeTable.records.Length; i++)
1192 {
1193 if ((CustomAttributeTable.records[i].Parent >> 24) == TypeRefTable.Index)
1194 {
1195 var index = (CustomAttributeTable.records[i].Parent & 0xFFFFFF) - 1;
1196 if (typeName == GetTypeName(TypeRefTable.records[index].TypeNamespace, TypeRefTable.records[index].TypeName))
1197 list.Add(new CustomAttributeData(this, i));
1198 }
1199 }
1200
1201 return list;
1202 }
1203
1204 internal override void Dispose()
1205 {
1206 stream?.Dispose();
1207 }
1208
1209 internal override void ExportTypes(AssemblyFileHandle fileToken, IKVM.Reflection.Emit.ModuleBuilder manifestModule)
1210 {
1211 PopulateTypeDef();
1212 manifestModule.ExportTypes(typeDefs, fileToken);
1213 }
1214
1215 protected override ulong GetImageBaseImpl()
1216 {
1217 return peFile.OptionalHeader.ImageBase;
1218 }
1219
1220 protected override ulong GetStackReserveImpl()
1221 {
1222 return peFile.OptionalHeader.SizeOfStackReserve;
1223 }
1224
1225 protected override uint GetFileAlignmentImpl()
1226 {
1227 return peFile.OptionalHeader.FileAlignment;
1228 }
1229
1230 protected override DllCharacteristics GetDllCharacteristicsImpl()
1231 {
1232 return (DllCharacteristics)peFile.OptionalHeader.DllCharacteristics;
1233 }
1234
1235 public override int __EntryPointRVA
1236 {
1237 get { return (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) != 0 ? (int)cliHeader.EntryPointToken : 0; }
1238 }
1239
1240 public override int __EntryPointToken
1241 {
1242 get { return (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) == 0 ? (int)cliHeader.EntryPointToken : 0; }
1243 }
1244
1245 public override System.Security.Cryptography.X509Certificates.X509Certificate GetSignerCertificate()
1246 {
1247 return Authenticode.GetSignerCertificate(GetStream());
1248 }
1249
1250 }
1251
1252}
IKVM.Reflection.Module Module
IKVM.Reflection.Type Type
IKVM.Reflection.Assembly Assembly
IKVM.Reflection.AssemblyName AssemblyName
IKVM.Reflection.FieldInfo FieldInfo
IKVM.Reflection.MemberInfo MemberInfo
IKVM.Reflection.MethodInfo MethodInfo
IKVM.Reflection.MethodBase MethodBase
global::java.lang.invoke.LambdaForm.Name Name
Represents a method signature from IL metadadata.
override MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
override __StandAloneMethodSig __ResolveStandAloneMethodSig(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
override System.Security.Cryptography.X509Certificates.X509Certificate GetSignerCertificate()
override string ResolveString(int metadataToken)
override void GetPEKind(out PortableExecutableKinds peKind, out ImageFileMachine machine)
override IList< CustomAttributeData > __GetPlaceholderAssemblyCustomAttributes(bool multiple, bool security)
override string[] __GetReferencedModules()
override CustomModifiers __ResolveTypeSpecCustomModifiers(int typeSpecToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
override long __RelativeVirtualAddressToFileOffset(int rva)
override bool __GetSectionInfo(int rva, out string name, out int characteristics, out int virtualAddress, out int virtualSize, out int pointerToRawData, out int sizeOfRawData)
override void __ResolveReferencedAssemblies(Assembly[] assemblies)
override AssemblyName[] __GetReferencedAssemblies()
override MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
override void __GetDataDirectoryEntry(int index, out int rva, out int length)
override Type[] __ResolveOptionalParameterTypes(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments, out CustomModifiers[] customModifiers)
override DllCharacteristics GetDllCharacteristicsImpl()
override FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
override byte[] ResolveSignature(int metadataToken)
override int __ReadDataFromRVA(int rva, byte[] data, int offset, int length)
Type GetGenericTypeArgument(int index)