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

SamboyCoding / Cpp2IL / 30164692193

25 Jul 2026 03:58PM UTC coverage: 37.493% (-0.08%) from 37.57%
30164692193

push

github

SamboyCoding
Core: Fix dll_il_recovery being completely broken

2875 of 8614 branches covered (33.38%)

Branch coverage included in aggregate %.

5 of 9 new or added lines in 3 files covered. (55.56%)

6 existing lines in 3 files now uncovered.

5271 of 13113 relevant lines covered (40.2%)

168584.87 hits per line

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

0.84
/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.DotNet.Signatures;
8
using AsmResolver.PE.DotNet.Cil;
9
using AssetRipper.CIL;
10
using Cpp2IL.Core.Extensions;
11
using Cpp2IL.Core.Graphs;
12
using Cpp2IL.Core.Logging;
13
using Cpp2IL.Core.Model.Contexts;
14
using Cpp2IL.Core.Utils;
15

16
namespace Cpp2IL.Core.OutputFormats;
17

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

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

24
    protected override void FillMethodBody(MethodDefinition methodDefinition, MethodAnalysisContext methodContext)
25
    {
26
        var module = methodDefinition.DeclaringModule!;
×
27
        var moduleName = module.Name!.ToString();
×
28
        var shouldSkip = moduleName.StartsWith("UnityEngine.") || moduleName.StartsWith("Unity.") ||
×
29
                         moduleName.StartsWith("System.") || moduleName == "System" ||
×
30
                         moduleName.StartsWith("mscorlib");
×
31
        var importer = new ReferenceImporter(module);
×
32

33
        if (!methodDefinition.IsManagedMethodWithBody())
×
34
            return;
×
35

36
        methodDefinition.CilMethodBody = new();
×
37
        var instructions = methodDefinition.CilMethodBody.Instructions;
×
38

39
        if (shouldSkip)
×
40
        {
41
            methodDefinition.ReplaceMethodBodyWithMinimalImplementation();
×
42
            return;
×
43
        }
44

45
        try
46
        {
47
            TotalMethodCount++;
×
48

49
            methodContext.Analyze();
×
50

51
            if (methodContext.ConvertedIsil.Count == 0)
×
52
                methodDefinition.ReplaceMethodBodyWithMinimalImplementation();
×
53
            else
54
                IlGenerator.GenerateIl(methodContext, methodDefinition);
×
55

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

58
            SuccessfulMethodCount++;
×
59
        }
×
60
        catch (Exception e)
×
61
        {
62
            // Known analysis limitations (DecompilerException) get a one-line warning; anything
63
            // else is an unexpected bug and keeps its (collapsed) stack trace.
64
            var detail = e is DecompilerException ? e.Message : e.ToCollapsedString();
×
65

66
            if (e is DecompilerException)
×
67
                Logger.WarnNewline($"Skipping {methodContext.FullName}: {e.Message}");
×
68
            else
69
                Logger.ErrorNewline($"Decompiling {methodContext.FullName} failed: {detail}");
×
70
            
NEW
71
            methodDefinition.CilMethodBody = new();
×
NEW
72
            instructions = methodDefinition.CilMethodBody.Instructions;
×
73

UNCOV
74
            var factory = module.CorLibTypeFactory;
×
75
            var exceptionCtor = factory.CorLibScope
×
76
                .CreateTypeReference("System", "Exception")
×
77
                .CreateMemberReference(".ctor", MethodSignature.CreateInstance(factory.Void, [factory.String]))
×
78
                .ImportWith(importer);
×
79

80
            instructions.Add(CilOpCodes.Ldstr, detail);
×
81
            instructions.Add(CilOpCodes.Newobj, exceptionCtor);
×
82
            instructions.Add(CilOpCodes.Throw);
×
83
        }
×
84

85
        methodContext.ReleaseAnalysisData();
×
86
    }
×
87

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

92
        var sb = new StringBuilder();
×
93
        var edges = new List<(int, int)>();
×
94

95
        sb.AppendLine("digraph ControlFlowGraph {");
×
96
        sb.AppendLine("    \"label\"=\"Control flow graph\"");
×
97

98
        // no instructions
99
        graph ??= new ISILControlFlowGraph([]);
×
100

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

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

127
            edges.AddRange(block.Successors.Select(b => (block.ID, b.ID)));
×
128
        }
129

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

133
        sb.AppendLine("}");
×
134

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

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

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

150
        var directory = Path.GetDirectoryName(path)!;
×
151
        if (!Directory.Exists(directory))
×
152
            Directory.CreateDirectory(directory);
×
153

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

© 2026 Coveralls, Inc