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