1 //===- NaClBitcodeHeader.cpp ----------------------------------------------===//
2 // PNaCl bitcode header reader.
3 //
4 // The LLVM Compiler Infrastructure
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License. See LICENSE.TXT for details.
8 //
9 //===----------------------------------------------------------------------===//
10
11 #include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h"
12
13 #include "llvm/ADT/SmallSet.h"
14 #include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
15 #include "llvm/Bitcode/ReaderWriter.h"
16 #include "llvm/Support/ErrorHandling.h"
17 #include "llvm/Support/Format.h"
18 #include "llvm/Support/raw_ostream.h"
19 #include "llvm/Support/StreamingMemoryObject.h"
20
21 #include <cstring>
22 #include <iomanip>
23 #include <limits>
24
25 using namespace llvm;
26
27 namespace {
28
29 // The name for each ID tag.
30 static const char *TagName[] = {
31 "Invalid", // kInvalid
32 "PNaCl Version", // kPNaClVersion
33 "Align bitcode records" // kAlignBitcodeRecords
34 };
35
36 // The name for each field type.
37 static const char *FieldTypeName[] = {
38 "uint8[]", // kBufferType
39 "uint32", // kUInt32Type
40 "flag", // kFlagType
41 "unknown" // kUnknownType
42 };
43
44 // The type associated with each ID tag.
45 static const NaClBitcodeHeaderField::FieldType ExpectedType[] = {
46 NaClBitcodeHeaderField::kUnknownType, // kInvalid
47 NaClBitcodeHeaderField::kUInt32Type, // kPNaClVersion
48 NaClBitcodeHeaderField::kFlagType // kAlignBitcodeRecords
49 };
50
51 } // end of anonymous namespace
52
IDName(Tag ID)53 const char *NaClBitcodeHeaderField::IDName(Tag ID) {
54 return ID > kTag_MAX ? "???" : TagName[ID];
55 }
56
TypeName(FieldType FType)57 const char *NaClBitcodeHeaderField::TypeName(FieldType FType) {
58 return FType > kFieldType_MAX ? "???" : FieldTypeName[FType];
59 }
60
NaClBitcodeHeaderField()61 NaClBitcodeHeaderField::NaClBitcodeHeaderField()
62 : ID(kInvalid), FType(kBufferType), Len(0), Data(0) {}
63
NaClBitcodeHeaderField(Tag MyID)64 NaClBitcodeHeaderField::NaClBitcodeHeaderField(Tag MyID)
65 : ID(MyID), FType(kFlagType), Len(0), Data(0) {
66 assert(MyID <= kTag_MAX);
67 }
68
NaClBitcodeHeaderField(Tag MyID,uint32_t MyValue)69 NaClBitcodeHeaderField::NaClBitcodeHeaderField(Tag MyID, uint32_t MyValue)
70 : ID(MyID), FType(kUInt32Type), Len(4), Data(new uint8_t[4]) {
71 assert(MyID <= kTag_MAX);
72 Data[0] = static_cast<uint8_t>(MyValue & 0xFF);
73 Data[1] = static_cast<uint8_t>((MyValue >> 8) & 0xFF);
74 Data[2] = static_cast<uint8_t>((MyValue >> 16) & 0xFF);
75 Data[3] = static_cast<uint8_t>((MyValue >> 24) & 0xFF);
76 }
77
GetUInt32Value() const78 uint32_t NaClBitcodeHeaderField::GetUInt32Value() const {
79 assert(FType == kUInt32Type && "Header field must be uint32");
80 return static_cast<uint32_t>(Data[0]) |
81 (static_cast<uint32_t>(Data[1]) << 8) |
82 (static_cast<uint32_t>(Data[2]) << 16) |
83 (static_cast<uint32_t>(Data[2]) << 24);
84 }
85
NaClBitcodeHeaderField(Tag MyID,size_t MyLen,uint8_t * MyData)86 NaClBitcodeHeaderField::NaClBitcodeHeaderField(Tag MyID, size_t MyLen,
87 uint8_t *MyData)
88 : ID(MyID), FType(kBufferType), Len(MyLen), Data(new uint8_t[MyLen]) {
89 assert(MyID <= kTag_MAX);
90 for (size_t i = 0; i < MyLen; ++i) {
91 Data[i] = MyData[i];
92 }
93 }
94
Write(uint8_t * Buf,size_t BufLen) const95 bool NaClBitcodeHeaderField::Write(uint8_t *Buf, size_t BufLen) const {
96 size_t FieldsLen = kTagLenSize + Len;
97 size_t PadLen = (WordSize - (FieldsLen & (WordSize-1))) & (WordSize-1);
98 // Ensure buffer is large enough and that length can be represented
99 // in 32 bits
100 if (BufLen < FieldsLen + PadLen ||
101 Len > std::numeric_limits<FixedSubfield>::max())
102 return false;
103
104 WriteFixedSubfield(EncodeTypedID(), Buf);
105 WriteFixedSubfield(static_cast<FixedSubfield>(Len),
106 Buf + sizeof(FixedSubfield));
107 memcpy(Buf + kTagLenSize, Data, Len);
108 // Pad out to word alignment
109 if (PadLen) {
110 memset(Buf + FieldsLen, 0, PadLen);
111 }
112 return true;
113 }
114
Read(const uint8_t * Buf,size_t BufLen)115 bool NaClBitcodeHeaderField::Read(const uint8_t *Buf, size_t BufLen) {
116 if (BufLen < kTagLenSize)
117 return false;
118 FixedSubfield IdField;
119 ReadFixedSubfield(&IdField, Buf);
120 FixedSubfield LengthField;
121 ReadFixedSubfield(&LengthField, Buf + sizeof(FixedSubfield));
122 size_t Length = static_cast<size_t>(LengthField);
123 if (BufLen < kTagLenSize + Length)
124 return false;
125 if (Len != Length) {
126 // Need to reallocate data buffer.
127 if (Data)
128 delete[] Data;
129 Data = new uint8_t[Length];
130 }
131 Len = Length;
132 DecodeTypedID(IdField, ID, FType);
133 memcpy(Data, Buf + kTagLenSize, Len);
134 return true;
135 }
136
Contents() const137 std::string NaClBitcodeHeaderField::Contents() const {
138 std::string buffer;
139 raw_string_ostream ss(buffer);
140 ss << IDName() << ": ";
141 switch (FType) {
142 case kFlagType:
143 ss << "true";
144 break;
145 case kUInt32Type:
146 ss << GetUInt32Value();
147 break;
148 case kBufferType:
149 ss << "[";
150 for (size_t i = 0; i < Len; ++i) {
151 if (i)
152 ss << " ";
153 ss << format("%02x", Data[i]);
154 }
155 ss << "]";
156 break;
157 case kUnknownType:
158 ss << "unknown value";
159 break;
160 }
161 return ss.str();
162 }
163
NaClBitcodeHeader()164 NaClBitcodeHeader::NaClBitcodeHeader()
165 : HeaderSize(0), UnsupportedMessage(), IsSupportedFlag(false),
166 IsReadableFlag(false), PNaClVersion(0) {}
167
~NaClBitcodeHeader()168 NaClBitcodeHeader::~NaClBitcodeHeader() {
169 for (std::vector<NaClBitcodeHeaderField *>::const_iterator
170 Iter = Fields.begin(),
171 IterEnd = Fields.end();
172 Iter != IterEnd; ++Iter) {
173 delete *Iter;
174 }
175 }
176
ReadPrefix(const unsigned char * BufPtr,const unsigned char * BufEnd,unsigned & NumFields,unsigned & NumBytes)177 bool NaClBitcodeHeader::ReadPrefix(const unsigned char *BufPtr,
178 const unsigned char *BufEnd,
179 unsigned &NumFields, unsigned &NumBytes) {
180 // Must contain PEXE.
181 if (!isNaClBitcode(BufPtr, BufEnd)) {
182 UnsupportedMessage = "Invalid PNaCl bitcode header";
183 if (isBitcode(BufPtr, BufEnd)) {
184 UnsupportedMessage += " (to run in Chrome, bitcode files must be "
185 "finalized using pnacl-finalize)";
186 }
187 return true;
188 }
189 BufPtr += WordSize;
190
191 // Read #Fields and number of bytes needed for the header.
192 if (BufPtr + WordSize > BufEnd)
193 return UnsupportedError("Bitcode read failure");
194 NumFields = static_cast<unsigned>(BufPtr[0]) |
195 (static_cast<unsigned>(BufPtr[1]) << 8);
196 NumBytes = static_cast<unsigned>(BufPtr[2]) |
197 (static_cast<unsigned>(BufPtr[3]) << 8);
198 BufPtr += WordSize;
199 return false;
200 }
201
ReadFields(const unsigned char * BufPtr,const unsigned char * BufEnd,unsigned NumFields,unsigned NumBytes)202 bool NaClBitcodeHeader::ReadFields(const unsigned char *BufPtr,
203 const unsigned char *BufEnd,
204 unsigned NumFields, unsigned NumBytes) {
205 HeaderSize = NumBytes + (2 * WordSize);
206
207 // Read in each field.
208 for (size_t i = 0; i < NumFields; ++i) {
209 NaClBitcodeHeaderField *Field = new NaClBitcodeHeaderField();
210 Fields.push_back(Field);
211 if (!Field->Read(BufPtr, BufEnd - BufPtr))
212 return UnsupportedError("Bitcode read failure");
213 size_t FieldSize = Field->GetTotalSize();
214 BufPtr += FieldSize;
215 }
216 return false;
217 }
218
Read(const unsigned char * BufPtr,const unsigned char * BufEnd)219 bool NaClBitcodeHeader::Read(const unsigned char *BufPtr,
220 const unsigned char *BufEnd) {
221 unsigned NumFields;
222 unsigned NumBytes;
223 if (ReadPrefix(BufPtr, BufEnd, NumFields, NumBytes))
224 return true; // ReadPrefix sets UnsupportedMessage
225 BufPtr += 2 * WordSize;
226
227 if (ReadFields(BufPtr, BufEnd, NumFields, NumBytes))
228 return true; // ReadFields sets UnsupportedMessage
229 BufPtr += NumBytes;
230 InstallFields();
231 return false;
232 }
233
Read(MemoryObject * Bytes)234 bool NaClBitcodeHeader::Read(MemoryObject *Bytes) {
235 unsigned NumFields;
236 unsigned NumBytes;
237 // First, read the prefix, which is 2 * WordSize, to determine the
238 // NumBytes and NumFields.
239 {
240 unsigned char Buffer[2 * WordSize];
241 if (Bytes->readBytes(Buffer, sizeof(Buffer), 0) != sizeof(Buffer))
242 return UnsupportedError("Bitcode read failure");
243 if (ReadPrefix(Buffer, Buffer + sizeof(Buffer), NumFields, NumBytes))
244 return true; // ReadPrefix sets UnsupportedMessage
245 }
246 // Then read the rest, starting after the 2 * WordSize of the prefix.
247 uint8_t *Header = new uint8_t[NumBytes];
248 bool failed =
249 Bytes->readBytes(Header, NumBytes, 2 * WordSize) != NumBytes ||
250 ReadFields(Header, Header + NumBytes, NumFields, NumBytes);
251 delete[] Header;
252 if (failed)
253 return UnsupportedError("Bitcode read failure");
254 InstallFields();
255 return false;
256 }
257
258 NaClBitcodeHeaderField *
GetTaggedField(NaClBitcodeHeaderField::Tag ID) const259 NaClBitcodeHeader::GetTaggedField(NaClBitcodeHeaderField::Tag ID) const {
260 for (std::vector<NaClBitcodeHeaderField *>::const_iterator
261 Iter = Fields.begin(),
262 IterEnd = Fields.end();
263 Iter != IterEnd; ++Iter) {
264 if ((*Iter)->GetID() == ID) {
265 return *Iter;
266 }
267 }
268 return 0;
269 }
270
GetField(size_t index) const271 NaClBitcodeHeaderField *NaClBitcodeHeader::GetField(size_t index) const {
272 if (index >= Fields.size())
273 return 0;
274 return Fields[index];
275 }
276
GetPNaClVersionPtr(NaClBitcodeHeader * Header)277 NaClBitcodeHeaderField *GetPNaClVersionPtr(NaClBitcodeHeader *Header) {
278 if (NaClBitcodeHeaderField *Version =
279 Header->GetTaggedField(NaClBitcodeHeaderField::kPNaClVersion)) {
280 if (Version->GetType() == NaClBitcodeHeaderField::kUInt32Type) {
281 return Version;
282 }
283 }
284 return 0;
285 }
286
InstallFields()287 void NaClBitcodeHeader::InstallFields() {
288 IsSupportedFlag = true;
289 IsReadableFlag = true;
290 AlignBitcodeRecords = false;
291 PNaClVersion = 0;
292 UnsupportedMessage.clear();
293 SmallSet<unsigned, NaClBitcodeHeaderField::kTag_MAX> FieldIDs;
294
295 auto ReportProblem = [&](bool IsReadable) {
296 UnsupportedMessage.append("\n");
297 IsSupportedFlag = false;
298 IsReadableFlag = IsReadableFlag && IsReadable;
299 };
300
301 auto ReportProblemWithContents = [&](NaClBitcodeHeaderField *Field,
302 bool IsReadable) {
303 UnsupportedMessage.append(": ");
304 UnsupportedMessage.append(Field->Contents());
305 ReportProblem(IsReadable);
306 };
307
308 for (size_t i = 0, e = NumberFields(); i < e; ++i) {
309 // Start by checking expected properties for any field
310 NaClBitcodeHeaderField *Field = GetField(i);
311 if (!FieldIDs.insert(Field->GetID()).second) {
312 UnsupportedMessage.append("Specified multiple times: ");
313 UnsupportedMessage.append(Field->IDName());
314 ReportProblem(false);
315 continue;
316 }
317 NaClBitcodeHeaderField::FieldType ExpectedTy = ExpectedType[Field->GetID()];
318 if (Field->GetType() != ExpectedTy) {
319 UnsupportedMessage.append("Expects type ");
320 UnsupportedMessage.append(NaClBitcodeHeaderField::TypeName(ExpectedTy));
321 ReportProblemWithContents(Field, false);
322 continue;
323 }
324 if (Field->GetType() == NaClBitcodeHeaderField::kUnknownType) {
325 UnsupportedMessage.append("Unknown value");
326 ReportProblemWithContents(Field, false);
327 continue;
328 }
329
330 // Check specific ID values and install.
331 switch (Field->GetID()) {
332 case NaClBitcodeHeaderField::kInvalid:
333 UnsupportedMessage.append("Unsupported");
334 ReportProblemWithContents(Field, false);
335 continue;
336 case NaClBitcodeHeaderField::kPNaClVersion:
337 PNaClVersion = Field->GetUInt32Value();
338 if (PNaClVersion != 2) {
339 UnsupportedMessage.append("Unsupported");
340 ReportProblemWithContents(Field, false);
341 continue;
342 }
343 break;
344 case NaClBitcodeHeaderField::kAlignBitcodeRecords:
345 AlignBitcodeRecords = true;
346 UnsupportedMessage.append("Unsupported");
347 ReportProblemWithContents(Field, true);
348 continue;
349 }
350 }
351 }
352