C++: Handle function pointers

This commit is contained in:
Katy Coe
2020-06-28 01:35:03 +02:00
parent 9ee8065d57
commit 9e72412230

View File

@@ -71,7 +71,7 @@ namespace Il2CppInspector.CppUtils
public CppType ElementType { get; }
// Even an array of 1-bit bitfirleds must use at least 1 byte each
// Even an array of 1-bit bitfields must use at least 1 byte each
public override int Size => SizeBytes * 8;
public override int SizeBytes => ElementType.SizeBytes * Length;
@@ -84,6 +84,22 @@ namespace Il2CppInspector.CppUtils
public override string ToString() => ElementType + "[" + Length + "]";
}
// A function pointer type
public class CppFnPtrType : CppType
{
// For display purposes only
// We could figure out the actual CppTypes for these but I'm not sure there is any advantage to it
public string ReturnType { get; }
public string Arguments { get; }
public CppFnPtrType(int WordSize, string returnType, string arguments) : base(null, WordSize) {
ReturnType = returnType;
Arguments = arguments;
}
public override string ToString() => $"typedef {ReturnType} (*{Name})({Arguments});";
}
// A typedef alias
public class CppAlias : CppType
{
@@ -151,7 +167,7 @@ namespace Il2CppInspector.CppUtils
if (Fields.Any()) {
sb.AppendLine("{");
foreach (var field in Fields.Values.SelectMany(f => f))
sb.AppendLine(" " + string.Join("\n ", field.ToString().Split('\n')));
sb.AppendLine("\t" + string.Join("\n\t", field.ToString().Split('\n')));
sb.Append($"}} {Name}{(Name.Length > 0 ? " " : "")}/* Size: 0x{SizeBytes:x2} */;");
}
@@ -196,17 +212,32 @@ namespace Il2CppInspector.CppUtils
internal CppType Type { get; set; }
// C++ representation of field (might be incorrect due to the above)
public override string ToString() =>
$"/* 0x{OffsetBytes:x2} - 0x{OffsetBytes + SizeBytes - 1:x2} (0x{SizeBytes:x2}) */"
// nested anonymous types
+ (Type is CppComplexType && Type.Name == "" ? "\n" + Type.ToString()[..^1] + " " + Name :
public override string ToString() {
var offset = $"/* 0x{OffsetBytes:x2} - 0x{OffsetBytes + SizeBytes - 1:x2} (0x{SizeBytes:x2}) */";
var field = Type switch {
// nested anonymouse types
CppComplexType t when string.IsNullOrEmpty(t.Name) => "\n" + t.ToString()[..^1] + " " + Name,
// function pointers
CppFnPtrType t when string.IsNullOrEmpty(t.Name) => $" {t.ReturnType} (*{Name})({t.Arguments})",
// regular fields
$" {Type.Name} {Name}" + (BitfieldSize > 0? $" : {BitfieldSize}" : ""))
_ => $" {Type.Name} {Name}" + (BitfieldSize > 0? $" : {BitfieldSize}" : "")
};
var suffix = "";
// arrays
+ (Type is CppArrayType? "[" + ((CppArrayType)Type).Length + "]" : "")
+ ";"
if (Type is CppArrayType a)
suffix += "[" + a.Length + "]";
suffix += ";";
// bitfields
+ (BitfieldSize > 0? $" // bits {BitfieldLSB} - {BitfieldMSB}" : "");
if (BitfieldSize > 0)
suffix += $" // bits {BitfieldLSB} - {BitfieldMSB}";
return offset + field + suffix;
}
}
// A collection of C++ types
@@ -256,7 +287,7 @@ namespace Il2CppInspector.CppUtils
public void AddFromDeclarationText(string text) {
using StringReader lines = new StringReader(text);
var fnPtr = @"\S+\s*\(\s*\*(\S+)\)\s*\(.*\)";
var fnPtr = @"(\S+)\s*\(\s*\*(\S+)\s*\)\s*\(\s*(.*?)\s*\)";
var rgxExternDecl = new Regex(@"struct (\S+);");
var rgxTypedefForwardDecl = new Regex(@"typedef struct (\S+) (\S+);");
var rgxTypedefFnPtr = new Regex(@"typedef\s+(?:struct )?" + fnPtr + ";");
@@ -280,12 +311,8 @@ namespace Il2CppInspector.CppUtils
bool inMethod = false;
string line;
// TODO: function pointer signatures
while ((line = lines.ReadLine()) != null) {
// Sanitize
// Remove comments
if (line.Contains("//"))
line = line.Substring(0, line.IndexOf("//", StringComparison.Ordinal));
@@ -422,8 +449,10 @@ namespace Il2CppInspector.CppUtils
// typedef <retType> (*<alias>)(<args>);
typedef = rgxTypedefFnPtr.Match(line);
if (typedef.Success) {
var alias = typedef.Groups[1].Captures[0].ToString();
Types.Add(alias, Types["uintptr_t"]);
var returnType = typedef.Groups[1].Captures[0].ToString();
var arguments = typedef.Groups[3].Captures[0].ToString();
var alias = typedef.Groups[2].Captures[0].ToString();
Types.Add(alias, new CppFnPtrType(WordSize, returnType, arguments) {Name = alias});
Debug.WriteLine($"[TYPEDEF FNPTR] {line} -- Adding method pointer typedef to {alias}");
continue;
@@ -554,10 +583,12 @@ namespace Il2CppInspector.CppUtils
// Function pointer field
var fieldFnPtr = rgxFieldFnPtr.Match(line);
if (fieldFnPtr.Success) {
var name = fieldFnPtr.Groups[1].Captures[0].ToString();
var returnType = fieldFnPtr.Groups[1].Captures[0].ToString();
var arguments = fieldFnPtr.Groups[3].Captures[0].ToString();
var name = fieldFnPtr.Groups[2].Captures[0].ToString();
var ct = currentType.Peek();
ct.AddField(new CppField {Name = name, Type = Types["uintptr_t"]}, alignment);
ct.AddField(new CppField {Name = name, Type = new CppFnPtrType(WordSize, returnType, arguments)}, alignment);
Debug.WriteLine($"[FIELD FNPTR ] {line} -- {name}");
continue;