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; } 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 Size => SizeBytes * 8;
public override int SizeBytes => ElementType.SizeBytes * Length; public override int SizeBytes => ElementType.SizeBytes * Length;
@@ -84,6 +84,22 @@ namespace Il2CppInspector.CppUtils
public override string ToString() => ElementType + "[" + Length + "]"; 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 // A typedef alias
public class CppAlias : CppType public class CppAlias : CppType
{ {
@@ -151,7 +167,7 @@ namespace Il2CppInspector.CppUtils
if (Fields.Any()) { if (Fields.Any()) {
sb.AppendLine("{"); sb.AppendLine("{");
foreach (var field in Fields.Values.SelectMany(f => f)) 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} */;"); sb.Append($"}} {Name}{(Name.Length > 0 ? " " : "")}/* Size: 0x{SizeBytes:x2} */;");
} }
@@ -196,17 +212,32 @@ namespace Il2CppInspector.CppUtils
internal CppType Type { get; set; } internal CppType Type { get; set; }
// C++ representation of field (might be incorrect due to the above) // C++ representation of field (might be incorrect due to the above)
public override string ToString() => public override string ToString() {
$"/* 0x{OffsetBytes:x2} - 0x{OffsetBytes + SizeBytes - 1:x2} (0x{SizeBytes:x2}) */" var offset = $"/* 0x{OffsetBytes:x2} - 0x{OffsetBytes + SizeBytes - 1:x2} (0x{SizeBytes:x2}) */";
// nested anonymous types
+ (Type is CppComplexType && Type.Name == "" ? "\n" + Type.ToString()[..^1] + " " + Name : var field = Type switch {
// regular fields // nested anonymouse types
$" {Type.Name} {Name}" + (BitfieldSize > 0? $" : {BitfieldSize}" : "")) 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}" : "")
};
var suffix = "";
// arrays // arrays
+ (Type is CppArrayType? "[" + ((CppArrayType)Type).Length + "]" : "") if (Type is CppArrayType a)
+ ";" suffix += "[" + a.Length + "]";
suffix += ";";
// bitfields // bitfields
+ (BitfieldSize > 0? $" // bits {BitfieldLSB} - {BitfieldMSB}" : ""); if (BitfieldSize > 0)
suffix += $" // bits {BitfieldLSB} - {BitfieldMSB}";
return offset + field + suffix;
}
} }
// A collection of C++ types // A collection of C++ types
@@ -256,7 +287,7 @@ namespace Il2CppInspector.CppUtils
public void AddFromDeclarationText(string text) { public void AddFromDeclarationText(string text) {
using StringReader lines = new StringReader(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 rgxExternDecl = new Regex(@"struct (\S+);");
var rgxTypedefForwardDecl = new Regex(@"typedef struct (\S+) (\S+);"); var rgxTypedefForwardDecl = new Regex(@"typedef struct (\S+) (\S+);");
var rgxTypedefFnPtr = new Regex(@"typedef\s+(?:struct )?" + fnPtr + ";"); var rgxTypedefFnPtr = new Regex(@"typedef\s+(?:struct )?" + fnPtr + ";");
@@ -280,12 +311,8 @@ namespace Il2CppInspector.CppUtils
bool inMethod = false; bool inMethod = false;
string line; string line;
// TODO: function pointer signatures
while ((line = lines.ReadLine()) != null) { while ((line = lines.ReadLine()) != null) {
// Sanitize
// Remove comments // Remove comments
if (line.Contains("//")) if (line.Contains("//"))
line = line.Substring(0, line.IndexOf("//", StringComparison.Ordinal)); line = line.Substring(0, line.IndexOf("//", StringComparison.Ordinal));
@@ -422,8 +449,10 @@ namespace Il2CppInspector.CppUtils
// typedef <retType> (*<alias>)(<args>); // typedef <retType> (*<alias>)(<args>);
typedef = rgxTypedefFnPtr.Match(line); typedef = rgxTypedefFnPtr.Match(line);
if (typedef.Success) { if (typedef.Success) {
var alias = typedef.Groups[1].Captures[0].ToString(); var returnType = typedef.Groups[1].Captures[0].ToString();
Types.Add(alias, Types["uintptr_t"]); 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}"); Debug.WriteLine($"[TYPEDEF FNPTR] {line} -- Adding method pointer typedef to {alias}");
continue; continue;
@@ -554,10 +583,12 @@ namespace Il2CppInspector.CppUtils
// Function pointer field // Function pointer field
var fieldFnPtr = rgxFieldFnPtr.Match(line); var fieldFnPtr = rgxFieldFnPtr.Match(line);
if (fieldFnPtr.Success) { 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(); 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}"); Debug.WriteLine($"[FIELD FNPTR ] {line} -- {name}");
continue; continue;