Files
Alessandro Di Federico 5820908675 Remove and ban \file
2025-12-16 17:41:55 +01:00

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;
}