Path: blob/main/contrib/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp
35230 views
//===-- ToolRunner.cpp ----------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the interfaces described in the ToolRunner.h file.9//10//===----------------------------------------------------------------------===//1112#include "ToolRunner.h"13#include "llvm/Config/config.h"14#include "llvm/Support/CommandLine.h"15#include "llvm/Support/Debug.h"16#include "llvm/Support/FileSystem.h"17#include "llvm/Support/FileUtilities.h"18#include "llvm/Support/Program.h"19#include "llvm/Support/raw_ostream.h"20#include <fstream>21#include <sstream>22#include <utility>23using namespace llvm;2425#define DEBUG_TYPE "toolrunner"2627namespace llvm {28cl::opt<bool> SaveTemps("save-temps", cl::init(false),29cl::desc("Save temporary files"));30}3132namespace {33cl::opt<std::string>34RemoteClient("remote-client",35cl::desc("Remote execution client (rsh/ssh)"));3637cl::opt<std::string> RemoteHost("remote-host",38cl::desc("Remote execution (rsh/ssh) host"));3940cl::opt<std::string> RemotePort("remote-port",41cl::desc("Remote execution (rsh/ssh) port"));4243cl::opt<std::string> RemoteUser("remote-user",44cl::desc("Remote execution (rsh/ssh) user id"));4546cl::opt<std::string>47RemoteExtra("remote-extra-options",48cl::desc("Remote execution (rsh/ssh) extra options"));49}5051/// RunProgramWithTimeout - This function provides an alternate interface52/// to the sys::Program::ExecuteAndWait interface.53/// @see sys::Program::ExecuteAndWait54static int RunProgramWithTimeout(StringRef ProgramPath,55ArrayRef<StringRef> Args, StringRef StdInFile,56StringRef StdOutFile, StringRef StdErrFile,57unsigned NumSeconds = 0,58unsigned MemoryLimit = 0,59std::string *ErrMsg = nullptr) {60std::optional<StringRef> Redirects[3] = {StdInFile, StdOutFile, StdErrFile};61return sys::ExecuteAndWait(ProgramPath, Args, std::nullopt, Redirects,62NumSeconds, MemoryLimit, ErrMsg);63}6465/// RunProgramRemotelyWithTimeout - This function runs the given program66/// remotely using the given remote client and the sys::Program::ExecuteAndWait.67/// Returns the remote program exit code or reports a remote client error if it68/// fails. Remote client is required to return 255 if it failed or program exit69/// code otherwise.70/// @see sys::Program::ExecuteAndWait71static int RunProgramRemotelyWithTimeout(72StringRef RemoteClientPath, ArrayRef<StringRef> Args, StringRef StdInFile,73StringRef StdOutFile, StringRef StdErrFile, unsigned NumSeconds = 0,74unsigned MemoryLimit = 0) {75std::optional<StringRef> Redirects[3] = {StdInFile, StdOutFile, StdErrFile};7677// Run the program remotely with the remote client78int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, std::nullopt,79Redirects, NumSeconds, MemoryLimit);8081// Has the remote client fail?82if (255 == ReturnCode) {83std::ostringstream OS;84OS << "\nError running remote client:\n ";85for (StringRef Arg : Args)86OS << " " << Arg.str();87OS << "\n";8889// The error message is in the output file, let's print it out from there.90std::string StdOutFileName = StdOutFile.str();91std::ifstream ErrorFile(StdOutFileName.c_str());92if (ErrorFile) {93std::copy(std::istreambuf_iterator<char>(ErrorFile),94std::istreambuf_iterator<char>(),95std::ostreambuf_iterator<char>(OS));96ErrorFile.close();97}9899errs() << OS.str();100}101102return ReturnCode;103}104105static Error ProcessFailure(StringRef ProgPath, ArrayRef<StringRef> Args,106unsigned Timeout = 0, unsigned MemoryLimit = 0) {107std::ostringstream OS;108OS << "\nError running tool:\n ";109for (StringRef Arg : Args)110OS << " " << Arg.str();111OS << "\n";112113// Rerun the compiler, capturing any error messages to print them.114SmallString<128> ErrorFilename;115std::error_code EC = sys::fs::createTemporaryFile(116"bugpoint.program_error_messages", "", ErrorFilename);117if (EC) {118errs() << "Error making unique filename: " << EC.message() << "\n";119exit(1);120}121122RunProgramWithTimeout(ProgPath, Args, "", ErrorFilename.str(),123ErrorFilename.str(), Timeout, MemoryLimit);124// FIXME: check return code ?125126// Print out the error messages generated by CC if possible...127std::ifstream ErrorFile(ErrorFilename.c_str());128if (ErrorFile) {129std::copy(std::istreambuf_iterator<char>(ErrorFile),130std::istreambuf_iterator<char>(),131std::ostreambuf_iterator<char>(OS));132ErrorFile.close();133}134135sys::fs::remove(ErrorFilename.c_str());136return make_error<StringError>(OS.str(), inconvertibleErrorCode());137}138139//===---------------------------------------------------------------------===//140// LLI Implementation of AbstractIntepreter interface141//142namespace {143class LLI : public AbstractInterpreter {144std::string LLIPath; // The path to the LLI executable145std::vector<std::string> ToolArgs; // Args to pass to LLI146public:147LLI(const std::string &Path, const std::vector<std::string> *Args)148: LLIPath(Path) {149ToolArgs.clear();150if (Args) {151ToolArgs = *Args;152}153}154155Expected<int> ExecuteProgram(156const std::string &Bitcode, const std::vector<std::string> &Args,157const std::string &InputFile, const std::string &OutputFile,158const std::vector<std::string> &CCArgs,159const std::vector<std::string> &SharedLibs = std::vector<std::string>(),160unsigned Timeout = 0, unsigned MemoryLimit = 0) override;161};162}163164Expected<int> LLI::ExecuteProgram(const std::string &Bitcode,165const std::vector<std::string> &Args,166const std::string &InputFile,167const std::string &OutputFile,168const std::vector<std::string> &CCArgs,169const std::vector<std::string> &SharedLibs,170unsigned Timeout, unsigned MemoryLimit) {171std::vector<StringRef> LLIArgs;172LLIArgs.push_back(LLIPath);173LLIArgs.push_back("-force-interpreter=true");174175for (std::vector<std::string>::const_iterator i = SharedLibs.begin(),176e = SharedLibs.end();177i != e; ++i) {178LLIArgs.push_back("-load");179LLIArgs.push_back(*i);180}181182// Add any extra LLI args.183for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)184LLIArgs.push_back(ToolArgs[i]);185186LLIArgs.push_back(Bitcode);187// Add optional parameters to the running program from Argv188for (unsigned i = 0, e = Args.size(); i != e; ++i)189LLIArgs.push_back(Args[i]);190191outs() << "<lli>";192outs().flush();193LLVM_DEBUG(errs() << "\nAbout to run:\t";194for (unsigned i = 0, e = LLIArgs.size(); i != e; ++i) errs()195<< " " << LLIArgs[i];196errs() << "\n";);197return RunProgramWithTimeout(LLIPath, LLIArgs, InputFile, OutputFile,198OutputFile, Timeout, MemoryLimit);199}200201void AbstractInterpreter::anchor() {}202203ErrorOr<std::string> llvm::FindProgramByName(const std::string &ExeName,204const char *Argv0,205void *MainAddr) {206// Check the directory that the calling program is in. We can do207// this if ProgramPath contains at least one / character, indicating that it208// is a relative path to the executable itself.209std::string Main = sys::fs::getMainExecutable(Argv0, MainAddr);210StringRef Result = sys::path::parent_path(Main);211if (ErrorOr<std::string> Path = sys::findProgramByName(ExeName, Result))212return *Path;213214// Check the user PATH.215return sys::findProgramByName(ExeName);216}217218// LLI create method - Try to find the LLI executable219AbstractInterpreter *220AbstractInterpreter::createLLI(const char *Argv0, std::string &Message,221const std::vector<std::string> *ToolArgs) {222if (ErrorOr<std::string> LLIPath =223FindProgramByName("lli", Argv0, (void *)(intptr_t)&createLLI)) {224Message = "Found lli: " + *LLIPath + "\n";225return new LLI(*LLIPath, ToolArgs);226} else {227Message = LLIPath.getError().message() + "\n";228return nullptr;229}230}231232//===---------------------------------------------------------------------===//233// Custom compiler command implementation of AbstractIntepreter interface234//235// Allows using a custom command for compiling the bitcode, thus allows, for236// example, to compile a bitcode fragment without linking or executing, then237// using a custom wrapper script to check for compiler errors.238namespace {239class CustomCompiler : public AbstractInterpreter {240std::string CompilerCommand;241std::vector<std::string> CompilerArgs;242243public:244CustomCompiler(const std::string &CompilerCmd,245std::vector<std::string> CompArgs)246: CompilerCommand(CompilerCmd), CompilerArgs(std::move(CompArgs)) {}247248Error compileProgram(const std::string &Bitcode, unsigned Timeout = 0,249unsigned MemoryLimit = 0) override;250251Expected<int> ExecuteProgram(252const std::string &Bitcode, const std::vector<std::string> &Args,253const std::string &InputFile, const std::string &OutputFile,254const std::vector<std::string> &CCArgs = std::vector<std::string>(),255const std::vector<std::string> &SharedLibs = std::vector<std::string>(),256unsigned Timeout = 0, unsigned MemoryLimit = 0) override {257return make_error<StringError>(258"Execution not supported with -compile-custom",259inconvertibleErrorCode());260}261};262}263264Error CustomCompiler::compileProgram(const std::string &Bitcode,265unsigned Timeout, unsigned MemoryLimit) {266267std::vector<StringRef> ProgramArgs;268ProgramArgs.push_back(CompilerCommand);269270for (const auto &Arg : CompilerArgs)271ProgramArgs.push_back(Arg);272ProgramArgs.push_back(Bitcode);273274// Add optional parameters to the running program from Argv275for (const auto &Arg : CompilerArgs)276ProgramArgs.push_back(Arg);277278if (RunProgramWithTimeout(CompilerCommand, ProgramArgs, "", "", "", Timeout,279MemoryLimit))280return ProcessFailure(CompilerCommand, ProgramArgs, Timeout, MemoryLimit);281return Error::success();282}283284//===---------------------------------------------------------------------===//285// Custom execution command implementation of AbstractIntepreter interface286//287// Allows using a custom command for executing the bitcode, thus allows,288// for example, to invoke a cross compiler for code generation followed by289// a simulator that executes the generated binary.290namespace {291class CustomExecutor : public AbstractInterpreter {292std::string ExecutionCommand;293std::vector<std::string> ExecutorArgs;294295public:296CustomExecutor(const std::string &ExecutionCmd,297std::vector<std::string> ExecArgs)298: ExecutionCommand(ExecutionCmd), ExecutorArgs(std::move(ExecArgs)) {}299300Expected<int> ExecuteProgram(301const std::string &Bitcode, const std::vector<std::string> &Args,302const std::string &InputFile, const std::string &OutputFile,303const std::vector<std::string> &CCArgs,304const std::vector<std::string> &SharedLibs = std::vector<std::string>(),305unsigned Timeout = 0, unsigned MemoryLimit = 0) override;306};307}308309Expected<int> CustomExecutor::ExecuteProgram(310const std::string &Bitcode, const std::vector<std::string> &Args,311const std::string &InputFile, const std::string &OutputFile,312const std::vector<std::string> &CCArgs,313const std::vector<std::string> &SharedLibs, unsigned Timeout,314unsigned MemoryLimit) {315316std::vector<StringRef> ProgramArgs;317ProgramArgs.push_back(ExecutionCommand);318319for (std::size_t i = 0; i < ExecutorArgs.size(); ++i)320ProgramArgs.push_back(ExecutorArgs[i]);321ProgramArgs.push_back(Bitcode);322323// Add optional parameters to the running program from Argv324for (unsigned i = 0, e = Args.size(); i != e; ++i)325ProgramArgs.push_back(Args[i]);326327return RunProgramWithTimeout(ExecutionCommand, ProgramArgs, InputFile,328OutputFile, OutputFile, Timeout, MemoryLimit);329}330331// Tokenize the CommandLine to the command and the args to allow332// defining a full command line as the command instead of just the333// executed program. We cannot just pass the whole string after the command334// as a single argument because then the program sees only a single335// command line argument (with spaces in it: "foo bar" instead336// of "foo" and "bar").337//338// Spaces are used as a delimiter; however repeated, leading, and trailing339// whitespace are ignored. Simple escaping is allowed via the '\'340// character, as seen below:341//342// Two consecutive '\' evaluate to a single '\'.343// A space after a '\' evaluates to a space that is not interpreted as a344// delimiter.345// Any other instances of the '\' character are removed.346//347// Example:348// '\\' -> '\'349// '\ ' -> ' '350// 'exa\mple' -> 'example'351//352static void lexCommand(const char *Argv0, std::string &Message,353const std::string &CommandLine, std::string &CmdPath,354std::vector<std::string> &Args) {355356std::string Token;357std::string Command;358bool FoundPath = false;359360// first argument is the PATH.361// Skip repeated whitespace, leading whitespace and trailing whitespace.362for (std::size_t Pos = 0u; Pos <= CommandLine.size(); ++Pos) {363if ('\\' == CommandLine[Pos]) {364if (Pos + 1 < CommandLine.size())365Token.push_back(CommandLine[++Pos]);366367continue;368}369if (' ' == CommandLine[Pos] || CommandLine.size() == Pos) {370if (Token.empty())371continue;372373if (!FoundPath) {374Command = Token;375FoundPath = true;376Token.clear();377continue;378}379380Args.push_back(Token);381Token.clear();382continue;383}384Token.push_back(CommandLine[Pos]);385}386387auto Path = FindProgramByName(Command, Argv0, (void *)(intptr_t)&lexCommand);388if (!Path) {389Message = std::string("Cannot find '") + Command +390"' in PATH: " + Path.getError().message() + "\n";391return;392}393CmdPath = *Path;394395Message = "Found command in: " + CmdPath + "\n";396}397398// Custom execution environment create method, takes the execution command399// as arguments400AbstractInterpreter *AbstractInterpreter::createCustomCompiler(401const char *Argv0, std::string &Message,402const std::string &CompileCommandLine) {403404std::string CmdPath;405std::vector<std::string> Args;406lexCommand(Argv0, Message, CompileCommandLine, CmdPath, Args);407if (CmdPath.empty())408return nullptr;409410return new CustomCompiler(CmdPath, Args);411}412413// Custom execution environment create method, takes the execution command414// as arguments415AbstractInterpreter *416AbstractInterpreter::createCustomExecutor(const char *Argv0,417std::string &Message,418const std::string &ExecCommandLine) {419420std::string CmdPath;421std::vector<std::string> Args;422lexCommand(Argv0, Message, ExecCommandLine, CmdPath, Args);423if (CmdPath.empty())424return nullptr;425426return new CustomExecutor(CmdPath, Args);427}428429//===----------------------------------------------------------------------===//430// LLC Implementation of AbstractIntepreter interface431//432Expected<CC::FileType> LLC::OutputCode(const std::string &Bitcode,433std::string &OutputAsmFile,434unsigned Timeout, unsigned MemoryLimit) {435const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s");436437SmallString<128> UniqueFile;438std::error_code EC =439sys::fs::createUniqueFile(Bitcode + "-%%%%%%%" + Suffix, UniqueFile);440if (EC) {441errs() << "Error making unique filename: " << EC.message() << "\n";442exit(1);443}444OutputAsmFile = std::string(UniqueFile);445std::vector<StringRef> LLCArgs;446LLCArgs.push_back(LLCPath);447448// Add any extra LLC args.449for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)450LLCArgs.push_back(ToolArgs[i]);451452LLCArgs.push_back("-o");453LLCArgs.push_back(OutputAsmFile); // Output to the Asm file454LLCArgs.push_back(Bitcode); // This is the input bitcode455456if (UseIntegratedAssembler)457LLCArgs.push_back("-filetype=obj");458459outs() << (UseIntegratedAssembler ? "<llc-ia>" : "<llc>");460outs().flush();461LLVM_DEBUG(errs() << "\nAbout to run:\t";462for (unsigned i = 0, e = LLCArgs.size(); i != e; ++i) errs()463<< " " << LLCArgs[i];464errs() << "\n";);465if (RunProgramWithTimeout(LLCPath, LLCArgs, "", "", "", Timeout, MemoryLimit))466return ProcessFailure(LLCPath, LLCArgs, Timeout, MemoryLimit);467return UseIntegratedAssembler ? CC::ObjectFile : CC::AsmFile;468}469470Error LLC::compileProgram(const std::string &Bitcode, unsigned Timeout,471unsigned MemoryLimit) {472std::string OutputAsmFile;473Expected<CC::FileType> Result =474OutputCode(Bitcode, OutputAsmFile, Timeout, MemoryLimit);475sys::fs::remove(OutputAsmFile);476if (Error E = Result.takeError())477return E;478return Error::success();479}480481Expected<int> LLC::ExecuteProgram(const std::string &Bitcode,482const std::vector<std::string> &Args,483const std::string &InputFile,484const std::string &OutputFile,485const std::vector<std::string> &ArgsForCC,486const std::vector<std::string> &SharedLibs,487unsigned Timeout, unsigned MemoryLimit) {488489std::string OutputAsmFile;490Expected<CC::FileType> FileKind =491OutputCode(Bitcode, OutputAsmFile, Timeout, MemoryLimit);492FileRemover OutFileRemover(OutputAsmFile, !SaveTemps);493if (Error E = FileKind.takeError())494return std::move(E);495496std::vector<std::string> CCArgs(ArgsForCC);497llvm::append_range(CCArgs, SharedLibs);498499// Assuming LLC worked, compile the result with CC and run it.500return cc->ExecuteProgram(OutputAsmFile, Args, *FileKind, InputFile,501OutputFile, CCArgs, Timeout, MemoryLimit);502}503504/// createLLC - Try to find the LLC executable505///506LLC *AbstractInterpreter::createLLC(const char *Argv0, std::string &Message,507const std::string &CCBinary,508const std::vector<std::string> *Args,509const std::vector<std::string> *CCArgs,510bool UseIntegratedAssembler) {511ErrorOr<std::string> LLCPath =512FindProgramByName("llc", Argv0, (void *)(intptr_t)&createLLC);513if (!LLCPath) {514Message = LLCPath.getError().message() + "\n";515return nullptr;516}517518CC *cc = CC::create(Argv0, Message, CCBinary, CCArgs);519if (!cc) {520errs() << Message << "\n";521exit(1);522}523Message = "Found llc: " + *LLCPath + "\n";524return new LLC(*LLCPath, cc, Args, UseIntegratedAssembler);525}526527//===---------------------------------------------------------------------===//528// JIT Implementation of AbstractIntepreter interface529//530namespace {531class JIT : public AbstractInterpreter {532std::string LLIPath; // The path to the LLI executable533std::vector<std::string> ToolArgs; // Args to pass to LLI534public:535JIT(const std::string &Path, const std::vector<std::string> *Args)536: LLIPath(Path) {537ToolArgs.clear();538if (Args) {539ToolArgs = *Args;540}541}542543Expected<int> ExecuteProgram(544const std::string &Bitcode, const std::vector<std::string> &Args,545const std::string &InputFile, const std::string &OutputFile,546const std::vector<std::string> &CCArgs = std::vector<std::string>(),547const std::vector<std::string> &SharedLibs = std::vector<std::string>(),548unsigned Timeout = 0, unsigned MemoryLimit = 0) override;549};550}551552Expected<int> JIT::ExecuteProgram(const std::string &Bitcode,553const std::vector<std::string> &Args,554const std::string &InputFile,555const std::string &OutputFile,556const std::vector<std::string> &CCArgs,557const std::vector<std::string> &SharedLibs,558unsigned Timeout, unsigned MemoryLimit) {559// Construct a vector of parameters, incorporating those from the command-line560std::vector<StringRef> JITArgs;561JITArgs.push_back(LLIPath);562JITArgs.push_back("-force-interpreter=false");563564// Add any extra LLI args.565for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)566JITArgs.push_back(ToolArgs[i]);567568for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) {569JITArgs.push_back("-load");570JITArgs.push_back(SharedLibs[i]);571}572JITArgs.push_back(Bitcode);573// Add optional parameters to the running program from Argv574for (unsigned i = 0, e = Args.size(); i != e; ++i)575JITArgs.push_back(Args[i]);576577outs() << "<jit>";578outs().flush();579LLVM_DEBUG(errs() << "\nAbout to run:\t";580for (unsigned i = 0, e = JITArgs.size(); i != e; ++i) errs()581<< " " << JITArgs[i];582errs() << "\n";);583LLVM_DEBUG(errs() << "\nSending output to " << OutputFile << "\n");584return RunProgramWithTimeout(LLIPath, JITArgs, InputFile, OutputFile,585OutputFile, Timeout, MemoryLimit);586}587588/// createJIT - Try to find the LLI executable589///590AbstractInterpreter *591AbstractInterpreter::createJIT(const char *Argv0, std::string &Message,592const std::vector<std::string> *Args) {593if (ErrorOr<std::string> LLIPath =594FindProgramByName("lli", Argv0, (void *)(intptr_t)&createJIT)) {595Message = "Found lli: " + *LLIPath + "\n";596return new JIT(*LLIPath, Args);597} else {598Message = LLIPath.getError().message() + "\n";599return nullptr;600}601}602603//===---------------------------------------------------------------------===//604// CC abstraction605//606607static bool IsARMArchitecture(std::vector<StringRef> Args) {608for (size_t I = 0; I < Args.size(); ++I) {609if (!Args[I].equals_insensitive("-arch"))610continue;611++I;612if (I == Args.size())613break;614if (Args[I].starts_with_insensitive("arm"))615return true;616}617618return false;619}620621Expected<int> CC::ExecuteProgram(const std::string &ProgramFile,622const std::vector<std::string> &Args,623FileType fileType,624const std::string &InputFile,625const std::string &OutputFile,626const std::vector<std::string> &ArgsForCC,627unsigned Timeout, unsigned MemoryLimit) {628std::vector<StringRef> CCArgs;629630CCArgs.push_back(CCPath);631632if (TargetTriple.getArch() == Triple::x86)633CCArgs.push_back("-m32");634635for (std::vector<std::string>::const_iterator I = ccArgs.begin(),636E = ccArgs.end();637I != E; ++I)638CCArgs.push_back(*I);639640// Specify -x explicitly in case the extension is wonky641if (fileType != ObjectFile) {642CCArgs.push_back("-x");643if (fileType == CFile) {644CCArgs.push_back("c");645CCArgs.push_back("-fno-strict-aliasing");646} else {647CCArgs.push_back("assembler");648649// For ARM architectures we don't want this flag. bugpoint isn't650// explicitly told what architecture it is working on, so we get651// it from cc flags652if (TargetTriple.isOSDarwin() && !IsARMArchitecture(CCArgs))653CCArgs.push_back("-force_cpusubtype_ALL");654}655}656657CCArgs.push_back(ProgramFile); // Specify the input filename.658659CCArgs.push_back("-x");660CCArgs.push_back("none");661CCArgs.push_back("-o");662663SmallString<128> OutputBinary;664std::error_code EC =665sys::fs::createUniqueFile(ProgramFile + "-%%%%%%%.cc.exe", OutputBinary);666if (EC) {667errs() << "Error making unique filename: " << EC.message() << "\n";668exit(1);669}670CCArgs.push_back(OutputBinary); // Output to the right file...671672// Add any arguments intended for CC. We locate them here because this is673// most likely -L and -l options that need to come before other libraries but674// after the source. Other options won't be sensitive to placement on the675// command line, so this should be safe.676for (unsigned i = 0, e = ArgsForCC.size(); i != e; ++i)677CCArgs.push_back(ArgsForCC[i]);678679CCArgs.push_back("-lm"); // Hard-code the math library...680CCArgs.push_back("-O2"); // Optimize the program a bit...681if (TargetTriple.getArch() == Triple::sparc)682CCArgs.push_back("-mcpu=v9");683684outs() << "<CC>";685outs().flush();686LLVM_DEBUG(errs() << "\nAbout to run:\t";687for (unsigned i = 0, e = CCArgs.size(); i != e; ++i) errs()688<< " " << CCArgs[i];689errs() << "\n";);690if (RunProgramWithTimeout(CCPath, CCArgs, "", "", ""))691return ProcessFailure(CCPath, CCArgs);692693std::vector<StringRef> ProgramArgs;694695// Declared here so that the destructor only runs after696// ProgramArgs is used.697std::string Exec;698699if (RemoteClientPath.empty())700ProgramArgs.push_back(OutputBinary);701else {702ProgramArgs.push_back(RemoteClientPath);703ProgramArgs.push_back(RemoteHost);704if (!RemoteUser.empty()) {705ProgramArgs.push_back("-l");706ProgramArgs.push_back(RemoteUser);707}708if (!RemotePort.empty()) {709ProgramArgs.push_back("-p");710ProgramArgs.push_back(RemotePort);711}712if (!RemoteExtra.empty()) {713ProgramArgs.push_back(RemoteExtra);714}715716// Full path to the binary. We need to cd to the exec directory because717// there is a dylib there that the exec expects to find in the CWD718char *env_pwd = getenv("PWD");719Exec = "cd ";720Exec += env_pwd;721Exec += "; ./";722Exec += OutputBinary.c_str();723ProgramArgs.push_back(Exec);724}725726// Add optional parameters to the running program from Argv727for (unsigned i = 0, e = Args.size(); i != e; ++i)728ProgramArgs.push_back(Args[i]);729730// Now that we have a binary, run it!731outs() << "<program>";732outs().flush();733LLVM_DEBUG(734errs() << "\nAbout to run:\t";735for (unsigned i = 0, e = ProgramArgs.size(); i != e; ++i) errs()736<< " " << ProgramArgs[i];737errs() << "\n";);738739FileRemover OutputBinaryRemover(OutputBinary.str(), !SaveTemps);740741if (RemoteClientPath.empty()) {742LLVM_DEBUG(errs() << "<run locally>");743std::string Error;744int ExitCode = RunProgramWithTimeout(OutputBinary.str(), ProgramArgs,745InputFile, OutputFile, OutputFile,746Timeout, MemoryLimit, &Error);747// Treat a signal (usually SIGSEGV) or timeout as part of the program output748// so that crash-causing miscompilation is handled seamlessly.749if (ExitCode < -1) {750std::ofstream outFile(OutputFile.c_str(), std::ios_base::app);751outFile << Error << '\n';752outFile.close();753}754return ExitCode;755} else {756outs() << "<run remotely>";757outs().flush();758return RunProgramRemotelyWithTimeout(RemoteClientPath, ProgramArgs,759InputFile, OutputFile, OutputFile,760Timeout, MemoryLimit);761}762}763764Error CC::MakeSharedObject(const std::string &InputFile, FileType fileType,765std::string &OutputFile,766const std::vector<std::string> &ArgsForCC) {767SmallString<128> UniqueFilename;768std::error_code EC = sys::fs::createUniqueFile(769InputFile + "-%%%%%%%" + LTDL_SHLIB_EXT, UniqueFilename);770if (EC) {771errs() << "Error making unique filename: " << EC.message() << "\n";772exit(1);773}774OutputFile = std::string(UniqueFilename);775776std::vector<StringRef> CCArgs;777778CCArgs.push_back(CCPath);779780if (TargetTriple.getArch() == Triple::x86)781CCArgs.push_back("-m32");782783for (std::vector<std::string>::const_iterator I = ccArgs.begin(),784E = ccArgs.end();785I != E; ++I)786CCArgs.push_back(*I);787788// Compile the C/asm file into a shared object789if (fileType != ObjectFile) {790CCArgs.push_back("-x");791CCArgs.push_back(fileType == AsmFile ? "assembler" : "c");792}793CCArgs.push_back("-fno-strict-aliasing");794CCArgs.push_back(InputFile); // Specify the input filename.795CCArgs.push_back("-x");796CCArgs.push_back("none");797if (TargetTriple.getArch() == Triple::sparc)798CCArgs.push_back("-G"); // Compile a shared library, `-G' for Sparc799else if (TargetTriple.isOSDarwin()) {800// link all source files into a single module in data segment, rather than801// generating blocks. dynamic_lookup requires that you set802// MACOSX_DEPLOYMENT_TARGET=10.3 in your env. FIXME: it would be better for803// bugpoint to just pass that in the environment of CC.804CCArgs.push_back("-single_module");805CCArgs.push_back("-dynamiclib"); // `-dynamiclib' for MacOS X/PowerPC806CCArgs.push_back("-undefined");807CCArgs.push_back("dynamic_lookup");808} else809CCArgs.push_back("-shared"); // `-shared' for Linux/X86, maybe others810811if (TargetTriple.getArch() == Triple::x86_64)812CCArgs.push_back("-fPIC"); // Requires shared objs to contain PIC813814if (TargetTriple.getArch() == Triple::sparc)815CCArgs.push_back("-mcpu=v9");816817CCArgs.push_back("-o");818CCArgs.push_back(OutputFile); // Output to the right filename.819CCArgs.push_back("-O2"); // Optimize the program a bit.820821// Add any arguments intended for CC. We locate them here because this is822// most likely -L and -l options that need to come before other libraries but823// after the source. Other options won't be sensitive to placement on the824// command line, so this should be safe.825for (unsigned i = 0, e = ArgsForCC.size(); i != e; ++i)826CCArgs.push_back(ArgsForCC[i]);827828outs() << "<CC>";829outs().flush();830LLVM_DEBUG(errs() << "\nAbout to run:\t";831for (unsigned i = 0, e = CCArgs.size(); i != e; ++i) errs()832<< " " << CCArgs[i];833errs() << "\n";);834if (RunProgramWithTimeout(CCPath, CCArgs, "", "", ""))835return ProcessFailure(CCPath, CCArgs);836return Error::success();837}838839/// create - Try to find the CC executable840///841CC *CC::create(const char *Argv0, std::string &Message,842const std::string &CCBinary,843const std::vector<std::string> *Args) {844auto CCPath = FindProgramByName(CCBinary, Argv0, (void *)(intptr_t)&create);845if (!CCPath) {846Message = "Cannot find `" + CCBinary + "' in PATH: " +847CCPath.getError().message() + "\n";848return nullptr;849}850851std::string RemoteClientPath;852if (!RemoteClient.empty()) {853auto Path = sys::findProgramByName(RemoteClient);854if (!Path) {855Message = "Cannot find `" + RemoteClient + "' in PATH: " +856Path.getError().message() + "\n";857return nullptr;858}859RemoteClientPath = *Path;860}861862Message = "Found CC: " + *CCPath + "\n";863return new CC(*CCPath, RemoteClientPath, Args);864}865866867