Files
UnrealEngine/Engine/Source/Programs/UnrealBuildAccelerator/Common/Private/UbaObjectFileLLVMIR.cpp
2025-05-18 13:04:45 +08:00

1005 lines
22 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "UbaObjectFileLLVMIR.h"
#include "UbaBinaryReaderWriter.h"
#include "UbaObjectFileCoff.h"
#define UBA_LOG_STREAM 0
namespace uba
{
// https://llvm.org/docs/BitCodeFormat.html
bool IsRawBitcode(const u8* data, u64 dataSize)
{
constexpr u8 magic[] = { 'B', 'C', 0xc0, 0xde };
return dataSize >= 4 && memcmp(data, magic, sizeof(magic)) == 0;
}
bool IsWrappedBitcode(const u8* data, u64 dataSize)
{
constexpr u8 wrapperMagic[] = { 0xDE, 0xC0, 0x17, 0x0B };
return dataSize >= 4 && memcmp(data, wrapperMagic, sizeof(wrapperMagic)) == 0;
}
bool IsLLVMIRFile(const u8* data, u64 dataSize)
{
return IsRawBitcode(data, dataSize) || IsWrappedBitcode(data, dataSize);
}
#define BLOCK_IDS \
BLOCK_ID(MODULE_BLOCK_ID) \
BLOCK_ID(PARAMATTR_BLOCK_ID) \
BLOCK_ID(PARAMATTR_GROUP_BLOCK_ID) \
BLOCK_ID(CONSTANTS_BLOCK_ID) \
BLOCK_ID(FUNCTION_BLOCK_ID) \
BLOCK_ID(IDENTIFICATION_BLOCK_ID) \
BLOCK_ID(VALUE_SYMTAB_BLOCK_ID) \
BLOCK_ID(METADATA_BLOCK_ID) \
BLOCK_ID(METADATA_ATTACHMENT_ID) \
BLOCK_ID(TYPE_BLOCK_ID_NEW) \
BLOCK_ID(USELIST_BLOCK_ID) \
BLOCK_ID(MODULE_STRTAB_BLOCK_ID) \
BLOCK_ID(GLOBALVAL_SUMMARY_BLOCK_ID) \
BLOCK_ID(OPERAND_BUNDLE_TAGS_BLOCK_ID) \
BLOCK_ID(METADATA_KIND_BLOCK_ID) \
BLOCK_ID(STRTAB_BLOCK_ID) \
BLOCK_ID(FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID) \
BLOCK_ID(SYMTAB_BLOCK_ID) \
BLOCK_ID(SYNC_SCOPE_NAMES_BLOCK_ID) \
enum BlockIDs : u8
{
BLOCKINFO_BLOCK_ID = 0,
BEFORE_FIRST_APPLICATION_BLOCKID = 7,
#define BLOCK_ID(x) x,
BLOCK_IDS
#undef BLOCK_ID
};
const tchar* BlockIdToString(u32 id)
{
switch(id)
{
case 0: return TC("BLOCKINFO_BLOCK_ID");
#define BLOCK_ID(x) case x: return TC(#x);
BLOCK_IDS
#undef BLOCK_ID
}
return TC("UNKNOWN_BLOCK_ID");
}
#define MODULE_CODES \
MODULE_CODE(VERSION, 1) \
MODULE_CODE(TRIPLE, 2) \
MODULE_CODE(DATALAYOUT, 3) \
MODULE_CODE(ASM, 4) \
MODULE_CODE(SECTIONNAME, 5) \
MODULE_CODE(DEPLIB, 6) \
MODULE_CODE(GLOBALVAR, 7) \
MODULE_CODE(FUNCTION, 8) \
MODULE_CODE(ALIAS_OLD, 9) \
MODULE_CODE(GCNAME, 11) \
MODULE_CODE(COMDAT, 12) \
MODULE_CODE(VSTOFFSET, 13) \
MODULE_CODE(ALIAS, 14) \
MODULE_CODE(METADATA_VALUES_UNUSED, 15) \
MODULE_CODE(SOURCE_FILENAME, 16) \
MODULE_CODE(HASH, 17) \
MODULE_CODE(IFUNC, 18)
enum ModuleCodes {
#define MODULE_CODE(x, v) MODULE_CODE_##x = v,
MODULE_CODES
#undef MODULE_CODE
};
const tchar* ModuleCodeToString(u32 code)
{
switch(code)
{
#define MODULE_CODE(x, v) case MODULE_CODE_##x: return TC("MODULE_CODE_" #x);
MODULE_CODES
#undef MODULE_CODE
}
return TC("MODULE_CODE_UNKNOWN");
}
enum ObjectFileLLVMIR::BlockInfoCodes : u8
{
BLOCKINFO_CODE_SETBID = 1,
BLOCKINFO_CODE_BLOCKNAME = 2,
BLOCKINFO_CODE_SETRECORDNAME = 3
};
enum ObjectFileLLVMIR::FixedAbbrevIDs : u8
{
END_BLOCK = 0,
ENTER_SUBBLOCK = 1,
DEFINE_ABBREV = 2,
UNABBREV_RECORD = 3,
FIRST_APPLICATION_ABBREV = 4
};
enum ObjectFileLLVMIR::EntryKind : u8
{
EntryKind_Error,
EntryKind_EndBlock,
EntryKind_SubBlock,
EntryKind_Record
};
enum ObjectFileLLVMIR::Encoding : u8
{
Encoding_Fixed = 1,
Encoding_VBR = 2,
Encoding_Array = 3,
Encoding_Char6 = 4,
Encoding_Blob = 5
};
enum
{
AF_DontPopBlockAtEnd = 1,
AF_DontAutoprocessAbbrevs = 2
};
struct ObjectFileLLVMIR::AbbrevOp
{
explicit AbbrevOp(u64 v) : val(v), isLiteral(true) {}
explicit AbbrevOp(Encoding e, u64 data = 0) : val(data), isLiteral(false), encoding(e) {}
u64 val;
bool isLiteral : 1;
u32 encoding : 3;
};
struct ObjectFileLLVMIR::Abbrev
{
Vector<AbbrevOp> operands;
};
struct ObjectFileLLVMIR::Entry
{
EntryKind kind;
u32 id;
};
struct ObjectFileLLVMIR::BlockInfo
{
struct Record
{
u32 blockId = 0;
Vector<AbbrevPtr> abbrevs;
std::string name;
Vector<std::pair<u32, std::string>> recordNames;
};
Vector<Record> records;
const Record* GetBlockInfo(u32 blockId) const
{
if (!records.empty() && records.back().blockId == blockId)
return &records.back();
for (const Record& bi : records)
if (bi.blockId == blockId)
return &bi;
return nullptr;
}
Record& GetOrCreateBlockInfo(u32 blockId)
{
if (const Record* bi = GetBlockInfo(blockId))
return *const_cast<Record*>(bi);
records.emplace_back();
records.back().blockId = blockId;
return records.back();
}
};
class ObjectFileLLVMIR::BitStreamReader
{
public:
BitStreamReader(ObjectFileLLVMIR& owner, Logger& logger, u8* data, u64 dataSize)
: m_owner(owner)
, m_logger(logger)
, m_begin(data)
, m_pos(data)
, m_end(data + dataSize)
{
}
u64 GetCurrentBitNo() const
{
return u64(m_pos - m_begin)*8 - m_wordBits;
}
bool CanSkipToPos(u64 pos) const
{
return pos <= u64(m_end - m_begin);
}
void SkipToEnd()
{
m_pos = m_end;
}
void JumpToBit(u64 bitNo)
{
u64 byteNo = u64(bitNo/8) & ~(sizeof(u32)-1);
u32 wordBitNo = u32(bitNo & (sizeof(u32)*8-1));
m_pos = m_begin + byteNo;
m_wordBits = 0;
if (wordBitNo)
Read(wordBitNo);
}
u32 Read(u32 bits)
{
if (m_wordBits >= bits)
{
#if !defined( __clang_analyzer__ )
u32 res = m_word & (~0u >> (32u - bits));
#else
u32 res = 0;
#endif
m_word >>= (bits & 0x1f);
m_wordBits -= bits;
return res;
}
u32 res = m_wordBits ? m_word : 0;
u32 bitsLeft = bits - m_wordBits;
UBA_ASSERT((m_end - m_pos) >= 4);
m_word = *(u32*)m_pos;
m_wordBits = 32;
m_pos += 4;
u32 res2 = m_word & (~0u >> (32 - bitsLeft));
m_word >>= (bitsLeft & 0x1f);
m_wordBits -= bitsLeft;
res |= res2 << (bits - bitsLeft);
return res;
}
u32 ReadVBR(u32 bits)
{
u32 piece = Read(bits);
u32 maskBitOrder = (bits - 1);
u32 mask = 1u << maskBitOrder;
if ((piece & mask) == 0)
return piece;
u32 result = 0;
u32 nextBit = 0;
while (true)
{
result |= (piece & (mask - 1)) << nextBit;
if ((piece & mask) == 0)
return result;
nextBit += bits-1;
UBA_ASSERT(nextBit < 32);
piece = Read(bits);
}
}
u64 ReadVBR64(u32 bits)
{
u32 piece = Read(bits);
u32 maskBitOrder = (bits - 1);
u32 mask = 1u << maskBitOrder;
if ((piece & mask) == 0)
return piece;
u64 result = 0;
u32 nextBit = 0;
while (true)
{
result |= u64(piece & (mask - 1)) << nextBit;
if ((piece & mask) == 0)
return result;
nextBit += bits-1;
UBA_ASSERT(nextBit < 64);
piece = Read(bits);
}
}
u32 ReadCode()
{
return Read(m_currentCodeSize);
}
void SkipToFourByteBoundary()
{
m_wordBits = 0;
}
bool IsDone()
{
return m_pos == m_end;
}
void SkipBlock()
{
ReadVBR(4); // CodeLenWidth
SkipToFourByteBoundary();
size_t numFourBytes = Read(32); // BlockSizeWidth
size_t skipTo = GetCurrentBitNo() + numFourBytes * 4 * 8;
JumpToBit(skipTo);
}
void EnterSubBlock(u32& outNumWords, u32 blockId)
{
auto& block = m_blockScope.emplace_back();
block.prevCodeSize = m_currentCodeSize;
block.prevAbbrevs.swap(m_curAbbrevs);
if (m_blockInfo)
if (const BlockInfo::Record* record = m_blockInfo->GetBlockInfo(blockId))
m_curAbbrevs.insert(m_curAbbrevs.end(), record->abbrevs.begin(), record->abbrevs.end());
m_currentCodeSize = ReadVBR(4);
UBA_ASSERT(m_currentCodeSize);
SkipToFourByteBoundary();
u32 numWords = Read(32);
UBA_ASSERT(numWords);
outNumWords = numWords;
}
BlockInfo ReadBlockInfoBlock(bool readBlockInfoNames)
{
u32 numWords;
EnterSubBlock(numWords, BLOCKINFO_BLOCK_ID);
BlockInfo newBlockInfo;
Vector<u64> record;
BlockInfo::Record* curBlockInfo = nullptr;
while (true)
{
Entry entry = AdvanceSkippingSubblocks(AF_DontAutoprocessAbbrevs);
switch (entry.kind)
{
case EntryKind_SubBlock:
case EntryKind_Error:
UBA_ASSERT(false);
return {};
case EntryKind_EndBlock:
return newBlockInfo;
case EntryKind_Record:
break;
}
if (entry.id == DEFINE_ABBREV)
{
if (!curBlockInfo)
{
UBA_ASSERT(false);
return {};
}
ReadAbbrevRecord();
curBlockInfo->abbrevs.push_back(std::move(m_curAbbrevs.back()));
m_curAbbrevs.pop_back();
continue;
}
record.clear();
u32 code = ReadRecord(record, entry.id);
switch (code)
{
default:
break;
case BLOCKINFO_CODE_SETBID:
if (record.size() < 1)
{
UBA_ASSERT(false);
return {};
}
curBlockInfo = &newBlockInfo.GetOrCreateBlockInfo(u32(record[0]));
break;
case BLOCKINFO_CODE_BLOCKNAME: {
if (!curBlockInfo)
{
UBA_ASSERT(false);
return {};
}
UBA_ASSERT(!readBlockInfoNames);
break;
}
case BLOCKINFO_CODE_SETRECORDNAME: {
if (!curBlockInfo)
{
UBA_ASSERT(false);
return {};
}
UBA_ASSERT(!readBlockInfoNames);
break;
}
}
}
return newBlockInfo;
}
bool ReadAbbrevRecord()
{
auto abbv = std::make_shared<Abbrev>();
u32 numOpInfo = ReadVBR(5);
for (u32 i = 0; i != numOpInfo; ++i)
{
bool isLiteral = Read(1);
if (isLiteral)
{
u64 op = ReadVBR64(8);
abbv->operands.emplace_back(op);
continue;
}
Encoding encoding = Encoding(Read(3));
UBA_ASSERT(encoding >= 1 && encoding <= 5);
if (encoding == Encoding_Fixed || encoding == Encoding_VBR)
{
u64 data = ReadVBR64(5);
if (data == 0)
abbv->operands.emplace_back(0);
else
abbv->operands.emplace_back(encoding, data);
}
else
abbv->operands.emplace_back(encoding);
}
m_curAbbrevs.push_back(abbv);
return true;
}
u64 ReadAbbreviatedField(const AbbrevOp& op)
{
switch (op.encoding)
{
case Encoding_Fixed:
return Read(u32(op.val));
case Encoding_VBR:
return ReadVBR64(u32(op.val));
case Encoding_Char6:
return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._"[Read(6)];
default:
UBA_ASSERT(false);
return ~0ull;
}
}
void SkipRecord(u32 abbrevId)
{
if (abbrevId == UNABBREV_RECORD)
{
ReadVBR(6);
u32 numElts = ReadVBR(6);
for (u32 i = 0; i != numElts; ++i)
ReadVBR64(6);
return;
}
u32 abbrevIndex = abbrevId - FIRST_APPLICATION_ABBREV;
Abbrev& abbv = *m_curAbbrevs[abbrevIndex];
UBA_ASSERT(!abbv.operands.empty());
AbbrevOp& codeOp = abbv.operands[0];
if (!codeOp.isLiteral)
ReadAbbreviatedField(codeOp);
for (u64 i = 1, e = abbv.operands.size(); i != e; ++i) {
const AbbrevOp& op = abbv.operands[i];
if (op.isLiteral)
continue;
if (op.encoding != Encoding_Array && op.encoding != Encoding_Blob)
{
ReadAbbreviatedField(op);
continue;
}
if (op.encoding == Encoding_Array)
{
u32 numElts = ReadVBR(6);
const AbbrevOp& eltEnc = abbv.operands[++i];
switch (eltEnc.encoding)
{
default:
UBA_ASSERT(false);
return;
case Encoding_Fixed:
JumpToBit(GetCurrentBitNo() + u64(numElts) * eltEnc.val);
break;
case Encoding_VBR:
for (; numElts; --numElts)
ReadVBR64(u32(eltEnc.val));
break;
case Encoding_Char6:
JumpToBit(GetCurrentBitNo() + numElts * 6);
}
continue;
}
UBA_ASSERT(op.encoding == Encoding_Blob);
u32 numElts = ReadVBR(6);
SkipToFourByteBoundary();
u64 newEnd = GetCurrentBitNo() + AlignUp(numElts, 4) * 8;
if (!CanSkipToPos(newEnd/8))
{
SkipToEnd();
break;
}
JumpToBit(newEnd);
}
return;
}
void ReadRecordOperands(Vector<u64>& outVals, const Vector<AbbrevOp>& operands, std::string* blob = nullptr, u32 blockId = 0)
{
for (u64 i = 1, e = operands.size(); i != e; ++i) {
const AbbrevOp& op = operands[i];
if (op.isLiteral)
{
outVals.push_back(op.val);
continue;
}
if (op.encoding != Encoding_Array && op.encoding != Encoding_Blob)
{
u64 val = ReadAbbreviatedField(op);(void)val;
outVals.push_back(val);
continue;
}
if (op.encoding == Encoding_Array)
{
u32 numElts = ReadVBR(6);
outVals.reserve(outVals.size() + numElts);
const AbbrevOp& eltEnc = operands[++i];
UBA_ASSERT(!eltEnc.isLiteral);
switch (eltEnc.encoding)
{
default:
UBA_ASSERT(false);
return;
case Encoding_Fixed:
for (; numElts; --numElts)
outVals.push_back(Read(u32(eltEnc.val)));
break;
case Encoding_VBR:
for (; numElts; --numElts)
outVals.push_back(ReadVBR64(u32(eltEnc.val)));
break;
case Encoding_Char6:
for (; numElts; --numElts)
outVals.push_back("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._"[Read(6)]);
}
continue;
}
UBA_ASSERT(op.encoding == Encoding_Blob);
u32 numElts = ReadVBR(6);
SkipToFourByteBoundary(); // 32-bit alignment
size_t curBitPos = GetCurrentBitNo();
size_t newEnd = curBitPos + AlignUp(numElts, 4) * 8;
UBA_ASSERT(CanSkipToPos(newEnd/8));
JumpToBit(newEnd);
if (blockId == STRTAB_BLOCK_ID)
{
m_owner.m_strTabPos = u64(curBitPos/8);
m_owner.m_strTabSize = numElts;
}
char* ptr = (char*)(m_begin + (curBitPos/8));
if (blob)
*blob = std::string(ptr, numElts);
else
{
auto* uptr = reinterpret_cast<const unsigned char*>(ptr);
outVals.insert(outVals.end(), uptr, uptr + numElts);
}
}
}
bool CanBeExported(u32 blockId, u32 code)
{
if (blockId != MODULE_BLOCK_ID)
return false;
switch (code)
{
case MODULE_CODE_FUNCTION:
case MODULE_CODE_GLOBALVAR:
case MODULE_CODE_IFUNC:
case MODULE_CODE_ALIAS:
case MODULE_CODE_ALIAS_OLD:
return true;
default:
return false;
}
}
u32 ReadRecord(Vector<u64>& outVals, u32 abbrevId, std::string* blob = nullptr, u32 blockId = 0)
{
if (abbrevId == UNABBREV_RECORD)
{
u32 code = ReadVBR(6);
if (CanBeExported(blockId, code))
m_owner.m_globalVarOrFunctionRecords.push_back(BitStreamEntry{u64(m_pos - m_begin), m_word, m_wordBits, code});
u32 numElts = ReadVBR(6);
outVals.reserve(outVals.size() + numElts);
for (u32 i = 0; i != numElts; ++i)
outVals.push_back(ReadVBR64(6));
#if UBA_LOG_STREAM
if (blockId == MODULE_BLOCK_ID)
{
auto str = ModuleCodeToString(code);
u32 indent = 2;
m_logger.Info(TC("%s%s (%u)"), TC(" ") + 8 - indent, str, code);
}
#endif
return code;
}
u32 abbrevIndex = abbrevId - FIRST_APPLICATION_ABBREV;
UBA_ASSERT(abbrevIndex < m_curAbbrevs.size());
Abbrev& abbv = *m_curAbbrevs[abbrevIndex];
UBA_ASSERT(!abbv.operands.empty());
AbbrevOp& codeOp = abbv.operands[0];
u32 code;
if (codeOp.isLiteral)
code = u32(codeOp.val);
else
{
UBA_ASSERT(codeOp.encoding != Encoding_Array && codeOp.encoding != Encoding_Blob);
code = u32(ReadAbbreviatedField(codeOp));
}
if (CanBeExported(blockId, code))
{
UBA_ASSERT(!abbv.operands.empty());
m_owner.m_globalVarOrFunctionRecords.push_back(BitStreamEntry{u64(m_pos - m_begin), m_word, m_wordBits, code, abbv.operands });
}
#if UBA_LOG_STREAM
if (blockId == MODULE_BLOCK_ID)
{
auto str = ModuleCodeToString(code);
u32 indent = 2;
m_logger.Info(TC("%s%s (%u)"), TC(" ") + 8 - indent, str, code);
}
#endif
ReadRecordOperands(outVals, abbv.operands, blob, blockId);
return code;
}
Entry Advance(u32 flags)
{
while (true)
{
UBA_ASSERT(!IsDone());
u32 code = ReadCode();
if (code == END_BLOCK)
{
if (flags & AF_DontPopBlockAtEnd)
return { EntryKind_EndBlock };
UBA_ASSERT(!m_blockScope.empty());
SkipToFourByteBoundary();
m_currentCodeSize = m_blockScope.back().prevCodeSize;
m_curAbbrevs = std::move(m_blockScope.back().prevAbbrevs);
m_blockScope.pop_back();
return { EntryKind_EndBlock };
}
if (code == ENTER_SUBBLOCK)
{
u32 subBlockId = ReadVBR(8);
return { EntryKind_SubBlock, subBlockId };
}
if (code == DEFINE_ABBREV && !(flags & AF_DontAutoprocessAbbrevs))
{
ReadAbbrevRecord();
continue;
}
return { EntryKind_Record, code };
}
}
Entry AdvanceSkippingSubblocks(u32 flags)
{
while (true)
{
Entry entry = Advance(flags);
if (entry.kind != EntryKind_SubBlock)
return entry;
SkipBlock();
}
}
ObjectFileLLVMIR& m_owner;
Logger& m_logger;
u32 m_word = 0;
u32 m_wordBits = 0;
u8* m_begin;
u8* m_pos;
u8* m_end;
u32 m_currentCodeSize = 2;
struct Block
{
u32 prevCodeSize;
Vector<AbbrevPtr> prevAbbrevs;
};
Vector<Block> m_blockScope;
Vector<AbbrevPtr> m_curAbbrevs;
BlockInfo* m_blockInfo = nullptr;
};
ObjectFileLLVMIR::ObjectFileLLVMIR()
{
m_type = ObjectFileType_LLVMIR;
}
ObjectFileLLVMIR::~ObjectFileLLVMIR() = default;
u32 GetDllStorageIndex(u32 code)
{
if (code == MODULE_CODE_FUNCTION)
return 13;
if (code == MODULE_CODE_GLOBALVAR)
return 12;
if (code == MODULE_CODE_ALIAS)
return 7;
if (code == MODULE_CODE_ALIAS_OLD)
return 6;
UBA_ASSERTF(false, TC("module code %s not supported"), ModuleCodeToString(code));
return ~0u;
}
u32 GetLinkageIndex(u32 code)
{
if (code == MODULE_CODE_FUNCTION)
return 5;
if (code == MODULE_CODE_GLOBALVAR)
return 5;
if (code == MODULE_CODE_ALIAS)
return 3;
if (code == MODULE_CODE_ALIAS_OLD)
return 2;
UBA_ASSERTF(false, TC("module code %s not supported"), ModuleCodeToString(code));
return ~0u;
}
bool ObjectFileLLVMIR::Parse(Logger& logger, ObjectFileParseMode parseMode, const tchar* hint)
{
BitStreamReader reader(*this, logger, m_data, m_dataSize);
if (IsWrappedBitcode(m_data, m_dataSize))
{
reader.Read(32);
u32 version = reader.Read(32);(void)version;
u32 bitcodeOffset = reader.Read(32);(void)bitcodeOffset;
u32 bitcodeSize = reader.Read(32);(void)bitcodeSize;
u32 cpuType = reader.Read(32);(void)cpuType;
reader.JumpToBit(bitcodeOffset*8);
reader.m_end = reader.m_pos + bitcodeSize;
}
reader.Read(32); // Skip magic
BlockInfo blockInfo;
reader.m_blockInfo = &blockInfo;
while (!reader.IsDone())
{
u32 code = reader.ReadCode();(void)code;
UBA_ASSERT(code == ENTER_SUBBLOCK);
u32 blockId = reader.ReadVBR(8);
u64 subBlockBitStart = reader.GetCurrentBitNo();(void)subBlockBitStart;
ParseBlock(logger, reader, blockInfo, blockId, 0);
}
Vector<u64> recordData;
std::string name;
Set<std::string> recordsWithOds;
u32 index = 0;
for (auto& record : m_globalVarOrFunctionRecords)
{
reader.m_pos = m_data + record.pos;
reader.m_word = record.word;
reader.m_wordBits = record.wordBits;
recordData.clear();
if (record.operands.empty())
{
u32 numElts = reader.ReadVBR(6);
recordData.reserve(recordData.size() + numElts);
for (u32 i = 0; i != numElts; ++i)
recordData.push_back(reader.ReadVBR64(6));
}
else
{
reader.ReadRecordOperands(recordData, record.operands);
}
u64* recIt = recordData.data();
u64 recSize = recordData.size();
if (recIt[0] + recIt[1] >= m_strTabSize)
continue;
name.assign((char*)(m_data + m_strTabPos) + recIt[0], recIt[1]);
u32 dllStorageIndex = GetDllStorageIndex(record.code);
u64 dllStorage = ~0ull;
if (recSize > dllStorageIndex)
dllStorage = recIt[dllStorageIndex];
// Left here for debugging purposes :)
//if (name.find("RemoveHighlight") != -1)
// printf("");
bool isExported = false;
u32 linkageIndex = GetLinkageIndex(record.code);
u64 linkage = 0;
if (recSize > linkageIndex)
{
linkage = recIt[linkageIndex];
if (linkage == 9) // PrivateLinkage
continue;
if (linkage == 19) // LinkOnceODRLinkage
{
recordsWithOds.insert(name);
continue;
}
// ExternalLinkage || DLLImportLinkage || DLLExportLinkage || LinkOnceODRAutoHideLinkage || WeakODRLinkage
isExported = linkage == 0 || linkage == 5 || linkage == 6 || linkage == 15 || linkage == 17;
if (dllStorage == DllStorage_Import)
isExported = false;
}
if (record.code == MODULE_CODE_GLOBALVAR)
{
bool hasInitializer = recordData[4] != 0;
if (!hasInitializer)
isExported = false;
if (isExported)
{
m_exports.emplace(ToStringKeyRaw(name.data(), name.size()), ExportInfo{name, false, index++});
}
else if (name.find(".str") == -1)
{
if (recordsWithOds.find(name) != recordsWithOds.end())
continue;
m_imports.emplace(name);
}
}
else if (record.code == MODULE_CODE_FUNCTION)
{
bool isProto = recordData[4] != 0;
if (linkage == 12) // thunk import?!? (like _ZThn840_N21UFortHUDElementWidget15RemoveHighlightEv)
isProto = true;
if (isProto)
{
if (recordsWithOds.find(name) != recordsWithOds.end())
continue;
m_imports.emplace(name);
}
else if (isExported)
{
m_exports.emplace(ToStringKeyRaw(name.data(), name.size()), ExportInfo{name, false, index++});
}
}
else if (record.code == MODULE_CODE_ALIAS)
{
if (isExported)
m_exports.emplace(ToStringKeyRaw(name.data(), name.size()), ExportInfo{name, false, index++});
}
(void)index;
}
return true;
}
bool ObjectFileLLVMIR::ParseBlock(Logger& logger, BitStreamReader& reader, BlockInfo& blockInfo, u32 blockId, u32 indent)
{
if (blockId == BLOCKINFO_BLOCK_ID)
{
uint64_t blockBitStart = reader.GetCurrentBitNo();
blockInfo = reader.ReadBlockInfoBlock(true);
reader.JumpToBit(blockBitStart);
}
u32 numWords = 0;
reader.EnterSubBlock(numWords, blockId);
#if UBA_LOG_STREAM
const tchar* str = BlockIdToString(blockId);
logger.Info(TC("%s%s (%u)"), TC(" ") + 8 - indent, str, blockId);
#endif
Vector<u64> record;
std::string blob;
while (true)
{
UBA_ASSERT(!reader.IsDone());
Entry entry = reader.Advance(AF_DontAutoprocessAbbrevs);
switch (entry.kind)
{
case EntryKind_Record:
break;
case EntryKind_EndBlock:
return true;
case EntryKind_SubBlock:
{
u64 subBlockBitStart = reader.GetCurrentBitNo();(void)subBlockBitStart;
ParseBlock(logger, reader, blockInfo, entry.id, indent + 2);
continue;
}
default:
UBA_ASSERT(false);
}
if (entry.id == DEFINE_ABBREV)
{
reader.ReadAbbrevRecord();
continue;
}
if (blockId == MODULE_BLOCK_ID || blockId == STRTAB_BLOCK_ID)
{
record.clear();
reader.ReadRecord(record, entry.id, nullptr, blockId);
}
else
reader.SkipRecord(entry.id);
#if UBA_LOG_STREAM
//logger.Log(LogEntryType_Info, blob);
#endif
}
return true;
}
}