|  | //===- NaClBitstreamReader.cpp --------------------------------------------===// | 
|  | //     NaClBitstreamReader implementation | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/ADT/STLExtras.h" | 
|  | #include "llvm/Bitcode/NaCl/NaClBitstreamReader.h" | 
|  | #include "llvm/Support/Format.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | static const char *ErrorLevelName[] = { | 
|  | "Warning", | 
|  | "Error", | 
|  | "Fatal" | 
|  | }; | 
|  |  | 
|  | } // End of anonymous namespace. | 
|  |  | 
|  | std::string llvm::naclbitc::getBitAddress(uint64_t Bit) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream Stream(Buffer); | 
|  | Stream << (Bit / 8) << ":" << (Bit % 8); | 
|  | return Stream.str(); | 
|  | } | 
|  |  | 
|  | raw_ostream &llvm::naclbitc::ErrorAt( | 
|  | raw_ostream &Out, ErrorLevel Level, uint64_t BitPosition) { | 
|  | assert(Level < array_lengthof(::ErrorLevelName)); | 
|  | return Out << ErrorLevelName[Level] << "(" | 
|  | << naclbitc::getBitAddress(BitPosition) << "): "; | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | //  NaClBitstreamCursor implementation | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | void NaClBitstreamCursor::ErrorHandler:: | 
|  | Fatal(const std::string &ErrorMessage) const { | 
|  | // Default implementation is simply print message, and the bit where | 
|  | // the error occurred. | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | naclbitc::ErrorAt(StrBuf, naclbitc::Fatal, | 
|  | Cursor.getErrorBitNo(getCurrentBitNo())) << ErrorMessage; | 
|  | report_fatal_error(StrBuf.str()); | 
|  | } | 
|  |  | 
|  | void NaClBitstreamCursor::reportInvalidAbbrevNumber(unsigned AbbrevNo) const { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Invalid abbreviation # " << AbbrevNo << " defined for record"; | 
|  | ErrHandler->Fatal(StrBuf.str()); | 
|  | } | 
|  |  | 
|  | void NaClBitstreamCursor::reportInvalidJumpToBit(uint64_t BitNo) const { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Invalid jump to bit " << BitNo; | 
|  | ErrHandler->Fatal(StrBuf.str()); | 
|  | } | 
|  |  | 
|  | /// EnterSubBlock - Having read the ENTER_SUBBLOCK abbrevid, enter | 
|  | /// the block, and return true if the block has an error. | 
|  | bool NaClBitstreamCursor::EnterSubBlock(unsigned BlockID, unsigned *NumWordsP) { | 
|  | const bool IsFixed = true; | 
|  | NaClBitcodeSelectorAbbrev | 
|  | CodeAbbrev(IsFixed, ReadVBR(naclbitc::CodeLenWidth)); | 
|  | BlockScope.push_back(Block(BitStream->getBlockInfo(BlockID), CodeAbbrev)); | 
|  | SkipToFourByteBoundary(); | 
|  | unsigned NumWords = Read(naclbitc::BlockSizeWidth); | 
|  | if (NumWordsP) *NumWordsP = NumWords; | 
|  |  | 
|  | // Validate that this block is sane. | 
|  | if (BlockScope.back().getCodeAbbrev().NumBits == 0 || AtEndOfStream()) | 
|  | return true; | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void NaClBitstreamCursor::skipAbbreviatedField(const NaClBitCodeAbbrevOp &Op) { | 
|  | // Decode the value as we are commanded. | 
|  | switch (Op.getEncoding()) { | 
|  | case NaClBitCodeAbbrevOp::Literal: | 
|  | // No read necessary for literal. | 
|  | break; | 
|  | case NaClBitCodeAbbrevOp::Fixed: | 
|  | (void)Read((unsigned)Op.getValue()); | 
|  | break; | 
|  | case NaClBitCodeAbbrevOp::VBR: | 
|  | (void)ReadVBR64((unsigned)Op.getValue()); | 
|  | break; | 
|  | case NaClBitCodeAbbrevOp::Array: | 
|  | // This can't happen because the abbreviation must be valid. | 
|  | llvm_unreachable("Bad array abbreviation encoding!"); | 
|  | break; | 
|  | case NaClBitCodeAbbrevOp::Char6: | 
|  | (void)Read(6); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// skipRecord - Read the current record and discard it. | 
|  | void NaClBitstreamCursor::skipRecord(unsigned AbbrevID) { | 
|  | // Skip unabbreviated records by reading past their entries. | 
|  | if (AbbrevID == naclbitc::UNABBREV_RECORD) { | 
|  | unsigned Code = ReadVBR(6); | 
|  | (void)Code; | 
|  | unsigned NumElts = ReadVBR(6); | 
|  | for (unsigned i = 0; i != NumElts; ++i) | 
|  | (void)ReadVBR64(6); | 
|  | SkipToByteBoundaryIfAligned(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | const NaClBitCodeAbbrev *Abbv = getAbbrev(AbbrevID); | 
|  |  | 
|  | for (unsigned i = 0, e = Abbv->getNumOperandInfos(); i != e; ++i) { | 
|  | const NaClBitCodeAbbrevOp &Op = Abbv->getOperandInfo(i); | 
|  | switch (Op.getEncoding()) { | 
|  | default: | 
|  | skipAbbreviatedField(Op); | 
|  | break; | 
|  | case NaClBitCodeAbbrevOp::Literal: | 
|  | break; | 
|  | case NaClBitCodeAbbrevOp::Array: { | 
|  | // Array case.  Read the number of elements as a vbr6. | 
|  | unsigned NumElts = ReadVBR(6); | 
|  |  | 
|  | // Get the element encoding. | 
|  | const NaClBitCodeAbbrevOp &EltEnc = Abbv->getOperandInfo(++i); | 
|  |  | 
|  | // Read all the elements. | 
|  | for (; NumElts; --NumElts) | 
|  | skipAbbreviatedField(EltEnc); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | SkipToByteBoundaryIfAligned(); | 
|  | } | 
|  |  | 
|  | bool NaClBitstreamCursor::readRecordAbbrevField( | 
|  | const NaClBitCodeAbbrevOp &Op, uint64_t &Value) { | 
|  | switch (Op.getEncoding()) { | 
|  | case NaClBitCodeAbbrevOp::Literal: | 
|  | Value = Op.getValue(); | 
|  | break; | 
|  | case NaClBitCodeAbbrevOp::Array: | 
|  | // Returns number of elements in the array. | 
|  | Value = ReadVBR(6); | 
|  | return true; | 
|  | case NaClBitCodeAbbrevOp::Fixed: | 
|  | Value = Read((unsigned)Op.getValue()); | 
|  | break; | 
|  | case NaClBitCodeAbbrevOp::VBR: | 
|  | Value = ReadVBR64((unsigned)Op.getValue()); | 
|  | break; | 
|  | case NaClBitCodeAbbrevOp::Char6: | 
|  | Value = NaClBitCodeAbbrevOp::DecodeChar6(Read(6)); | 
|  | break; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint64_t NaClBitstreamCursor::readArrayAbbreviatedField( | 
|  | const NaClBitCodeAbbrevOp &Op) { | 
|  | // Decode the value as we are commanded. | 
|  | switch (Op.getEncoding()) { | 
|  | case NaClBitCodeAbbrevOp::Literal: | 
|  | return Op.getValue(); | 
|  | case NaClBitCodeAbbrevOp::Fixed: | 
|  | return Read((unsigned)Op.getValue()); | 
|  | case NaClBitCodeAbbrevOp::VBR: | 
|  | return ReadVBR64((unsigned)Op.getValue()); | 
|  | case NaClBitCodeAbbrevOp::Array: | 
|  | // This can't happen because the abbreviation must be valid. | 
|  | llvm_unreachable("Bad array abbreviation encoding!"); | 
|  | break; | 
|  | case NaClBitCodeAbbrevOp::Char6: | 
|  | return NaClBitCodeAbbrevOp::DecodeChar6(Read(6)); | 
|  | } | 
|  | llvm_unreachable("Illegal abbreviation encoding for field!"); | 
|  | } | 
|  |  | 
|  | void NaClBitstreamCursor::readArrayAbbrev( | 
|  | const NaClBitCodeAbbrevOp &Op, unsigned NumArrayElements, | 
|  | SmallVectorImpl<uint64_t> &Vals) { | 
|  | for (; NumArrayElements; --NumArrayElements) { | 
|  | Vals.push_back(readArrayAbbreviatedField(Op)); | 
|  | } | 
|  | } | 
|  |  | 
|  | unsigned NaClBitstreamCursor::readRecord(unsigned AbbrevID, | 
|  | SmallVectorImpl<uint64_t> &Vals) { | 
|  | if (AbbrevID == naclbitc::UNABBREV_RECORD) { | 
|  | unsigned Code = ReadVBR(6); | 
|  | unsigned NumElts = ReadVBR(6); | 
|  | for (unsigned i = 0; i != NumElts; ++i) | 
|  | Vals.push_back(ReadVBR64(6)); | 
|  | SkipToByteBoundaryIfAligned(); | 
|  | return Code; | 
|  | } | 
|  |  | 
|  | // Read code. | 
|  | const NaClBitCodeAbbrev *Abbv = getAbbrev(AbbrevID); | 
|  | uint64_t Value; | 
|  | unsigned Code; | 
|  | if (readRecordAbbrevField(Abbv->getOperandInfo(0), Value)) { | 
|  | // Array found, use to read all elements. | 
|  | if (Value == 0) | 
|  | ErrHandler->Fatal("No code found for record!"); | 
|  | const NaClBitCodeAbbrevOp &Op = Abbv->getOperandInfo(1); | 
|  | Code = readArrayAbbreviatedField(Op); | 
|  | readArrayAbbrev(Op, Value - 1, Vals); | 
|  | SkipToByteBoundaryIfAligned(); | 
|  | return Code; | 
|  | } | 
|  | Code = Value; | 
|  |  | 
|  | // Read arguments. | 
|  | unsigned NumOperands = Abbv->getNumOperandInfos(); | 
|  | for (unsigned i = 1; i != NumOperands; ++i) { | 
|  | if (readRecordAbbrevField(Abbv->getOperandInfo(i), Value)) { | 
|  | ++i; | 
|  | readArrayAbbrev(Abbv->getOperandInfo(i), Value, Vals); | 
|  | SkipToByteBoundaryIfAligned(); | 
|  | return Code; | 
|  | } | 
|  | Vals.push_back(Value); | 
|  | } | 
|  | SkipToByteBoundaryIfAligned(); | 
|  | return Code; | 
|  | } | 
|  |  | 
|  |  | 
|  | NaClBitCodeAbbrevOp::Encoding NaClBitstreamCursor:: | 
|  | getEncoding(uint64_t Value) { | 
|  | if (!NaClBitCodeAbbrevOp::isValidEncoding(Value)) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Invalid abbreviation encoding specified in bitcode file: " | 
|  | << Value; | 
|  | ErrHandler->Fatal(StrBuf.str()); | 
|  | } | 
|  | return NaClBitCodeAbbrevOp::Encoding(Value); | 
|  | } | 
|  |  | 
|  | void NaClBitstreamCursor::ReadAbbrevRecord(bool IsLocal, | 
|  | NaClAbbrevListener *Listener) { | 
|  | NaClBitCodeAbbrev *Abbv = BlockScope.back().appendLocalCreate(); | 
|  | unsigned NumOpInfo = ReadVBR(5); | 
|  | if (Listener) Listener->Values.push_back(NumOpInfo); | 
|  | for (unsigned i = 0; i != NumOpInfo; ++i) { | 
|  | bool IsLiteral = Read(1) ? true : false; | 
|  | if (Listener) Listener->Values.push_back(IsLiteral); | 
|  | if (IsLiteral) { | 
|  | uint64_t Value = ReadVBR64(8); | 
|  | if (Listener) Listener->Values.push_back(Value); | 
|  | Abbv->Add(NaClBitCodeAbbrevOp(Value)); | 
|  | continue; | 
|  | } | 
|  | NaClBitCodeAbbrevOp::Encoding E = getEncoding(Read(3)); | 
|  | if (Listener) Listener->Values.push_back(E); | 
|  | if (NaClBitCodeAbbrevOp::hasValue(E)) { | 
|  | unsigned Data = ReadVBR64(5); | 
|  | if (Listener) Listener->Values.push_back(Data); | 
|  |  | 
|  | // As a special case, handle fixed(0) (i.e., a fixed field with zero bits) | 
|  | // and vbr(0) as a literal zero.  This is decoded the same way, and avoids | 
|  | // a slow path in Read() to have to handle reading zero bits. | 
|  | if ((E == NaClBitCodeAbbrevOp::Fixed || E == NaClBitCodeAbbrevOp::VBR) && | 
|  | Data == 0) { | 
|  | if (Listener) Listener->Values.push_back(0); | 
|  | Abbv->Add(NaClBitCodeAbbrevOp(0)); | 
|  | continue; | 
|  | } | 
|  | if (!NaClBitCodeAbbrevOp::isValid(E, Data)) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Invalid abbreviation encoding (" | 
|  | << NaClBitCodeAbbrevOp::getEncodingName(E) | 
|  | << ", " << Data << ")"; | 
|  | ErrHandler->Fatal(StrBuf.str()); | 
|  | } | 
|  | Abbv->Add(NaClBitCodeAbbrevOp(E, Data)); | 
|  | } else { | 
|  | if (!NaClBitCodeAbbrevOp::isValid(E)) { | 
|  | std::string Buffer; | 
|  | raw_string_ostream StrBuf(Buffer); | 
|  | StrBuf << "Invalid abbreviation encoding (" | 
|  | << NaClBitCodeAbbrevOp::getEncodingName(E) << ")"; | 
|  | ErrHandler->Fatal(StrBuf.str()); | 
|  | } | 
|  | Abbv->Add(NaClBitCodeAbbrevOp(E)); | 
|  | } | 
|  | } | 
|  | SkipToByteBoundaryIfAligned(); | 
|  | if (!Abbv->isValid()) | 
|  | ErrHandler->Fatal("Invalid abbreviation specified in bitcode file"); | 
|  | if (Listener) { | 
|  | Listener->ProcessAbbreviation(Abbv, IsLocal); | 
|  | // Reset record information of the listener. | 
|  | Listener->Values.clear(); | 
|  | Listener->StartBit = GetCurrentBitNo(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void NaClBitstreamCursor::SkipAbbrevRecord() { | 
|  | unsigned NumOpInfo = ReadVBR(5); | 
|  | for (unsigned i = 0; i != NumOpInfo; ++i) { | 
|  | bool IsLiteral = Read(1) ? true : false; | 
|  | if (IsLiteral) { | 
|  | ReadVBR64(8); | 
|  | continue; | 
|  | } | 
|  | NaClBitCodeAbbrevOp::Encoding E = getEncoding(Read(3)); | 
|  | if (NaClBitCodeAbbrevOp::hasValue(E)) { | 
|  | ReadVBR64(5); | 
|  | } | 
|  | } | 
|  | SkipToByteBoundaryIfAligned(); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | unsigned ValidBlockIDs[] = { | 
|  | naclbitc::BLOCKINFO_BLOCK_ID, | 
|  | naclbitc::CONSTANTS_BLOCK_ID, | 
|  | naclbitc::FUNCTION_BLOCK_ID, | 
|  | naclbitc::GLOBALVAR_BLOCK_ID, | 
|  | naclbitc::MODULE_BLOCK_ID, | 
|  | naclbitc::TOP_LEVEL_BLOCKID, | 
|  | naclbitc::TYPE_BLOCK_ID_NEW, | 
|  | naclbitc::VALUE_SYMTAB_BLOCK_ID | 
|  | }; | 
|  |  | 
|  | } // end of anonymous namespace | 
|  |  | 
|  | NaClBitstreamReader::BlockInfoRecordsMap:: | 
|  | BlockInfoRecordsMap() : IsFrozen(false) { | 
|  | for (size_t BlockID : ValidBlockIDs) { | 
|  | std::unique_ptr<BlockInfo> Info(new BlockInfo(BlockID)); | 
|  | KnownInfos.emplace(BlockID, std::move(Info)); | 
|  | } | 
|  | } | 
|  |  | 
|  | NaClBitstreamReader::BlockInfo * NaClBitstreamReader::BlockInfoRecordsMap:: | 
|  | getOrCreateUnknownBlockInfo(unsigned BlockID) { | 
|  | std::unique_lock<std::mutex> Lock(UnknownBlockInfoLock); | 
|  | while (true) { | 
|  | auto Pos = UnknownInfos.find(BlockID); | 
|  | if (Pos != UnknownInfos.end()) | 
|  | return Pos->second.get(); | 
|  | // Install, then let next iteration find. | 
|  | std::unique_ptr<BlockInfo> Info(new BlockInfo(BlockID)); | 
|  | UnknownInfos.emplace(BlockID, std::move(Info)); | 
|  | } | 
|  | } | 
|  |  | 
|  | NaClBitstreamReader::BlockInfoRecordsMap::UpdateLock:: | 
|  | UpdateLock(BlockInfoRecordsMap &BlockInfoRecords) | 
|  | : BlockInfoRecords(BlockInfoRecords), | 
|  | Lock(BlockInfoRecords.UpdateRecordsLock) {} | 
|  |  | 
|  | NaClBitstreamReader::BlockInfoRecordsMap::UpdateLock:: | 
|  | ~UpdateLock() { | 
|  | if (BlockInfoRecords.freeze()) | 
|  | report_fatal_error("Global abbreviations block frozen while building."); | 
|  | } | 
|  |  | 
|  | bool NaClBitstreamCursor::ReadBlockInfoBlock(NaClAbbrevListener *Listener) { | 
|  | // If this is the second read of the block info block, skip it. | 
|  | if (BitStream->BlockInfoRecords->isFrozen()) | 
|  | return SkipBlock(); | 
|  |  | 
|  | NaClBitstreamReader::BlockInfoRecordsMap::UpdateLock | 
|  | Lock(*BitStream->BlockInfoRecords); | 
|  | unsigned NumWords; | 
|  | if (EnterSubBlock(naclbitc::BLOCKINFO_BLOCK_ID, &NumWords)) return true; | 
|  |  | 
|  | if (Listener) Listener->BeginBlockInfoBlock(NumWords); | 
|  |  | 
|  | NaClBitcodeRecordVector Record; | 
|  | Block &CurBlock = BlockScope.back(); | 
|  | NaClBitstreamReader::AbbrevList *UpdateAbbrevs = | 
|  | &CurBlock.GlobalAbbrevs->getAbbrevs(); | 
|  | bool FoundSetBID = false; | 
|  |  | 
|  | // Read records of the BlockInfo block. | 
|  | while (1) { | 
|  | if (Listener) Listener->StartBit = GetCurrentBitNo(); | 
|  | NaClBitstreamEntry Entry = advance(AF_DontAutoprocessAbbrevs, Listener); | 
|  |  | 
|  | switch (Entry.Kind) { | 
|  | case llvm::NaClBitstreamEntry::SubBlock:  // PNaCl doesn't allow! | 
|  | case llvm::NaClBitstreamEntry::Error: | 
|  | return true; | 
|  | case llvm::NaClBitstreamEntry::EndBlock: | 
|  | if (Listener) Listener->EndBlockInfoBlock(); | 
|  | return false; | 
|  | case llvm::NaClBitstreamEntry::Record: | 
|  | // The interesting case. | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Read abbrev records, associate them with CurBID. | 
|  | if (Entry.ID == naclbitc::DEFINE_ABBREV) { | 
|  | ReadAbbrevRecord(false, Listener); | 
|  |  | 
|  | // ReadAbbrevRecord installs a local abbreviation.  Move it to the | 
|  | // appropriate BlockInfo if the corresponding SetBID record has been | 
|  | // found. | 
|  | if (FoundSetBID) | 
|  | CurBlock.moveLocalAbbrevToAbbrevList(UpdateAbbrevs); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Read a record. | 
|  | Record.clear(); | 
|  | switch (readRecord(Entry.ID, Record)) { | 
|  | default: | 
|  | // No other records should be found! | 
|  | return true; | 
|  | case naclbitc::BLOCKINFO_CODE_SETBID: | 
|  | if (Record.size() < 1) return true; | 
|  | FoundSetBID = true; | 
|  | UpdateAbbrevs = | 
|  | &BitStream->getBlockInfo((unsigned)Record[0])->getAbbrevs(); | 
|  | if (Listener) { | 
|  | Listener->Values = Record; | 
|  | Listener->SetBID(); | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | } |