blob: 2c39e57be9ec999e74875f58cdf5dc779bd4dcd3 [file] [log] [blame]
//===-- injectf - Fault Injector Tool -------------------------------------===//
//
// The SAFECode Project
//
// This file was developed by the LLVM research group and is distributed
// under the University of Illinois Open Source License. See LICENSE.TXT for
// details.
//
//===--------------------------------------------------------------------===//
//
// This program is a tool to run the fault injection pass.
//
//===--------------------------------------------------------------------===//
#include "llvm/Module.h"
#include "llvm/LLVMContext.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/PassManager.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/System/Signals.h"
#include "safecode/FaultInjector.h"
#include <fstream>
#include <iostream>
#include <memory>
using namespace llvm;
// General options for sc.
static cl::opt<std::string>
InputFilename(cl::Positional, cl::desc("<input bytecode>"), cl::init("-"));
static cl::opt<std::string>
OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"));
static cl::opt<bool>
Force("f", cl::desc("Overwrite output files"));
// GetFileNameRoot - Helper function to get the basename of a filename.
static inline std::string
GetFileNameRoot(const std::string &InputFilename) {
std::string IFN = InputFilename;
std::string outputFilename;
int Len = IFN.length();
if ((Len > 2) &&
IFN[Len-3] == '.' && IFN[Len-2] == 'b' && IFN[Len-1] == 'c') {
outputFilename = std::string(IFN.begin(), IFN.end()-3); // s/.bc/.s/
} else {
outputFilename = IFN;
}
return outputFilename;
}
//
// Function: main()
//
// Descripton
// Entry point for the program compiler.
//
int
main(int argc, char **argv) {
LLVMContext Context;
llvm_shutdown_obj ShutdownObject;
try {
cl::ParseCommandLineOptions(argc, argv, "Fault Injector Tool\n");
sys::PrintStackTraceOnErrorSignal();
// Load the module to be compiled...
std::auto_ptr<Module> M;
std::string ErrorMessage;
if (MemoryBuffer *Buffer
= MemoryBuffer::getFileOrSTDIN(InputFilename, &ErrorMessage)) {
M.reset(ParseBitcodeFile(Buffer, Context, &ErrorMessage));
delete Buffer;
}
if (M.get() == 0) {
std::cerr << argv[0] << ": bytecode didn't read correctly.\n";
return 1;
}
// Build up all of the passes that we want to do to the module...
PassManager Passes;
Passes.add(new TargetData(M.get()));
// Remove indirect calls to malloc and free functions
Passes.add(createIndMemRemPass());
// Ensure that all malloc/free calls are changed into LLVM instructions
Passes.add(createRaiseAllocationsPass());
// Inject faults into the program
Passes.add(new FaultInjector());
// Verify the final result - it should still be valid LLVM even if it's
// now got faults injected into it
Passes.add(createVerifierPass());
// Figure out where we are going to send the output...
std::ostream *Out = 0;
if (OutputFilename != "") {
if (OutputFilename != "-") {
// Specified an output filename?
if (!Force && std::ifstream(OutputFilename.c_str())) {
// If force is not specified, make sure not to overwrite a file!
std::cerr << argv[0] << ": error opening '" << OutputFilename
<< "': file exists!\n"
<< "Use -f command line argument to force output\n";
return 1;
}
Out = new std::ofstream(OutputFilename.c_str());
// Make sure that the Out file gets unlinked from the disk if we get a
// SIGINT
sys::RemoveFileOnSignal(sys::Path(OutputFilename));
} else {
Out = &std::cout;
}
} else {
if (InputFilename == "-") {
OutputFilename = "-";
Out = &std::cout;
} else {
OutputFilename = GetFileNameRoot(InputFilename);
OutputFilename += ".faults.bc";
}
if (!Force && std::ifstream(OutputFilename.c_str())) {
// If force is not specified, make sure not to overwrite a file!
std::cerr << argv[0] << ": error opening '" << OutputFilename
<< "': file exists!\n"
<< "Use -f command line argument to force output\n";
return 1;
}
Out = new std::ofstream(OutputFilename.c_str());
if (!Out->good()) {
std::cerr << argv[0] << ": error opening " << OutputFilename << "!\n";
delete Out;
return 1;
}
// Make sure that the Out file gets unlinked from the disk if we get a
// SIGINT
sys::RemoveFileOnSignal(sys::Path(OutputFilename));
}
// Add the writing of the output file to the list of passes
Passes.add (CreateBitcodeWriterPass(*Out));
// Run our queue of passes all at once now, efficiently.
Passes.run(*M.get());
// Delete the ostream if it's not a stdout stream
if (Out != &std::cout) delete Out;
return 0;
} catch (const std::string & msg) {
std::cerr << argv[0] << ": " << msg << "\n";
} catch (...) {
std::cerr << argv[0] << ": Unexpected unknown exception occurred.\n";
}
llvm_shutdown();
return 1;
}