blob: 50ca5aaed86e65b132b5055ccfb4d6cfbdc74bab [file] [log] [blame]
//===-- llvm/Bitcode/NaCl/NaClBitcodeHeader.h - ----------------*- C++ -*-===//
// NaCl Bitcode header reader.
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This header defines interfaces to read and write NaCl bitcode wire format
// file headers.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_BITCODE_NACL_NACLBITCODEHEADER_H
#define LLVM_BITCODE_NACL_NACLBITCODEHEADER_H
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DataTypes.h"
#include <string>
#include <vector>
namespace llvm {
class MemoryObject;
// Class representing a variable-size metadata field in the bitcode header.
// Also contains the list of known (typed) Tag IDs.
//
// The serialized format has 2 fixed subfields (ID:type and data length) and the
// variable-length data subfield
class NaClBitcodeHeaderField {
NaClBitcodeHeaderField(const NaClBitcodeHeaderField &) = delete;
void operator=(const NaClBitcodeHeaderField &) = delete;
public:
// Defines the ID associated with the value. Valid values are in
// {0x0, ..., 0xFFF}
typedef enum {
kInvalid = 0, // KUnknownType.
kPNaClVersion = 1, // kUint32Type.
kAlignBitcodeRecords = 2, // kFlagType.
kTag_MAX = kAlignBitcodeRecords
} Tag;
// Defines the type of value.
typedef enum {
kBufferType, // Buffer of form uint8_t[len].
kUInt32Type,
kFlagType,
kUnknownType,
kFieldType_MAX = kUnknownType
} FieldType;
// Defines the number of bytes in a (32-bit) word.
static const int WordSize = 4;
// Defines the encoding of the fixed fields {i.e. ID:type and data length).
typedef uint16_t FixedSubfield;
// Create an invalid header field.
NaClBitcodeHeaderField();
// Creates a header field where MyID is a flag.
NaClBitcodeHeaderField(Tag MyID);
// Create a header field with an uint32_t value.
NaClBitcodeHeaderField(Tag MyID, uint32_t value);
// Create a header field for the given data.
NaClBitcodeHeaderField(Tag MyID, size_t MyLen, uint8_t *MyData);
virtual ~NaClBitcodeHeaderField() {
if (Data)
delete[] Data;
}
/// \brief Number of bytes used to represent header field.
size_t GetTotalSize() const {
// Round up to 4 byte alignment
return (kTagLenSize + Len + (WordSize - 1)) & ~(WordSize - 1);
}
/// \brief Write field into Buf[BufLen].
bool Write(uint8_t *Buf, size_t BufLen) const;
/// \brief Read field from Buf[BufLen].
bool Read(const uint8_t *Buf, size_t BufLen);
/// \brief Returns string describing ID of field.
static const char *IDName(Tag ID);
const char *IDName() const {
return IDName(ID);
}
/// \brief Returns string describing type of field.
static const char *TypeName(FieldType FType);
const char *TypeName() const {
return TypeName(FType);
}
/// \brief Returns string describing field.
std::string Contents() const;
/// \brief Get the data size from a serialized field to allow allocation.
static size_t GetDataSizeFromSerialized(const uint8_t *Buf) {
FixedSubfield Length;
ReadFixedSubfield(&Length, Buf + sizeof(FixedSubfield));
return Length;
}
/// \brief Return the ID of the field.
Tag GetID() const { return ID; }
FieldType GetType() const { return FType; }
/// \brief Return the length of the data (in bytes).
size_t GetLen() const { return Len; }
/// \brief Return the data. Data is array getData()[getLen()].
const uint8_t *GetData() const { return Data; }
/// \brief Returns the uint32_t value stored. Requires that
/// getType() == kUint32Type
uint32_t GetUInt32Value() const;
private:
// Convert ID:Type into a fixed subfield
FixedSubfield EncodeTypedID() const { return (ID << 4) | FType; }
// Extract out ID and Type from a fixed subfield.
void DecodeTypedID(FixedSubfield Subfield, Tag &ID, FieldType &FType) {
FixedSubfield PossibleID = Subfield >> 4;
ID = (PossibleID > kTag_MAX ? kInvalid : static_cast<Tag>(PossibleID));
FixedSubfield PossibleFType = Subfield & 0xF;
FType = (PossibleFType > kFieldType_MAX
? kUnknownType : static_cast<FieldType>(PossibleFType));
}
// Combined size of the fixed subfields
const static size_t kTagLenSize = 2 * sizeof(FixedSubfield);
static void WriteFixedSubfield(FixedSubfield Value, uint8_t *Buf) {
Buf[0] = Value & 0xFF;
Buf[1] = (Value >> 8) & 0xFF;
}
static void ReadFixedSubfield(FixedSubfield *Value, const uint8_t *Buf) {
*Value = Buf[0] | Buf[1] << 8;
}
Tag ID;
FieldType FType;
size_t Len;
uint8_t *Data;
};
/// \brief Class holding parsed header fields in PNaCl bitcode file.
class NaClBitcodeHeader {
NaClBitcodeHeader(const NaClBitcodeHeader &) = delete;
void operator=(const NaClBitcodeHeader &) = delete;
// The set of parsed header fields. The header takes ownership of
// all fields in this vector.
std::vector<NaClBitcodeHeaderField *> Fields;
// The number of bytes in the PNaCl header.
size_t HeaderSize;
// String defining why it is unsupported (if unsupported).
std::string UnsupportedMessage;
// Flag defining if header is supported.
bool IsSupportedFlag;
// Flag defining if the corresponding bitcode file is readable.
bool IsReadableFlag;
// Defines the PNaCl version defined by the header file.
uint32_t PNaClVersion;
// Byte align bitcode records when nonzero.
bool AlignBitcodeRecords = false;
public:
static const int WordSize = NaClBitcodeHeaderField::WordSize;
NaClBitcodeHeader();
~NaClBitcodeHeader();
/// \brief Installs the fields of the header, defining if the header
/// is readable and supported. Sets UnsupportedMessage on failure.
void InstallFields();
/// \brief Adds a field to the list of fields in a header. Takes ownership
/// of fields added.
void push_back(NaClBitcodeHeaderField *Field) {
Fields.push_back(Field);
}
/// \brief Read the PNaCl bitcode header, The format of the header is:
///
/// 1) 'PEXE' - The four character sequence defining the magic number.
/// 2) uint_16 num_fields - The number of NaClBitcodeHeaderField's.
/// 3) uint_16 num_bytes - The number of bytes to hold fields in
/// the header.
/// 4) NaClBitcodeHeaderField f1 - The first bitcode header field.
/// ...
/// 2 + num_fields) NaClBitcodeHeaderField fn - The last bitcode header
/// field.
///
/// Returns false if able to read (all of) the bitcode header.
bool Read(const unsigned char *BufPtr, const unsigned char *BufEnd);
// \brief Read the PNaCl bitcode header, recording the fields found
// in the header. Returns false if able to read (all of) the bitcode header.
bool Read(MemoryObject *Bytes);
// \brief Returns the number of bytes read to consume the header.
size_t getHeaderSize() { return HeaderSize; }
/// \brief Returns string describing why the header describes
/// an unsupported PNaCl Bitcode file.
const std::string &Unsupported() const { return UnsupportedMessage; }
/// \brief Returns true if supported. That is, it can be run in the
/// browser.
bool IsSupported() const { return IsSupportedFlag; }
/// \brief Returns true if the bitcode file should be readable. Note
/// that just because it is readable, it doesn't necessarily mean that
/// it is supported.
bool IsReadable() const { return IsReadableFlag; }
/// \brief Returns number of fields defined.
size_t NumberFields() const { return Fields.size(); }
/// \brief Returns a pointer to the field with the given ID
/// (0 if no such field).
NaClBitcodeHeaderField *GetTaggedField(NaClBitcodeHeaderField::Tag ID) const;
/// \brief Returns a pointer to the Nth field in the header
/// (0 if no such field).
NaClBitcodeHeaderField *GetField(size_t index) const;
/// \brief Returns the PNaClVersion, as defined by the header.
uint32_t GetPNaClVersion() const { return PNaClVersion; }
/// \brief Returns if one should byte align bitcode records.
bool getAlignBitcodeRecords() const { return AlignBitcodeRecords; }
private:
// Reads and verifies the first 8 bytes of the header, consisting
// of the magic number 'PEXE', and the value defining the number
// of fields and number of bytes used to hold fields.
// Returns false if successful, sets UnsupportedMessage otherwise.
bool ReadPrefix(const unsigned char *BufPtr, const unsigned char *BufEnd,
unsigned &NumFields, unsigned &NumBytes);
// Reads and verifies the fields in the header.
// Returns false if successful, sets UnsupportedMessage otherwise.
bool ReadFields(const unsigned char *BufPtr, const unsigned char *BufEnd,
unsigned NumFields, unsigned NumBytes);
// Sets the Unsupported error message and returns true.
bool UnsupportedError(StringRef Message) {
UnsupportedMessage = Message.str();
return true;
}
};
} // namespace llvm
#endif