OLD | NEW |
(Empty) | |
| 1 //===--- Bitcode/NaCl/TestUtils/NaClBitcodeMunge.cpp - Bitcode Munger -----===// |
| 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 // Bitcode writer/munger implementation for testing. |
| 11 // |
| 12 //===----------------------------------------------------------------------===// |
| 13 |
| 14 #include "llvm/Bitcode/NaCl/NaClBitcodeMunge.h" |
| 15 |
| 16 #include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h" |
| 17 #include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" |
| 18 #include "llvm/Bitcode/NaCl/NaClBitstreamWriter.h" |
| 19 #include "llvm/Bitcode/NaCl/NaClReaderWriter.h" |
| 20 #include "llvm/IR/LLVMContext.h" |
| 21 #include "llvm/IR/Module.h" |
| 22 #include "llvm/Support/ErrorHandling.h" |
| 23 #include "llvm/Support/MemoryBuffer.h" |
| 24 |
| 25 #include <memory> |
| 26 |
| 27 using namespace llvm; |
| 28 |
| 29 // For debugging. When true, shows each PNaCl record that is |
| 30 // emitted to the bitcode file. |
| 31 static bool DebugEmitRecord = false; |
| 32 |
| 33 void NaClBitcodeMunger::setupTest( |
| 34 const char *TestName, const uint64_t Munges[], size_t MungesSize, |
| 35 bool AddHeader) { |
| 36 assert(DumpStream == nullptr && "Test run with DumpStream already defined"); |
| 37 assert(MungedInput.get() == nullptr |
| 38 && "Test run with MungedInput already defined"); |
| 39 FoundErrors = false; |
| 40 DumpResults.clear(); // Throw away any previous results. |
| 41 std::string DumpBuffer; |
| 42 DumpStream = new raw_string_ostream(DumpResults); |
| 43 SmallVector<char, 0> StreamBuffer; |
| 44 StreamBuffer.reserve(256*1024); |
| 45 NaClBitstreamWriter OutStream(StreamBuffer); |
| 46 Writer = &OutStream; |
| 47 |
| 48 if (DebugEmitRecord) { |
| 49 errs() << "*** Run test: " << TestName << "\n"; |
| 50 } |
| 51 |
| 52 WriteBlockID = -1; |
| 53 SetBID = -1; |
| 54 writeMungedData(Munges, MungesSize, AddHeader); |
| 55 |
| 56 std::string OutBuffer; |
| 57 raw_string_ostream BitcodeStrm(OutBuffer); |
| 58 for (SmallVectorImpl<char>::const_iterator |
| 59 Iter = StreamBuffer.begin(), IterEnd = StreamBuffer.end(); |
| 60 Iter != IterEnd; ++Iter) { |
| 61 BitcodeStrm << *Iter; |
| 62 } |
| 63 MungedInput = MemoryBuffer::getMemBufferCopy(BitcodeStrm.str(), TestName); |
| 64 } |
| 65 |
| 66 void NaClBitcodeMunger::cleanupTest() { |
| 67 MungedInput.reset(); |
| 68 assert(DumpStream && "Dump stream removed before cleanup!"); |
| 69 DumpStream->flush(); |
| 70 delete DumpStream; |
| 71 DumpStream = nullptr; |
| 72 Writer = nullptr; |
| 73 } |
| 74 |
| 75 // Return the next line of input (including eoln), starting from |
| 76 // Pos. Then increment Pos past the end of that line. |
| 77 static std::string getLine(const std::string &Input, size_t &Pos) { |
| 78 std::string Line; |
| 79 if (Pos >= Input.size()) { |
| 80 Pos = std::string::npos; |
| 81 return Line; |
| 82 } |
| 83 size_t Eoln = Input.find_first_of("\n", Pos); |
| 84 if (Eoln != std::string::npos) { |
| 85 for (size_t i = Pos; i <= Eoln; ++i) |
| 86 Line.push_back(Input[i]); |
| 87 Pos = Eoln + 1; |
| 88 return Line; |
| 89 } |
| 90 Pos = std::string::npos; |
| 91 return Input.substr(Pos); |
| 92 } |
| 93 |
| 94 std::string NaClBitcodeMunger:: |
| 95 getLinesWithTextMatch(const std::string &Substring, bool MustBePrefix) const { |
| 96 std::string Messages; |
| 97 size_t LastLinePos = 0; |
| 98 while (1) { |
| 99 std::string Line = getLine(DumpResults, LastLinePos); |
| 100 if (LastLinePos == std::string::npos) break; |
| 101 size_t Pos = Line.find(Substring); |
| 102 if (Pos != std::string::npos && (!MustBePrefix || Pos == 0)) { |
| 103 Messages.append(Line); |
| 104 } |
| 105 } |
| 106 return Messages; |
| 107 } |
| 108 |
| 109 void NaClBitcodeMunger::writeMungedData(const uint64_t Munges[], |
| 110 size_t MungesSize, bool AddHeader) { |
| 111 uint64_t RecordCount = 0; |
| 112 size_t MungesIndex = 0; |
| 113 if (AddHeader) { |
| 114 NaClWriteHeader(*Writer, true); |
| 115 } |
| 116 for (size_t RecordsIndex = 0; RecordsIndex < RecordsSize;) { |
| 117 if (MungesIndex < MungesSize && Munges[MungesIndex] == RecordCount) { |
| 118 if (MungesIndex + 2 > MungesSize) { |
| 119 Fatal() << "Munges entry must contain at least 2 elements. Found: " |
| 120 << MungesIndex; |
| 121 ReportFatalError(); |
| 122 } |
| 123 ++MungesIndex; |
| 124 switch (Munges[MungesIndex++]) { |
| 125 case NaClBitcodeMunger::AddBefore: |
| 126 emitRecordAtIndex(Munges, MungesSize, MungesIndex); |
| 127 break; |
| 128 case NaClBitcodeMunger::AddAfter: |
| 129 emitRecordAtIndex(Records, RecordsSize, RecordsIndex); |
| 130 ++RecordCount; |
| 131 emitRecordAtIndex(Munges, MungesSize, MungesIndex); |
| 132 break; |
| 133 case NaClBitcodeMunger::Remove: |
| 134 deleteRecord(Records, RecordsSize, RecordsIndex); |
| 135 ++RecordCount; |
| 136 break; |
| 137 case NaClBitcodeMunger::Replace: |
| 138 deleteRecord(Records, RecordsSize, RecordsIndex); |
| 139 emitRecordAtIndex(Munges, MungesSize, MungesIndex); |
| 140 ++RecordCount; |
| 141 break; |
| 142 default: |
| 143 Fatal() << "Munge directive not understood: " << Munges[MungesIndex]; |
| 144 ReportFatalError(); |
| 145 break; |
| 146 } |
| 147 } else { |
| 148 emitRecordAtIndex(Records, RecordsSize, RecordsIndex); |
| 149 ++RecordCount; |
| 150 } |
| 151 } |
| 152 if (MungesIndex < MungesSize) { |
| 153 Fatal() << "Unprocessed modifications. At index " << MungesIndex << "\n"; |
| 154 ReportFatalError(); |
| 155 } |
| 156 } |
| 157 |
| 158 void NaClBitcodeMunger::deleteRecord( |
| 159 const uint64_t Record[], size_t RecordSize, size_t &Index) { |
| 160 while (Index < RecordSize) { |
| 161 if (Record[Index++] == RecordTerminator) |
| 162 break; |
| 163 } |
| 164 } |
| 165 |
| 166 void NaClBitcodeMunger::emitRecordAtIndex( |
| 167 const uint64_t Record[], size_t RecordSize, size_t &Index) { |
| 168 if (Index + 3 > RecordSize) { |
| 169 Fatal() << "Last record doesn't contain at least 3 elements. Found: " |
| 170 << (RecordSize - Index); |
| 171 ReportFatalError(); |
| 172 } |
| 173 SmallVector<uint64_t, 32> RecordValues; |
| 174 unsigned AbbrevIndex = static_cast<unsigned>(Record[Index++]); |
| 175 unsigned RecordCode = static_cast<unsigned>(Record[Index++]); |
| 176 while (Index < RecordSize && Record[Index] != RecordTerminator) { |
| 177 RecordValues.push_back(Record[Index++]); |
| 178 } |
| 179 emitRecord(AbbrevIndex, RecordCode, RecordValues); |
| 180 if (Index == RecordSize) { |
| 181 Fatal() << "Last record not followed by terminator.\n"; |
| 182 ReportFatalError(); |
| 183 } |
| 184 ++Index; |
| 185 } |
| 186 |
| 187 void NaClBitcodeMunger::emitRecord(unsigned AbbrevIndex, |
| 188 unsigned RecordCode, |
| 189 SmallVectorImpl<uint64_t> &Values) { |
| 190 if (DebugEmitRecord) { |
| 191 errs() << "Emit " << AbbrevIndex << ": <" << RecordCode; |
| 192 for (size_t i = 0; i < Values.size(); ++i) { |
| 193 errs() << ", " << Values[i]; |
| 194 } |
| 195 errs() << ">\n"; |
| 196 } |
| 197 |
| 198 switch (RecordCode) { |
| 199 case naclbitc::BLK_CODE_ENTER: { |
| 200 unsigned NumBits = naclbitc::DEFAULT_MAX_ABBREV; |
| 201 WriteBlockID = -1; |
| 202 if (AbbrevIndex != naclbitc::ENTER_SUBBLOCK) { |
| 203 Fatal() << "Enter block record code " << RecordCode |
| 204 << " uses illegal abbreviation index " << AbbrevIndex << "\n"; |
| 205 ReportFatalError(); |
| 206 } |
| 207 if (Values.size() == 2) { |
| 208 WriteBlockID = Values[0]; |
| 209 NumBits = Values[1]; |
| 210 if (NumBits > 32) { |
| 211 Fatal() << "Error: Bit size " << NumBits |
| 212 << " for record should be <= 32\n"; |
| 213 ReportFatalError(); |
| 214 } |
| 215 } else { |
| 216 Fatal() << "Error: Values for enter record should be of size 2. Found: " |
| 217 << Values.size(); |
| 218 ReportFatalError(); |
| 219 } |
| 220 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) { |
| 221 if (NumBits != naclbitc::DEFAULT_MAX_ABBREV) { |
| 222 Fatal() |
| 223 << "Error: Numbits entry for abbreviations record not 2. Found: " |
| 224 << NumBits << "\n"; |
| 225 ReportFatalError(); |
| 226 } |
| 227 Writer->EnterBlockInfoBlock(); |
| 228 } else { |
| 229 Writer->EnterSubblock(WriteBlockID, NumBits); |
| 230 } |
| 231 return; |
| 232 } |
| 233 case naclbitc::BLK_CODE_EXIT: |
| 234 if (AbbrevIndex != naclbitc::END_BLOCK) { |
| 235 Fatal() << "Error: Exit block record code " << RecordCode |
| 236 << " uses illegal abbreviation index " << AbbrevIndex << "\n"; |
| 237 ReportFatalError(); |
| 238 } |
| 239 if (!Values.empty()) { |
| 240 Fatal() << "Error: Exit block should not have values. Found: " |
| 241 << Values.size() << "\n"; |
| 242 ReportFatalError(); |
| 243 } |
| 244 Writer->ExitBlock(); |
| 245 return; |
| 246 case naclbitc::BLK_CODE_DEFINE_ABBREV: { |
| 247 if (AbbrevIndex != naclbitc::DEFINE_ABBREV) { |
| 248 Fatal() << "Error: Define abbreviation record code " << RecordCode |
| 249 << " uses illegal abbreviation index " << AbbrevIndex << "\n"; |
| 250 ReportFatalError(); |
| 251 } |
| 252 NaClBitCodeAbbrev *Abbrev = buildAbbrev(RecordCode, Values); |
| 253 if (Abbrev == NULL) return; |
| 254 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) { |
| 255 Writer->EmitBlockInfoAbbrev(SetBID, Abbrev); |
| 256 } else { |
| 257 Writer->EmitAbbrev(Abbrev); |
| 258 } |
| 259 return; |
| 260 } |
| 261 case naclbitc::BLK_CODE_HEADER: |
| 262 // Note: There is no abbreviation index here. Ignore. |
| 263 for (SmallVectorImpl<uint64_t>::const_iterator |
| 264 Iter = Values.begin(), IterEnd = Values.end(); |
| 265 Iter != IterEnd; ++Iter) { |
| 266 Writer->Emit(*Iter, 8); |
| 267 } |
| 268 return; |
| 269 default: |
| 270 if ((AbbrevIndex != naclbitc::UNABBREV_RECORD |
| 271 && !Writer->isUserRecordAbbreviation(AbbrevIndex))) { |
| 272 Fatal() << "Error: Record code " << RecordCode |
| 273 << " uses illegal abbreviation index " << AbbrevIndex << "\n"; |
| 274 ReportFatalError(); |
| 275 } |
| 276 if (AbbrevIndex == naclbitc::UNABBREV_RECORD) |
| 277 Writer->EmitRecord(RecordCode, Values); |
| 278 else |
| 279 Writer->EmitRecord(RecordCode, Values, AbbrevIndex); |
| 280 return; |
| 281 } |
| 282 Fatal() << "emitRecord on unimplemented code" << "\n"; |
| 283 ReportFatalError(); |
| 284 } |
| 285 |
| 286 NaClBitCodeAbbrev *NaClBitcodeMunger::buildAbbrev( |
| 287 unsigned RecordCode, SmallVectorImpl<uint64_t> &Values) { |
| 288 NaClBitCodeAbbrev *Abbrev = new NaClBitCodeAbbrev(); |
| 289 for (size_t Index = 0; Index < Values.size(); ) { |
| 290 switch (Values[Index]) { |
| 291 case 1: |
| 292 if (Index + 1 >= Values.size()) { |
| 293 Fatal() << "Malformed literal abbreviation.\n"; |
| 294 ReportFatalError(); |
| 295 } |
| 296 Abbrev->Add(NaClBitCodeAbbrevOp(Values[++Index])); |
| 297 break; |
| 298 case 0: { |
| 299 if (Index >= Values.size()) { |
| 300 Fatal() << "Malformed abbreviation found.\n"; |
| 301 ReportFatalError(); |
| 302 } |
| 303 unsigned Kind = Values[++Index]; |
| 304 switch (Kind) { |
| 305 case NaClBitCodeAbbrevOp::Fixed: |
| 306 if (Index >= Values.size()) { |
| 307 Fatal() << "Malformed fixed abbreviation found.\n"; |
| 308 ReportFatalError(); |
| 309 } |
| 310 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, |
| 311 Values[++Index])); |
| 312 break; |
| 313 case NaClBitCodeAbbrevOp::VBR: |
| 314 if (Index >= Values.size()) { |
| 315 Fatal() << "Malformed vbr abbreviation found.\n"; |
| 316 ReportFatalError(); |
| 317 } |
| 318 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, |
| 319 Values[++Index])); |
| 320 break; |
| 321 case NaClBitCodeAbbrevOp::Array: |
| 322 if (Index >= Values.size()) { |
| 323 Fatal() << "Malformed array abbreviation found.\n"; |
| 324 ReportFatalError(); |
| 325 } |
| 326 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array)); |
| 327 break; |
| 328 case NaClBitCodeAbbrevOp::Char6: |
| 329 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Char6)); |
| 330 break; |
| 331 default: |
| 332 Fatal() << "Unknown abbreviation kind. Found: " << Kind << "\n"; |
| 333 ReportFatalError(); |
| 334 } |
| 335 break; |
| 336 } |
| 337 default: |
| 338 Fatal() << "Error: Bad literal flag in abbreviation. Found: " |
| 339 << Values[Index]; |
| 340 ReportFatalError(); |
| 341 } |
| 342 } |
| 343 return Abbrev; |
| 344 } |
| 345 |
| 346 bool NaClObjDumpMunger::runTestWithFlags( |
| 347 const char *Name, const uint64_t Munges[], size_t MungesSize, |
| 348 bool AddHeader, bool NoRecords, bool NoAssembly) { |
| 349 setupTest(Name, Munges, MungesSize, AddHeader); |
| 350 // TODO(jvoung,kschimpf): Should NaClObjDump take a MemoryBufferRef |
| 351 // like the parser? |
| 352 if (NaClObjDump(MungedInput.get(), *DumpStream, NoRecords, NoAssembly)) |
| 353 FoundErrors = true; |
| 354 cleanupTest(); |
| 355 return !FoundErrors; |
| 356 } |
| 357 |
| 358 bool NaClParseBitcodeMunger::runTest( |
| 359 const char *Name, const uint64_t Munges[], size_t MungesSize, |
| 360 bool VerboseErrors) { |
| 361 bool AddHeader = true; |
| 362 setupTest(Name, Munges, MungesSize, AddHeader); |
| 363 LLVMContext &Context = getGlobalContext(); |
| 364 raw_ostream *VerboseStrm = VerboseErrors ? DumpStream : nullptr; |
| 365 ErrorOr<Module *> ModuleOrError = |
| 366 NaClParseBitcodeFile(MungedInput->getMemBufferRef(), Context, |
| 367 VerboseStrm); |
| 368 if (ModuleOrError) { |
| 369 if (VerboseErrors) |
| 370 *DumpStream << "Successful parse!\n"; |
| 371 delete ModuleOrError.get(); |
| 372 } else { |
| 373 Error() << ModuleOrError.getError().message() << "\n"; |
| 374 } |
| 375 cleanupTest(); |
| 376 return !FoundErrors; |
| 377 } |
OLD | NEW |