| Index: pnacl-llvm/NaClBitcodeHeader.cpp
|
| diff --git a/pnacl-llvm/NaClBitcodeHeader.cpp b/pnacl-llvm/NaClBitcodeHeader.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8a65f50829b601a0d09426267ac1b8f70f0989b9
|
| --- /dev/null
|
| +++ b/pnacl-llvm/NaClBitcodeHeader.cpp
|
| @@ -0,0 +1,351 @@
|
| +//===- NaClBitcodeHeader.cpp ----------------------------------------------===//
|
| +// PNaCl bitcode header reader.
|
| +//
|
| +// The LLVM Compiler Infrastructure
|
| +//
|
| +// This file is distributed under the University of Illinois Open Source
|
| +// License. See LICENSE.TXT for details.
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +
|
| +#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h"
|
| +
|
| +#include "llvm/ADT/SmallSet.h"
|
| +#include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
|
| +#include "llvm/Bitcode/ReaderWriter.h"
|
| +#include "llvm/Support/ErrorHandling.h"
|
| +#include "llvm/Support/Format.h"
|
| +#include "llvm/Support/raw_ostream.h"
|
| +#include "llvm/Support/StreamingMemoryObject.h"
|
| +
|
| +#include <cstring>
|
| +#include <iomanip>
|
| +#include <limits>
|
| +
|
| +using namespace llvm;
|
| +
|
| +namespace {
|
| +
|
| +// The name for each ID tag.
|
| +static const char *TagName[] = {
|
| + "Invalid", // kInvalid
|
| + "PNaCl Version", // kPNaClVersion
|
| + "Align bitcode records" // kAlignBitcodeRecords
|
| +};
|
| +
|
| +// The name for each field type.
|
| +static const char *FieldTypeName[] = {
|
| + "uint8[]", // kBufferType
|
| + "uint32", // kUInt32Type
|
| + "flag", // kFlagType
|
| + "unknown" // kUnknownType
|
| +};
|
| +
|
| +// The type associated with each ID tag.
|
| +static const NaClBitcodeHeaderField::FieldType ExpectedType[] = {
|
| + NaClBitcodeHeaderField::kUnknownType, // kInvalid
|
| + NaClBitcodeHeaderField::kUInt32Type, // kPNaClVersion
|
| + NaClBitcodeHeaderField::kFlagType // kAlignBitcodeRecords
|
| +};
|
| +
|
| +} // end of anonymous namespace
|
| +
|
| +const char *NaClBitcodeHeaderField::IDName(Tag ID) {
|
| + return ID > kTag_MAX ? "???" : TagName[ID];
|
| +}
|
| +
|
| +const char *NaClBitcodeHeaderField::TypeName(FieldType FType) {
|
| + return FType > kFieldType_MAX ? "???" : FieldTypeName[FType];
|
| +}
|
| +
|
| +NaClBitcodeHeaderField::NaClBitcodeHeaderField()
|
| + : ID(kInvalid), FType(kBufferType), Len(0), Data(0) {}
|
| +
|
| +NaClBitcodeHeaderField::NaClBitcodeHeaderField(Tag MyID)
|
| + : ID(MyID), FType(kFlagType), Len(0), Data(0) {
|
| + assert(MyID <= kTag_MAX);
|
| +}
|
| +
|
| +NaClBitcodeHeaderField::NaClBitcodeHeaderField(Tag MyID, uint32_t MyValue)
|
| + : ID(MyID), FType(kUInt32Type), Len(4), Data(new uint8_t[4]) {
|
| + assert(MyID <= kTag_MAX);
|
| + Data[0] = static_cast<uint8_t>(MyValue & 0xFF);
|
| + Data[1] = static_cast<uint8_t>((MyValue >> 8) & 0xFF);
|
| + Data[2] = static_cast<uint8_t>((MyValue >> 16) & 0xFF);
|
| + Data[3] = static_cast<uint8_t>((MyValue >> 24) & 0xFF);
|
| +}
|
| +
|
| +uint32_t NaClBitcodeHeaderField::GetUInt32Value() const {
|
| + assert(FType == kUInt32Type && "Header field must be uint32");
|
| + return static_cast<uint32_t>(Data[0]) |
|
| + (static_cast<uint32_t>(Data[1]) << 8) |
|
| + (static_cast<uint32_t>(Data[2]) << 16) |
|
| + (static_cast<uint32_t>(Data[2]) << 24);
|
| +}
|
| +
|
| +NaClBitcodeHeaderField::NaClBitcodeHeaderField(Tag MyID, size_t MyLen,
|
| + uint8_t *MyData)
|
| + : ID(MyID), FType(kBufferType), Len(MyLen), Data(new uint8_t[MyLen]) {
|
| + assert(MyID <= kTag_MAX);
|
| + for (size_t i = 0; i < MyLen; ++i) {
|
| + Data[i] = MyData[i];
|
| + }
|
| +}
|
| +
|
| +bool NaClBitcodeHeaderField::Write(uint8_t *Buf, size_t BufLen) const {
|
| + size_t FieldsLen = kTagLenSize + Len;
|
| + size_t PadLen = (WordSize - (FieldsLen & (WordSize-1))) & (WordSize-1);
|
| + // Ensure buffer is large enough and that length can be represented
|
| + // in 32 bits
|
| + if (BufLen < FieldsLen + PadLen ||
|
| + Len > std::numeric_limits<FixedSubfield>::max())
|
| + return false;
|
| +
|
| + WriteFixedSubfield(EncodeTypedID(), Buf);
|
| + WriteFixedSubfield(static_cast<FixedSubfield>(Len),
|
| + Buf + sizeof(FixedSubfield));
|
| + memcpy(Buf + kTagLenSize, Data, Len);
|
| + // Pad out to word alignment
|
| + if (PadLen) {
|
| + memset(Buf + FieldsLen, 0, PadLen);
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool NaClBitcodeHeaderField::Read(const uint8_t *Buf, size_t BufLen) {
|
| + if (BufLen < kTagLenSize)
|
| + return false;
|
| + FixedSubfield IdField;
|
| + ReadFixedSubfield(&IdField, Buf);
|
| + FixedSubfield LengthField;
|
| + ReadFixedSubfield(&LengthField, Buf + sizeof(FixedSubfield));
|
| + size_t Length = static_cast<size_t>(LengthField);
|
| + if (BufLen < kTagLenSize + Length)
|
| + return false;
|
| + if (Len != Length) {
|
| + // Need to reallocate data buffer.
|
| + if (Data)
|
| + delete[] Data;
|
| + Data = new uint8_t[Length];
|
| + }
|
| + Len = Length;
|
| + DecodeTypedID(IdField, ID, FType);
|
| + memcpy(Data, Buf + kTagLenSize, Len);
|
| + return true;
|
| +}
|
| +
|
| +std::string NaClBitcodeHeaderField::Contents() const {
|
| + std::string buffer;
|
| + raw_string_ostream ss(buffer);
|
| + ss << IDName() << ": ";
|
| + switch (FType) {
|
| + case kFlagType:
|
| + ss << "true";
|
| + break;
|
| + case kUInt32Type:
|
| + ss << GetUInt32Value();
|
| + break;
|
| + case kBufferType:
|
| + ss << "[";
|
| + for (size_t i = 0; i < Len; ++i) {
|
| + if (i)
|
| + ss << " ";
|
| + ss << format("%02x", Data[i]);
|
| + }
|
| + ss << "]";
|
| + break;
|
| + case kUnknownType:
|
| + ss << "unknown value";
|
| + break;
|
| + }
|
| + return ss.str();
|
| +}
|
| +
|
| +NaClBitcodeHeader::NaClBitcodeHeader()
|
| + : HeaderSize(0), UnsupportedMessage(), IsSupportedFlag(false),
|
| + IsReadableFlag(false), PNaClVersion(0) {}
|
| +
|
| +NaClBitcodeHeader::~NaClBitcodeHeader() {
|
| + for (std::vector<NaClBitcodeHeaderField *>::const_iterator
|
| + Iter = Fields.begin(),
|
| + IterEnd = Fields.end();
|
| + Iter != IterEnd; ++Iter) {
|
| + delete *Iter;
|
| + }
|
| +}
|
| +
|
| +bool NaClBitcodeHeader::ReadPrefix(const unsigned char *BufPtr,
|
| + const unsigned char *BufEnd,
|
| + unsigned &NumFields, unsigned &NumBytes) {
|
| + // Must contain PEXE.
|
| + if (!isNaClBitcode(BufPtr, BufEnd)) {
|
| + UnsupportedMessage = "Invalid PNaCl bitcode header";
|
| + if (isBitcode(BufPtr, BufEnd)) {
|
| + UnsupportedMessage += " (to run in Chrome, bitcode files must be "
|
| + "finalized using pnacl-finalize)";
|
| + }
|
| + return true;
|
| + }
|
| + BufPtr += WordSize;
|
| +
|
| + // Read #Fields and number of bytes needed for the header.
|
| + if (BufPtr + WordSize > BufEnd)
|
| + return UnsupportedError("Bitcode read failure");
|
| + NumFields = static_cast<unsigned>(BufPtr[0]) |
|
| + (static_cast<unsigned>(BufPtr[1]) << 8);
|
| + NumBytes = static_cast<unsigned>(BufPtr[2]) |
|
| + (static_cast<unsigned>(BufPtr[3]) << 8);
|
| + BufPtr += WordSize;
|
| + return false;
|
| +}
|
| +
|
| +bool NaClBitcodeHeader::ReadFields(const unsigned char *BufPtr,
|
| + const unsigned char *BufEnd,
|
| + unsigned NumFields, unsigned NumBytes) {
|
| + HeaderSize = NumBytes + (2 * WordSize);
|
| +
|
| + // Read in each field.
|
| + for (size_t i = 0; i < NumFields; ++i) {
|
| + NaClBitcodeHeaderField *Field = new NaClBitcodeHeaderField();
|
| + Fields.push_back(Field);
|
| + if (!Field->Read(BufPtr, BufEnd - BufPtr))
|
| + return UnsupportedError("Bitcode read failure");
|
| + size_t FieldSize = Field->GetTotalSize();
|
| + BufPtr += FieldSize;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +bool NaClBitcodeHeader::Read(const unsigned char *BufPtr,
|
| + const unsigned char *BufEnd) {
|
| + unsigned NumFields;
|
| + unsigned NumBytes;
|
| + if (ReadPrefix(BufPtr, BufEnd, NumFields, NumBytes))
|
| + return true; // ReadPrefix sets UnsupportedMessage
|
| + BufPtr += 2 * WordSize;
|
| +
|
| + if (ReadFields(BufPtr, BufEnd, NumFields, NumBytes))
|
| + return true; // ReadFields sets UnsupportedMessage
|
| + BufPtr += NumBytes;
|
| + InstallFields();
|
| + return false;
|
| +}
|
| +
|
| +bool NaClBitcodeHeader::Read(MemoryObject *Bytes) {
|
| + unsigned NumFields;
|
| + unsigned NumBytes;
|
| + // First, read the prefix, which is 2 * WordSize, to determine the
|
| + // NumBytes and NumFields.
|
| + {
|
| + unsigned char Buffer[2 * WordSize];
|
| + if (Bytes->readBytes(Buffer, sizeof(Buffer), 0) != sizeof(Buffer))
|
| + return UnsupportedError("Bitcode read failure");
|
| + if (ReadPrefix(Buffer, Buffer + sizeof(Buffer), NumFields, NumBytes))
|
| + return true; // ReadPrefix sets UnsupportedMessage
|
| + }
|
| + // Then read the rest, starting after the 2 * WordSize of the prefix.
|
| + uint8_t *Header = new uint8_t[NumBytes];
|
| + bool failed =
|
| + Bytes->readBytes(Header, NumBytes, 2 * WordSize) != NumBytes ||
|
| + ReadFields(Header, Header + NumBytes, NumFields, NumBytes);
|
| + delete[] Header;
|
| + if (failed)
|
| + return UnsupportedError("Bitcode read failure");
|
| + InstallFields();
|
| + return false;
|
| +}
|
| +
|
| +NaClBitcodeHeaderField *
|
| +NaClBitcodeHeader::GetTaggedField(NaClBitcodeHeaderField::Tag ID) const {
|
| + for (std::vector<NaClBitcodeHeaderField *>::const_iterator
|
| + Iter = Fields.begin(),
|
| + IterEnd = Fields.end();
|
| + Iter != IterEnd; ++Iter) {
|
| + if ((*Iter)->GetID() == ID) {
|
| + return *Iter;
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +NaClBitcodeHeaderField *NaClBitcodeHeader::GetField(size_t index) const {
|
| + if (index >= Fields.size())
|
| + return 0;
|
| + return Fields[index];
|
| +}
|
| +
|
| +NaClBitcodeHeaderField *GetPNaClVersionPtr(NaClBitcodeHeader *Header) {
|
| + if (NaClBitcodeHeaderField *Version =
|
| + Header->GetTaggedField(NaClBitcodeHeaderField::kPNaClVersion)) {
|
| + if (Version->GetType() == NaClBitcodeHeaderField::kUInt32Type) {
|
| + return Version;
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +void NaClBitcodeHeader::InstallFields() {
|
| + IsSupportedFlag = true;
|
| + IsReadableFlag = true;
|
| + AlignBitcodeRecords = false;
|
| + PNaClVersion = 0;
|
| + UnsupportedMessage.clear();
|
| + SmallSet<unsigned, NaClBitcodeHeaderField::kTag_MAX> FieldIDs;
|
| +
|
| + auto ReportProblem = [&](bool IsReadable) {
|
| + UnsupportedMessage.append("\n");
|
| + IsSupportedFlag = false;
|
| + IsReadableFlag = IsReadableFlag && IsReadable;
|
| + };
|
| +
|
| + auto ReportProblemWithContents = [&](NaClBitcodeHeaderField *Field,
|
| + bool IsReadable) {
|
| + UnsupportedMessage.append(": ");
|
| + UnsupportedMessage.append(Field->Contents());
|
| + ReportProblem(IsReadable);
|
| + };
|
| +
|
| + for (size_t i = 0, e = NumberFields(); i < e; ++i) {
|
| + // Start by checking expected properties for any field
|
| + NaClBitcodeHeaderField *Field = GetField(i);
|
| + if (!FieldIDs.insert(Field->GetID()).second) {
|
| + UnsupportedMessage.append("Specified multiple times: ");
|
| + UnsupportedMessage.append(Field->IDName());
|
| + ReportProblem(false);
|
| + continue;
|
| + }
|
| + NaClBitcodeHeaderField::FieldType ExpectedTy = ExpectedType[Field->GetID()];
|
| + if (Field->GetType() != ExpectedTy) {
|
| + UnsupportedMessage.append("Expects type ");
|
| + UnsupportedMessage.append(NaClBitcodeHeaderField::TypeName(ExpectedTy));
|
| + ReportProblemWithContents(Field, false);
|
| + continue;
|
| + }
|
| + if (Field->GetType() == NaClBitcodeHeaderField::kUnknownType) {
|
| + UnsupportedMessage.append("Unknown value");
|
| + ReportProblemWithContents(Field, false);
|
| + continue;
|
| + }
|
| +
|
| + // Check specific ID values and install.
|
| + switch (Field->GetID()) {
|
| + case NaClBitcodeHeaderField::kInvalid:
|
| + UnsupportedMessage.append("Unsupported");
|
| + ReportProblemWithContents(Field, false);
|
| + continue;
|
| + case NaClBitcodeHeaderField::kPNaClVersion:
|
| + PNaClVersion = Field->GetUInt32Value();
|
| + if (PNaClVersion != 2) {
|
| + UnsupportedMessage.append("Unsupported");
|
| + ReportProblemWithContents(Field, false);
|
| + continue;
|
| + }
|
| + break;
|
| + case NaClBitcodeHeaderField::kAlignBitcodeRecords:
|
| + AlignBitcodeRecords = true;
|
| + UnsupportedMessage.append("Unsupported");
|
| + ReportProblemWithContents(Field, true);
|
| + continue;
|
| + }
|
| + }
|
| +}
|
|
|