Files
RedHotRoast-ios/HybridCLRData/LocalIl2CppData-OSXEditor/il2cpp/libil2cpp/hybridclr/metadata/RawImageBase.h
T
2026-07-17 14:03:00 +08:00

423 lines
12 KiB
C++

#pragma once
#include "../CommonDef.h"
#include "vm/String.h"
#include "MetadataDef.h"
#include "BlobReader.h"
#include "MetadataUtil.h"
namespace hybridclr
{
namespace metadata
{
enum class LoadImageErrorCode
{
OK = 0,
BAD_IMAGE,
NOT_IMPLEMENT,
AOT_ASSEMBLY_NOT_FIND,
HOMOLOGOUS_ONLY_SUPPORT_AOT_ASSEMBLY,
HOMOLOGOUS_ASSEMBLY_HAS_BEEN_LOADED,
INVALID_HOMOLOGOUS_MODE,
PDB_BAD_FILE,
UNKNOWN_IMAGE_FORMAT,
UNSUPPORT_FORMAT_VERSION,
UNMATCH_FORMAT_VARIANT,
};
class RawImageBase
{
public:
RawImageBase() : _imageData(nullptr), _imageLength(0), _ptrRawDataEnd(nullptr),
_streamStringHeap{}, _streamUS{}, _streamBlobHeap{}, _streamGuidHeap{}, _streamTables{},
_4byteStringIndex(false), _4byteGUIDIndex(false), _4byteBlobIndex(false)
{
}
virtual ~RawImageBase()
{
if (_imageData)
{
HYBRIDCLR_FREE((void*)_imageData);
_imageData = nullptr;
}
}
virtual LoadImageErrorCode Load(const void* imageData, size_t length);
virtual LoadImageErrorCode PostLoadStreams() { return LoadImageErrorCode::OK; }
virtual LoadImageErrorCode PostLoadTables() { return LoadImageErrorCode::OK; }
virtual Il2CppString* GetUserStringBlogByIndex(uint32_t index) const
{
IL2CPP_ASSERT(index >= 0 && (uint32_t)index < _streamUS.size);
const byte* str = _streamUS.data + index;
uint32_t lengthSize;
uint32_t stringLength = BlobReader::ReadCompressedUint32(str, lengthSize);
return CreateUserString((const char*)(str + lengthSize), stringLength);
}
const char* GetStringFromRawIndex(StringIndex index) const
{
IL2CPP_ASSERT(DecodeImageIndex(index) == 0);
IL2CPP_ASSERT(index >= 0 && (uint32_t)index < _streamStringHeap.size);
return (const char*)(_streamStringHeap.data + index);
}
const byte* GetBlobFromRawIndex(StringIndex index) const
{
IL2CPP_ASSERT(DecodeImageIndex(index) == 0);
IL2CPP_ASSERT(index == 0 || (index > 0 && (size_t)index < _streamBlobHeap.size));
return _streamBlobHeap.data + index;
}
const uint8_t* GetFieldOrParameterDefalutValueByRawIndex(uint32_t index) const
{
return _imageData + index;
}
static BlobReader DecodeBlob(const byte* buf)
{
uint32_t sizeLength;
uint32_t length = BlobReader::ReadCompressedUint32(buf, sizeLength);
return BlobReader(buf + sizeLength, length);
}
BlobReader GetBlobReaderByRawIndex(uint32_t rawIndex) const
{
IL2CPP_ASSERT(DecodeImageIndex(rawIndex) == 0);
const byte* buf = _streamBlobHeap.data + rawIndex;
return DecodeBlob(buf);
}
uint32_t GetImageOffsetOfBlob(Il2CppTypeEnum type, uint32_t index) const
{
if (type != IL2CPP_TYPE_STRING)
{
return (uint32_t)(GetBlobReaderByRawIndex(index).GetData() - _imageData);
}
else
{
return (uint32_t)(_streamBlobHeap.data + index - _imageData);
}
}
const byte* GetDataPtrByImageOffset(uint32_t imageOffset) const
{
IL2CPP_ASSERT(imageOffset < _imageLength);
return _imageData + imageOffset;
}
uint32_t GetEntryPointToken() const
{
return _entryPointToken;
}
const Table& GetTable(TableType type) const
{
return _tables[(int)type];
}
uint32_t GetTableRowNum(TableType tableIndex) const
{
return _tables[(int)tableIndex].rowNum;
}
bool TranslateRVAToImageOffset(uint32_t rvaOffset, uint32_t& imageOffset) const
{
for (const SectionHeader& sh : _sections)
{
if (sh.virtualAddressBegin <= rvaOffset && rvaOffset < sh.virtualAddressEnd)
{
imageOffset = sh.ptrRawDataRelatedToVirtualAddress + rvaOffset;
return true;
}
}
return false;
}
virtual LoadImageErrorCode LoadStreamHeaders(uint32_t metadataRva, uint32_t metadataSize);
virtual LoadImageErrorCode ValidateStreams() const;
virtual LoadImageErrorCode LoadTables();
virtual void BuildTableRowMetas();
uint32_t ComputTableRowMetaDataSize(TableType tableIndex) const;
uint32_t ComputStringIndexByte() const
{
return _4byteStringIndex ? 4 : 2;
}
uint32_t ComputGUIDIndexByte() const
{
return _4byteGUIDIndex ? 4 : 2;
}
uint32_t ComputBlobIndexByte() const
{
return _4byteBlobIndex ? 4 : 2;
}
uint32_t ComputTableIndexByte(TableType tableIndex) const
{
return _tables[(int)tableIndex].rowNum < 65536 ? 2 : 4;
}
uint32_t ComputIndexByte(uint32_t maxRowNum, uint32_t tagBitNum) const
{
return (maxRowNum << tagBitNum) < 65536 ? 2 : 4;
}
uint32_t ComputTableIndexByte(TableType t1, TableType t2, uint32_t tagBitNum) const
{
uint32_t n = GetTableRowNum(t1);
n = std::max(n, GetTableRowNum(t2));
return ComputIndexByte(n, tagBitNum);
}
uint32_t ComputTableIndexByte(TableType t1, TableType t2, TableType t3, uint32_t tagBitNum) const
{
uint32_t n = GetTableRowNum(t1);
n = std::max(n, GetTableRowNum(t2));
n = std::max(n, GetTableRowNum(t3));
return ComputIndexByte(n, tagBitNum);
}
uint32_t ComputTableIndexByte(TableType t1, TableType t2, TableType t3, TableType t4, uint32_t tagBitNum) const
{
uint32_t n = GetTableRowNum(t1);
n = std::max(n, GetTableRowNum(t2));
n = std::max(n, GetTableRowNum(t3));
n = std::max(n, GetTableRowNum(t4));
return ComputIndexByte(n, tagBitNum);
}
uint32_t ComputTableIndexByte(TableType t1, TableType t2, TableType t3, TableType t4, TableType t5, uint32_t tagBitNum) const
{
uint32_t n = GetTableRowNum(t1);
n = std::max(n, GetTableRowNum(t2));
n = std::max(n, GetTableRowNum(t3));
n = std::max(n, GetTableRowNum(t4));
n = std::max(n, GetTableRowNum(t5));
return ComputIndexByte(n, tagBitNum);
}
uint32_t ComputTableIndexByte(const TableType* ts, int num, uint32_t tagBitNum) const
{
uint32_t n = 0;
for (int i = 0; i < num; i++)
{
n = std::max(n, GetTableRowNum(ts[i]));
}
return ComputIndexByte(n, tagBitNum);
}
protected:
virtual LoadImageErrorCode LoadCLIHeader(uint32_t& entryPointToken, uint32_t& metadataRva, uint32_t& metadataSize) = 0;
const byte* GetTableRowPtr(TableType type, uint32_t rawIndex) const
{
auto& tb = _tables[(int)type];
IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= tb.rowNum);
return tb.data + tb.rowMetaDataSize * (rawIndex - 1);
}
const std::vector<ColumnOffsetSize>& GetRowSchema(TableType type) const
{
return _tableRowMetas[(int)type];
}
uint32_t ReadColumn(const byte* rowPtr, const ColumnOffsetSize& columnMt) const
{
return ReadColumn(rowPtr, columnMt.offset, columnMt.size);
}
uint32_t ReadColumn(const byte* data, uint32_t offset, uint32_t size) const
{
const byte* dataPtr = data + offset;
switch (size)
{
case 1: return *dataPtr;
case 2: return GetU2LittleEndian(dataPtr);
case 4: return GetU4LittleEndian(dataPtr);
default: IL2CPP_ASSERT(false); return 0;
}
}
void ReadColumn(const byte* rowPtr, const ColumnOffsetSize& columnMt, uint8_t& value) const
{
IL2CPP_ASSERT(columnMt.size == 1);
const byte* dataPtr = rowPtr + columnMt.offset;
value = *dataPtr;
}
void ReadColumn(const byte* rowPtr, const ColumnOffsetSize& columnMt, uint32_t& value) const
{
IL2CPP_ASSERT(columnMt.size == 2 || columnMt.size == 4);
const byte* dataPtr = rowPtr + columnMt.offset;
value = columnMt.size == 2 ? GetU2LittleEndian(dataPtr) : GetU4LittleEndian(dataPtr);
}
static Il2CppString* CreateUserString(const char* str, uint32_t length)
{
if (length == 0)
{
return il2cpp::vm::String::Empty();
}
else
{
IL2CPP_ASSERT(length % 2 == 1);
UserStringEncoding charEncoding = (UserStringEncoding)str[length - 1];
return il2cpp::vm::String::NewUtf16((const Il2CppChar*)str, (length - 1) / 2);
}
}
public:
#define TABLE_BEGIN(name, tableType) virtual Tb##name Read##name(uint32_t rawIndex) \
{ \
IL2CPP_ASSERT(rawIndex > 0 && rawIndex <= GetTable(tableType).rowNum); \
const byte* rowPtr = GetTableRowPtr(tableType, rawIndex); \
auto& rowSchema = GetRowSchema(tableType); \
uint32_t __fieldIndex = 0; \
Tb##name __r = {};
#define __F(fieldName) const ColumnOffsetSize& col_##fieldName = rowSchema[__fieldIndex++]; \
__r.fieldName = ReadColumn(rowPtr, col_##fieldName);
#define TABLE_END return __r; \
}
#define TABLE1(name, tableType, f1) TABLE_BEGIN(name, tableType) \
__F(f1) \
TABLE_END
#define TABLE2(name, tableType, f1, f2) TABLE_BEGIN(name, tableType) \
__F(f1) \
__F(f2) \
TABLE_END
#define TABLE3(name, tableType, f1, f2, f3) TABLE_BEGIN(name, tableType) \
__F(f1) \
__F(f2) \
__F(f3) \
TABLE_END
#define TABLE4(name, tableType, f1, f2, f3, f4) TABLE_BEGIN(name, tableType) \
__F(f1) \
__F(f2) \
__F(f3) \
__F(f4) \
TABLE_END
#define TABLE5(name, tableType, f1, f2, f3, f4, f5) TABLE_BEGIN(name, tableType) \
__F(f1) \
__F(f2) \
__F(f3) \
__F(f4) \
__F(f5) \
TABLE_END
#define TABLE6(name, tableType, f1, f2, f3, f4, f5, f6) TABLE_BEGIN(name, tableType) \
__F(f1) \
__F(f2) \
__F(f3) \
__F(f4) \
__F(f5) \
__F(f6) \
TABLE_END
TABLE5(Module, TableType::MODULE, generation, name, mvid, encid, encBaseId)
TABLE3(TypeRef, TableType::TYPEREF, resolutionScope, typeName, typeNamespace)
TABLE6(TypeDef, TableType::TYPEDEF, flags, typeName, typeNamespace, extends, fieldList, methodList)
TABLE1(TypeSpec, TableType::TYPESPEC, signature);
TABLE4(ImplMap, TableType::IMPLMAP, mappingFlags, memberForwarded, importName, importScope)
TABLE1(ModuleRef, TableType::MODULEREF, name)
TABLE3(Field, TableType::FIELD, flags, name, signature)
TABLE4(GenericParam, TableType::GENERICPARAM, number, flags, owner, name)
TABLE2(GenericParamConstraint, TableType::GENERICPARAMCONSTRAINT, owner, constraint)
TABLE3(MemberRef, TableType::MEMBERREF, classIdx, name, signature)
TABLE1(StandAloneSig, TableType::STANDALONESIG, signature)
TABLE3(MethodImpl, TableType::METHODIMPL, classIdx, methodBody, methodDeclaration)
TABLE2(FieldRVA, TableType::FIELDRVA, rva, field)
TABLE2(FieldLayout, TableType::FIELDLAYOUT, offset, field)
TABLE4(Constant, TableType::CONSTANT, type, padding, parent, value)
TABLE2(MethodSpec, TableType::METHODSPEC, method, instantiation)
TABLE3(CustomAttribute, TableType::CUSTOMATTRIBUTE, parent, type, value)
TABLE2(PropertyMap, TableType::PROPERTYMAP, parent, propertyList)
TABLE3(Property, TableType::PROPERTY, flags, name, type)
TABLE2(EventMap, TableType::EVENTMAP, parent, eventList)
TABLE3(Event, TableType::EVENT, eventFlags, name, eventType)
TABLE3(MethodSemantics, TableType::METHODSEMANTICS, semantics, method, association)
TABLE2(NestedClass, TableType::NESTEDCLASS, nestedClass, enclosingClass)
TABLE6(Method, TableType::METHOD, rva, implFlags, flags, name, signature, paramList)
TABLE3(Param, TableType::PARAM, flags, sequence, name)
TABLE3(ClassLayout, TableType::CLASSLAYOUT, packingSize, classSize, parent)
TABLE2(InterfaceImpl, TableType::INTERFACEIMPL, classIdx, interfaceIdx)
TABLE_BEGIN(Assembly, TableType::ASSEMBLY)
__F(hashAlgId)
__F(majorVersion)
__F(minorVersion)
__F(buildNumber)
__F(revisionNumber)
__F(flags)
__F(publicKey)
__F(name)
__F(locale)
TABLE_END
TABLE_BEGIN(AssemblyRef, TableType::ASSEMBLYREF)
__F(majorVersion)
__F(minorVersion)
__F(buildNumber)
__F(revisionNumber)
__F(flags)
__F(publicKeyOrToken)
__F(name)
__F(locale)
__F(hashValue)
TABLE_END
TABLE4(Document, TableType::DOCUMENT, name, hashAlgorithm, hash, language)
TABLE2(MethodDebugInformation, TableType::METHODDEBUGINFORMATION, document, sequencePoints)
TABLE6(LocalScope, TableType::LOCALSCOPE, method, importScope, variables, constants, startOffset, length)
TABLE3(LocalVariable, TableType::LOCALVARIABLE, attributes, index, name)
TABLE2(LocalConstant, TableType::LOCALCONSTANT, name, signature)
TABLE2(ImportScope, TableType::IMPORTSCOPE, parent, imports)
TABLE2(StateMachineMethod, TableType::STATEMACHINEMETHOD, moveNextMethod, kickoffMethod)
TABLE3(CustomDebugInformation, TableType::CUSTOMDEBUGINFORMATION, parent, kind, value)
protected:
const byte* _imageData;
uint32_t _imageLength;
const byte* _ptrRawDataEnd;
std::vector<SectionHeader> _sections;
uint32_t _entryPointToken;
CliStream _streamStringHeap;
CliStream _streamUS;
CliStream _streamBlobHeap;
CliStream _streamGuidHeap;
CliStream _streamTables;
bool _4byteStringIndex;
bool _4byteGUIDIndex;
bool _4byteBlobIndex;
Table _tables[TABLE_NUM];
std::vector<ColumnOffsetSize> _tableRowMetas[TABLE_NUM];
};
}
}