Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(72)

Side by Side Diff: lib/Bitcode/NaCl/TestUtils/NaClBitcodeMunge.cpp

Issue 1113023005: Add abilities to generate bitcode buffers from munged bitcode. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-llvm.git@master
Patch Set: Fix nits. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 WriteFlags.setErrStream(getDumpStream());
50 NaClMungedBitcode::WriteResults Results =
51 MungedBitcode.writeMaybeRepair(MungedInputBuffer, AddHeader, WriteFlags);
52 if (Results.NumErrors != 0
53 && !(WriteFlags.getTryToRecover()
54 && Results.NumRepairs == Results.NumErrors)
55 && !(WriteFlags.getWriteBadAbbrevIndex()
56 && Results.WroteBadAbbrevIndex && Results.NumErrors == 1))
57 report_fatal_error("Unable to generate bitcode file due to write errors");
57 58
58 // Add null terminator, so that we meet the requirements of the 59 // Add null terminator, so that we meet the requirements of the
59 // MemoryBuffer API. 60 // MemoryBuffer API.
60 MungedInputBuffer.push_back('\0'); 61 MungedInputBuffer.push_back('\0');
61 62
62 MungedInput = MemoryBuffer::getMemBuffer( 63 MungedInput = MemoryBuffer::getMemBuffer(
63 StringRef(MungedInputBuffer.data(), MungedInputBuffer.size()-1), 64 StringRef(MungedInputBuffer.data(), MungedInputBuffer.size()-1),
64 TestName); 65 TestName);
65 } 66 }
66 67
67 void NaClBitcodeMunger::cleanupTest() { 68 void NaClBitcodeMunger::cleanupTest() {
69 RunAsDeathTest = false;
70 WriteFlags.reset();
68 MungedBitcode.removeEdits(); 71 MungedBitcode.removeEdits();
69 MungedInput.reset(); 72 MungedInput.reset();
70 assert(DumpStream && "Dump stream removed before cleanup!"); 73 assert(DumpStream && "Dump stream removed before cleanup!");
71 DumpStream->flush(); 74 DumpStream->flush();
72 delete DumpStream; 75 delete DumpStream;
73 DumpStream = nullptr; 76 DumpStream = nullptr;
74 Writer = nullptr;
75 } 77 }
76 78
77 // Return the next line of input (including eoln), starting from 79 // Return the next line of input (including eoln), starting from
78 // Pos. Then increment Pos past the end of that line. 80 // Pos. Then increment Pos past the end of that line.
79 static std::string getLine(const std::string &Input, size_t &Pos) { 81 static std::string getLine(const std::string &Input, size_t &Pos) {
80 std::string Line; 82 std::string Line;
81 if (Pos >= Input.size()) { 83 if (Pos >= Input.size()) {
82 Pos = std::string::npos; 84 Pos = std::string::npos;
83 return Line; 85 return Line;
84 } 86 }
(...skipping 16 matching lines...) Expand all
101 std::string Line = getLine(DumpResults, LastLinePos); 103 std::string Line = getLine(DumpResults, LastLinePos);
102 if (LastLinePos == std::string::npos) break; 104 if (LastLinePos == std::string::npos) break;
103 size_t Pos = Line.find(Substring); 105 size_t Pos = Line.find(Substring);
104 if (Pos != std::string::npos && (!MustBePrefix || Pos == 0)) { 106 if (Pos != std::string::npos && (!MustBePrefix || Pos == 0)) {
105 Messages.append(Line); 107 Messages.append(Line);
106 } 108 }
107 } 109 }
108 return Messages; 110 return Messages;
109 } 111 }
110 112
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( 113 bool NaClObjDumpMunger::runTestWithFlags(
325 const char *Name, const uint64_t Munges[], size_t MungesSize, 114 const char *Name, const uint64_t Munges[], size_t MungesSize,
326 bool AddHeader, bool NoRecords, bool NoAssembly) { 115 bool AddHeader, bool NoRecords, bool NoAssembly) {
327 setupTest(Name, Munges, MungesSize, AddHeader); 116 setupTest(Name, Munges, MungesSize, AddHeader);
328 117
329 /// If running in death mode, redirect output directly to the
330 /// error stream (rather than buffering in DumpStream), so that
331 /// output can be seen in gtest death test.
332 raw_ostream &Output = RunAsDeathTest ? errs() : *DumpStream;
333 if (NaClObjDump(MungedInput.get()->getMemBufferRef(), 118 if (NaClObjDump(MungedInput.get()->getMemBufferRef(),
334 Output, NoRecords, NoAssembly)) 119 getDumpStream(), NoRecords, NoAssembly))
335 FoundErrors = true; 120 FoundErrors = true;
336 cleanupTest(); 121 cleanupTest();
337 return !FoundErrors; 122 return !FoundErrors;
338 } 123 }
339 124
340 bool NaClParseBitcodeMunger::runTest( 125 bool NaClParseBitcodeMunger::runTest(
341 const char *Name, const uint64_t Munges[], size_t MungesSize, 126 const char *Name, const uint64_t Munges[], size_t MungesSize,
342 bool VerboseErrors) { 127 bool VerboseErrors) {
343 bool AddHeader = true; 128 bool AddHeader = true;
344 setupTest(Name, Munges, MungesSize, AddHeader); 129 setupTest(Name, Munges, MungesSize, AddHeader);
345 LLVMContext &Context = getGlobalContext(); 130 LLVMContext &Context = getGlobalContext();
346 raw_ostream *VerboseStrm = VerboseErrors ? DumpStream : nullptr; 131 raw_ostream *VerboseStrm = VerboseErrors ? &getDumpStream() : nullptr;
347 ErrorOr<Module *> ModuleOrError = 132 ErrorOr<Module *> ModuleOrError =
348 NaClParseBitcodeFile(MungedInput->getMemBufferRef(), Context, 133 NaClParseBitcodeFile(MungedInput->getMemBufferRef(), Context,
349 VerboseStrm); 134 VerboseStrm);
350 if (ModuleOrError) { 135 if (ModuleOrError) {
351 if (VerboseErrors) 136 if (VerboseErrors)
352 *DumpStream << "Successful parse!\n"; 137 getDumpStream() << "Successful parse!\n";
353 delete ModuleOrError.get(); 138 delete ModuleOrError.get();
354 } else { 139 } else {
355 Error() << ModuleOrError.getError().message() << "\n"; 140 Error() << ModuleOrError.getError().message() << "\n";
356 } 141 }
357 cleanupTest(); 142 cleanupTest();
358 return !FoundErrors; 143 return !FoundErrors;
359 } 144 }
360 145
361 bool NaClCompressMunger::runTest(const char* Name, const uint64_t Munges[], 146 bool NaClCompressMunger::runTest(const char* Name, const uint64_t Munges[],
362 size_t MungesSize) { 147 size_t MungesSize) {
363 bool AddHeader = true; 148 bool AddHeader = true;
364 setupTest(Name, Munges, MungesSize, AddHeader); 149 setupTest(Name, Munges, MungesSize, AddHeader);
365 NaClBitcodeCompressor Compressor; 150 NaClBitcodeCompressor Compressor;
366 bool Result = Compressor.compress(MungedInput.get(), *DumpStream); 151 bool Result = Compressor.compress(MungedInput.get(), getDumpStream());
367 cleanupTest(); 152 cleanupTest();
368 return Result; 153 return Result;
369 } 154 }
OLDNEW
« no previous file with comments | « lib/Bitcode/NaCl/TestUtils/CMakeLists.txt ('k') | lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeReader.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698