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