xref: /aosp_15_r20/external/swiftshader/third_party/subzero/pnacl-llvm/NaClBitcodeHeader.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
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/StreamingMemoryObject.h"
19 #include "llvm/Support/raw_ostream.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 = Bytes->readBytes(Header, NumBytes, 2 * WordSize) != NumBytes ||
249                 ReadFields(Header, Header + NumBytes, NumFields, NumBytes);
250   delete[] Header;
251   if (failed)
252     return UnsupportedError("Bitcode read failure");
253   InstallFields();
254   return false;
255 }
256 
257 NaClBitcodeHeaderField *
GetTaggedField(NaClBitcodeHeaderField::Tag ID) const258 NaClBitcodeHeader::GetTaggedField(NaClBitcodeHeaderField::Tag ID) const {
259   for (std::vector<NaClBitcodeHeaderField *>::const_iterator
260            Iter = Fields.begin(),
261            IterEnd = Fields.end();
262        Iter != IterEnd; ++Iter) {
263     if ((*Iter)->GetID() == ID) {
264       return *Iter;
265     }
266   }
267   return 0;
268 }
269 
GetField(size_t index) const270 NaClBitcodeHeaderField *NaClBitcodeHeader::GetField(size_t index) const {
271   if (index >= Fields.size())
272     return 0;
273   return Fields[index];
274 }
275 
GetPNaClVersionPtr(NaClBitcodeHeader * Header)276 NaClBitcodeHeaderField *GetPNaClVersionPtr(NaClBitcodeHeader *Header) {
277   if (NaClBitcodeHeaderField *Version =
278           Header->GetTaggedField(NaClBitcodeHeaderField::kPNaClVersion)) {
279     if (Version->GetType() == NaClBitcodeHeaderField::kUInt32Type) {
280       return Version;
281     }
282   }
283   return 0;
284 }
285 
InstallFields()286 void NaClBitcodeHeader::InstallFields() {
287   IsSupportedFlag = true;
288   IsReadableFlag = true;
289   AlignBitcodeRecords = false;
290   PNaClVersion = 0;
291   UnsupportedMessage.clear();
292   SmallSet<unsigned, NaClBitcodeHeaderField::kTag_MAX> FieldIDs;
293 
294   auto ReportProblem = [&](bool IsReadable) {
295     UnsupportedMessage.append("\n");
296     IsSupportedFlag = false;
297     IsReadableFlag = IsReadableFlag && IsReadable;
298   };
299 
300   auto ReportProblemWithContents = [&](NaClBitcodeHeaderField *Field,
301                                        bool IsReadable) {
302     UnsupportedMessage.append(": ");
303     UnsupportedMessage.append(Field->Contents());
304     ReportProblem(IsReadable);
305   };
306 
307   for (size_t i = 0, e = NumberFields(); i < e; ++i) {
308     // Start by checking expected properties for any field
309     NaClBitcodeHeaderField *Field = GetField(i);
310     if (!FieldIDs.insert(Field->GetID()).second) {
311       UnsupportedMessage.append("Specified multiple times: ");
312       UnsupportedMessage.append(Field->IDName());
313       ReportProblem(false);
314       continue;
315     }
316     NaClBitcodeHeaderField::FieldType ExpectedTy = ExpectedType[Field->GetID()];
317     if (Field->GetType() != ExpectedTy) {
318       UnsupportedMessage.append("Expects type ");
319       UnsupportedMessage.append(NaClBitcodeHeaderField::TypeName(ExpectedTy));
320       ReportProblemWithContents(Field, false);
321       continue;
322     }
323     if (Field->GetType() == NaClBitcodeHeaderField::kUnknownType) {
324       UnsupportedMessage.append("Unknown value");
325       ReportProblemWithContents(Field, false);
326       continue;
327     }
328 
329     // Check specific ID values and install.
330     switch (Field->GetID()) {
331     case NaClBitcodeHeaderField::kInvalid:
332       UnsupportedMessage.append("Unsupported");
333       ReportProblemWithContents(Field, false);
334       continue;
335     case NaClBitcodeHeaderField::kPNaClVersion:
336       PNaClVersion = Field->GetUInt32Value();
337       if (PNaClVersion != 2) {
338         UnsupportedMessage.append("Unsupported");
339         ReportProblemWithContents(Field, false);
340         continue;
341       }
342       break;
343     case NaClBitcodeHeaderField::kAlignBitcodeRecords:
344       AlignBitcodeRecords = true;
345       UnsupportedMessage.append("Unsupported");
346       ReportProblemWithContents(Field, true);
347       continue;
348     }
349   }
350 }
351