// dnlib: See LICENSE.txt for more info using System; using System.Collections.Generic; using System.Diagnostics; using dnlib.DotNet.Emit; using dnlib.DotNet.MD; using dnlib.DotNet.Pdb; using dnlib.PE; using dnlib.Threading; using dnlib.W32Resources; namespace dnlib.DotNet { readonly struct ModuleLoader { readonly ModuleDef module; readonly ICancellationToken cancellationToken; readonly Dictionary seen; readonly Stack stack; ModuleLoader(ModuleDef module, ICancellationToken cancellationToken) { const int CAPACITY = 0x4000; this.module = module; this.cancellationToken = cancellationToken; seen = new Dictionary(CAPACITY); stack = new Stack(CAPACITY); } public static void LoadAll(ModuleDef module, ICancellationToken cancellationToken) => new ModuleLoader(module, cancellationToken).Load(); void Add(UTF8String a) { } void Add(Guid? a) { } void Add(ushort a) { } void Add(AssemblyHashAlgorithm a) { } void Add(Version a) { } void Add(AssemblyAttributes a) { } void Add(PublicKeyBase a) { } void Add(RVA a) { } void Add(IManagedEntryPoint a) { } void Add(string a) { } void Add(WinMDStatus a) { } void Add(TypeAttributes a) { } void Add(FieldAttributes a) { } void Add(uint? a) { } void Add(byte[] a) { } void Add(MethodImplAttributes a) { } void Add(MethodAttributes a) { } void Add(MethodSemanticsAttributes a) { } void Add(ParamAttributes a) { } void Add(ElementType a) { } void Add(SecurityAction a) { } void Add(EventAttributes a) { } void Add(PropertyAttributes a) { } void Add(PInvokeAttributes a) { } void Add(FileAttributes a) { } void Add(ManifestResourceAttributes a) { } void Add(GenericParamAttributes a) { } void Add(NativeType a) { } void Load() { LoadAllTables(); Load(module); Process(); } void Process() { while (stack.Count != 0) { if (cancellationToken is not null) cancellationToken.ThrowIfCancellationRequested(); var o = stack.Pop(); LoadObj(o); } } void LoadAllTables() { var resolver = module as ITokenResolver; if (resolver is null) return; for (Table tbl = 0; tbl <= Table.GenericParamConstraint; tbl++) { for (uint rid = 1; ; rid++) { var o = resolver.ResolveToken(new MDToken(tbl, rid).Raw, new GenericParamContext()); if (o is null) break; Add(o); Process(); } } } void LoadObj(object o) { if (o is TypeSig ts) { Load(ts); return; } if (o is IMDTokenProvider mdt) { Load(mdt); return; } if (o is CustomAttribute ca) { Load(ca); return; } if (o is SecurityAttribute sa) { Load(sa); return; } if (o is CANamedArgument na) { Load(na); return; } if (o is Parameter p) { Load(p); return; } if (o is PdbMethod pdbMethod) { Load(pdbMethod); return; } if (o is ResourceDirectory rd) { Load(rd); return; } if (o is ResourceData rdata) { Load(rdata); return; } Debug.Fail("Unknown type"); } void Load(TypeSig ts) { if (ts is null) return; Add(ts.Next); switch (ts.ElementType) { case ElementType.Void: case ElementType.Boolean: case ElementType.Char: case ElementType.I1: case ElementType.U1: case ElementType.I2: case ElementType.U2: case ElementType.I4: case ElementType.U4: case ElementType.I8: case ElementType.U8: case ElementType.R4: case ElementType.R8: case ElementType.String: case ElementType.ValueType: case ElementType.Class: case ElementType.TypedByRef: case ElementType.I: case ElementType.U: case ElementType.Object: Add(((TypeDefOrRefSig)ts).TypeDefOrRef); break; case ElementType.Var: case ElementType.MVar: var vsig = (GenericSig)ts; Add(vsig.OwnerType); Add(vsig.OwnerMethod); break; case ElementType.GenericInst: var gis = (GenericInstSig)ts; Add(gis.GenericType); Add(gis.GenericArguments); break; case ElementType.FnPtr: var fpsig = (FnPtrSig)ts; Add(fpsig.Signature); break; case ElementType.CModReqd: case ElementType.CModOpt: var cmod = (ModifierSig)ts; Add(cmod.Modifier); break; case ElementType.End: case ElementType.Ptr: case ElementType.ByRef: case ElementType.Array: case ElementType.ValueArray: case ElementType.SZArray: case ElementType.Module: case ElementType.Pinned: case ElementType.Sentinel: case ElementType.R: case ElementType.Internal: default: break; } } void Load(IMDTokenProvider mdt) { if (mdt is null) return; switch (mdt.MDToken.Table) { case Table.Module: Load((ModuleDef)mdt); break; case Table.TypeRef: Load((TypeRef)mdt); break; case Table.TypeDef: Load((TypeDef)mdt); break; case Table.Field: Load((FieldDef)mdt); break; case Table.Method: Load((MethodDef)mdt); break; case Table.Param: Load((ParamDef)mdt); break; case Table.InterfaceImpl: Load((InterfaceImpl)mdt); break; case Table.MemberRef: Load((MemberRef)mdt); break; case Table.Constant: Load((Constant)mdt); break; case Table.DeclSecurity: Load((DeclSecurity)mdt); break; case Table.ClassLayout: Load((ClassLayout)mdt); break; case Table.StandAloneSig: Load((StandAloneSig)mdt); break; case Table.Event: Load((EventDef)mdt); break; case Table.Property: Load((PropertyDef)mdt); break; case Table.ModuleRef: Load((ModuleRef)mdt); break; case Table.TypeSpec: Load((TypeSpec)mdt); break; case Table.ImplMap: Load((ImplMap)mdt); break; case Table.Assembly: Load((AssemblyDef)mdt); break; case Table.AssemblyRef: Load((AssemblyRef)mdt); break; case Table.File: Load((FileDef)mdt); break; case Table.ExportedType: Load((ExportedType)mdt); break; case Table.GenericParam: Load((GenericParam)mdt); break; case Table.MethodSpec: Load((MethodSpec)mdt); break; case Table.GenericParamConstraint: Load((GenericParamConstraint)mdt); break; case Table.ManifestResource: var rsrc = mdt as Resource; if (rsrc is not null) { Load(rsrc); break; } var mr = mdt as ManifestResource; if (mr is not null) { Load(mr); break; } Debug.Fail("Unknown ManifestResource"); break; case Table.FieldPtr: case Table.MethodPtr: case Table.ParamPtr: case Table.CustomAttribute: case Table.FieldMarshal: case Table.FieldLayout: case Table.EventMap: case Table.EventPtr: case Table.PropertyMap: case Table.PropertyPtr: case Table.MethodSemantics: case Table.MethodImpl: case Table.FieldRVA: case Table.ENCLog: case Table.ENCMap: case Table.AssemblyProcessor: case Table.AssemblyOS: case Table.AssemblyRefProcessor: case Table.AssemblyRefOS: case Table.NestedClass: case Table.Document: case Table.MethodDebugInformation: case Table.LocalScope: case Table.LocalVariable: case Table.LocalConstant: case Table.ImportScope: case Table.StateMachineMethod: case Table.CustomDebugInformation: break; default: Debug.Fail("Unknown type"); break; } } void Load(ModuleDef obj) { if (obj is null || obj != module) return; Add(obj.Generation); Add(obj.Name); Add(obj.Mvid); Add(obj.EncId); Add(obj.EncBaseId); Add(obj.CustomAttributes); Add(obj.Assembly); Add(obj.Types); Add(obj.ExportedTypes); Add(obj.NativeEntryPoint); Add(obj.ManagedEntryPoint); Add(obj.Resources); Add(obj.VTableFixups); Add(obj.Location); Add(obj.Win32Resources); Add(obj.RuntimeVersion); Add(obj.WinMDStatus); Add(obj.RuntimeVersionWinMD); Add(obj.WinMDVersion); Add(obj.PdbState); } void Load(TypeRef obj) { if (obj is null) return; Add(obj.ResolutionScope); Add(obj.Name); Add(obj.Namespace); Add(obj.CustomAttributes); } void Load(TypeDef obj) { if (obj is null) return; Add(obj.Module2); Add(obj.Attributes); Add(obj.Name); Add(obj.Namespace); Add(obj.BaseType); Add(obj.Fields); Add(obj.Methods); Add(obj.GenericParameters); Add(obj.Interfaces); Add(obj.DeclSecurities); Add(obj.ClassLayout); Add(obj.DeclaringType); Add(obj.DeclaringType2); Add(obj.NestedTypes); Add(obj.Events); Add(obj.Properties); Add(obj.CustomAttributes); } void Load(FieldDef obj) { if (obj is null) return; Add(obj.CustomAttributes); Add(obj.Attributes); Add(obj.Name); Add(obj.Signature); Add(obj.FieldOffset); Add(obj.MarshalType); Add(obj.RVA); Add(obj.InitialValue); Add(obj.ImplMap); Add(obj.Constant); Add(obj.DeclaringType); } void Load(MethodDef obj) { if (obj is null) return; Add(obj.RVA); Add(obj.ImplAttributes); Add(obj.Attributes); Add(obj.Name); Add(obj.Signature); Add(obj.ParamDefs); Add(obj.GenericParameters); Add(obj.DeclSecurities); Add(obj.ImplMap); Add(obj.MethodBody); Add(obj.CustomAttributes); Add(obj.Overrides); Add(obj.DeclaringType); Add(obj.Parameters); Add(obj.SemanticsAttributes); } void Load(ParamDef obj) { if (obj is null) return; Add(obj.DeclaringMethod); Add(obj.Attributes); Add(obj.Sequence); Add(obj.Name); Add(obj.MarshalType); Add(obj.Constant); Add(obj.CustomAttributes); } void Load(InterfaceImpl obj) { if (obj is null) return; Add(obj.Interface); Add(obj.CustomAttributes); } void Load(MemberRef obj) { if (obj is null) return; Add(obj.Class); Add(obj.Name); Add(obj.Signature); Add(obj.CustomAttributes); } void Load(Constant obj) { if (obj is null) return; Add(obj.Type); var o = obj.Value; } void Load(DeclSecurity obj) { if (obj is null) return; Add(obj.Action); Add(obj.SecurityAttributes); Add(obj.CustomAttributes); obj.GetBlob(); } void Load(ClassLayout obj) { if (obj is null) return; Add(obj.PackingSize); Add(obj.ClassSize); } void Load(StandAloneSig obj) { if (obj is null) return; Add(obj.Signature); Add(obj.CustomAttributes); } void Load(EventDef obj) { if (obj is null) return; Add(obj.Attributes); Add(obj.Name); Add(obj.EventType); Add(obj.CustomAttributes); Add(obj.AddMethod); Add(obj.InvokeMethod); Add(obj.RemoveMethod); Add(obj.OtherMethods); Add(obj.DeclaringType); } void Load(PropertyDef obj) { if (obj is null) return; Add(obj.Attributes); Add(obj.Name); Add(obj.Type); Add(obj.Constant); Add(obj.CustomAttributes); Add(obj.GetMethods); Add(obj.SetMethods); Add(obj.OtherMethods); Add(obj.DeclaringType); } void Load(ModuleRef obj) { if (obj is null) return; Add(obj.Name); Add(obj.CustomAttributes); } void Load(TypeSpec obj) { if (obj is null) return; Add(obj.TypeSig); Add(obj.ExtraData); Add(obj.CustomAttributes); } void Load(ImplMap obj) { if (obj is null) return; Add(obj.Attributes); Add(obj.Name); Add(obj.Module); } void Load(AssemblyDef obj) { if (obj is null) return; if (obj.ManifestModule != module) return; Add(obj.HashAlgorithm); Add(obj.Version); Add(obj.Attributes); Add(obj.PublicKey); Add(obj.Name); Add(obj.Culture); Add(obj.DeclSecurities); Add(obj.Modules); Add(obj.CustomAttributes); } void Load(AssemblyRef obj) { if (obj is null) return; Add(obj.Version); Add(obj.Attributes); Add(obj.PublicKeyOrToken); Add(obj.Name); Add(obj.Culture); Add(obj.Hash); Add(obj.CustomAttributes); } void Load(FileDef obj) { if (obj is null) return; Add(obj.Flags); Add(obj.Name); Add(obj.HashValue); Add(obj.CustomAttributes); } void Load(ExportedType obj) { if (obj is null) return; Add(obj.CustomAttributes); Add(obj.Attributes); Add(obj.TypeDefId); Add(obj.TypeName); Add(obj.TypeNamespace); Add(obj.Implementation); } void Load(Resource obj) { if (obj is null) return; Add(obj.Offset); Add(obj.Name); Add(obj.Attributes); Add(obj.CustomAttributes); switch (obj.ResourceType) { case ResourceType.Embedded: break; case ResourceType.AssemblyLinked: var ar = (AssemblyLinkedResource)obj; Add(ar.Assembly); break; case ResourceType.Linked: var lr = (LinkedResource)obj; Add(lr.File); Add(lr.Hash); break; default: Debug.Fail("Unknown resource"); break; } } void Load(ManifestResource obj) { if (obj is null) return; Add(obj.Offset); Add(obj.Flags); Add(obj.Name); Add(obj.Implementation); Add(obj.CustomAttributes); } void Load(GenericParam obj) { if (obj is null) return; Add(obj.Owner); Add(obj.Number); Add(obj.Flags); Add(obj.Name); Add(obj.Kind); Add(obj.GenericParamConstraints); Add(obj.CustomAttributes); } void Load(MethodSpec obj) { if (obj is null) return; Add(obj.Method); Add(obj.Instantiation); Add(obj.CustomAttributes); } void Load(GenericParamConstraint obj) { if (obj is null) return; Add(obj.Owner); Add(obj.Constraint); Add(obj.CustomAttributes); } void Load(CANamedArgument obj) { if (obj is null) return; Add(obj.Type); Add(obj.Name); Load(obj.Argument); } void Load(Parameter obj) { if (obj is null) return; Add(obj.Type); } void Load(SecurityAttribute obj) { if (obj is null) return; Add(obj.AttributeType); Add(obj.NamedArguments); } void Load(CustomAttribute obj) { if (obj is null) return; Add(obj.Constructor); Add(obj.RawData); Add(obj.ConstructorArguments); Add(obj.NamedArguments); } void Load(MethodOverride obj) { Add(obj.MethodBody); Add(obj.MethodDeclaration); } void AddCAValue(object obj) { if (obj is CAArgument) { Load((CAArgument)obj); return; } if (obj is IList list) { Add(list); return; } if (obj is IMDTokenProvider md) { Add(md); return; } } void Load(CAArgument obj) { Add(obj.Type); AddCAValue(obj.Value); } void Load(PdbMethod obj) { } void Load(ResourceDirectory obj) { if (obj is null) return; Add(obj.Directories); Add(obj.Data); } void Load(ResourceData obj) { } void AddToStack(T t) where T : class { if (t is null) return; if (seen.ContainsKey(t)) return; seen[t] = true; stack.Push(t); } void Add(CustomAttribute obj) => AddToStack(obj); void Add(SecurityAttribute obj) => AddToStack(obj); void Add(CANamedArgument obj) => AddToStack(obj); void Add(Parameter obj) => AddToStack(obj); void Add(IMDTokenProvider o) => AddToStack(o); void Add(PdbMethod pdbMethod) { } void Add(TypeSig ts) => AddToStack(ts); void Add(ResourceDirectory rd) => AddToStack(rd); void Add(ResourceData rd) => AddToStack(rd); void Add(IList list) where T : IMDTokenProvider { if (list is null) return; foreach (var item in list) Add(item); } void Add(IList list) { if (list is null) return; foreach (var item in list) Add(item); } void Add(IList list) { if (list is null) return; foreach (var item in list) Add(item); } void Add(IList list) { if (list is null) return; foreach (var item in list) Add(item); } void Add(IList list) { if (list is null) return; foreach (var item in list) Load(item); } void Add(IList list) { if (list is null) return; foreach (var item in list) Load(item); } void Add(IList list) { if (list is null) return; foreach (var item in list) Add(item); } void Add(ParameterList list) { if (list is null) return; foreach (var item in list) Add(item); } void Add(IList list) { if (list is null) return; foreach (var item in list) Add(item); } void Add(IList list) { if (list is null) return; foreach (var item in list) Add(item); } void Add(IList list) { if (list is null) return; foreach (var item in list) Add(item); } void Add(IList list) { if (list is null) return; foreach (var item in list) Add(item); } void Add(IList list) { if (list is null) return; foreach (var item in list) Add(item); } void Add(VTableFixups vtf) { if (vtf is null) return; foreach (var fixup in vtf) { foreach (var method in fixup) Add(method); } } void Add(Win32Resources vtf) { if (vtf is null) return; Add(vtf.Root); } void Add(CallingConventionSig sig) { if (sig is MethodBaseSig msig) { Add(msig); return; } if (sig is FieldSig fsig) { Add(fsig); return; } if (sig is LocalSig lsig) { Add(lsig); return; } if (sig is GenericInstMethodSig gsig) { Add(gsig); return; } Debug.Assert(sig is null); } void Add(MethodBaseSig msig) { if (msig is null) return; Add(msig.ExtraData); Add(msig.RetType); Add(msig.Params); Add(msig.ParamsAfterSentinel); } void Add(FieldSig fsig) { if (fsig is null) return; Add(fsig.ExtraData); Add(fsig.Type); } void Add(LocalSig lsig) { if (lsig is null) return; Add(lsig.ExtraData); Add(lsig.Locals); } void Add(GenericInstMethodSig gsig) { if (gsig is null) return; Add(gsig.ExtraData); Add(gsig.GenericArguments); } void Add(MarshalType mt) { if (mt is null) return; Add(mt.NativeType); } void Add(MethodBody mb) { if (mb is CilBody cilBody) { Add(cilBody); return; } if (mb is NativeMethodBody nb) { Add(nb); return; } Debug.Assert(mb is null, "Unknown method body"); } void Add(NativeMethodBody body) { if (body is null) return; Add(body.RVA); } void Add(CilBody body) { if (body is null) return; Add(body.Instructions); Add(body.ExceptionHandlers); Add(body.Variables); Add(body.PdbMethod); } void Add(Instruction instr) { if (instr is null) return; if (instr.Operand is IMDTokenProvider mdt) { Add(mdt); return; } if (instr.Operand is Parameter p) { Add(p); return; } if (instr.Operand is Local l) { Add(l); return; } if (instr.Operand is CallingConventionSig csig) { Add(csig); return; } } void Add(ExceptionHandler eh) { if (eh is null) return; Add(eh.CatchType); } void Add(Local local) { if (local is null) return; Add(local.Type); } void Add(PdbState state) { if (state is null) return; Add(state.UserEntryPoint); } } }