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

SamboyCoding / Cpp2IL / 12074790339

28 Nov 2024 07:54PM UTC coverage: 28.371% (-0.02%) from 28.392%
12074790339

push

github

web-flow
Add a plugin for outputting Windows PDB files (#382)

1265 of 6204 branches covered (20.39%)

Branch coverage included in aggregate %.

2 of 53 new or added lines in 7 files covered. (3.77%)

3 existing lines in 3 files now uncovered.

3383 of 10179 relevant lines covered (33.24%)

126063.94 hits per line

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

36.71
/Cpp2IL.Core/Model/Contexts/MethodAnalysisContext.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Diagnostics.CodeAnalysis;
4
using System.Reflection;
5
using Cpp2IL.Core.Graphs;
6
using Cpp2IL.Core.ISIL;
7
using Cpp2IL.Core.Graphs.Processors;
8
using Cpp2IL.Core.Logging;
9
using Cpp2IL.Core.Utils;
10
using LibCpp2IL;
11
using LibCpp2IL.Metadata;
12
using StableNameDotNet.Providers;
13
using System.Linq;
14

15
namespace Cpp2IL.Core.Model.Contexts;
16

17
/// <summary>
18
/// Represents one method within the application. Can be analyzed to attempt to reconstruct the function body.
19
/// </summary>
20
public class MethodAnalysisContext : HasCustomAttributesAndName, IMethodInfoProvider
21
{
22
    /// <summary>
23
    /// The underlying metadata for the method.
24
    ///
25
    /// Nullable iff this is a subclass.
26
    /// </summary>
27
    public readonly Il2CppMethodDefinition? Definition;
28

29
    /// <summary>
30
    /// The analysis context for the declaring type of this method.
31
    /// </summary>
32
    public readonly TypeAnalysisContext? DeclaringType;
33

34
    /// <summary>
35
    /// The address of this method as defined in the underlying metadata.
36
    /// </summary>
37
    public virtual ulong UnderlyingPointer => Definition?.MethodPointer ?? throw new("Subclasses of MethodAnalysisContext should override UnderlyingPointer");
488,988!
38

39
    public ulong Rva => UnderlyingPointer == 0 || LibCpp2IlMain.Binary == null ? 0 : LibCpp2IlMain.Binary.GetRva(UnderlyingPointer);
×
40

41
    /// <summary>
42
    /// The raw method body as machine code in the active instruction set.
43
    /// </summary>
44
    public Memory<byte> RawBytes => rawMethodBody ??= InitRawBytes();
42,600!
45

46
    /// <summary>
47
    /// The first-stage-analyzed Instruction-Set-Independent Language Instructions.
48
    /// </summary>
49
    public List<InstructionSetIndependentInstruction>? ConvertedIsil;
50

51
    /// <summary>
52
    /// The control flow graph for this method, if one is built.
53
    /// </summary>
54
    public ISILControlFlowGraph? ControlFlowGraph;
55

56
    public List<ParameterAnalysisContext> Parameters = [];
436,626✔
57

58
    /// <summary>
59
    /// Does this method return void?
60
    /// </summary>
61
    public virtual bool IsVoid => (Definition?.ReturnType?.ToString() ?? throw new("Subclasses of MethodAnalysisContext should override IsVoid")) == "System.Void";
×
62

63
    public virtual bool IsStatic => Definition?.IsStatic ?? throw new("Subclasses of MethodAnalysisContext should override IsStatic");
×
64

65
    protected override int CustomAttributeIndex => Definition?.customAttributeIndex ?? throw new("Subclasses of MethodAnalysisContext should override CustomAttributeIndex if they have custom attributes");
174,060!
66

67
    public override AssemblyAnalysisContext CustomAttributeAssembly => DeclaringType?.DeclaringAssembly ?? throw new("Subclasses of MethodAnalysisContext should override CustomAttributeAssembly if they have custom attributes");
322,971!
68

69
    public override string DefaultName => Definition?.Name ?? throw new("Subclasses of MethodAnalysisContext should override DefaultName");
22!
70

71
    public string FullName => DeclaringType == null ? Name : $"{DeclaringType.FullName}::{Name}";
22!
72

NEW
73
    public string FullNameWithSignature => $"{ReturnTypeContext.FullName} {FullName}({string.Join(", ", Parameters.Select(p => p.HumanReadableSignature))})";
×
74

UNCOV
75
    public virtual MethodAttributes Attributes => Definition?.Attributes ?? throw new("Subclasses of MethodAnalysisContext should override Attributes");
×
76

77
    public TypeAnalysisContext? InjectedReturnType { get; set; }
290,901✔
78

79
    public int ParameterCount => Parameters.Count;
×
80

81
    //TODO Support custom attributes on return types (v31 feature)
82
    public TypeAnalysisContext ReturnTypeContext => InjectedReturnType ?? DeclaringType!.DeclaringAssembly.ResolveIl2CppType(Definition!.RawReturnType!);
145,389✔
83
    
84
    protected Memory<byte>? rawMethodBody;
85

86

87
    private static readonly List<IBlockProcessor> blockProcessors =
×
88
    [
×
89
        new MetadataProcessor(),
×
90
        new CallProcessor()
×
91
    ];
×
92

93
    public MethodAnalysisContext(Il2CppMethodDefinition? definition, TypeAnalysisContext parent) : base(definition?.token ?? 0, parent.AppContext)
394,026✔
94
    {
95
        DeclaringType = parent;
394,026✔
96
        Definition = definition;
394,026✔
97

98
        if (Definition != null)
394,026✔
99
        {
100
            InitCustomAttributeData();
248,514✔
101

102
            for (var i = 0; i < Definition.InternalParameterData!.Length; i++)
1,075,284✔
103
            {
104
                var parameterDefinition = Definition.InternalParameterData![i];
289,128✔
105
                Parameters.Add(new(parameterDefinition, i, this));
289,128✔
106
            }
107
        }
108
        else
109
            rawMethodBody = Array.Empty<byte>();
145,512✔
110
    }
145,512✔
111

112
    [MemberNotNull(nameof(rawMethodBody))]
113
    public void EnsureRawBytes()
114
    {
115
        rawMethodBody ??= InitRawBytes();
248,514✔
116
    }
248,514✔
117

118
    private Memory<byte> InitRawBytes()
119
    {
120
        //Some abstract methods (on interfaces, no less) apparently have a body? Unity doesn't support default interface methods so idk what's going on here.
121
        //E.g. UnityEngine.Purchasing.AppleCore.dll: UnityEngine.Purchasing.INativeAppleStore::SetUnityPurchasingCallback on among us (itch.io build)
122
        if (Definition != null && Definition.MethodPointer != 0 && !Definition.Attributes.HasFlag(MethodAttributes.Abstract))
248,514✔
123
        {
124
            var ret = AppContext.InstructionSet.GetRawBytesForMethod(this, false);
240,474✔
125

126
            if (ret.Length == 0)
240,474✔
127
            {
128
                Logger.VerboseNewline("\t\t\tUnexpectedly got 0-byte method body for " + this + $". Pointer was 0x{Definition.MethodPointer:X}", "MAC");
22!
129
            }
130

131
            return ret;
240,474✔
132
        }
133
        else
134
            return Array.Empty<byte>();
8,040✔
135
    }
136

137
    protected MethodAnalysisContext(ApplicationAnalysisContext context) : base(0, context)
42,600✔
138
    {
139
        rawMethodBody = Array.Empty<byte>();
42,600✔
140
    }
42,600✔
141

142
    [MemberNotNull(nameof(ConvertedIsil))]
143
    public void Analyze()
144
    {
145
        if (ConvertedIsil != null)
×
146
            return;
×
147

148
        if (UnderlyingPointer == 0)
×
149
        {
150
            ConvertedIsil = [];
×
151
            return;
×
152
        }
153

154
        ConvertedIsil = AppContext.InstructionSet.GetIsilFromMethod(this);
×
155

156
        if (ConvertedIsil.Count == 0)
×
157
            return; //Nothing to do, empty function
×
158

159
        ControlFlowGraph = new ISILControlFlowGraph();
×
160
        ControlFlowGraph.Build(ConvertedIsil);
×
161

162
        // Post step to convert metadata usage. Ldstr Opcodes etc.
163
        foreach (var block in ControlFlowGraph.Blocks)
×
164
        {
165
            foreach (var converter in blockProcessors)
×
166
            {
167
                converter.Process(this, block);
×
168
            }
169
        }
170
    }
×
171

172
    public void ReleaseAnalysisData()
173
    {
174
        ConvertedIsil = null;
×
175
        ControlFlowGraph = null;
×
176
    }
×
177

178
    public override string ToString() => $"Method: {FullName}";
22✔
179

180
    #region StableNameDot implementation
181

182
    ITypeInfoProvider IMethodInfoProvider.ReturnType =>
183
        Definition!.RawReturnType!.ThisOrElementIsGenericParam()
×
184
            ? new GenericParameterTypeInfoProviderWrapper(Definition.RawReturnType!.GetGenericParamName())
×
185
            : TypeAnalysisContext.GetSndnProviderForType(AppContext, Definition!.RawReturnType);
×
186

187
    IEnumerable<IParameterInfoProvider> IMethodInfoProvider.ParameterInfoProviders => Parameters;
×
188

189
    string IMethodInfoProvider.MethodName => Name;
×
190

191
    MethodAttributes IMethodInfoProvider.MethodAttributes => Attributes;
×
192

193
    MethodSemantics IMethodInfoProvider.MethodSemantics
194
    {
195
        get
196
        {
197
            if (DeclaringType != null)
×
198
            {
199
                //This one is a bit trickier, as il2cpp doesn't use semantics.
200
                foreach (var prop in DeclaringType.Properties)
×
201
                {
202
                    if (prop.Getter == this)
×
203
                        return MethodSemantics.Getter;
×
204
                    if (prop.Setter == this)
×
205
                        return MethodSemantics.Setter;
×
206
                }
207

208
                foreach (var evt in DeclaringType.Events)
×
209
                {
210
                    if (evt.Adder == this)
×
211
                        return MethodSemantics.AddOn;
×
212
                    if (evt.Remover == this)
×
213
                        return MethodSemantics.RemoveOn;
×
214
                    if (evt.Invoker == this)
×
215
                        return MethodSemantics.Fire;
×
216
                }
217
            }
218

219
            return 0;
×
220
        }
×
221
    }
222

223
    #endregion
224
}
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