Add FieldRva MetadataUsage type and fix current heuristic
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using Il2CppInspector.Utils;
|
||||
using NoisyCowStudios.Bin2Object;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -184,69 +185,29 @@ namespace Il2CppInspector
|
||||
var encodedToken = (uint)metadataValue;
|
||||
var usage = MetadataUsage.FromEncodedIndex(this, encodedToken);
|
||||
|
||||
if (usage.Type > 0
|
||||
&& usage.Type <= MetadataUsageType.MethodRef
|
||||
&& metadataValue == (((uint)usage.Type << 29) | ((uint)usage.SourceIndex << 1)) + 1
|
||||
if (CheckMetadataUsageSanity(usage)
|
||||
&& BinaryImage.TryMapFileOffsetToVA(i * ((uint)BinaryImage.Bits / 8), out var va))
|
||||
{
|
||||
usages.Add(MetadataUsage.FromEncodedIndex(this, encodedToken, va));
|
||||
usage.SetAddress(va);
|
||||
usages.Add(usage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return usages;
|
||||
|
||||
/*BinaryImage.Position = 0;
|
||||
var sequenceLength = 0;
|
||||
var threshold = 6000; // current versions of mscorlib generate about 6000-7000 metadata usages
|
||||
var usagesCount = 0;
|
||||
|
||||
var words = BinaryImage.ReadArray<ulong>(0, (int) BinaryImage.Length / (BinaryImage.Bits / 8));
|
||||
|
||||
// Scan the image looking for a sequential block of at least 'threshold' valid metadata tokens
|
||||
int pos;
|
||||
for (pos = 0; pos < words.Length && (usagesCount == 0 || sequenceLength > 0); pos++) {
|
||||
var word = words[pos];
|
||||
|
||||
if (word % 2 != 1 || word >> 32 != 0) {
|
||||
sequenceLength = 0;
|
||||
continue;
|
||||
bool CheckMetadataUsageSanity(MetadataUsage usage)
|
||||
{
|
||||
return usage.Type switch
|
||||
{
|
||||
MetadataUsageType.TypeInfo or MetadataUsageType.Type => TypeReferences.Count > usage.SourceIndex,
|
||||
MetadataUsageType.MethodDef => Methods.Length > usage.SourceIndex,
|
||||
MetadataUsageType.FieldInfo or MetadataUsageType.FieldRva => FieldRefs.Length > usage.SourceIndex,
|
||||
MetadataUsageType.StringLiteral => StringLiterals.Length > usage.SourceIndex,
|
||||
MetadataUsageType.MethodRef => MethodSpecs.Length > usage.SourceIndex,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
var potentialUsage = MetadataUsage.FromEncodedIndex(this, (uint) word);
|
||||
switch (potentialUsage.Type) {
|
||||
case MetadataUsageType.Type:
|
||||
case MetadataUsageType.TypeInfo:
|
||||
case MetadataUsageType.MethodDef:
|
||||
case MetadataUsageType.MethodRef:
|
||||
case MetadataUsageType.FieldInfo:
|
||||
case MetadataUsageType.StringLiteral:
|
||||
sequenceLength++;
|
||||
|
||||
if (sequenceLength >= threshold)
|
||||
usagesCount = sequenceLength;
|
||||
break;
|
||||
default:
|
||||
sequenceLength = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a block, read all the tokens and map them with their VAs to MetadataUsage objects
|
||||
if (usagesCount > 0) {
|
||||
var wordSize = BinaryImage.Bits / 8;
|
||||
var pMetadataUsages = (uint) (pos * wordSize - (usagesCount + 1) * wordSize);
|
||||
var pMetadataUsagesVA = BinaryImage.MapFileOffsetToVA(pMetadataUsages);
|
||||
var usageTokens = BinaryImage.ReadWordArray(pMetadataUsages, usagesCount);
|
||||
var usages = usageTokens.Zip(Enumerable.Range(0, usagesCount)
|
||||
.Select(a => pMetadataUsagesVA + (ulong) (a * wordSize)), (t, a) => MetadataUsage.FromEncodedIndex(this, (uint) t, a));
|
||||
|
||||
Console.WriteLine("Late binding metadata usage block found successfully for metadata v27");
|
||||
return usages.ToList();
|
||||
}
|
||||
|
||||
Console.WriteLine("Late binding metadata usage block could not be auto-detected - metadata usage references will not be available for this project");
|
||||
return null;*/
|
||||
}
|
||||
|
||||
// Thumb instruction pointers have the bottom bit set to signify a switch from ARM to Thumb when jumping
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Il2CppInspector
|
||||
FieldInfo = 4,
|
||||
StringLiteral = 5,
|
||||
MethodRef = 6,
|
||||
FieldRva = 7
|
||||
}
|
||||
|
||||
public class MetadataUsage
|
||||
|
||||
@@ -210,38 +210,28 @@ namespace Il2CppInspector.Model
|
||||
|
||||
switch (usage.Type) {
|
||||
case MetadataUsageType.StringLiteral:
|
||||
//if (usage.SourceIndex >= TypeModel.Package.Metadata.StringLiterals.Length)
|
||||
// break;
|
||||
|
||||
var str = TypeModel.GetMetadataUsageName(usage);
|
||||
Strings.Add(address, str);
|
||||
break;
|
||||
|
||||
case MetadataUsageType.Type:
|
||||
case MetadataUsageType.TypeInfo:
|
||||
//if (usage.SourceIndex >= TypeModel.TypesByReferenceIndex.Length)
|
||||
// break;
|
||||
|
||||
case MetadataUsageType.Type or MetadataUsageType.TypeInfo:
|
||||
var type = TypeModel.GetMetadataUsageType(usage);
|
||||
declarationGenerator.IncludeType(type);
|
||||
AddTypes(declarationGenerator.GenerateRemainingTypeDeclarations());
|
||||
|
||||
if (!Types.ContainsKey(type))
|
||||
// Generic type definition has no associated C++ type, therefore no dictionary sub-key
|
||||
Types.Add(type, new AppType(type, null) { Group = Group });
|
||||
|
||||
if (usage.Type == MetadataUsageType.TypeInfo)
|
||||
// Regular type definition
|
||||
Types[type].TypeClassAddress = address;
|
||||
|
||||
else if (!Types.ContainsKey(type))
|
||||
// Generic type definition has no associated C++ type, therefore no dictionary sub-key
|
||||
Types.Add(type, new AppType(type, null, cppTypeRefPtr: address) { Group = Group });
|
||||
else
|
||||
// Regular type reference
|
||||
Types[type].TypeRefPtrAddress = address;
|
||||
break;
|
||||
case MetadataUsageType.MethodDef:
|
||||
case MetadataUsageType.MethodRef:
|
||||
//if (usage.SourceIndex > TypeModel.Package.Metadata.Methods.Length)
|
||||
// break;
|
||||
|
||||
break;
|
||||
case MetadataUsageType.MethodDef or MetadataUsageType.MethodRef:
|
||||
var method = TypeModel.GetMetadataUsageMethod(usage);
|
||||
declarationGenerator.IncludeMethod(method);
|
||||
AddTypes(declarationGenerator.GenerateRemainingTypeDeclarations());
|
||||
@@ -256,14 +246,18 @@ namespace Il2CppInspector.Model
|
||||
Methods[method].MethodInfoPtrAddress = address;
|
||||
break;
|
||||
|
||||
case MetadataUsageType.FieldInfo:
|
||||
if (usage.SourceIndex > TypeModel.Package.Metadata.FieldRefs.Length)
|
||||
break;
|
||||
|
||||
case MetadataUsageType.FieldInfo or MetadataUsageType.FieldRva:
|
||||
var fieldRef = TypeModel.Package.FieldRefs[usage.SourceIndex];
|
||||
var fieldType = TypeModel.GetMetadataUsageType(usage);
|
||||
var field = fieldType.DeclaredFields.First(f => f.Index == fieldType.Definition.fieldStart + fieldRef.fieldIndex);
|
||||
|
||||
if (usage.Type == MetadataUsageType.FieldInfo)
|
||||
Fields.Add(usage.VirtualAddress, $"{fieldType.Name}.{field.Name}".ToCIdentifier());
|
||||
else
|
||||
{
|
||||
var defaultValue = Package.FieldDefaultValue[field.Index];
|
||||
// TODO: Unsure what it could be used for here. Maybe PID array initializers?
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,18 +344,21 @@ namespace Il2CppInspector.Reflection
|
||||
type = GetMetadataUsageType(usage);
|
||||
method = GetMetadataUsageMethod(usage);
|
||||
return $"{type.Name}.{method.Name}";
|
||||
|
||||
case MetadataUsageType.FieldRva:
|
||||
fieldRef = Package.FieldRefs[usage.SourceIndex];
|
||||
type = GetMetadataUsageType(usage);
|
||||
field = type.DeclaredFields.First(f => f.Index == type.Definition.fieldStart + fieldRef.fieldIndex);
|
||||
return $"{type.Name}.{field.Name}_Default"; // TODO: Find out if this is really needed for anything
|
||||
}
|
||||
throw new NotImplementedException("Unknown metadata usage type: " + usage.Type);
|
||||
}
|
||||
|
||||
// Get the type used in a metadata usage
|
||||
public TypeInfo GetMetadataUsageType(MetadataUsage usage) => usage.Type switch {
|
||||
MetadataUsageType.Type => TypesByReferenceIndex[usage.SourceIndex],
|
||||
MetadataUsageType.TypeInfo => TypesByReferenceIndex[usage.SourceIndex],
|
||||
MetadataUsageType.MethodDef => GetMetadataUsageMethod(usage).DeclaringType,
|
||||
MetadataUsageType.FieldInfo => TypesByReferenceIndex[Package.FieldRefs[usage.SourceIndex].typeIndex],
|
||||
MetadataUsageType.MethodRef => GetMetadataUsageMethod(usage).DeclaringType,
|
||||
|
||||
MetadataUsageType.Type or MetadataUsageType.TypeInfo => TypesByReferenceIndex[usage.SourceIndex],
|
||||
MetadataUsageType.MethodDef or MetadataUsageType.MethodRef => GetMetadataUsageMethod(usage).DeclaringType,
|
||||
MetadataUsageType.FieldInfo or MetadataUsageType.FieldRva => TypesByReferenceIndex[Package.FieldRefs[usage.SourceIndex].typeIndex],
|
||||
_ => throw new InvalidOperationException("Incorrect metadata usage type to retrieve referenced type")
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user