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

SamboyCoding / Cpp2IL / 15094463386

18 May 2025 09:18AM UTC coverage: 34.039% (-0.008%) from 34.047%
15094463386

Pull #460

github

web-flow
Merge 743db42b9 into cc6dfc6a8
Pull Request #460: Don't use assembly names for resolution

1771 of 6624 branches covered (26.74%)

Branch coverage included in aggregate %.

8 of 9 new or added lines in 2 files covered. (88.89%)

1 existing line in 1 file now uncovered.

4163 of 10809 relevant lines covered (38.51%)

182354.27 hits per line

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

72.39
/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
    private readonly Dictionary<Il2CppImageDefinition, AssemblyAnalysisContext> AssembliesByImageDefinition = new();
27✔
82

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

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

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

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

108
        SystemTypes = new(this);
27✔
109
        
110
        MiscUtils.InitFunctionStarts(this);
27✔
111

112
        PopulateMethodsByAddressTable();
27✔
113

114
        HasFinishedInitializing = true;
27✔
115
    }
27✔
116

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

27✔
127
            if (!MethodsByAddress.ContainsKey(ptr))
439,980✔
128
                MethodsByAddress.Add(ptr, []);
350,547✔
129

27✔
130
            MethodsByAddress[ptr].Add(m);
439,980✔
131
        });
440,007✔
132

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

142
            var ptr = InstructionSet.GetPointerForMethod(gm);
298,308✔
143

144
            if (!MethodsByAddress.ContainsKey(ptr))
298,308✔
145
                MethodsByAddress[ptr] = [];
99,918✔
146

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

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

173
        return AssembliesByName[name];
33✔
174
    }
175

176
    public AssemblyAnalysisContext? ResolveContextForAssembly(Il2CppImageDefinition? imageDefinition)
177
    {
178
        return imageDefinition is not null
298,308!
179
            ? AssembliesByImageDefinition[imageDefinition]
298,308✔
180
            : null;
298,308✔
181
    }
182

183
    public AssemblyAnalysisContext? ResolveContextForAssembly(Il2CppAssemblyDefinition? assemblyDefinition)
184
    {
NEW
185
        return ResolveContextForAssembly(assemblyDefinition?.Image);
×
186
    }
187

188
    public TypeAnalysisContext? ResolveContextForType(Il2CppTypeDefinition? typeDefinition)
189
    {
190
        return typeDefinition is not null
1,811,983!
191
            ? AssembliesByImageDefinition[typeDefinition.DeclaringAssembly!].GetTypeByDefinition(typeDefinition)
1,811,983✔
192
            : null;
1,811,983✔
193
    }
194

195
    public MethodAnalysisContext? ResolveContextForMethod(Il2CppMethodDefinition? methodDefinition)
196
    {
197
        return ResolveContextForType(methodDefinition?.DeclaringType)?.Methods.FirstOrDefault(m => m.Definition == methodDefinition);
3,854,271!
198
    }
199

200
    public FieldAnalysisContext? ResolveContextForField(Il2CppFieldDefinition? field)
201
    {
202
        return ResolveContextForType(field?.DeclaringType)?.Fields.FirstOrDefault(f => f.BackingData?.Field == field);
2!
203
    }
204

205
    public EventAnalysisContext? ResolveContextForEvent(Il2CppEventDefinition? eventDefinition)
206
    {
207
        return ResolveContextForType(eventDefinition?.DeclaringType)?.Events.FirstOrDefault(e => e.Definition == eventDefinition);
2!
208
    }
209

210
    public PropertyAnalysisContext? ResolveContextForProperty(Il2CppPropertyDefinition? propertyDefinition)
211
    {
212
        return ResolveContextForType(propertyDefinition?.DeclaringType)?.Properties.FirstOrDefault(p => p.Definition == propertyDefinition);
2!
213
    }
214

215
    public GenericParameterTypeAnalysisContext? ResolveContextForGenericParameter(Il2CppGenericParameter? genericParameter)
216
    {
217
        if (genericParameter is null)
263,078!
218
            return null;
×
219

220
        if (genericParameter.Owner.TypeOwner is { } typeOwner)
263,078✔
221
        {
222
            return ResolveContextForType(typeOwner)?.GenericParameters[genericParameter.genericParameterIndexInOwner];
207,666!
223
        }
224
        else
225
        {
226
            Debug.Assert(genericParameter.Owner.MethodOwner is not null);
227
            return ResolveContextForMethod(genericParameter.Owner.MethodOwner)?.GenericParameters[genericParameter.genericParameterIndexInOwner];
55,412!
228
        }
229
    }
230

231
    public BaseKeyFunctionAddresses GetOrCreateKeyFunctionAddresses()
232
    {
233
        lock (InstructionSet)
×
234
        {
235
            if (_keyFunctionAddresses == null)
×
236
                (_keyFunctionAddresses = InstructionSet.CreateKeyFunctionAddressesInstance()).Find(this);
×
237

238
            return _keyFunctionAddresses;
×
239
        }
240
    }
×
241

242
    public MultiAssemblyInjectedType InjectTypeIntoAllAssemblies(string ns, string name, TypeAnalysisContext? baseType)
243
    {
244
        var types = Assemblies.Select(a => (InjectedTypeAnalysisContext)a.InjectType(ns, name, baseType)).ToArray();
344✔
245

246
        return new(types);
8✔
247
    }
248

249
    public InjectedAssemblyAnalysisContext InjectAssembly(
250
        string name,
251
        Version? version = null,
252
        uint hashAlgorithm = 0,
253
        uint flags = 0,
254
        string? culture = null,
255
        byte[]? publicKeyToken = null,
256
        byte[]? publicKey = null)
257
    {
258
        var assembly = new InjectedAssemblyAnalysisContext(name, this, version, hashAlgorithm, flags, culture, publicKeyToken, publicKey);
1✔
259
        Assemblies.Add(assembly);
1✔
260
        AssembliesByName.Add(name, assembly);
1✔
261
        return assembly;
1✔
262
    }
263

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