aboutsummaryrefslogtreecommitdiff
path: root/include/llvm/Bitcode/NaCl/NaClBitcodeHeader.h
blob: 4f5f83a17a6cca5a9fc3926f7cbf4261f9d01bf9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
//===-- 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/Support/Compiler.h"
#include "llvm/Support/DataTypes.h"
#include <string>
#include <vector>

namespace llvm {
class StreamableMemoryObject;

// 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 &) LLVM_DELETED_FUNCTION;
  void operator=(const NaClBitcodeHeaderField &)LLVM_DELETED_FUNCTION;

public:
  // Defines the ID associated with the value. Valid values are in
  // {0x0, ..., 0xFFF}
  typedef enum {
    kInvalid = 0,     // KUnknownType.
    kPNaClVersion = 1 // kUint32.
  } Tag;
  // Defines the type of value.
  typedef enum {
    kBufferType, // Buffer of form uint8_t[len].
    kUInt32Type
  } 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();

  // 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 form Buf[BufLen].
  bool Read(const uint8_t *Buf, size_t BufLen);

  /// \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) {
    ID = static_cast<Tag>(Subfield >> 4);
    FType = static_cast<FieldType>(Subfield & 0xF);
  }
  // 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 {
  // 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;

public:
  static const int WordSize = NaClBitcodeHeaderField::WordSize;

  NaClBitcodeHeader();
  ~NaClBitcodeHeader();

  /// \brief Installs the fields of the header, defining if the header
  /// is readable and supported.
  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(StreamableMemoryObject *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; }

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.
  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.
  bool ReadFields(const unsigned char *BufPtr, const unsigned char *BufEnd,
                  unsigned NumFields, unsigned NumBytes);

};

} // namespace llvm

#endif