Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ICSharpCode.Decompiler + Mono.Cecil -> How to generate code for a single method?

I'm able to use Mono.Cecil and ICSharpCode.Decompiler to generate the code for a type or an assembly.

But if I try to generate the code for a single method I'll get an error "Object reference not set to an instance of an object."

Can you guys give me any hints about this? Thanks ahead for all the help.

Code to generate code for all the types inside an assembly:

DirectoryInfo di = new DirectoryInfo(appPath);
FileInfo[] allAssemblies = di.GetFiles("*.dll");
foreach (var assemblyFile in allAssemblies)
{
    string pathToAssembly = assemblyFile.FullName;
    System.Reflection.Assembly assembly = System.Reflection.Assembly.ReflectionOnlyLoadFrom(pathToAssembly);
    Mono.Cecil.AssemblyDefinition assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(pathToAssembly,parameters);
    AstBuilder astBuilder = null;

    foreach (var typeInAssembly in assemblyDefinition.MainModule.Types)
    {
        if (typeInAssembly.IsPublic)
        {
             Console.WriteLine("T:{0}", typeInAssembly.Name);
            //just reset the builder to include only code for a single type
            astBuilder = new AstBuilder(new ICSharpCode.Decompiler.DecompilerContext(assemblyDefinition.MainModule));
            astBuilder.AddType(typeInAssembly);
            StringWriter output = new StringWriter();
            astBuilder.GenerateCode(new PlainTextOutput(output));
            string result = output.ToString();
            output.Dispose();
        }
    }
}

Code to generate code for all the public methods inside an assembly:

DirectoryInfo di = new DirectoryInfo(appPath);
FileInfo[] allAssemblies = di.GetFiles("*.dll");
foreach (var assemblyFile in allAssemblies)
{
    string pathToAssembly = assemblyFile.FullName;
    System.Reflection.Assembly assembly = System.Reflection.Assembly.ReflectionOnlyLoadFrom(pathToAssembly);
    Mono.Cecil.AssemblyDefinition assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(pathToAssembly,parameters);
    AstBuilder astBuilder = null;

    foreach (var typeInAssembly in assemblyDefinition.MainModule.Types)
    {
        if (typeInAssembly.IsPublic)
        {
            Console.WriteLine("T:{0}", typeInAssembly.Name);
            foreach (var method in typeInAssembly.Methods)
            {
                //just reset the builder to include only code for a single method
                astBuilder = new AstBuilder(new ICSharpCode.Decompiler.DecompilerContext(assemblyDefinition.MainModule));
                astBuilder.AddMethod(method);
                if (method.IsPublic && !method.IsGetter && !method.IsSetter && !method.IsConstructor)
                {
                    Console.WriteLine("M:{0}", method.Name);
                    StringWriter output = new StringWriter();
                    astBuilder.GenerateCode(new PlainTextOutput(output));
                    string result = output.ToString();
                    output.Dispose();
                }
            }
        }
    }
}
like image 201
lpinho Avatar asked Jan 17 '23 03:01

lpinho


2 Answers

I had the same problem. You should set the property CurrentType of the DecompilerContext. Change your code to

astBuilder = new AstBuilder(new ICSharpCode.Decompiler.DecompilerContext(assemblyDefinition.MainModule) { CurrentType = typeInAssembly } );
like image 169
Torsten Avatar answered Jan 31 '23 06:01

Torsten


When I recently implemented a quick C# decompiler (MonoDecompiler based), I used the ILSpy methods :)

public string getSourceCode(MethodDefinition methodDefinition)
{
    try
    {
        var csharpLanguage = new CSharpLanguage();
        var textOutput = new PlainTextOutput();
        var decompilationOptions = new DecompilationOptions();
        decompilationOptions.FullDecompilation = true;
        csharpLanguage.DecompileMethod(methodDefinition, textOutput, decompilationOptions);
        return textOutput.ToString();              

    }
    catch (Exception exception)
    {
        PublicDI.log.error("in getSourceCode: {0}", new object[] { exception.Message });
        return ("Error in creating source code from IL: " + exception.Message);
    }
}

For this and other examples see: https://github.com/o2platform/O2.Platform.Scripts/blob/master/3rdParty/MonoCecil/CecilDecompiler/CecilDecompiler.cs

The stand-alone mini C# decompilation tool is created by this script https://github.com/o2platform/O2.Platform.Scripts/blob/master/3rdParty/MonoCecil/Utils/Tool%20-%20C%23%20Quick%20Decompiler.h2

like image 23
Dinis Cruz Avatar answered Jan 31 '23 05:01

Dinis Cruz