diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index d5f3c7f6096..a4ba05216ad 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -23,33 +23,50 @@ namespace llvm { namespace bitc { // The only top-level block type defined is for a module. - enum BlockIDs { - // Blocks - MODULE_BLOCK_ID = FIRST_APPLICATION_BLOCKID, +enum BlockIDs { + // Blocks + MODULE_BLOCK_ID = FIRST_APPLICATION_BLOCKID, - // Module sub-block id's. - PARAMATTR_BLOCK_ID, - PARAMATTR_GROUP_BLOCK_ID, + // Module sub-block id's. + PARAMATTR_BLOCK_ID, + PARAMATTR_GROUP_BLOCK_ID, - CONSTANTS_BLOCK_ID, - FUNCTION_BLOCK_ID, + CONSTANTS_BLOCK_ID, + FUNCTION_BLOCK_ID, - UNUSED_ID1, + // Block intended to contains information on the bitcode versioning. + // Can be used to provide better error messages when we fail to parse a + // bitcode file. + IDENTIFICATION_BLOCK_ID, - VALUE_SYMTAB_BLOCK_ID, - METADATA_BLOCK_ID, - METADATA_ATTACHMENT_ID, + VALUE_SYMTAB_BLOCK_ID, + METADATA_BLOCK_ID, + METADATA_ATTACHMENT_ID, - TYPE_BLOCK_ID_NEW, + TYPE_BLOCK_ID_NEW, - USELIST_BLOCK_ID, + USELIST_BLOCK_ID, - MODULE_STRTAB_BLOCK_ID, - FUNCTION_SUMMARY_BLOCK_ID, + MODULE_STRTAB_BLOCK_ID, + FUNCTION_SUMMARY_BLOCK_ID, - OPERAND_BUNDLE_TAGS_BLOCK_ID - }; + OPERAND_BUNDLE_TAGS_BLOCK_ID +}; +/// Idenfitication block contains a string that describes the producer details, +/// and an epoch that defines the auto-upgrade capability. +enum IdentificationCodes { + IDENTIFICATION_CODE_STRING = 1, // IDENTIFICATION: [strchr x N] + IDENTIFICATION_CODE_EPOCH = 2, // EPOCH: [epoch#] +}; + +/// The epoch that defines the auto-upgrade compatibility for the bitcode. +/// +/// LLVM guarantees in a major release that a minor release can read bitcode +/// generated by previous minor releases. We translate this by making the reader +/// accepting only bitcode with the same epoch, except for the X.0 release which +/// also accepts N-1. +enum { BITCODE_CURRENT_EPOCH = 0 }; /// MODULE blocks have a number of optional fields and subblocks. enum ModuleCodes { diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index e8d45790e3b..d926f324145 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -152,6 +152,8 @@ class BitcodeReader : public GVMaterializer { uint64_t LastFunctionBlockBit = 0; bool SeenValueSymbolTable = false; unsigned VSTOffset = 0; + // Contains an arbitrary and optional string identifying the bitcode producer + std::string ProducerIdentification; std::vector TypeList; BitcodeReaderValueList ValueList; @@ -273,6 +275,11 @@ public: void setStripDebugInfo() override; private: + /// Parse the "IDENTIFICATION_BLOCK_ID" block, populate the + // ProducerIdentification data member, and do some basic enforcement on the + // "epoch" encoded in the bitcode. + std::error_code parseBitcodeVersion(); + std::vector IdentifiedStructTypes; StructType *createIdentifiedStructType(LLVMContext &Context, StringRef Name); StructType *createIdentifiedStructType(LLVMContext &Context); @@ -518,10 +525,21 @@ static std::error_code error(DiagnosticHandlerFunction DiagnosticHandler, } std::error_code BitcodeReader::error(BitcodeError E, const Twine &Message) { + if (!ProducerIdentification.empty()) { + Twine MsgWithID = Message + " (Producer: '" + ProducerIdentification + + "' Reader: 'LLVM " + LLVM_VERSION_STRING "')"; + return ::error(DiagnosticHandler, make_error_code(E), MsgWithID); + } return ::error(DiagnosticHandler, make_error_code(E), Message); } std::error_code BitcodeReader::error(const Twine &Message) { + if (!ProducerIdentification.empty()) { + Twine MsgWithID = Message + " (Producer: '" + ProducerIdentification + + "' Reader: 'LLVM " + LLVM_VERSION_STRING "')"; + return ::error(DiagnosticHandler, + make_error_code(BitcodeError::CorruptedBitcode), MsgWithID); + } return ::error(DiagnosticHandler, make_error_code(BitcodeError::CorruptedBitcode), Message); } @@ -3061,6 +3079,50 @@ std::error_code BitcodeReader::rememberAndSkipFunctionBodies() { } } +std::error_code BitcodeReader::parseBitcodeVersion() { + if (Stream.EnterSubBlock(bitc::IDENTIFICATION_BLOCK_ID)) + return error("Invalid record"); + + // Read all the records. + SmallVector Record; + while (1) { + BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + default: + case BitstreamEntry::Error: + return error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + Record.clear(); + unsigned BitCode = Stream.readRecord(Entry.ID, Record); + switch (BitCode) { + default: // Default behavior: reject + return error("Invalid value"); + case bitc::IDENTIFICATION_CODE_STRING: { // IDENTIFICATION: [strchr x + // N] + convertToString(Record, 0, ProducerIdentification); + break; + } + case bitc::IDENTIFICATION_CODE_EPOCH: { // EPOCH: [epoch#] + unsigned epoch = (unsigned)Record[0]; + if (epoch != bitc::BITCODE_CURRENT_EPOCH) { + auto BitcodeEpoch = std::to_string(epoch); + auto CurrentEpoch = std::to_string(bitc::BITCODE_CURRENT_EPOCH); + return error(Twine("Incompatible epoch: Bitcode '") + BitcodeEpoch + + "' vs current: '" + CurrentEpoch + "'"); + } + } + } + } +} + std::error_code BitcodeReader::parseModule(uint64_t ResumeBit, bool ShouldLazyLoadMetadata) { if (ResumeBit) @@ -3552,6 +3614,11 @@ BitcodeReader::parseBitcodeInto(std::unique_ptr Streamer, if (Entry.Kind != BitstreamEntry::SubBlock) return error("Malformed block"); + if (Entry.ID == bitc::IDENTIFICATION_BLOCK_ID) { + parseBitcodeVersion(); + continue; + } + if (Entry.ID == bitc::MODULE_BLOCK_ID) return parseModule(0, ShouldLazyLoadMetadata); diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index 5b50a905e1b..5e90cd1bf10 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2829,6 +2829,29 @@ static void WriteCombinedFunctionSummary(const FunctionInfoIndex &I, Stream.ExitBlock(); } +// Create the "IDENTIFICATION_BLOCK_ID" containing a single string with the +// current llvm version, and a record for the epoch number. +static void WriteIdentificationBlock(const Module *M, BitstreamWriter &Stream) { + Stream.EnterSubblock(bitc::IDENTIFICATION_BLOCK_ID, 5); + + // Write the "user readable" string identifying the bitcode producer + BitCodeAbbrev *Abbv = new BitCodeAbbrev(); + Abbv->Add(BitCodeAbbrevOp(bitc::IDENTIFICATION_CODE_STRING)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Char6)); + auto StringAbbrev = Stream.EmitAbbrev(Abbv); + WriteStringRecord(bitc::IDENTIFICATION_CODE_STRING, + "LLVM" LLVM_VERSION_STRING, StringAbbrev, Stream); + + // Write the epoch version + Abbv = new BitCodeAbbrev(); + Abbv->Add(BitCodeAbbrevOp(bitc::IDENTIFICATION_CODE_EPOCH)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + SmallVector Vals = {bitc::BITCODE_CURRENT_EPOCH}; + Stream.EmitRecord(bitc::IDENTIFICATION_CODE_EPOCH, Vals); + Stream.ExitBlock(); +} + /// WriteModule - Emit the specified module to the bitstream. static void WriteModule(const Module *M, BitstreamWriter &Stream, bool ShouldPreserveUseListOrder, @@ -3000,6 +3023,8 @@ void llvm::WriteBitcodeToFile(const Module *M, raw_ostream &Out, // Emit the file header. WriteBitcodeHeader(Stream); + WriteIdentificationBlock(M, Stream); + // Emit the module. WriteModule(M, Stream, ShouldPreserveUseListOrder, BitcodeStartBit, EmitFunctionSummary); diff --git a/test/Bitcode/identification.ll b/test/Bitcode/identification.ll new file mode 100644 index 00000000000..2f09d5a4328 --- /dev/null +++ b/test/Bitcode/identification.ll @@ -0,0 +1,6 @@ +; Check that a block "IDENTIFICATION_BLOCK_ID" is emitted. +;RUN: llvm-as < %s | llvm-bcanalyzer -dump | FileCheck %s +;CHECK: