OLD | NEW |
(Empty) | |
| 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 #include "llvm/Bitcode/NaCl/NaClReaderWriter.h" |
| 13 #include "llvm/Bitcode/ReaderWriter.h" |
| 14 #include "llvm/Support/ErrorHandling.h" |
| 15 #include "llvm/Support/Format.h" |
| 16 #include "llvm/Support/raw_ostream.h" |
| 17 #include "llvm/Support/StreamingMemoryObject.h" |
| 18 |
| 19 #include <limits> |
| 20 #include <cstring> |
| 21 #include <iomanip> |
| 22 |
| 23 using namespace llvm; |
| 24 |
| 25 NaClBitcodeHeaderField::NaClBitcodeHeaderField() |
| 26 : ID(kInvalid), FType(kBufferType), Len(0), Data(0) {} |
| 27 |
| 28 NaClBitcodeHeaderField::NaClBitcodeHeaderField(Tag MyID, uint32_t MyValue) |
| 29 : ID(MyID), FType(kUInt32Type), Len(4), Data(new uint8_t[4]) { |
| 30 Data[0] = static_cast<uint8_t>(MyValue & 0xFF); |
| 31 Data[1] = static_cast<uint8_t>((MyValue >> 8) & 0xFF); |
| 32 Data[2] = static_cast<uint8_t>((MyValue >> 16) & 0xFF); |
| 33 Data[3] = static_cast<uint8_t>((MyValue >> 24) & 0xFF); |
| 34 } |
| 35 |
| 36 uint32_t NaClBitcodeHeaderField::GetUInt32Value() const { |
| 37 assert(FType == kUInt32Type && "Header field must be uint32"); |
| 38 return static_cast<uint32_t>(Data[0]) | |
| 39 (static_cast<uint32_t>(Data[1]) << 8) | |
| 40 (static_cast<uint32_t>(Data[2]) << 16) | |
| 41 (static_cast<uint32_t>(Data[2]) << 24); |
| 42 } |
| 43 |
| 44 NaClBitcodeHeaderField::NaClBitcodeHeaderField(Tag MyID, size_t MyLen, |
| 45 uint8_t *MyData) |
| 46 : ID(MyID), FType(kBufferType), Len(MyLen), Data(new uint8_t[MyLen]) { |
| 47 for (size_t i = 0; i < MyLen; ++i) { |
| 48 Data[i] = MyData[i]; |
| 49 } |
| 50 } |
| 51 |
| 52 bool NaClBitcodeHeaderField::Write(uint8_t *Buf, size_t BufLen) const { |
| 53 size_t FieldsLen = kTagLenSize + Len; |
| 54 size_t PadLen = (WordSize - (FieldsLen & (WordSize-1))) & (WordSize-1); |
| 55 // Ensure buffer is large enough and that length can be represented |
| 56 // in 32 bits |
| 57 if (BufLen < FieldsLen + PadLen || |
| 58 Len > std::numeric_limits<FixedSubfield>::max()) |
| 59 return false; |
| 60 |
| 61 WriteFixedSubfield(EncodeTypedID(), Buf); |
| 62 WriteFixedSubfield(static_cast<FixedSubfield>(Len), |
| 63 Buf + sizeof(FixedSubfield)); |
| 64 memcpy(Buf + kTagLenSize, Data, Len); |
| 65 // Pad out to word alignment |
| 66 if (PadLen) { |
| 67 memset(Buf + FieldsLen, 0, PadLen); |
| 68 } |
| 69 return true; |
| 70 } |
| 71 |
| 72 bool NaClBitcodeHeaderField::Read(const uint8_t *Buf, size_t BufLen) { |
| 73 if (BufLen < kTagLenSize) |
| 74 return false; |
| 75 FixedSubfield IdField; |
| 76 ReadFixedSubfield(&IdField, Buf); |
| 77 FixedSubfield LengthField; |
| 78 ReadFixedSubfield(&LengthField, Buf + sizeof(FixedSubfield)); |
| 79 size_t Length = static_cast<size_t>(LengthField); |
| 80 if (BufLen < kTagLenSize + Length) |
| 81 return false; |
| 82 if (Len != Length) { |
| 83 // Need to reallocate data buffer. |
| 84 if (Data) |
| 85 delete[] Data; |
| 86 Data = new uint8_t[Length]; |
| 87 } |
| 88 Len = Length; |
| 89 DecodeTypedID(IdField, ID, FType); |
| 90 memcpy(Data, Buf + kTagLenSize, Len); |
| 91 return true; |
| 92 } |
| 93 |
| 94 std::string NaClBitcodeHeaderField::Contents() const { |
| 95 std::string buffer; |
| 96 raw_string_ostream ss(buffer); |
| 97 switch (ID) { |
| 98 case kPNaClVersion: |
| 99 ss << "PNaCl Version"; |
| 100 break; |
| 101 case kInvalid: |
| 102 ss << "Invalid"; |
| 103 break; |
| 104 } |
| 105 ss << ": "; |
| 106 switch (FType) { |
| 107 case kUInt32Type: |
| 108 ss << GetUInt32Value(); |
| 109 break; |
| 110 case kBufferType: |
| 111 ss << "["; |
| 112 for (size_t i = 0; i < Len; ++i) { |
| 113 if (i) |
| 114 ss << " "; |
| 115 ss << format("%02x", Data[i]); |
| 116 } |
| 117 ss << "]"; |
| 118 break; |
| 119 } |
| 120 return ss.str(); |
| 121 } |
| 122 |
| 123 NaClBitcodeHeader::NaClBitcodeHeader() |
| 124 : HeaderSize(0), UnsupportedMessage(), IsSupportedFlag(false), |
| 125 IsReadableFlag(false), PNaClVersion(0) {} |
| 126 |
| 127 NaClBitcodeHeader::~NaClBitcodeHeader() { |
| 128 for (std::vector<NaClBitcodeHeaderField *>::const_iterator |
| 129 Iter = Fields.begin(), |
| 130 IterEnd = Fields.end(); |
| 131 Iter != IterEnd; ++Iter) { |
| 132 delete *Iter; |
| 133 } |
| 134 } |
| 135 |
| 136 bool NaClBitcodeHeader::ReadPrefix(const unsigned char *BufPtr, |
| 137 const unsigned char *BufEnd, |
| 138 unsigned &NumFields, unsigned &NumBytes) { |
| 139 // Must contain PEXE. |
| 140 if (!isNaClBitcode(BufPtr, BufEnd)) { |
| 141 UnsupportedMessage = "Invalid PNaCl bitcode header"; |
| 142 if (isBitcode(BufPtr, BufEnd)) { |
| 143 UnsupportedMessage += " (to run in Chrome, bitcode files must be " |
| 144 "finalized using pnacl-finalize)"; |
| 145 } |
| 146 return true; |
| 147 } |
| 148 BufPtr += WordSize; |
| 149 |
| 150 // Read #Fields and number of bytes needed for the header. |
| 151 if (BufPtr + WordSize > BufEnd) |
| 152 return UnsupportedError("Bitcode read failure"); |
| 153 NumFields = static_cast<unsigned>(BufPtr[0]) | |
| 154 (static_cast<unsigned>(BufPtr[1]) << 8); |
| 155 NumBytes = static_cast<unsigned>(BufPtr[2]) | |
| 156 (static_cast<unsigned>(BufPtr[3]) << 8); |
| 157 BufPtr += WordSize; |
| 158 return false; |
| 159 } |
| 160 |
| 161 bool NaClBitcodeHeader::ReadFields(const unsigned char *BufPtr, |
| 162 const unsigned char *BufEnd, |
| 163 unsigned NumFields, unsigned NumBytes) { |
| 164 HeaderSize = NumBytes + (2 * WordSize); |
| 165 |
| 166 // Read in each field. |
| 167 for (size_t i = 0; i < NumFields; ++i) { |
| 168 NaClBitcodeHeaderField *Field = new NaClBitcodeHeaderField(); |
| 169 Fields.push_back(Field); |
| 170 if (!Field->Read(BufPtr, BufEnd - BufPtr)) |
| 171 return UnsupportedError("Bitcode read failure"); |
| 172 size_t FieldSize = Field->GetTotalSize(); |
| 173 BufPtr += FieldSize; |
| 174 } |
| 175 return false; |
| 176 } |
| 177 |
| 178 bool NaClBitcodeHeader::Read(const unsigned char *&BufPtr, |
| 179 const unsigned char *&BufEnd) { |
| 180 unsigned NumFields; |
| 181 unsigned NumBytes; |
| 182 if (ReadPrefix(BufPtr, BufEnd, NumFields, NumBytes)) |
| 183 return true; // ReadPrefix sets UnsupportedMessage |
| 184 BufPtr += 2 * WordSize; |
| 185 |
| 186 if (ReadFields(BufPtr, BufEnd, NumFields, NumBytes)) |
| 187 return true; // ReadFields sets UnsupportedMessage |
| 188 BufPtr += NumBytes; |
| 189 InstallFields(); |
| 190 return false; |
| 191 } |
| 192 |
| 193 bool NaClBitcodeHeader::Read(MemoryObject *Bytes) { |
| 194 unsigned NumFields; |
| 195 unsigned NumBytes; |
| 196 // First, read the prefix, which is 2 * WordSize, to determine the |
| 197 // NumBytes and NumFields. |
| 198 { |
| 199 unsigned char Buffer[2 * WordSize]; |
| 200 if (Bytes->readBytes(Buffer, sizeof(Buffer), 0) != sizeof(Buffer)) |
| 201 return UnsupportedError("Bitcode read failure"); |
| 202 if (ReadPrefix(Buffer, Buffer + sizeof(Buffer), NumFields, NumBytes)) |
| 203 return true; // ReadPrefix sets UnsupportedMessage |
| 204 } |
| 205 // Then read the rest, starting after the 2 * WordSize of the prefix. |
| 206 uint8_t *Header = new uint8_t[NumBytes]; |
| 207 bool failed = |
| 208 Bytes->readBytes(Header, NumBytes, 2 * WordSize) != NumBytes || |
| 209 ReadFields(Header, Header + NumBytes, NumFields, NumBytes); |
| 210 delete[] Header; |
| 211 if (failed) |
| 212 return UnsupportedError("Bitcode read failure"); |
| 213 InstallFields(); |
| 214 return false; |
| 215 } |
| 216 |
| 217 NaClBitcodeHeaderField * |
| 218 NaClBitcodeHeader::GetTaggedField(NaClBitcodeHeaderField::Tag ID) const { |
| 219 for (std::vector<NaClBitcodeHeaderField *>::const_iterator |
| 220 Iter = Fields.begin(), |
| 221 IterEnd = Fields.end(); |
| 222 Iter != IterEnd; ++Iter) { |
| 223 if ((*Iter)->GetID() == ID) { |
| 224 return *Iter; |
| 225 } |
| 226 } |
| 227 return 0; |
| 228 } |
| 229 |
| 230 NaClBitcodeHeaderField *NaClBitcodeHeader::GetField(size_t index) const { |
| 231 if (index >= Fields.size()) |
| 232 return 0; |
| 233 return Fields[index]; |
| 234 } |
| 235 |
| 236 NaClBitcodeHeaderField *GetPNaClVersionPtr(NaClBitcodeHeader *Header) { |
| 237 if (NaClBitcodeHeaderField *Version = |
| 238 Header->GetTaggedField(NaClBitcodeHeaderField::kPNaClVersion)) { |
| 239 if (Version->GetType() == NaClBitcodeHeaderField::kUInt32Type) { |
| 240 return Version; |
| 241 } |
| 242 } |
| 243 return 0; |
| 244 } |
| 245 |
| 246 void NaClBitcodeHeader::InstallFields() { |
| 247 // Assume supported until contradicted. |
| 248 bool UpdatedUnsupportedMessage = false; |
| 249 IsSupportedFlag = true; |
| 250 IsReadableFlag = true; |
| 251 UnsupportedMessage = "Supported"; |
| 252 PNaClVersion = 0; |
| 253 if (NaClBitcodeHeaderField *Version = GetPNaClVersionPtr(this)) { |
| 254 PNaClVersion = Version->GetUInt32Value(); |
| 255 } |
| 256 if (PNaClVersion != 2) { |
| 257 IsSupportedFlag = false; |
| 258 IsReadableFlag = false; |
| 259 UpdatedUnsupportedMessage = true; |
| 260 UnsupportedMessage.clear(); |
| 261 raw_string_ostream UnsupportedStream(UnsupportedMessage); |
| 262 UnsupportedStream << "Unsupported PNaCl bitcode version: " |
| 263 << PNaClVersion << "\n"; |
| 264 UnsupportedStream.flush(); |
| 265 } |
| 266 if (Fields.size() != 1) { |
| 267 IsSupportedFlag = false; |
| 268 IsReadableFlag = false; |
| 269 if (!UpdatedUnsupportedMessage) |
| 270 UnsupportedMessage = "Unknown header field(s) found"; |
| 271 } |
| 272 } |
OLD | NEW |