Files
2026-06-29 21:18:33 +08:00

362 lines
9.9 KiB
C++

#pragma once
#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,
};
class RawImage
{
public:
RawImage(): _ptrRawData(nullptr), _imageLength(0), _ptrRawDataEnd(nullptr),
_isDll(false), _PEHeader(nullptr), _PESectionHeaders(nullptr), _ptrMetaData(nullptr), _ptrMetaRoot(nullptr),
_streamStringHeap{}, _streamUS{}, _streamBlobHeap{}, _streamGuidHeap{}, _streamTables{},
_stringHeapStrNum(0), _userStringStrNum(0), _blobNum(0),
_4byteStringIndex(false), _4byteGUIDIndex(false), _4byteBlobIndex(false)
{
}
LoadImageErrorCode Load(const void* imageData, size_t length);
uint32_t GetTypeCount() const
{
return _tables[(int)TableType::TYPEDEF].rowNum;
}
uint32_t GetExportedTypeCount() const
{
return _tables[(int)TableType::EXPORTEDTYPE].rowNum;
}
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 && (size_t)index < _streamBlobHeap.size);
return _streamBlobHeap.data + index;
}
const uint8_t* GetFieldOrParameterDefalutValueByRawIndex(uint32_t index) const
{
return _ptrRawData + 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() - _ptrRawData);
}
else
{
return (uint32_t)(_streamBlobHeap.data + index - _ptrRawData);
}
}
const byte* GetDataPtrByImageOffset(uint32_t imageOffset) const
{
IL2CPP_ASSERT(imageOffset < _imageLength);
return _ptrRawData + imageOffset;
}
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 Table& GetTable(TableType type) const
{
return _tables[(int)type];
}
const std::vector<ColumnOffsetSize>& GetRowSchema(TableType type) const
{
return _tableRowMetas[(int)type];
}
bool TranslateRVAToImageOffset(uint32_t rvaOffset, uint32_t& imageOffset);
LoadImageErrorCode LoadStreams();
LoadImageErrorCode LoadTables();
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 GetTableRowNum(TableType tableIndex) const
{
return _tables[(int)tableIndex].rowNum;
}
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);
}
uint32_t GetEntryPointToken() const
{
return _CLIHeader->entryPointToken;
}
const byte* GetUserStringBlogByIndex(uint32_t index) const
{
IL2CPP_ASSERT(index >= 0 && (uint32_t)index < _streamUS.size);
return _streamUS.data + index;
}
private:
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
{
IL2CPP_ASSERT(size == 2 || size == 4);
return (size == 2 ? *(uint16_t*)(data + offset) : *(uint32_t*)(data + offset));
}
public:
#define TABLE_BEGIN(name, tableType) Tb##name Read##name(uint32_t rawIndex) const \
{ \
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);
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)
TABLE3(Constant, TableType::CONSTANT, type, 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(culture)
TABLE_END
TABLE_BEGIN(AssemblyRef, TableType::ASSEMBLYREF)
__F(majorVersion)
__F(minorVersion)
__F(buildNumber)
__F(revisionNumber)
__F(flags)
__F(publicKeyOrToken)
__F(name)
__F(culture)
__F(hashValue)
TABLE_END
private:
const byte* _ptrRawData;
uint32_t _imageLength;
const byte* _ptrRawDataEnd;
bool _isDll;
const PEHeader* _PEHeader;
const CLIHeader* _CLIHeader;
const PESectionHeader* _PESectionHeaders;
const MetadataRootPartial* _ptrMetaRoot;
const byte* _ptrMetaData;
CliStream _streamStringHeap;
CliStream _streamUS;
CliStream _streamBlobHeap;
CliStream _streamGuidHeap;
CliStream _streamTables;
uint32_t _stringHeapStrNum;
uint32_t _userStringStrNum;
uint32_t _blobNum;
bool _4byteStringIndex;
bool _4byteGUIDIndex;
bool _4byteBlobIndex;
Table _tables[TABLE_NUM];
std::vector<ColumnOffsetSize> _tableRowMetas[TABLE_NUM];
};
}
}