C++: Handle function pointers
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user