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 |