Home | History | Annotate | Download | only in pnacl-llvm
      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