C++: Improve handling of multiple pointer indirection and typedefs
This commit is contained in:
@@ -30,35 +30,45 @@ namespace Il2CppInspector.Cpp
|
|||||||
public class CppType
|
public class CppType
|
||||||
{
|
{
|
||||||
// The name of the type
|
// The name of the type
|
||||||
protected string name;
|
public virtual string Name { get; set; }
|
||||||
|
|
||||||
public virtual string Name {
|
|
||||||
get => name;
|
|
||||||
set => name = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The size of the C++ type in bytes
|
// The size of the C++ type in bytes
|
||||||
public virtual int Size { get; protected set; }
|
public virtual int Size { get; set; }
|
||||||
|
|
||||||
public CppType(string name, int size) {
|
public CppType(string name = null, int size = 0) {
|
||||||
Name = name;
|
Name = name;
|
||||||
Size = size;
|
Size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate pointer to this type
|
// Generate pointer to this type
|
||||||
public CppPointerType AsPointer(int WordSize, string Name = null) => new CppPointerType(WordSize) {Name = Name, ElementType = this};
|
public CppPointerType AsPointer(int WordSize) => new CppPointerType(WordSize, this);
|
||||||
|
|
||||||
public override string ToString() => $"/* {Size:x2} */ {Name}";
|
// Generate typedef to this type
|
||||||
|
public CppAlias AsAlias(string Name) => new CppAlias(Name, this);
|
||||||
|
|
||||||
|
public override string ToString() => $"/* {Size:x2} - {Name} */";
|
||||||
}
|
}
|
||||||
|
|
||||||
// A pointer type
|
// A pointer type
|
||||||
public class CppPointerType : CppType
|
public class CppPointerType : CppType
|
||||||
{
|
{
|
||||||
public override string Name => name ?? ElementType.Name + "*";
|
public override string Name => ElementType.Name + "*";
|
||||||
|
|
||||||
public CppType ElementType { get; set; }
|
public CppType ElementType { get; }
|
||||||
|
|
||||||
public CppPointerType(int WordSize) : base(null, WordSize) {}
|
public CppPointerType(int WordSize, CppType elementType) : base(null, WordSize) => ElementType = elementType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A typedef alias
|
||||||
|
public class CppAlias : CppType
|
||||||
|
{
|
||||||
|
public CppType ElementType { get; }
|
||||||
|
|
||||||
|
public override int Size => ElementType.Size;
|
||||||
|
|
||||||
|
public CppAlias(string name, CppType elementType) : base(name) => ElementType = elementType;
|
||||||
|
|
||||||
|
public override string ToString() => $"typedef {ElementType.Name} {Name};";
|
||||||
}
|
}
|
||||||
|
|
||||||
// A struct, union or class type (type with fields)
|
// A struct, union or class type (type with fields)
|
||||||
@@ -103,7 +113,7 @@ namespace Il2CppInspector.Cpp
|
|||||||
foreach (var field in Fields.Values.SelectMany(f => f))
|
foreach (var field in Fields.Values.SelectMany(f => f))
|
||||||
sb.AppendLine(" " + field);
|
sb.AppendLine(" " + field);
|
||||||
|
|
||||||
sb.Append($"}} /* Size: 0x{Size:x2} */");
|
sb.Append($"}} /* Size: 0x{Size:x2} */;");
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
@@ -129,7 +139,7 @@ namespace Il2CppInspector.Cpp
|
|||||||
// 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() => $"/* 0x{Offset:x2} - 0x{Offset + Size - 1:x2} (0x{Size:x2}) */"
|
public override string ToString() => $"/* 0x{Offset:x2} - 0x{Offset + Size - 1:x2} (0x{Size:x2}) */"
|
||||||
// nested anonymous types
|
// nested anonymous types
|
||||||
+ (Type is CppComplexType && Type.Name == "" ? "\n" + Type + " " + Name :
|
+ (Type is CppComplexType && Type.Name == "" ? "\n" + Type.ToString()[..^1] + " " + Name :
|
||||||
// regular fields
|
// regular fields
|
||||||
$" {Type.Name} {Name}")
|
$" {Type.Name} {Name}")
|
||||||
+ ";";
|
+ ";";
|
||||||
@@ -181,10 +191,10 @@ namespace Il2CppInspector.Cpp
|
|||||||
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 )?\S+\s*\(\s*\*(\S+)\)\s*\(.*\);");
|
var rgxTypedefFnPtr = new Regex(@"typedef\s+(?:struct )?\S+\s*\(\s*\*(\S+)\)\s*\(.*\);");
|
||||||
var rgxTypedefPtr = new Regex(@"typedef (\S+)\s*\*\s*(\S+);");
|
var rgxTypedefPtr = new Regex(@"typedef (\S+?)\s*\*+\s*(\S+);");
|
||||||
var rgxTypedef = new Regex(@"typedef (\S+) (\S+);");
|
var rgxTypedef = new Regex(@"typedef (\S+) (\S+);");
|
||||||
var rgxFieldFnPtr = new Regex(@"\S+\s*\(\s*\*(\S+)\)\s*\(.*\);");
|
var rgxFieldFnPtr = new Regex(@"\S+\s*\(\s*\*(\S+)\)\s*\(.*\);");
|
||||||
var rgxFieldPtr = new Regex(@"^(?:struct )?(\S+)\s*\*\s*(\S+);");
|
var rgxFieldPtr = new Regex(@"^(?:struct )?(\S+?)\s*\*+\s*(\S+);");
|
||||||
var rgxFieldVal = new Regex(@"^(?:struct )?(\S+)\s+(\S+);");
|
var rgxFieldVal = new Regex(@"^(?:struct )?(\S+)\s+(\S+);");
|
||||||
|
|
||||||
var currentType = new Stack<CppComplexType>();
|
var currentType = new Stack<CppComplexType>();
|
||||||
@@ -200,7 +210,6 @@ namespace Il2CppInspector.Cpp
|
|||||||
// TODO: #ifdef IS_32BIT
|
// TODO: #ifdef IS_32BIT
|
||||||
// TODO: volatile
|
// TODO: volatile
|
||||||
// TODO: function pointer signatures
|
// TODO: function pointer signatures
|
||||||
// TODO: multiple indirection
|
|
||||||
|
|
||||||
while ((line = lines.ReadLine()) != null) {
|
while ((line = lines.ReadLine()) != null) {
|
||||||
|
|
||||||
@@ -210,8 +219,7 @@ namespace Il2CppInspector.Cpp
|
|||||||
line = line.Replace("const*", "*");
|
line = line.Replace("const*", "*");
|
||||||
if (line.StartsWith("const "))
|
if (line.StartsWith("const "))
|
||||||
line = line.Substring(6);
|
line = line.Substring(6);
|
||||||
line = line.Replace("**", "*"); // we don't care about pointers to pointers
|
line = line.Replace("* *", "**"); // pointer to const pointer
|
||||||
line = line.Replace("* *", "*"); // pointer to const pointer
|
|
||||||
|
|
||||||
// External declaration
|
// External declaration
|
||||||
// struct <external-type>;
|
// struct <external-type>;
|
||||||
@@ -256,14 +264,20 @@ namespace Il2CppInspector.Cpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pointer alias
|
// Pointer alias
|
||||||
// typedef <targetType>* <alias>;
|
// typedef <targetType>*+ <alias>;
|
||||||
typedef = rgxTypedefPtr.Match(line);
|
typedef = rgxTypedefPtr.Match(line);
|
||||||
if (typedef.Success) {
|
if (typedef.Success) {
|
||||||
var alias = typedef.Groups[2].Captures[0].ToString();
|
var alias = typedef.Groups[2].Captures[0].ToString();
|
||||||
var existingType = typedef.Groups[1].Captures[0].ToString();
|
var existingType = typedef.Groups[1].Captures[0].ToString();
|
||||||
Types.Add(alias, Types[existingType].AsPointer(WordSize, alias));
|
|
||||||
|
|
||||||
Debug.WriteLine($"[TYPEDEF PTR ] {line} -- Adding pointer typedef from {existingType} to {alias}");
|
// Potential multiple indirection
|
||||||
|
var type = Types[existingType];
|
||||||
|
for (int i = 0; i < line.Count(c => c == '*'); i++)
|
||||||
|
type = type.AsPointer(WordSize);
|
||||||
|
|
||||||
|
Types.Add(alias, type.AsAlias(alias));
|
||||||
|
|
||||||
|
Debug.WriteLine($"[TYPEDEF PTR ] {line} -- Adding pointer typedef from {type.Name} to {alias}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,7 +288,7 @@ namespace Il2CppInspector.Cpp
|
|||||||
var alias = typedef.Groups[2].Captures[0].ToString();
|
var alias = typedef.Groups[2].Captures[0].ToString();
|
||||||
var existingType = typedef.Groups[1].Captures[0].ToString();
|
var existingType = typedef.Groups[1].Captures[0].ToString();
|
||||||
|
|
||||||
Types.Add(alias, Types[existingType]);
|
Types.Add(alias, Types[existingType].AsAlias(alias));
|
||||||
|
|
||||||
Debug.WriteLine($"[TYPEDEF ALIAS] {line} -- Adding typedef from {existingType} to {alias}");
|
Debug.WriteLine($"[TYPEDEF ALIAS] {line} -- Adding typedef from {existingType} to {alias}");
|
||||||
continue;
|
continue;
|
||||||
@@ -402,10 +416,15 @@ namespace Il2CppInspector.Cpp
|
|||||||
if (fieldPtr.Success || fieldVal.Success) {
|
if (fieldPtr.Success || fieldVal.Success) {
|
||||||
var fieldMatch = fieldPtr.Success ? fieldPtr : fieldVal;
|
var fieldMatch = fieldPtr.Success ? fieldPtr : fieldVal;
|
||||||
var name = fieldMatch.Groups[2].Captures[0].ToString();
|
var name = fieldMatch.Groups[2].Captures[0].ToString();
|
||||||
var type = fieldMatch.Groups[1].Captures[0].ToString();
|
var typeName = fieldMatch.Groups[1].Captures[0].ToString();
|
||||||
|
|
||||||
|
// Potential multiple indirection
|
||||||
|
var type = Types[typeName];
|
||||||
|
for (int i = 0; i < line.Count(c => c == '*'); i++)
|
||||||
|
type = type.AsPointer(WordSize);
|
||||||
|
|
||||||
var ct = currentType.Peek();
|
var ct = currentType.Peek();
|
||||||
ct.AddField(new CppField {Name = name, Type = fieldPtr.Success? Types[type].AsPointer(WordSize) : Types[type]});
|
ct.AddField(new CppField {Name = name, Type = type});
|
||||||
|
|
||||||
Debug.WriteLine($"[FIELD {(fieldPtr.Success? "PTR":"VAL")} ] {line} -- {name}");
|
Debug.WriteLine($"[FIELD {(fieldPtr.Success? "PTR":"VAL")} ] {line} -- {name}");
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
Reference in New Issue
Block a user