// 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 operands; }; struct ObjectFileLLVMIR::Entry { EntryKind kind; u32 id; }; struct ObjectFileLLVMIR::BlockInfo { struct Record { u32 blockId = 0; Vector abbrevs; std::string name; Vector> recordNames; }; Vector 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(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 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(); 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& outVals, const Vector& 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(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& 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 prevAbbrevs; }; Vector m_blockScope; Vector 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 recordData; std::string name; Set 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 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; } }