forked from djkaty/Il2CppInspector
-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add name mangling to Methods/MethodInfo/TypeInfo/TypeRef, remove Boxi…
…ng from ValueTypes when used as the this parameter, fix crashes when a module has no attributes
- Loading branch information
Showing
11 changed files
with
335 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,50 @@ | ||
/* | ||
Copyright 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty | ||
All rights reserved. | ||
*/ | ||
|
||
using Il2CppInspector.Cpp; | ||
using Il2CppInspector.Reflection; | ||
|
||
namespace Il2CppInspector.Model | ||
{ | ||
// Class that represents a composite IL/C++ method | ||
public class AppMethod | ||
{ | ||
// The logical group this method is part of | ||
// This is purely for querying methods in related groups and has no bearing on the code | ||
public string Group { get; set; } | ||
|
||
// The corresponding C++ function pointer type | ||
public CppFnPtrType CppFnPtrType { get; internal set; } | ||
|
||
// The corresponding .NET method | ||
public MethodBase Method { 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 | ||
public ulong MethodInfoPtrAddress { get; internal set; } | ||
|
||
// The VA of the method code itself | ||
// Generic method definitions do not have a code address but may have a reference above | ||
public ulong MethodCodeAddress => Method.VirtualAddress?.Start ?? 0xffffffff_ffffffff; | ||
|
||
// Helpers | ||
public bool HasMethodInfo => MethodInfoPtrAddress != 0xffffffff_ffffffff; | ||
public bool HasCompiledCode => Method.VirtualAddress.HasValue && Method.VirtualAddress.Value.Start != 0; | ||
|
||
public AppMethod(MethodBase method, CppFnPtrType cppMethod, ulong methodInfoPtr = 0xffffffff_ffffffff) { | ||
Method = method; | ||
CppFnPtrType = cppMethod; | ||
MethodInfoPtrAddress = methodInfoPtr; | ||
} | ||
|
||
public override string ToString() => CppFnPtrType.ToSignatureString(); | ||
} | ||
} | ||
/* | ||
Copyright 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty | ||
Copyright 2023 LukeFZ - https://github.com/LukeFZ | ||
All rights reserved. | ||
*/ | ||
|
||
using System.Diagnostics; | ||
using Il2CppInspector.Cpp; | ||
using Il2CppInspector.Reflection; | ||
using System.Text; | ||
|
||
namespace Il2CppInspector.Model | ||
{ | ||
// Class that represents a composite IL/C++ method | ||
public class AppMethod | ||
{ | ||
// The logical group this method is part of | ||
// This is purely for querying methods in related groups and has no bearing on the code | ||
public string Group { get; set; } | ||
|
||
// The corresponding C++ function pointer type | ||
public CppFnPtrType CppFnPtrType { get; internal set; } | ||
|
||
// The corresponding .NET method | ||
public MethodBase Method { 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 | ||
public ulong MethodInfoPtrAddress { get; internal set; } | ||
|
||
// The VA of the method code itself | ||
// Generic method definitions do not have a code address but may have a reference above | ||
public ulong MethodCodeAddress => Method.VirtualAddress?.Start ?? 0xffffffff_ffffffff; | ||
|
||
// Helpers | ||
public bool HasMethodInfo => MethodInfoPtrAddress != 0xffffffff_ffffffff; | ||
public bool HasCompiledCode => Method.VirtualAddress.HasValue && Method.VirtualAddress.Value.Start != 0; | ||
|
||
public AppMethod(MethodBase method, CppFnPtrType cppMethod, ulong methodInfoPtr = 0xffffffff_ffffffff) { | ||
Method = method; | ||
CppFnPtrType = cppMethod; | ||
MethodInfoPtrAddress = methodInfoPtr; | ||
} | ||
|
||
public override string ToString() => CppFnPtrType.ToSignatureString(); | ||
|
||
public string ToMangledString() => MangledNameBuilder.Method(Method); | ||
public string ToMangledMethodInfoString() => MangledNameBuilder.MethodInfo(Method); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.