Chromium Code Reviews| Index: pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeMungeUtils.h |
| diff --git a/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeMungeUtils.h b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeMungeUtils.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..0b749a87f38edeafe130c149093bdd543a64737c |
| --- /dev/null |
| +++ b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeMungeUtils.h |
| @@ -0,0 +1,492 @@ |
| +//===- NaClBitcodeMungeUtils.h - Munge bitcode records --------*- C++ -*-===// |
| +// |
| +// The LLVM Compiler Infrastructure |
| +// |
| +// This file is distributed under the University of Illinois Open Source |
| +// License. See LICENSE.TXT for details. |
| +// |
| +//===----------------------------------------------------------------------===// |
| +// |
| +// This file defines utility class NaClMungedBitcode to edit a base |
| +// sequence of PNaCl bitcode records. It is intended to be used for |
| +// both unit testing, and for fuzzing bitcode files. |
| +// |
| +// The editing actions are defined in terms of the base sequence of |
| +// bitcode records, and do not actually modify that base sequence. As |
| +// such, all edits are defined relative to a record index in the base |
| +// sequence of bitcode records. Using record indices into the base |
| +// sequence means that succeeding edits need not modify record indices |
| +// based on the effects of preceding edits. Rather, the record index |
| +// remains constant across all editing actions. |
| +// |
| +// There are two steps in creating munged bitcode. The first step |
| +// defines the initial (base) sequence of bitcode records to be |
| +// edited. The second is to apply editing actions to the base sequence |
| +// of records. |
| +// |
| +// Defining the initial sequence of bitcode records is done by |
| +// using NaClMungedBitcode's constructor. |
| +// |
| +// There are four kinds of editing actions: |
| +// |
| +// 1) Add a record before a (base) record index. |
| +// 2) Add a record after a (base) record index. |
| +// 3) Remove a record at a (base) record index. |
| +// 4) Replace a record at a (base) record index. |
| +// |
| +// Each of the editing actions are defined by the methods addBefore(), |
| +// addAfter(), remove(), and replace(). The edited sequence of records |
| +// is defined by an iterator, and is accessible using methods begin() |
| +// and end(). |
| +// |
| +// If multiple records are added before/after a record index, the |
| +// order of the added records correspond to the order they were added. |
| +// |
| +// For unit testing, simple array interfaces are provided. The first |
| +// interface defines the initial base sequence of bitcode records. The |
| +// second interface, method munge(), defines a sequence of editing |
| +// actions to apply to the base sequence of records. |
| +// |
| +// These arrays are defined using type uint64_t. A bitcode record is |
| +// defined as a sequence of values of the form: |
| +// |
| +// AbbrevIndex, RecordCode, Value1, ..., ValueN , Terminator |
| +// |
| +// Terminator is a (user-specified) designated constant used to mark |
| +// the end of bitcode records. A record can contain zero or more |
| +// values. |
| +// |
| +// An editing action is defined as one of the following sequences of |
| +// values: |
| +// |
| +// RecordIndex, AddBefore, AbbrevIndex, RecordCode, Value, ..., Terminator |
| +// RecordIndex, AddAfter, AbbrevIndex, RecordCode, Value, ..., Terminator |
| +// RecordIndex, Remove |
| +// RecordIndex, Replace, AbbrevIndex, RecordCode, Value, ..., Terminator. |
| +// |
| +// RecordIndex defines where the action applies, relative to the base |
| +// sequence of records. EditAction defines the editing action to |
| +// apply. The remaining fields define an optional record associated |
| +// with the editing action. |
| +// |
| +// ===---------------------------------------------------------------------===// |
|
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.
|
| + |
| +#ifndef LLVM_BITCODE_NACL_NACLBITCODEMUNGEUTILS_H |
| +#define LLVM_BITCODE_NACL_NACLBITCODEMUNGEUTILS_H |
| + |
| +#include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" |
| +#include "llvm/Support/MemoryBuffer.h" |
| + |
| +#include <list> |
| +#include <map> |
| + |
| +namespace llvm { |
| + |
| +class NaClBitcodeAbbrevRecord; // bitcode record. |
| +class NaClMungedBitcodeIter; // iterator over edited bitcode records. |
| + |
| +/// \brief Defines a list of bitcode records. |
| +typedef std::vector<std::unique_ptr<NaClBitcodeAbbrevRecord>> |
| + NaClBitcodeRecordList; |
| + |
| +// TODO(kschimpf): Modify following two methods to return error_code. |
| + |
| +/// \brief Extracts out the records in Records, and puts them into RecordList. |
| +/// |
| +/// \brief RecordList[in/out] Record list to read into. |
| +/// \brief Records Array containing data defining records. |
| +/// \brief RecordsSize The size of array Records. |
| +/// \brief RecordTerminator The value used to terminate records. |
| +void readNaClBitcodeRecordList(NaClBitcodeRecordList &RecordList, |
| + const uint64_t Records[], |
| + size_t RecordsSize, |
| + uint64_t RecordTerminator); |
| + |
| +/// Read in the list of records from binary bitcode from a memory buffer. |
| +void readNaClBitcodeRecordList(NaClBitcodeRecordList &RecordList, |
| + std::unique_ptr<MemoryBuffer> InputBuffer); |
| + |
| +/// Read in the list of records from textual bitcode from a memory buffer. |
| +std::error_code readNaClTextBcRecordList( |
| + NaClBitcodeRecordList &RecordList, |
| + std::unique_ptr<MemoryBuffer> InputBuffer); |
| + |
| +/// Read textual bitcode records from Filename, and fill Buffer with |
| +/// corresponding bitcode. Return error_code describing success of |
| +/// read. Verbose (if not nullptr) is used to generate more human |
| +/// readable error messages than the text in the returned error |
| +/// message. |
| +std::error_code readNaClRecordTextAndBuildBitcode( |
| + StringRef Filename, SmallVectorImpl<char> &Buffer, |
| + raw_ostream *Verbose = nullptr); |
| + |
| +/// Write out RecordList (as text) to Buffer. Returns true when |
| +/// successful. Error message are written to ErrStream. |
| +bool writeNaClBitcodeRecordList(NaClBitcodeRecordList &RecordList, |
| + SmallVectorImpl<char> &Buffer, |
| + raw_ostream &ErrStream); |
| + |
| +/// \brief An edited (i.e. munged) list of bitcode records. Edits are |
| +/// always relative to the initial list of records. |
| +class NaClMungedBitcode { |
| + friend class NaClMungedBitcodeIter; |
| + NaClMungedBitcode() = delete; |
| + NaClMungedBitcode(const NaClMungedBitcode &) = delete; |
| + NaClMungedBitcode &operator=(const NaClMungedBitcode &) = delete; |
| + |
| +public: |
| + /// \brief Iterator over edited records. |
| + typedef NaClMungedBitcodeIter iterator; |
| + |
| + /// \brief Read in initial list of records from bitcode in a memory buffer. |
| + explicit NaClMungedBitcode(std::unique_ptr<MemoryBuffer> InputBuffer, |
| + bool ReadAsText=false) |
| + : BaseRecords(new NaClBitcodeRecordList()) { |
| + if (ReadAsText) |
| + readNaClTextBcRecordList(*BaseRecords, std::move(InputBuffer)); |
| + else |
| + readNaClBitcodeRecordList(*BaseRecords, std::move(InputBuffer)); |
| + } |
| + |
| + /// \brief Initialize the list of records to be edited. |
| + explicit NaClMungedBitcode(std::unique_ptr<NaClBitcodeRecordList> BaseRecords) |
| + : BaseRecords(std::move(BaseRecords)) {} |
| + |
| + /// \brief Initialize the list of records to be edited using |
| + /// array specification. |
| + /// |
| + /// \brief Records Array containing data defining records. |
| + /// \brief RecordsSize The size of array Records. |
| + /// \brief RecordTerminator The value used to terminate records. |
| + NaClMungedBitcode(const uint64_t Records[], size_t RecordsSize, |
| + uint64_t RecordTerminator); |
| + |
| + ~NaClMungedBitcode(); |
| + |
| + /// \brief Iterator pointing to first record in edited records. |
| + NaClMungedBitcodeIter begin() const; |
| + |
| + /// \brief Iterator pointing after last record in edited records. |
| + NaClMungedBitcodeIter end() const; |
| + |
| + /// \brief Insert Record immediately before the record at RecordIndex. |
| + /// |
| + /// \param RecordIndex The index (within BaseRecords) to add before. |
| + /// \param Record The record to add. |
| + void addBefore(size_t RecordIndex, NaClBitcodeAbbrevRecord &Record); |
| + |
| + /// \brief Insert Record after the record at RecordIndex (and after |
| + /// any previously added after records for RecordIndex). |
| + /// |
| + /// \param RecordIndex The index (within BaseRecords) to add after. |
| + /// \param Record The record to add. |
| + void addAfter(size_t RecordIndex, NaClBitcodeAbbrevRecord &Record); |
| + |
| + /// \brief Remove the record at RecordIndex. Note that because |
| + /// the record index is based on the base records, and those records |
| + /// are not modified, this editing action effectively undoes all |
| + /// previous remove/replace editing actions for this index. |
| + void remove(size_t RecordIndex); |
| + |
| + /// \brief Replace the record at RecordIndex with Record. Note that |
| + /// because the record index is based on the base records, and those |
| + /// records are not modified, this editing action effectively undoes |
| + /// all previous remove/replace editing actions for this index. |
| + void replace(size_t RecordIndex, NaClBitcodeAbbrevRecord &Record); |
| + |
| + /// \brief Print out the resulting edited list of records. |
| + void print(raw_ostream &Out) const; |
| + |
| + /// Defines set of possible write flags. |
| + struct WriteFlags { |
| + /// True if error recovery should be applied. |
| + bool getTryToRecover() const { return TryToRecover; } |
| + |
| + /// Define that error recovery should be applied when writing. |
| + void setTryToRecover(bool NewValue) { |
| + TryToRecover = NewValue; |
| + assert(!(TryToRecover && WriteBadAbbrevIndex)); |
| + } |
| + |
| + /// True if a bad abbreviation index should be written (rather than |
| + /// trying error recovery) so that bitcode readers can be tested for |
| + /// this condition. |
| + bool getWriteBadAbbrevIndex() const { return WriteBadAbbrevIndex; } |
| + |
| + /// Define that the first bad abbreviation index should be written, |
| + /// and corresponding minimal context added so that the bitcode can |
| + /// be used to test reading the erroneous written bitcode. |
| + void setWriteBadAbbrevIndex(bool NewValue) { |
| + WriteBadAbbrevIndex = NewValue; |
| + assert(!(TryToRecover && WriteBadAbbrevIndex)); |
| + } |
| + |
| + /// Get the stream to print errors while writing bitcode. |
| + raw_ostream &getErrStream() const { |
| + return ErrStream ? *ErrStream : errs(); |
| + } |
| + |
| + /// Set the stream to print errors to. |
| + void setErrStream(raw_ostream &NewValue) { |
| + ErrStream = &NewValue; |
| + } |
| + |
| + void reset() { |
| + TryToRecover = false; |
| + WriteBadAbbrevIndex = false; |
| + ErrStream = nullptr; |
| + } |
| + |
| + private: |
| + bool TryToRecover = false; |
| + bool WriteBadAbbrevIndex = false; |
| + raw_ostream *ErrStream = nullptr; |
| + }; |
| + |
| + /// Defines the results associated with writing bitcode. |
| + struct WriteResults { |
| + /// Number of errors generated. |
| + size_t NumErrors = 0; |
| + /// Number of repairs (via error recovery) that were applied. |
| + size_t NumRepairs = 0; |
| + /// True if a bad abbreviation index were written. |
| + bool WroteBadAbbrevIndex = false; |
| + }; |
| + |
| + /// \brief Write out the edited list of bitcode records using |
| + /// the given buffer. |
| + /// |
| + /// \param Buffer The buffer to write into. |
| + /// \param AddHeader Add header block when true. |
| + /// \param Flags Write flags to use. |
| + /// |
| + /// \return Returns the results of the write. |
| + WriteResults writeMaybeRepair( |
| + SmallVectorImpl<char> &Buffer, bool AddHeader, |
| + const WriteFlags &Flags) const; |
| + |
| + bool write(SmallVectorImpl<char> &Buffer, bool AddHeader, |
| + const WriteFlags &Flags) const { |
| + WriteResults Results = writeMaybeRepair(Buffer, AddHeader, Flags); |
| + return Results.NumErrors == 0 |
| + || (Flags.getTryToRecover() && Results.NumErrors == Results.NumRepairs); |
| + } |
| + |
| + bool write(SmallVectorImpl<char> &Buffer, bool AddHeader) const { |
| + WriteFlags Flags; |
| + return write(Buffer, AddHeader, Flags); |
| + } |
| + |
| + /// \brief The types of editing actions that can be applied. |
| + enum EditAction { |
| + AddBefore, // Insert new record before base record at index. |
| + AddAfter, // Insert new record after base record at index. |
| + Remove, // Remove record at index. |
| + Replace // Replace base record at index with new record. |
| + }; |
| + |
| + /// \brief Apply a set of edits defined in the given array. |
| + /// |
| + /// Actions are a sequence of values, followed by a (common) |
| + /// terminator value. Valid action sequences are: |
| + /// |
| + /// RecordIndex AddBefore Abbrev Code Values Terminator |
| + /// |
| + /// RecordIndex AddAfter Abbrev Code Values Terminator |
| + /// |
| + /// RecordIndex Remove |
| + /// |
| + /// RecordIndex Replace Abbrev Code Values Terminator |
| + /// |
| + /// \param Munges The array containing the edits to apply. |
| + /// \param MungesSize The size of Munges. |
| + /// \param Terminator The value used to terminate records in editing actions. |
| + void munge(const uint64_t Munges[], size_t MungesSize, uint64_t Terminator); |
| + |
| + /// \brief Removes all editing actions and resets back to the original |
| + /// set of base records. |
| + void removeEdits(); |
| + |
| + /// Returns the unedited list of bitcode records. |
| + const NaClBitcodeRecordList &getBaseRecords() const { |
| + return *BaseRecords; |
| + } |
| + |
| +private: |
| + typedef std::list<NaClBitcodeAbbrevRecord *> RecordListType; |
| + typedef std::map<size_t, RecordListType *> InsertionsMapType; |
| + typedef std::map<size_t, NaClBitcodeAbbrevRecord *> ReplaceMapType; |
| + |
| + /// \brief The list of base records that will be edited. |
| + std::unique_ptr<NaClBitcodeRecordList> BaseRecords; |
| + // Holds map from record index to list of records added before |
| + // the corresponding record in the list of base records. |
| + InsertionsMapType BeforeInsertionsMap; |
| + // Holds map from record index to the list of records added after |
| + // the corresponding record in the list of base records. |
| + InsertionsMapType AfterInsertionsMap; |
| + // Holds map from record index to the record that replaces the |
| + // corresponding record in the list of base records. Note: If the |
| + // range is the nullptr, it corresponds to a remove instead of a |
| + // replace. |
| + ReplaceMapType ReplaceMap; |
| + |
| + // Returns the list of records associated with Index in Map. |
| + RecordListType &at(InsertionsMapType &Map, size_t Index) { |
| + InsertionsMapType::iterator Pos = Map.find(Index); |
| + if (Pos == Map.end()) { |
| + RecordListType *List = new RecordListType(); |
| + Map.emplace(Index, List); |
| + return *List; |
| + } |
| + return *Pos->second; |
| + } |
| + |
| + // Creates a (heap allocated) copy of the given record. |
| + NaClBitcodeAbbrevRecord *copy(const NaClBitcodeAbbrevRecord &Record); |
| + |
| + // Delete nested objects within insertions map. |
| + void destroyInsertionsMap(NaClMungedBitcode::InsertionsMapType &Map); |
| +}; |
| + |
| +/// \brief Defines a bitcode record with its associated abbreviation index. |
| +class NaClBitcodeAbbrevRecord : public NaClBitcodeRecordData { |
| + NaClBitcodeAbbrevRecord &operator=(NaClBitcodeAbbrevRecord &) = delete; |
| + |
| +public: |
| + /// \brief The abbreviation associated with the bitcode record. |
| + unsigned Abbrev; |
| + |
| + /// \brief Creates a bitcode record. |
| + /// |
| + /// \param Abbrev Abbreviation index associated with record. |
| + /// \param Code The selector code of the record. |
| + /// \param Values The values associated with the selector code. |
| + NaClBitcodeAbbrevRecord(unsigned Abbrev, unsigned Code, |
| + const NaClRecordVector &Values) |
| + : NaClBitcodeRecordData(Code, Values), Abbrev(Abbrev) {} |
| + |
| + /// \brief Creates a copy of the given abbreviated bitcode record. |
| + explicit NaClBitcodeAbbrevRecord(const NaClBitcodeAbbrevRecord &Rcd) |
| + : NaClBitcodeRecordData(Rcd), Abbrev(Rcd.Abbrev) {} |
| + |
| + /// \brief Creates a default abbreviated bitcode record. |
| + NaClBitcodeAbbrevRecord() : Abbrev(naclbitc::UNABBREV_RECORD) {} |
| + |
| + ~NaClBitcodeAbbrevRecord() {} |
| + |
| + /// \brief Replaces the contents of the abbreviated bitcode record with |
| + /// the corresponding contents in the array. |
| + /// |
| + /// \param Values The array to get values from. |
| + /// \param ValuesSize The length of the Values array. |
| + /// \param Terminator The value defining the end of the record in Values. |
| + /// \param Index The index of the first value to be used in Values. |
| + void read(const uint64_t Values[], size_t ValuesSize, |
| + const uint64_t Terminator, size_t &Index); |
| + |
| + void print(raw_ostream &out) const; |
| +}; |
| + |
| +inline raw_ostream &operator<<(raw_ostream &Out, |
| + const NaClBitcodeAbbrevRecord &Record) { |
| + Record.print(Out); |
| + return Out; |
| +} |
| + |
| +/// \brief Defines an iterator to walk over elements of an edited |
| +/// record list. |
| +class NaClMungedBitcodeIter { |
| + |
| +public: |
| + /// \brief Returns an iterator pointing to the first record in the |
| + /// edited list of records. |
| + static NaClMungedBitcodeIter begin(const NaClMungedBitcode &MungedBitcode) { |
| + return NaClMungedBitcodeIter(MungedBitcode, 0); |
| + } |
| + |
| + /// \brief Returns an iterator pointing past the last record in the |
| + /// edited list of records. |
| + static NaClMungedBitcodeIter end(const NaClMungedBitcode &MungedBitcode) { |
| + return NaClMungedBitcodeIter(MungedBitcode, |
| + MungedBitcode.BaseRecords->size()); |
| + } |
| + |
| + bool operator==(const NaClMungedBitcodeIter &Iter) const; |
| + |
| + bool operator!=(const NaClMungedBitcodeIter &Iter) const { |
| + return !operator==(Iter); |
| + } |
| + |
| + /// \brief Advances the iterator over one record in the list of |
| + /// edited records. |
| + NaClMungedBitcodeIter &operator++(); |
| + |
| + /// \brief Returns the bitcode record the iterator is before. |
| + NaClBitcodeAbbrevRecord &operator*(); |
| + |
| +private: |
| + /// \brief Defines position of the iterator, relative to the corresponding |
| + /// record index in the base list of records. |
| + enum MungedPosition { |
| + /// Processing the list of records inserted before the record |
| + /// index of the base list of records. |
| + InBeforeInsertions, |
| + /// Processing the record at the given record index of the base |
| + /// list of records. |
| + AtIndex, |
| + /// Processing the list of records inserted after the record index |
| + /// of the base list of records. |
| + InAfterInsertions, |
| + }; |
| + |
| + // The edited list of records to iterate over. |
| + const NaClMungedBitcode *MungedBitcode; |
| + // The corresponding index, wrt to the edited list of records, that |
| + // is being processed. |
| + size_t Index; |
| + // The position of the iterator wrt to Index. |
| + MungedPosition Position; |
| + // An iterator defining the current position within a |
| + // BeforeInsertions or AfterInsertions list. When the iterator is |
| + // not in the corresponding position (i.e. InBeforeInsertions or |
| + // InAfterInsertions) this iterator is undefined. |
| + NaClMungedBitcode::RecordListType::const_iterator InsertionsIter; |
| + // An iterator defining the end position of the corresponding list |
| + // of records defined by InsertionsIter. Only defined when |
| + // InsertionsIter is defined. |
| + NaClMungedBitcode::RecordListType::const_iterator InsertionsIterEnd; |
| + // Dummy list to initialize InsertionsIter if no such list exists. |
| + NaClMungedBitcode::RecordListType EmptyList; |
| + |
| + // \brief Defines an iterator at the beginning of the |
| + // BeforeInsertions list associated with the given Index in |
| + // MungedBitcode. |
| + NaClMungedBitcodeIter(const NaClMungedBitcode &MungedBitcode, size_t Index) |
| + : MungedBitcode(&MungedBitcode), Index(Index), |
| + Position(InBeforeInsertions), InsertionsIter(), InsertionsIterEnd() { |
| + placeAt(MungedBitcode.BeforeInsertionsMap, 0); |
| + updatePosition(); |
| + } |
| + |
| + // \brief Places the corresponding insertions iterator based on the |
| + // list of records defined at Index for the given insertions Map. |
| + void placeAt(const NaClMungedBitcode::InsertionsMapType &Map, size_t Index) { |
| + NaClMungedBitcode::InsertionsMapType::const_iterator Pos = Map.find(Index); |
| + if (Pos == Map.end()) { |
| + InsertionsIter = EmptyList.end(); |
| + InsertionsIterEnd = EmptyList.end(); |
| + } else { |
| + InsertionsIter = Pos->second->begin(); |
| + InsertionsIterEnd = Pos->second->end(); |
| + } |
| + } |
| + |
| + // \brief Moves the iterator to the position of the next edited |
| + // record. |
| + void updatePosition(); |
| +}; |
| + |
| +} // end namespace llvm. |
| + |
| +#endif // LLVM_BITCODE_NACL_NACLBITCODEMUNGE_H |