Index: lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp |
diff --git a/lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp b/lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..85da68ddaf3cbcb769ad2f29c2a59d8c67696384 |
--- /dev/null |
+++ b/lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp |
@@ -0,0 +1,336 @@ |
+//===- NaClBitcodeMungeWriter.cpp - Write munged bitcode --------*- C++ -*-===// |
+// |
+// The LLVM Compiler Infrastructure |
+// |
+// This file is distributed under the University of Illinois Open Source |
+// License. See LICENSE.TXT for details. |
+// |
+//===----------------------------------------------------------------------===// |
+// |
+// Implements method NaClMungedBitcode.write(), which writes out a munged |
+// list of bitcode records using a bitstream writer. |
+ |
+#include "llvm/Bitcode/NaCl/NaClBitcodeMungeUtils.h" |
+ |
+#include "llvm/Bitcode/NaCl/NaClBitstreamWriter.h" |
+#include "llvm/Bitcode/NaCl/NaClReaderWriter.h" |
+ |
+using namespace llvm; |
+ |
+namespace { |
+ |
+// For debugging. When true, shows each PNaCl record that is |
+// emitted to the bitcode file. |
+static bool DebugEmitRecord = false; |
+ |
+// State of bitcode writing. |
+struct WriteState { |
+ // The block ID associated with the block being written. |
+ int WriteBlockID = -1; |
+ // The SetBID for the blockinfo block. |
+ int SetBID = -1; |
+ // The stack of maximum abbreviation indices allowed by block enter record. |
+ SmallVector<uint64_t, 3> AbbrevIndexLimitStack; |
+ // The set of write flags to use. |
+ const NaClMungedBitcode::WriteFlags &Flags; |
+ // The results of the attempted write. |
+ NaClMungedBitcode::WriteResults Results; |
+ |
+ WriteState(const NaClMungedBitcode::WriteFlags &Flags) : Flags(Flags) {} |
+ |
+ // Returns stream to print error message to. |
+ raw_ostream &Error() { |
+ Results.HasErrors = true; |
+ return errs() << "Error (Block " << WriteBlockID << "): "; |
+ } |
+ |
+ // Returns stream to print error message to, assuming that |
+ // the error message can be repaired if Flags.TryToRecover is true. |
+ raw_ostream &RecoverableError() { |
+ if (Flags.TryToRecover) |
+ Results.HasRepairs = true; |
+ return Error(); |
+ } |
+ |
+ // Converts the abbreviation record to the corresponding abbreviation. |
+ // Returns nullptr if unable to build abbreviation. |
+ NaClBitCodeAbbrev *buildAbbrev(const NaClBitcodeAbbrevRecord &Record); |
+ |
+ // Emits the given record to the bitcode file. Returns true if |
+ // successful. |
+ bool emitRecord(NaClBitstreamWriter &Writer, |
+ const NaClBitcodeAbbrevRecord &Record); |
+ |
+ // Adds any missing end blocks to written bitcode. |
+ void writeMissingEndBlocks(NaClBitstreamWriter &Writer) { |
+ while (!AbbrevIndexLimitStack.empty()) { |
+ Writer.ExitBlock(); |
+ AbbrevIndexLimitStack.pop_back(); |
+ } |
+ } |
+}; |
+ |
+bool WriteState::emitRecord(NaClBitstreamWriter &Writer, |
+ const NaClBitcodeAbbrevRecord &Record) { |
+ size_t NumValues = Record.Values.size(); |
+ if (DebugEmitRecord) { |
+ errs() << "Emit " << Record.Abbrev << ": <" << Record.Code; |
+ for (size_t i = 0; i < NumValues; ++i) { |
+ errs() << ", " << Record.Values[i]; |
+ } |
+ errs() << ">\n"; |
+ } |
+ |
+ switch (Record.Code) { |
+ case naclbitc::BLK_CODE_ENTER: { |
+ unsigned NumBits = naclbitc::DEFAULT_MAX_ABBREV; |
jvoung (off chromium)
2015/05/06 22:08:09
Should this also be NaClBitsNeededForValue( naclbi
Karl
2015/05/07 20:09:18
Good catch. Fixing!
|
+ WriteBlockID = -1; |
+ if (Record.Abbrev != naclbitc::ENTER_SUBBLOCK) { |
+ RecoverableError() |
+ << "Uses illegal abbreviation index in enter block record: " |
+ << Record << "\n"; |
+ if (!Flags.TryToRecover) |
+ return false; |
+ } |
+ if (NumValues == 2) { |
+ WriteBlockID = Record.Values[0]; |
+ NumBits = Record.Values[1]; |
+ if (NumBits > 32 || NumBits < 2) { |
+ RecoverableError() |
+ << "Bit size " << NumBits << " for record should be " |
+ << (NumBits > 32 ? "<= 32" : ">= 2") << ": " << Record << "\n"; |
+ if (!Flags.TryToRecover) |
+ return false; |
+ NumBits = 32; |
+ } |
+ } else { |
+ Error() << "Values for enter record should be of size 2, but found " |
+ << NumValues << ": " << Record << "\n"; |
+ return false; |
+ } |
+ uint64_t MaxAbbrev = (static_cast<uint64_t>(1) << NumBits) - 1; |
+ AbbrevIndexLimitStack.push_back(MaxAbbrev); |
+ if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) { |
+ unsigned DefaultMaxBits = |
+ NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV); |
+ if (NumBits != DefaultMaxBits) { |
+ RecoverableError() |
+ << "Numbits entry for abbreviations record not " |
+ << DefaultMaxBits << " but found " << NumBits << |
+ ": " << Record << "\n"; |
+ if (!Flags.TryToRecover) |
+ return false; |
+ } |
+ Writer.EnterBlockInfoBlock(); |
+ } else { |
+ NaClBitcodeSelectorAbbrev CurCodeLen(MaxAbbrev); |
+ Writer.EnterSubblock(WriteBlockID, CurCodeLen); |
+ } |
+ break; |
+ } |
+ case naclbitc::BLK_CODE_EXIT: |
+ if (Record.Abbrev != naclbitc::END_BLOCK) { |
+ RecoverableError() |
+ << "Uses illegal abbreviation index in exit block record: " |
+ << Record << "\n"; |
+ if (!Flags.TryToRecover) |
+ return false; |
+ } |
+ if (NumValues != 0) { |
+ RecoverableError() << "Exit block should not have values: " |
+ << Record << "\n"; |
+ if (!Flags.TryToRecover) |
+ return false; |
+ } |
+ if (!AbbrevIndexLimitStack.empty()) |
+ AbbrevIndexLimitStack.pop_back(); |
+ Writer.ExitBlock(); |
+ break; |
+ case naclbitc::BLK_CODE_DEFINE_ABBREV: { |
+ if (Record.Abbrev != naclbitc::DEFINE_ABBREV) { |
+ RecoverableError() |
+ << "Uses illegal abbreviation index in define abbreviation record: " |
+ << Record << "\n"; |
+ if (!Flags.TryToRecover) |
+ return false; |
+ } |
+ NaClBitCodeAbbrev *Abbrev = buildAbbrev(Record); |
+ if (Abbrev == NULL) |
+ return Flags.TryToRecover; |
+ if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) { |
+ Writer.EmitBlockInfoAbbrev(SetBID, Abbrev); |
+ } else { |
+ Writer.EmitAbbrev(Abbrev); |
+ } |
+ break; |
+ } |
+ case naclbitc::BLK_CODE_HEADER: |
+ // Note: There is no abbreviation index here. Ignore. |
+ for (uint64_t Value : Record.Values) |
+ Writer.Emit(Value, 8); |
+ break; |
+ default: |
+ bool UsesDefaultAbbrev = Record.Abbrev == naclbitc::UNABBREV_RECORD; |
+ if (!UsesDefaultAbbrev |
+ && !Writer.isUserRecordAbbreviation(Record.Abbrev)) { |
+ uint64_t BlockAbbrevIndexLimit = 0; |
+ if (!AbbrevIndexLimitStack.empty()) |
+ BlockAbbrevIndexLimit = AbbrevIndexLimitStack.back(); |
+ // Can't generate abbreviation ID because not enough bits |
+ // specified in block ID. |
+ raw_ostream &ErrStrm = RecoverableError(); |
+ ErrStrm << "Uses illegal abbreviation index"; |
+ if (Record.Abbrev > BlockAbbrevIndexLimit) |
jvoung (off chromium)
2015/05/06 22:08:09
When does this > check fail? If for some reason th
Karl
2015/05/07 20:09:18
Decided to simplify this code and be more generic.
|
+ ErrStrm << ". Must not exceed " << BlockAbbrevIndexLimit; |
+ ErrStrm << ": " << Record << "\n"; |
+ if (!Flags.TryToRecover && !Flags.SaveBadAbbrevIndices) |
jvoung (off chromium)
2015/05/06 22:08:09
So this code is saying that SaveBadAbbrevIndices w
Karl
2015/05/07 20:09:18
Hopefully the code is now clearer since I simplifi
jvoung (off chromium)
2015/05/07 21:33:56
Thanks -- I like the new version more.
|
+ return false; |
+ if (Flags.SaveBadAbbrevIndices) { |
+ // Note: If this point is reached, the abbreviation is bad and |
+ // RecoverOnBadAbbrevID is true. Generate bad abbreviation index |
jvoung (off chromium)
2015/05/06 22:08:09
there is no RecoverOnBadAbbrevID anymore
You also
Karl
2015/05/07 20:09:18
Again, I simplified this code so that we don't nee
|
+ // so that the bitcode reader can be tested. |
+ Writer.EmitCode(Record.Abbrev); |
+ // Note: We need to close blocks or the bitcode Writer will terminate |
+ // due to assertions. |
+ writeMissingEndBlocks(Writer); |
+ Results.SavedBadAbbrevIndices = true; |
jvoung (off chromium)
2015/05/06 22:08:09
Perhaps "Save..." should be "Write..." ?
In some
Karl
2015/05/07 20:09:18
Hopefully I have clarified that the Save Case (now
|
+ return false; |
+ } |
+ UsesDefaultAbbrev = true; |
+ } |
+ if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID |
+ && Record.Code == naclbitc::BLOCKINFO_CODE_SETBID) { |
+ // Note: SetBID records are handled by Writer->EmitBlockInfoAbbrev, |
+ // based on the SetBID value. Don't bother to generate SetBID record here. |
+ // Rather just set SetBID and let call to Writer->EmitBlockInfoAbbrev |
+ // generate the SetBID record. |
+ if (NumValues != 1) { |
+ Error() << "SetBID record expects 1 value but found " |
+ << NumValues << ": " << Record << "\n"; |
+ return false; |
+ } |
+ SetBID = Record.Values[0]; |
+ return true; |
+ } |
+ if (UsesDefaultAbbrev) |
+ Writer.EmitRecord(Record.Code, Record.Values); |
+ else |
+ Writer.EmitRecord(Record.Code, Record.Values, Record.Abbrev); |
+ } |
+ return true; |
+} |
+ |
+static NaClBitCodeAbbrev *deleteAbbrev(NaClBitCodeAbbrev *Abbrev) { |
+ Abbrev->dropRef(); |
+ return nullptr; |
+} |
+ |
+NaClBitCodeAbbrev *WriteState::buildAbbrev( |
+ const NaClBitcodeAbbrevRecord &Record) { |
+ // Note: Recover by removing abbreviation. |
+ NaClBitCodeAbbrev *Abbrev = new NaClBitCodeAbbrev(); |
+ size_t Index = 0; |
+ size_t NumValues = Record.Values.size(); |
+ if (NumValues == 0) { |
+ RecoverableError() << "Empty abbreviation record not allowed: " |
+ << Record << "\n"; |
+ return deleteAbbrev(Abbrev); |
+ } |
+ size_t NumAbbreviations = Record.Values[Index++]; |
+ if (NumAbbreviations == 0) { |
+ RecoverableError() << "Abbreviation must contain at least one operator: " |
+ << Record << "\n"; |
+ return deleteAbbrev(Abbrev); |
+ } |
+ for (size_t Count = 0; Count < NumAbbreviations; ++Count) { |
+ if (Index >= NumValues) { |
+ RecoverableError() |
+ << "Malformed abbreviation found. Expects " << NumAbbreviations |
+ << " operands but ound " << Count << ": " << Record << "\n"; |
+ return deleteAbbrev(Abbrev); |
+ } |
+ switch (Record.Values[Index++]) { |
+ case 1: |
+ if (Index >= NumValues) { |
+ RecoverableError() << "Malformed literal abbreviation: " |
+ << Record << "\n"; |
+ return deleteAbbrev(Abbrev); |
+ } |
+ Abbrev->Add(NaClBitCodeAbbrevOp(Record.Values[Index++])); |
+ break; |
+ case 0: { |
+ if (Index >= NumValues) { |
+ RecoverableError() << "Malformed abbreviation found: " |
+ << Record << "\n"; |
+ return deleteAbbrev(Abbrev); |
+ } |
+ unsigned Kind = Record.Values[Index++]; |
+ switch (Kind) { |
+ case NaClBitCodeAbbrevOp::Fixed: |
+ if (Index >= NumValues) { |
+ RecoverableError() << "Malformed fixed abbreviation found: " |
+ << Record << "\n"; |
+ return deleteAbbrev(Abbrev); |
+ } |
+ Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, |
+ Record.Values[Index++])); |
+ break; |
+ case NaClBitCodeAbbrevOp::VBR: |
+ if (Index >= NumValues) { |
+ RecoverableError() << "Malformed vbr abbreviation found: " |
+ << Record << "\n"; |
+ return deleteAbbrev(Abbrev); |
+ } |
+ Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, |
+ Record.Values[Index++])); |
+ break; |
+ case NaClBitCodeAbbrevOp::Array: |
+ if (Index >= NumValues) { |
+ RecoverableError() << "Malformed array abbreviation found: " |
+ << Record << "\n"; |
+ return deleteAbbrev(Abbrev); |
+ } |
+ Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array)); |
+ break; |
+ case NaClBitCodeAbbrevOp::Char6: |
+ Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Char6)); |
+ break; |
+ default: |
+ RecoverableError() << "Unknown abbreviation kind " << Kind |
+ << ": " << Record << "\n"; |
+ return deleteAbbrev(Abbrev); |
+ } |
+ break; |
+ } |
+ default: |
+ RecoverableError() << "Error: Bad literal flag " << Record.Values[Index] |
+ << ": " << Record << "\n"; |
+ return deleteAbbrev(Abbrev); |
+ } |
+ } |
+ return Abbrev; |
+} |
+ |
+} // end of anonymous namespace. |
+ |
+NaClMungedBitcode::WriteResults NaClMungedBitcode::writeMaybeRepair( |
+ SmallVectorImpl<char> &Buffer, bool AddHeader, |
+ const WriteFlags &Flags) const { |
+ NaClBitstreamWriter Writer(Buffer); |
+ WriteState State(Flags); |
+ if (AddHeader) { |
+ NaClWriteHeader(Writer, true); |
+ } |
+ for (const NaClBitcodeAbbrevRecord &Record : *this) { |
+ if (!State.emitRecord(Writer, Record)) |
+ break; |
+ } |
+ if (!State.AbbrevIndexLimitStack.empty()) { |
+ State.RecoverableError() |
+ << "Bitcode missing " << State.AbbrevIndexLimitStack.size() |
+ << " close blocks.\n"; |
+ if (Flags.TryToRecover) |
+ State.writeMissingEndBlocks(Writer); |
+ } |
+ return State.Results; |
+} |