//===- 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;
}
}
}