Skip to content

Commit 61f82d0

Browse files
Fix #3563: Add support for ildasm /caverbal format
1 parent a79a587 commit 61f82d0

File tree

8 files changed

+145
-51
lines changed

8 files changed

+145
-51
lines changed

ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

Lines changed: 119 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ public IDebugInfoProvider DebugInfo {
7474

7575
public bool ExpandMemberDefinitions { get; set; }
7676

77+
/// <summary>
78+
/// Gets or sets whether custom attribute blobs should be decoded or dumped as raw bytes. Default is <see langword="false"/>.
79+
/// Setting this value to <see langword="true"/> (roughly) corresponds to the <c>/CAVERBAL</c> switch of <c>ildasm</c>.
80+
/// </summary>
81+
public bool DecodeCustomAttributeBlobs { get; set; }
82+
7783
public IAssemblyResolver AssemblyResolver { get; set; }
7884

7985
public IEntityProcessor EntityProcessor { get; set; }
@@ -476,7 +482,7 @@ void WriteSecurityDeclarations(MetadataFile module, DeclarativeSecurityAttribute
476482
}
477483
}
478484

479-
class SecurityDeclarationDecoder : ICustomAttributeTypeProvider<(PrimitiveTypeCode, string)>
485+
class SecurityDeclarationDecoder : ICustomAttributeTypeProvider<(PrimitiveTypeCode Code, string Name)>
480486
{
481487
readonly ITextOutput output;
482488
readonly IAssemblyResolver resolver;
@@ -506,12 +512,54 @@ public SecurityDeclarationDecoder(ITextOutput output, IAssemblyResolver resolver
506512

507513
public (PrimitiveTypeCode, string) GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind)
508514
{
509-
throw new NotImplementedException();
515+
string fullTypeName = handle.GetFullTypeName(reader).FullName;
516+
if (handle.IsEnum(reader, out var typeCode))
517+
return (typeCode, "enum " + fullTypeName);
518+
return (0, fullTypeName);
510519
}
511520

512521
public (PrimitiveTypeCode, string) GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind)
513522
{
514-
throw new NotImplementedException();
523+
string fullTypeName = handle.GetFullTypeName(reader).FullName;
524+
var containingModule = GetDeclaringModule(handle);
525+
526+
string assemblyQualifiedTypeName = containingModule != null
527+
? fullTypeName + ", " + containingModule
528+
: fullTypeName;
529+
530+
PrimitiveTypeCode typeCode = 0;
531+
var (targetModule, resolvedType) = ResolveType(assemblyQualifiedTypeName, module);
532+
if (targetModule != null)
533+
{
534+
if (!resolvedType.IsEnum(targetModule.Metadata, out typeCode))
535+
{
536+
typeCode = 0;
537+
}
538+
else
539+
{
540+
assemblyQualifiedTypeName = "enum " + assemblyQualifiedTypeName;
541+
}
542+
}
543+
544+
return (typeCode, assemblyQualifiedTypeName);
545+
546+
string GetDeclaringModule(TypeReferenceHandle handle)
547+
{
548+
var tr = reader.GetTypeReference(handle);
549+
switch (tr.ResolutionScope.Kind)
550+
{
551+
case HandleKind.TypeReference:
552+
return GetDeclaringModule((TypeReferenceHandle)tr.ResolutionScope);
553+
case HandleKind.AssemblyReference:
554+
var asmRef = reader.GetAssemblyReference((AssemblyReferenceHandle)tr.ResolutionScope);
555+
return asmRef.TryGetFullAssemblyName(reader, out var assemblyName) ? assemblyName : null;
556+
case HandleKind.ModuleReference:
557+
var modRef = reader.GetModuleReference((ModuleReferenceHandle)tr.ResolutionScope);
558+
return reader.GetString(modRef.Name);
559+
default:
560+
return null;
561+
}
562+
}
515563
}
516564

517565
public (PrimitiveTypeCode, string) GetTypeFromSerializedName(string name)
@@ -608,17 +656,6 @@ TypeDefinitionHandle FindType(MetadataFile currentModule, string[] name)
608656
}
609657
}
610658

611-
PrimitiveTypeCode ResolveEnumUnderlyingType(string typeName, PEFile module)
612-
{
613-
if (typeName.StartsWith("enum ", StringComparison.Ordinal))
614-
typeName = typeName.Substring(5);
615-
var (containingModule, typeDefHandle) = ResolveType(typeName, module);
616-
617-
if (typeDefHandle.IsNil || !typeDefHandle.IsEnum(containingModule.Metadata, out var typeCode))
618-
throw new EnumUnderlyingTypeResolveException();
619-
return typeCode;
620-
}
621-
622659
MetadataFile mscorlib;
623660

624661
bool TryResolveMscorlib(out MetadataFile mscorlib)
@@ -704,7 +741,7 @@ void TryDecodeSecurityDeclaration(TextOutputWithRollback output, BlobReader blob
704741
}
705742

706743
output.Write(argument.Type.Name ?? PrimitiveTypeCodeToString(argument.Type.Code));
707-
output.Write(" " + argument.Name + " = ");
744+
output.Write(" " + DisassemblerHelpers.Escape(argument.Name) + " = ");
708745

709746
WriteValue(output, argument.Type, argument.Value);
710747
output.WriteLine();
@@ -1824,12 +1861,62 @@ void WriteAttributes(MetadataFile module, CustomAttributeHandleCollection attrib
18241861
if (!attr.Value.IsNil)
18251862
{
18261863
output.Write(" = ");
1827-
WriteBlob(attr.Value, metadata);
1864+
if (DecodeCustomAttributeBlobs)
1865+
WriteDecodedCustomAttributeBlob(attr, module);
1866+
else
1867+
WriteBlob(attr.Value, metadata);
18281868
}
18291869
output.WriteLine();
18301870
}
18311871
}
18321872

1873+
void WriteDecodedCustomAttributeBlob(CustomAttribute attr, MetadataFile module)
1874+
{
1875+
CustomAttributeValue<(PrimitiveTypeCode Code, string Name)> value;
1876+
try
1877+
{
1878+
var provider = new SecurityDeclarationDecoder(output, AssemblyResolver, module);
1879+
value = attr.DecodeValue(provider);
1880+
}
1881+
catch (BadImageFormatException)
1882+
{
1883+
output.Write("/* Could not decode attribute value */ ");
1884+
WriteBlob(attr.Value, module.Metadata);
1885+
return;
1886+
}
1887+
1888+
output.Write("{");
1889+
output.Indent();
1890+
1891+
foreach (var arg in value.FixedArguments)
1892+
{
1893+
output.WriteLine();
1894+
WriteValue(output, arg.Type, arg.Value);
1895+
}
1896+
1897+
foreach (var arg in value.NamedArguments)
1898+
{
1899+
output.WriteLine();
1900+
switch (arg.Kind)
1901+
{
1902+
case CustomAttributeNamedArgumentKind.Field:
1903+
output.Write("field ");
1904+
break;
1905+
case CustomAttributeNamedArgumentKind.Property:
1906+
output.Write("property ");
1907+
break;
1908+
}
1909+
1910+
output.Write(arg.Type.Name ?? PrimitiveTypeCodeToString(arg.Type.Code));
1911+
output.Write(" " + DisassemblerHelpers.Escape(arg.Name) + " = ");
1912+
WriteValue(output, arg.Type, arg.Value);
1913+
}
1914+
1915+
output.WriteLine();
1916+
output.Unindent();
1917+
output.Write("}");
1918+
}
1919+
18331920
void WriteBlob(BlobHandle blob, MetadataReader metadata)
18341921
{
18351922
var reader = metadata.GetBlobReader(blob);
@@ -1839,23 +1926,26 @@ void WriteBlob(BlobHandle blob, MetadataReader metadata)
18391926
void WriteBlob(BlobReader reader)
18401927
{
18411928
output.Write("(");
1842-
output.Indent();
1843-
1844-
for (int i = 0; i < reader.Length; i++)
1929+
if (reader.Length > 0)
18451930
{
1846-
if (i % 16 == 0 && i < reader.Length - 1)
1847-
{
1848-
output.WriteLine();
1849-
}
1850-
else
1931+
output.Indent();
1932+
1933+
for (int i = 0; i < reader.Length; i++)
18511934
{
1852-
output.Write(' ');
1935+
if (i % 16 == 0 && i < reader.Length - 1)
1936+
{
1937+
output.WriteLine();
1938+
}
1939+
else
1940+
{
1941+
output.Write(' ');
1942+
}
1943+
output.Write(reader.ReadByte().ToString("x2"));
18531944
}
1854-
output.Write(reader.ReadByte().ToString("x2"));
1855-
}
18561945

1857-
output.WriteLine();
1858-
output.Unindent();
1946+
output.WriteLine();
1947+
output.Unindent();
1948+
}
18591949
output.Write(")");
18601950
}
18611951

ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -210,25 +210,6 @@ public static string ToILNameString(this FullTypeName typeName, bool omitGeneric
210210
return Disassembler.DisassemblerHelpers.Escape(name);
211211
}
212212

213-
[Obsolete("Use MetadataModule.GetDeclaringModule() instead")]
214-
public static IModuleReference GetDeclaringModule(this TypeReferenceHandle handle, MetadataReader reader)
215-
{
216-
var tr = reader.GetTypeReference(handle);
217-
switch (tr.ResolutionScope.Kind)
218-
{
219-
case HandleKind.TypeReference:
220-
return ((TypeReferenceHandle)tr.ResolutionScope).GetDeclaringModule(reader);
221-
case HandleKind.AssemblyReference:
222-
var asmRef = reader.GetAssemblyReference((AssemblyReferenceHandle)tr.ResolutionScope);
223-
return new DefaultAssemblyReference(reader.GetString(asmRef.Name));
224-
case HandleKind.ModuleReference:
225-
var modRef = reader.GetModuleReference((ModuleReferenceHandle)tr.ResolutionScope);
226-
return new DefaultAssemblyReference(reader.GetString(modRef.Name));
227-
default:
228-
return DefaultAssemblyReference.CurrentAssembly;
229-
}
230-
}
231-
232213
internal static readonly TypeProvider minimalCorlibTypeProvider =
233214
new TypeProvider(new SimpleCompilation(MinimalCorlib.Instance));
234215

ILSpy/Languages/CSharpILMixedLanguage.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ protected override ReflectionDisassembler CreateDisassembler(ITextOutput output,
6060
ShowMetadataTokens = displaySettings.ShowMetadataTokens,
6161
ShowMetadataTokensInBase10 = displaySettings.ShowMetadataTokensInBase10,
6262
ShowRawRVAOffsetAndBytes = displaySettings.ShowRawOffsetsAndBytesBeforeInstruction,
63-
ExpandMemberDefinitions = options.DecompilerSettings.ExpandMemberDefinitions
63+
ExpandMemberDefinitions = options.DecompilerSettings.ExpandMemberDefinitions,
64+
DecodeCustomAttributeBlobs = displaySettings.DecodeCustomAttributeBlobs
6465
};
6566
}
6667

ILSpy/Languages/ILLanguage.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ protected virtual ReflectionDisassembler CreateDisassembler(ITextOutput output,
6767
ShowMetadataTokens = displaySettings.ShowMetadataTokens,
6868
ShowMetadataTokensInBase10 = displaySettings.ShowMetadataTokensInBase10,
6969
ShowRawRVAOffsetAndBytes = displaySettings.ShowRawOffsetsAndBytesBeforeInstruction,
70-
ExpandMemberDefinitions = options.DecompilerSettings.ExpandMemberDefinitions
70+
ExpandMemberDefinitions = options.DecompilerSettings.ExpandMemberDefinitions,
71+
DecodeCustomAttributeBlobs = displaySettings.DecodeCustomAttributeBlobs
7172
};
7273
}
7374

ILSpy/Options/DisplaySettings.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,12 @@ public bool EnableSmoothScrolling {
156156
set => SetProperty(ref enableSmoothScrolling, value);
157157
}
158158

159+
private bool decodeCustomAttributeBlobs;
160+
public bool DecodeCustomAttributeBlobs {
161+
get => decodeCustomAttributeBlobs;
162+
set => SetProperty(ref decodeCustomAttributeBlobs, value);
163+
}
164+
159165
public XName SectionName => "DisplaySettings";
160166

161167
public void LoadFromXml(XElement section)
@@ -181,6 +187,7 @@ public void LoadFromXml(XElement section)
181187
ShowRawOffsetsAndBytesBeforeInstruction = (bool?)section.Attribute("ShowRawOffsetsAndBytesBeforeInstruction") ?? false;
182188
StyleWindowTitleBar = (bool?)section.Attribute("StyleWindowTitleBar") ?? false;
183189
EnableSmoothScrolling = (bool?)section.Attribute("EnableSmoothScrolling") ?? true;
190+
DecodeCustomAttributeBlobs = (bool?)section.Attribute("DecodeCustomAttributeBlobs") ?? false;
184191
}
185192

186193
public XElement SaveToXml()
@@ -208,6 +215,7 @@ public XElement SaveToXml()
208215
section.SetAttributeValue("ShowRawOffsetsAndBytesBeforeInstruction", ShowRawOffsetsAndBytesBeforeInstruction);
209216
section.SetAttributeValue("StyleWindowTitleBar", StyleWindowTitleBar);
210217
section.SetAttributeValue("EnableSmoothScrolling", EnableSmoothScrolling);
218+
section.SetAttributeValue("DecodeCustomAttributeBlobs", DecodeCustomAttributeBlobs);
211219

212220
return section;
213221
}

ILSpy/Options/DisplaySettingsPanel.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
<CheckBox IsChecked="{Binding Settings.ExpandUsingDeclarations}" Content="{x:Static properties:Resources.ExpandUsingDeclarationsAfterDecompilation}"></CheckBox>
6565
<CheckBox IsChecked="{Binding Settings.ShowDebugInfo}" Content="{x:Static properties:Resources.ShowInfoFromDebugSymbolsAvailable}"></CheckBox>
6666
<CheckBox IsChecked="{Binding Settings.ShowRawOffsetsAndBytesBeforeInstruction}" Content="{x:Static properties:Resources.ShowRawOffsetsAndBytesBeforeInstruction}"></CheckBox>
67+
<CheckBox IsChecked="{Binding Settings.DecodeCustomAttributeBlobs}" Content="{x:Static properties:Resources.DecodeCustomAttributeBlobs}"></CheckBox>
6768
</StackPanel>
6869
</GroupBox>
6970
<GroupBox Header="{x:Static properties:Resources.TreeViewOptions}">

ILSpy/Properties/Resources.Designer.cs

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ILSpy/Properties/Resources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,9 @@ Are you sure you want to continue?</value>
234234
<data name="DebugThisStep" xml:space="preserve">
235235
<value>Debug this step</value>
236236
</data>
237+
<data name="DecodeCustomAttributeBlobs" xml:space="preserve">
238+
<value>Decode custom attribute blobs</value>
239+
</data>
237240
<data name="DecompilationCompleteInF1Seconds" xml:space="preserve">
238241
<value>Decompilation complete in {0:F1} seconds.</value>
239242
</data>

0 commit comments

Comments
 (0)