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

SamboyCoding / Cpp2IL / 19646943404

24 Nov 2025 07:38PM UTC coverage: 30.3% (-4.0%) from 34.31%
19646943404

Pull #481

github

web-flow
Merge 07574344a into e66a74bb3
Pull Request #481: Decompiler

1806 of 7575 branches covered (23.84%)

Branch coverage included in aggregate %.

100 of 1854 new or added lines in 29 files covered. (5.39%)

41 existing lines in 6 files now uncovered.

4084 of 11864 relevant lines covered (34.42%)

165379.78 hits per line

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

0.0
/Cpp2IL.Core/Analysis/MetadataResolver.cs
1
using System.Linq;
2
using Cpp2IL.Core.Extensions;
3
using Cpp2IL.Core.Graphs;
4
using Cpp2IL.Core.Il2CppApiFunctions;
5
using Cpp2IL.Core.ISIL;
6
using Cpp2IL.Core.Model.Contexts;
7
using Cpp2IL.Core.Utils;
8
using LibCpp2IL;
9

10
namespace Cpp2IL.Core.Analysis;
11

12
public static class MetadataResolver
13
{
14
    public static void ResolveAll(MethodAnalysisContext method)
15
    {
NEW
16
        ResolveCalls(method);
×
NEW
17
        ResolveFieldOffsets(method);
×
NEW
18
        ResolveGetter(method);
×
NEW
19
        ResolveStrings(method);
×
NEW
20
    }
×
21

22
    private static void ResolveStrings(MethodAnalysisContext method)
23
    {
NEW
24
        foreach (var instruction in method.ControlFlowGraph!.Instructions)
×
25
        {
NEW
26
            if (instruction.OpCode != OpCode.Move)
×
27
                continue;
28

NEW
29
            if ((instruction.Operands[0] is not LocalVariable) || (instruction.Operands[1] is not MemoryOperand memory))
×
30
                continue;
31

NEW
32
            if (memory.Base == null && memory.Index == null && memory.Scale == 0)
×
33
            {
NEW
34
                var stringLiteral = LibCpp2IlMain.GetLiteralByAddress((ulong)memory.Addend);
×
35

NEW
36
                if (stringLiteral == null)
×
37
                {
38
                    // Try instead check if its type metadata usage
NEW
39
                    var metadataUsage = LibCpp2IlMain.GetTypeGlobalByAddress((ulong)memory.Addend);
×
NEW
40
                    if (metadataUsage != null && method.DeclaringType is not null)
×
41
                    {
NEW
42
                        var typeAnalysisContext = metadataUsage.ToContext(method.DeclaringType!.DeclaringAssembly);
×
NEW
43
                        if (typeAnalysisContext != null)
×
NEW
44
                            instruction.Operands[1] = typeAnalysisContext;
×
45
                    }
46

NEW
47
                    continue;
×
48
                }
49

NEW
50
                instruction.Operands[1] = stringLiteral;
×
51
            }
52
        }
NEW
53
    }
×
54

55
    private static void ResolveFieldOffsets(MethodAnalysisContext method)
56
    {
NEW
57
        foreach (var instruction in method.ControlFlowGraph!.Instructions)
×
58
        {
NEW
59
            for (var i = 0; i < instruction.Operands.Count; i++)
×
60
            {
NEW
61
                var operand = instruction.Operands[i];
×
62

NEW
63
                if (operand is not MemoryOperand memory)
×
64
                    continue;
65

66
                // Has to be [base (local) + addend (field offset)]
NEW
67
                if (memory.Index != null || memory.Scale != 0)
×
68
                    continue;
69

NEW
70
                if (memory.Base is not LocalVariable local || local?.Type == null)
×
71
                    continue;
72

NEW
73
                var field = local.Type.Fields.FirstOrDefault(f => f.BackingData?.FieldOffset == memory.Addend);
×
74

NEW
75
                if (field == null) // TODO: Support nested fields (Field1.Field2.Field3)
×
76
                    continue;
77

NEW
78
                instruction.Operands[i] = new FieldReference(field, local, (int)memory.Addend);
×
79
            }
80
        }
NEW
81
    }
×
82

83
    private static void ResolveCalls(MethodAnalysisContext method)
84
    {
NEW
85
        foreach (var block in method.ControlFlowGraph!.Blocks)
×
86
        {
NEW
87
            if (block.BlockType != BlockType.Call && block.BlockType != BlockType.TailCall)
×
88
                continue;
89

NEW
90
            var callInstruction = block.Instructions[^1];
×
NEW
91
            var dest = callInstruction.Operands[0];
×
92

NEW
93
            if (!dest.IsNumeric())
×
94
                continue;
95

NEW
96
            var target = (ulong)dest;
×
97

NEW
98
            var keyFunctionAddresses = method.AppContext.GetOrCreateKeyFunctionAddresses();
×
99

NEW
100
            if (keyFunctionAddresses.IsKeyFunctionAddress(target))
×
101
            {
NEW
102
                HandleKeyFunction(method.AppContext, callInstruction, target, keyFunctionAddresses);
×
NEW
103
                continue;
×
104
            }
105

106
            //Non-key function call. Try to find a single match
NEW
107
            if (!method.AppContext.MethodsByAddress.TryGetValue(target, out var targetMethods))
×
108
                continue;
109

NEW
110
            if (targetMethods is not [{ } singleTargetMethod])
×
111
                continue;
112

NEW
113
            callInstruction.Operands[0] = singleTargetMethod;
×
114
        }
115

NEW
116
        method.ControlFlowGraph.MergeCallBlocks();
×
NEW
117
    }
×
118

119
    private static void HandleKeyFunction(ApplicationAnalysisContext appContext, Instruction instruction, ulong target, BaseKeyFunctionAddresses kFA)
120
    {
NEW
121
        var method = "";
×
NEW
122
        if (target == kFA.il2cpp_codegen_initialize_method || target == kFA.il2cpp_codegen_initialize_runtime_metadata)
×
123
        {
NEW
124
            if (appContext.MetadataVersion < 27)
×
125
            {
NEW
126
                method = nameof(kFA.il2cpp_codegen_initialize_method);
×
127
            }
128
            else
129
            {
NEW
130
                method = nameof(kFA.il2cpp_codegen_initialize_runtime_metadata);
×
131
            }
132
        }
133
        else
134
        {
NEW
135
            var pairs = kFA.Pairs.ToList();
×
NEW
136
            var key = pairs.FirstOrDefault(pair => pair.Value == target).Key;
×
NEW
137
            if (key == null)
×
NEW
138
                return;
×
NEW
139
            method = key;
×
140
        }
141

NEW
142
        if (method != "")
×
143
        {
NEW
144
            instruction.Operands[0] = method;
×
145
        }
NEW
146
    }
×
147

148
    // Because of il2cpp fields (like cctor_finished_or_no_cctor) [local @ reg+offset] sometimes can't be resolved, but this works for now
149
    private static void ResolveGetter(MethodAnalysisContext method)
150
    {
NEW
151
        if (!method.Name.StartsWith("get_"))
×
NEW
152
            return;
×
153

154
        // Default get: Return [this @ reg+offset]
NEW
155
        var instructions = method.ControlFlowGraph!.Instructions;
×
NEW
156
        if (instructions.Count == 1)
×
157
        {
NEW
158
            var instr = instructions[0];
×
159

NEW
160
            if (instr.OpCode != OpCode.Return
×
NEW
161
                || instr.Operands.Count < 1
×
NEW
162
                || instr.Operands[0] is not MemoryOperand memory
×
NEW
163
                || memory.Index != null || memory.Scale != 0
×
NEW
164
                || memory.Base is not LocalVariable local)
×
NEW
165
                return;
×
166

NEW
167
            var fieldName = $"<{method.Name[4..]}>k__BackingField";
×
168

NEW
169
            var field = method.DeclaringType!.Fields.Find(f => f.Name == fieldName);
×
NEW
170
            if (field == null)
×
NEW
171
                return;
×
172

NEW
173
            instr.Operands[0] = new FieldReference(field, local, (int)memory.Addend);
×
174
        }
NEW
175
    }
×
176
}
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