• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SamboyCoding / Cpp2IL / 17101091060

20 Aug 2025 02:16PM UTC coverage: 30.421% (-3.9%) from 34.352%
17101091060

Pull #481

github

web-flow
Merge 42542dde2 into d5260685f
Pull Request #481: Decompiler

1804 of 7551 branches covered (23.89%)

Branch coverage included in aggregate %.

102 of 1827 new or added lines in 35 files covered. (5.58%)

40 existing lines in 6 files now uncovered.

4095 of 11840 relevant lines covered (34.59%)

165714.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

1.61
/Cpp2IL.Core/OutputFormats/AsmResolverDllOutputFormatIlRecovery.cs
1
using System;
2
using System.Collections.Generic;
3
using System.IO;
4
using System.Linq;
5
using System.Text;
6
using AsmResolver.DotNet;
7
using AsmResolver.PE.DotNet.Cil;
8
using AssetRipper.CIL;
9
using Cpp2IL.Core.Extensions;
10
using Cpp2IL.Core.Graphs;
11
using Cpp2IL.Core.Logging;
12
using Cpp2IL.Core.Model.Contexts;
13
using Cpp2IL.Core.Utils;
14

15
namespace Cpp2IL.Core.OutputFormats;
16

17
public class AsmResolverDllOutputFormatIlRecovery : AsmResolverDllOutputFormat
18
{
19
    public override string OutputFormatId => "dll_il_recovery";
1✔
20

21
    public override string OutputFormatName => "DLL files with IL Recovery";
×
22

23
    private MethodDefinition? _exceptionConstructor;
24
    private Ilgenerator _ilGenerator = new();
1✔
25

26
    protected override void FillMethodBody(MethodDefinition methodDefinition, MethodAnalysisContext methodContext)
27
    {
NEW
28
        if (_exceptionConstructor == null)
×
NEW
29
            FindExceptionConstructor(methodDefinition);
×
30

NEW
31
        var module = methodDefinition.Module!;
×
NEW
32
        var moduleName = module.Name!.ToString();
×
NEW
33
        var shouldSkip = moduleName.StartsWith("UnityEngine.") || moduleName.StartsWith("Unity.") ||
×
NEW
34
                         moduleName.StartsWith("System.") || moduleName == "System" ||
×
NEW
35
                         moduleName.StartsWith("mscorlib");
×
NEW
36
        var importer = new ReferenceImporter(module);
×
37

NEW
38
        if (!methodDefinition.IsManagedMethodWithBody())
×
NEW
39
            return;
×
40

NEW
41
        methodDefinition.CilMethodBody = new(methodDefinition);
×
NEW
42
        var instructions = methodDefinition.CilMethodBody.Instructions;
×
43

NEW
44
        if (shouldSkip)
×
45
        {
46
            instructions.Add(CilOpCodes.Ldnull);
×
47
            instructions.Add(CilOpCodes.Throw);
×
NEW
48
            return;
×
49
        }
50

51
        try
52
        {
NEW
53
            TotalMethodCount++;
×
54

NEW
55
            methodContext.Analyze();
×
NEW
56
            _ilGenerator.GenerateIl(methodContext, methodDefinition);
×
57

58
            //WriteControlFlowGraph(methodContext, Path.Combine(Environment.CurrentDirectory, "Cpp2IL", "bin", "Debug", "net9.0", "cpp2il_out", "cfg"));
59

NEW
60
            SuccessfulMethodCount++;
×
NEW
61
        }
×
NEW
62
        catch (Exception e)
×
63
        {
NEW
64
            Logger.ErrorNewline($"Decompiling {methodContext.FullName} failed: {e}");
×
65

66
            // throw new Exception(error);
NEW
67
            instructions.Add(CilOpCodes.Ldstr, e.ToString());
×
NEW
68
            instructions.Add(CilOpCodes.Newobj, importer.ImportMethod(_exceptionConstructor!));
×
NEW
69
            instructions.Add(CilOpCodes.Throw);
×
NEW
70
        }
×
71

NEW
72
        methodContext.ReleaseAnalysisData();
×
NEW
73
    }
×
74

75
    private void FindExceptionConstructor(MethodDefinition method)
76
    {
NEW
77
        var module = method.Module!;
×
NEW
78
        var mscorlibReference = module.AssemblyReferences.First(a => a.Name == "mscorlib");
×
NEW
79
        var mscorlib = mscorlibReference.Resolve()!.Modules[0];
×
80

NEW
81
        var exception = mscorlib.TopLevelTypes.First(t => t.FullName == "System.Exception");
×
NEW
82
        _exceptionConstructor = exception.Methods.First(m =>
×
NEW
83
            m.Name == ".ctor" && m.Parameters is [{ ParameterType.FullName: "System.String" }]);
×
NEW
84
    }
×
85

86
    public static void WriteControlFlowGraph(MethodAnalysisContext method, string outputPath)
87
    {
NEW
88
        var graph = method.ControlFlowGraph;
×
89

NEW
90
        var sb = new StringBuilder();
×
NEW
91
        var edges = new List<(int, int)>();
×
92

NEW
93
        sb.AppendLine("digraph ControlFlowGraph {");
×
NEW
94
        sb.AppendLine("    \"label\"=\"Control flow graph\"");
×
95

96
        // no instructions
NEW
97
        graph ??= new ISILControlFlowGraph([]);
×
98

NEW
99
        var methodText = $@"{CsFileUtils.GetKeyWordsForMethod(method)} {method.FullNameWithSignature}
×
NEW
100
parameter locals: {string.Join(", ", method.ParameterLocals)}
×
NEW
101
parameter operands: {string.Join(", ", method.ParameterOperands)}";
×
102

NEW
103
        foreach (var block in graph.Blocks)
×
104
        {
NEW
105
            if (block == graph.EntryBlock || block == graph.ExitBlock)
×
106
            {
NEW
107
                var isEntry = block == graph.EntryBlock;
×
NEW
108
                sb.AppendLine($"""
×
NEW
109
                                       {block.ID} [
×
NEW
110
                                               "color"="{(isEntry ? "green" : "red")}"
×
NEW
111
                                               "label"="{(isEntry ? $"Entry ({block.ID})\n{methodText}" : $"Exit ({block.ID})")}"
×
NEW
112
                                       ]
×
NEW
113
                               """);
×
114
            }
115
            else
116
            {
NEW
117
                sb.AppendLine($"""
×
NEW
118
                                       {block.ID} [
×
NEW
119
                                               "shape"="box"
×
NEW
120
                                               "label"="{block.ToString().EscapeString().Replace("\\r", "")}"
×
NEW
121
                                       ]
×
NEW
122
                               """);
×
123
            }
124

NEW
125
            edges.AddRange(block.Successors.Select(b => (block.ID, b.ID)));
×
126
        }
127

NEW
128
        foreach (var edge in edges)
×
NEW
129
            sb.AppendLine($"    {edge.Item1} -> {edge.Item2}");
×
130

NEW
131
        sb.AppendLine("}");
×
132

NEW
133
        var type = method.DeclaringType!;
×
NEW
134
        var assemblyName = MiscUtils.CleanPathElement(type.DeclaringAssembly.CleanAssemblyName);
×
NEW
135
        var typePath = Path.Combine(type.FullName.Split('.').Select(MiscUtils.CleanPathElement).ToArray());
×
NEW
136
        var directoryPath = Path.Combine(outputPath, assemblyName, typePath);
×
137

NEW
138
        var methodName = MiscUtils.CleanPathElement(method.Name + "_" + string.Join("_",
×
NEW
139
            method.Parameters.Select(p => MiscUtils.CleanPathElement(p.ParameterType.Name))));
×
NEW
140
        var path = Path.Combine(directoryPath, methodName) + ".dot";
×
141

NEW
142
        if (path.Length > 260)
×
143
        {
NEW
144
            path = path[..250];
×
NEW
145
            path += ".dot";
×
146
        }
147

NEW
148
        var directory = Path.GetDirectoryName(path)!;
×
NEW
149
        if (!Directory.Exists(directory))
×
NEW
150
            Directory.CreateDirectory(directory);
×
151

NEW
152
        File.WriteAllText(path, sb.ToString());
×
UNCOV
153
    }
×
154
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc