#include "BugDriver.h"
#include "ToolRunner.h"
#include "llvm/Linker.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/IRReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Host.h"
#include <memory>
using namespace llvm;
namespace llvm {
Triple TargetTriple;
}
namespace {
cl::opt<std::string>
OutputFile("output", cl::desc("Specify a reference program output "
"(for miscompilation detection)"));
}
void BugDriver::setNewProgram(Module *M) {
delete Program;
Program = M;
}
std::string llvm::getPassesString(const std::vector<std::string> &Passes) {
std::string Result;
for (unsigned i = 0, e = Passes.size(); i != e; ++i) {
if (i) Result += " ";
Result += "-";
Result += Passes[i];
}
return Result;
}
BugDriver::BugDriver(const char *toolname, bool find_bugs,
unsigned timeout, unsigned memlimit, bool use_valgrind,
LLVMContext& ctxt)
: Context(ctxt), ToolName(toolname), ReferenceOutputFile(OutputFile),
Program(0), Interpreter(0), SafeInterpreter(0), gcc(0),
run_find_bugs(find_bugs), Timeout(timeout),
MemoryLimit(memlimit), UseValgrind(use_valgrind) {}
BugDriver::~BugDriver() {
delete Program;
}
Module *llvm::ParseInputFile(const std::string &Filename,
LLVMContext& Ctxt) {
SMDiagnostic Err;
Module *Result = ParseIRFile(Filename, Err, Ctxt);
if (!Result)
Err.Print("bugpoint", errs());
if (Result) {
if (TargetTriple.getTriple().empty()) {
Triple TheTriple(Result->getTargetTriple());
if (TheTriple.getTriple().empty())
TheTriple.setTriple(sys::getHostTriple());
TargetTriple.setTriple(TheTriple.getTriple());
}
Result->setTargetTriple(TargetTriple.getTriple()); }
return Result;
}
bool BugDriver::addSources(const std::vector<std::string> &Filenames) {
assert(Program == 0 && "Cannot call addSources multiple times!");
assert(!Filenames.empty() && "Must specify at least on input filename!");
Program = ParseInputFile(Filenames[0], Context);
if (Program == 0) return true;
outs() << "Read input file : '" << Filenames[0] << "'\n";
for (unsigned i = 1, e = Filenames.size(); i != e; ++i) {
std::auto_ptr<Module> M(ParseInputFile(Filenames[i], Context));
if (M.get() == 0) return true;
outs() << "Linking in input file: '" << Filenames[i] << "'\n";
std::string ErrorMessage;
if (Linker::LinkModules(Program, M.get(), &ErrorMessage)) {
errs() << ToolName << ": error linking in '" << Filenames[i] << "': "
<< ErrorMessage << '\n';
return true;
}
}
outs() << "*** All input ok\n";
return false;
}
bool BugDriver::run(std::string &ErrMsg) {
if (run_find_bugs) {
return runManyPasses(PassesToRun, ErrMsg);
}
if (!PassesToRun.empty()) {
outs() << "Running selected passes on program to test for crash: ";
if (runPasses(Program, PassesToRun))
return debugOptimizerCrash();
}
if (initializeExecutionEnvironment()) return true;
outs() << "Running the code generator to test for a crash: ";
std::string Error;
compileProgram(Program, &Error);
if (!Error.empty()) {
outs() << Error;
return debugCodeGeneratorCrash(ErrMsg);
}
outs() << '\n';
bool CreatedOutput = false;
if (ReferenceOutputFile.empty()) {
outs() << "Generating reference output from raw program: ";
if (!createReferenceFile(Program)) {
return debugCodeGeneratorCrash(ErrMsg);
}
CreatedOutput = true;
}
sys::Path ROF(ReferenceOutputFile);
FileRemover RemoverInstance(ROF.str(), CreatedOutput && !SaveTemps);
outs() << "*** Checking the code generator...\n";
bool Diff = diffProgram(Program, "", "", false, &Error);
if (!Error.empty()) {
errs() << Error;
return debugCodeGeneratorCrash(ErrMsg);
}
if (!Diff) {
outs() << "\n*** Output matches: Debugging miscompilation!\n";
debugMiscompilation(&Error);
if (!Error.empty()) {
errs() << Error;
return debugCodeGeneratorCrash(ErrMsg);
}
return false;
}
outs() << "\n*** Input program does not match reference diff!\n";
outs() << "Debugging code generator problem!\n";
bool Failure = debugCodeGenerator(&Error);
if (!Error.empty()) {
errs() << Error;
return debugCodeGeneratorCrash(ErrMsg);
}
return Failure;
}
void llvm::PrintFunctionList(const std::vector<Function*> &Funcs) {
unsigned NumPrint = Funcs.size();
if (NumPrint > 10) NumPrint = 10;
for (unsigned i = 0; i != NumPrint; ++i)
outs() << " " << Funcs[i]->getName();
if (NumPrint < Funcs.size())
outs() << "... <" << Funcs.size() << " total>";
outs().flush();
}
void llvm::PrintGlobalVariableList(const std::vector<GlobalVariable*> &GVs) {
unsigned NumPrint = GVs.size();
if (NumPrint > 10) NumPrint = 10;
for (unsigned i = 0; i != NumPrint; ++i)
outs() << " " << GVs[i]->getName();
if (NumPrint < GVs.size())
outs() << "... <" << GVs.size() << " total>";
outs().flush();
}