Add name mangling to Methods/MethodInfo/TypeInfo/TypeRef, remove Boxing from ValueTypes when used as the this parameter, fix crashes when a module has no attributes
This commit is contained in:
@@ -487,7 +487,7 @@ namespace Il2CppInspector.Cpp
|
|||||||
} else {
|
} else {
|
||||||
if (declaringType.IsValueType) {
|
if (declaringType.IsValueType) {
|
||||||
// Methods for structs take the boxed object as the this param
|
// Methods for structs take the boxed object as the this param
|
||||||
paramList.Add(("this", types.GetType(TypeNamer.GetName(declaringType) + "__Boxed *")));
|
paramList.Add(("this", types.GetType(TypeNamer.GetName(declaringType) + " *"))); // + "__Boxed *")));
|
||||||
} else {
|
} else {
|
||||||
paramList.Add(("this", AsCType(declaringType)));
|
paramList.Add(("this", AsCType(declaringType)));
|
||||||
}
|
}
|
||||||
|
|||||||
204
Il2CppInspector.Common/Cpp/MangledNameBuilder.cs
Normal file
204
Il2CppInspector.Common/Cpp/MangledNameBuilder.cs
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text;
|
||||||
|
using Il2CppInspector.Reflection;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Cpp;
|
||||||
|
|
||||||
|
// This follows Itanium/GCC mangling specifications.
|
||||||
|
public class MangledNameBuilder
|
||||||
|
{
|
||||||
|
private readonly StringBuilder _sb = new("_Z");
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
=> _sb.ToString();
|
||||||
|
|
||||||
|
public static string Method(MethodBase method)
|
||||||
|
{
|
||||||
|
var builder = new MangledNameBuilder();
|
||||||
|
builder.BuildMethod(method);
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string MethodInfo(MethodBase method)
|
||||||
|
{
|
||||||
|
var builder = new MangledNameBuilder();
|
||||||
|
builder.BuildMethod(method, "MethodInfo");
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string TypeInfo(TypeInfo type)
|
||||||
|
{
|
||||||
|
var builder = new MangledNameBuilder();
|
||||||
|
builder.BeginName();
|
||||||
|
builder.WriteIdentifier("TypeInfo");
|
||||||
|
builder.WriteTypeName(type);
|
||||||
|
builder.WriteEnd();
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string TypeRef(TypeInfo type)
|
||||||
|
{
|
||||||
|
var builder = new MangledNameBuilder();
|
||||||
|
builder.BeginName();
|
||||||
|
builder.WriteIdentifier("TypeRef");
|
||||||
|
builder.WriteTypeName(type);
|
||||||
|
builder.WriteEnd();
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildMethod(MethodBase method, string prefix = "")
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We do not have any CV-qualifiers nor ref-qualifiers,
|
||||||
|
* so we immediately write the nested name.
|
||||||
|
*/
|
||||||
|
|
||||||
|
BeginName();
|
||||||
|
|
||||||
|
if (prefix.Length > 0)
|
||||||
|
WriteIdentifier(prefix);
|
||||||
|
|
||||||
|
WriteTypeName(method.DeclaringType);
|
||||||
|
|
||||||
|
switch (method.Name)
|
||||||
|
{
|
||||||
|
case ".ctor":
|
||||||
|
_sb.Append("C1"); // Constructor
|
||||||
|
break;
|
||||||
|
case ".cctor":
|
||||||
|
WriteIdentifier("cctor");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WriteIdentifier(method.Name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var genericParams = method.GetGenericArguments();
|
||||||
|
|
||||||
|
WriteGenericParams(genericParams);
|
||||||
|
|
||||||
|
WriteEnd(); // End nested name
|
||||||
|
|
||||||
|
// Now write the method parameters
|
||||||
|
|
||||||
|
if (genericParams.Length > 0 && method is MethodInfo mInfo)
|
||||||
|
{
|
||||||
|
// If this is a generic method, the first parameter needs to be the return type
|
||||||
|
WriteType(mInfo.ReturnType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.DeclaredParameters.Count == 0)
|
||||||
|
_sb.Append('v');
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var param in method.DeclaredParameters)
|
||||||
|
WriteType(param.ParameterType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteTypeName(TypeInfo type)
|
||||||
|
{
|
||||||
|
if (type.HasElementType)
|
||||||
|
type = type.ElementType;
|
||||||
|
|
||||||
|
WriteName(type.Namespace);
|
||||||
|
|
||||||
|
if (type.DeclaringType != null)
|
||||||
|
WriteIdentifier(type.DeclaringType.Name);
|
||||||
|
|
||||||
|
WriteIdentifier(type.CSharpBaseName);
|
||||||
|
WriteGenericParams(type.GenericTypeArguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteType(TypeInfo type)
|
||||||
|
{
|
||||||
|
if (type.FullName == "System.Void")
|
||||||
|
{
|
||||||
|
_sb.Append('v');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.IsByRef)
|
||||||
|
_sb.Append('R');
|
||||||
|
|
||||||
|
if (type.IsPointer)
|
||||||
|
_sb.Append('P');
|
||||||
|
|
||||||
|
if (type.IsArray)
|
||||||
|
_sb.Append("A_");
|
||||||
|
|
||||||
|
if (type.IsPrimitive && type.Name != "Decimal")
|
||||||
|
{
|
||||||
|
if (type.Name is "IntPtr" or "UIntPtr")
|
||||||
|
_sb.Append("Pv"); // void*
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_sb.Append(type.Name switch
|
||||||
|
{
|
||||||
|
"Boolean" => 'b',
|
||||||
|
"Byte" => 'h',
|
||||||
|
"SByte" => 'a',
|
||||||
|
"Int16" => 's',
|
||||||
|
"UInt16" => 't',
|
||||||
|
"Int32" => 'i',
|
||||||
|
"UInt32" => 'j',
|
||||||
|
"Int64" => 'l',
|
||||||
|
"UInt64" => 'm',
|
||||||
|
"Char" => 'w',
|
||||||
|
"Single" => 'f',
|
||||||
|
"Double" => 'd',
|
||||||
|
_ => throw new UnreachableException()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BeginName();
|
||||||
|
WriteTypeName(type);
|
||||||
|
WriteEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteGenericParams(TypeInfo[] generics)
|
||||||
|
{
|
||||||
|
if (generics.Length > 0)
|
||||||
|
{
|
||||||
|
BeginGenerics();
|
||||||
|
|
||||||
|
foreach (var arg in generics)
|
||||||
|
WriteType(arg);
|
||||||
|
|
||||||
|
WriteEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteIdentifier(string identifier)
|
||||||
|
{
|
||||||
|
_sb.Append(identifier.Length);
|
||||||
|
_sb.Append(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteName(string name)
|
||||||
|
{
|
||||||
|
foreach (var part in name.Split("."))
|
||||||
|
{
|
||||||
|
if (part.Length > 0)
|
||||||
|
WriteIdentifier(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BeginName()
|
||||||
|
{
|
||||||
|
_sb.Append('N');
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BeginGenerics()
|
||||||
|
{
|
||||||
|
_sb.Append('I');
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteEnd()
|
||||||
|
{
|
||||||
|
_sb.Append('E');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -273,7 +273,8 @@ namespace Il2CppInspector
|
|||||||
attsByToken.Add(token, index);
|
attsByToken.Add(token, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeIndicesByToken.Add(image.customAttributeStart, attsByToken);
|
if (attsByToken.Count > 0)
|
||||||
|
AttributeIndicesByToken.Add(image.customAttributeStart, attsByToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,45 +1,50 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
|
Copyright 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
|
||||||
|
Copyright 2023 LukeFZ - https://github.com/LukeFZ
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Il2CppInspector.Cpp;
|
using System.Diagnostics;
|
||||||
using Il2CppInspector.Reflection;
|
using Il2CppInspector.Cpp;
|
||||||
|
using Il2CppInspector.Reflection;
|
||||||
namespace Il2CppInspector.Model
|
using System.Text;
|
||||||
{
|
|
||||||
// Class that represents a composite IL/C++ method
|
namespace Il2CppInspector.Model
|
||||||
public class AppMethod
|
{
|
||||||
{
|
// Class that represents a composite IL/C++ method
|
||||||
// The logical group this method is part of
|
public class AppMethod
|
||||||
// This is purely for querying methods in related groups and has no bearing on the code
|
{
|
||||||
public string Group { get; set; }
|
// The logical group this method is part of
|
||||||
|
// This is purely for querying methods in related groups and has no bearing on the code
|
||||||
// The corresponding C++ function pointer type
|
public string Group { get; set; }
|
||||||
public CppFnPtrType CppFnPtrType { get; internal set; }
|
|
||||||
|
// The corresponding C++ function pointer type
|
||||||
// The corresponding .NET method
|
public CppFnPtrType CppFnPtrType { get; internal set; }
|
||||||
public MethodBase Method { get; internal set; }
|
|
||||||
|
// The corresponding .NET method
|
||||||
// The VA of the MethodInfo* (VA of the pointer to the MethodInfo) object which defines this method
|
public MethodBase Method { get; internal set; }
|
||||||
// Methods not referenced by the binary will be 0xffffffff_ffffffff
|
|
||||||
public ulong MethodInfoPtrAddress { get; internal set; }
|
// The VA of the MethodInfo* (VA of the pointer to the MethodInfo) object which defines this method
|
||||||
|
// Methods not referenced by the binary will be 0xffffffff_ffffffff
|
||||||
// The VA of the method code itself
|
public ulong MethodInfoPtrAddress { get; internal set; }
|
||||||
// Generic method definitions do not have a code address but may have a reference above
|
|
||||||
public ulong MethodCodeAddress => Method.VirtualAddress?.Start ?? 0xffffffff_ffffffff;
|
// The VA of the method code itself
|
||||||
|
// Generic method definitions do not have a code address but may have a reference above
|
||||||
// Helpers
|
public ulong MethodCodeAddress => Method.VirtualAddress?.Start ?? 0xffffffff_ffffffff;
|
||||||
public bool HasMethodInfo => MethodInfoPtrAddress != 0xffffffff_ffffffff;
|
|
||||||
public bool HasCompiledCode => Method.VirtualAddress.HasValue && Method.VirtualAddress.Value.Start != 0;
|
// Helpers
|
||||||
|
public bool HasMethodInfo => MethodInfoPtrAddress != 0xffffffff_ffffffff;
|
||||||
public AppMethod(MethodBase method, CppFnPtrType cppMethod, ulong methodInfoPtr = 0xffffffff_ffffffff) {
|
public bool HasCompiledCode => Method.VirtualAddress.HasValue && Method.VirtualAddress.Value.Start != 0;
|
||||||
Method = method;
|
|
||||||
CppFnPtrType = cppMethod;
|
public AppMethod(MethodBase method, CppFnPtrType cppMethod, ulong methodInfoPtr = 0xffffffff_ffffffff) {
|
||||||
MethodInfoPtrAddress = methodInfoPtr;
|
Method = method;
|
||||||
}
|
CppFnPtrType = cppMethod;
|
||||||
|
MethodInfoPtrAddress = methodInfoPtr;
|
||||||
public override string ToString() => CppFnPtrType.ToSignatureString();
|
}
|
||||||
}
|
|
||||||
}
|
public override string ToString() => CppFnPtrType.ToSignatureString();
|
||||||
|
|
||||||
|
public string ToMangledString() => MangledNameBuilder.Method(Method);
|
||||||
|
public string ToMangledMethodInfoString() => MangledNameBuilder.MethodInfo(Method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ namespace Il2CppInspector.Model
|
|||||||
// For il2cpp < 19, the key is the string literal ordinal instead of the address
|
// For il2cpp < 19, the key is the string literal ordinal instead of the address
|
||||||
public Dictionary<ulong, string> Strings { get; } = [];
|
public Dictionary<ulong, string> Strings { get; } = [];
|
||||||
|
|
||||||
public Dictionary<ulong, (string Name, string Value)> Fields { get; } = [];
|
public Dictionary<ulong, (FieldInfo Field, string Value)> Fields { get; } = [];
|
||||||
public Dictionary<ulong, (string Name, string Value)> FieldRvas { get; } = [];
|
public Dictionary<ulong, (FieldInfo Field, string Value)> FieldRvas { get; } = [];
|
||||||
|
|
||||||
public bool StringIndexesAreOrdinals => Package.Version < 19;
|
public bool StringIndexesAreOrdinals => Package.Version < 19;
|
||||||
|
|
||||||
@@ -254,10 +254,6 @@ namespace Il2CppInspector.Model
|
|||||||
var fieldType = TypeModel.GetMetadataUsageType(usage);
|
var fieldType = TypeModel.GetMetadataUsageType(usage);
|
||||||
var field = fieldType.DeclaredFields.First(f => f.Index == fieldType.Definition.fieldStart + fieldRef.fieldIndex);
|
var field = fieldType.DeclaredFields.First(f => f.Index == fieldType.Definition.fieldStart + fieldRef.fieldIndex);
|
||||||
|
|
||||||
var name = usage.Type == MetadataUsageType.FieldInfo
|
|
||||||
? $"{fieldType.Name}.{field.Name}".ToCIdentifier()
|
|
||||||
: $"{fieldType.Name}.{field.Name}_FieldRva".ToCIdentifier();
|
|
||||||
|
|
||||||
var value = field.HasFieldRVA
|
var value = field.HasFieldRVA
|
||||||
? Convert.ToHexString(Package.Metadata.ReadBytes(
|
? Convert.ToHexString(Package.Metadata.ReadBytes(
|
||||||
(long) field.DefaultValueMetadataAddress, field.FieldType.Sizes.nativeSize))
|
(long) field.DefaultValueMetadataAddress, field.FieldType.Sizes.nativeSize))
|
||||||
@@ -265,9 +261,9 @@ namespace Il2CppInspector.Model
|
|||||||
|
|
||||||
|
|
||||||
if (usage.Type == MetadataUsageType.FieldInfo)
|
if (usage.Type == MetadataUsageType.FieldInfo)
|
||||||
Fields[usage.VirtualAddress] = (name, value);
|
Fields[usage.VirtualAddress] = (field, value);
|
||||||
else
|
else
|
||||||
FieldRvas[usage.VirtualAddress] = (name, value);
|
FieldRvas[usage.VirtualAddress] = (field, value);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -345,11 +341,8 @@ namespace Il2CppInspector.Model
|
|||||||
// Get the address map for the model
|
// Get the address map for the model
|
||||||
// This takes a while to construct so we only build it if requested
|
// This takes a while to construct so we only build it if requested
|
||||||
private AddressMap addressMap;
|
private AddressMap addressMap;
|
||||||
public AddressMap GetAddressMap() {
|
public AddressMap GetAddressMap()
|
||||||
if (addressMap == null)
|
=> addressMap ??= new AddressMap(this);
|
||||||
addressMap = new AddressMap(this);
|
|
||||||
return addressMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the byte offset in Il2CppClass for this app's Unity version to the vtable
|
// Get the byte offset in Il2CppClass for this app's Unity version to the vtable
|
||||||
public int GetVTableOffset() => CppTypeCollection.GetComplexType("Il2CppClass")["vtable"].OffsetBytes;
|
public int GetVTableOffset() => CppTypeCollection.GetComplexType("Il2CppClass")["vtable"].OffsetBytes;
|
||||||
|
|||||||
@@ -1,52 +1,56 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
|
Copyright 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Il2CppInspector.Cpp;
|
using Il2CppInspector.Cpp;
|
||||||
using Il2CppInspector.Reflection;
|
using Il2CppInspector.Reflection;
|
||||||
|
|
||||||
namespace Il2CppInspector.Model
|
namespace Il2CppInspector.Model
|
||||||
{
|
{
|
||||||
// Class that represents a composite IL/C++ type
|
// Class that represents a composite IL/C++ type
|
||||||
public class AppType
|
public class AppType
|
||||||
{
|
{
|
||||||
// The logical group this type is part of
|
// The logical group this type is part of
|
||||||
// This is purely for querying types in related groups and has no bearing on the code
|
// This is purely for querying types in related groups and has no bearing on the code
|
||||||
public string Group { get; set; }
|
public string Group { get; set; }
|
||||||
|
|
||||||
// The corresponding C++ type definition which represents an instance of the object
|
// The corresponding C++ type definition which represents an instance of the object
|
||||||
// This is derived from Il2CppObject
|
// This is derived from Il2CppObject
|
||||||
// If the underlying .NET type is a struct (value type), this will return the boxed version
|
// If the underlying .NET type is a struct (value type), this will return the boxed version
|
||||||
public CppComplexType CppType { get; internal set; }
|
public CppComplexType CppType { get; internal set; }
|
||||||
|
|
||||||
// For an underlying .NET type which is a struct (value type), the unboxed type, otherwise null
|
// For an underlying .NET type which is a struct (value type), the unboxed type, otherwise null
|
||||||
public CppComplexType CppValueType { get; internal set; }
|
public CppComplexType CppValueType { get; internal set; }
|
||||||
|
|
||||||
// The type in the .NET type model this object maps to
|
// The type in the .NET type model this object maps to
|
||||||
public TypeInfo Type { get; internal set; }
|
public TypeInfo Type { get; internal set; }
|
||||||
|
|
||||||
// The VA of the Il2CppClass object which defines this type (ClassName__TypeInfo)
|
// The VA of the Il2CppClass object which defines this type (ClassName__TypeInfo)
|
||||||
public ulong TypeClassAddress { get; internal set; }
|
public ulong TypeClassAddress { get; internal set; }
|
||||||
|
|
||||||
// The VA of the Il2CppType* (VA of the pointer to the Il2CppType) object which references this type (ClassName__TypeRef)
|
// The VA of the Il2CppType* (VA of the pointer to the Il2CppType) object which references this type (ClassName__TypeRef)
|
||||||
public ulong TypeRefPtrAddress { get; internal set; }
|
public ulong TypeRefPtrAddress { get; internal set; }
|
||||||
|
|
||||||
public AppType(TypeInfo ilType, CppComplexType cppType, CppComplexType valueType = null,
|
public AppType(TypeInfo ilType, CppComplexType cppType, CppComplexType valueType = null,
|
||||||
ulong cppClassPtr = 0xffffffff_ffffffff, ulong cppTypeRefPtr = 0xffffffff_ffffffff) {
|
ulong cppClassPtr = 0xffffffff_ffffffff, ulong cppTypeRefPtr = 0xffffffff_ffffffff) {
|
||||||
CppType = cppType;
|
CppType = cppType;
|
||||||
Type = ilType;
|
Type = ilType;
|
||||||
CppValueType = valueType;
|
CppValueType = valueType;
|
||||||
TypeClassAddress = cppClassPtr;
|
TypeClassAddress = cppClassPtr;
|
||||||
TypeRefPtrAddress = cppTypeRefPtr;
|
TypeRefPtrAddress = cppTypeRefPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The C++ name of the type
|
// The C++ name of the type
|
||||||
// TODO: Known issue here where we should be using CppDeclarationGenerator.TypeNamer to ensure uniqueness
|
// TODO: Known issue here where we should be using CppDeclarationGenerator.TypeNamer to ensure uniqueness
|
||||||
// Prefer Foo over Foo__Boxed; if there is no C++ type defined, just convert the IL type to a C identifier
|
// Prefer Foo over Foo__Boxed; if there is no C++ type defined, just convert the IL type to a C identifier
|
||||||
public string Name => CppValueType?.Name ?? CppType?.Name ?? Type.Name.ToCIdentifier();
|
public string Name => CppValueType?.Name ?? CppType?.Name ?? Type.Name.ToCIdentifier();
|
||||||
|
|
||||||
public override string ToString() => Type.FullName + " -> " + CppType.Name;
|
public override string ToString() => Type.FullName + " -> " + CppType.Name;
|
||||||
}
|
|
||||||
|
public string ToMangledTypeInfoString() => MangledNameBuilder.TypeInfo(Type);
|
||||||
|
|
||||||
|
public string ToMangledTypeRefString() => MangledNameBuilder.TypeRef(Type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
""");
|
""");
|
||||||
|
|
||||||
if (_useBetterArraySize)
|
if (_useBetterArraySize)
|
||||||
writeCode("#define il2cpp_array_size_t actual_il2cpp_array_size_t");
|
writeCode("#define actual_il2cpp_array_size_t il2cpp_array_size_t");
|
||||||
|
|
||||||
writeSectionHeader("IL2CPP internal types");
|
writeSectionHeader("IL2CPP internal types");
|
||||||
writeCode(_model.UnityHeaders.GetTypeHeaderText(_model.WordSizeBits));
|
writeCode(_model.UnityHeaders.GetTypeHeaderText(_model.WordSizeBits));
|
||||||
@@ -82,7 +82,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
actual_il2cpp_array_size_t value;
|
actual_il2cpp_array_size_t value;
|
||||||
} better_il2cpp_array_size_t;
|
} better_il2cpp_array_size_t;
|
||||||
|
|
||||||
#define il2cpp_array_size_t better_il2cpp_array_size_t
|
#define better_il2cpp_array_size_t il2cpp_array_size_t
|
||||||
""");
|
""");
|
||||||
|
|
||||||
if (_model.TargetCompiler == CppCompilerType.MSVC)
|
if (_model.TargetCompiler == CppCompilerType.MSVC)
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
private void writeMethods(IEnumerable<AppMethod> methods) {
|
private void writeMethods(IEnumerable<AppMethod> methods) {
|
||||||
foreach (var method in methods.Where(m => m.HasCompiledCode)) {
|
foreach (var method in methods.Where(m => m.HasCompiledCode)) {
|
||||||
writeObject(() => {
|
writeObject(() => {
|
||||||
writeTypedFunctionName(method.MethodCodeAddress, method.CppFnPtrType.ToSignatureString(), method.CppFnPtrType.Name);
|
writeTypedFunctionName(method.MethodCodeAddress, method.CppFnPtrType.ToSignatureString(), method.ToMangledString());
|
||||||
writeDotNetSignature(method.Method);
|
writeDotNetSignature(method.Method);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -105,7 +105,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
|
|
||||||
if (type.TypeClassAddress != 0xffffffff_ffffffff) {
|
if (type.TypeClassAddress != 0xffffffff_ffffffff) {
|
||||||
writeObject(() => {
|
writeObject(() => {
|
||||||
writeTypedName(type.TypeClassAddress, $"struct {type.Name}__Class *", $"{type.Name}__TypeInfo");
|
writeTypedName(type.TypeClassAddress, $"struct {type.Name}__Class *", type.ToMangledTypeInfoString());
|
||||||
writeDotNetTypeName(type.Type);
|
writeDotNetTypeName(type.Type);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
if (type.TypeRefPtrAddress != 0xffffffff_ffffffff) {
|
if (type.TypeRefPtrAddress != 0xffffffff_ffffffff) {
|
||||||
writeObject(() => {
|
writeObject(() => {
|
||||||
// A generic type definition does not have any direct C++ types, but may have a reference
|
// A generic type definition does not have any direct C++ types, but may have a reference
|
||||||
writeName(type.TypeRefPtrAddress, $"{type.Name}__TypeRef");
|
writeName(type.TypeRefPtrAddress, type.ToMangledTypeRefString());
|
||||||
writeDotNetTypeName(type.Type);
|
writeDotNetTypeName(type.Type);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
() => {
|
() => {
|
||||||
foreach (var method in model.Methods.Values.Where(m => m.HasMethodInfo)) {
|
foreach (var method in model.Methods.Values.Where(m => m.HasMethodInfo)) {
|
||||||
writeObject(() => {
|
writeObject(() => {
|
||||||
writeName(method.MethodInfoPtrAddress, $"{method.CppFnPtrType.Name}__MethodInfo");
|
writeName(method.MethodInfoPtrAddress, method.ToMangledMethodInfoString());
|
||||||
writeDotNetSignature(method.Method);
|
writeDotNetSignature(method.Method);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -221,13 +221,13 @@ namespace Il2CppInspector.Outputs
|
|||||||
writeArray("fields", () =>
|
writeArray("fields", () =>
|
||||||
{
|
{
|
||||||
foreach (var (addr, field) in model.Fields)
|
foreach (var (addr, field) in model.Fields)
|
||||||
writeFieldObject(addr, field.Name, field.Value);
|
writeFieldObject(addr, (field.Field + "_Field").ToCIdentifier(), field.Value);
|
||||||
});
|
});
|
||||||
|
|
||||||
writeArray("fieldRvas", () =>
|
writeArray("fieldRvas", () =>
|
||||||
{
|
{
|
||||||
foreach (var (addr, rva) in model.FieldRvas)
|
foreach (var (addr, rva) in model.FieldRvas)
|
||||||
writeFieldObject(addr, rva.Name, rva.Value);
|
writeFieldObject(addr, (rva.Field + "_FieldRva").ToCIdentifier(), rva.Value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -68,7 +69,9 @@ namespace Il2CppInspector.Reflection {
|
|||||||
public bool IsLiteral => (Attributes & FieldAttributes.Literal) == FieldAttributes.Literal;
|
public bool IsLiteral => (Attributes & FieldAttributes.Literal) == FieldAttributes.Literal;
|
||||||
|
|
||||||
// True if the field has the NonSerialized attribute
|
// True if the field has the NonSerialized attribute
|
||||||
|
#pragma warning disable SYSLIB0050
|
||||||
public bool IsNotSerialized => (Attributes & FieldAttributes.NotSerialized) == FieldAttributes.NotSerialized;
|
public bool IsNotSerialized => (Attributes & FieldAttributes.NotSerialized) == FieldAttributes.NotSerialized;
|
||||||
|
#pragma warning restore SYSLIB0050
|
||||||
|
|
||||||
// True if the field is extern
|
// True if the field is extern
|
||||||
public bool IsPinvokeImpl => (Attributes & FieldAttributes.PinvokeImpl) == FieldAttributes.PinvokeImpl;
|
public bool IsPinvokeImpl => (Attributes & FieldAttributes.PinvokeImpl) == FieldAttributes.PinvokeImpl;
|
||||||
|
|||||||
@@ -702,7 +702,9 @@ namespace Il2CppInspector.Reflection
|
|||||||
public bool IsPrimitive => Namespace == "System" && new[] { "Boolean", "Byte", "SByte", "Int16", "UInt16", "Int32", "UInt32", "Int64", "UInt64", "IntPtr", "UIntPtr", "Char", "Decimal", "Double", "Single" }.Contains(Name);
|
public bool IsPrimitive => Namespace == "System" && new[] { "Boolean", "Byte", "SByte", "Int16", "UInt16", "Int32", "UInt32", "Int64", "UInt64", "IntPtr", "UIntPtr", "Char", "Decimal", "Double", "Single" }.Contains(Name);
|
||||||
public bool IsPublic => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public;
|
public bool IsPublic => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public;
|
||||||
public bool IsSealed => (Attributes & TypeAttributes.Sealed) == TypeAttributes.Sealed;
|
public bool IsSealed => (Attributes & TypeAttributes.Sealed) == TypeAttributes.Sealed;
|
||||||
|
#pragma warning disable SYSLIB0050
|
||||||
public bool IsSerializable => (Attributes & TypeAttributes.Serializable) == TypeAttributes.Serializable;
|
public bool IsSerializable => (Attributes & TypeAttributes.Serializable) == TypeAttributes.Serializable;
|
||||||
|
#pragma warning restore SYSLIB0050
|
||||||
public bool IsSpecialName => (Attributes & TypeAttributes.SpecialName) == TypeAttributes.SpecialName;
|
public bool IsSpecialName => (Attributes & TypeAttributes.SpecialName) == TypeAttributes.SpecialName;
|
||||||
public bool IsValueType => BaseType?.FullName == "System.ValueType";
|
public bool IsValueType => BaseType?.FullName == "System.ValueType";
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ This is a continuation of [Il2CppInspector, by djkaty](https://github.com/djkaty
|
|||||||
* Support for [ThreadStatic] static fields
|
* Support for [ThreadStatic] static fields
|
||||||
* Better heuristic for detecting metadata usages
|
* Better heuristic for detecting metadata usages
|
||||||
* Performance improvements
|
* Performance improvements
|
||||||
|
* Slight IDA/Ghidra script improvements:
|
||||||
|
- Made ValueTypes use their non-boxed variants when used as the this parameter
|
||||||
|
- Added labeling of FieldInfo/FieldRva MetadataUsages and their respective values as comments
|
||||||
|
- Implemented name mangling to properly display generics and other normally-replaced characters
|
||||||
|
|
||||||
### Main features
|
### Main features
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user