diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs index 16bb69a13..47230c2b6 100644 --- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs @@ -74,6 +74,12 @@ namespace ICSharpCode.Decompiler.Disassembler public bool ExpandMemberDefinitions { get; set; } + /// + /// Gets or sets whether custom attribute blobs should be decoded or dumped as raw bytes. Default is . + /// Setting this value to (roughly) corresponds to the /CAVERBAL switch of ildasm. + /// + public bool DecodeCustomAttributeBlobs { get; set; } + public IAssemblyResolver AssemblyResolver { get; set; } public IEntityProcessor EntityProcessor { get; set; } @@ -476,7 +482,7 @@ namespace ICSharpCode.Decompiler.Disassembler } } - class SecurityDeclarationDecoder : ICustomAttributeTypeProvider<(PrimitiveTypeCode, string)> + class SecurityDeclarationDecoder : ICustomAttributeTypeProvider<(PrimitiveTypeCode Code, string Name)> { readonly ITextOutput output; readonly IAssemblyResolver resolver; @@ -506,12 +512,54 @@ namespace ICSharpCode.Decompiler.Disassembler public (PrimitiveTypeCode, string) GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) { - throw new NotImplementedException(); + string fullTypeName = handle.GetFullTypeName(reader).FullName; + if (handle.IsEnum(reader, out var typeCode)) + return (typeCode, "enum " + fullTypeName); + return (0, fullTypeName); } public (PrimitiveTypeCode, string) GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) { - throw new NotImplementedException(); + string fullTypeName = handle.GetFullTypeName(reader).FullName; + var containingModule = GetDeclaringModule(handle); + + string assemblyQualifiedTypeName = containingModule != null + ? fullTypeName + ", " + containingModule + : fullTypeName; + + PrimitiveTypeCode typeCode = 0; + var (targetModule, resolvedType) = ResolveType(assemblyQualifiedTypeName, module); + if (targetModule != null) + { + if (!resolvedType.IsEnum(targetModule.Metadata, out typeCode)) + { + typeCode = 0; + } + else + { + assemblyQualifiedTypeName = "enum " + assemblyQualifiedTypeName; + } + } + + return (typeCode, assemblyQualifiedTypeName); + + string GetDeclaringModule(TypeReferenceHandle handle) + { + var tr = reader.GetTypeReference(handle); + switch (tr.ResolutionScope.Kind) + { + case HandleKind.TypeReference: + return GetDeclaringModule((TypeReferenceHandle)tr.ResolutionScope); + case HandleKind.AssemblyReference: + var asmRef = reader.GetAssemblyReference((AssemblyReferenceHandle)tr.ResolutionScope); + return asmRef.TryGetFullAssemblyName(reader, out var assemblyName) ? assemblyName : null; + case HandleKind.ModuleReference: + var modRef = reader.GetModuleReference((ModuleReferenceHandle)tr.ResolutionScope); + return reader.GetString(modRef.Name); + default: + return null; + } + } } public (PrimitiveTypeCode, string) GetTypeFromSerializedName(string name) @@ -608,17 +656,6 @@ namespace ICSharpCode.Decompiler.Disassembler } } - PrimitiveTypeCode ResolveEnumUnderlyingType(string typeName, PEFile module) - { - if (typeName.StartsWith("enum ", StringComparison.Ordinal)) - typeName = typeName.Substring(5); - var (containingModule, typeDefHandle) = ResolveType(typeName, module); - - if (typeDefHandle.IsNil || !typeDefHandle.IsEnum(containingModule.Metadata, out var typeCode)) - throw new EnumUnderlyingTypeResolveException(); - return typeCode; - } - MetadataFile mscorlib; bool TryResolveMscorlib(out MetadataFile mscorlib) @@ -704,7 +741,7 @@ namespace ICSharpCode.Decompiler.Disassembler } output.Write(argument.Type.Name ?? PrimitiveTypeCodeToString(argument.Type.Code)); - output.Write(" " + argument.Name + " = "); + output.Write(" " + DisassemblerHelpers.Escape(argument.Name) + " = "); WriteValue(output, argument.Type, argument.Value); output.WriteLine(); @@ -1824,12 +1861,62 @@ namespace ICSharpCode.Decompiler.Disassembler if (!attr.Value.IsNil) { output.Write(" = "); - WriteBlob(attr.Value, metadata); + if (DecodeCustomAttributeBlobs) + WriteDecodedCustomAttributeBlob(attr, module); + else + WriteBlob(attr.Value, metadata); } output.WriteLine(); } } + void WriteDecodedCustomAttributeBlob(CustomAttribute attr, MetadataFile module) + { + CustomAttributeValue<(PrimitiveTypeCode Code, string Name)> value; + try + { + var provider = new SecurityDeclarationDecoder(output, AssemblyResolver, module); + value = attr.DecodeValue(provider); + } + catch (BadImageFormatException) + { + output.Write("/* Could not decode attribute value */ "); + WriteBlob(attr.Value, module.Metadata); + return; + } + + output.Write("{"); + output.Indent(); + + foreach (var arg in value.FixedArguments) + { + output.WriteLine(); + WriteValue(output, arg.Type, arg.Value); + } + + foreach (var arg in value.NamedArguments) + { + output.WriteLine(); + switch (arg.Kind) + { + case CustomAttributeNamedArgumentKind.Field: + output.Write("field "); + break; + case CustomAttributeNamedArgumentKind.Property: + output.Write("property "); + break; + } + + output.Write(arg.Type.Name ?? PrimitiveTypeCodeToString(arg.Type.Code)); + output.Write(" " + DisassemblerHelpers.Escape(arg.Name) + " = "); + WriteValue(output, arg.Type, arg.Value); + } + + output.WriteLine(); + output.Unindent(); + output.Write("}"); + } + void WriteBlob(BlobHandle blob, MetadataReader metadata) { var reader = metadata.GetBlobReader(blob); @@ -1839,23 +1926,26 @@ namespace ICSharpCode.Decompiler.Disassembler void WriteBlob(BlobReader reader) { output.Write("("); - output.Indent(); - - for (int i = 0; i < reader.Length; i++) + if (reader.Length > 0) { - if (i % 16 == 0 && i < reader.Length - 1) - { - output.WriteLine(); - } - else + output.Indent(); + + for (int i = 0; i < reader.Length; i++) { - output.Write(' '); + if (i % 16 == 0 && i < reader.Length - 1) + { + output.WriteLine(); + } + else + { + output.Write(' '); + } + output.Write(reader.ReadByte().ToString("x2")); } - output.Write(reader.ReadByte().ToString("x2")); - } - output.WriteLine(); - output.Unindent(); + output.WriteLine(); + output.Unindent(); + } output.Write(")"); } diff --git a/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs b/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs index b16fe4e4f..52452be12 100644 --- a/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs +++ b/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs @@ -210,25 +210,6 @@ namespace ICSharpCode.Decompiler.Metadata return Disassembler.DisassemblerHelpers.Escape(name); } - [Obsolete("Use MetadataModule.GetDeclaringModule() instead")] - public static IModuleReference GetDeclaringModule(this TypeReferenceHandle handle, MetadataReader reader) - { - var tr = reader.GetTypeReference(handle); - switch (tr.ResolutionScope.Kind) - { - case HandleKind.TypeReference: - return ((TypeReferenceHandle)tr.ResolutionScope).GetDeclaringModule(reader); - case HandleKind.AssemblyReference: - var asmRef = reader.GetAssemblyReference((AssemblyReferenceHandle)tr.ResolutionScope); - return new DefaultAssemblyReference(reader.GetString(asmRef.Name)); - case HandleKind.ModuleReference: - var modRef = reader.GetModuleReference((ModuleReferenceHandle)tr.ResolutionScope); - return new DefaultAssemblyReference(reader.GetString(modRef.Name)); - default: - return DefaultAssemblyReference.CurrentAssembly; - } - } - internal static readonly TypeProvider minimalCorlibTypeProvider = new TypeProvider(new SimpleCompilation(MinimalCorlib.Instance)); diff --git a/ILSpy/Languages/CSharpILMixedLanguage.cs b/ILSpy/Languages/CSharpILMixedLanguage.cs index ca349bbed..da06515fc 100644 --- a/ILSpy/Languages/CSharpILMixedLanguage.cs +++ b/ILSpy/Languages/CSharpILMixedLanguage.cs @@ -60,7 +60,8 @@ namespace ICSharpCode.ILSpy ShowMetadataTokens = displaySettings.ShowMetadataTokens, ShowMetadataTokensInBase10 = displaySettings.ShowMetadataTokensInBase10, ShowRawRVAOffsetAndBytes = displaySettings.ShowRawOffsetsAndBytesBeforeInstruction, - ExpandMemberDefinitions = options.DecompilerSettings.ExpandMemberDefinitions + ExpandMemberDefinitions = options.DecompilerSettings.ExpandMemberDefinitions, + DecodeCustomAttributeBlobs = displaySettings.DecodeCustomAttributeBlobs }; } diff --git a/ILSpy/Languages/ILLanguage.cs b/ILSpy/Languages/ILLanguage.cs index 384728e36..748328b7e 100644 --- a/ILSpy/Languages/ILLanguage.cs +++ b/ILSpy/Languages/ILLanguage.cs @@ -67,7 +67,8 @@ namespace ICSharpCode.ILSpy ShowMetadataTokens = displaySettings.ShowMetadataTokens, ShowMetadataTokensInBase10 = displaySettings.ShowMetadataTokensInBase10, ShowRawRVAOffsetAndBytes = displaySettings.ShowRawOffsetsAndBytesBeforeInstruction, - ExpandMemberDefinitions = options.DecompilerSettings.ExpandMemberDefinitions + ExpandMemberDefinitions = options.DecompilerSettings.ExpandMemberDefinitions, + DecodeCustomAttributeBlobs = displaySettings.DecodeCustomAttributeBlobs }; } diff --git a/ILSpy/Options/DisplaySettings.cs b/ILSpy/Options/DisplaySettings.cs index b77bf501e..95c9d02d1 100644 --- a/ILSpy/Options/DisplaySettings.cs +++ b/ILSpy/Options/DisplaySettings.cs @@ -156,6 +156,12 @@ namespace ICSharpCode.ILSpy.Options set => SetProperty(ref enableSmoothScrolling, value); } + private bool decodeCustomAttributeBlobs; + public bool DecodeCustomAttributeBlobs { + get => decodeCustomAttributeBlobs; + set => SetProperty(ref decodeCustomAttributeBlobs, value); + } + public XName SectionName => "DisplaySettings"; public void LoadFromXml(XElement section) @@ -181,6 +187,7 @@ namespace ICSharpCode.ILSpy.Options ShowRawOffsetsAndBytesBeforeInstruction = (bool?)section.Attribute("ShowRawOffsetsAndBytesBeforeInstruction") ?? false; StyleWindowTitleBar = (bool?)section.Attribute("StyleWindowTitleBar") ?? false; EnableSmoothScrolling = (bool?)section.Attribute("EnableSmoothScrolling") ?? true; + DecodeCustomAttributeBlobs = (bool?)section.Attribute("DecodeCustomAttributeBlobs") ?? false; } public XElement SaveToXml() @@ -208,6 +215,7 @@ namespace ICSharpCode.ILSpy.Options section.SetAttributeValue("ShowRawOffsetsAndBytesBeforeInstruction", ShowRawOffsetsAndBytesBeforeInstruction); section.SetAttributeValue("StyleWindowTitleBar", StyleWindowTitleBar); section.SetAttributeValue("EnableSmoothScrolling", EnableSmoothScrolling); + section.SetAttributeValue("DecodeCustomAttributeBlobs", DecodeCustomAttributeBlobs); return section; } diff --git a/ILSpy/Options/DisplaySettingsPanel.xaml b/ILSpy/Options/DisplaySettingsPanel.xaml index 0624bd444..58c7ae316 100644 --- a/ILSpy/Options/DisplaySettingsPanel.xaml +++ b/ILSpy/Options/DisplaySettingsPanel.xaml @@ -64,6 +64,7 @@ + diff --git a/ILSpy/Properties/Resources.Designer.cs b/ILSpy/Properties/Resources.Designer.cs index ad46f836b..3ddca0ae2 100644 --- a/ILSpy/Properties/Resources.Designer.cs +++ b/ILSpy/Properties/Resources.Designer.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 @@ -648,6 +648,15 @@ namespace ICSharpCode.ILSpy.Properties { } } + /// + /// Looks up a localized string similar to Decode custom attribute blobs. + /// + public static string DecodeCustomAttributeBlobs { + get { + return ResourceManager.GetString("DecodeCustomAttributeBlobs", resourceCulture); + } + } + /// /// Looks up a localized string similar to Decompilation complete in {0:F1} seconds.. /// diff --git a/ILSpy/Properties/Resources.resx b/ILSpy/Properties/Resources.resx index bb0d12dde..ee03a4325 100644 --- a/ILSpy/Properties/Resources.resx +++ b/ILSpy/Properties/Resources.resx @@ -234,6 +234,9 @@ Are you sure you want to continue? Debug this step + + Decode custom attribute blobs + Decompilation complete in {0:F1} seconds.