C++: Add parse loop, implement typedef alias parsing

This commit is contained in:
Katy Coe
2020-06-24 22:18:05 +02:00
parent bee75fc6b1
commit f407cb94df

View File

@@ -6,16 +6,27 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using Il2CppInspector.Outputs;
using Il2CppInspector.Outputs.UnityHeaders;
using Il2CppInspector.Reflection;
namespace Il2CppInspector.Cpp
{
public abstract class CppType
{
// The name of the type
public string Name { get; }
// Calculate the size of the C++ type in bytes
public abstract int GetSize();
protected CppType(string name) => Name = name;
}
// A non-struct non-class type
@@ -25,7 +36,7 @@ namespace Il2CppInspector.Cpp
public override int GetSize() => size;
public CppPrimitiveType(int size) => this.size = size;
public CppPrimitiveType(string name, int size) : base(name) => this.size = size;
}
// A struct or class type
@@ -36,6 +47,10 @@ namespace Il2CppInspector.Cpp
// Calculate the size by summing the size of each field's type
public override int GetSize() => Fields.Values.Select(f => f.Type.GetSize()).Sum();
public CppComplexType(string name) : base(name) {}
// TODO: Add fields
}
// A field in a C++ type
@@ -44,6 +59,9 @@ namespace Il2CppInspector.Cpp
// The name of the field
public string Name { get; }
// The offset of the field into the type
public int Offset { get; }
// The type of the field
public CppType Type { get; }
}
@@ -51,23 +69,92 @@ namespace Il2CppInspector.Cpp
// A collection of C++ types
public class CppTypes
{
// All of the types
private Dictionary<string, CppType> types { get; }
public CppType this[string s] => types[s];
public CppTypes() {
types = new Dictionary<string, CppType> {
["uint8_t"] = new CppPrimitiveType(1),
["uint16_t"] = new CppPrimitiveType(2),
["uint32_t"] = new CppPrimitiveType(4),
["uint64_t"] = new CppPrimitiveType(8),
["int8_t"] = new CppPrimitiveType(1),
["int16_t"] = new CppPrimitiveType(2),
["int32_t"] = new CppPrimitiveType(4),
["int64_t"] = new CppPrimitiveType(8),
["char"] = new CppPrimitiveType(1),
["void"] = new CppPrimitiveType(4), // or 8; pointer
// Architecture width in bytes (4 bytes for 32-bit or 8 bytes for 64-bit, to determine pointer sizes)
public int WordSize { get; }
private static readonly List<CppPrimitiveType> primitiveTypes = new List<CppPrimitiveType> {
new CppPrimitiveType("uint8_t", 1),
new CppPrimitiveType("uint16_t", 2),
new CppPrimitiveType("uint32_t", 4),
new CppPrimitiveType("uint64_t", 8),
new CppPrimitiveType("int8_t", 1),
new CppPrimitiveType("int16_t", 2),
new CppPrimitiveType("int32_t", 4),
new CppPrimitiveType("int64_t", 8),
new CppPrimitiveType("char", 1)
};
public CppTypes(int wordSize) {
WordSize = wordSize;
types = primitiveTypes.ToDictionary(t => t.Name, t => (CppType) t);
// This is all compiler-dependent, let's hope for the best!
types.Add("uintptr_t", new CppPrimitiveType("uintptr_t", WordSize));
types.Add("size_t", new CppPrimitiveType("size_t", WordSize));
}
// Parse a block of C++ source code, adding any types found
public void AddFromDeclarationText(string text) {
using StringReader lines = new StringReader(text);
var rgxTypedef = new Regex(@"typedef (\S+) (\S+);");
var rgxTypedefFnPtr = new Regex(@"typedef\s+\S+\s*\(\s*\*(\S+)\)\s*\(.*\);");
string line;
while ((line = lines.ReadLine()) != null) {
// Sanitize
line = line.Trim();
line = line.Replace(" const ", " ");
// typedef <retType> (*<alias>)(<args>);
var typedef = rgxTypedefFnPtr.Match(line);
if (typedef.Success) {
var alias = typedef.Groups[1].Captures[0].ToString();
Debug.WriteLine($"[TYPEDEF] {line} -- Adding method pointer typedef to {alias}");
types.Add(alias, types["uintptr_t"]);
continue;
}
// typedef <targetType> <alias>;
typedef = rgxTypedef.Match(line);
if (typedef.Success) {
var alias = typedef.Groups[2].Captures[0].ToString();
var existingType = typedef.Groups[1].Captures[0].ToString();
// Pointers
if (existingType.Contains("*")) {
// TODO: Typedef pointers
}
// Regular aliases
else {
Debug.WriteLine($"[TYPEDEF] {line} -- Adding typedef from {existingType} to {alias}");
types.Add(alias, types[existingType]);
continue;
}
}
Debug.WriteLine("[IGNORE ] " + line);
}
}
// Generate a populated CppTypes object from an
public static CppTypes FromUnityHeaders(UnityVersion version) {
var cppTypes = new CppTypes(8);
// Process Unity headers
var headers = UnityHeader.GetHeaderForVersion(version).GetHeaderText();
cppTypes.AddFromDeclarationText(headers);
return cppTypes;
}
}
}