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

SamboyCoding / Cpp2IL / 15032750078

14 May 2025 11:00PM UTC coverage: 34.393% (-0.4%) from 34.826%
15032750078

Pull #451

github

web-flow
Merge d7a22ee91 into e93c0fecc
Pull Request #451: Support injecting anything

1786 of 6584 branches covered (27.13%)

Branch coverage included in aggregate %.

140 of 187 new or added lines in 27 files covered. (74.87%)

53 existing lines in 2 files now uncovered.

4167 of 10725 relevant lines covered (38.85%)

189623.56 hits per line

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

75.4
/Cpp2IL.Core/Model/Contexts/ApplicationAnalysisContext.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Diagnostics;
4
using System.Linq;
5
using AssetRipper.Primitives;
6
using Cpp2IL.Core.Api;
7
using Cpp2IL.Core.Exceptions;
8
using Cpp2IL.Core.Il2CppApiFunctions;
9
using Cpp2IL.Core.Logging;
10
using Cpp2IL.Core.Utils;
11
using LibCpp2IL;
12
using LibCpp2IL.Metadata;
13

14
namespace Cpp2IL.Core.Model.Contexts;
15

16
/// <summary>
17
/// Top-level class to represent an individual il2cpp application that has been loaded into cpp2il.
18
/// </summary>
19
public class ApplicationAnalysisContext : ContextWithDataStorage
20
{
21
    /// <summary>
22
    /// The IL2CPP binary file this application was loaded from
23
    /// </summary>
24
    public Il2CppBinary Binary;
25

26
    /// <summary>
27
    /// The IL2CPP global-metadata file this application was loaded from.
28
    /// </summary>
29
    public Il2CppMetadata Metadata;
30

31
    /// <summary>
32
    /// The version of the IL2CPP metadata file this application was loaded from.
33
    /// </summary>
34
    public float MetadataVersion => Metadata.MetadataVersion;
1,400,319✔
35
    
36
    /// <summary>
37
    /// The Unity version this application was compiled with.
38
    /// </summary>
39
    public UnityVersion UnityVersion => Metadata.UnityVersion;
×
40

41
    /// <summary>
42
    /// The instruction set helper class associated with the instruction set that this application was compiled with.
43
    /// </summary>
44
    public Cpp2IlInstructionSet InstructionSet;
45

46
    /// <summary>
47
    /// Contains references to some commonly-used System types.
48
    /// </summary>
49
    public SystemTypesContext SystemTypes;
50

51
    /// <summary>
52
    /// All the managed assemblies contained within the metadata file.
53
    /// </summary>
54
    public readonly List<AssemblyAnalysisContext> Assemblies = [];
27✔
55

56
    /// <summary>
57
    /// A dictionary of all the managed assemblies, by their name.
58
    /// </summary>
59
    public readonly Dictionary<string, AssemblyAnalysisContext> AssembliesByName = new();
27✔
60

61
    /// <summary>
62
    /// A dictionary of method pointers to the corresponding method, which may or may not be generic.
63
    /// </summary>
64
    public readonly Dictionary<ulong, List<MethodAnalysisContext>> MethodsByAddress = new();
27✔
65

66
    /// <summary>
67
    /// A dictionary of all the generic method variants to their corresponding analysis contexts.
68
    /// </summary>
69
    public readonly Dictionary<Cpp2IlMethodRef, ConcreteGenericMethodAnalysisContext> ConcreteGenericMethodsByRef = new();
27✔
70

71
    /// <summary>
72
    /// Key Function Addresses for the binary file. Populated on-demand
73
    /// </summary>
74
    private BaseKeyFunctionAddresses? _keyFunctionAddresses;
75

76
    /// <summary>
77
    /// True if this ApplicationAnalysisContext has finished initialization of all of its child contexts, else false.
78
    /// </summary>
79
    public bool HasFinishedInitializing { get; private set; }
27✔
80

81
    public ApplicationAnalysisContext(Il2CppBinary binary, Il2CppMetadata metadata)
27✔
82
    {
83
        Binary = binary;
27✔
84
        Metadata = metadata;
27✔
85

86
        try
87
        {
88
            InstructionSet = InstructionSetRegistry.GetInstructionSet(binary.InstructionSetId);
27✔
89
        }
27✔
90
        catch (Exception)
×
91
        {
92
            throw new InstructionSetHandlerNotRegisteredException(binary.InstructionSetId);
×
93
        }
94

95
        Logger.VerboseNewline("\tUsing instruction set handler: " + InstructionSet.GetType().FullName);
27✔
96

97
        foreach (var assemblyDefinition in Metadata.AssemblyDefinitions)
2,250✔
98
        {
99
            Logger.VerboseNewline($"\tProcessing assembly: {assemblyDefinition.AssemblyName.Name}...");
1,098✔
100
            var aac = new AssemblyAnalysisContext(assemblyDefinition, this);
1,098✔
101
            Assemblies.Add(aac);
1,098✔
102
            AssembliesByName[assemblyDefinition.AssemblyName.Name] = aac;
1,098✔
103
        }
104

105
        SystemTypes = new(this);
27✔
106
        
107
        MiscUtils.InitFunctionStarts(this);
27✔
108

109
        PopulateMethodsByAddressTable();
27✔
110

111
        HasFinishedInitializing = true;
27✔
112
    }
27✔
113

114
    /// <summary>
115
    /// Populates the <see cref="MethodsByAddress"/> dictionary with all the methods in the application, including concrete generic ones.
116
    /// </summary>
117
    private void PopulateMethodsByAddressTable()
118
    {
119
        Assemblies.SelectMany(a => a.Types).SelectMany(t => t.Methods).ToList().ForEach(m =>
77,379✔
120
        {
27✔
121
            m.EnsureRawBytes();
439,980✔
122
            var ptr = InstructionSet.GetPointerForMethod(m);
439,980✔
123

27✔
124
            if (!MethodsByAddress.ContainsKey(ptr))
439,980✔
125
                MethodsByAddress.Add(ptr, []);
350,547✔
126

27✔
127
            MethodsByAddress[ptr].Add(m);
439,980✔
128
        });
440,007✔
129

130
        Logger.VerboseNewline("\tProcessing concrete generic methods...");
27✔
131
        foreach (var methodRef in Binary.ConcreteGenericMethods.Values.SelectMany(v => v))
629,391✔
132
        {
133
#if !DEBUG
134
            try
135
            {
136
#endif
137
            var gm = new ConcreteGenericMethodAnalysisContext(methodRef, this);
298,308✔
138

139
            var ptr = InstructionSet.GetPointerForMethod(gm);
298,308✔
140

141
            if (!MethodsByAddress.ContainsKey(ptr))
298,308✔
142
                MethodsByAddress[ptr] = [];
99,918✔
143

144
            MethodsByAddress[ptr].Add(gm);
298,308✔
145
            ConcreteGenericMethodsByRef[methodRef] = gm;
298,308✔
146
#if !DEBUG
147
            }
298,308✔
148
            catch (Exception e)
×
149
            {
150
                throw new("Failed to process concrete generic method: " + methodRef, e);
×
151
            }
152
#endif
153
        }
154
    }
27✔
155

156
    /// <summary>
157
    /// Finds an assembly by its name and returns the analysis context for it.
158
    /// </summary>
159
    /// <param name="name">The name of the assembly (without any extension)</param>
160
    /// <returns>An assembly analysis context if one can be found which matches the given name, else null.</returns>
161
    public AssemblyAnalysisContext? GetAssemblyByName(string name)
162
    {
163
        if (name.Length >= 4 && name[^4] == '.' && name[^3] == 'd')
2,334,310✔
164
            //Trim .dll extension
165
            name = name[..^4];
2,318,593✔
166
        else if (name.Length >= 6 && name[^6] == '.' && name[^5] == 'w')
15,717!
167
            //Trim .winmd extension
168
            name = name[..^6];
×
169

170
        return AssembliesByName[name];
2,334,310✔
171
    }
172

173
    public TypeAnalysisContext? ResolveContextForType(Il2CppTypeDefinition? typeDefinition)
174
    {
175
        return typeDefinition is not null
2,035,969!
176
            ? GetAssemblyByName(typeDefinition.DeclaringAssembly!.Name!)?.GetTypeByDefinition(typeDefinition)
2,035,969✔
177
            : null;
2,035,969✔
178
    }
179

180
    public MethodAnalysisContext? ResolveContextForMethod(Il2CppMethodDefinition? methodDefinition)
181
    {
182
        return ResolveContextForType(methodDefinition?.DeclaringType)?.Methods.FirstOrDefault(m => m.Definition == methodDefinition);
6,595,268!
183
    }
184

185
    public FieldAnalysisContext? ResolveContextForField(Il2CppFieldDefinition? field)
186
    {
187
        return ResolveContextForType(field?.DeclaringType)?.Fields.FirstOrDefault(f => f.BackingData?.Field == field);
2!
188
    }
189

190
    public EventAnalysisContext? ResolveContextForEvent(Il2CppEventDefinition? eventDefinition)
191
    {
192
        return ResolveContextForType(eventDefinition?.DeclaringType)?.Events.FirstOrDefault(e => e.Definition == eventDefinition);
2!
193
    }
194

195
    public PropertyAnalysisContext? ResolveContextForProperty(Il2CppPropertyDefinition? propertyDefinition)
196
    {
197
        return ResolveContextForType(propertyDefinition?.DeclaringType)?.Properties.FirstOrDefault(p => p.Definition == propertyDefinition);
2!
198
    }
199

200
    public GenericParameterTypeAnalysisContext? ResolveContextForGenericParameter(Il2CppGenericParameter? genericParameter)
201
    {
202
        if (genericParameter is null)
404,404!
NEW
203
            return null;
×
204

205
        if (genericParameter.Owner.TypeOwner is { } typeOwner)
404,404✔
206
        {
207
            return ResolveContextForType(typeOwner)?.GenericParameters[genericParameter.Index];
310,081!
208
        }
209
        else
210
        {
211
            Debug.Assert(genericParameter.Owner.MethodOwner is not null);
212
            return ResolveContextForMethod(genericParameter.Owner.MethodOwner)?.GenericParameters[genericParameter.Index];
94,323!
213
        }
214
    }
215

216
    public BaseKeyFunctionAddresses GetOrCreateKeyFunctionAddresses()
217
    {
218
        lock (InstructionSet)
×
219
        {
220
            if (_keyFunctionAddresses == null)
×
221
                (_keyFunctionAddresses = InstructionSet.CreateKeyFunctionAddressesInstance()).Find(this);
×
222

223
            return _keyFunctionAddresses;
×
224
        }
225
    }
×
226

227
    public MultiAssemblyInjectedType InjectTypeIntoAllAssemblies(string ns, string name, TypeAnalysisContext? baseType)
228
    {
229
        var types = Assemblies.Select(a => (InjectedTypeAnalysisContext)a.InjectType(ns, name, baseType)).ToArray();
344✔
230

231
        return new(types);
8✔
232
    }
233

234
    public InjectedAssemblyAnalysisContext InjectAssembly(
235
        string name,
236
        Version? version = null,
237
        uint hashAlgorithm = 0,
238
        uint flags = 0,
239
        string? culture = null,
240
        byte[]? publicKeyToken = null,
241
        byte[]? publicKey = null)
242
    {
243
        var assembly = new InjectedAssemblyAnalysisContext(name, this, version, hashAlgorithm, flags, culture, publicKeyToken, publicKey);
1✔
244
        Assemblies.Add(assembly);
1✔
245
        AssembliesByName[name] = assembly;
1✔
246
        return assembly;
1✔
247
    }
248

249
    public IEnumerable<TypeAnalysisContext> AllTypes => Assemblies.SelectMany(a => a.Types);
280✔
250
}
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

© 2025 Coveralls, Inc