From e75aa6f674ce90570fba9e5a3600535cba12a016 Mon Sep 17 00:00:00 2001 From: Mehdi Amini Date: Mon, 11 Jul 2016 23:10:18 +0000 Subject: Add a libLTO API to query a memory buffer and check if it contains ObjC categories The linker supports a feature to force load an object from a static archive if it defines an Objective-C category. This API supports this feature by looking at every section in the module to find if a category is defined in the module. llvm-svn: 275125 --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 90 +++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) (limited to 'llvm/lib/Bitcode/Reader/BitcodeReader.cpp') diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 9aaf3500cad..73a30c61eca 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -313,6 +313,10 @@ public: /// Cheap mechanism to just extract the identification block out of bitcode. ErrorOr parseIdentificationBlock(); + /// Peak at the module content and return true if any ObjC category or class + /// is found. + ErrorOr hasObjCCategory(); + static uint64_t decodeSignRotatedValue(uint64_t V); /// Materialize any deferred Metadata block. @@ -450,6 +454,7 @@ private: ArrayRef Record); std::error_code parseMetadataAttachment(Function &F); ErrorOr parseModuleTriple(); + ErrorOr hasObjCCategoryInModule(); std::error_code parseUseLists(); std::error_code initStream(std::unique_ptr Streamer); std::error_code initStreamFromBuffer(); @@ -4195,6 +4200,81 @@ std::error_code BitcodeReader::parseGlobalObjectAttachment( return std::error_code(); } +ErrorOr BitcodeReader::hasObjCCategory() { + if (std::error_code EC = initStream(nullptr)) + return EC; + + // Sniff for the signature. + if (!hasValidBitcodeHeader(Stream)) + return error("Invalid bitcode signature"); + + // We expect a number of well-defined blocks, though we don't necessarily + // need to understand them all. + while (1) { + BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case BitstreamEntry::Error: + return error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + + case BitstreamEntry::SubBlock: + if (Entry.ID == bitc::MODULE_BLOCK_ID) + return hasObjCCategoryInModule(); + + // Ignore other sub-blocks. + if (Stream.SkipBlock()) + return error("Malformed block"); + continue; + + case BitstreamEntry::Record: + Stream.skipRecord(Entry.ID); + continue; + } + } +} + +ErrorOr BitcodeReader::hasObjCCategoryInModule() { + if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) + return error("Invalid record"); + + SmallVector Record; + // Read all the records for this module. + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return error("Malformed block"); + case BitstreamEntry::EndBlock: + return false; + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + switch (Stream.readRecord(Entry.ID, Record)) { + default: + break; // Default behavior, ignore unknown content. + case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N] + std::string S; + if (convertToString(Record, 0, S)) + return error("Invalid record"); + // Check for the i386 and other (x86_64, ARM) conventions + if (S.find("__DATA, __objc_catlist") != std::string::npos || + S.find("__OBJC,__category") != std::string::npos) + return true; + break; + } + } + Record.clear(); + } + llvm_unreachable("Exit infinite loop"); +} + /// Parse metadata attachments. std::error_code BitcodeReader::parseMetadataAttachment(Function &F) { if (Stream.EnterSubBlock(bitc::METADATA_ATTACHMENT_ID)) @@ -6548,6 +6628,16 @@ std::string llvm::getBitcodeTargetTriple(MemoryBufferRef Buffer, return Triple.get(); } +bool llvm::isBitcodeContainingObjCCategory(MemoryBufferRef Buffer, + LLVMContext &Context) { + std::unique_ptr Buf = MemoryBuffer::getMemBuffer(Buffer, false); + auto R = llvm::make_unique(Buf.release(), Context); + ErrorOr hasObjCCategory = R->hasObjCCategory(); + if (hasObjCCategory.getError()) + return false; + return hasObjCCategory.get(); +} + std::string llvm::getBitcodeProducerString(MemoryBufferRef Buffer, LLVMContext &Context) { std::unique_ptr Buf = MemoryBuffer::getMemBuffer(Buffer, false); -- cgit v1.2.3