1 //===-- ToolRunner.cpp ----------------------------------------------------===// 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 implements the interfaces described in the ToolRunner.h file. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "ToolRunner.h" 14 #include "llvm/Config/config.h" 15 #include "llvm/Support/CommandLine.h" 16 #include "llvm/Support/Debug.h" 17 #include "llvm/Support/FileSystem.h" 18 #include "llvm/Support/FileUtilities.h" 19 #include "llvm/Support/Program.h" 20 #include "llvm/Support/raw_ostream.h" 21 #include <fstream> 22 #include <sstream> 23 #include <utility> 24 using namespace llvm; 25 26 #define DEBUG_TYPE "toolrunner" 27 28 namespace llvm { 29 cl::opt<bool> SaveTemps("save-temps", cl::init(false), 30 cl::desc("Save temporary files")); 31 } 32 33 namespace { 34 cl::opt<std::string> 35 RemoteClient("remote-client", 36 cl::desc("Remote execution client (rsh/ssh)")); 37 38 cl::opt<std::string> RemoteHost("remote-host", 39 cl::desc("Remote execution (rsh/ssh) host")); 40 41 cl::opt<std::string> RemotePort("remote-port", 42 cl::desc("Remote execution (rsh/ssh) port")); 43 44 cl::opt<std::string> RemoteUser("remote-user", 45 cl::desc("Remote execution (rsh/ssh) user id")); 46 47 cl::opt<std::string> 48 RemoteExtra("remote-extra-options", 49 cl::desc("Remote execution (rsh/ssh) extra options")); 50 } 51 52 /// RunProgramWithTimeout - This function provides an alternate interface 53 /// to the sys::Program::ExecuteAndWait interface. 54 /// @see sys::Program::ExecuteAndWait 55 static int RunProgramWithTimeout(StringRef ProgramPath, 56 ArrayRef<StringRef> Args, StringRef StdInFile, 57 StringRef StdOutFile, StringRef StdErrFile, 58 unsigned NumSeconds = 0, 59 unsigned MemoryLimit = 0, 60 std::string *ErrMsg = nullptr) { 61 std::optional<StringRef> Redirects[3] = {StdInFile, StdOutFile, StdErrFile}; 62 return sys::ExecuteAndWait(ProgramPath, Args, std::nullopt, Redirects, 63 NumSeconds, MemoryLimit, ErrMsg); 64 } 65 66 /// RunProgramRemotelyWithTimeout - This function runs the given program 67 /// remotely using the given remote client and the sys::Program::ExecuteAndWait. 68 /// Returns the remote program exit code or reports a remote client error if it 69 /// fails. Remote client is required to return 255 if it failed or program exit 70 /// code otherwise. 71 /// @see sys::Program::ExecuteAndWait 72 static int RunProgramRemotelyWithTimeout( 73 StringRef RemoteClientPath, ArrayRef<StringRef> Args, StringRef StdInFile, 74 StringRef StdOutFile, StringRef StdErrFile, unsigned NumSeconds = 0, 75 unsigned MemoryLimit = 0) { 76 std::optional<StringRef> Redirects[3] = {StdInFile, StdOutFile, StdErrFile}; 77 78 // Run the program remotely with the remote client 79 int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, std::nullopt, 80 Redirects, NumSeconds, MemoryLimit); 81 82 // Has the remote client fail? 83 if (255 == ReturnCode) { 84 std::ostringstream OS; 85 OS << "\nError running remote client:\n "; 86 for (StringRef Arg : Args) 87 OS << " " << Arg.str(); 88 OS << "\n"; 89 90 // The error message is in the output file, let's print it out from there. 91 std::string StdOutFileName = StdOutFile.str(); 92 std::ifstream ErrorFile(StdOutFileName.c_str()); 93 if (ErrorFile) { 94 std::copy(std::istreambuf_iterator<char>(ErrorFile), 95 std::istreambuf_iterator<char>(), 96 std::ostreambuf_iterator<char>(OS)); 97 ErrorFile.close(); 98 } 99 100 errs() << OS.str(); 101 } 102 103 return ReturnCode; 104 } 105 106 static Error ProcessFailure(StringRef ProgPath, ArrayRef<StringRef> Args, 107 unsigned Timeout = 0, unsigned MemoryLimit = 0) { 108 std::ostringstream OS; 109 OS << "\nError running tool:\n "; 110 for (StringRef Arg : Args) 111 OS << " " << Arg.str(); 112 OS << "\n"; 113 114 // Rerun the compiler, capturing any error messages to print them. 115 SmallString<128> ErrorFilename; 116 std::error_code EC = sys::fs::createTemporaryFile( 117 "bugpoint.program_error_messages", "", ErrorFilename); 118 if (EC) { 119 errs() << "Error making unique filename: " << EC.message() << "\n"; 120 exit(1); 121 } 122 123 RunProgramWithTimeout(ProgPath, Args, "", ErrorFilename.str(), 124 ErrorFilename.str(), Timeout, MemoryLimit); 125 // FIXME: check return code ? 126 127 // Print out the error messages generated by CC if possible... 128 std::ifstream ErrorFile(ErrorFilename.c_str()); 129 if (ErrorFile) { 130 std::copy(std::istreambuf_iterator<char>(ErrorFile), 131 std::istreambuf_iterator<char>(), 132 std::ostreambuf_iterator<char>(OS)); 133 ErrorFile.close(); 134 } 135 136 sys::fs::remove(ErrorFilename.c_str()); 137 return make_error<StringError>(OS.str(), inconvertibleErrorCode()); 138 } 139 140 //===---------------------------------------------------------------------===// 141 // LLI Implementation of AbstractIntepreter interface 142 // 143 namespace { 144 class LLI : public AbstractInterpreter { 145 std::string LLIPath; // The path to the LLI executable 146 std::vector<std::string> ToolArgs; // Args to pass to LLI 147 public: 148 LLI(const std::string &Path, const std::vector<std::string> *Args) 149 : LLIPath(Path) { 150 ToolArgs.clear(); 151 if (Args) { 152 ToolArgs = *Args; 153 } 154 } 155 156 Expected<int> ExecuteProgram( 157 const std::string &Bitcode, const std::vector<std::string> &Args, 158 const std::string &InputFile, const std::string &OutputFile, 159 const std::vector<std::string> &CCArgs, 160 const std::vector<std::string> &SharedLibs = std::vector<std::string>(), 161 unsigned Timeout = 0, unsigned MemoryLimit = 0) override; 162 }; 163 } 164 165 Expected<int> LLI::ExecuteProgram(const std::string &Bitcode, 166 const std::vector<std::string> &Args, 167 const std::string &InputFile, 168 const std::string &OutputFile, 169 const std::vector<std::string> &CCArgs, 170 const std::vector<std::string> &SharedLibs, 171 unsigned Timeout, unsigned MemoryLimit) { 172 std::vector<StringRef> LLIArgs; 173 LLIArgs.push_back(LLIPath); 174 LLIArgs.push_back("-force-interpreter=true"); 175 176 for (std::vector<std::string>::const_iterator i = SharedLibs.begin(), 177 e = SharedLibs.end(); 178 i != e; ++i) { 179 LLIArgs.push_back("-load"); 180 LLIArgs.push_back(*i); 181 } 182 183 // Add any extra LLI args. 184 for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) 185 LLIArgs.push_back(ToolArgs[i]); 186 187 LLIArgs.push_back(Bitcode); 188 // Add optional parameters to the running program from Argv 189 for (unsigned i = 0, e = Args.size(); i != e; ++i) 190 LLIArgs.push_back(Args[i]); 191 192 outs() << "<lli>"; 193 outs().flush(); 194 LLVM_DEBUG(errs() << "\nAbout to run:\t"; 195 for (unsigned i = 0, e = LLIArgs.size(); i != e; ++i) errs() 196 << " " << LLIArgs[i]; 197 errs() << "\n";); 198 return RunProgramWithTimeout(LLIPath, LLIArgs, InputFile, OutputFile, 199 OutputFile, Timeout, MemoryLimit); 200 } 201 202 void AbstractInterpreter::anchor() {} 203 204 ErrorOr<std::string> llvm::FindProgramByName(const std::string &ExeName, 205 const char *Argv0, 206 void *MainAddr) { 207 // Check the directory that the calling program is in. We can do 208 // this if ProgramPath contains at least one / character, indicating that it 209 // is a relative path to the executable itself. 210 std::string Main = sys::fs::getMainExecutable(Argv0, MainAddr); 211 StringRef Result = sys::path::parent_path(Main); 212 if (ErrorOr<std::string> Path = sys::findProgramByName(ExeName, Result)) 213 return *Path; 214 215 // Check the user PATH. 216 return sys::findProgramByName(ExeName); 217 } 218 219 // LLI create method - Try to find the LLI executable 220 AbstractInterpreter * 221 AbstractInterpreter::createLLI(const char *Argv0, std::string &Message, 222 const std::vector<std::string> *ToolArgs) { 223 if (ErrorOr<std::string> LLIPath = 224 FindProgramByName("lli", Argv0, (void *)(intptr_t)&createLLI)) { 225 Message = "Found lli: " + *LLIPath + "\n"; 226 return new LLI(*LLIPath, ToolArgs); 227 } else { 228 Message = LLIPath.getError().message() + "\n"; 229 return nullptr; 230 } 231 } 232 233 //===---------------------------------------------------------------------===// 234 // Custom compiler command implementation of AbstractIntepreter interface 235 // 236 // Allows using a custom command for compiling the bitcode, thus allows, for 237 // example, to compile a bitcode fragment without linking or executing, then 238 // using a custom wrapper script to check for compiler errors. 239 namespace { 240 class CustomCompiler : public AbstractInterpreter { 241 std::string CompilerCommand; 242 std::vector<std::string> CompilerArgs; 243 244 public: 245 CustomCompiler(const std::string &CompilerCmd, 246 std::vector<std::string> CompArgs) 247 : CompilerCommand(CompilerCmd), CompilerArgs(std::move(CompArgs)) {} 248 249 Error compileProgram(const std::string &Bitcode, unsigned Timeout = 0, 250 unsigned MemoryLimit = 0) override; 251 252 Expected<int> ExecuteProgram( 253 const std::string &Bitcode, const std::vector<std::string> &Args, 254 const std::string &InputFile, const std::string &OutputFile, 255 const std::vector<std::string> &CCArgs = std::vector<std::string>(), 256 const std::vector<std::string> &SharedLibs = std::vector<std::string>(), 257 unsigned Timeout = 0, unsigned MemoryLimit = 0) override { 258 return make_error<StringError>( 259 "Execution not supported with -compile-custom", 260 inconvertibleErrorCode()); 261 } 262 }; 263 } 264 265 Error CustomCompiler::compileProgram(const std::string &Bitcode, 266 unsigned Timeout, unsigned MemoryLimit) { 267 268 std::vector<StringRef> ProgramArgs; 269 ProgramArgs.push_back(CompilerCommand); 270 271 for (const auto &Arg : CompilerArgs) 272 ProgramArgs.push_back(Arg); 273 ProgramArgs.push_back(Bitcode); 274 275 // Add optional parameters to the running program from Argv 276 for (const auto &Arg : CompilerArgs) 277 ProgramArgs.push_back(Arg); 278 279 if (RunProgramWithTimeout(CompilerCommand, ProgramArgs, "", "", "", Timeout, 280 MemoryLimit)) 281 return ProcessFailure(CompilerCommand, ProgramArgs, Timeout, MemoryLimit); 282 return Error::success(); 283 } 284 285 //===---------------------------------------------------------------------===// 286 // Custom execution command implementation of AbstractIntepreter interface 287 // 288 // Allows using a custom command for executing the bitcode, thus allows, 289 // for example, to invoke a cross compiler for code generation followed by 290 // a simulator that executes the generated binary. 291 namespace { 292 class CustomExecutor : public AbstractInterpreter { 293 std::string ExecutionCommand; 294 std::vector<std::string> ExecutorArgs; 295 296 public: 297 CustomExecutor(const std::string &ExecutionCmd, 298 std::vector<std::string> ExecArgs) 299 : ExecutionCommand(ExecutionCmd), ExecutorArgs(std::move(ExecArgs)) {} 300 301 Expected<int> ExecuteProgram( 302 const std::string &Bitcode, const std::vector<std::string> &Args, 303 const std::string &InputFile, const std::string &OutputFile, 304 const std::vector<std::string> &CCArgs, 305 const std::vector<std::string> &SharedLibs = std::vector<std::string>(), 306 unsigned Timeout = 0, unsigned MemoryLimit = 0) override; 307 }; 308 } 309 310 Expected<int> CustomExecutor::ExecuteProgram( 311 const std::string &Bitcode, const std::vector<std::string> &Args, 312 const std::string &InputFile, const std::string &OutputFile, 313 const std::vector<std::string> &CCArgs, 314 const std::vector<std::string> &SharedLibs, unsigned Timeout, 315 unsigned MemoryLimit) { 316 317 std::vector<StringRef> ProgramArgs; 318 ProgramArgs.push_back(ExecutionCommand); 319 320 for (std::size_t i = 0; i < ExecutorArgs.size(); ++i) 321 ProgramArgs.push_back(ExecutorArgs[i]); 322 ProgramArgs.push_back(Bitcode); 323 324 // Add optional parameters to the running program from Argv 325 for (unsigned i = 0, e = Args.size(); i != e; ++i) 326 ProgramArgs.push_back(Args[i]); 327 328 return RunProgramWithTimeout(ExecutionCommand, ProgramArgs, InputFile, 329 OutputFile, OutputFile, Timeout, MemoryLimit); 330 } 331 332 // Tokenize the CommandLine to the command and the args to allow 333 // defining a full command line as the command instead of just the 334 // executed program. We cannot just pass the whole string after the command 335 // as a single argument because then the program sees only a single 336 // command line argument (with spaces in it: "foo bar" instead 337 // of "foo" and "bar"). 338 // 339 // Spaces are used as a delimiter; however repeated, leading, and trailing 340 // whitespace are ignored. Simple escaping is allowed via the '\' 341 // character, as seen below: 342 // 343 // Two consecutive '\' evaluate to a single '\'. 344 // A space after a '\' evaluates to a space that is not interpreted as a 345 // delimiter. 346 // Any other instances of the '\' character are removed. 347 // 348 // Example: 349 // '\\' -> '\' 350 // '\ ' -> ' ' 351 // 'exa\mple' -> 'example' 352 // 353 static void lexCommand(const char *Argv0, std::string &Message, 354 const std::string &CommandLine, std::string &CmdPath, 355 std::vector<std::string> &Args) { 356 357 std::string Token; 358 std::string Command; 359 bool FoundPath = false; 360 361 // first argument is the PATH. 362 // Skip repeated whitespace, leading whitespace and trailing whitespace. 363 for (std::size_t Pos = 0u; Pos <= CommandLine.size(); ++Pos) { 364 if ('\\' == CommandLine[Pos]) { 365 if (Pos + 1 < CommandLine.size()) 366 Token.push_back(CommandLine[++Pos]); 367 368 continue; 369 } 370 if (' ' == CommandLine[Pos] || CommandLine.size() == Pos) { 371 if (Token.empty()) 372 continue; 373 374 if (!FoundPath) { 375 Command = Token; 376 FoundPath = true; 377 Token.clear(); 378 continue; 379 } 380 381 Args.push_back(Token); 382 Token.clear(); 383 continue; 384 } 385 Token.push_back(CommandLine[Pos]); 386 } 387 388 auto Path = FindProgramByName(Command, Argv0, (void *)(intptr_t)&lexCommand); 389 if (!Path) { 390 Message = std::string("Cannot find '") + Command + 391 "' in PATH: " + Path.getError().message() + "\n"; 392 return; 393 } 394 CmdPath = *Path; 395 396 Message = "Found command in: " + CmdPath + "\n"; 397 } 398 399 // Custom execution environment create method, takes the execution command 400 // as arguments 401 AbstractInterpreter *AbstractInterpreter::createCustomCompiler( 402 const char *Argv0, std::string &Message, 403 const std::string &CompileCommandLine) { 404 405 std::string CmdPath; 406 std::vector<std::string> Args; 407 lexCommand(Argv0, Message, CompileCommandLine, CmdPath, Args); 408 if (CmdPath.empty()) 409 return nullptr; 410 411 return new CustomCompiler(CmdPath, Args); 412 } 413 414 // Custom execution environment create method, takes the execution command 415 // as arguments 416 AbstractInterpreter * 417 AbstractInterpreter::createCustomExecutor(const char *Argv0, 418 std::string &Message, 419 const std::string &ExecCommandLine) { 420 421 std::string CmdPath; 422 std::vector<std::string> Args; 423 lexCommand(Argv0, Message, ExecCommandLine, CmdPath, Args); 424 if (CmdPath.empty()) 425 return nullptr; 426 427 return new CustomExecutor(CmdPath, Args); 428 } 429 430 //===----------------------------------------------------------------------===// 431 // LLC Implementation of AbstractIntepreter interface 432 // 433 Expected<CC::FileType> LLC::OutputCode(const std::string &Bitcode, 434 std::string &OutputAsmFile, 435 unsigned Timeout, unsigned MemoryLimit) { 436 const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s"); 437 438 SmallString<128> UniqueFile; 439 std::error_code EC = 440 sys::fs::createUniqueFile(Bitcode + "-%%%%%%%" + Suffix, UniqueFile); 441 if (EC) { 442 errs() << "Error making unique filename: " << EC.message() << "\n"; 443 exit(1); 444 } 445 OutputAsmFile = std::string(UniqueFile.str()); 446 std::vector<StringRef> LLCArgs; 447 LLCArgs.push_back(LLCPath); 448 449 // Add any extra LLC args. 450 for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) 451 LLCArgs.push_back(ToolArgs[i]); 452 453 LLCArgs.push_back("-o"); 454 LLCArgs.push_back(OutputAsmFile); // Output to the Asm file 455 LLCArgs.push_back(Bitcode); // This is the input bitcode 456 457 if (UseIntegratedAssembler) 458 LLCArgs.push_back("-filetype=obj"); 459 460 outs() << (UseIntegratedAssembler ? "<llc-ia>" : "<llc>"); 461 outs().flush(); 462 LLVM_DEBUG(errs() << "\nAbout to run:\t"; 463 for (unsigned i = 0, e = LLCArgs.size(); i != e; ++i) errs() 464 << " " << LLCArgs[i]; 465 errs() << "\n";); 466 if (RunProgramWithTimeout(LLCPath, LLCArgs, "", "", "", Timeout, MemoryLimit)) 467 return ProcessFailure(LLCPath, LLCArgs, Timeout, MemoryLimit); 468 return UseIntegratedAssembler ? CC::ObjectFile : CC::AsmFile; 469 } 470 471 Error LLC::compileProgram(const std::string &Bitcode, unsigned Timeout, 472 unsigned MemoryLimit) { 473 std::string OutputAsmFile; 474 Expected<CC::FileType> Result = 475 OutputCode(Bitcode, OutputAsmFile, Timeout, MemoryLimit); 476 sys::fs::remove(OutputAsmFile); 477 if (Error E = Result.takeError()) 478 return E; 479 return Error::success(); 480 } 481 482 Expected<int> LLC::ExecuteProgram(const std::string &Bitcode, 483 const std::vector<std::string> &Args, 484 const std::string &InputFile, 485 const std::string &OutputFile, 486 const std::vector<std::string> &ArgsForCC, 487 const std::vector<std::string> &SharedLibs, 488 unsigned Timeout, unsigned MemoryLimit) { 489 490 std::string OutputAsmFile; 491 Expected<CC::FileType> FileKind = 492 OutputCode(Bitcode, OutputAsmFile, Timeout, MemoryLimit); 493 FileRemover OutFileRemover(OutputAsmFile, !SaveTemps); 494 if (Error E = FileKind.takeError()) 495 return std::move(E); 496 497 std::vector<std::string> CCArgs(ArgsForCC); 498 llvm::append_range(CCArgs, SharedLibs); 499 500 // Assuming LLC worked, compile the result with CC and run it. 501 return cc->ExecuteProgram(OutputAsmFile, Args, *FileKind, InputFile, 502 OutputFile, CCArgs, Timeout, MemoryLimit); 503 } 504 505 /// createLLC - Try to find the LLC executable 506 /// 507 LLC *AbstractInterpreter::createLLC(const char *Argv0, std::string &Message, 508 const std::string &CCBinary, 509 const std::vector<std::string> *Args, 510 const std::vector<std::string> *CCArgs, 511 bool UseIntegratedAssembler) { 512 ErrorOr<std::string> LLCPath = 513 FindProgramByName("llc", Argv0, (void *)(intptr_t)&createLLC); 514 if (!LLCPath) { 515 Message = LLCPath.getError().message() + "\n"; 516 return nullptr; 517 } 518 519 CC *cc = CC::create(Argv0, Message, CCBinary, CCArgs); 520 if (!cc) { 521 errs() << Message << "\n"; 522 exit(1); 523 } 524 Message = "Found llc: " + *LLCPath + "\n"; 525 return new LLC(*LLCPath, cc, Args, UseIntegratedAssembler); 526 } 527 528 //===---------------------------------------------------------------------===// 529 // JIT Implementation of AbstractIntepreter interface 530 // 531 namespace { 532 class JIT : public AbstractInterpreter { 533 std::string LLIPath; // The path to the LLI executable 534 std::vector<std::string> ToolArgs; // Args to pass to LLI 535 public: 536 JIT(const std::string &Path, const std::vector<std::string> *Args) 537 : LLIPath(Path) { 538 ToolArgs.clear(); 539 if (Args) { 540 ToolArgs = *Args; 541 } 542 } 543 544 Expected<int> ExecuteProgram( 545 const std::string &Bitcode, const std::vector<std::string> &Args, 546 const std::string &InputFile, const std::string &OutputFile, 547 const std::vector<std::string> &CCArgs = std::vector<std::string>(), 548 const std::vector<std::string> &SharedLibs = std::vector<std::string>(), 549 unsigned Timeout = 0, unsigned MemoryLimit = 0) override; 550 }; 551 } 552 553 Expected<int> JIT::ExecuteProgram(const std::string &Bitcode, 554 const std::vector<std::string> &Args, 555 const std::string &InputFile, 556 const std::string &OutputFile, 557 const std::vector<std::string> &CCArgs, 558 const std::vector<std::string> &SharedLibs, 559 unsigned Timeout, unsigned MemoryLimit) { 560 // Construct a vector of parameters, incorporating those from the command-line 561 std::vector<StringRef> JITArgs; 562 JITArgs.push_back(LLIPath); 563 JITArgs.push_back("-force-interpreter=false"); 564 565 // Add any extra LLI args. 566 for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) 567 JITArgs.push_back(ToolArgs[i]); 568 569 for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) { 570 JITArgs.push_back("-load"); 571 JITArgs.push_back(SharedLibs[i]); 572 } 573 JITArgs.push_back(Bitcode); 574 // Add optional parameters to the running program from Argv 575 for (unsigned i = 0, e = Args.size(); i != e; ++i) 576 JITArgs.push_back(Args[i]); 577 578 outs() << "<jit>"; 579 outs().flush(); 580 LLVM_DEBUG(errs() << "\nAbout to run:\t"; 581 for (unsigned i = 0, e = JITArgs.size(); i != e; ++i) errs() 582 << " " << JITArgs[i]; 583 errs() << "\n";); 584 LLVM_DEBUG(errs() << "\nSending output to " << OutputFile << "\n"); 585 return RunProgramWithTimeout(LLIPath, JITArgs, InputFile, OutputFile, 586 OutputFile, Timeout, MemoryLimit); 587 } 588 589 /// createJIT - Try to find the LLI executable 590 /// 591 AbstractInterpreter * 592 AbstractInterpreter::createJIT(const char *Argv0, std::string &Message, 593 const std::vector<std::string> *Args) { 594 if (ErrorOr<std::string> LLIPath = 595 FindProgramByName("lli", Argv0, (void *)(intptr_t)&createJIT)) { 596 Message = "Found lli: " + *LLIPath + "\n"; 597 return new JIT(*LLIPath, Args); 598 } else { 599 Message = LLIPath.getError().message() + "\n"; 600 return nullptr; 601 } 602 } 603 604 //===---------------------------------------------------------------------===// 605 // CC abstraction 606 // 607 608 static bool IsARMArchitecture(std::vector<StringRef> Args) { 609 for (size_t I = 0; I < Args.size(); ++I) { 610 if (!Args[I].equals_insensitive("-arch")) 611 continue; 612 ++I; 613 if (I == Args.size()) 614 break; 615 if (Args[I].starts_with_insensitive("arm")) 616 return true; 617 } 618 619 return false; 620 } 621 622 Expected<int> CC::ExecuteProgram(const std::string &ProgramFile, 623 const std::vector<std::string> &Args, 624 FileType fileType, 625 const std::string &InputFile, 626 const std::string &OutputFile, 627 const std::vector<std::string> &ArgsForCC, 628 unsigned Timeout, unsigned MemoryLimit) { 629 std::vector<StringRef> CCArgs; 630 631 CCArgs.push_back(CCPath); 632 633 if (TargetTriple.getArch() == Triple::x86) 634 CCArgs.push_back("-m32"); 635 636 for (std::vector<std::string>::const_iterator I = ccArgs.begin(), 637 E = ccArgs.end(); 638 I != E; ++I) 639 CCArgs.push_back(*I); 640 641 // Specify -x explicitly in case the extension is wonky 642 if (fileType != ObjectFile) { 643 CCArgs.push_back("-x"); 644 if (fileType == CFile) { 645 CCArgs.push_back("c"); 646 CCArgs.push_back("-fno-strict-aliasing"); 647 } else { 648 CCArgs.push_back("assembler"); 649 650 // For ARM architectures we don't want this flag. bugpoint isn't 651 // explicitly told what architecture it is working on, so we get 652 // it from cc flags 653 if (TargetTriple.isOSDarwin() && !IsARMArchitecture(CCArgs)) 654 CCArgs.push_back("-force_cpusubtype_ALL"); 655 } 656 } 657 658 CCArgs.push_back(ProgramFile); // Specify the input filename. 659 660 CCArgs.push_back("-x"); 661 CCArgs.push_back("none"); 662 CCArgs.push_back("-o"); 663 664 SmallString<128> OutputBinary; 665 std::error_code EC = 666 sys::fs::createUniqueFile(ProgramFile + "-%%%%%%%.cc.exe", OutputBinary); 667 if (EC) { 668 errs() << "Error making unique filename: " << EC.message() << "\n"; 669 exit(1); 670 } 671 CCArgs.push_back(OutputBinary); // Output to the right file... 672 673 // Add any arguments intended for CC. We locate them here because this is 674 // most likely -L and -l options that need to come before other libraries but 675 // after the source. Other options won't be sensitive to placement on the 676 // command line, so this should be safe. 677 for (unsigned i = 0, e = ArgsForCC.size(); i != e; ++i) 678 CCArgs.push_back(ArgsForCC[i]); 679 680 CCArgs.push_back("-lm"); // Hard-code the math library... 681 CCArgs.push_back("-O2"); // Optimize the program a bit... 682 if (TargetTriple.getArch() == Triple::sparc) 683 CCArgs.push_back("-mcpu=v9"); 684 685 outs() << "<CC>"; 686 outs().flush(); 687 LLVM_DEBUG(errs() << "\nAbout to run:\t"; 688 for (unsigned i = 0, e = CCArgs.size(); i != e; ++i) errs() 689 << " " << CCArgs[i]; 690 errs() << "\n";); 691 if (RunProgramWithTimeout(CCPath, CCArgs, "", "", "")) 692 return ProcessFailure(CCPath, CCArgs); 693 694 std::vector<StringRef> ProgramArgs; 695 696 // Declared here so that the destructor only runs after 697 // ProgramArgs is used. 698 std::string Exec; 699 700 if (RemoteClientPath.empty()) 701 ProgramArgs.push_back(OutputBinary); 702 else { 703 ProgramArgs.push_back(RemoteClientPath); 704 ProgramArgs.push_back(RemoteHost); 705 if (!RemoteUser.empty()) { 706 ProgramArgs.push_back("-l"); 707 ProgramArgs.push_back(RemoteUser); 708 } 709 if (!RemotePort.empty()) { 710 ProgramArgs.push_back("-p"); 711 ProgramArgs.push_back(RemotePort); 712 } 713 if (!RemoteExtra.empty()) { 714 ProgramArgs.push_back(RemoteExtra); 715 } 716 717 // Full path to the binary. We need to cd to the exec directory because 718 // there is a dylib there that the exec expects to find in the CWD 719 char *env_pwd = getenv("PWD"); 720 Exec = "cd "; 721 Exec += env_pwd; 722 Exec += "; ./"; 723 Exec += OutputBinary.c_str(); 724 ProgramArgs.push_back(Exec); 725 } 726 727 // Add optional parameters to the running program from Argv 728 for (unsigned i = 0, e = Args.size(); i != e; ++i) 729 ProgramArgs.push_back(Args[i]); 730 731 // Now that we have a binary, run it! 732 outs() << "<program>"; 733 outs().flush(); 734 LLVM_DEBUG( 735 errs() << "\nAbout to run:\t"; 736 for (unsigned i = 0, e = ProgramArgs.size(); i != e; ++i) errs() 737 << " " << ProgramArgs[i]; 738 errs() << "\n";); 739 740 FileRemover OutputBinaryRemover(OutputBinary.str(), !SaveTemps); 741 742 if (RemoteClientPath.empty()) { 743 LLVM_DEBUG(errs() << "<run locally>"); 744 std::string Error; 745 int ExitCode = RunProgramWithTimeout(OutputBinary.str(), ProgramArgs, 746 InputFile, OutputFile, OutputFile, 747 Timeout, MemoryLimit, &Error); 748 // Treat a signal (usually SIGSEGV) or timeout as part of the program output 749 // so that crash-causing miscompilation is handled seamlessly. 750 if (ExitCode < -1) { 751 std::ofstream outFile(OutputFile.c_str(), std::ios_base::app); 752 outFile << Error << '\n'; 753 outFile.close(); 754 } 755 return ExitCode; 756 } else { 757 outs() << "<run remotely>"; 758 outs().flush(); 759 return RunProgramRemotelyWithTimeout(RemoteClientPath, ProgramArgs, 760 InputFile, OutputFile, OutputFile, 761 Timeout, MemoryLimit); 762 } 763 } 764 765 Error CC::MakeSharedObject(const std::string &InputFile, FileType fileType, 766 std::string &OutputFile, 767 const std::vector<std::string> &ArgsForCC) { 768 SmallString<128> UniqueFilename; 769 std::error_code EC = sys::fs::createUniqueFile( 770 InputFile + "-%%%%%%%" + LTDL_SHLIB_EXT, UniqueFilename); 771 if (EC) { 772 errs() << "Error making unique filename: " << EC.message() << "\n"; 773 exit(1); 774 } 775 OutputFile = std::string(UniqueFilename.str()); 776 777 std::vector<StringRef> CCArgs; 778 779 CCArgs.push_back(CCPath); 780 781 if (TargetTriple.getArch() == Triple::x86) 782 CCArgs.push_back("-m32"); 783 784 for (std::vector<std::string>::const_iterator I = ccArgs.begin(), 785 E = ccArgs.end(); 786 I != E; ++I) 787 CCArgs.push_back(*I); 788 789 // Compile the C/asm file into a shared object 790 if (fileType != ObjectFile) { 791 CCArgs.push_back("-x"); 792 CCArgs.push_back(fileType == AsmFile ? "assembler" : "c"); 793 } 794 CCArgs.push_back("-fno-strict-aliasing"); 795 CCArgs.push_back(InputFile); // Specify the input filename. 796 CCArgs.push_back("-x"); 797 CCArgs.push_back("none"); 798 if (TargetTriple.getArch() == Triple::sparc) 799 CCArgs.push_back("-G"); // Compile a shared library, `-G' for Sparc 800 else if (TargetTriple.isOSDarwin()) { 801 // link all source files into a single module in data segment, rather than 802 // generating blocks. dynamic_lookup requires that you set 803 // MACOSX_DEPLOYMENT_TARGET=10.3 in your env. FIXME: it would be better for 804 // bugpoint to just pass that in the environment of CC. 805 CCArgs.push_back("-single_module"); 806 CCArgs.push_back("-dynamiclib"); // `-dynamiclib' for MacOS X/PowerPC 807 CCArgs.push_back("-undefined"); 808 CCArgs.push_back("dynamic_lookup"); 809 } else 810 CCArgs.push_back("-shared"); // `-shared' for Linux/X86, maybe others 811 812 if (TargetTriple.getArch() == Triple::x86_64) 813 CCArgs.push_back("-fPIC"); // Requires shared objs to contain PIC 814 815 if (TargetTriple.getArch() == Triple::sparc) 816 CCArgs.push_back("-mcpu=v9"); 817 818 CCArgs.push_back("-o"); 819 CCArgs.push_back(OutputFile); // Output to the right filename. 820 CCArgs.push_back("-O2"); // Optimize the program a bit. 821 822 // Add any arguments intended for CC. We locate them here because this is 823 // most likely -L and -l options that need to come before other libraries but 824 // after the source. Other options won't be sensitive to placement on the 825 // command line, so this should be safe. 826 for (unsigned i = 0, e = ArgsForCC.size(); i != e; ++i) 827 CCArgs.push_back(ArgsForCC[i]); 828 829 outs() << "<CC>"; 830 outs().flush(); 831 LLVM_DEBUG(errs() << "\nAbout to run:\t"; 832 for (unsigned i = 0, e = CCArgs.size(); i != e; ++i) errs() 833 << " " << CCArgs[i]; 834 errs() << "\n";); 835 if (RunProgramWithTimeout(CCPath, CCArgs, "", "", "")) 836 return ProcessFailure(CCPath, CCArgs); 837 return Error::success(); 838 } 839 840 /// create - Try to find the CC executable 841 /// 842 CC *CC::create(const char *Argv0, std::string &Message, 843 const std::string &CCBinary, 844 const std::vector<std::string> *Args) { 845 auto CCPath = FindProgramByName(CCBinary, Argv0, (void *)(intptr_t)&create); 846 if (!CCPath) { 847 Message = "Cannot find `" + CCBinary + "' in PATH: " + 848 CCPath.getError().message() + "\n"; 849 return nullptr; 850 } 851 852 std::string RemoteClientPath; 853 if (!RemoteClient.empty()) { 854 auto Path = sys::findProgramByName(RemoteClient); 855 if (!Path) { 856 Message = "Cannot find `" + RemoteClient + "' in PATH: " + 857 Path.getError().message() + "\n"; 858 return nullptr; 859 } 860 RemoteClientPath = *Path; 861 } 862 863 Message = "Found CC: " + *CCPath + "\n"; 864 return new CC(*CCPath, RemoteClientPath, Args); 865 } 866