• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- ExecutionDriver.cpp - Allow execution of LLVM program --------------===//
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 // This file contains code used to execute the program utilizing one of the
11 // various ways of running LLVM bitcode.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "BugDriver.h"
16 #include "ToolRunner.h"
17 #include "llvm/Support/CommandLine.h"
18 #include "llvm/Support/Debug.h"
19 #include "llvm/Support/FileUtilities.h"
20 #include "llvm/Support/Program.h"
21 #include "llvm/Support/SystemUtils.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include <fstream>
24 
25 using namespace llvm;
26 
27 namespace {
28   // OutputType - Allow the user to specify the way code should be run, to test
29   // for miscompilation.
30   //
31   enum OutputType {
32     AutoPick, RunLLI, RunJIT, RunLLC, RunLLCIA, LLC_Safe, CompileCustom, Custom
33   };
34 
35   cl::opt<double>
36   AbsTolerance("abs-tolerance", cl::desc("Absolute error tolerated"),
37                cl::init(0.0));
38   cl::opt<double>
39   RelTolerance("rel-tolerance", cl::desc("Relative error tolerated"),
40                cl::init(0.0));
41 
42   cl::opt<OutputType>
43   InterpreterSel(cl::desc("Specify the \"test\" i.e. suspect back-end:"),
44                  cl::values(clEnumValN(AutoPick, "auto", "Use best guess"),
45                             clEnumValN(RunLLI, "run-int",
46                                        "Execute with the interpreter"),
47                             clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
48                             clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
49                             clEnumValN(RunLLCIA, "run-llc-ia",
50                                   "Compile with LLC with integrated assembler"),
51                             clEnumValN(LLC_Safe, "llc-safe", "Use LLC for all"),
52                             clEnumValN(CompileCustom, "compile-custom",
53                             "Use -compile-command to define a command to "
54                             "compile the bitcode. Useful to avoid linking."),
55                             clEnumValN(Custom, "run-custom",
56                             "Use -exec-command to define a command to execute "
57                             "the bitcode. Useful for cross-compilation."),
58                             clEnumValEnd),
59                  cl::init(AutoPick));
60 
61   cl::opt<OutputType>
62   SafeInterpreterSel(cl::desc("Specify \"safe\" i.e. known-good backend:"),
63               cl::values(clEnumValN(AutoPick, "safe-auto", "Use best guess"),
64                          clEnumValN(RunLLC, "safe-run-llc", "Compile with LLC"),
65                          clEnumValN(Custom, "safe-run-custom",
66                          "Use -exec-command to define a command to execute "
67                          "the bitcode. Useful for cross-compilation."),
68                          clEnumValEnd),
69                      cl::init(AutoPick));
70 
71   cl::opt<std::string>
72   SafeInterpreterPath("safe-path",
73                    cl::desc("Specify the path to the \"safe\" backend program"),
74                    cl::init(""));
75 
76   cl::opt<bool>
77   AppendProgramExitCode("append-exit-code",
78       cl::desc("Append the exit code to the output so it gets diff'd too"),
79       cl::init(false));
80 
81   cl::opt<std::string>
82   InputFile("input", cl::init("/dev/null"),
83             cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
84 
85   cl::list<std::string>
86   AdditionalSOs("additional-so",
87                 cl::desc("Additional shared objects to load "
88                          "into executing programs"));
89 
90   cl::list<std::string>
91   AdditionalLinkerArgs("Xlinker",
92       cl::desc("Additional arguments to pass to the linker"));
93 
94   cl::opt<std::string>
95   CustomCompileCommand("compile-command", cl::init("llc"),
96       cl::desc("Command to compile the bitcode (use with -compile-custom) "
97                "(default: llc)"));
98 
99   cl::opt<std::string>
100   CustomExecCommand("exec-command", cl::init("simulate"),
101       cl::desc("Command to execute the bitcode (use with -run-custom) "
102                "(default: simulate)"));
103 }
104 
105 namespace llvm {
106   // Anything specified after the --args option are taken as arguments to the
107   // program being debugged.
108   cl::list<std::string>
109   InputArgv("args", cl::Positional, cl::desc("<program arguments>..."),
110             cl::ZeroOrMore, cl::PositionalEatsArgs);
111 
112   cl::opt<std::string>
113   OutputPrefix("output-prefix", cl::init("bugpoint"),
114             cl::desc("Prefix to use for outputs (default: 'bugpoint')"));
115 }
116 
117 namespace {
118   cl::list<std::string>
119   ToolArgv("tool-args", cl::Positional, cl::desc("<tool arguments>..."),
120            cl::ZeroOrMore, cl::PositionalEatsArgs);
121 
122   cl::list<std::string>
123   SafeToolArgv("safe-tool-args", cl::Positional,
124                cl::desc("<safe-tool arguments>..."),
125                cl::ZeroOrMore, cl::PositionalEatsArgs);
126 
127   cl::opt<std::string>
128   CCBinary("gcc", cl::init(""), cl::desc("The gcc binary to use."));
129 
130   cl::list<std::string>
131   CCToolArgv("gcc-tool-args", cl::Positional,
132               cl::desc("<gcc-tool arguments>..."),
133               cl::ZeroOrMore, cl::PositionalEatsArgs);
134 }
135 
136 //===----------------------------------------------------------------------===//
137 // BugDriver method implementation
138 //
139 
140 /// initializeExecutionEnvironment - This method is used to set up the
141 /// environment for executing LLVM programs.
142 ///
initializeExecutionEnvironment()143 bool BugDriver::initializeExecutionEnvironment() {
144   outs() << "Initializing execution environment: ";
145 
146   // Create an instance of the AbstractInterpreter interface as specified on
147   // the command line
148   SafeInterpreter = nullptr;
149   std::string Message;
150 
151   if (CCBinary.empty()) {
152     if (sys::findProgramByName("clang"))
153       CCBinary = "clang";
154     else
155       CCBinary = "gcc";
156   }
157 
158   switch (InterpreterSel) {
159   case AutoPick:
160     if (!Interpreter) {
161       InterpreterSel = RunJIT;
162       Interpreter = AbstractInterpreter::createJIT(getToolName(), Message,
163                                                    &ToolArgv);
164     }
165     if (!Interpreter) {
166       InterpreterSel = RunLLC;
167       Interpreter = AbstractInterpreter::createLLC(getToolName(), Message,
168                                                    CCBinary, &ToolArgv,
169                                                    &CCToolArgv);
170     }
171     if (!Interpreter) {
172       InterpreterSel = RunLLI;
173       Interpreter = AbstractInterpreter::createLLI(getToolName(), Message,
174                                                    &ToolArgv);
175     }
176     if (!Interpreter) {
177       InterpreterSel = AutoPick;
178       Message = "Sorry, I can't automatically select an interpreter!\n";
179     }
180     break;
181   case RunLLI:
182     Interpreter = AbstractInterpreter::createLLI(getToolName(), Message,
183                                                  &ToolArgv);
184     break;
185   case RunLLC:
186   case RunLLCIA:
187   case LLC_Safe:
188     Interpreter = AbstractInterpreter::createLLC(getToolName(), Message,
189                                                  CCBinary, &ToolArgv,
190                                                  &CCToolArgv,
191                                                  InterpreterSel == RunLLCIA);
192     break;
193   case RunJIT:
194     Interpreter = AbstractInterpreter::createJIT(getToolName(), Message,
195                                                  &ToolArgv);
196     break;
197   case CompileCustom:
198     Interpreter =
199       AbstractInterpreter::createCustomCompiler(Message, CustomCompileCommand);
200     break;
201   case Custom:
202     Interpreter =
203       AbstractInterpreter::createCustomExecutor(Message, CustomExecCommand);
204     break;
205   }
206   if (!Interpreter)
207     errs() << Message;
208   else // Display informational messages on stdout instead of stderr
209     outs() << Message;
210 
211   std::string Path = SafeInterpreterPath;
212   if (Path.empty())
213     Path = getToolName();
214   std::vector<std::string> SafeToolArgs = SafeToolArgv;
215   switch (SafeInterpreterSel) {
216   case AutoPick:
217     // In "llc-safe" mode, default to using LLC as the "safe" backend.
218     if (!SafeInterpreter &&
219         InterpreterSel == LLC_Safe) {
220       SafeInterpreterSel = RunLLC;
221       SafeToolArgs.push_back("--relocation-model=pic");
222       SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message,
223                                                        CCBinary,
224                                                        &SafeToolArgs,
225                                                        &CCToolArgv);
226     }
227 
228     if (!SafeInterpreter &&
229         InterpreterSel != RunLLC &&
230         InterpreterSel != RunJIT) {
231       SafeInterpreterSel = RunLLC;
232       SafeToolArgs.push_back("--relocation-model=pic");
233       SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message,
234                                                        CCBinary,
235                                                        &SafeToolArgs,
236                                                        &CCToolArgv);
237     }
238     if (!SafeInterpreter) {
239       SafeInterpreterSel = AutoPick;
240       Message = "Sorry, I can't automatically select a safe interpreter!\n";
241     }
242     break;
243   case RunLLC:
244   case RunLLCIA:
245     SafeToolArgs.push_back("--relocation-model=pic");
246     SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message,
247                                                      CCBinary, &SafeToolArgs,
248                                                      &CCToolArgv,
249                                                 SafeInterpreterSel == RunLLCIA);
250     break;
251   case Custom:
252     SafeInterpreter =
253       AbstractInterpreter::createCustomExecutor(Message, CustomExecCommand);
254     break;
255   default:
256     Message = "Sorry, this back-end is not supported by bugpoint as the "
257               "\"safe\" backend right now!\n";
258     break;
259   }
260   if (!SafeInterpreter) { outs() << Message << "\nExiting.\n"; exit(1); }
261 
262   cc = CC::create(Message, CCBinary, &CCToolArgv);
263   if (!cc) { outs() << Message << "\nExiting.\n"; exit(1); }
264 
265   // If there was an error creating the selected interpreter, quit with error.
266   return Interpreter == nullptr;
267 }
268 
269 /// compileProgram - Try to compile the specified module, returning false and
270 /// setting Error if an error occurs.  This is used for code generation
271 /// crash testing.
272 ///
compileProgram(Module * M,std::string * Error) const273 void BugDriver::compileProgram(Module *M, std::string *Error) const {
274   // Emit the program to a bitcode file...
275   SmallString<128> BitcodeFile;
276   int BitcodeFD;
277   std::error_code EC = sys::fs::createUniqueFile(
278       OutputPrefix + "-test-program-%%%%%%%.bc", BitcodeFD, BitcodeFile);
279   if (EC) {
280     errs() << ToolName << ": Error making unique filename: " << EC.message()
281            << "\n";
282     exit(1);
283   }
284   if (writeProgramToFile(BitcodeFile.str(), BitcodeFD, M)) {
285     errs() << ToolName << ": Error emitting bitcode to file '" << BitcodeFile
286            << "'!\n";
287     exit(1);
288   }
289 
290   // Remove the temporary bitcode file when we are done.
291   FileRemover BitcodeFileRemover(BitcodeFile.str(), !SaveTemps);
292 
293   // Actually compile the program!
294   Interpreter->compileProgram(BitcodeFile.str(), Error, Timeout, MemoryLimit);
295 }
296 
297 
298 /// executeProgram - This method runs "Program", capturing the output of the
299 /// program to a file, returning the filename of the file.  A recommended
300 /// filename may be optionally specified.
301 ///
executeProgram(const Module * Program,std::string OutputFile,std::string BitcodeFile,const std::string & SharedObj,AbstractInterpreter * AI,std::string * Error) const302 std::string BugDriver::executeProgram(const Module *Program,
303                                       std::string OutputFile,
304                                       std::string BitcodeFile,
305                                       const std::string &SharedObj,
306                                       AbstractInterpreter *AI,
307                                       std::string *Error) const {
308   if (!AI) AI = Interpreter;
309   assert(AI && "Interpreter should have been created already!");
310   bool CreatedBitcode = false;
311   if (BitcodeFile.empty()) {
312     // Emit the program to a bitcode file...
313     SmallString<128> UniqueFilename;
314     int UniqueFD;
315     std::error_code EC = sys::fs::createUniqueFile(
316         OutputPrefix + "-test-program-%%%%%%%.bc", UniqueFD, UniqueFilename);
317     if (EC) {
318       errs() << ToolName << ": Error making unique filename: "
319              << EC.message() << "!\n";
320       exit(1);
321     }
322     BitcodeFile = UniqueFilename.str();
323 
324     if (writeProgramToFile(BitcodeFile, UniqueFD, Program)) {
325       errs() << ToolName << ": Error emitting bitcode to file '"
326              << BitcodeFile << "'!\n";
327       exit(1);
328     }
329     CreatedBitcode = true;
330   }
331 
332   // Remove the temporary bitcode file when we are done.
333   std::string BitcodePath(BitcodeFile);
334   FileRemover BitcodeFileRemover(BitcodePath,
335     CreatedBitcode && !SaveTemps);
336 
337   if (OutputFile.empty()) OutputFile = OutputPrefix + "-execution-output-%%%%%%%";
338 
339   // Check to see if this is a valid output filename...
340   SmallString<128> UniqueFile;
341   std::error_code EC = sys::fs::createUniqueFile(OutputFile, UniqueFile);
342   if (EC) {
343     errs() << ToolName << ": Error making unique filename: "
344            << EC.message() << "\n";
345     exit(1);
346   }
347   OutputFile = UniqueFile.str();
348 
349   // Figure out which shared objects to run, if any.
350   std::vector<std::string> SharedObjs(AdditionalSOs);
351   if (!SharedObj.empty())
352     SharedObjs.push_back(SharedObj);
353 
354   int RetVal = AI->ExecuteProgram(BitcodeFile, InputArgv, InputFile, OutputFile,
355                                   Error, AdditionalLinkerArgs, SharedObjs,
356                                   Timeout, MemoryLimit);
357   if (!Error->empty())
358     return OutputFile;
359 
360   if (RetVal == -1) {
361     errs() << "<timeout>";
362     static bool FirstTimeout = true;
363     if (FirstTimeout) {
364       outs() << "\n"
365  "*** Program execution timed out!  This mechanism is designed to handle\n"
366  "    programs stuck in infinite loops gracefully.  The -timeout option\n"
367  "    can be used to change the timeout threshold or disable it completely\n"
368  "    (with -timeout=0).  This message is only displayed once.\n";
369       FirstTimeout = false;
370     }
371   }
372 
373   if (AppendProgramExitCode) {
374     std::ofstream outFile(OutputFile.c_str(), std::ios_base::app);
375     outFile << "exit " << RetVal << '\n';
376     outFile.close();
377   }
378 
379   // Return the filename we captured the output to.
380   return OutputFile;
381 }
382 
383 /// executeProgramSafely - Used to create reference output with the "safe"
384 /// backend, if reference output is not provided.
385 ///
executeProgramSafely(const Module * Program,const std::string & OutputFile,std::string * Error) const386 std::string BugDriver::executeProgramSafely(const Module *Program,
387                                             const std::string &OutputFile,
388                                             std::string *Error) const {
389   return executeProgram(Program, OutputFile, "", "", SafeInterpreter, Error);
390 }
391 
compileSharedObject(const std::string & BitcodeFile,std::string & Error)392 std::string BugDriver::compileSharedObject(const std::string &BitcodeFile,
393                                            std::string &Error) {
394   assert(Interpreter && "Interpreter should have been created already!");
395   std::string OutputFile;
396 
397   // Using the known-good backend.
398   CC::FileType FT = SafeInterpreter->OutputCode(BitcodeFile, OutputFile,
399                                                  Error);
400   if (!Error.empty())
401     return "";
402 
403   std::string SharedObjectFile;
404   bool Failure = cc->MakeSharedObject(OutputFile, FT, SharedObjectFile,
405                                        AdditionalLinkerArgs, Error);
406   if (!Error.empty())
407     return "";
408   if (Failure)
409     exit(1);
410 
411   // Remove the intermediate C file
412   sys::fs::remove(OutputFile);
413 
414   return SharedObjectFile;
415 }
416 
417 /// createReferenceFile - calls compileProgram and then records the output
418 /// into ReferenceOutputFile. Returns true if reference file created, false
419 /// otherwise. Note: initializeExecutionEnvironment should be called BEFORE
420 /// this function.
421 ///
createReferenceFile(Module * M,const std::string & Filename)422 bool BugDriver::createReferenceFile(Module *M, const std::string &Filename) {
423   std::string Error;
424   compileProgram(Program, &Error);
425   if (!Error.empty())
426     return false;
427 
428   ReferenceOutputFile = executeProgramSafely(Program, Filename, &Error);
429   if (!Error.empty()) {
430     errs() << Error;
431     if (Interpreter != SafeInterpreter) {
432       errs() << "*** There is a bug running the \"safe\" backend.  Either"
433              << " debug it (for example with the -run-jit bugpoint option,"
434              << " if JIT is being used as the \"safe\" backend), or fix the"
435              << " error some other way.\n";
436     }
437     return false;
438   }
439   outs() << "\nReference output is: " << ReferenceOutputFile << "\n\n";
440   return true;
441 }
442 
443 /// diffProgram - This method executes the specified module and diffs the
444 /// output against the file specified by ReferenceOutputFile.  If the output
445 /// is different, 1 is returned.  If there is a problem with the code
446 /// generator (e.g., llc crashes), this will set ErrMsg.
447 ///
diffProgram(const Module * Program,const std::string & BitcodeFile,const std::string & SharedObject,bool RemoveBitcode,std::string * ErrMsg) const448 bool BugDriver::diffProgram(const Module *Program,
449                             const std::string &BitcodeFile,
450                             const std::string &SharedObject,
451                             bool RemoveBitcode,
452                             std::string *ErrMsg) const {
453   // Execute the program, generating an output file...
454   std::string Output(
455       executeProgram(Program, "", BitcodeFile, SharedObject, nullptr, ErrMsg));
456   if (!ErrMsg->empty())
457     return false;
458 
459   std::string Error;
460   bool FilesDifferent = false;
461   if (int Diff = DiffFilesWithTolerance(ReferenceOutputFile,
462                                         Output,
463                                         AbsTolerance, RelTolerance, &Error)) {
464     if (Diff == 2) {
465       errs() << "While diffing output: " << Error << '\n';
466       exit(1);
467     }
468     FilesDifferent = true;
469   }
470   else {
471     // Remove the generated output if there are no differences.
472     sys::fs::remove(Output);
473   }
474 
475   // Remove the bitcode file if we are supposed to.
476   if (RemoveBitcode)
477     sys::fs::remove(BitcodeFile);
478   return FilesDifferent;
479 }
480 
isExecutingJIT()481 bool BugDriver::isExecutingJIT() {
482   return InterpreterSel == RunJIT;
483 }
484 
485