Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 //===--- Bitcode/NaCl/TestUtils/NaClBitcodeMunge.cpp - Bitcode Munger -----===// | 1 //===--- Bitcode/NaCl/TestUtils/NaClBitcodeMunge.cpp - Bitcode Munger -----===// |
| 2 // | 2 // |
| 3 // The LLVM Compiler Infrastructure | 3 // The LLVM Compiler Infrastructure |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 // | 9 // |
| 10 // Bitcode writer/munger implementation for testing. | 10 // Bitcode writer/munger implementation for testing. |
| 11 // | 11 // |
| 12 //===----------------------------------------------------------------------===// | 12 //===----------------------------------------------------------------------===// |
| 13 | 13 |
| 14 #include "llvm/Bitcode/NaCl/NaClBitcodeMunge.h" | 14 #include "llvm/Bitcode/NaCl/NaClBitcodeMunge.h" |
| 15 | 15 |
| 16 #include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h" | 16 #include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h" |
| 17 #include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" | 17 #include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" |
| 18 #include "llvm/Bitcode/NaCl/NaClBitstreamWriter.h" | |
| 19 #include "llvm/Bitcode/NaCl/NaClCompress.h" | 18 #include "llvm/Bitcode/NaCl/NaClCompress.h" |
| 20 #include "llvm/Bitcode/NaCl/NaClReaderWriter.h" | 19 #include "llvm/Bitcode/NaCl/NaClReaderWriter.h" |
| 21 #include "llvm/IR/LLVMContext.h" | 20 #include "llvm/IR/LLVMContext.h" |
| 22 #include "llvm/IR/Module.h" | 21 #include "llvm/IR/Module.h" |
| 23 #include "llvm/Support/ErrorHandling.h" | 22 #include "llvm/Support/ErrorHandling.h" |
| 24 #include "llvm/Support/MemoryBuffer.h" | 23 #include "llvm/Support/MemoryBuffer.h" |
| 25 | 24 |
| 26 #include <memory> | 25 #include <memory> |
| 27 | 26 |
| 28 using namespace llvm; | 27 using namespace llvm; |
| 29 | 28 |
| 30 // For debugging. When true, shows each PNaCl record that is | 29 // For debugging. When true, shows each test being run. |
| 31 // emitted to the bitcode file. | 30 static bool TraceTestRuns = false; |
| 32 static bool DebugEmitRecord = false; | |
| 33 | 31 |
| 34 void NaClBitcodeMunger::setupTest( | 32 void NaClBitcodeMunger::setupTest( |
| 35 const char *TestName, const uint64_t Munges[], size_t MungesSize, | 33 const char *TestName, const uint64_t Munges[], size_t MungesSize, |
| 36 bool AddHeader) { | 34 bool AddHeader) { |
| 37 assert(DumpStream == nullptr && "Test run with DumpStream already defined"); | 35 assert(DumpStream == nullptr && "Test run with DumpStream already defined"); |
| 38 assert(MungedInput.get() == nullptr | 36 assert(MungedInput.get() == nullptr |
| 39 && "Test run with MungedInput already defined"); | 37 && "Test run with MungedInput already defined"); |
| 40 FoundErrors = false; | 38 FoundErrors = false; |
| 41 DumpResults.clear(); // Throw away any previous results. | 39 DumpResults.clear(); // Throw away any previous results. |
| 42 std::string DumpBuffer; | 40 std::string DumpBuffer; |
| 43 DumpStream = new raw_string_ostream(DumpResults); | 41 DumpStream = new raw_string_ostream(DumpResults); |
| 44 MungedInputBuffer.clear(); | 42 MungedInputBuffer.clear(); |
| 45 NaClBitstreamWriter OutStream(MungedInputBuffer); | |
| 46 Writer = &OutStream; | |
| 47 | 43 |
| 48 if (DebugEmitRecord) { | 44 if (TraceTestRuns) { |
| 49 errs() << "*** Run test: " << TestName << "\n"; | 45 errs() << "*** Run test: " << TestName << "\n"; |
| 50 } | 46 } |
| 51 | 47 |
| 52 WriteBlockID = -1; | |
| 53 SetBID = -1; | |
| 54 | |
| 55 MungedBitcode.munge(Munges, MungesSize, RecordTerminator); | 48 MungedBitcode.munge(Munges, MungesSize, RecordTerminator); |
| 56 writeMungedBitcode(MungedBitcode, AddHeader); | 49 NaClMungedBitcode::WriteResults Results = |
| 50 MungedBitcode.writeMaybeRepair(MungedInputBuffer, AddHeader, WriteFlags); | |
| 51 if (Results.HasErrors | |
| 52 && (!WriteFlags.TryToRecover || !Results.HasRepairs) | |
|
jvoung (off chromium)
2015/05/06 22:08:09
Hmm might be easier to read with a round of Captai
Karl
2015/05/07 20:09:18
Done.
| |
| 53 && (!WriteFlags.SaveBadAbbrevIndices || !Results.SavedBadAbbrevIndices)) | |
| 54 report_fatal_error("Unable to generate bitcode file due to write errors"); | |
| 57 | 55 |
| 58 // Add null terminator, so that we meet the requirements of the | 56 // Add null terminator, so that we meet the requirements of the |
| 59 // MemoryBuffer API. | 57 // MemoryBuffer API. |
| 60 MungedInputBuffer.push_back('\0'); | 58 MungedInputBuffer.push_back('\0'); |
| 61 | 59 |
| 62 MungedInput = MemoryBuffer::getMemBuffer( | 60 MungedInput = MemoryBuffer::getMemBuffer( |
| 63 StringRef(MungedInputBuffer.data(), MungedInputBuffer.size()-1), | 61 StringRef(MungedInputBuffer.data(), MungedInputBuffer.size()-1), |
| 64 TestName); | 62 TestName); |
| 65 } | 63 } |
| 66 | 64 |
| 67 void NaClBitcodeMunger::cleanupTest() { | 65 void NaClBitcodeMunger::cleanupTest() { |
| 68 MungedBitcode.removeEdits(); | 66 MungedBitcode.removeEdits(); |
| 69 MungedInput.reset(); | 67 MungedInput.reset(); |
| 70 assert(DumpStream && "Dump stream removed before cleanup!"); | 68 assert(DumpStream && "Dump stream removed before cleanup!"); |
| 71 DumpStream->flush(); | 69 DumpStream->flush(); |
| 72 delete DumpStream; | 70 delete DumpStream; |
| 73 DumpStream = nullptr; | 71 DumpStream = nullptr; |
| 74 Writer = nullptr; | |
| 75 } | 72 } |
| 76 | 73 |
| 77 // Return the next line of input (including eoln), starting from | 74 // Return the next line of input (including eoln), starting from |
| 78 // Pos. Then increment Pos past the end of that line. | 75 // Pos. Then increment Pos past the end of that line. |
| 79 static std::string getLine(const std::string &Input, size_t &Pos) { | 76 static std::string getLine(const std::string &Input, size_t &Pos) { |
| 80 std::string Line; | 77 std::string Line; |
| 81 if (Pos >= Input.size()) { | 78 if (Pos >= Input.size()) { |
| 82 Pos = std::string::npos; | 79 Pos = std::string::npos; |
| 83 return Line; | 80 return Line; |
| 84 } | 81 } |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 101 std::string Line = getLine(DumpResults, LastLinePos); | 98 std::string Line = getLine(DumpResults, LastLinePos); |
| 102 if (LastLinePos == std::string::npos) break; | 99 if (LastLinePos == std::string::npos) break; |
| 103 size_t Pos = Line.find(Substring); | 100 size_t Pos = Line.find(Substring); |
| 104 if (Pos != std::string::npos && (!MustBePrefix || Pos == 0)) { | 101 if (Pos != std::string::npos && (!MustBePrefix || Pos == 0)) { |
| 105 Messages.append(Line); | 102 Messages.append(Line); |
| 106 } | 103 } |
| 107 } | 104 } |
| 108 return Messages; | 105 return Messages; |
| 109 } | 106 } |
| 110 | 107 |
| 111 void NaClBitcodeMunger::writeMungedBitcode(const NaClMungedBitcode &Bitcode, | |
| 112 bool AddHeader) { | |
| 113 if (AddHeader) { | |
| 114 NaClWriteHeader(*Writer, true); | |
| 115 } | |
| 116 for (const NaClBitcodeAbbrevRecord &Record : Bitcode) { | |
| 117 emitRecord(Record); | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 void NaClBitcodeMunger::emitRecord(const NaClBitcodeAbbrevRecord &Record) { | |
| 122 if (DebugEmitRecord) { | |
| 123 errs() << "Emit " << Record.Abbrev << ": <" << Record.Code; | |
| 124 for (size_t i = 0, e = Record.Values.size(); i < e; ++i) { | |
| 125 errs() << ", " << Record.Values[i]; | |
| 126 } | |
| 127 errs() << ">\n"; | |
| 128 } | |
| 129 | |
| 130 switch (Record.Code) { | |
| 131 case naclbitc::BLK_CODE_ENTER: { | |
| 132 unsigned NumBits = naclbitc::DEFAULT_MAX_ABBREV; | |
| 133 WriteBlockID = -1; | |
| 134 if (Record.Abbrev != naclbitc::ENTER_SUBBLOCK) { | |
| 135 Fatal() << "Enter block record code " << Record.Code | |
| 136 << " uses illegal abbreviation index " << Record.Abbrev << "\n"; | |
| 137 ReportFatalError(); | |
| 138 } | |
| 139 if (Record.Values.size() == 2) { | |
| 140 WriteBlockID = Record.Values[0]; | |
| 141 NumBits = Record.Values[1]; | |
| 142 if (NumBits > 32) { | |
| 143 Fatal() << "Error: Bit size " << NumBits | |
| 144 << " for record should be <= 32\n"; | |
| 145 ReportFatalError(); | |
| 146 } | |
| 147 if (NumBits < 2) { | |
| 148 Fatal() << "Error: Bit size " << NumBits | |
| 149 << " for record should be >= 2\n"; | |
| 150 ReportFatalError(); | |
| 151 } | |
| 152 } else { | |
| 153 Fatal() << "Error: Values for enter record should be of size 2. Found: " | |
| 154 << Record.Values.size(); | |
| 155 ReportFatalError(); | |
| 156 } | |
| 157 uint64_t MaxAbbrev = (static_cast<uint64_t>(1) << NumBits) - 1; | |
| 158 AbbrevIndexLimitStack.push_back(MaxAbbrev); | |
| 159 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) { | |
| 160 if (NumBits != naclbitc::DEFAULT_MAX_ABBREV) { | |
| 161 Fatal() | |
| 162 << "Error: Numbits entry for abbreviations record not 2. Found: " | |
| 163 << NumBits << "\n"; | |
| 164 ReportFatalError(); | |
| 165 } | |
| 166 Writer->EnterBlockInfoBlock(); | |
| 167 } else { | |
| 168 NaClBitcodeSelectorAbbrev CurCodeLen(MaxAbbrev); | |
| 169 Writer->EnterSubblock(WriteBlockID, CurCodeLen); | |
| 170 } | |
| 171 return; | |
| 172 } | |
| 173 case naclbitc::BLK_CODE_EXIT: | |
| 174 if (Record.Abbrev != naclbitc::END_BLOCK) { | |
| 175 Fatal() << "Error: Exit block record code " << Record.Code | |
| 176 << " uses illegal abbreviation index " << Record.Abbrev << "\n"; | |
| 177 ReportFatalError(); | |
| 178 } | |
| 179 if (!Record.Values.empty()) { | |
| 180 Fatal() << "Error: Exit block should not have values. Found: " | |
| 181 << Record.Values.size() << "\n"; | |
| 182 ReportFatalError(); | |
| 183 } | |
| 184 if (!AbbrevIndexLimitStack.empty()) | |
| 185 AbbrevIndexLimitStack.pop_back(); | |
| 186 Writer->ExitBlock(); | |
| 187 return; | |
| 188 case naclbitc::BLK_CODE_DEFINE_ABBREV: { | |
| 189 if (Record.Abbrev != naclbitc::DEFINE_ABBREV) { | |
| 190 Fatal() << "Error: Define abbreviation record code " << Record.Code | |
| 191 << " uses illegal abbreviation index " << Record.Abbrev << "\n"; | |
| 192 ReportFatalError(); | |
| 193 } | |
| 194 NaClBitCodeAbbrev *Abbrev = buildAbbrev(Record); | |
| 195 if (Abbrev == NULL) return; | |
| 196 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) { | |
| 197 Writer->EmitBlockInfoAbbrev(SetBID, Abbrev); | |
| 198 } else { | |
| 199 Writer->EmitAbbrev(Abbrev); | |
| 200 } | |
| 201 return; | |
| 202 } | |
| 203 case naclbitc::BLK_CODE_HEADER: | |
| 204 // Note: There is no abbreviation index here. Ignore. | |
| 205 for (uint64_t Value : Record.Values) | |
| 206 Writer->Emit(Value, 8); | |
| 207 return; | |
| 208 default: | |
| 209 if ((Record.Abbrev != naclbitc::UNABBREV_RECORD | |
| 210 && !Writer->isUserRecordAbbreviation(Record.Abbrev))) { | |
| 211 uint64_t BlockAbbrevIndexLimit = 0; | |
| 212 if (!AbbrevIndexLimitStack.empty()) | |
| 213 BlockAbbrevIndexLimit = AbbrevIndexLimitStack.back(); | |
| 214 if (Record.Abbrev > BlockAbbrevIndexLimit) { | |
| 215 Fatal() << "Error: Record code " << Record.Code | |
| 216 << " uses illegal abbreviation index " << Record.Abbrev | |
| 217 << ". Must not exceed " << BlockAbbrevIndexLimit << "\n"; | |
| 218 ReportFatalError(); | |
| 219 } | |
| 220 // Note: If this point is reached, the abbreviation is | |
| 221 // bad. However, that may be the point of munge being | |
| 222 // applied. Hence, emit the bad abbreviation and the data so | |
| 223 // that the reader can be tested on this bad input. For | |
| 224 // simplicity, we output the record data using the default | |
| 225 // abbreviation pattern. | |
| 226 errs() << "Warning: Record code " << Record.Code | |
| 227 << " uses illegal abbreviation index " << Record.Abbrev << "\n"; | |
| 228 Writer->EmitCode(Record.Abbrev); | |
| 229 Writer->EmitVBR(Record.Code, 6); | |
| 230 uint32_t NumValues = static_cast<uint32_t>(Record.Values.size()); | |
| 231 Writer->EmitVBR(NumValues, 6); | |
| 232 for (uint32_t i = 0; i < NumValues; ++i) { | |
| 233 Writer->EmitVBR64(Record.Values[i], 6); | |
| 234 } | |
| 235 return; | |
| 236 } | |
| 237 if (Record.Abbrev == naclbitc::UNABBREV_RECORD) | |
| 238 Writer->EmitRecord(Record.Code, Record.Values); | |
| 239 else | |
| 240 Writer->EmitRecord(Record.Code, Record.Values, Record.Abbrev); | |
| 241 return; | |
| 242 } | |
| 243 Fatal() << "emitRecord on unimplemented code" << "\n"; | |
| 244 ReportFatalError(); | |
| 245 } | |
| 246 | |
| 247 NaClBitCodeAbbrev *NaClBitcodeMunger::buildAbbrev( | |
| 248 const NaClBitcodeAbbrevRecord &Record) { | |
| 249 NaClBitCodeAbbrev *Abbrev = new NaClBitCodeAbbrev(); | |
| 250 size_t Index = 0; | |
| 251 if (Record.Values.empty()) { | |
| 252 Fatal() << "Empty abbreviation record not allowed\n"; | |
| 253 ReportFatalError(); | |
| 254 } | |
| 255 size_t NumAbbreviations = Record.Values[Index++]; | |
| 256 size_t NumValues = Record.Values.size(); | |
| 257 if (NumAbbreviations == 0) { | |
| 258 Fatal() << "Abbreviation must contain at least one operator\n"; | |
| 259 ReportFatalError(); | |
| 260 } | |
| 261 for (size_t Count = 0; Count < NumAbbreviations; ++Count) { | |
| 262 if (Index >= NumValues) { | |
| 263 Fatal() << "Malformed abbreviation found. Expects " | |
| 264 << NumAbbreviations << " operands. Found: " | |
| 265 << Count << "\n"; | |
| 266 ReportFatalError(); | |
| 267 } | |
| 268 switch (Record.Values[Index++]) { | |
| 269 case 1: | |
| 270 if (Index >= NumValues) { | |
| 271 Fatal() << "Malformed literal abbreviation.\n"; | |
| 272 ReportFatalError(); | |
| 273 } | |
| 274 Abbrev->Add(NaClBitCodeAbbrevOp(Record.Values[Index++])); | |
| 275 break; | |
| 276 case 0: { | |
| 277 if (Index >= NumValues) { | |
| 278 Fatal() << "Malformed abbreviation found.\n"; | |
| 279 ReportFatalError(); | |
| 280 } | |
| 281 unsigned Kind = Record.Values[Index++]; | |
| 282 switch (Kind) { | |
| 283 case NaClBitCodeAbbrevOp::Fixed: | |
| 284 if (Index >= NumValues) { | |
| 285 Fatal() << "Malformed fixed abbreviation found.\n"; | |
| 286 ReportFatalError(); | |
| 287 } | |
| 288 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, | |
| 289 Record.Values[Index++])); | |
| 290 break; | |
| 291 case NaClBitCodeAbbrevOp::VBR: | |
| 292 if (Index >= NumValues) { | |
| 293 Fatal() << "Malformed vbr abbreviation found.\n"; | |
| 294 ReportFatalError(); | |
| 295 } | |
| 296 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, | |
| 297 Record.Values[Index++])); | |
| 298 break; | |
| 299 case NaClBitCodeAbbrevOp::Array: | |
| 300 if (Index >= NumValues) { | |
| 301 Fatal() << "Malformed array abbreviation found.\n"; | |
| 302 ReportFatalError(); | |
| 303 } | |
| 304 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array)); | |
| 305 break; | |
| 306 case NaClBitCodeAbbrevOp::Char6: | |
| 307 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Char6)); | |
| 308 break; | |
| 309 default: | |
| 310 Fatal() << "Unknown abbreviation kind. Found: " << Kind << "\n"; | |
| 311 ReportFatalError(); | |
| 312 } | |
| 313 break; | |
| 314 } | |
| 315 default: | |
| 316 Fatal() << "Error: Bad literal flag in abbreviation. Found: " | |
| 317 << Record.Values[Index]; | |
| 318 ReportFatalError(); | |
| 319 } | |
| 320 } | |
| 321 return Abbrev; | |
| 322 } | |
| 323 | |
| 324 bool NaClObjDumpMunger::runTestWithFlags( | 108 bool NaClObjDumpMunger::runTestWithFlags( |
| 325 const char *Name, const uint64_t Munges[], size_t MungesSize, | 109 const char *Name, const uint64_t Munges[], size_t MungesSize, |
| 326 bool AddHeader, bool NoRecords, bool NoAssembly) { | 110 bool AddHeader, bool NoRecords, bool NoAssembly) { |
| 327 setupTest(Name, Munges, MungesSize, AddHeader); | 111 setupTest(Name, Munges, MungesSize, AddHeader); |
| 328 | 112 |
| 329 /// If running in death mode, redirect output directly to the | 113 /// If running in death mode, redirect output directly to the |
| 330 /// error stream (rather than buffering in DumpStream), so that | 114 /// error stream (rather than buffering in DumpStream), so that |
| 331 /// output can be seen in gtest death test. | 115 /// output can be seen in gtest death test. |
| 332 raw_ostream &Output = RunAsDeathTest ? errs() : *DumpStream; | 116 raw_ostream &Output = RunAsDeathTest ? errs() : *DumpStream; |
| 333 if (NaClObjDump(MungedInput.get()->getMemBufferRef(), | 117 if (NaClObjDump(MungedInput.get()->getMemBufferRef(), |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 360 | 144 |
| 361 bool NaClCompressMunger::runTest(const char* Name, const uint64_t Munges[], | 145 bool NaClCompressMunger::runTest(const char* Name, const uint64_t Munges[], |
| 362 size_t MungesSize) { | 146 size_t MungesSize) { |
| 363 bool AddHeader = true; | 147 bool AddHeader = true; |
| 364 setupTest(Name, Munges, MungesSize, AddHeader); | 148 setupTest(Name, Munges, MungesSize, AddHeader); |
| 365 NaClBitcodeCompressor Compressor; | 149 NaClBitcodeCompressor Compressor; |
| 366 bool Result = Compressor.compress(MungedInput.get(), *DumpStream); | 150 bool Result = Compressor.compress(MungedInput.get(), *DumpStream); |
| 367 cleanupTest(); | 151 cleanupTest(); |
| 368 return Result; | 152 return Result; |
| 369 } | 153 } |
| OLD | NEW |