OLD | NEW |
(Empty) | |
| 1 //===- NaClBitcodeMunge.h - Bitcode Munger ----------------------*- 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 // Test harness for generating a PNaCl bitcode memory buffer from |
| 11 // an array, and parse/objdump the resulting contents. |
| 12 // |
| 13 // Generates a bitcode memory buffer from an array containing 1 or |
| 14 // more PNaCl records. Used to test errors in PNaCl bitcode. |
| 15 // |
| 16 // For simplicity of API, we model records as an array of uint64_t. To |
| 17 // specify the end of a record in the array, a special "terminator" |
| 18 // value is used. This terminator value must be a uint64_t value that |
| 19 // is not used by any of the records. |
| 20 // |
| 21 // A record is defined as a sequence of integers consisting of: |
| 22 // * The abbreviation index associated with the record. |
| 23 // * The record code associated with the record. |
| 24 // * The sequence of values associated with the record code. |
| 25 // * The terminator value. |
| 26 // |
| 27 // Note: Since the header record doesn't have any abbreviation indices |
| 28 // associated with it, one can use any value. The value will simply be |
| 29 // ignored. |
| 30 // |
| 31 // In addition to specifying the sequence of records, one can also |
| 32 // define a sequence of edits to be applied to the original sequence |
| 33 // of records. This allows the same record sequence to be used in |
| 34 // multiple tests. |
| 35 // |
| 36 // An edit consists of: |
| 37 // |
| 38 // * A record number defining where the edit is to be applied. |
| 39 // * An action defining the type of edit. |
| 40 // * An optional record associated with the action. |
| 41 // |
| 42 // Note that edits must be sorted by record number, so that the records |
| 43 // and edits can be processed with a linear pass. |
| 44 // |
| 45 // Generally, you can generate any legal/illegal record |
| 46 // sequence. However, abbreviations are intimately tied to the |
| 47 // internals of the bitstream writer and can't contain illegal |
| 48 // data. Whenever class NaClBitcodeMunger is unable to accept illegal |
| 49 // data, a corresponding "Fatal" error is generated and execution |
| 50 // is terminated. |
| 51 // |
| 52 // ===---------------------------------------------------------------------===// |
| 53 |
| 54 #ifndef LLVM_BITCODE_NACL_NACLBITCODEMUNGE_H |
| 55 #define LLVM_BITCODE_NACL_NACLBITCODEMUNGE_H |
| 56 |
| 57 #include "llvm/ADT/SmallVector.h" |
| 58 #include "llvm/IR/Module.h" |
| 59 #include "llvm/Support/DataTypes.h" |
| 60 #include "llvm/Support/ErrorHandling.h" |
| 61 #include "llvm/Support/MemoryBuffer.h" |
| 62 #include "llvm/Support/raw_ostream.h" |
| 63 |
| 64 #include <string> |
| 65 |
| 66 namespace llvm { |
| 67 |
| 68 class NaClBitstreamWriter; |
| 69 class NaClBitCodeAbbrev; |
| 70 |
| 71 /// Base class to run tests on munged bitcode files. |
| 72 class NaClBitcodeMunger { |
| 73 public: |
| 74 /// The types of editing actions that can be applied. |
| 75 enum EditAction { |
| 76 AddBefore, // Insert record before record with index. |
| 77 AddAfter, // Insert record after record with index. |
| 78 Remove, // Remove record with index. |
| 79 Replace // Replace record with index with specified record. |
| 80 }; |
| 81 |
| 82 /// Creates a bitcode munger, based on the given array of values. |
| 83 NaClBitcodeMunger(const uint64_t Records[], size_t RecordsSize, |
| 84 uint64_t RecordTerminator) |
| 85 : Records(Records), RecordsSize(RecordsSize), |
| 86 RecordTerminator(RecordTerminator), WriteBlockID(-1), SetBID(-1), |
| 87 DumpResults("Error: No previous dump results!\n"), |
| 88 DumpStream(nullptr), Writer(nullptr), FoundErrors(false), |
| 89 FatalBuffer(), FatalStream(FatalBuffer) {} |
| 90 |
| 91 /// Creates MungedInput and DumpStream for running tests, based on |
| 92 /// given Munges. |
| 93 void setupTest( |
| 94 const char *TestName, const uint64_t Munges[], size_t MungesSize, |
| 95 bool AddHeader); |
| 96 |
| 97 /// Cleans up state after a test. |
| 98 void cleanupTest(); |
| 99 |
| 100 /// Returns the resulting string generated by the corresponding test. |
| 101 const std::string &getTestResults() const { |
| 102 return DumpResults; |
| 103 } |
| 104 |
| 105 /// Returns the lines containing the given Substring, from the |
| 106 /// string getTestResults(). |
| 107 std::string getLinesWithSubstring(const std::string &Substring) const { |
| 108 return getLinesWithTextMatch(Substring, false); |
| 109 } |
| 110 |
| 111 /// Returns the lines starting with the given Prefix, from the string |
| 112 /// getTestResults(). |
| 113 std::string getLinesWithPrefix(const std::string &Prefix) const { |
| 114 return getLinesWithTextMatch(Prefix, true); |
| 115 } |
| 116 |
| 117 protected: |
| 118 // The list of (base) records. |
| 119 const uint64_t *Records; |
| 120 // The number of (base) records. |
| 121 size_t RecordsSize; |
| 122 // The value used as record terminator. |
| 123 uint64_t RecordTerminator; |
| 124 // The block ID associated with the block being written. |
| 125 int WriteBlockID; |
| 126 // The SetBID for the blockinfo block. |
| 127 int SetBID; |
| 128 // The results buffer of the last dump. |
| 129 std::string DumpResults; |
| 130 // The memory buffer containing the munged input. |
| 131 std::unique_ptr<MemoryBuffer> MungedInput; |
| 132 // The stream containing errors and the objdump of the generated bitcode file. |
| 133 raw_ostream *DumpStream; |
| 134 // The bitstream writer to use to generate the bitcode file. |
| 135 NaClBitstreamWriter *Writer; |
| 136 // True if any errors were reported. |
| 137 bool FoundErrors; |
| 138 // The buffer to hold the generated fatal message. |
| 139 std::string FatalBuffer; |
| 140 // The stream to write the fatal message to. |
| 141 raw_string_ostream FatalStream; |
| 142 |
| 143 // Records that an error occurred, and returns stream to print error |
| 144 // message to. |
| 145 raw_ostream &Error() { |
| 146 FoundErrors = true; |
| 147 return *DumpStream << "Error: "; |
| 148 } |
| 149 |
| 150 // Returns stream to print fatal error message to. |
| 151 // Note: Once the fatal error message has been dumped to the stream, |
| 152 // one must call ReportFatalError to display the error and terminate |
| 153 // execution. |
| 154 raw_ostream &Fatal() { |
| 155 return FatalStream << "Fatal: "; |
| 156 } |
| 157 |
| 158 // Displays the fatal error message and exits the program. |
| 159 void ReportFatalError() { |
| 160 report_fatal_error(FatalStream.str()); |
| 161 } |
| 162 |
| 163 /// Returns the lines containing the given Substring, from the |
| 164 /// string getTestResults(). If MustBePrefix, then Substring must |
| 165 /// match at the beginning of the line. |
| 166 std::string getLinesWithTextMatch(const std::string &Substring, |
| 167 bool MustBePrefix = false) const; |
| 168 |
| 169 // Writes out sequence of records, applying the given sequence of |
| 170 // munges. |
| 171 void writeMungedData(const uint64_t Munges[], size_t MungesSize, |
| 172 bool AddHeader); |
| 173 |
| 174 // Emits the given record to the bitcode file. |
| 175 void emitRecord(unsigned AbbrevIndex, unsigned RecordCode, |
| 176 SmallVectorImpl<uint64_t> &Values); |
| 177 |
| 178 // Converts the abbreviation record to the corresponding abbreviation. |
| 179 NaClBitCodeAbbrev *buildAbbrev(unsigned RecordCode, |
| 180 SmallVectorImpl<uint64_t> &Values); |
| 181 |
| 182 // Emits the record at the given Index to the bitcode file. Then |
| 183 // updates Index by one. |
| 184 void emitRecordAtIndex(const uint64_t Record[], size_t RecordSize, |
| 185 size_t &Index); |
| 186 |
| 187 // Skips the record starting at Index by advancing Index past the |
| 188 // contents of the record. |
| 189 void deleteRecord(const uint64_t Record[], size_t RecordSize, |
| 190 size_t &Index); |
| 191 }; |
| 192 |
| 193 /// Class to run tests for function llvm::NaClObjDump. |
| 194 class NaClObjDumpMunger : public NaClBitcodeMunger { |
| 195 public: |
| 196 |
| 197 /// Creates a bitcode munger, based on the given array of values. |
| 198 NaClObjDumpMunger(const uint64_t Records[], size_t RecordsSize, |
| 199 uint64_t RecordTerminator) |
| 200 : NaClBitcodeMunger(Records, RecordsSize, RecordTerminator) {} |
| 201 |
| 202 /// Runs function NaClObjDump on the sequence of records associated |
| 203 /// with the instance. The memory buffer containing the bitsequence |
| 204 /// associated with the record is automatically generated, and |
| 205 /// passed to NaClObjDump. TestName is the name associated with the |
| 206 /// memory buffer. If AddHeader is true, test assumes that the |
| 207 /// sequence of records doesn't contain a header record, and the |
| 208 /// test should add one. Arguments NoRecords and NoAssembly are |
| 209 /// passed to NaClObjDump. Returns true if test succeeds without |
| 210 /// errors. |
| 211 bool runTestWithFlags(const char *TestName, bool AddHeader, |
| 212 bool NoRecords, bool NoAssembly) { |
| 213 uint64_t NoMunges[] = {0}; |
| 214 return runTestWithFlags(TestName, NoMunges, 0, AddHeader, NoRecords, |
| 215 NoAssembly); |
| 216 } |
| 217 |
| 218 /// Same as above except it runs function NaClObjDump with flags |
| 219 /// NoRecords and NoAssembly set to false, and AddHeader set to true. |
| 220 bool runTest(const char *TestName) { |
| 221 return runTestWithFlags(TestName, true, false, false); |
| 222 } |
| 223 |
| 224 /// Same as runTest, but only print out assembly and errors. |
| 225 bool runTestForAssembly(const char *TestName) { |
| 226 return runTestWithFlags(TestName, true, true, false); |
| 227 } |
| 228 |
| 229 /// Same as runTest, but only generate error messages. |
| 230 bool runTestForErrors(const char *TestName) { |
| 231 return runTestWithFlags(TestName, true, true, true); |
| 232 } |
| 233 |
| 234 /// Runs function llvm::NaClObjDump on the sequence of records |
| 235 /// associated with the instance. Array Munges contains the sequence |
| 236 /// of edits to apply to the sequence of records when generating the |
| 237 /// bitsequence in a memory buffer. This generated bitsequence is |
| 238 /// then passed to NaClObjDump. TestName is the name associated |
| 239 /// with the memory buffer. Arguments NoRecords and NoAssembly are |
| 240 /// passed to NaClObjDump. Returns true if test succeeds without |
| 241 /// errors. |
| 242 bool runTestWithFlags(const char* TestName, const uint64_t Munges[], |
| 243 size_t MungesSize, bool AddHeader, |
| 244 bool NoRecords, bool NoAssembly); |
| 245 |
| 246 /// Same as above except it runs function NaClObjDump with flags |
| 247 /// NoRecords and NoAssembly set to false, and AddHeader set to |
| 248 /// true. |
| 249 bool runTest(const char* TestName, const uint64_t Munges[], |
| 250 size_t MungesSize) { |
| 251 return runTestWithFlags(TestName, Munges, MungesSize, true, false, false); |
| 252 } |
| 253 |
| 254 bool runTestForAssembly(const char* TestName, const uint64_t Munges[], |
| 255 size_t MungesSize) { |
| 256 return runTestWithFlags(TestName, Munges, MungesSize, true, true, false); |
| 257 } |
| 258 |
| 259 bool runTestForErrors(const char* TestName, const uint64_t Munges[], |
| 260 size_t MungesSize) { |
| 261 return runTestWithFlags(TestName, Munges, MungesSize, true, true, true); |
| 262 } |
| 263 }; |
| 264 |
| 265 // Class to run tests for function NaClParseBitcodeFile. |
| 266 class NaClParseBitcodeMunger : public NaClBitcodeMunger { |
| 267 public: |
| 268 NaClParseBitcodeMunger(const uint64_t Records[], size_t RecordsSize, |
| 269 uint64_t RecordTerminator) |
| 270 : NaClBitcodeMunger(Records, RecordsSize, RecordTerminator) {} |
| 271 |
| 272 /// Runs function llvm::NaClParseBitcodeFile, and puts error messages |
| 273 /// into DumpResults. Returns true if parse is successful. |
| 274 bool runTest(const char* TestName, const uint64_t Munges[], |
| 275 size_t MungesSize, bool VerboseErrors); |
| 276 |
| 277 // Same as above, but without any edits. |
| 278 bool runTest(const char* TestName, bool VerboseErrors) { |
| 279 uint64_t NoMunges[] = {0}; |
| 280 return runTest(TestName, NoMunges, 0, VerboseErrors); |
| 281 } |
| 282 }; |
| 283 |
| 284 } // end namespace llvm. |
| 285 |
| 286 #endif // LLVM_BITCODE_NACL_NACLBITCODEMUNGE_H |
OLD | NEW |