Browse Source

Add filtering/sorting capabilities to ReflectionDisassembler (#2835)

Co-authored-by: Siegfried Pammer <siegfriedpammer@gmail.com>
pull/2846/head
tom-englert 3 years ago committed by GitHub
parent
commit
3248657d2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      ICSharpCode.Decompiler.Tests/DisassemblerPrettyTestRunner.cs
  2. 10
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  3. 2
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  4. 2
      ICSharpCode.Decompiler.Tests/TestCases/Disassembler/Pretty/.gitignore
  5. 395
      ICSharpCode.Decompiler.Tests/TestCases/Disassembler/Pretty/SortMembers.expected.il
  6. 381
      ICSharpCode.Decompiler.Tests/TestCases/Disassembler/Pretty/SortMembers.il
  7. 44
      ICSharpCode.Decompiler/Disassembler/IEntityProcessor.cs
  8. 62
      ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  9. 122
      ICSharpCode.Decompiler/Disassembler/SortByNameProcessor.cs
  10. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  11. 2
      ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs

17
ICSharpCode.Decompiler.Tests/DisassemblerPrettyTestRunner.cs

@ -58,15 +58,22 @@ namespace ICSharpCode.Decompiler.Tests @@ -58,15 +58,22 @@ namespace ICSharpCode.Decompiler.Tests
await Run();
}
async Task Run([CallerMemberName] string testName = null)
[Test]
public async Task SortMembers()
{
await Run(ilExpectedFile: Path.Combine(TestCasePath, "SortMembers.expected.il"), asmOptions: AssemblerOptions.SortedOutput);
}
async Task Run([CallerMemberName] string testName = null, string ilExpectedFile = null, AssemblerOptions asmOptions = AssemblerOptions.None)
{
var ilExpectedFile = Path.Combine(TestCasePath, testName + ".il");
var ilInputFile = Path.Combine(TestCasePath, testName + ".il");
ilExpectedFile ??= ilInputFile;
var ilResultFile = Path.Combine(TestCasePath, testName + ".result.il");
var executable = await Tester.AssembleIL(ilExpectedFile, AssemblerOptions.Library).ConfigureAwait(false);
var disassembled = await Tester.Disassemble(executable, ilResultFile, AssemblerOptions.UseOwnDisassembler).ConfigureAwait(false);
var executable = await Tester.AssembleIL(ilInputFile, AssemblerOptions.Library).ConfigureAwait(false);
var disassembled = await Tester.Disassemble(executable, ilResultFile, AssemblerOptions.UseOwnDisassembler | asmOptions).ConfigureAwait(false);
CodeAssert.FilesAreEqual(ilExpectedFile, ilResultFile);
CodeAssert.FilesAreEqual(ilExpectedFile, disassembled);
}
}
}

10
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -85,6 +85,8 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -85,6 +85,8 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
UseOwnDisassembler = 0x8,
/// Work around bug in .NET 5 ilasm (https://github.com/dotnet/runtime/issues/32400)
UseLegacyAssembler = 0x10,
/// UseSortByNameFilter, implies UseOwnDisassembler
SortedOutput = 0x20,
}
public static partial class Tester
@ -196,7 +198,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -196,7 +198,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
public static async Task<string> Disassemble(string sourceFileName, string outputFile, AssemblerOptions asmOptions)
{
if (asmOptions.HasFlag(AssemblerOptions.UseOwnDisassembler))
if (asmOptions.HasFlag(AssemblerOptions.UseOwnDisassembler) || asmOptions.HasFlag(AssemblerOptions.SortedOutput))
{
using (var peFileStream = new FileStream(sourceFileName, FileMode.Open, FileAccess.Read))
using (var peFile = new PEFile(sourceFileName, peFileStream))
@ -205,7 +207,11 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -205,7 +207,11 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
var metadata = peFile.Metadata;
var output = new PlainTextOutput(writer);
ReflectionDisassembler rd = new ReflectionDisassembler(output, CancellationToken.None);
rd.AssemblyResolver = new UniversalAssemblyResolver(sourceFileName, true, null);
if (asmOptions.HasFlag(AssemblerOptions.SortedOutput))
{
rd.EntityProcessor = new SortByNameProcessor();
}
rd.AssemblyResolver = new UniversalAssemblyResolver(sourceFileName, throwOnError: true, null);
rd.DetectControlStructure = false;
rd.WriteAssemblyReferences(metadata);
if (metadata.IsAssembly)

2
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -73,6 +73,8 @@ @@ -73,6 +73,8 @@
<None Include="TestCases\Correctness\StackTests.il" />
<None Include="TestCases\Correctness\StackTypes.il" />
<None Include="TestCases\Correctness\Uninit.vb" />
<None Include="TestCases\Disassembler\Pretty\SortMembers.expected.il" />
<None Include="TestCases\Disassembler\Pretty\SortMembers.il" />
<None Include="TestCases\ILPretty\GuessAccessors.cs" />
<None Include="TestCases\ILPretty\GuessAccessors.il" />
<None Include="TestCases\ILPretty\Issue2260SwitchString.il" />

2
ICSharpCode.Decompiler.Tests/TestCases/Disassembler/Pretty/.gitignore vendored

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
*.result.il
*.dll

395
ICSharpCode.Decompiler.Tests/TestCases/Disassembler/Pretty/SortMembers.expected.il

@ -0,0 +1,395 @@ @@ -0,0 +1,395 @@
.assembly extern mscorlib
{
.publickeytoken = (
b7 7a 5c 56 19 34 e0 89
)
.ver 4:0:0:0
}
.assembly SecurityDeclarations
{
.custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = (
01 00 07 31 2e 30 2e 30 2e 30 00 00
)
.hash algorithm 0x00008004 // SHA1
.ver 1:0:0:0
}
.module SecurityDeclarations.dll
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WindowsCui
.corflags 0x00000001 // ILOnly
.class private auto ansi '<Module>'
{
} // end of class <Module>
.class private auto ansi beforefieldinit SecurityDeclarations.NestedArrays
extends [mscorlib]System.Object
{
.permissionset assert = {
class 'SecurityDeclarations.SecurityAttrTest, SecurityDeclarations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' = {
field object TestBoxed2 = object(object[4](int32(1) int32(2) int32(3) object[3](int32(4) int32(5) int32(6))))
}
}
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x20d4
// Header size: 1
// Code size: 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method NestedArrays::.ctor
} // end of class SecurityDeclarations.NestedArrays
.class private auto ansi beforefieldinit SecurityDeclarations.SecurityAttrTest
extends [mscorlib]System.Security.Permissions.SecurityAttribute
{
// Fields
.field private valuetype SecurityDeclarations.TestEnum[] _testEnumArray
.field private int32[] _testInt32Array
.field private string[] _testStringArray
.field private class [mscorlib]System.Type[] _testTypeArray
.field public object TestBoxed
.field public object TestBoxed2
.field public object TestBoxedArray
.field public object TestBoxedString
.field public object TestBoxedType
.field public valuetype SecurityDeclarations.TestEnum TestEnumType
.field public int32 TestInt32
.field public string TestString
.field public class [mscorlib]System.Type TestType
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
valuetype [mscorlib]System.Security.Permissions.SecurityAction action
) cil managed
{
// Method begins at RVA 0x2059
// Header size: 1
// Code size: 10 (0xa)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: call instance void [mscorlib]System.Security.Permissions.SecurityAttribute::.ctor(valuetype [mscorlib]System.Security.Permissions.SecurityAction)
IL_0007: nop
IL_0008: nop
IL_0009: ret
} // end of method SecurityAttrTest::.ctor
.method public hidebysig virtual
instance class [mscorlib]System.Security.IPermission CreatePermission () cil managed
{
// Method begins at RVA 0x2064
// Header size: 1
// Code size: 7 (0x7)
.maxstack 8
IL_0000: nop
IL_0001: newobj instance void [mscorlib]System.NotImplementedException::.ctor()
IL_0006: throw
} // end of method SecurityAttrTest::CreatePermission
.method public hidebysig specialname
instance valuetype SecurityDeclarations.TestEnum[] get_TestEnumArray () cil managed
{
// Method begins at RVA 0x208e
// Header size: 1
// Code size: 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld valuetype SecurityDeclarations.TestEnum[] SecurityDeclarations.SecurityAttrTest::_testEnumArray
IL_0006: ret
} // end of method SecurityAttrTest::get_TestEnumArray
.method public hidebysig specialname
instance int32[] get_TestInt32Array () cil managed
{
// Method begins at RVA 0x207d
// Header size: 1
// Code size: 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld int32[] SecurityDeclarations.SecurityAttrTest::_testInt32Array
IL_0006: ret
} // end of method SecurityAttrTest::get_TestInt32Array
.method public hidebysig specialname
instance string[] get_TestStringArray () cil managed
{
// Method begins at RVA 0x206c
// Header size: 1
// Code size: 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld string[] SecurityDeclarations.SecurityAttrTest::_testStringArray
IL_0006: ret
} // end of method SecurityAttrTest::get_TestStringArray
.method public hidebysig specialname
instance class [mscorlib]System.Type[] get_TestTypeArray () cil managed
{
// Method begins at RVA 0x209f
// Header size: 1
// Code size: 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Type[] SecurityDeclarations.SecurityAttrTest::_testTypeArray
IL_0006: ret
} // end of method SecurityAttrTest::get_TestTypeArray
.method public hidebysig specialname
instance void set_TestEnumArray (
valuetype SecurityDeclarations.TestEnum[] 'value'
) cil managed
{
// Method begins at RVA 0x2096
// Header size: 1
// Code size: 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld valuetype SecurityDeclarations.TestEnum[] SecurityDeclarations.SecurityAttrTest::_testEnumArray
IL_0007: ret
} // end of method SecurityAttrTest::set_TestEnumArray
.method public hidebysig specialname
instance void set_TestInt32Array (
int32[] 'value'
) cil managed
{
// Method begins at RVA 0x2085
// Header size: 1
// Code size: 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld int32[] SecurityDeclarations.SecurityAttrTest::_testInt32Array
IL_0007: ret
} // end of method SecurityAttrTest::set_TestInt32Array
.method public hidebysig specialname
instance void set_TestStringArray (
string[] 'value'
) cil managed
{
// Method begins at RVA 0x2074
// Header size: 1
// Code size: 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld string[] SecurityDeclarations.SecurityAttrTest::_testStringArray
IL_0007: ret
} // end of method SecurityAttrTest::set_TestStringArray
.method public hidebysig specialname
instance void set_TestTypeArray (
class [mscorlib]System.Type[] 'value'
) cil managed
{
// Method begins at RVA 0x20a7
// Header size: 1
// Code size: 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld class [mscorlib]System.Type[] SecurityDeclarations.SecurityAttrTest::_testTypeArray
IL_0007: ret
} // end of method SecurityAttrTest::set_TestTypeArray
// Properties
.property instance valuetype SecurityDeclarations.TestEnum[] TestEnumArray()
{
.get instance valuetype SecurityDeclarations.TestEnum[] SecurityDeclarations.SecurityAttrTest::get_TestEnumArray()
.set instance void SecurityDeclarations.SecurityAttrTest::set_TestEnumArray(valuetype SecurityDeclarations.TestEnum[])
}
.property instance int32[] TestInt32Array()
{
.get instance int32[] SecurityDeclarations.SecurityAttrTest::get_TestInt32Array()
.set instance void SecurityDeclarations.SecurityAttrTest::set_TestInt32Array(int32[])
}
.property instance string[] TestStringArray()
{
.get instance string[] SecurityDeclarations.SecurityAttrTest::get_TestStringArray()
.set instance void SecurityDeclarations.SecurityAttrTest::set_TestStringArray(string[])
}
.property instance class [mscorlib]System.Type[] TestTypeArray()
{
.get instance class [mscorlib]System.Type[] SecurityDeclarations.SecurityAttrTest::get_TestTypeArray()
.set instance void SecurityDeclarations.SecurityAttrTest::set_TestTypeArray(class [mscorlib]System.Type[])
}
} // end of class SecurityDeclarations.SecurityAttrTest
.class private auto ansi beforefieldinit SecurityDeclarations.SimpleType
extends [mscorlib]System.Object
{
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2050
// Header size: 1
// Code size: 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method SimpleType::.ctor
} // end of class SecurityDeclarations.SimpleType
.class private auto ansi sealed SecurityDeclarations.TestEnum
extends [mscorlib]System.Enum
{
// Fields
.field public static literal valuetype SecurityDeclarations.TestEnum A = int32(0)
.field public static literal valuetype SecurityDeclarations.TestEnum B = int32(1)
.field public static literal valuetype SecurityDeclarations.TestEnum C = int32(2)
.field public specialname rtspecialname int32 value__
} // end of class SecurityDeclarations.TestEnum
.class private auto ansi beforefieldinit SecurityDeclarations.TestEnumTypes
extends [mscorlib]System.Object
{
.permissionset inheritcheck = {
class 'SecurityDeclarations.SecurityAttrTest, SecurityDeclarations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' = {
field enum SecurityDeclarations.TestEnum TestEnumType = int32(0)
field object TestBoxed = object(int32(1))
property enum SecurityDeclarations.TestEnum[] TestEnumArray = int32[3](0 1 2)
field object TestBoxed2 = object(object[4](int32(0) int32(1) int32(2) object[1](int32(3))))
field object TestBoxedArray = object(int32[3](0 1 2))
}
}
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x20c2
// Header size: 1
// Code size: 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method TestEnumTypes::.ctor
} // end of class SecurityDeclarations.TestEnumTypes
.class private auto ansi beforefieldinit SecurityDeclarations.TestInt32Types
extends [mscorlib]System.Object
{
.permissionset permitonly = {
class 'SecurityDeclarations.SecurityAttrTest, SecurityDeclarations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' = {
field int32 TestInt32 = int32(5)
field object TestBoxed = object(int32(10))
property int32[] TestInt32Array = int32[3](1 2 3)
field object TestBoxedArray = object(int32[3](4 5 6))
field object TestBoxed2 = object(object[3](int32(7) int32(8) int32(9)))
}
}
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x20cb
// Header size: 1
// Code size: 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method TestInt32Types::.ctor
} // end of class SecurityDeclarations.TestInt32Types
.class private auto ansi beforefieldinit SecurityDeclarations.TestStringTypes
extends [mscorlib]System.Object
{
.permissionset assert = {
class 'SecurityDeclarations.SecurityAttrTest, SecurityDeclarations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' = {
field string TestString = string('Hello World!')
field object TestBoxedString = object(string('Boxed String'))
property string[] TestStringArray = string[2]('a' 'b')
field object TestBoxedArray = object(string[2]('c' 'd'))
}
}
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x20b0
// Header size: 1
// Code size: 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method TestStringTypes::.ctor
} // end of class SecurityDeclarations.TestStringTypes
.class private sequential ansi sealed beforefieldinit SecurityDeclarations.TestStruct
extends [mscorlib]System.ValueType
{
.pack 0
.size 1
} // end of class SecurityDeclarations.TestStruct
.class private auto ansi beforefieldinit SecurityDeclarations.TestTypeTypes
extends [mscorlib]System.Object
{
.permissionset demand = {
class 'SecurityDeclarations.SecurityAttrTest, SecurityDeclarations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' = {
field type TestType = type(SecurityDeclarations.SimpleType)
field object TestBoxed = object(type(SecurityDeclarations.TestEnum))
property type[] TestTypeArray = type[2](SecurityDeclarations.TestStruct SecurityDeclarations.SimpleType)
field object TestBoxedArray = object(type[2](SecurityDeclarations.TestStringTypes SecurityDeclarations.TestTypeTypes))
}
}
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x20b9
// Header size: 1
// Code size: 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method TestTypeTypes::.ctor
} // end of class SecurityDeclarations.TestTypeTypes

381
ICSharpCode.Decompiler.Tests/TestCases/Disassembler/Pretty/SortMembers.il

@ -0,0 +1,381 @@ @@ -0,0 +1,381 @@
.assembly extern mscorlib
{
.publickeytoken = (
b7 7a 5c 56 19 34 e0 89
)
.ver 4:0:0:0
}
.assembly SecurityDeclarations
{
.custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = (
01 00 07 31 2e 30 2e 30 2e 30 00 00
)
.hash algorithm 0x00008004 // SHA1
.ver 1:0:0:0
}
.module SecurityDeclarations.dll
// MVID: {761F919A-2373-48EB-9282-9DAB26913D43}
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WindowsCui
.corflags 0x00000001 // ILOnly
.class private auto ansi '<Module>'
{
} // end of class <Module>
.class private sequential ansi sealed beforefieldinit SecurityDeclarations.TestStruct
extends [mscorlib]System.ValueType
{
.pack 0
.size 1
} // end of class SecurityDeclarations.TestStruct
.class private auto ansi beforefieldinit SecurityDeclarations.SimpleType
extends [mscorlib]System.Object
{
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2050
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method SimpleType::.ctor
} // end of class SecurityDeclarations.SimpleType
.class private auto ansi sealed SecurityDeclarations.TestEnum
extends [mscorlib]System.Enum
{
// Fields
.field public specialname rtspecialname int32 value__
.field public static literal valuetype SecurityDeclarations.TestEnum A = int32(0)
.field public static literal valuetype SecurityDeclarations.TestEnum B = int32(1)
.field public static literal valuetype SecurityDeclarations.TestEnum C = int32(2)
} // end of class SecurityDeclarations.TestEnum
.class private auto ansi beforefieldinit SecurityDeclarations.SecurityAttrTest
extends [mscorlib]System.Security.Permissions.SecurityAttribute
{
// Fields
.field private string[] _testStringArray
.field private int32[] _testInt32Array
.field private valuetype SecurityDeclarations.TestEnum[] _testEnumArray
.field private class [mscorlib]System.Type[] _testTypeArray
.field public int32 TestInt32
.field public class [mscorlib]System.Type TestType
.field public valuetype SecurityDeclarations.TestEnum TestEnumType
.field public object TestBoxed
.field public object TestBoxed2
.field public string TestString
.field public object TestBoxedString
.field public object TestBoxedArray
.field public object TestBoxedType
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
valuetype [mscorlib]System.Security.Permissions.SecurityAction action
) cil managed
{
// Method begins at RVA 0x2059
// Code size 10 (0xa)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: call instance void [mscorlib]System.Security.Permissions.SecurityAttribute::.ctor(valuetype [mscorlib]System.Security.Permissions.SecurityAction)
IL_0007: nop
IL_0008: nop
IL_0009: ret
} // end of method SecurityAttrTest::.ctor
.method public hidebysig virtual
instance class [mscorlib]System.Security.IPermission CreatePermission () cil managed
{
// Method begins at RVA 0x2064
// Code size 7 (0x7)
.maxstack 8
IL_0000: nop
IL_0001: newobj instance void [mscorlib]System.NotImplementedException::.ctor()
IL_0006: throw
} // end of method SecurityAttrTest::CreatePermission
.method public hidebysig specialname
instance string[] get_TestStringArray () cil managed
{
// Method begins at RVA 0x206c
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld string[] SecurityDeclarations.SecurityAttrTest::_testStringArray
IL_0006: ret
} // end of method SecurityAttrTest::get_TestStringArray
.method public hidebysig specialname
instance void set_TestStringArray (
string[] 'value'
) cil managed
{
// Method begins at RVA 0x2074
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld string[] SecurityDeclarations.SecurityAttrTest::_testStringArray
IL_0007: ret
} // end of method SecurityAttrTest::set_TestStringArray
.method public hidebysig specialname
instance int32[] get_TestInt32Array () cil managed
{
// Method begins at RVA 0x207d
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld int32[] SecurityDeclarations.SecurityAttrTest::_testInt32Array
IL_0006: ret
} // end of method SecurityAttrTest::get_TestInt32Array
.method public hidebysig specialname
instance void set_TestInt32Array (
int32[] 'value'
) cil managed
{
// Method begins at RVA 0x2085
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld int32[] SecurityDeclarations.SecurityAttrTest::_testInt32Array
IL_0007: ret
} // end of method SecurityAttrTest::set_TestInt32Array
.method public hidebysig specialname
instance valuetype SecurityDeclarations.TestEnum[] get_TestEnumArray () cil managed
{
// Method begins at RVA 0x208e
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld valuetype SecurityDeclarations.TestEnum[] SecurityDeclarations.SecurityAttrTest::_testEnumArray
IL_0006: ret
} // end of method SecurityAttrTest::get_TestEnumArray
.method public hidebysig specialname
instance void set_TestEnumArray (
valuetype SecurityDeclarations.TestEnum[] 'value'
) cil managed
{
// Method begins at RVA 0x2096
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld valuetype SecurityDeclarations.TestEnum[] SecurityDeclarations.SecurityAttrTest::_testEnumArray
IL_0007: ret
} // end of method SecurityAttrTest::set_TestEnumArray
.method public hidebysig specialname
instance class [mscorlib]System.Type[] get_TestTypeArray () cil managed
{
// Method begins at RVA 0x209f
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Type[] SecurityDeclarations.SecurityAttrTest::_testTypeArray
IL_0006: ret
} // end of method SecurityAttrTest::get_TestTypeArray
.method public hidebysig specialname
instance void set_TestTypeArray (
class [mscorlib]System.Type[] 'value'
) cil managed
{
// Method begins at RVA 0x20a7
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld class [mscorlib]System.Type[] SecurityDeclarations.SecurityAttrTest::_testTypeArray
IL_0007: ret
} // end of method SecurityAttrTest::set_TestTypeArray
// Properties
.property instance string[] TestStringArray()
{
.get instance string[] SecurityDeclarations.SecurityAttrTest::get_TestStringArray()
.set instance void SecurityDeclarations.SecurityAttrTest::set_TestStringArray(string[])
}
.property instance int32[] TestInt32Array()
{
.get instance int32[] SecurityDeclarations.SecurityAttrTest::get_TestInt32Array()
.set instance void SecurityDeclarations.SecurityAttrTest::set_TestInt32Array(int32[])
}
.property instance valuetype SecurityDeclarations.TestEnum[] TestEnumArray()
{
.get instance valuetype SecurityDeclarations.TestEnum[] SecurityDeclarations.SecurityAttrTest::get_TestEnumArray()
.set instance void SecurityDeclarations.SecurityAttrTest::set_TestEnumArray(valuetype SecurityDeclarations.TestEnum[])
}
.property instance class [mscorlib]System.Type[] TestTypeArray()
{
.get instance class [mscorlib]System.Type[] SecurityDeclarations.SecurityAttrTest::get_TestTypeArray()
.set instance void SecurityDeclarations.SecurityAttrTest::set_TestTypeArray(class [mscorlib]System.Type[])
}
} // end of class SecurityDeclarations.SecurityAttrTest
.class private auto ansi beforefieldinit SecurityDeclarations.TestStringTypes
extends [mscorlib]System.Object
{
.permissionset assert = {
class 'SecurityDeclarations.SecurityAttrTest, SecurityDeclarations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' = {
field string TestString = string('Hello World!')
field object TestBoxedString = object(string('Boxed String'))
property string[] TestStringArray = string[2]('a' 'b')
field object TestBoxedArray = object(string[2]('c' 'd'))
}
}
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2050
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method TestStringTypes::.ctor
} // end of class SecurityDeclarations.TestStringTypes
.class private auto ansi beforefieldinit SecurityDeclarations.TestTypeTypes
extends [mscorlib]System.Object
{
.permissionset demand = {
class 'SecurityDeclarations.SecurityAttrTest, SecurityDeclarations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' = {
field type TestType = type(SecurityDeclarations.SimpleType)
field object TestBoxed = object(type(SecurityDeclarations.TestEnum))
property type[] TestTypeArray = type[2](SecurityDeclarations.TestStruct SecurityDeclarations.SimpleType)
field object TestBoxedArray = object(type[2](SecurityDeclarations.TestStringTypes SecurityDeclarations.TestTypeTypes))
}
}
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2050
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method TestTypeTypes::.ctor
} // end of class SecurityDeclarations.TestTypeTypes
.class private auto ansi beforefieldinit SecurityDeclarations.TestEnumTypes
extends [mscorlib]System.Object
{
.permissionset inheritcheck = {
class 'SecurityDeclarations.SecurityAttrTest, SecurityDeclarations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' = {
field enum SecurityDeclarations.TestEnum TestEnumType = int32(0)
field object TestBoxed = object(int32(1))
property enum SecurityDeclarations.TestEnum[] TestEnumArray = int32[3](0 1 2)
field object TestBoxed2 = object(object[4](int32(0) int32(1) int32(2) object[1](int32(3))))
field object TestBoxedArray = object(int32[3](0 1 2))
}
}
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2050
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method TestEnumTypes::.ctor
} // end of class SecurityDeclarations.TestEnumTypes
.class private auto ansi beforefieldinit SecurityDeclarations.TestInt32Types
extends [mscorlib]System.Object
{
.permissionset permitonly = {
class 'SecurityDeclarations.SecurityAttrTest, SecurityDeclarations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' = {
field int32 TestInt32 = int32(5)
field object TestBoxed = object(int32(10))
property int32[] TestInt32Array = int32[3](1 2 3)
field object TestBoxedArray = object(int32[3](4 5 6))
field object TestBoxed2 = object(object[3](int32(7) int32(8) int32(9)))
}
}
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2050
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method TestInt32Types::.ctor
} // end of class SecurityDeclarations.TestInt32Types
.class private auto ansi beforefieldinit SecurityDeclarations.NestedArrays
extends [mscorlib]System.Object
{
.permissionset assert = {
class 'SecurityDeclarations.SecurityAttrTest, SecurityDeclarations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' = {
field object TestBoxed2 = object(object[4](int32(1) int32(2) int32(3) object[3](int32(4) int32(5) int32(6))))
}
}
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2050
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method NestedArrays::.ctor
} // end of class SecurityDeclarations.NestedArrays

44
ICSharpCode.Decompiler/Disassembler/IEntityProcessor.cs

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
// Copyright (c) 2022 Tom Englert
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System.Collections.Generic;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.Decompiler.Disassembler
{
public interface IEntityProcessor
{
IReadOnlyCollection<InterfaceImplementationHandle> Process(PEFile module, IReadOnlyCollection<InterfaceImplementationHandle> items);
IReadOnlyCollection<TypeDefinitionHandle> Process(PEFile module, IReadOnlyCollection<TypeDefinitionHandle> items);
IReadOnlyCollection<MethodDefinitionHandle> Process(PEFile module, IReadOnlyCollection<MethodDefinitionHandle> items);
IReadOnlyCollection<PropertyDefinitionHandle> Process(PEFile module, IReadOnlyCollection<PropertyDefinitionHandle> items);
IReadOnlyCollection<EventDefinitionHandle> Process(PEFile module, IReadOnlyCollection<EventDefinitionHandle> items);
IReadOnlyCollection<FieldDefinitionHandle> Process(PEFile module, IReadOnlyCollection<FieldDefinitionHandle> items);
IReadOnlyCollection<CustomAttributeHandle> Process(PEFile module, IReadOnlyCollection<CustomAttributeHandle> items);
}
}

62
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -71,10 +71,12 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -71,10 +71,12 @@ namespace ICSharpCode.Decompiler.Disassembler
set => methodBodyDisassembler.DebugInfo = value;
}
public bool ExpandMemberDefinitions { get; set; } = false;
public bool ExpandMemberDefinitions { get; set; }
public IAssemblyResolver AssemblyResolver { get; set; }
public IEntityProcessor EntityProcessor { get; set; }
public ReflectionDisassembler(ITextOutput output, CancellationToken cancellationToken)
: this(output, new MethodBodyDisassembler(output, cancellationToken), cancellationToken)
{
@ -1560,7 +1562,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -1560,7 +1562,7 @@ namespace ICSharpCode.Decompiler.Disassembler
DisassembleTypeHeaderInternal(module, type, typeDefinition, genericContext);
var interfaces = typeDefinition.GetInterfaceImplementations();
var interfaces = Process(module, typeDefinition.GetInterfaceImplementations());
if (interfaces.Count > 0)
{
output.Indent();
@ -1599,8 +1601,8 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -1599,8 +1601,8 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine(".size {0}", layout.Size);
output.WriteLine();
}
var nestedTypes = typeDefinition.GetNestedTypes();
if (!nestedTypes.IsEmpty)
var nestedTypes = Process(module, typeDefinition.GetNestedTypes());
if (nestedTypes.Any())
{
output.WriteLine("// Nested Types");
foreach (var nestedType in nestedTypes)
@ -1611,7 +1613,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -1611,7 +1613,7 @@ namespace ICSharpCode.Decompiler.Disassembler
}
output.WriteLine();
}
var fields = typeDefinition.GetFields();
var fields = Process(module, typeDefinition.GetFields());
if (fields.Any())
{
output.WriteLine("// Fields");
@ -1622,7 +1624,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -1622,7 +1624,7 @@ namespace ICSharpCode.Decompiler.Disassembler
}
output.WriteLine();
}
var methods = typeDefinition.GetMethods();
var methods = Process(module, typeDefinition.GetMethods());
if (methods.Any())
{
output.WriteLine("// Methods");
@ -1633,7 +1635,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -1633,7 +1635,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine();
}
}
var events = typeDefinition.GetEvents();
var events = Process(module, typeDefinition.GetEvents());
if (events.Any())
{
output.WriteLine("// Events");
@ -1645,7 +1647,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -1645,7 +1647,7 @@ namespace ICSharpCode.Decompiler.Disassembler
}
output.WriteLine();
}
var properties = typeDefinition.GetProperties();
var properties = Process(module, typeDefinition.GetProperties());
if (properties.Any())
{
output.WriteLine("// Properties");
@ -1747,11 +1749,51 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -1747,11 +1749,51 @@ namespace ICSharpCode.Decompiler.Disassembler
}
#endregion
#region Processing
private IReadOnlyCollection<InterfaceImplementationHandle> Process(PEFile module, IReadOnlyCollection<InterfaceImplementationHandle> items)
{
return EntityProcessor?.Process(module, items) ?? items;
}
private IReadOnlyCollection<TypeDefinitionHandle> Process(PEFile module, IReadOnlyCollection<TypeDefinitionHandle> items)
{
return EntityProcessor?.Process(module, items) ?? items;
}
private IReadOnlyCollection<MethodDefinitionHandle> Process(PEFile module, IReadOnlyCollection<MethodDefinitionHandle> items)
{
return EntityProcessor?.Process(module, items) ?? items;
}
private IReadOnlyCollection<PropertyDefinitionHandle> Process(PEFile module, IReadOnlyCollection<PropertyDefinitionHandle> items)
{
return EntityProcessor?.Process(module, items) ?? items;
}
private IReadOnlyCollection<EventDefinitionHandle> Process(PEFile module, IReadOnlyCollection<EventDefinitionHandle> items)
{
return EntityProcessor?.Process(module, items) ?? items;
}
private IReadOnlyCollection<FieldDefinitionHandle> Process(PEFile module, IReadOnlyCollection<FieldDefinitionHandle> items)
{
return EntityProcessor?.Process(module, items) ?? items;
}
private IReadOnlyCollection<CustomAttributeHandle> Process(PEFile module, IReadOnlyCollection<CustomAttributeHandle> items)
{
return EntityProcessor?.Process(module, items) ?? items;
}
#endregion
#region Helper methods
void WriteAttributes(PEFile module, CustomAttributeHandleCollection attributes)
{
var metadata = module.Metadata;
foreach (CustomAttributeHandle a in attributes)
foreach (CustomAttributeHandle a in Process(module, attributes))
{
output.Write(".custom ");
var attr = metadata.GetCustomAttribute(a);
@ -2037,7 +2079,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -2037,7 +2079,7 @@ namespace ICSharpCode.Decompiler.Disassembler
public void WriteModuleContents(PEFile module)
{
foreach (var handle in module.Metadata.GetTopLevelTypeDefinitions())
foreach (var handle in Process(module, module.Metadata.GetTopLevelTypeDefinitions().ToArray()))
{
DisassembleType(module, handle);
output.WriteLine();

122
ICSharpCode.Decompiler/Disassembler/SortByNameProcessor.cs

@ -0,0 +1,122 @@ @@ -0,0 +1,122 @@
// Copyright (c) 2022 Tom Englert
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.Decompiler.Disassembler
{
public class SortByNameProcessor : IEntityProcessor
{
public IReadOnlyCollection<InterfaceImplementationHandle> Process(PEFile module,
IReadOnlyCollection<InterfaceImplementationHandle> items)
{
return items.OrderBy(item => GetSortKey(item, module)).ToArray();
}
public IReadOnlyCollection<TypeDefinitionHandle> Process(PEFile module,
IReadOnlyCollection<TypeDefinitionHandle> items)
{
return items.OrderBy(item => GetSortKey(item, module)).ToArray();
}
public IReadOnlyCollection<MethodDefinitionHandle> Process(PEFile module,
IReadOnlyCollection<MethodDefinitionHandle> items)
{
return items.OrderBy(item => GetSortKey(item, module)).ToArray();
}
public IReadOnlyCollection<PropertyDefinitionHandle> Process(PEFile module,
IReadOnlyCollection<PropertyDefinitionHandle> items)
{
return items.OrderBy(item => GetSortKey(item, module)).ToArray();
}
public IReadOnlyCollection<EventDefinitionHandle> Process(PEFile module,
IReadOnlyCollection<EventDefinitionHandle> items)
{
return items.OrderBy(item => GetSortKey(item, module)).ToArray();
}
public IReadOnlyCollection<FieldDefinitionHandle> Process(PEFile module,
IReadOnlyCollection<FieldDefinitionHandle> items)
{
return items.OrderBy(item => GetSortKey(item, module)).ToArray();
}
public IReadOnlyCollection<CustomAttributeHandle> Process(PEFile module,
IReadOnlyCollection<CustomAttributeHandle> items)
{
return items.OrderBy(item => GetSortKey(item, module)).ToArray();
}
private static string GetSortKey(TypeDefinitionHandle handle, PEFile module) =>
handle.GetFullTypeName(module.Metadata).ToILNameString();
private static string GetSortKey(MethodDefinitionHandle handle, PEFile module)
{
PlainTextOutput output = new PlainTextOutput();
MethodDefinition definition = module.Metadata.GetMethodDefinition(handle);
// Start with the methods name, skip return type
output.Write(module.Metadata.GetString(definition.Name));
DisassemblerSignatureTypeProvider signatureProvider = new DisassemblerSignatureTypeProvider(module, output);
MethodSignature<Action<ILNameSyntax>> signature =
definition.DecodeSignature(signatureProvider, new MetadataGenericContext(handle, module));
if (signature.GenericParameterCount > 0)
{
output.Write($"`{signature.GenericParameterCount}");
}
InstructionOutputExtensions.WriteParameterList(output, signature);
return output.ToString();
}
private static string GetSortKey(InterfaceImplementationHandle handle, PEFile module) =>
module.Metadata.GetInterfaceImplementation(handle)
.Interface
.GetFullTypeName(module.Metadata)
.ToILNameString();
private static string GetSortKey(FieldDefinitionHandle handle, PEFile module) =>
module.Metadata.GetString(module.Metadata.GetFieldDefinition(handle).Name);
private static string GetSortKey(PropertyDefinitionHandle handle, PEFile module) =>
module.Metadata.GetString(module.Metadata.GetPropertyDefinition(handle).Name);
private static string GetSortKey(EventDefinitionHandle handle, PEFile module) =>
module.Metadata.GetString(module.Metadata.GetEventDefinition(handle).Name);
private static string GetSortKey(CustomAttributeHandle handle, PEFile module) =>
module.Metadata.GetCustomAttribute(handle)
.Constructor
.GetDeclaringType(module.Metadata)
.GetFullTypeName(module.Metadata)
.ToILNameString();
}
}

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -92,6 +92,8 @@ @@ -92,6 +92,8 @@
<Compile Include="CSharp\CallBuilder.cs" />
<Compile Include="CSharp\CSharpLanguageVersion.cs" />
<Compile Include="DecompilationProgress.cs" />
<Compile Include="Disassembler\IEntityProcessor.cs" />
<Compile Include="Disassembler\SortByNameProcessor.cs" />
<Compile Include="NRTAttributes.cs" />
<Compile Include="PartialTypeInfo.cs" />
<Compile Include="CSharp\ProjectDecompiler\IProjectFileWriter.cs" />

2
ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs

@ -321,7 +321,7 @@ namespace ICSharpCode.Decompiler.IL @@ -321,7 +321,7 @@ namespace ICSharpCode.Decompiler.IL
output.Write('>');
}
static void WriteParameterList(ITextOutput output, MethodSignature<Action<ILNameSyntax>> methodSignature)
internal static void WriteParameterList(ITextOutput output, MethodSignature<Action<ILNameSyntax>> methodSignature)
{
output.Write("(");
for (int i = 0; i < methodSignature.ParameterTypes.Length; ++i)

Loading…
Cancel
Save