10b57cec5SDimitry Andric //===-- ToolRunner.cpp ----------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the interfaces described in the ToolRunner.h file.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "ToolRunner.h"
140b57cec5SDimitry Andric #include "llvm/Config/config.h"
150b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
160b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
170b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
180b57cec5SDimitry Andric #include "llvm/Support/FileUtilities.h"
190b57cec5SDimitry Andric #include "llvm/Support/Program.h"
200b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
210b57cec5SDimitry Andric #include <fstream>
220b57cec5SDimitry Andric #include <sstream>
230b57cec5SDimitry Andric #include <utility>
240b57cec5SDimitry Andric using namespace llvm;
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric #define DEBUG_TYPE "toolrunner"
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric namespace llvm {
290b57cec5SDimitry Andric cl::opt<bool> SaveTemps("save-temps", cl::init(false),
300b57cec5SDimitry Andric                         cl::desc("Save temporary files"));
310b57cec5SDimitry Andric }
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric namespace {
340b57cec5SDimitry Andric cl::opt<std::string>
350b57cec5SDimitry Andric     RemoteClient("remote-client",
360b57cec5SDimitry Andric                  cl::desc("Remote execution client (rsh/ssh)"));
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric cl::opt<std::string> RemoteHost("remote-host",
390b57cec5SDimitry Andric                                 cl::desc("Remote execution (rsh/ssh) host"));
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric cl::opt<std::string> RemotePort("remote-port",
420b57cec5SDimitry Andric                                 cl::desc("Remote execution (rsh/ssh) port"));
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric cl::opt<std::string> RemoteUser("remote-user",
450b57cec5SDimitry Andric                                 cl::desc("Remote execution (rsh/ssh) user id"));
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric cl::opt<std::string>
480b57cec5SDimitry Andric     RemoteExtra("remote-extra-options",
490b57cec5SDimitry Andric                 cl::desc("Remote execution (rsh/ssh) extra options"));
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric /// RunProgramWithTimeout - This function provides an alternate interface
530b57cec5SDimitry Andric /// to the sys::Program::ExecuteAndWait interface.
540b57cec5SDimitry Andric /// @see sys::Program::ExecuteAndWait
RunProgramWithTimeout(StringRef ProgramPath,ArrayRef<StringRef> Args,StringRef StdInFile,StringRef StdOutFile,StringRef StdErrFile,unsigned NumSeconds=0,unsigned MemoryLimit=0,std::string * ErrMsg=nullptr)550b57cec5SDimitry Andric static int RunProgramWithTimeout(StringRef ProgramPath,
560b57cec5SDimitry Andric                                  ArrayRef<StringRef> Args, StringRef StdInFile,
570b57cec5SDimitry Andric                                  StringRef StdOutFile, StringRef StdErrFile,
580b57cec5SDimitry Andric                                  unsigned NumSeconds = 0,
590b57cec5SDimitry Andric                                  unsigned MemoryLimit = 0,
600b57cec5SDimitry Andric                                  std::string *ErrMsg = nullptr) {
61bdd1243dSDimitry Andric   std::optional<StringRef> Redirects[3] = {StdInFile, StdOutFile, StdErrFile};
62bdd1243dSDimitry Andric   return sys::ExecuteAndWait(ProgramPath, Args, std::nullopt, Redirects,
63bdd1243dSDimitry Andric                              NumSeconds, MemoryLimit, ErrMsg);
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric /// RunProgramRemotelyWithTimeout - This function runs the given program
670b57cec5SDimitry Andric /// remotely using the given remote client and the sys::Program::ExecuteAndWait.
680b57cec5SDimitry Andric /// Returns the remote program exit code or reports a remote client error if it
690b57cec5SDimitry Andric /// fails. Remote client is required to return 255 if it failed or program exit
700b57cec5SDimitry Andric /// code otherwise.
710b57cec5SDimitry Andric /// @see sys::Program::ExecuteAndWait
RunProgramRemotelyWithTimeout(StringRef RemoteClientPath,ArrayRef<StringRef> Args,StringRef StdInFile,StringRef StdOutFile,StringRef StdErrFile,unsigned NumSeconds=0,unsigned MemoryLimit=0)720b57cec5SDimitry Andric static int RunProgramRemotelyWithTimeout(
730b57cec5SDimitry Andric     StringRef RemoteClientPath, ArrayRef<StringRef> Args, StringRef StdInFile,
740b57cec5SDimitry Andric     StringRef StdOutFile, StringRef StdErrFile, unsigned NumSeconds = 0,
750b57cec5SDimitry Andric     unsigned MemoryLimit = 0) {
76bdd1243dSDimitry Andric   std::optional<StringRef> Redirects[3] = {StdInFile, StdOutFile, StdErrFile};
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   // Run the program remotely with the remote client
79bdd1243dSDimitry Andric   int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, std::nullopt,
80bdd1243dSDimitry Andric                                        Redirects, NumSeconds, MemoryLimit);
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   // Has the remote client fail?
830b57cec5SDimitry Andric   if (255 == ReturnCode) {
840b57cec5SDimitry Andric     std::ostringstream OS;
850b57cec5SDimitry Andric     OS << "\nError running remote client:\n ";
860b57cec5SDimitry Andric     for (StringRef Arg : Args)
870b57cec5SDimitry Andric       OS << " " << Arg.str();
880b57cec5SDimitry Andric     OS << "\n";
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric     // The error message is in the output file, let's print it out from there.
910b57cec5SDimitry Andric     std::string StdOutFileName = StdOutFile.str();
920b57cec5SDimitry Andric     std::ifstream ErrorFile(StdOutFileName.c_str());
930b57cec5SDimitry Andric     if (ErrorFile) {
940b57cec5SDimitry Andric       std::copy(std::istreambuf_iterator<char>(ErrorFile),
950b57cec5SDimitry Andric                 std::istreambuf_iterator<char>(),
960b57cec5SDimitry Andric                 std::ostreambuf_iterator<char>(OS));
970b57cec5SDimitry Andric       ErrorFile.close();
980b57cec5SDimitry Andric     }
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric     errs() << OS.str();
1010b57cec5SDimitry Andric   }
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   return ReturnCode;
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric 
ProcessFailure(StringRef ProgPath,ArrayRef<StringRef> Args,unsigned Timeout=0,unsigned MemoryLimit=0)1060b57cec5SDimitry Andric static Error ProcessFailure(StringRef ProgPath, ArrayRef<StringRef> Args,
1070b57cec5SDimitry Andric                             unsigned Timeout = 0, unsigned MemoryLimit = 0) {
1080b57cec5SDimitry Andric   std::ostringstream OS;
1090b57cec5SDimitry Andric   OS << "\nError running tool:\n ";
1100b57cec5SDimitry Andric   for (StringRef Arg : Args)
1110b57cec5SDimitry Andric     OS << " " << Arg.str();
1120b57cec5SDimitry Andric   OS << "\n";
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   // Rerun the compiler, capturing any error messages to print them.
1150b57cec5SDimitry Andric   SmallString<128> ErrorFilename;
1160b57cec5SDimitry Andric   std::error_code EC = sys::fs::createTemporaryFile(
1170b57cec5SDimitry Andric       "bugpoint.program_error_messages", "", ErrorFilename);
1180b57cec5SDimitry Andric   if (EC) {
1190b57cec5SDimitry Andric     errs() << "Error making unique filename: " << EC.message() << "\n";
1200b57cec5SDimitry Andric     exit(1);
1210b57cec5SDimitry Andric   }
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   RunProgramWithTimeout(ProgPath, Args, "", ErrorFilename.str(),
1240b57cec5SDimitry Andric                         ErrorFilename.str(), Timeout, MemoryLimit);
1250b57cec5SDimitry Andric   // FIXME: check return code ?
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   // Print out the error messages generated by CC if possible...
1280b57cec5SDimitry Andric   std::ifstream ErrorFile(ErrorFilename.c_str());
1290b57cec5SDimitry Andric   if (ErrorFile) {
1300b57cec5SDimitry Andric     std::copy(std::istreambuf_iterator<char>(ErrorFile),
1310b57cec5SDimitry Andric               std::istreambuf_iterator<char>(),
1320b57cec5SDimitry Andric               std::ostreambuf_iterator<char>(OS));
1330b57cec5SDimitry Andric     ErrorFile.close();
1340b57cec5SDimitry Andric   }
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric   sys::fs::remove(ErrorFilename.c_str());
1370b57cec5SDimitry Andric   return make_error<StringError>(OS.str(), inconvertibleErrorCode());
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric //===---------------------------------------------------------------------===//
1410b57cec5SDimitry Andric // LLI Implementation of AbstractIntepreter interface
1420b57cec5SDimitry Andric //
1430b57cec5SDimitry Andric namespace {
1440b57cec5SDimitry Andric class LLI : public AbstractInterpreter {
1450b57cec5SDimitry Andric   std::string LLIPath;               // The path to the LLI executable
1460b57cec5SDimitry Andric   std::vector<std::string> ToolArgs; // Args to pass to LLI
1470b57cec5SDimitry Andric public:
LLI(const std::string & Path,const std::vector<std::string> * Args)1480b57cec5SDimitry Andric   LLI(const std::string &Path, const std::vector<std::string> *Args)
1490b57cec5SDimitry Andric       : LLIPath(Path) {
1500b57cec5SDimitry Andric     ToolArgs.clear();
1510b57cec5SDimitry Andric     if (Args) {
1520b57cec5SDimitry Andric       ToolArgs = *Args;
1530b57cec5SDimitry Andric     }
1540b57cec5SDimitry Andric   }
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric   Expected<int> ExecuteProgram(
1570b57cec5SDimitry Andric       const std::string &Bitcode, const std::vector<std::string> &Args,
1580b57cec5SDimitry Andric       const std::string &InputFile, const std::string &OutputFile,
1590b57cec5SDimitry Andric       const std::vector<std::string> &CCArgs,
1600b57cec5SDimitry Andric       const std::vector<std::string> &SharedLibs = std::vector<std::string>(),
1610b57cec5SDimitry Andric       unsigned Timeout = 0, unsigned MemoryLimit = 0) override;
1620b57cec5SDimitry Andric };
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric 
ExecuteProgram(const std::string & Bitcode,const std::vector<std::string> & Args,const std::string & InputFile,const std::string & OutputFile,const std::vector<std::string> & CCArgs,const std::vector<std::string> & SharedLibs,unsigned Timeout,unsigned MemoryLimit)1650b57cec5SDimitry Andric Expected<int> LLI::ExecuteProgram(const std::string &Bitcode,
1660b57cec5SDimitry Andric                                   const std::vector<std::string> &Args,
1670b57cec5SDimitry Andric                                   const std::string &InputFile,
1680b57cec5SDimitry Andric                                   const std::string &OutputFile,
1690b57cec5SDimitry Andric                                   const std::vector<std::string> &CCArgs,
1700b57cec5SDimitry Andric                                   const std::vector<std::string> &SharedLibs,
1710b57cec5SDimitry Andric                                   unsigned Timeout, unsigned MemoryLimit) {
1720b57cec5SDimitry Andric   std::vector<StringRef> LLIArgs;
1738bcb0991SDimitry Andric   LLIArgs.push_back(LLIPath);
1740b57cec5SDimitry Andric   LLIArgs.push_back("-force-interpreter=true");
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric   for (std::vector<std::string>::const_iterator i = SharedLibs.begin(),
1770b57cec5SDimitry Andric                                                 e = SharedLibs.end();
1780b57cec5SDimitry Andric        i != e; ++i) {
1790b57cec5SDimitry Andric     LLIArgs.push_back("-load");
1800b57cec5SDimitry Andric     LLIArgs.push_back(*i);
1810b57cec5SDimitry Andric   }
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   // Add any extra LLI args.
1840b57cec5SDimitry Andric   for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
1850b57cec5SDimitry Andric     LLIArgs.push_back(ToolArgs[i]);
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric   LLIArgs.push_back(Bitcode);
1880b57cec5SDimitry Andric   // Add optional parameters to the running program from Argv
1890b57cec5SDimitry Andric   for (unsigned i = 0, e = Args.size(); i != e; ++i)
1900b57cec5SDimitry Andric     LLIArgs.push_back(Args[i]);
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric   outs() << "<lli>";
1930b57cec5SDimitry Andric   outs().flush();
1940b57cec5SDimitry Andric   LLVM_DEBUG(errs() << "\nAbout to run:\t";
195349cc55cSDimitry Andric              for (unsigned i = 0, e = LLIArgs.size(); i != e; ++i) errs()
1960b57cec5SDimitry Andric              << " " << LLIArgs[i];
1970b57cec5SDimitry Andric              errs() << "\n";);
1980b57cec5SDimitry Andric   return RunProgramWithTimeout(LLIPath, LLIArgs, InputFile, OutputFile,
1990b57cec5SDimitry Andric                                OutputFile, Timeout, MemoryLimit);
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric 
anchor()2020b57cec5SDimitry Andric void AbstractInterpreter::anchor() {}
2030b57cec5SDimitry Andric 
FindProgramByName(const std::string & ExeName,const char * Argv0,void * MainAddr)2040b57cec5SDimitry Andric ErrorOr<std::string> llvm::FindProgramByName(const std::string &ExeName,
2050b57cec5SDimitry Andric                                              const char *Argv0,
2060b57cec5SDimitry Andric                                              void *MainAddr) {
2070b57cec5SDimitry Andric   // Check the directory that the calling program is in.  We can do
2080b57cec5SDimitry Andric   // this if ProgramPath contains at least one / character, indicating that it
2090b57cec5SDimitry Andric   // is a relative path to the executable itself.
2100b57cec5SDimitry Andric   std::string Main = sys::fs::getMainExecutable(Argv0, MainAddr);
2110b57cec5SDimitry Andric   StringRef Result = sys::path::parent_path(Main);
2120b57cec5SDimitry Andric   if (ErrorOr<std::string> Path = sys::findProgramByName(ExeName, Result))
2130b57cec5SDimitry Andric     return *Path;
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric   // Check the user PATH.
2160b57cec5SDimitry Andric   return sys::findProgramByName(ExeName);
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric // LLI create method - Try to find the LLI executable
2200b57cec5SDimitry Andric AbstractInterpreter *
createLLI(const char * Argv0,std::string & Message,const std::vector<std::string> * ToolArgs)2210b57cec5SDimitry Andric AbstractInterpreter::createLLI(const char *Argv0, std::string &Message,
2220b57cec5SDimitry Andric                                const std::vector<std::string> *ToolArgs) {
2230b57cec5SDimitry Andric   if (ErrorOr<std::string> LLIPath =
2240b57cec5SDimitry Andric       FindProgramByName("lli", Argv0, (void *)(intptr_t)&createLLI)) {
2250b57cec5SDimitry Andric     Message = "Found lli: " + *LLIPath + "\n";
2260b57cec5SDimitry Andric     return new LLI(*LLIPath, ToolArgs);
2270b57cec5SDimitry Andric   } else {
2280b57cec5SDimitry Andric     Message = LLIPath.getError().message() + "\n";
2290b57cec5SDimitry Andric     return nullptr;
2300b57cec5SDimitry Andric   }
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric //===---------------------------------------------------------------------===//
2340b57cec5SDimitry Andric // Custom compiler command implementation of AbstractIntepreter interface
2350b57cec5SDimitry Andric //
2360b57cec5SDimitry Andric // Allows using a custom command for compiling the bitcode, thus allows, for
2370b57cec5SDimitry Andric // example, to compile a bitcode fragment without linking or executing, then
2380b57cec5SDimitry Andric // using a custom wrapper script to check for compiler errors.
2390b57cec5SDimitry Andric namespace {
2400b57cec5SDimitry Andric class CustomCompiler : public AbstractInterpreter {
2410b57cec5SDimitry Andric   std::string CompilerCommand;
2420b57cec5SDimitry Andric   std::vector<std::string> CompilerArgs;
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric public:
CustomCompiler(const std::string & CompilerCmd,std::vector<std::string> CompArgs)2450b57cec5SDimitry Andric   CustomCompiler(const std::string &CompilerCmd,
2460b57cec5SDimitry Andric                  std::vector<std::string> CompArgs)
2470b57cec5SDimitry Andric       : CompilerCommand(CompilerCmd), CompilerArgs(std::move(CompArgs)) {}
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric   Error compileProgram(const std::string &Bitcode, unsigned Timeout = 0,
2500b57cec5SDimitry Andric                        unsigned MemoryLimit = 0) override;
2510b57cec5SDimitry Andric 
ExecuteProgram(const std::string & Bitcode,const std::vector<std::string> & Args,const std::string & InputFile,const std::string & OutputFile,const std::vector<std::string> & CCArgs=std::vector<std::string> (),const std::vector<std::string> & SharedLibs=std::vector<std::string> (),unsigned Timeout=0,unsigned MemoryLimit=0)2520b57cec5SDimitry Andric   Expected<int> ExecuteProgram(
2530b57cec5SDimitry Andric       const std::string &Bitcode, const std::vector<std::string> &Args,
2540b57cec5SDimitry Andric       const std::string &InputFile, const std::string &OutputFile,
2550b57cec5SDimitry Andric       const std::vector<std::string> &CCArgs = std::vector<std::string>(),
2560b57cec5SDimitry Andric       const std::vector<std::string> &SharedLibs = std::vector<std::string>(),
2570b57cec5SDimitry Andric       unsigned Timeout = 0, unsigned MemoryLimit = 0) override {
2580b57cec5SDimitry Andric     return make_error<StringError>(
2590b57cec5SDimitry Andric         "Execution not supported with -compile-custom",
2600b57cec5SDimitry Andric         inconvertibleErrorCode());
2610b57cec5SDimitry Andric   }
2620b57cec5SDimitry Andric };
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric 
compileProgram(const std::string & Bitcode,unsigned Timeout,unsigned MemoryLimit)2650b57cec5SDimitry Andric Error CustomCompiler::compileProgram(const std::string &Bitcode,
2660b57cec5SDimitry Andric                                      unsigned Timeout, unsigned MemoryLimit) {
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric   std::vector<StringRef> ProgramArgs;
2698bcb0991SDimitry Andric   ProgramArgs.push_back(CompilerCommand);
2700b57cec5SDimitry Andric 
2718bcb0991SDimitry Andric   for (const auto &Arg : CompilerArgs)
2728bcb0991SDimitry Andric     ProgramArgs.push_back(Arg);
2730b57cec5SDimitry Andric   ProgramArgs.push_back(Bitcode);
2740b57cec5SDimitry Andric 
2750b57cec5SDimitry Andric   // Add optional parameters to the running program from Argv
2768bcb0991SDimitry Andric   for (const auto &Arg : CompilerArgs)
2778bcb0991SDimitry Andric     ProgramArgs.push_back(Arg);
2780b57cec5SDimitry Andric 
2790b57cec5SDimitry Andric   if (RunProgramWithTimeout(CompilerCommand, ProgramArgs, "", "", "", Timeout,
2800b57cec5SDimitry Andric                             MemoryLimit))
2810b57cec5SDimitry Andric     return ProcessFailure(CompilerCommand, ProgramArgs, Timeout, MemoryLimit);
2820b57cec5SDimitry Andric   return Error::success();
2830b57cec5SDimitry Andric }
2840b57cec5SDimitry Andric 
2850b57cec5SDimitry Andric //===---------------------------------------------------------------------===//
2860b57cec5SDimitry Andric // Custom execution command implementation of AbstractIntepreter interface
2870b57cec5SDimitry Andric //
2880b57cec5SDimitry Andric // Allows using a custom command for executing the bitcode, thus allows,
2890b57cec5SDimitry Andric // for example, to invoke a cross compiler for code generation followed by
2900b57cec5SDimitry Andric // a simulator that executes the generated binary.
2910b57cec5SDimitry Andric namespace {
2920b57cec5SDimitry Andric class CustomExecutor : public AbstractInterpreter {
2930b57cec5SDimitry Andric   std::string ExecutionCommand;
2940b57cec5SDimitry Andric   std::vector<std::string> ExecutorArgs;
2950b57cec5SDimitry Andric 
2960b57cec5SDimitry Andric public:
CustomExecutor(const std::string & ExecutionCmd,std::vector<std::string> ExecArgs)2970b57cec5SDimitry Andric   CustomExecutor(const std::string &ExecutionCmd,
2980b57cec5SDimitry Andric                  std::vector<std::string> ExecArgs)
2990b57cec5SDimitry Andric       : ExecutionCommand(ExecutionCmd), ExecutorArgs(std::move(ExecArgs)) {}
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric   Expected<int> ExecuteProgram(
3020b57cec5SDimitry Andric       const std::string &Bitcode, const std::vector<std::string> &Args,
3030b57cec5SDimitry Andric       const std::string &InputFile, const std::string &OutputFile,
3040b57cec5SDimitry Andric       const std::vector<std::string> &CCArgs,
3050b57cec5SDimitry Andric       const std::vector<std::string> &SharedLibs = std::vector<std::string>(),
3060b57cec5SDimitry Andric       unsigned Timeout = 0, unsigned MemoryLimit = 0) override;
3070b57cec5SDimitry Andric };
3080b57cec5SDimitry Andric }
3090b57cec5SDimitry Andric 
ExecuteProgram(const std::string & Bitcode,const std::vector<std::string> & Args,const std::string & InputFile,const std::string & OutputFile,const std::vector<std::string> & CCArgs,const std::vector<std::string> & SharedLibs,unsigned Timeout,unsigned MemoryLimit)3100b57cec5SDimitry Andric Expected<int> CustomExecutor::ExecuteProgram(
3110b57cec5SDimitry Andric     const std::string &Bitcode, const std::vector<std::string> &Args,
3120b57cec5SDimitry Andric     const std::string &InputFile, const std::string &OutputFile,
3130b57cec5SDimitry Andric     const std::vector<std::string> &CCArgs,
3140b57cec5SDimitry Andric     const std::vector<std::string> &SharedLibs, unsigned Timeout,
3150b57cec5SDimitry Andric     unsigned MemoryLimit) {
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric   std::vector<StringRef> ProgramArgs;
3180b57cec5SDimitry Andric   ProgramArgs.push_back(ExecutionCommand);
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric   for (std::size_t i = 0; i < ExecutorArgs.size(); ++i)
3210b57cec5SDimitry Andric     ProgramArgs.push_back(ExecutorArgs[i]);
3220b57cec5SDimitry Andric   ProgramArgs.push_back(Bitcode);
3230b57cec5SDimitry Andric 
3240b57cec5SDimitry Andric   // Add optional parameters to the running program from Argv
3250b57cec5SDimitry Andric   for (unsigned i = 0, e = Args.size(); i != e; ++i)
3260b57cec5SDimitry Andric     ProgramArgs.push_back(Args[i]);
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric   return RunProgramWithTimeout(ExecutionCommand, ProgramArgs, InputFile,
3290b57cec5SDimitry Andric                                OutputFile, OutputFile, Timeout, MemoryLimit);
3300b57cec5SDimitry Andric }
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric // Tokenize the CommandLine to the command and the args to allow
3330b57cec5SDimitry Andric // defining a full command line as the command instead of just the
3340b57cec5SDimitry Andric // executed program. We cannot just pass the whole string after the command
3350b57cec5SDimitry Andric // as a single argument because then the program sees only a single
3360b57cec5SDimitry Andric // command line argument (with spaces in it: "foo bar" instead
3370b57cec5SDimitry Andric // of "foo" and "bar").
3380b57cec5SDimitry Andric //
3390b57cec5SDimitry Andric // Spaces are used as a delimiter; however repeated, leading, and trailing
3400b57cec5SDimitry Andric // whitespace are ignored. Simple escaping is allowed via the '\'
3410b57cec5SDimitry Andric // character, as seen below:
3420b57cec5SDimitry Andric //
3430b57cec5SDimitry Andric // Two consecutive '\' evaluate to a single '\'.
3440b57cec5SDimitry Andric // A space after a '\' evaluates to a space that is not interpreted as a
3450b57cec5SDimitry Andric // delimiter.
3460b57cec5SDimitry Andric // Any other instances of the '\' character are removed.
3470b57cec5SDimitry Andric //
3480b57cec5SDimitry Andric // Example:
3490b57cec5SDimitry Andric // '\\' -> '\'
3500b57cec5SDimitry Andric // '\ ' -> ' '
3510b57cec5SDimitry Andric // 'exa\mple' -> 'example'
3520b57cec5SDimitry Andric //
lexCommand(const char * Argv0,std::string & Message,const std::string & CommandLine,std::string & CmdPath,std::vector<std::string> & Args)3530b57cec5SDimitry Andric static void lexCommand(const char *Argv0, std::string &Message,
3540b57cec5SDimitry Andric                        const std::string &CommandLine, std::string &CmdPath,
3550b57cec5SDimitry Andric                        std::vector<std::string> &Args) {
3560b57cec5SDimitry Andric 
3570b57cec5SDimitry Andric   std::string Token;
3580b57cec5SDimitry Andric   std::string Command;
3590b57cec5SDimitry Andric   bool FoundPath = false;
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric   // first argument is the PATH.
3620b57cec5SDimitry Andric   // Skip repeated whitespace, leading whitespace and trailing whitespace.
3630b57cec5SDimitry Andric   for (std::size_t Pos = 0u; Pos <= CommandLine.size(); ++Pos) {
3640b57cec5SDimitry Andric     if ('\\' == CommandLine[Pos]) {
3650b57cec5SDimitry Andric       if (Pos + 1 < CommandLine.size())
3660b57cec5SDimitry Andric         Token.push_back(CommandLine[++Pos]);
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric       continue;
3690b57cec5SDimitry Andric     }
3700b57cec5SDimitry Andric     if (' ' == CommandLine[Pos] || CommandLine.size() == Pos) {
3710b57cec5SDimitry Andric       if (Token.empty())
3720b57cec5SDimitry Andric         continue;
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric       if (!FoundPath) {
3750b57cec5SDimitry Andric         Command = Token;
3760b57cec5SDimitry Andric         FoundPath = true;
3770b57cec5SDimitry Andric         Token.clear();
3780b57cec5SDimitry Andric         continue;
3790b57cec5SDimitry Andric       }
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric       Args.push_back(Token);
3820b57cec5SDimitry Andric       Token.clear();
3830b57cec5SDimitry Andric       continue;
3840b57cec5SDimitry Andric     }
3850b57cec5SDimitry Andric     Token.push_back(CommandLine[Pos]);
3860b57cec5SDimitry Andric   }
3870b57cec5SDimitry Andric 
3880b57cec5SDimitry Andric   auto Path = FindProgramByName(Command, Argv0, (void *)(intptr_t)&lexCommand);
3890b57cec5SDimitry Andric   if (!Path) {
3900b57cec5SDimitry Andric     Message = std::string("Cannot find '") + Command +
3910b57cec5SDimitry Andric               "' in PATH: " + Path.getError().message() + "\n";
3920b57cec5SDimitry Andric     return;
3930b57cec5SDimitry Andric   }
3940b57cec5SDimitry Andric   CmdPath = *Path;
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric   Message = "Found command in: " + CmdPath + "\n";
3970b57cec5SDimitry Andric }
3980b57cec5SDimitry Andric 
3990b57cec5SDimitry Andric // Custom execution environment create method, takes the execution command
4000b57cec5SDimitry Andric // as arguments
createCustomCompiler(const char * Argv0,std::string & Message,const std::string & CompileCommandLine)4010b57cec5SDimitry Andric AbstractInterpreter *AbstractInterpreter::createCustomCompiler(
4020b57cec5SDimitry Andric     const char *Argv0, std::string &Message,
4030b57cec5SDimitry Andric     const std::string &CompileCommandLine) {
4040b57cec5SDimitry Andric 
4050b57cec5SDimitry Andric   std::string CmdPath;
4060b57cec5SDimitry Andric   std::vector<std::string> Args;
4070b57cec5SDimitry Andric   lexCommand(Argv0, Message, CompileCommandLine, CmdPath, Args);
4080b57cec5SDimitry Andric   if (CmdPath.empty())
4090b57cec5SDimitry Andric     return nullptr;
4100b57cec5SDimitry Andric 
4110b57cec5SDimitry Andric   return new CustomCompiler(CmdPath, Args);
4120b57cec5SDimitry Andric }
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric // Custom execution environment create method, takes the execution command
4150b57cec5SDimitry Andric // as arguments
4160b57cec5SDimitry Andric AbstractInterpreter *
createCustomExecutor(const char * Argv0,std::string & Message,const std::string & ExecCommandLine)4170b57cec5SDimitry Andric AbstractInterpreter::createCustomExecutor(const char *Argv0,
4180b57cec5SDimitry Andric                                           std::string &Message,
4190b57cec5SDimitry Andric                                           const std::string &ExecCommandLine) {
4200b57cec5SDimitry Andric 
4210b57cec5SDimitry Andric   std::string CmdPath;
4220b57cec5SDimitry Andric   std::vector<std::string> Args;
4230b57cec5SDimitry Andric   lexCommand(Argv0, Message, ExecCommandLine, CmdPath, Args);
4240b57cec5SDimitry Andric   if (CmdPath.empty())
4250b57cec5SDimitry Andric     return nullptr;
4260b57cec5SDimitry Andric 
4270b57cec5SDimitry Andric   return new CustomExecutor(CmdPath, Args);
4280b57cec5SDimitry Andric }
4290b57cec5SDimitry Andric 
4300b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4310b57cec5SDimitry Andric // LLC Implementation of AbstractIntepreter interface
4320b57cec5SDimitry Andric //
OutputCode(const std::string & Bitcode,std::string & OutputAsmFile,unsigned Timeout,unsigned MemoryLimit)4330b57cec5SDimitry Andric Expected<CC::FileType> LLC::OutputCode(const std::string &Bitcode,
4340b57cec5SDimitry Andric                                        std::string &OutputAsmFile,
4350b57cec5SDimitry Andric                                        unsigned Timeout, unsigned MemoryLimit) {
4360b57cec5SDimitry Andric   const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s");
4370b57cec5SDimitry Andric 
4380b57cec5SDimitry Andric   SmallString<128> UniqueFile;
4390b57cec5SDimitry Andric   std::error_code EC =
4400b57cec5SDimitry Andric       sys::fs::createUniqueFile(Bitcode + "-%%%%%%%" + Suffix, UniqueFile);
4410b57cec5SDimitry Andric   if (EC) {
4420b57cec5SDimitry Andric     errs() << "Error making unique filename: " << EC.message() << "\n";
4430b57cec5SDimitry Andric     exit(1);
4440b57cec5SDimitry Andric   }
4457a6dacacSDimitry Andric   OutputAsmFile = std::string(UniqueFile);
4460b57cec5SDimitry Andric   std::vector<StringRef> LLCArgs;
4470b57cec5SDimitry Andric   LLCArgs.push_back(LLCPath);
4480b57cec5SDimitry Andric 
4490b57cec5SDimitry Andric   // Add any extra LLC args.
4500b57cec5SDimitry Andric   for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
4510b57cec5SDimitry Andric     LLCArgs.push_back(ToolArgs[i]);
4520b57cec5SDimitry Andric 
4530b57cec5SDimitry Andric   LLCArgs.push_back("-o");
4540b57cec5SDimitry Andric   LLCArgs.push_back(OutputAsmFile); // Output to the Asm file
4550b57cec5SDimitry Andric   LLCArgs.push_back(Bitcode);       // This is the input bitcode
4560b57cec5SDimitry Andric 
4570b57cec5SDimitry Andric   if (UseIntegratedAssembler)
4580b57cec5SDimitry Andric     LLCArgs.push_back("-filetype=obj");
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric   outs() << (UseIntegratedAssembler ? "<llc-ia>" : "<llc>");
4610b57cec5SDimitry Andric   outs().flush();
4620b57cec5SDimitry Andric   LLVM_DEBUG(errs() << "\nAbout to run:\t";
463349cc55cSDimitry Andric              for (unsigned i = 0, e = LLCArgs.size(); i != e; ++i) errs()
4640b57cec5SDimitry Andric              << " " << LLCArgs[i];
4650b57cec5SDimitry Andric              errs() << "\n";);
4660b57cec5SDimitry Andric   if (RunProgramWithTimeout(LLCPath, LLCArgs, "", "", "", Timeout, MemoryLimit))
4670b57cec5SDimitry Andric     return ProcessFailure(LLCPath, LLCArgs, Timeout, MemoryLimit);
4680b57cec5SDimitry Andric   return UseIntegratedAssembler ? CC::ObjectFile : CC::AsmFile;
4690b57cec5SDimitry Andric }
4700b57cec5SDimitry Andric 
compileProgram(const std::string & Bitcode,unsigned Timeout,unsigned MemoryLimit)4710b57cec5SDimitry Andric Error LLC::compileProgram(const std::string &Bitcode, unsigned Timeout,
4720b57cec5SDimitry Andric                           unsigned MemoryLimit) {
4730b57cec5SDimitry Andric   std::string OutputAsmFile;
4740b57cec5SDimitry Andric   Expected<CC::FileType> Result =
4750b57cec5SDimitry Andric       OutputCode(Bitcode, OutputAsmFile, Timeout, MemoryLimit);
4760b57cec5SDimitry Andric   sys::fs::remove(OutputAsmFile);
4770b57cec5SDimitry Andric   if (Error E = Result.takeError())
4780b57cec5SDimitry Andric     return E;
4790b57cec5SDimitry Andric   return Error::success();
4800b57cec5SDimitry Andric }
4810b57cec5SDimitry Andric 
ExecuteProgram(const std::string & Bitcode,const std::vector<std::string> & Args,const std::string & InputFile,const std::string & OutputFile,const std::vector<std::string> & ArgsForCC,const std::vector<std::string> & SharedLibs,unsigned Timeout,unsigned MemoryLimit)4820b57cec5SDimitry Andric Expected<int> LLC::ExecuteProgram(const std::string &Bitcode,
4830b57cec5SDimitry Andric                                   const std::vector<std::string> &Args,
4840b57cec5SDimitry Andric                                   const std::string &InputFile,
4850b57cec5SDimitry Andric                                   const std::string &OutputFile,
4860b57cec5SDimitry Andric                                   const std::vector<std::string> &ArgsForCC,
4870b57cec5SDimitry Andric                                   const std::vector<std::string> &SharedLibs,
4880b57cec5SDimitry Andric                                   unsigned Timeout, unsigned MemoryLimit) {
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric   std::string OutputAsmFile;
4910b57cec5SDimitry Andric   Expected<CC::FileType> FileKind =
4920b57cec5SDimitry Andric       OutputCode(Bitcode, OutputAsmFile, Timeout, MemoryLimit);
4930b57cec5SDimitry Andric   FileRemover OutFileRemover(OutputAsmFile, !SaveTemps);
4940b57cec5SDimitry Andric   if (Error E = FileKind.takeError())
4950b57cec5SDimitry Andric     return std::move(E);
4960b57cec5SDimitry Andric 
4970b57cec5SDimitry Andric   std::vector<std::string> CCArgs(ArgsForCC);
498e8d8bef9SDimitry Andric   llvm::append_range(CCArgs, SharedLibs);
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric   // Assuming LLC worked, compile the result with CC and run it.
5010b57cec5SDimitry Andric   return cc->ExecuteProgram(OutputAsmFile, Args, *FileKind, InputFile,
5020b57cec5SDimitry Andric                             OutputFile, CCArgs, Timeout, MemoryLimit);
5030b57cec5SDimitry Andric }
5040b57cec5SDimitry Andric 
5050b57cec5SDimitry Andric /// createLLC - Try to find the LLC executable
5060b57cec5SDimitry Andric ///
createLLC(const char * Argv0,std::string & Message,const std::string & CCBinary,const std::vector<std::string> * Args,const std::vector<std::string> * CCArgs,bool UseIntegratedAssembler)5070b57cec5SDimitry Andric LLC *AbstractInterpreter::createLLC(const char *Argv0, std::string &Message,
5080b57cec5SDimitry Andric                                     const std::string &CCBinary,
5090b57cec5SDimitry Andric                                     const std::vector<std::string> *Args,
5100b57cec5SDimitry Andric                                     const std::vector<std::string> *CCArgs,
5110b57cec5SDimitry Andric                                     bool UseIntegratedAssembler) {
5120b57cec5SDimitry Andric   ErrorOr<std::string> LLCPath =
5130b57cec5SDimitry Andric       FindProgramByName("llc", Argv0, (void *)(intptr_t)&createLLC);
5140b57cec5SDimitry Andric   if (!LLCPath) {
5150b57cec5SDimitry Andric     Message = LLCPath.getError().message() + "\n";
5160b57cec5SDimitry Andric     return nullptr;
5170b57cec5SDimitry Andric   }
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric   CC *cc = CC::create(Argv0, Message, CCBinary, CCArgs);
5200b57cec5SDimitry Andric   if (!cc) {
5210b57cec5SDimitry Andric     errs() << Message << "\n";
5220b57cec5SDimitry Andric     exit(1);
5230b57cec5SDimitry Andric   }
5240b57cec5SDimitry Andric   Message = "Found llc: " + *LLCPath + "\n";
5250b57cec5SDimitry Andric   return new LLC(*LLCPath, cc, Args, UseIntegratedAssembler);
5260b57cec5SDimitry Andric }
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric //===---------------------------------------------------------------------===//
5290b57cec5SDimitry Andric // JIT Implementation of AbstractIntepreter interface
5300b57cec5SDimitry Andric //
5310b57cec5SDimitry Andric namespace {
5320b57cec5SDimitry Andric class JIT : public AbstractInterpreter {
5330b57cec5SDimitry Andric   std::string LLIPath;               // The path to the LLI executable
5340b57cec5SDimitry Andric   std::vector<std::string> ToolArgs; // Args to pass to LLI
5350b57cec5SDimitry Andric public:
JIT(const std::string & Path,const std::vector<std::string> * Args)5360b57cec5SDimitry Andric   JIT(const std::string &Path, const std::vector<std::string> *Args)
5370b57cec5SDimitry Andric       : LLIPath(Path) {
5380b57cec5SDimitry Andric     ToolArgs.clear();
5390b57cec5SDimitry Andric     if (Args) {
5400b57cec5SDimitry Andric       ToolArgs = *Args;
5410b57cec5SDimitry Andric     }
5420b57cec5SDimitry Andric   }
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric   Expected<int> ExecuteProgram(
5450b57cec5SDimitry Andric       const std::string &Bitcode, const std::vector<std::string> &Args,
5460b57cec5SDimitry Andric       const std::string &InputFile, const std::string &OutputFile,
5470b57cec5SDimitry Andric       const std::vector<std::string> &CCArgs = std::vector<std::string>(),
5480b57cec5SDimitry Andric       const std::vector<std::string> &SharedLibs = std::vector<std::string>(),
5490b57cec5SDimitry Andric       unsigned Timeout = 0, unsigned MemoryLimit = 0) override;
5500b57cec5SDimitry Andric };
5510b57cec5SDimitry Andric }
5520b57cec5SDimitry Andric 
ExecuteProgram(const std::string & Bitcode,const std::vector<std::string> & Args,const std::string & InputFile,const std::string & OutputFile,const std::vector<std::string> & CCArgs,const std::vector<std::string> & SharedLibs,unsigned Timeout,unsigned MemoryLimit)5530b57cec5SDimitry Andric Expected<int> JIT::ExecuteProgram(const std::string &Bitcode,
5540b57cec5SDimitry Andric                                   const std::vector<std::string> &Args,
5550b57cec5SDimitry Andric                                   const std::string &InputFile,
5560b57cec5SDimitry Andric                                   const std::string &OutputFile,
5570b57cec5SDimitry Andric                                   const std::vector<std::string> &CCArgs,
5580b57cec5SDimitry Andric                                   const std::vector<std::string> &SharedLibs,
5590b57cec5SDimitry Andric                                   unsigned Timeout, unsigned MemoryLimit) {
5600b57cec5SDimitry Andric   // Construct a vector of parameters, incorporating those from the command-line
5610b57cec5SDimitry Andric   std::vector<StringRef> JITArgs;
5628bcb0991SDimitry Andric   JITArgs.push_back(LLIPath);
5630b57cec5SDimitry Andric   JITArgs.push_back("-force-interpreter=false");
5640b57cec5SDimitry Andric 
5650b57cec5SDimitry Andric   // Add any extra LLI args.
5660b57cec5SDimitry Andric   for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
5670b57cec5SDimitry Andric     JITArgs.push_back(ToolArgs[i]);
5680b57cec5SDimitry Andric 
5690b57cec5SDimitry Andric   for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) {
5700b57cec5SDimitry Andric     JITArgs.push_back("-load");
5710b57cec5SDimitry Andric     JITArgs.push_back(SharedLibs[i]);
5720b57cec5SDimitry Andric   }
5738bcb0991SDimitry Andric   JITArgs.push_back(Bitcode);
5740b57cec5SDimitry Andric   // Add optional parameters to the running program from Argv
5750b57cec5SDimitry Andric   for (unsigned i = 0, e = Args.size(); i != e; ++i)
5760b57cec5SDimitry Andric     JITArgs.push_back(Args[i]);
5770b57cec5SDimitry Andric 
5780b57cec5SDimitry Andric   outs() << "<jit>";
5790b57cec5SDimitry Andric   outs().flush();
5800b57cec5SDimitry Andric   LLVM_DEBUG(errs() << "\nAbout to run:\t";
581349cc55cSDimitry Andric              for (unsigned i = 0, e = JITArgs.size(); i != e; ++i) errs()
5820b57cec5SDimitry Andric              << " " << JITArgs[i];
5830b57cec5SDimitry Andric              errs() << "\n";);
5840b57cec5SDimitry Andric   LLVM_DEBUG(errs() << "\nSending output to " << OutputFile << "\n");
5850b57cec5SDimitry Andric   return RunProgramWithTimeout(LLIPath, JITArgs, InputFile, OutputFile,
5860b57cec5SDimitry Andric                                OutputFile, Timeout, MemoryLimit);
5870b57cec5SDimitry Andric }
5880b57cec5SDimitry Andric 
5890b57cec5SDimitry Andric /// createJIT - Try to find the LLI executable
5900b57cec5SDimitry Andric ///
5910b57cec5SDimitry Andric AbstractInterpreter *
createJIT(const char * Argv0,std::string & Message,const std::vector<std::string> * Args)5920b57cec5SDimitry Andric AbstractInterpreter::createJIT(const char *Argv0, std::string &Message,
5930b57cec5SDimitry Andric                                const std::vector<std::string> *Args) {
5940b57cec5SDimitry Andric   if (ErrorOr<std::string> LLIPath =
5950b57cec5SDimitry Andric           FindProgramByName("lli", Argv0, (void *)(intptr_t)&createJIT)) {
5960b57cec5SDimitry Andric     Message = "Found lli: " + *LLIPath + "\n";
5970b57cec5SDimitry Andric     return new JIT(*LLIPath, Args);
5980b57cec5SDimitry Andric   } else {
5990b57cec5SDimitry Andric     Message = LLIPath.getError().message() + "\n";
6000b57cec5SDimitry Andric     return nullptr;
6010b57cec5SDimitry Andric   }
6020b57cec5SDimitry Andric }
6030b57cec5SDimitry Andric 
6040b57cec5SDimitry Andric //===---------------------------------------------------------------------===//
6050b57cec5SDimitry Andric // CC abstraction
6060b57cec5SDimitry Andric //
6070b57cec5SDimitry Andric 
IsARMArchitecture(std::vector<StringRef> Args)6080b57cec5SDimitry Andric static bool IsARMArchitecture(std::vector<StringRef> Args) {
6090b57cec5SDimitry Andric   for (size_t I = 0; I < Args.size(); ++I) {
610fe6060f1SDimitry Andric     if (!Args[I].equals_insensitive("-arch"))
6110b57cec5SDimitry Andric       continue;
6120b57cec5SDimitry Andric     ++I;
6130b57cec5SDimitry Andric     if (I == Args.size())
6140b57cec5SDimitry Andric       break;
61506c3fb27SDimitry Andric     if (Args[I].starts_with_insensitive("arm"))
6160b57cec5SDimitry Andric       return true;
6170b57cec5SDimitry Andric   }
6180b57cec5SDimitry Andric 
6190b57cec5SDimitry Andric   return false;
6200b57cec5SDimitry Andric }
6210b57cec5SDimitry Andric 
ExecuteProgram(const std::string & ProgramFile,const std::vector<std::string> & Args,FileType fileType,const std::string & InputFile,const std::string & OutputFile,const std::vector<std::string> & ArgsForCC,unsigned Timeout,unsigned MemoryLimit)6220b57cec5SDimitry Andric Expected<int> CC::ExecuteProgram(const std::string &ProgramFile,
6230b57cec5SDimitry Andric                                  const std::vector<std::string> &Args,
6240b57cec5SDimitry Andric                                  FileType fileType,
6250b57cec5SDimitry Andric                                  const std::string &InputFile,
6260b57cec5SDimitry Andric                                  const std::string &OutputFile,
6270b57cec5SDimitry Andric                                  const std::vector<std::string> &ArgsForCC,
6280b57cec5SDimitry Andric                                  unsigned Timeout, unsigned MemoryLimit) {
6290b57cec5SDimitry Andric   std::vector<StringRef> CCArgs;
6300b57cec5SDimitry Andric 
6310b57cec5SDimitry Andric   CCArgs.push_back(CCPath);
6320b57cec5SDimitry Andric 
6330b57cec5SDimitry Andric   if (TargetTriple.getArch() == Triple::x86)
6340b57cec5SDimitry Andric     CCArgs.push_back("-m32");
6350b57cec5SDimitry Andric 
6360b57cec5SDimitry Andric   for (std::vector<std::string>::const_iterator I = ccArgs.begin(),
6370b57cec5SDimitry Andric                                                 E = ccArgs.end();
6380b57cec5SDimitry Andric        I != E; ++I)
6390b57cec5SDimitry Andric     CCArgs.push_back(*I);
6400b57cec5SDimitry Andric 
6410b57cec5SDimitry Andric   // Specify -x explicitly in case the extension is wonky
6420b57cec5SDimitry Andric   if (fileType != ObjectFile) {
6430b57cec5SDimitry Andric     CCArgs.push_back("-x");
6440b57cec5SDimitry Andric     if (fileType == CFile) {
6450b57cec5SDimitry Andric       CCArgs.push_back("c");
6460b57cec5SDimitry Andric       CCArgs.push_back("-fno-strict-aliasing");
6470b57cec5SDimitry Andric     } else {
6480b57cec5SDimitry Andric       CCArgs.push_back("assembler");
6490b57cec5SDimitry Andric 
6500b57cec5SDimitry Andric       // For ARM architectures we don't want this flag. bugpoint isn't
6510b57cec5SDimitry Andric       // explicitly told what architecture it is working on, so we get
6520b57cec5SDimitry Andric       // it from cc flags
6530b57cec5SDimitry Andric       if (TargetTriple.isOSDarwin() && !IsARMArchitecture(CCArgs))
6540b57cec5SDimitry Andric         CCArgs.push_back("-force_cpusubtype_ALL");
6550b57cec5SDimitry Andric     }
6560b57cec5SDimitry Andric   }
6570b57cec5SDimitry Andric 
6580b57cec5SDimitry Andric   CCArgs.push_back(ProgramFile); // Specify the input filename.
6590b57cec5SDimitry Andric 
6600b57cec5SDimitry Andric   CCArgs.push_back("-x");
6610b57cec5SDimitry Andric   CCArgs.push_back("none");
6620b57cec5SDimitry Andric   CCArgs.push_back("-o");
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric   SmallString<128> OutputBinary;
6650b57cec5SDimitry Andric   std::error_code EC =
6660b57cec5SDimitry Andric       sys::fs::createUniqueFile(ProgramFile + "-%%%%%%%.cc.exe", OutputBinary);
6670b57cec5SDimitry Andric   if (EC) {
6680b57cec5SDimitry Andric     errs() << "Error making unique filename: " << EC.message() << "\n";
6690b57cec5SDimitry Andric     exit(1);
6700b57cec5SDimitry Andric   }
6710b57cec5SDimitry Andric   CCArgs.push_back(OutputBinary); // Output to the right file...
6720b57cec5SDimitry Andric 
6730b57cec5SDimitry Andric   // Add any arguments intended for CC. We locate them here because this is
6740b57cec5SDimitry Andric   // most likely -L and -l options that need to come before other libraries but
6750b57cec5SDimitry Andric   // after the source. Other options won't be sensitive to placement on the
6760b57cec5SDimitry Andric   // command line, so this should be safe.
6770b57cec5SDimitry Andric   for (unsigned i = 0, e = ArgsForCC.size(); i != e; ++i)
6780b57cec5SDimitry Andric     CCArgs.push_back(ArgsForCC[i]);
6790b57cec5SDimitry Andric 
6800b57cec5SDimitry Andric   CCArgs.push_back("-lm"); // Hard-code the math library...
6810b57cec5SDimitry Andric   CCArgs.push_back("-O2"); // Optimize the program a bit...
6820b57cec5SDimitry Andric   if (TargetTriple.getArch() == Triple::sparc)
6830b57cec5SDimitry Andric     CCArgs.push_back("-mcpu=v9");
6840b57cec5SDimitry Andric 
6850b57cec5SDimitry Andric   outs() << "<CC>";
6860b57cec5SDimitry Andric   outs().flush();
6870b57cec5SDimitry Andric   LLVM_DEBUG(errs() << "\nAbout to run:\t";
688349cc55cSDimitry Andric              for (unsigned i = 0, e = CCArgs.size(); i != e; ++i) errs()
6890b57cec5SDimitry Andric              << " " << CCArgs[i];
6900b57cec5SDimitry Andric              errs() << "\n";);
6910b57cec5SDimitry Andric   if (RunProgramWithTimeout(CCPath, CCArgs, "", "", ""))
6920b57cec5SDimitry Andric     return ProcessFailure(CCPath, CCArgs);
6930b57cec5SDimitry Andric 
6940b57cec5SDimitry Andric   std::vector<StringRef> ProgramArgs;
6950b57cec5SDimitry Andric 
6960b57cec5SDimitry Andric   // Declared here so that the destructor only runs after
6970b57cec5SDimitry Andric   // ProgramArgs is used.
6980b57cec5SDimitry Andric   std::string Exec;
6990b57cec5SDimitry Andric 
7000b57cec5SDimitry Andric   if (RemoteClientPath.empty())
7010b57cec5SDimitry Andric     ProgramArgs.push_back(OutputBinary);
7020b57cec5SDimitry Andric   else {
7030b57cec5SDimitry Andric     ProgramArgs.push_back(RemoteClientPath);
7040b57cec5SDimitry Andric     ProgramArgs.push_back(RemoteHost);
7050b57cec5SDimitry Andric     if (!RemoteUser.empty()) {
7060b57cec5SDimitry Andric       ProgramArgs.push_back("-l");
7070b57cec5SDimitry Andric       ProgramArgs.push_back(RemoteUser);
7080b57cec5SDimitry Andric     }
7090b57cec5SDimitry Andric     if (!RemotePort.empty()) {
7100b57cec5SDimitry Andric       ProgramArgs.push_back("-p");
7110b57cec5SDimitry Andric       ProgramArgs.push_back(RemotePort);
7120b57cec5SDimitry Andric     }
7130b57cec5SDimitry Andric     if (!RemoteExtra.empty()) {
7140b57cec5SDimitry Andric       ProgramArgs.push_back(RemoteExtra);
7150b57cec5SDimitry Andric     }
7160b57cec5SDimitry Andric 
7170b57cec5SDimitry Andric     // Full path to the binary. We need to cd to the exec directory because
7180b57cec5SDimitry Andric     // there is a dylib there that the exec expects to find in the CWD
7190b57cec5SDimitry Andric     char *env_pwd = getenv("PWD");
7200b57cec5SDimitry Andric     Exec = "cd ";
7210b57cec5SDimitry Andric     Exec += env_pwd;
7220b57cec5SDimitry Andric     Exec += "; ./";
7230b57cec5SDimitry Andric     Exec += OutputBinary.c_str();
7240b57cec5SDimitry Andric     ProgramArgs.push_back(Exec);
7250b57cec5SDimitry Andric   }
7260b57cec5SDimitry Andric 
7270b57cec5SDimitry Andric   // Add optional parameters to the running program from Argv
7280b57cec5SDimitry Andric   for (unsigned i = 0, e = Args.size(); i != e; ++i)
7290b57cec5SDimitry Andric     ProgramArgs.push_back(Args[i]);
7300b57cec5SDimitry Andric 
7310b57cec5SDimitry Andric   // Now that we have a binary, run it!
7320b57cec5SDimitry Andric   outs() << "<program>";
7330b57cec5SDimitry Andric   outs().flush();
7340b57cec5SDimitry Andric   LLVM_DEBUG(
7350b57cec5SDimitry Andric       errs() << "\nAbout to run:\t";
736349cc55cSDimitry Andric       for (unsigned i = 0, e = ProgramArgs.size(); i != e; ++i) errs()
7370b57cec5SDimitry Andric       << " " << ProgramArgs[i];
7380b57cec5SDimitry Andric       errs() << "\n";);
7390b57cec5SDimitry Andric 
7400b57cec5SDimitry Andric   FileRemover OutputBinaryRemover(OutputBinary.str(), !SaveTemps);
7410b57cec5SDimitry Andric 
7420b57cec5SDimitry Andric   if (RemoteClientPath.empty()) {
7430b57cec5SDimitry Andric     LLVM_DEBUG(errs() << "<run locally>");
7440b57cec5SDimitry Andric     std::string Error;
7450b57cec5SDimitry Andric     int ExitCode = RunProgramWithTimeout(OutputBinary.str(), ProgramArgs,
7460b57cec5SDimitry Andric                                          InputFile, OutputFile, OutputFile,
7470b57cec5SDimitry Andric                                          Timeout, MemoryLimit, &Error);
7480b57cec5SDimitry Andric     // Treat a signal (usually SIGSEGV) or timeout as part of the program output
7490b57cec5SDimitry Andric     // so that crash-causing miscompilation is handled seamlessly.
7500b57cec5SDimitry Andric     if (ExitCode < -1) {
7510b57cec5SDimitry Andric       std::ofstream outFile(OutputFile.c_str(), std::ios_base::app);
7520b57cec5SDimitry Andric       outFile << Error << '\n';
7530b57cec5SDimitry Andric       outFile.close();
7540b57cec5SDimitry Andric     }
7550b57cec5SDimitry Andric     return ExitCode;
7560b57cec5SDimitry Andric   } else {
7570b57cec5SDimitry Andric     outs() << "<run remotely>";
7580b57cec5SDimitry Andric     outs().flush();
7590b57cec5SDimitry Andric     return RunProgramRemotelyWithTimeout(RemoteClientPath, ProgramArgs,
7600b57cec5SDimitry Andric                                          InputFile, OutputFile, OutputFile,
7610b57cec5SDimitry Andric                                          Timeout, MemoryLimit);
7620b57cec5SDimitry Andric   }
7630b57cec5SDimitry Andric }
7640b57cec5SDimitry Andric 
MakeSharedObject(const std::string & InputFile,FileType fileType,std::string & OutputFile,const std::vector<std::string> & ArgsForCC)7650b57cec5SDimitry Andric Error CC::MakeSharedObject(const std::string &InputFile, FileType fileType,
7660b57cec5SDimitry Andric                            std::string &OutputFile,
7670b57cec5SDimitry Andric                            const std::vector<std::string> &ArgsForCC) {
7680b57cec5SDimitry Andric   SmallString<128> UniqueFilename;
7690b57cec5SDimitry Andric   std::error_code EC = sys::fs::createUniqueFile(
7700b57cec5SDimitry Andric       InputFile + "-%%%%%%%" + LTDL_SHLIB_EXT, UniqueFilename);
7710b57cec5SDimitry Andric   if (EC) {
7720b57cec5SDimitry Andric     errs() << "Error making unique filename: " << EC.message() << "\n";
7730b57cec5SDimitry Andric     exit(1);
7740b57cec5SDimitry Andric   }
7757a6dacacSDimitry Andric   OutputFile = std::string(UniqueFilename);
7760b57cec5SDimitry Andric 
7770b57cec5SDimitry Andric   std::vector<StringRef> CCArgs;
7780b57cec5SDimitry Andric 
7790b57cec5SDimitry Andric   CCArgs.push_back(CCPath);
7800b57cec5SDimitry Andric 
7810b57cec5SDimitry Andric   if (TargetTriple.getArch() == Triple::x86)
7820b57cec5SDimitry Andric     CCArgs.push_back("-m32");
7830b57cec5SDimitry Andric 
7840b57cec5SDimitry Andric   for (std::vector<std::string>::const_iterator I = ccArgs.begin(),
7850b57cec5SDimitry Andric                                                 E = ccArgs.end();
7860b57cec5SDimitry Andric        I != E; ++I)
7870b57cec5SDimitry Andric     CCArgs.push_back(*I);
7880b57cec5SDimitry Andric 
7890b57cec5SDimitry Andric   // Compile the C/asm file into a shared object
7900b57cec5SDimitry Andric   if (fileType != ObjectFile) {
7910b57cec5SDimitry Andric     CCArgs.push_back("-x");
7920b57cec5SDimitry Andric     CCArgs.push_back(fileType == AsmFile ? "assembler" : "c");
7930b57cec5SDimitry Andric   }
7940b57cec5SDimitry Andric   CCArgs.push_back("-fno-strict-aliasing");
7950b57cec5SDimitry Andric   CCArgs.push_back(InputFile); // Specify the input filename.
7960b57cec5SDimitry Andric   CCArgs.push_back("-x");
7970b57cec5SDimitry Andric   CCArgs.push_back("none");
7980b57cec5SDimitry Andric   if (TargetTriple.getArch() == Triple::sparc)
7990b57cec5SDimitry Andric     CCArgs.push_back("-G"); // Compile a shared library, `-G' for Sparc
8000b57cec5SDimitry Andric   else if (TargetTriple.isOSDarwin()) {
8010b57cec5SDimitry Andric     // link all source files into a single module in data segment, rather than
8020b57cec5SDimitry Andric     // generating blocks. dynamic_lookup requires that you set
8030b57cec5SDimitry Andric     // MACOSX_DEPLOYMENT_TARGET=10.3 in your env.  FIXME: it would be better for
8040b57cec5SDimitry Andric     // bugpoint to just pass that in the environment of CC.
8050b57cec5SDimitry Andric     CCArgs.push_back("-single_module");
8060b57cec5SDimitry Andric     CCArgs.push_back("-dynamiclib"); // `-dynamiclib' for MacOS X/PowerPC
8070b57cec5SDimitry Andric     CCArgs.push_back("-undefined");
8080b57cec5SDimitry Andric     CCArgs.push_back("dynamic_lookup");
8090b57cec5SDimitry Andric   } else
8100b57cec5SDimitry Andric     CCArgs.push_back("-shared"); // `-shared' for Linux/X86, maybe others
8110b57cec5SDimitry Andric 
8120b57cec5SDimitry Andric   if (TargetTriple.getArch() == Triple::x86_64)
8130b57cec5SDimitry Andric     CCArgs.push_back("-fPIC"); // Requires shared objs to contain PIC
8140b57cec5SDimitry Andric 
8150b57cec5SDimitry Andric   if (TargetTriple.getArch() == Triple::sparc)
8160b57cec5SDimitry Andric     CCArgs.push_back("-mcpu=v9");
8170b57cec5SDimitry Andric 
8180b57cec5SDimitry Andric   CCArgs.push_back("-o");
8190b57cec5SDimitry Andric   CCArgs.push_back(OutputFile);         // Output to the right filename.
8200b57cec5SDimitry Andric   CCArgs.push_back("-O2");              // Optimize the program a bit.
8210b57cec5SDimitry Andric 
8220b57cec5SDimitry Andric   // Add any arguments intended for CC. We locate them here because this is
8230b57cec5SDimitry Andric   // most likely -L and -l options that need to come before other libraries but
8240b57cec5SDimitry Andric   // after the source. Other options won't be sensitive to placement on the
8250b57cec5SDimitry Andric   // command line, so this should be safe.
8260b57cec5SDimitry Andric   for (unsigned i = 0, e = ArgsForCC.size(); i != e; ++i)
8270b57cec5SDimitry Andric     CCArgs.push_back(ArgsForCC[i]);
8280b57cec5SDimitry Andric 
8290b57cec5SDimitry Andric   outs() << "<CC>";
8300b57cec5SDimitry Andric   outs().flush();
8310b57cec5SDimitry Andric   LLVM_DEBUG(errs() << "\nAbout to run:\t";
832349cc55cSDimitry Andric              for (unsigned i = 0, e = CCArgs.size(); i != e; ++i) errs()
8330b57cec5SDimitry Andric              << " " << CCArgs[i];
8340b57cec5SDimitry Andric              errs() << "\n";);
8350b57cec5SDimitry Andric   if (RunProgramWithTimeout(CCPath, CCArgs, "", "", ""))
8360b57cec5SDimitry Andric     return ProcessFailure(CCPath, CCArgs);
8370b57cec5SDimitry Andric   return Error::success();
8380b57cec5SDimitry Andric }
8390b57cec5SDimitry Andric 
8400b57cec5SDimitry Andric /// create - Try to find the CC executable
8410b57cec5SDimitry Andric ///
create(const char * Argv0,std::string & Message,const std::string & CCBinary,const std::vector<std::string> * Args)8420b57cec5SDimitry Andric CC *CC::create(const char *Argv0, std::string &Message,
8430b57cec5SDimitry Andric                const std::string &CCBinary,
8440b57cec5SDimitry Andric                const std::vector<std::string> *Args) {
8450b57cec5SDimitry Andric   auto CCPath = FindProgramByName(CCBinary, Argv0, (void *)(intptr_t)&create);
8460b57cec5SDimitry Andric   if (!CCPath) {
8470b57cec5SDimitry Andric     Message = "Cannot find `" + CCBinary + "' in PATH: " +
8480b57cec5SDimitry Andric               CCPath.getError().message() + "\n";
8490b57cec5SDimitry Andric     return nullptr;
8500b57cec5SDimitry Andric   }
8510b57cec5SDimitry Andric 
8520b57cec5SDimitry Andric   std::string RemoteClientPath;
8530b57cec5SDimitry Andric   if (!RemoteClient.empty()) {
8540b57cec5SDimitry Andric     auto Path = sys::findProgramByName(RemoteClient);
8550b57cec5SDimitry Andric     if (!Path) {
8560b57cec5SDimitry Andric       Message = "Cannot find `" + RemoteClient + "' in PATH: " +
8570b57cec5SDimitry Andric                 Path.getError().message() + "\n";
8580b57cec5SDimitry Andric       return nullptr;
8590b57cec5SDimitry Andric     }
8600b57cec5SDimitry Andric     RemoteClientPath = *Path;
8610b57cec5SDimitry Andric   }
8620b57cec5SDimitry Andric 
8630b57cec5SDimitry Andric   Message = "Found CC: " + *CCPath + "\n";
8640b57cec5SDimitry Andric   return new CC(*CCPath, RemoteClientPath, Args);
8650b57cec5SDimitry Andric }
866