mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
158 lines
5.7 KiB
C++
158 lines
5.7 KiB
C++
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <system_error>
|
|
#include <utility>
|
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/DynamicLibrary.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/ToolOutputFile.h"
|
|
#include "llvm/Support/raw_os_ostream.h"
|
|
|
|
#include "revng/Model/LoadModelPass.h"
|
|
#include "revng/Pipeline/AllRegistries.h"
|
|
#include "revng/Pipeline/ContainerSet.h"
|
|
#include "revng/Pipeline/CopyPipe.h"
|
|
#include "revng/Pipeline/GenericLLVMPipe.h"
|
|
#include "revng/Pipeline/Global.h"
|
|
#include "revng/Pipeline/LLVMContainerFactory.h"
|
|
#include "revng/Pipeline/LLVMKind.h"
|
|
#include "revng/Pipeline/Loader.h"
|
|
#include "revng/Pipeline/Step.h"
|
|
#include "revng/Pipeline/Target.h"
|
|
#include "revng/Pipeline/Target/YAMLTraits.h"
|
|
#include "revng/Pipes/ModelGlobal.h"
|
|
#include "revng/Pipes/PipelineManager.h"
|
|
#include "revng/Pipes/ToolCLOptions.h"
|
|
#include "revng/Support/CommandLine.h"
|
|
#include "revng/Support/InitRevng.h"
|
|
#include "revng/TupleTree/TupleTree.h"
|
|
|
|
namespace cl = llvm::cl;
|
|
using namespace pipeline;
|
|
using namespace ::revng::pipes;
|
|
|
|
static cl::list<std::string> Arguments(cl::Positional,
|
|
cl::ZeroOrMore,
|
|
cl::desc("<analysis> <binary>"),
|
|
cl::cat(MainCategory));
|
|
|
|
static revng::OutputPathOpt Output("o",
|
|
cl::desc("Output filepath of produced "
|
|
"model"),
|
|
cl::cat(MainCategory),
|
|
cl::init(revng::PathInit::Dash));
|
|
|
|
static cl::opt<bool> NoApplyModel("no-apply",
|
|
cl::desc("run the analysis but do not apply "
|
|
"it (used to recreate consistent "
|
|
"debug configurations)"),
|
|
cl::cat(MainCategory),
|
|
cl::init(false));
|
|
|
|
static cl::opt<std::string> InvalidationsPath("save-invalidations",
|
|
cl::desc("path where to save the "
|
|
"list of invalidated "
|
|
"targets"),
|
|
cl::cat(MainCategory),
|
|
cl::init(""));
|
|
|
|
static ToolCLOptions BaseOptions(MainCategory);
|
|
|
|
static llvm::ExitOnError AbortOnError;
|
|
|
|
static TupleTreeGlobal<model::Binary> &getModel(PipelineManager &Manager) {
|
|
auto &Context = Manager.context();
|
|
const auto &ModelName = revng::ModelGlobalName;
|
|
auto *Result = AbortOnError(Context.getGlobal<revng::ModelGlobal>(ModelName));
|
|
revng_assert(Result != nullptr);
|
|
return *Result;
|
|
}
|
|
|
|
static llvm::Error overrideModel(PipelineManager &Manager,
|
|
TupleTree<model::Binary> NewModel) {
|
|
const auto &Name = revng::ModelGlobalName;
|
|
auto *Model(cantFail(Manager.context().getGlobal<revng::ModelGlobal>(Name)));
|
|
Model->get() = std::move(NewModel);
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
using revng::FilePath;
|
|
|
|
revng::InitRevng X(argc, argv, "", { &MainCategory });
|
|
|
|
Registry::runAllInitializationRoutines();
|
|
|
|
auto Manager = AbortOnError(BaseOptions.makeManager());
|
|
const auto &C = Manager.context();
|
|
using BR = TupleTreeGlobal<model::Binary>;
|
|
auto OriginalModel = *AbortOnError(C.getGlobal<BR>(revng::ModelGlobalName));
|
|
|
|
if (Arguments.size() == 0) {
|
|
std::cout << "USAGE: revng-analyze [options] <analysis> <binary>\n\n";
|
|
std::vector<std::pair<std::string, std::string>> Pairs;
|
|
|
|
std::cout << "<analysis> can be one of the following analyses list:\n\n";
|
|
|
|
for (size_t I = 0; I < Manager.getRunner().getAnalysesListCount(); I++) {
|
|
AnalysesList AL = Manager.getRunner().getAnalysesList(I);
|
|
std::cout << " " << AL.getName().str() << "\n";
|
|
}
|
|
|
|
std::cout << "\n<analysis> can also be one of the following analyses:\n\n";
|
|
for (const auto &Step : Manager.getRunner())
|
|
for (const auto &Analysis : Step.analyses())
|
|
std::cout << " " << Analysis.getKey().str() << "\n";
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
if (Arguments.size() == 1) {
|
|
AbortOnError(revng::createError("Expected any number of positional "
|
|
"arguments different from 1"));
|
|
}
|
|
|
|
auto &InputContainer = Manager.getRunner().begin()->containers()["input"];
|
|
InputPath = Arguments[1];
|
|
FilePath InputFilePath = FilePath::fromLocalStorage(Arguments[1]);
|
|
AbortOnError(InputFilePath.check());
|
|
AbortOnError(InputContainer.load(InputFilePath));
|
|
|
|
auto InvMap = revng::pipes::runAnalysisOrAnalysesList(Manager,
|
|
Arguments[0],
|
|
AbortOnError);
|
|
|
|
if (NoApplyModel)
|
|
AbortOnError(overrideModel(Manager, OriginalModel.get()));
|
|
|
|
if (not InvalidationsPath.empty()) {
|
|
std::error_code EC;
|
|
llvm::ToolOutputFile InvalidationOutput(InvalidationsPath,
|
|
EC,
|
|
llvm::sys::fs::OpenFlags::OF_Text);
|
|
if (EC)
|
|
AbortOnError(llvm::createStringError(EC, EC.message()));
|
|
|
|
serialize(InvalidationOutput.os(), InvMap);
|
|
|
|
InvalidationOutput.keep();
|
|
}
|
|
|
|
AbortOnError(Manager.store());
|
|
|
|
auto &FinalModel = getModel(Manager);
|
|
|
|
auto MaybeOutput = AbortOnError(Output.get());
|
|
revng_assert(MaybeOutput.has_value());
|
|
AbortOnError(FinalModel.store(*MaybeOutput));
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|