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