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 53 const char *NaClBitcodeHeaderField::IDName(Tag ID) { 54 return ID > kTag_MAX ? "???" : TagName[ID]; 55 } 56 57 const char *NaClBitcodeHeaderField::TypeName(FieldType FType) { 58 return FType > kFieldType_MAX ? "???" : FieldTypeName[FType]; 59 } 60 61 NaClBitcodeHeaderField::NaClBitcodeHeaderField() 62 : ID(kInvalid), FType(kBufferType), Len(0), Data(0) {} 63 64 NaClBitcodeHeaderField::NaClBitcodeHeaderField(Tag MyID) 65 : ID(MyID), FType(kFlagType), Len(0), Data(0) { 66 assert(MyID <= kTag_MAX); 67 } 68 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 78 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 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 95 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 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 137 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 164 NaClBitcodeHeader::NaClBitcodeHeader() 165 : HeaderSize(0), UnsupportedMessage(), IsSupportedFlag(false), 166 IsReadableFlag(false), PNaClVersion(0) {} 167 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 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 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 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 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 * 259 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 271 NaClBitcodeHeaderField *NaClBitcodeHeader::GetField(size_t index) const { 272 if (index >= Fields.size()) 273 return 0; 274 return Fields[index]; 275 } 276 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 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