OLD | NEW |
---|---|
(Empty) | |
1 //===- NaClBitcodeMungeUtils.h - Munge bitcode records --------*- C++ -*-===// | |
2 // | |
3 // The LLVM Compiler Infrastructure | |
4 // | |
5 // This file is distributed under the University of Illinois Open Source | |
6 // License. See LICENSE.TXT for details. | |
7 // | |
8 //===----------------------------------------------------------------------===// | |
9 // | |
10 // This file defines utility class NaClMungedBitcode to edit a base | |
11 // sequence of PNaCl bitcode records. It is intended to be used for | |
12 // both unit testing, and for fuzzing bitcode files. | |
13 // | |
14 // The editing actions are defined in terms of the base sequence of | |
15 // bitcode records, and do not actually modify that base sequence. As | |
16 // such, all edits are defined relative to a record index in the base | |
17 // sequence of bitcode records. Using record indices into the base | |
18 // sequence means that succeeding edits need not modify record indices | |
19 // based on the effects of preceding edits. Rather, the record index | |
20 // remains constant across all editing actions. | |
21 // | |
22 // There are two steps in creating munged bitcode. The first step | |
23 // defines the initial (base) sequence of bitcode records to be | |
24 // edited. The second is to apply editing actions to the base sequence | |
25 // of records. | |
26 // | |
27 // Defining the initial sequence of bitcode records is done by | |
28 // using NaClMungedBitcode's constructor. | |
29 // | |
30 // There are four kinds of editing actions: | |
31 // | |
32 // 1) Add a record before a (base) record index. | |
33 // 2) Add a record after a (base) record index. | |
34 // 3) Remove a record at a (base) record index. | |
35 // 4) Replace a record at a (base) record index. | |
36 // | |
37 // Each of the editing actions are defined by the methods addBefore(), | |
38 // addAfter(), remove(), and replace(). The edited sequence of records | |
39 // is defined by an iterator, and is accessible using methods begin() | |
40 // and end(). | |
41 // | |
42 // If multiple records are added before/after a record index, the | |
43 // order of the added records correspond to the order they were added. | |
44 // | |
45 // For unit testing, simple array interfaces are provided. The first | |
46 // interface defines the initial base sequence of bitcode records. The | |
47 // second interface, method munge(), defines a sequence of editing | |
48 // actions to apply to the base sequence of records. | |
49 // | |
50 // These arrays are defined using type uint64_t. A bitcode record is | |
51 // defined as a sequence of values of the form: | |
52 // | |
53 // AbbrevIndex, RecordCode, Value1, ..., ValueN , Terminator | |
54 // | |
55 // Terminator is a (user-specified) designated constant used to mark | |
56 // the end of bitcode records. A record can contain zero or more | |
57 // values. | |
58 // | |
59 // An editing action is defined as one of the following sequences of | |
60 // values: | |
61 // | |
62 // RecordIndex, AddBefore, AbbrevIndex, RecordCode, Value, ..., Terminator | |
63 // RecordIndex, AddAfter, AbbrevIndex, RecordCode, Value, ..., Terminator | |
64 // RecordIndex, Remove | |
65 // RecordIndex, Replace, AbbrevIndex, RecordCode, Value, ..., Terminator. | |
66 // | |
67 // RecordIndex defines where the action applies, relative to the base | |
68 // sequence of records. EditAction defines the editing action to | |
69 // apply. The remaining fields define an optional record associated | |
70 // with the editing action. | |
71 // | |
72 // ===---------------------------------------------------------------------===// | |
Karl
2016/05/10 14:49:48
Is this file really needed?
It is only used in a
Jim Stichnoth
2016/05/10 18:11:48
Done.
| |
73 | |
74 #ifndef LLVM_BITCODE_NACL_NACLBITCODEMUNGEUTILS_H | |
75 #define LLVM_BITCODE_NACL_NACLBITCODEMUNGEUTILS_H | |
76 | |
77 #include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" | |
78 #include "llvm/Support/MemoryBuffer.h" | |
79 | |
80 #include <list> | |
81 #include <map> | |
82 | |
83 namespace llvm { | |
84 | |
85 class NaClBitcodeAbbrevRecord; // bitcode record. | |
86 class NaClMungedBitcodeIter; // iterator over edited bitcode records. | |
87 | |
88 /// \brief Defines a list of bitcode records. | |
89 typedef std::vector<std::unique_ptr<NaClBitcodeAbbrevRecord>> | |
90 NaClBitcodeRecordList; | |
91 | |
92 // TODO(kschimpf): Modify following two methods to return error_code. | |
93 | |
94 /// \brief Extracts out the records in Records, and puts them into RecordList. | |
95 /// | |
96 /// \brief RecordList[in/out] Record list to read into. | |
97 /// \brief Records Array containing data defining records. | |
98 /// \brief RecordsSize The size of array Records. | |
99 /// \brief RecordTerminator The value used to terminate records. | |
100 void readNaClBitcodeRecordList(NaClBitcodeRecordList &RecordList, | |
101 const uint64_t Records[], | |
102 size_t RecordsSize, | |
103 uint64_t RecordTerminator); | |
104 | |
105 /// Read in the list of records from binary bitcode from a memory buffer. | |
106 void readNaClBitcodeRecordList(NaClBitcodeRecordList &RecordList, | |
107 std::unique_ptr<MemoryBuffer> InputBuffer); | |
108 | |
109 /// Read in the list of records from textual bitcode from a memory buffer. | |
110 std::error_code readNaClTextBcRecordList( | |
111 NaClBitcodeRecordList &RecordList, | |
112 std::unique_ptr<MemoryBuffer> InputBuffer); | |
113 | |
114 /// Read textual bitcode records from Filename, and fill Buffer with | |
115 /// corresponding bitcode. Return error_code describing success of | |
116 /// read. Verbose (if not nullptr) is used to generate more human | |
117 /// readable error messages than the text in the returned error | |
118 /// message. | |
119 std::error_code readNaClRecordTextAndBuildBitcode( | |
120 StringRef Filename, SmallVectorImpl<char> &Buffer, | |
121 raw_ostream *Verbose = nullptr); | |
122 | |
123 /// Write out RecordList (as text) to Buffer. Returns true when | |
124 /// successful. Error message are written to ErrStream. | |
125 bool writeNaClBitcodeRecordList(NaClBitcodeRecordList &RecordList, | |
126 SmallVectorImpl<char> &Buffer, | |
127 raw_ostream &ErrStream); | |
128 | |
129 /// \brief An edited (i.e. munged) list of bitcode records. Edits are | |
130 /// always relative to the initial list of records. | |
131 class NaClMungedBitcode { | |
132 friend class NaClMungedBitcodeIter; | |
133 NaClMungedBitcode() = delete; | |
134 NaClMungedBitcode(const NaClMungedBitcode &) = delete; | |
135 NaClMungedBitcode &operator=(const NaClMungedBitcode &) = delete; | |
136 | |
137 public: | |
138 /// \brief Iterator over edited records. | |
139 typedef NaClMungedBitcodeIter iterator; | |
140 | |
141 /// \brief Read in initial list of records from bitcode in a memory buffer. | |
142 explicit NaClMungedBitcode(std::unique_ptr<MemoryBuffer> InputBuffer, | |
143 bool ReadAsText=false) | |
144 : BaseRecords(new NaClBitcodeRecordList()) { | |
145 if (ReadAsText) | |
146 readNaClTextBcRecordList(*BaseRecords, std::move(InputBuffer)); | |
147 else | |
148 readNaClBitcodeRecordList(*BaseRecords, std::move(InputBuffer)); | |
149 } | |
150 | |
151 /// \brief Initialize the list of records to be edited. | |
152 explicit NaClMungedBitcode(std::unique_ptr<NaClBitcodeRecordList> BaseRecords) | |
153 : BaseRecords(std::move(BaseRecords)) {} | |
154 | |
155 /// \brief Initialize the list of records to be edited using | |
156 /// array specification. | |
157 /// | |
158 /// \brief Records Array containing data defining records. | |
159 /// \brief RecordsSize The size of array Records. | |
160 /// \brief RecordTerminator The value used to terminate records. | |
161 NaClMungedBitcode(const uint64_t Records[], size_t RecordsSize, | |
162 uint64_t RecordTerminator); | |
163 | |
164 ~NaClMungedBitcode(); | |
165 | |
166 /// \brief Iterator pointing to first record in edited records. | |
167 NaClMungedBitcodeIter begin() const; | |
168 | |
169 /// \brief Iterator pointing after last record in edited records. | |
170 NaClMungedBitcodeIter end() const; | |
171 | |
172 /// \brief Insert Record immediately before the record at RecordIndex. | |
173 /// | |
174 /// \param RecordIndex The index (within BaseRecords) to add before. | |
175 /// \param Record The record to add. | |
176 void addBefore(size_t RecordIndex, NaClBitcodeAbbrevRecord &Record); | |
177 | |
178 /// \brief Insert Record after the record at RecordIndex (and after | |
179 /// any previously added after records for RecordIndex). | |
180 /// | |
181 /// \param RecordIndex The index (within BaseRecords) to add after. | |
182 /// \param Record The record to add. | |
183 void addAfter(size_t RecordIndex, NaClBitcodeAbbrevRecord &Record); | |
184 | |
185 /// \brief Remove the record at RecordIndex. Note that because | |
186 /// the record index is based on the base records, and those records | |
187 /// are not modified, this editing action effectively undoes all | |
188 /// previous remove/replace editing actions for this index. | |
189 void remove(size_t RecordIndex); | |
190 | |
191 /// \brief Replace the record at RecordIndex with Record. Note that | |
192 /// because the record index is based on the base records, and those | |
193 /// records are not modified, this editing action effectively undoes | |
194 /// all previous remove/replace editing actions for this index. | |
195 void replace(size_t RecordIndex, NaClBitcodeAbbrevRecord &Record); | |
196 | |
197 /// \brief Print out the resulting edited list of records. | |
198 void print(raw_ostream &Out) const; | |
199 | |
200 /// Defines set of possible write flags. | |
201 struct WriteFlags { | |
202 /// True if error recovery should be applied. | |
203 bool getTryToRecover() const { return TryToRecover; } | |
204 | |
205 /// Define that error recovery should be applied when writing. | |
206 void setTryToRecover(bool NewValue) { | |
207 TryToRecover = NewValue; | |
208 assert(!(TryToRecover && WriteBadAbbrevIndex)); | |
209 } | |
210 | |
211 /// True if a bad abbreviation index should be written (rather than | |
212 /// trying error recovery) so that bitcode readers can be tested for | |
213 /// this condition. | |
214 bool getWriteBadAbbrevIndex() const { return WriteBadAbbrevIndex; } | |
215 | |
216 /// Define that the first bad abbreviation index should be written, | |
217 /// and corresponding minimal context added so that the bitcode can | |
218 /// be used to test reading the erroneous written bitcode. | |
219 void setWriteBadAbbrevIndex(bool NewValue) { | |
220 WriteBadAbbrevIndex = NewValue; | |
221 assert(!(TryToRecover && WriteBadAbbrevIndex)); | |
222 } | |
223 | |
224 /// Get the stream to print errors while writing bitcode. | |
225 raw_ostream &getErrStream() const { | |
226 return ErrStream ? *ErrStream : errs(); | |
227 } | |
228 | |
229 /// Set the stream to print errors to. | |
230 void setErrStream(raw_ostream &NewValue) { | |
231 ErrStream = &NewValue; | |
232 } | |
233 | |
234 void reset() { | |
235 TryToRecover = false; | |
236 WriteBadAbbrevIndex = false; | |
237 ErrStream = nullptr; | |
238 } | |
239 | |
240 private: | |
241 bool TryToRecover = false; | |
242 bool WriteBadAbbrevIndex = false; | |
243 raw_ostream *ErrStream = nullptr; | |
244 }; | |
245 | |
246 /// Defines the results associated with writing bitcode. | |
247 struct WriteResults { | |
248 /// Number of errors generated. | |
249 size_t NumErrors = 0; | |
250 /// Number of repairs (via error recovery) that were applied. | |
251 size_t NumRepairs = 0; | |
252 /// True if a bad abbreviation index were written. | |
253 bool WroteBadAbbrevIndex = false; | |
254 }; | |
255 | |
256 /// \brief Write out the edited list of bitcode records using | |
257 /// the given buffer. | |
258 /// | |
259 /// \param Buffer The buffer to write into. | |
260 /// \param AddHeader Add header block when true. | |
261 /// \param Flags Write flags to use. | |
262 /// | |
263 /// \return Returns the results of the write. | |
264 WriteResults writeMaybeRepair( | |
265 SmallVectorImpl<char> &Buffer, bool AddHeader, | |
266 const WriteFlags &Flags) const; | |
267 | |
268 bool write(SmallVectorImpl<char> &Buffer, bool AddHeader, | |
269 const WriteFlags &Flags) const { | |
270 WriteResults Results = writeMaybeRepair(Buffer, AddHeader, Flags); | |
271 return Results.NumErrors == 0 | |
272 || (Flags.getTryToRecover() && Results.NumErrors == Results.NumRepairs); | |
273 } | |
274 | |
275 bool write(SmallVectorImpl<char> &Buffer, bool AddHeader) const { | |
276 WriteFlags Flags; | |
277 return write(Buffer, AddHeader, Flags); | |
278 } | |
279 | |
280 /// \brief The types of editing actions that can be applied. | |
281 enum EditAction { | |
282 AddBefore, // Insert new record before base record at index. | |
283 AddAfter, // Insert new record after base record at index. | |
284 Remove, // Remove record at index. | |
285 Replace // Replace base record at index with new record. | |
286 }; | |
287 | |
288 /// \brief Apply a set of edits defined in the given array. | |
289 /// | |
290 /// Actions are a sequence of values, followed by a (common) | |
291 /// terminator value. Valid action sequences are: | |
292 /// | |
293 /// RecordIndex AddBefore Abbrev Code Values Terminator | |
294 /// | |
295 /// RecordIndex AddAfter Abbrev Code Values Terminator | |
296 /// | |
297 /// RecordIndex Remove | |
298 /// | |
299 /// RecordIndex Replace Abbrev Code Values Terminator | |
300 /// | |
301 /// \param Munges The array containing the edits to apply. | |
302 /// \param MungesSize The size of Munges. | |
303 /// \param Terminator The value used to terminate records in editing actions. | |
304 void munge(const uint64_t Munges[], size_t MungesSize, uint64_t Terminator); | |
305 | |
306 /// \brief Removes all editing actions and resets back to the original | |
307 /// set of base records. | |
308 void removeEdits(); | |
309 | |
310 /// Returns the unedited list of bitcode records. | |
311 const NaClBitcodeRecordList &getBaseRecords() const { | |
312 return *BaseRecords; | |
313 } | |
314 | |
315 private: | |
316 typedef std::list<NaClBitcodeAbbrevRecord *> RecordListType; | |
317 typedef std::map<size_t, RecordListType *> InsertionsMapType; | |
318 typedef std::map<size_t, NaClBitcodeAbbrevRecord *> ReplaceMapType; | |
319 | |
320 /// \brief The list of base records that will be edited. | |
321 std::unique_ptr<NaClBitcodeRecordList> BaseRecords; | |
322 // Holds map from record index to list of records added before | |
323 // the corresponding record in the list of base records. | |
324 InsertionsMapType BeforeInsertionsMap; | |
325 // Holds map from record index to the list of records added after | |
326 // the corresponding record in the list of base records. | |
327 InsertionsMapType AfterInsertionsMap; | |
328 // Holds map from record index to the record that replaces the | |
329 // corresponding record in the list of base records. Note: If the | |
330 // range is the nullptr, it corresponds to a remove instead of a | |
331 // replace. | |
332 ReplaceMapType ReplaceMap; | |
333 | |
334 // Returns the list of records associated with Index in Map. | |
335 RecordListType &at(InsertionsMapType &Map, size_t Index) { | |
336 InsertionsMapType::iterator Pos = Map.find(Index); | |
337 if (Pos == Map.end()) { | |
338 RecordListType *List = new RecordListType(); | |
339 Map.emplace(Index, List); | |
340 return *List; | |
341 } | |
342 return *Pos->second; | |
343 } | |
344 | |
345 // Creates a (heap allocated) copy of the given record. | |
346 NaClBitcodeAbbrevRecord *copy(const NaClBitcodeAbbrevRecord &Record); | |
347 | |
348 // Delete nested objects within insertions map. | |
349 void destroyInsertionsMap(NaClMungedBitcode::InsertionsMapType &Map); | |
350 }; | |
351 | |
352 /// \brief Defines a bitcode record with its associated abbreviation index. | |
353 class NaClBitcodeAbbrevRecord : public NaClBitcodeRecordData { | |
354 NaClBitcodeAbbrevRecord &operator=(NaClBitcodeAbbrevRecord &) = delete; | |
355 | |
356 public: | |
357 /// \brief The abbreviation associated with the bitcode record. | |
358 unsigned Abbrev; | |
359 | |
360 /// \brief Creates a bitcode record. | |
361 /// | |
362 /// \param Abbrev Abbreviation index associated with record. | |
363 /// \param Code The selector code of the record. | |
364 /// \param Values The values associated with the selector code. | |
365 NaClBitcodeAbbrevRecord(unsigned Abbrev, unsigned Code, | |
366 const NaClRecordVector &Values) | |
367 : NaClBitcodeRecordData(Code, Values), Abbrev(Abbrev) {} | |
368 | |
369 /// \brief Creates a copy of the given abbreviated bitcode record. | |
370 explicit NaClBitcodeAbbrevRecord(const NaClBitcodeAbbrevRecord &Rcd) | |
371 : NaClBitcodeRecordData(Rcd), Abbrev(Rcd.Abbrev) {} | |
372 | |
373 /// \brief Creates a default abbreviated bitcode record. | |
374 NaClBitcodeAbbrevRecord() : Abbrev(naclbitc::UNABBREV_RECORD) {} | |
375 | |
376 ~NaClBitcodeAbbrevRecord() {} | |
377 | |
378 /// \brief Replaces the contents of the abbreviated bitcode record with | |
379 /// the corresponding contents in the array. | |
380 /// | |
381 /// \param Values The array to get values from. | |
382 /// \param ValuesSize The length of the Values array. | |
383 /// \param Terminator The value defining the end of the record in Values. | |
384 /// \param Index The index of the first value to be used in Values. | |
385 void read(const uint64_t Values[], size_t ValuesSize, | |
386 const uint64_t Terminator, size_t &Index); | |
387 | |
388 void print(raw_ostream &out) const; | |
389 }; | |
390 | |
391 inline raw_ostream &operator<<(raw_ostream &Out, | |
392 const NaClBitcodeAbbrevRecord &Record) { | |
393 Record.print(Out); | |
394 return Out; | |
395 } | |
396 | |
397 /// \brief Defines an iterator to walk over elements of an edited | |
398 /// record list. | |
399 class NaClMungedBitcodeIter { | |
400 | |
401 public: | |
402 /// \brief Returns an iterator pointing to the first record in the | |
403 /// edited list of records. | |
404 static NaClMungedBitcodeIter begin(const NaClMungedBitcode &MungedBitcode) { | |
405 return NaClMungedBitcodeIter(MungedBitcode, 0); | |
406 } | |
407 | |
408 /// \brief Returns an iterator pointing past the last record in the | |
409 /// edited list of records. | |
410 static NaClMungedBitcodeIter end(const NaClMungedBitcode &MungedBitcode) { | |
411 return NaClMungedBitcodeIter(MungedBitcode, | |
412 MungedBitcode.BaseRecords->size()); | |
413 } | |
414 | |
415 bool operator==(const NaClMungedBitcodeIter &Iter) const; | |
416 | |
417 bool operator!=(const NaClMungedBitcodeIter &Iter) const { | |
418 return !operator==(Iter); | |
419 } | |
420 | |
421 /// \brief Advances the iterator over one record in the list of | |
422 /// edited records. | |
423 NaClMungedBitcodeIter &operator++(); | |
424 | |
425 /// \brief Returns the bitcode record the iterator is before. | |
426 NaClBitcodeAbbrevRecord &operator*(); | |
427 | |
428 private: | |
429 /// \brief Defines position of the iterator, relative to the corresponding | |
430 /// record index in the base list of records. | |
431 enum MungedPosition { | |
432 /// Processing the list of records inserted before the record | |
433 /// index of the base list of records. | |
434 InBeforeInsertions, | |
435 /// Processing the record at the given record index of the base | |
436 /// list of records. | |
437 AtIndex, | |
438 /// Processing the list of records inserted after the record index | |
439 /// of the base list of records. | |
440 InAfterInsertions, | |
441 }; | |
442 | |
443 // The edited list of records to iterate over. | |
444 const NaClMungedBitcode *MungedBitcode; | |
445 // The corresponding index, wrt to the edited list of records, that | |
446 // is being processed. | |
447 size_t Index; | |
448 // The position of the iterator wrt to Index. | |
449 MungedPosition Position; | |
450 // An iterator defining the current position within a | |
451 // BeforeInsertions or AfterInsertions list. When the iterator is | |
452 // not in the corresponding position (i.e. InBeforeInsertions or | |
453 // InAfterInsertions) this iterator is undefined. | |
454 NaClMungedBitcode::RecordListType::const_iterator InsertionsIter; | |
455 // An iterator defining the end position of the corresponding list | |
456 // of records defined by InsertionsIter. Only defined when | |
457 // InsertionsIter is defined. | |
458 NaClMungedBitcode::RecordListType::const_iterator InsertionsIterEnd; | |
459 // Dummy list to initialize InsertionsIter if no such list exists. | |
460 NaClMungedBitcode::RecordListType EmptyList; | |
461 | |
462 // \brief Defines an iterator at the beginning of the | |
463 // BeforeInsertions list associated with the given Index in | |
464 // MungedBitcode. | |
465 NaClMungedBitcodeIter(const NaClMungedBitcode &MungedBitcode, size_t Index) | |
466 : MungedBitcode(&MungedBitcode), Index(Index), | |
467 Position(InBeforeInsertions), InsertionsIter(), InsertionsIterEnd() { | |
468 placeAt(MungedBitcode.BeforeInsertionsMap, 0); | |
469 updatePosition(); | |
470 } | |
471 | |
472 // \brief Places the corresponding insertions iterator based on the | |
473 // list of records defined at Index for the given insertions Map. | |
474 void placeAt(const NaClMungedBitcode::InsertionsMapType &Map, size_t Index) { | |
475 NaClMungedBitcode::InsertionsMapType::const_iterator Pos = Map.find(Index); | |
476 if (Pos == Map.end()) { | |
477 InsertionsIter = EmptyList.end(); | |
478 InsertionsIterEnd = EmptyList.end(); | |
479 } else { | |
480 InsertionsIter = Pos->second->begin(); | |
481 InsertionsIterEnd = Pos->second->end(); | |
482 } | |
483 } | |
484 | |
485 // \brief Moves the iterator to the position of the next edited | |
486 // record. | |
487 void updatePosition(); | |
488 }; | |
489 | |
490 } // end namespace llvm. | |
491 | |
492 #endif // LLVM_BITCODE_NACL_NACLBITCODEMUNGE_H | |
OLD | NEW |