Unity/C++: Significant re-factoring of Unity header management (see description)
Extract resource handling to UnityResource Add API header resource helpers Fix UnityVersion ToString() when Min == Max Replace fixed list of Il2Cpp header reserved names with parsed names from actual selected headers (solves TypeInfo/MemberInfo problems in 5.3.0-5.3.4 (metadata v16-20)) Use CppDeclarationGenerator when initializing CppTypeCollection to ensure all Il2Cpp header symbols are reserved Process API headers in CppTypeCollection.FromUnityHeaders Move #define IS_32BIT handling to UnityHeaders Update tests
This commit is contained in:
@@ -16,13 +16,16 @@ using Il2CppInspector.Reflection;
|
|||||||
namespace Il2CppInspector.Cpp
|
namespace Il2CppInspector.Cpp
|
||||||
{
|
{
|
||||||
// Class for generating C header declarations from Reflection objects (TypeInfo, etc.)
|
// Class for generating C header declarations from Reflection objects (TypeInfo, etc.)
|
||||||
internal class CppDeclarationGenerator
|
public class CppDeclarationGenerator
|
||||||
{
|
{
|
||||||
private readonly AppModel appModel;
|
private readonly AppModel appModel;
|
||||||
|
|
||||||
private TypeModel model => appModel.ILModel;
|
private TypeModel model => appModel.ILModel;
|
||||||
private CppTypeCollection types => appModel.CppTypeCollection;
|
private CppTypeCollection types => appModel.CppTypeCollection;
|
||||||
|
|
||||||
|
// Word size (32/64-bit) for this generator
|
||||||
|
public int WordSize => appModel.WordSize;
|
||||||
|
|
||||||
// Version number and header file to generate structures for
|
// Version number and header file to generate structures for
|
||||||
public UnityVersion UnityVersion => appModel.UnityVersion;
|
public UnityVersion UnityVersion => appModel.UnityVersion;
|
||||||
|
|
||||||
@@ -63,7 +66,7 @@ namespace Il2CppInspector.Cpp
|
|||||||
public CppType AsCType(TypeInfo ti) {
|
public CppType AsCType(TypeInfo ti) {
|
||||||
// IsArray case handled by TypeNamer.GetName
|
// IsArray case handled by TypeNamer.GetName
|
||||||
if (ti.IsByRef || ti.IsPointer) {
|
if (ti.IsByRef || ti.IsPointer) {
|
||||||
return AsCType(ti.ElementType).AsPointer(types.WordSize);
|
return AsCType(ti.ElementType).AsPointer(WordSize);
|
||||||
}
|
}
|
||||||
if (ti.IsValueType) {
|
if (ti.IsValueType) {
|
||||||
if (ti.IsPrimitive && primitiveTypeMap.ContainsKey(ti.Name)) {
|
if (ti.IsPrimitive && primitiveTypeMap.ContainsKey(ti.Name)) {
|
||||||
@@ -513,16 +516,10 @@ namespace Il2CppInspector.Cpp
|
|||||||
// You can customize how naming works by modifying this function.
|
// You can customize how naming works by modifying this function.
|
||||||
private void InitializeNaming() {
|
private void InitializeNaming() {
|
||||||
TypeNamespace = CreateNamespace();
|
TypeNamespace = CreateNamespace();
|
||||||
// Type names that may appear in the header
|
|
||||||
foreach (var typeName in new [] { "CustomAttributesCache", "CustomAttributeTypeCache", "EventInfo", "FieldInfo", "Hash16", "MemberInfo", "MethodInfo", "MethodVariableKind", "MonitorData", "ParameterInfo", "PInvokeArguments", "PropertyInfo", "SequencePointKind", "StackFrameType", "VirtualInvokeData" }) {
|
|
||||||
TypeNamespace.ReserveName(typeName);
|
|
||||||
}
|
|
||||||
TypeNamer = TypeNamespace.MakeNamer<TypeInfo>((ti) => {
|
TypeNamer = TypeNamespace.MakeNamer<TypeInfo>((ti) => {
|
||||||
if (ti.IsArray)
|
if (ti.IsArray)
|
||||||
return TypeNamer.GetName(ti.ElementType) + "__Array";
|
return TypeNamer.GetName(ti.ElementType) + "__Array";
|
||||||
var name = ti.Name.ToCIdentifier();
|
var name = ti.Name.ToCIdentifier();
|
||||||
if (name.StartsWith("Il2Cpp"))
|
|
||||||
name = "_" + name;
|
|
||||||
name = Regex.Replace(name, "__+", "_");
|
name = Regex.Replace(name, "__+", "_");
|
||||||
// Work around a dumb IDA bug: enums can't be named the same as certain "built-in" types
|
// Work around a dumb IDA bug: enums can't be named the same as certain "built-in" types
|
||||||
// like KeyCode, Position, ErrorType. This only applies to enums, not structs.
|
// like KeyCode, Position, ErrorType. This only applies to enums, not structs.
|
||||||
|
|||||||
@@ -535,6 +535,9 @@ namespace Il2CppInspector.Cpp
|
|||||||
// Get all of the types in a logical group
|
// Get all of the types in a logical group
|
||||||
public IEnumerable<CppType> GetTypeGroup(string groupName) => Types.Values.Where(t => t.Group == groupName);
|
public IEnumerable<CppType> GetTypeGroup(string groupName) => Types.Values.Where(t => t.Group == groupName);
|
||||||
|
|
||||||
|
// Get all of the typedefs in a logical group
|
||||||
|
public IEnumerable<CppType> GetTypedefGroup(string groupName) => TypedefAliases.Values.Where(t => t.Group == groupName);
|
||||||
|
|
||||||
// Add a type
|
// Add a type
|
||||||
private void Add(CppType type) {
|
private void Add(CppType type) {
|
||||||
type.Group = currentGroup;
|
type.Group = currentGroup;
|
||||||
@@ -578,22 +581,45 @@ namespace Il2CppInspector.Cpp
|
|||||||
public CppEnumType NewDefaultEnum(string name = "") => Enum(Types["int"], name);
|
public CppEnumType NewDefaultEnum(string name = "") => Enum(Types["int"], name);
|
||||||
|
|
||||||
// Generate a populated CppTypeCollection object from a set of Unity headers
|
// Generate a populated CppTypeCollection object from a set of Unity headers
|
||||||
public static CppTypeCollection FromUnityVersion(UnityVersion version, int wordSize = 32)
|
// The CppDeclarationGenerator is used to ensure that the Unity header type names are not used again afterwards
|
||||||
=> FromUnityHeaders(UnityHeader.GetHeaderForVersion(version), wordSize);
|
// Omit this parameter only when fetching headers for inspection without a model
|
||||||
|
public static CppTypeCollection FromUnityVersion(UnityVersion version, CppDeclarationGenerator declGen = null)
|
||||||
|
=> FromUnityHeaders(UnityHeaders.UnityHeaders.GetHeadersForVersion(version), declGen);
|
||||||
|
|
||||||
public static CppTypeCollection FromUnityHeaders(UnityHeader header, int wordSize = 32) {
|
public static CppTypeCollection FromUnityHeaders(UnityHeaders.UnityHeaders header, CppDeclarationGenerator declGen = null) {
|
||||||
|
var wordSize = declGen?.WordSize ?? 64;
|
||||||
var cppTypes = new CppTypeCollection(wordSize);
|
var cppTypes = new CppTypeCollection(wordSize);
|
||||||
|
|
||||||
|
// Process Unity headers
|
||||||
cppTypes.SetGroup("il2cpp");
|
cppTypes.SetGroup("il2cpp");
|
||||||
|
|
||||||
// Add junk from config files we haven't included
|
// Add junk from config files we haven't included
|
||||||
cppTypes.TypedefAliases.Add("Il2CppIManagedObjectHolder", cppTypes["void"].AsPointer(wordSize));
|
cppTypes.TypedefAliases.Add("Il2CppIManagedObjectHolder", cppTypes["void"].AsPointer(wordSize));
|
||||||
cppTypes.TypedefAliases.Add("Il2CppIUnknown", cppTypes["void"].AsPointer(wordSize));
|
cppTypes.TypedefAliases.Add("Il2CppIUnknown", cppTypes["void"].AsPointer(wordSize));
|
||||||
|
|
||||||
// Process Unity headers
|
var headers = header.GetTypeHeaderText(wordSize);
|
||||||
var headers = header.GetHeaderText();
|
|
||||||
cppTypes.AddFromDeclarationText(headers);
|
cppTypes.AddFromDeclarationText(headers);
|
||||||
|
|
||||||
|
// Don't allow any of the header type names to be re-used; ignore primitive types
|
||||||
|
foreach (var type in cppTypes.GetTypeGroup("il2cpp"))
|
||||||
|
declGen?.TypeNamespace.ReserveName(type.Name);
|
||||||
|
|
||||||
|
foreach (var typedef in cppTypes.GetTypedefGroup("il2cpp"))
|
||||||
|
declGen?.GlobalsNamespace.ReserveName(typedef.Name);
|
||||||
|
|
||||||
|
cppTypes.SetGroup("il2cpp-api");
|
||||||
|
|
||||||
|
var apis = header.GetAPIHeaderTypedefText();
|
||||||
|
cppTypes.AddFromDeclarationText(apis);
|
||||||
|
|
||||||
|
foreach (var type in cppTypes.GetTypeGroup("il2cpp-api"))
|
||||||
|
declGen?.TypeNamespace.ReserveName(type.Name);
|
||||||
|
|
||||||
|
foreach (var typedef in cppTypes.GetTypedefGroup("il2cpp-api"))
|
||||||
|
declGen?.GlobalsNamespace.ReserveName(typedef.Name);
|
||||||
|
|
||||||
|
cppTypes.SetGroup("");
|
||||||
|
|
||||||
return cppTypes;
|
return cppTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2017-2020 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
|
|
||||||
Copyright 2020 Robert Xiao - https://robertxiao.ca
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System.Reflection;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
|
|
||||||
namespace Il2CppInspector.Cpp.UnityHeaders
|
|
||||||
{
|
|
||||||
// Each instance of UnityHeader represents one header file which potentially covers multiple versions of Unity.
|
|
||||||
public class UnityHeader
|
|
||||||
{
|
|
||||||
// Metadata version of this header. Multiple headers may have the same metadata version
|
|
||||||
public double MetadataVersion { get; }
|
|
||||||
|
|
||||||
// Minimum and maximum Unity version numbers corresponding to this header. Both endpoints are inclusive
|
|
||||||
public UnityVersionRange Version { get; }
|
|
||||||
|
|
||||||
// Filename for the embedded .h resource file containing the header
|
|
||||||
public string HeaderFilename { get; }
|
|
||||||
|
|
||||||
private UnityHeader(string headerFilename) {
|
|
||||||
HeaderFilename = headerFilename;
|
|
||||||
Version = UnityVersionRange.FromFilename(HeaderFilename);
|
|
||||||
MetadataVersion = double.Parse(headerFilename.Split("-")[0], NumberFormatInfo.InvariantInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString() => Version.ToString();
|
|
||||||
|
|
||||||
// Return the contents of this header file as a string
|
|
||||||
public string GetHeaderText() {
|
|
||||||
var str = ResourceHelper.GetText(typeof(UnityHeader).Namespace + "." + HeaderFilename);
|
|
||||||
|
|
||||||
// Versions 5.3.6-5.4.6 don't include a definition for VirtualInvokeData
|
|
||||||
if (Version.Min.CompareTo("5.3.6") >= 0 && Version.Max.CompareTo("5.4.6") <= 0) {
|
|
||||||
str = str + @"struct VirtualInvokeData
|
|
||||||
{
|
|
||||||
Il2CppMethodPointer methodPtr;
|
|
||||||
const MethodInfo* method;
|
|
||||||
} VirtualInvokeData;";
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
// List all header files embedded into this build of Il2CppInspector
|
|
||||||
public static IEnumerable<UnityHeader> GetAllHeaders() => ResourceHelper.GetNamesForNamespace(typeof(UnityHeader).Namespace)
|
|
||||||
.Where(s => s.EndsWith(".h"))
|
|
||||||
.Select(s => new UnityHeader(s.Substring(typeof(UnityHeader).Namespace.Length + 1)));
|
|
||||||
|
|
||||||
// List all API header files and versions embedded into this build of Il2CppInspector
|
|
||||||
public static Dictionary<string, UnityVersionRange> GetAllAPIs() {
|
|
||||||
var list = ResourceHelper.GetNamesForNamespace("Il2CppInspector.Cpp.Il2CppAPIHeaders");
|
|
||||||
return list.Select(i => new {
|
|
||||||
Key = i,
|
|
||||||
Value = UnityVersionRange.FromFilename(i),
|
|
||||||
}).ToDictionary(kv => kv.Key, kv => kv.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the header file which supports the given version of Unity
|
|
||||||
public static UnityHeader GetHeaderForVersion(string version) => GetHeaderForVersion(new UnityVersion(version));
|
|
||||||
public static UnityHeader GetHeaderForVersion(UnityVersion version) => GetAllHeaders().First(h => h.Version.Contains(version));
|
|
||||||
|
|
||||||
// Get API file resources
|
|
||||||
public static string GetAPIResourceNameForVersion(UnityVersion version) => GetAllAPIs().First(h => h.Value.Contains(version)).Key;
|
|
||||||
public static string GetAPITextForVersion(UnityVersion version) => ResourceHelper.GetText(GetAPIResourceNameForVersion(version));
|
|
||||||
|
|
||||||
// Guess which header file(s) correspond to the given metadata+binary.
|
|
||||||
// Note that this may match multiple headers due to structural changes between versions
|
|
||||||
// that are not reflected in the metadata version.
|
|
||||||
public static List<UnityHeader> GuessHeadersForModel(Reflection.TypeModel model) {
|
|
||||||
List<UnityHeader> result = new List<UnityHeader>();
|
|
||||||
foreach (var h in GetAllHeaders()) {
|
|
||||||
if (h.MetadataVersion != model.Package.BinaryImage.Version)
|
|
||||||
continue;
|
|
||||||
if (h.MetadataVersion == 21) {
|
|
||||||
/* Special version logic for metadata version 21 based on the Il2CppMetadataRegistration.fieldOffsets field */
|
|
||||||
var headerFieldOffsetsArePointers = h.Version.Min.CompareTo("5.3.7") >= 0 && h.Version.Min.CompareTo("5.4.0") != 0;
|
|
||||||
var binaryFieldOffsetsArePointers = model.Package.Binary.FieldOffsets == null;
|
|
||||||
if (headerFieldOffsetsArePointers != binaryFieldOffsetsArePointers)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
result.Add(h);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
152
Il2CppInspector.Common/Cpp/UnityHeaders/UnityHeaders.cs
Normal file
152
Il2CppInspector.Common/Cpp/UnityHeaders/UnityHeaders.cs
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017-2020 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
|
||||||
|
Copyright 2020 Robert Xiao - https://robertxiao.ca
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Cpp.UnityHeaders
|
||||||
|
{
|
||||||
|
// Each instance of UnityHeaders represents all of the header files needed to build for a specific range of Unity versions
|
||||||
|
// Also provides helper functions to fetch various types of resources
|
||||||
|
public class UnityHeaders
|
||||||
|
{
|
||||||
|
// Metadata version for which this group of headers are valid. Multiple headers may have the same metadata version
|
||||||
|
public double MetadataVersion { get; }
|
||||||
|
|
||||||
|
// Range of Unity versions for which this group of headers are valid
|
||||||
|
public UnityVersionRange VersionRange { get; }
|
||||||
|
|
||||||
|
// The fully qualified names of the embedded resources
|
||||||
|
private readonly UnityResource typeHeaderResource;
|
||||||
|
private readonly UnityResource apiHeaderResource;
|
||||||
|
|
||||||
|
// Initialize from a type header and an API header
|
||||||
|
private UnityHeaders(UnityResource typeHeaders, UnityResource apiHeaders) {
|
||||||
|
typeHeaderResource = typeHeaders;
|
||||||
|
apiHeaderResource = apiHeaders;
|
||||||
|
|
||||||
|
VersionRange = typeHeaders.VersionRange.Intersect(apiHeaders.VersionRange);
|
||||||
|
MetadataVersion = GetMetadataVersionFromFilename(typeHeaders.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the contents of the type header file as a string
|
||||||
|
public string GetTypeHeaderText(int WordSize) {
|
||||||
|
var str = (WordSize == 32 ? "#define IS_32BIT\n" : "") + typeHeaderResource.GetText();
|
||||||
|
|
||||||
|
// Versions 5.3.6-5.4.6 don't include a definition for VirtualInvokeData
|
||||||
|
if (VersionRange.Min.CompareTo("5.3.6") >= 0 && VersionRange.Max.CompareTo("5.4.6") <= 0) {
|
||||||
|
str = str + @"struct VirtualInvokeData
|
||||||
|
{
|
||||||
|
Il2CppMethodPointer methodPtr;
|
||||||
|
const MethodInfo* method;
|
||||||
|
} VirtualInvokeData;";
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the contents of the API header file as a string
|
||||||
|
public string GetAPIHeaderText() => apiHeaderResource.GetText();
|
||||||
|
|
||||||
|
// Return the contents of the API header file translated to typedefs as a string
|
||||||
|
public string GetAPIHeaderTypedefText() => GetTypedefsFromAPIHeader(GetAPIHeaderText());
|
||||||
|
|
||||||
|
public override string ToString() => VersionRange.ToString();
|
||||||
|
|
||||||
|
// Class which associates an embedded resource with a range of Unity versions
|
||||||
|
public class UnityResource
|
||||||
|
{
|
||||||
|
// The fully qualified name of the embdedded resource
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
// Minimum and maximum Unity version numbers corresponding to this resource. Both endpoints are inclusive
|
||||||
|
public UnityVersionRange VersionRange { get; }
|
||||||
|
|
||||||
|
// Get the text of this resource
|
||||||
|
public string GetText() => ResourceHelper.GetText(Name);
|
||||||
|
|
||||||
|
public UnityResource(string name) {
|
||||||
|
Name = name;
|
||||||
|
VersionRange = UnityVersionRange.FromFilename(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => Name + " for " + VersionRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static helpers
|
||||||
|
|
||||||
|
// List all type header files embedded into this build of Il2CppInspector
|
||||||
|
public static IEnumerable<UnityResource> GetAllTypeHeaders() =>
|
||||||
|
ResourceHelper.GetNamesForNamespace(typeof(UnityHeaders).Namespace)
|
||||||
|
.Where(s => s.EndsWith(".h"))
|
||||||
|
.Select(s => new UnityResource(s));
|
||||||
|
|
||||||
|
// List all API header files embedded into this build of Il2CppInspector
|
||||||
|
public static IEnumerable<UnityResource> GetAllAPIHeaders() =>
|
||||||
|
ResourceHelper.GetNamesForNamespace("Il2CppInspector.Cpp.Il2CppAPIHeaders")
|
||||||
|
.Where(s => s.EndsWith(".h"))
|
||||||
|
.Select(s => new UnityResource(s));
|
||||||
|
|
||||||
|
// Get the headers which support the given version of Unity
|
||||||
|
public static UnityHeaders GetHeadersForVersion(UnityVersion version) =>
|
||||||
|
new UnityHeaders(GetTypeHeaderForVersion(version), GetAPIHeaderForVersion(version));
|
||||||
|
|
||||||
|
public static UnityResource GetTypeHeaderForVersion(UnityVersion version) => GetAllTypeHeaders().First(r => r.VersionRange.Contains(version));
|
||||||
|
|
||||||
|
// Get the API header file which supports the given version of Unity
|
||||||
|
public static UnityResource GetAPIHeaderForVersion(UnityVersion version) => GetAllAPIHeaders().First(r => r.VersionRange.Contains(version));
|
||||||
|
|
||||||
|
// Guess which header file(s) correspond to the given metadata+binary.
|
||||||
|
// Note that this may match multiple headers due to structural changes between versions
|
||||||
|
// that are not reflected in the metadata version.
|
||||||
|
public static List<UnityHeaders> GuessHeadersForBinary(Il2CppBinary binary) {
|
||||||
|
|
||||||
|
List<UnityResource> typeHeaders = new List<UnityResource>();
|
||||||
|
foreach (var r in GetAllTypeHeaders()) {
|
||||||
|
var metadataVersion = GetMetadataVersionFromFilename(r.Name);
|
||||||
|
|
||||||
|
if (metadataVersion != binary.Image.Version)
|
||||||
|
continue;
|
||||||
|
if (metadataVersion == 21) {
|
||||||
|
/* Special version logic for metadata version 21 based on the Il2CppMetadataRegistration.fieldOffsets field */
|
||||||
|
var headerFieldOffsetsArePointers = r.VersionRange.Min.CompareTo("5.3.7") >= 0 && r.VersionRange.Min.CompareTo("5.4.0") != 0;
|
||||||
|
var binaryFieldOffsetsArePointers = binary.FieldOffsets == null;
|
||||||
|
if (headerFieldOffsetsArePointers != binaryFieldOffsetsArePointers)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
typeHeaders.Add(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Replace this with an implementation which searches for the correct API header
|
||||||
|
return typeHeaders.Select(t => new UnityHeaders(t, GetAPIHeaderForVersion(t.VersionRange.Min))).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert il2cpp-api-functions.h from "DO_API(r, n, p)" to "typedef r (*n)(p)"
|
||||||
|
internal static string GetTypedefsFromAPIHeader(string text) {
|
||||||
|
var rgx = new Regex(@"^DO_API(?:_NO_RETURN)?\((.*?),(.*?),\s*\((.*?)\)\s*\);", RegexOptions.Multiline);
|
||||||
|
return rgx.Replace(text, "typedef $1 (*$2)($3);");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a list of function names from il2cpp-api-functions.h, taking #ifs into account
|
||||||
|
private static IEnumerable<string> GetFunctionNamesFromAPIHeaderText(string text) {
|
||||||
|
var defText = GetTypedefsFromAPIHeader(text);
|
||||||
|
var defs = new CppTypeCollection(32); // word size doesn't matter
|
||||||
|
defs.AddFromDeclarationText(defText);
|
||||||
|
|
||||||
|
return defs.TypedefAliases.Keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the metadata version from a type header resource name
|
||||||
|
private static double GetMetadataVersionFromFilename(string resourceName)
|
||||||
|
=> double.Parse(resourceName.Substring(typeof(UnityHeaders).Namespace.Length + 1).Split('-')[0], NumberFormatInfo.InvariantInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
@@ -181,7 +180,7 @@ namespace Il2CppInspector.Cpp.UnityHeaders
|
|||||||
var res = $"{Min}";
|
var res = $"{Min}";
|
||||||
if (Max == null)
|
if (Max == null)
|
||||||
res += "+";
|
res += "+";
|
||||||
else if (Max != Min)
|
else if (!Max.Equals(Min))
|
||||||
res += $" - {Max}";
|
res += $" - {Max}";
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace Il2CppInspector.Model
|
|||||||
|
|
||||||
// The Unity IL2CPP C++ headers for the binary
|
// The Unity IL2CPP C++ headers for the binary
|
||||||
// Use this for code output
|
// Use this for code output
|
||||||
public UnityHeader UnityHeader { get; private set; }
|
public UnityHeaders UnityHeaders { get; private set; }
|
||||||
|
|
||||||
// All of the C++ types used in the application including Unity internal types
|
// All of the C++ types used in the application including Unity internal types
|
||||||
// NOTE: This is for querying individual types for static analysis
|
// NOTE: This is for querying individual types for static analysis
|
||||||
@@ -58,7 +58,7 @@ namespace Il2CppInspector.Model
|
|||||||
// The .NET type model for the application
|
// The .NET type model for the application
|
||||||
public TypeModel ILModel { get; }
|
public TypeModel ILModel { get; }
|
||||||
|
|
||||||
// All of the function exports for the binary
|
// All of the symbol exports (including function exports) for the binary
|
||||||
public List<Export> Exports { get; }
|
public List<Export> Exports { get; }
|
||||||
|
|
||||||
// Delegated C++ types iterator
|
// Delegated C++ types iterator
|
||||||
@@ -79,9 +79,6 @@ namespace Il2CppInspector.Model
|
|||||||
// The compiler used to build the binary
|
// The compiler used to build the binary
|
||||||
public CppCompilerType SourceCompiler => declarationGenerator.InheritanceStyle;
|
public CppCompilerType SourceCompiler => declarationGenerator.InheritanceStyle;
|
||||||
|
|
||||||
// The Unity header text including word size define
|
|
||||||
public string UnityHeaderText => (WordSize == 32 ? "#define IS_32BIT\n" : "") + UnityHeader.GetHeaderText();
|
|
||||||
|
|
||||||
// The group that the next added type(s) will be placed in
|
// The group that the next added type(s) will be placed in
|
||||||
private string group = string.Empty;
|
private string group = string.Empty;
|
||||||
private string Group {
|
private string Group {
|
||||||
@@ -97,7 +94,7 @@ namespace Il2CppInspector.Model
|
|||||||
// Save .NET type model
|
// Save .NET type model
|
||||||
ILModel = model;
|
ILModel = model;
|
||||||
|
|
||||||
// Get addresses of IL2CPP API function exports
|
// Get addresses of all exports
|
||||||
Exports = model.Package.Binary.Image.GetExports()?.ToList() ?? new List<Export>();
|
Exports = model.Package.Binary.Image.GetExports()?.ToList() ?? new List<Export>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,22 +113,22 @@ namespace Il2CppInspector.Model
|
|||||||
TargetCompiler = compiler == CppCompilerType.BinaryFormat ? CppCompiler.GuessFromImage(ILModel.Package.BinaryImage) : compiler;
|
TargetCompiler = compiler == CppCompilerType.BinaryFormat ? CppCompiler.GuessFromImage(ILModel.Package.BinaryImage) : compiler;
|
||||||
|
|
||||||
// Determine Unity version and get headers
|
// Determine Unity version and get headers
|
||||||
UnityHeader = unityVersion != null ? UnityHeader.GetHeaderForVersion(unityVersion) : UnityHeader.GuessHeadersForModel(ILModel)[0];
|
UnityHeaders = unityVersion != null ? UnityHeaders.GetHeadersForVersion(unityVersion) : UnityHeaders.GuessHeadersForBinary(ILModel.Package.Binary)[0];
|
||||||
UnityVersion = unityVersion ?? UnityHeader.Version.Min;
|
UnityVersion = unityVersion ?? UnityHeaders.VersionRange.Min;
|
||||||
|
|
||||||
// Check for matching metadata and binary versions
|
// Check for matching metadata and binary versions
|
||||||
if (UnityHeader.MetadataVersion != ILModel.Package.BinaryImage.Version) {
|
if (UnityHeaders.MetadataVersion != ILModel.Package.BinaryImage.Version) {
|
||||||
Console.WriteLine($"Warning: selected version {UnityVersion} (metadata version {UnityHeader.MetadataVersion})" +
|
Console.WriteLine($"Warning: selected version {UnityVersion} (metadata version {UnityHeaders.MetadataVersion})" +
|
||||||
$" does not match metadata version {ILModel.Package.BinaryImage.Version}.");
|
$" does not match metadata version {ILModel.Package.BinaryImage.Version}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start creation of type model by parsing all of the Unity IL2CPP headers
|
|
||||||
// Calling declarationGenerator.GenerateRemainingTypeDeclarations() below will automatically add to this collection
|
|
||||||
CppTypeCollection = CppTypeCollection.FromUnityHeaders(UnityHeader, WordSize);
|
|
||||||
|
|
||||||
// Initialize declaration generator to process every type in the binary
|
// Initialize declaration generator to process every type in the binary
|
||||||
declarationGenerator = new CppDeclarationGenerator(this);
|
declarationGenerator = new CppDeclarationGenerator(this);
|
||||||
|
|
||||||
|
// Start creation of type model by parsing all of the Unity IL2CPP headers
|
||||||
|
// Calling declarationGenerator.GenerateRemainingTypeDeclarations() below will automatically add to this collection
|
||||||
|
CppTypeCollection = CppTypeCollection.FromUnityHeaders(UnityHeaders, declarationGenerator);
|
||||||
|
|
||||||
// Initialize ordered type list for code output
|
// Initialize ordered type list for code output
|
||||||
DependencyOrderedCppTypes = new List<CppType>();
|
DependencyOrderedCppTypes = new List<CppType>();
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
|
|
||||||
writeHeader();
|
writeHeader();
|
||||||
writeSectionHeader("IL2CPP internal types");
|
writeSectionHeader("IL2CPP internal types");
|
||||||
writeCode(model.UnityHeaderText);
|
writeCode(model.UnityHeaders.GetTypeHeaderText(model.WordSize));
|
||||||
|
|
||||||
writeCode("namespace app {");
|
writeCode("namespace app {");
|
||||||
writeLine("");
|
writeLine("");
|
||||||
@@ -133,15 +133,10 @@ namespace Il2CppInspector.Outputs
|
|||||||
|
|
||||||
private void writeHeader() {
|
private void writeHeader() {
|
||||||
writeLine("// Generated C++ file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty");
|
writeLine("// Generated C++ file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty");
|
||||||
writeLine("// Target Unity version: " + model.UnityHeader);
|
writeLine("// Target Unity version: " + model.UnityHeaders);
|
||||||
writeLine("");
|
writeLine("");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeUnityHeaders() {
|
|
||||||
var prefix = (model.Package.BinaryImage.Bits == 32) ? "#define IS_32BIT\n" : "";
|
|
||||||
writeCode(prefix + model.UnityHeader.GetHeaderText());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeTypesForGroup(string header, string group) {
|
private void writeTypesForGroup(string header, string group) {
|
||||||
writeSectionHeader(header);
|
writeSectionHeader(header);
|
||||||
foreach (var cppType in model.GetDependencyOrderedCppTypeGroup(group))
|
foreach (var cppType in model.GetDependencyOrderedCppTypeGroup(group))
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
writer = new StreamWriter(fs, Encoding.UTF8);
|
writer = new StreamWriter(fs, Encoding.UTF8);
|
||||||
|
|
||||||
writeLine("# Generated script file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty");
|
writeLine("# Generated script file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty");
|
||||||
writeLine("# Target Unity version: " + model.UnityHeader);
|
writeLine("# Target Unity version: " + model.UnityHeaders);
|
||||||
writeLine("print('Generated script file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty')");
|
writeLine("print('Generated script file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty')");
|
||||||
writeSectionHeader("Preamble");
|
writeSectionHeader("Preamble");
|
||||||
writePreamble();
|
writePreamble();
|
||||||
@@ -84,7 +84,7 @@ typedef __int64 int64_t;
|
|||||||
|
|
||||||
private void writeTypes() {
|
private void writeTypes() {
|
||||||
writeSectionHeader("IL2CPP internal types");
|
writeSectionHeader("IL2CPP internal types");
|
||||||
writeDecls(model.UnityHeaderText);
|
writeDecls(model.UnityHeaders.GetTypeHeaderText(model.WordSize));
|
||||||
|
|
||||||
writeSectionHeader("Application types from method calls");
|
writeSectionHeader("Application types from method calls");
|
||||||
writeTypes(model.GetDependencyOrderedCppTypeGroup("types_from_methods"));
|
writeTypes(model.GetDependencyOrderedCppTypeGroup("types_from_methods"));
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Il2CppInspector.Cpp.UnityHeaders;
|
|
||||||
|
|
||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ namespace Il2CppInspectorGUI
|
|||||||
var prevCppSelection = cboCppUnityVersion.SelectedItem;
|
var prevCppSelection = cboCppUnityVersion.SelectedItem;
|
||||||
cboUnityVersion.Items.Clear();
|
cboUnityVersion.Items.Clear();
|
||||||
cboCppUnityVersion.Items.Clear();
|
cboCppUnityVersion.Items.Clear();
|
||||||
foreach (var version in UnityHeader.GuessHeadersForModel(model.ILModel)) {
|
foreach (var version in UnityHeaders.GuessHeadersForBinary(model.Package.Binary)) {
|
||||||
cboUnityVersion.Items.Add(version);
|
cboUnityVersion.Items.Add(version);
|
||||||
cboCppUnityVersion.Items.Add(version);
|
cboCppUnityVersion.Items.Add(version);
|
||||||
}
|
}
|
||||||
@@ -406,7 +406,7 @@ namespace Il2CppInspectorGUI
|
|||||||
var outFile = scriptSaveFileDialog.FileName;
|
var outFile = scriptSaveFileDialog.FileName;
|
||||||
|
|
||||||
areaBusyIndicator.Visibility = Visibility.Visible;
|
areaBusyIndicator.Visibility = Visibility.Visible;
|
||||||
var selectedVersion = ((UnityHeader) cboUnityVersion.SelectedItem)?.Version.Min;
|
var selectedVersion = ((UnityHeaders) cboUnityVersion.SelectedItem)?.VersionRange.Min;
|
||||||
await Task.Run(() => {
|
await Task.Run(() => {
|
||||||
OnStatusUpdate(this, "Building C++ application model");
|
OnStatusUpdate(this, "Building C++ application model");
|
||||||
model.Build(selectedVersion, CppCompilerType.GCC);
|
model.Build(selectedVersion, CppCompilerType.GCC);
|
||||||
@@ -430,7 +430,7 @@ namespace Il2CppInspectorGUI
|
|||||||
var cppOutPath = cppSaveFolderDialog.SelectedPath;
|
var cppOutPath = cppSaveFolderDialog.SelectedPath;
|
||||||
|
|
||||||
areaBusyIndicator.Visibility = Visibility.Visible;
|
areaBusyIndicator.Visibility = Visibility.Visible;
|
||||||
var selectedCppUnityVersion = ((UnityHeader) cboCppUnityVersion.SelectedItem)?.Version.Min;
|
var selectedCppUnityVersion = ((UnityHeaders) cboCppUnityVersion.SelectedItem)?.VersionRange.Min;
|
||||||
var cppCompiler = (CppCompilerType) Enum.Parse(typeof(CppCompilerType), cboCppCompiler.SelectionBoxItem.ToString());
|
var cppCompiler = (CppCompilerType) Enum.Parse(typeof(CppCompilerType), cboCppCompiler.SelectionBoxItem.ToString());
|
||||||
await Task.Run(() => {
|
await Task.Run(() => {
|
||||||
OnStatusUpdate(this, "Building C++ application model");
|
OnStatusUpdate(this, "Building C++ application model");
|
||||||
|
|||||||
@@ -22,15 +22,17 @@ namespace Il2CppInspector
|
|||||||
public void TestCppTypeDeclarations() {
|
public void TestCppTypeDeclarations() {
|
||||||
// NOTE: This test doesn't check for correct results, only that parsing doesn't fail!
|
// NOTE: This test doesn't check for correct results, only that parsing doesn't fail!
|
||||||
|
|
||||||
var unityAllHeaders = UnityHeader.GetAllHeaders();
|
var unityTypeHeaders = UnityHeaders.GetAllTypeHeaders();
|
||||||
|
|
||||||
// Ensure we have read the embedded assembly resources
|
// Ensure we have read the embedded assembly resources
|
||||||
Assert.IsTrue(unityAllHeaders.Any());
|
Assert.IsTrue(unityTypeHeaders.Any());
|
||||||
|
|
||||||
// Ensure we can interpret every header from every version of Unity without errors
|
// Ensure we can interpret every header from every version of Unity without errors
|
||||||
// This will throw InvalidOperationException if there is a problem
|
// This will throw InvalidOperationException if there is a problem
|
||||||
foreach (var unityHeader in unityAllHeaders) {
|
foreach (var unityTypeHeader in unityTypeHeaders) {
|
||||||
var cppTypes = CppTypeCollection.FromUnityHeaders(unityHeader);
|
var cppTypes = new CppTypeCollection(64);
|
||||||
|
cppTypes.AddFromDeclarationText(unityTypeHeader.GetText());
|
||||||
|
|
||||||
foreach (var cppType in cppTypes.Types)
|
foreach (var cppType in cppTypes.Types)
|
||||||
Debug.WriteLine("// " + cppType.Key + "\n" + cppType.Value.ToString("o"));
|
Debug.WriteLine("// " + cppType.Key + "\n" + cppType.Value.ToString("o"));
|
||||||
}
|
}
|
||||||
@@ -38,7 +40,7 @@ namespace Il2CppInspector
|
|||||||
// Do a few sanity checks taken from real applications
|
// Do a few sanity checks taken from real applications
|
||||||
// NOTE: Does not provide full code coverage!
|
// NOTE: Does not provide full code coverage!
|
||||||
|
|
||||||
var cppTypes2 = CppTypeCollection.FromUnityVersion(new UnityVersion("2019.3.1f1"), 64);
|
var cppTypes2 = CppTypeCollection.FromUnityVersion(new UnityVersion("2019.3.1f1"));
|
||||||
|
|
||||||
CppComplexType ct;
|
CppComplexType ct;
|
||||||
CppField field;
|
CppField field;
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ namespace Il2CppInspector
|
|||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestVersions() {
|
public void TestVersions() {
|
||||||
Assert.That(UnityHeader.GetHeaderForVersion("5.3.1p4").ToString(), Is.EqualTo("5.3.0 - 5.3.1"));
|
Assert.That(UnityHeaders.GetTypeHeaderForVersion("5.3.1p4").VersionRange.ToString(), Is.EqualTo("5.3.0 - 5.3.1"));
|
||||||
Assert.That(UnityHeader.GetHeaderForVersion("5.6.4").ToString(), Is.EqualTo("5.6.0 - 5.6.7"));
|
Assert.That(UnityHeaders.GetTypeHeaderForVersion("5.6.4").VersionRange.ToString(), Is.EqualTo("5.6.0 - 5.6.7"));
|
||||||
Assert.That(new UnityVersion("2020.1.0b5").ToString(), Is.EqualTo("2020.1.0b5"));
|
Assert.That(new UnityVersion("2020.1.0b5").ToString(), Is.EqualTo("2020.1.0b5"));
|
||||||
Assert.That(new UnityVersion("2020.1").ToString(), Is.EqualTo("2020.1.0"));
|
Assert.That(new UnityVersion("2020.1").ToString(), Is.EqualTo("2020.1.0"));
|
||||||
Assert.That(new UnityVersion("5.3.1").CompareTo("5.3.1p4") == 0);
|
Assert.That(new UnityVersion("5.3.1").CompareTo("5.3.1p4") == 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user