diff --git a/CMakeLists.txt b/CMakeLists.txt index e00919a18..651096093 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,7 +122,6 @@ add_flag_if_available("-Wmissing-prototypes") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") add_definitions("-D_FILE_OFFSET_BITS=64") -include_directories(argparse/) CHECK_CXX_COMPILER_FLAG("-no-pie" COMPILER_SUPPORTS_NO_PIE) if(COMPILER_SUPPORTS_NO_PIE) diff --git a/CREDITS.md b/CREDITS.md index 4e402c9a5..a6f84f82e 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -8,5 +8,3 @@ components: [GNU General Public License, version 2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)) * [Boost](http://www.boost.org/) by **The Boost authors** (licensed under the [Boost license](http://www.boost.org/users/license.html)) -* [argparse](http://cofyc.github.io/argparse/) by **Yecheng Fu** (licensed under - the [MIT License](https://opensource.org/licenses/MIT)) diff --git a/docs/RevambDumpUsage.rst b/docs/RevambDumpUsage.rst index cf9f616cd..6ff7afaeb 100644 --- a/docs/RevambDumpUsage.rst +++ b/docs/RevambDumpUsage.rst @@ -40,7 +40,7 @@ a basic block* as represented by `revamb` in the generated module (typically should be stored. The output will be a CSV file with a single column `noreturn`, containing the name of the ``noreturn`` basic block. -:``-f``, ``--function-boundaries``: Path where the list of *function*<->*basic +:``-f``, ``--functions-boundaries``: Path where the list of *function*<->*basic block* pairs should be stored. The output will be a CSV file with two column: `function`, the name of the entry basic diff --git a/docs/RevambUsage.rst b/docs/RevambUsage.rst index 32ce11fc4..5729a3708 100644 --- a/docs/RevambUsage.rst +++ b/docs/RevambUsage.rst @@ -84,6 +84,6 @@ are described: the translated basic blocks. This option is deprecated in favor of using `revamb-dump` and will be removed. Default: ``OUTFILE.bbsummary.csv``. -:``-f``, ``--function-boundaries``: Enable function boundaries detection. This +:``-f``, ``--functions-boundaries``: Enable function boundaries detection. This process currently can be quite expensive and it's therefore disabled by default. diff --git a/include/revng/DebugHelper/DebugHelper.h b/include/revng/DebugHelper/DebugHelper.h index a24b52aa8..230ea8994 100644 --- a/include/revng/DebugHelper/DebugHelper.h +++ b/include/revng/DebugHelper/DebugHelper.h @@ -24,6 +24,22 @@ class DISubprogram; class Function; } // namespace llvm +namespace DebugInfoType { + +/// \brief Type of debug information to produce +enum Values { + /// No debug information + None, + /// Produce a file containing the assembly code of the input binary + OriginalAssembly, + /// Produce the PTC as translated by libtinycode + PTC, + /// Prduce an LLVM IR with debug metadata referring to itself + LLVMIR +}; + +} // namespace DebugInfoType + /// \brief AssemblyAnnotationWriter decorating the output withe debug /// information /// @@ -70,11 +86,10 @@ public: /// DebugInfoType::PTC, `.S` if it's DebugInfoType::OriginalAssembly or /// will match \p Output if \p Type is DebugInfoType::LLVMIR. /// \param TheModule the LLVM module to print out. - /// \param Type type of debug information requested. DebugHelper(std::string Output, - std::string Debug, llvm::Module *TheModule, - DebugInfoType Type); + DebugInfoType::Values DebugInfo, + std::string DebugPath); /// Decorates the root and the isolated functions with the requested debug /// info @@ -95,9 +110,7 @@ private: private: std::string OutputPath; - std::string DebugPath; llvm::DIBuilder Builder; - DebugInfoType Type; llvm::Module *TheModule; llvm::DICompileUnit *CompileUnit; std::unique_ptr Annotator; @@ -105,6 +118,9 @@ private: unsigned OriginalInstrMDKind; unsigned PTCInstrMDKind; unsigned DbgMDKind; + + DebugInfoType::Values DebugInfo; + std::string DebugPath; }; #endif // DEBUGHELPER_H diff --git a/include/revng/Support/CommandLine.h b/include/revng/Support/CommandLine.h new file mode 100644 index 000000000..9feaf50e6 --- /dev/null +++ b/include/revng/Support/CommandLine.h @@ -0,0 +1,16 @@ +#ifndef COMMANDLINE_H +#define COMMANDLINE_H + +// +// This file is distributed under the MIT License. See LICENSE.md for details. +// + +// LLVM includes +#include "llvm/Support/CommandLine.h" + +extern llvm::cl::OptionCategory MainCategory; + +// Popular option +extern llvm::cl::opt UseDebugSymbols; + +#endif // COMMANDLINE_H diff --git a/include/revng/Support/Debug.h b/include/revng/Support/Debug.h index 07b6d87f7..f6ef68f4c 100644 --- a/include/revng/Support/Debug.h +++ b/include/revng/Support/Debug.h @@ -62,8 +62,13 @@ public: bool isEnabled() const { return StaticEnabled && Enabled; } llvm::StringRef name() const { return Name; } + // TODO: allow optional description + llvm::StringRef description() const { return ""; } - void enable() { Enabled = true; } + void enable() { + MaxLoggerNameLength = std::max(MaxLoggerNameLength, Name.size()); + Enabled = true; + } void disable() { Enabled = false; } @@ -162,7 +167,6 @@ public: for (Logger *L : Loggers) { if (L->name() == Name) { L->enable(); - MaxLoggerNameLength = std::max(MaxLoggerNameLength, Name.size()); return; } } @@ -181,6 +185,9 @@ public: revng_abort("Requested logger not available"); } + void registerArguments() const; + void activateArguments(); + private: std::vector *> Loggers; }; diff --git a/include/revng/Support/Statistics.h b/include/revng/Support/Statistics.h index 4c9d08f9b..542064a59 100644 --- a/include/revng/Support/Statistics.h +++ b/include/revng/Support/Statistics.h @@ -210,4 +210,6 @@ inline void CounterMap::init() { OnQuitStatistics->add(this); } +extern void installStatistics(); + #endif // STATISTICS_H diff --git a/include/revng/Support/revng.h b/include/revng/Support/revng.h index 4ebac3699..4c926794a 100644 --- a/include/revng/Support/revng.h +++ b/include/revng/Support/revng.h @@ -60,15 +60,6 @@ public: } }; -/// \brief Type of debug information to produce -enum class DebugInfoType { - None, ///< no debug information. - OriginalAssembly, ///< produce a file containing the assembly code of the - /// input binary. - PTC, ///< produce the PTC as translated by libtinycode. - LLVMIR ///< produce an LLVM IR with debug metadata referring to itself. -}; - // TODO: move me to another header file /// \brief Classification of the various basic blocks we are creating enum BlockType { diff --git a/include/revng/argparse/argparse.h b/include/revng/argparse/argparse.h deleted file mode 100644 index 345e84829..000000000 --- a/include/revng/argparse/argparse.h +++ /dev/null @@ -1,133 +0,0 @@ -/** - * Copyright (C) 2012-2015 Yecheng Fu - * All rights reserved. - * - * Use of this source code is governed by a MIT-style license that can be found - * in the LICENSE file. - */ -#ifndef ARGPARSE_H -#define ARGPARSE_H - -/* For c++ compatibility */ -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include -#include -#include - -struct argparse; -struct argparse_option; - -typedef int argparse_callback (struct argparse *self, - const struct argparse_option *option); - -enum argparse_flag { - ARGPARSE_STOP_AT_NON_OPTION = 1, -}; - -enum argparse_option_type { - /* special */ - ARGPARSE_OPT_END, - ARGPARSE_OPT_GROUP, - /* options with no arguments */ - ARGPARSE_OPT_BOOLEAN, - ARGPARSE_OPT_BIT, - /* options with arguments (optional or required) */ - ARGPARSE_OPT_INTEGER, - ARGPARSE_OPT_STRING, -}; - -enum argparse_option_flags { - OPT_NONEG = 1, /* disable negation */ -}; - -/** - * argparse option - * - * `type`: - * holds the type of the option, you must have an ARGPARSE_OPT_END last in your - * array. - * - * `short_name`: - * the character to use as a short option name, '\0' if none. - * - * `long_name`: - * the long option name, without the leading dash, NULL if none. - * - * `value`: - * stores pointer to the value to be filled. - * - * `help`: - * the short help message associated to what the option does. - * Must never be NULL (except for ARGPARSE_OPT_END). - * - * `callback`: - * function is called when corresponding argument is parsed. - * - * `data`: - * associated data. Callbacks can use it like they want. - * - * `flags`: - * option flags. - */ -struct argparse_option { - enum argparse_option_type type; - const char short_name; - const char *long_name; - void *value; - const char *help; - argparse_callback *callback; - intptr_t data; - int flags; -}; - -/** - * argpparse - */ -struct argparse { - // user supplied - const struct argparse_option *options; - const char *const *usages; - int flags; - const char *description; // a description after usage - const char *epilog; // a description at the end - // internal context - int argc; - const char **argv; - const char **out; - int cpidx; - const char *optvalue; // current option value -}; - -// built-in callbacks -int argparse_help_cb(struct argparse *self, - const struct argparse_option *option); - -// built-in option macros -#define OPT_END() { ARGPARSE_OPT_END, 0, NULL, NULL, 0, NULL } -#define OPT_BOOLEAN(...) { ARGPARSE_OPT_BOOLEAN, __VA_ARGS__ } -#define OPT_BIT(...) { ARGPARSE_OPT_BIT, __VA_ARGS__ } -#define OPT_INTEGER(...) { ARGPARSE_OPT_INTEGER, __VA_ARGS__ } -#define OPT_STRING(...) { ARGPARSE_OPT_STRING, __VA_ARGS__ } -#define OPT_GROUP(h) { ARGPARSE_OPT_GROUP, 0, NULL, NULL, h, NULL } -#define OPT_HELP() OPT_BOOLEAN('h', "help", NULL, \ - "show this help message and exit", \ - argparse_help_cb) - -int argparse_init(struct argparse *self, struct argparse_option *options, - const char *const *usages, int flags); -void argparse_describe(struct argparse *self, const char *description, - const char *epilog); -int argparse_parse(struct argparse *self, int argc, const char **argv); -void argparse_usage(struct argparse *self); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index d9781f8c3..3a5be5cab 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -4,6 +4,5 @@ add_subdirectory(Support) add_subdirectory(DebugHelper) -add_subdirectory(argparse) add_subdirectory(BasicAnalyses) add_subdirectory(StackAnalysis) diff --git a/lib/DebugHelper/DebugHelper.cpp b/lib/DebugHelper/DebugHelper.cpp index 08b2fcbd3..4ac1aaa01 100644 --- a/lib/DebugHelper/DebugHelper.cpp +++ b/lib/DebugHelper/DebugHelper.cpp @@ -7,6 +7,7 @@ // Standard includes #include +#include // LLVM includes #include "llvm/IR/AssemblyAnnotationWriter.h" @@ -18,6 +19,7 @@ // Local libraries includes #include "revng/DebugHelper/DebugHelper.h" +#include "revng/Support/CommandLine.h" using namespace llvm; @@ -123,31 +125,32 @@ void DAW::emitInstructionAnnot(const Instruction *Instr, } DebugHelper::DebugHelper(std::string Output, - std::string Debug, Module *TheModule, - DebugInfoType Type) : + DebugInfoType::Values DebugInfo, + std::string DebugPath) : OutputPath(Output), - DebugPath(Debug), Builder(*TheModule), - Type(Type), - TheModule(TheModule) { + TheModule(TheModule), + DebugInfo(DebugInfo), + DebugPath(DebugPath) { + OriginalInstrMDKind = TheModule->getContext().getMDKindID("oi"); PTCInstrMDKind = TheModule->getContext().getMDKindID("pi"); DbgMDKind = TheModule->getContext().getMDKindID("dbg"); // Generate automatically the name of the source file for debugging if (DebugPath.empty()) { - if (Type == DebugInfoType::PTC) - DebugPath = OutputPath + ".ptc"; - else if (Type == DebugInfoType::OriginalAssembly) - DebugPath = OutputPath + ".S"; - else if (Type == DebugInfoType::LLVMIR) - DebugPath = OutputPath; + if (DebugInfo == DebugInfoType::PTC) + this->DebugPath = OutputPath + ".ptc"; + else if (DebugInfo == DebugInfoType::OriginalAssembly) + this->DebugPath = OutputPath + ".S"; + else if (DebugInfo == DebugInfoType::LLVMIR) + this->DebugPath = OutputPath; } - if (Type != DebugInfoType::None) { + if (DebugInfo != DebugInfoType::None) { CompileUnit = Builder.createCompileUnit(dwarf::DW_LANG_C, - DebugPath, + this->DebugPath, "", "revamb", false, @@ -165,7 +168,7 @@ void DebugHelper::generateDebugInfo() { for (Function &F : TheModule->functions()) { // TODO: find a better way to identify root and the isolated functions if (F.getName() == "root" || F.getName().startswith("bb.")) { - if (Type != DebugInfoType::None) { + if (DebugInfo != DebugInfoType::None) { DISubroutineType *EmptyType = nullptr; DITypeRefArray EmptyArrayType = Builder.getOrCreateTypeArray({}); EmptyType = Builder.createSubroutineType(EmptyArrayType); @@ -188,14 +191,15 @@ void DebugHelper::generateDebugInfo() { } } - switch (Type) { + switch (DebugInfo) { case DebugInfoType::PTC: case DebugInfoType::OriginalAssembly: { // Generate the source file and the debugging information in tandem unsigned LineIndex = 1; - unsigned MetadataKind = Type == DebugInfoType::PTC ? PTCInstrMDKind : - OriginalInstrMDKind; + unsigned MetadataKind = DebugInfo == DebugInfoType::PTC ? + PTCInstrMDKind : + OriginalInstrMDKind; MDString *Last = nullptr; std::ofstream Source(DebugPath); @@ -253,7 +257,7 @@ void DebugHelper::print(std::ostream &Output, bool DebugInfo) { bool DebugHelper::copySource() { // If debug info refer to LLVM IR, just copy the output file - if (Type == DebugInfoType::LLVMIR && DebugPath != OutputPath) { + if (DebugInfo == DebugInfoType::LLVMIR && DebugPath != OutputPath) { std::ifstream Source(DebugPath, std::ios::binary); std::ofstream Destination(OutputPath, std::ios::binary); diff --git a/lib/Support/CMakeLists.txt b/lib/Support/CMakeLists.txt index a3c7552a8..9bc4eb211 100644 --- a/lib/Support/CMakeLists.txt +++ b/lib/Support/CMakeLists.txt @@ -1 +1 @@ -add_library(Support STATIC Assert.cpp Statistics.cpp Debug.cpp) +add_library(Support STATIC Assert.cpp CommandLine.cpp Statistics.cpp Debug.cpp) diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp new file mode 100644 index 000000000..9b06ce1e8 --- /dev/null +++ b/lib/Support/CommandLine.cpp @@ -0,0 +1,22 @@ +/// \file debug.cpp +/// \brief Implementation of the debug framework + +// +// This file is distributed under the MIT License. See LICENSE.md for details. +// + +// Local libraries includes +#include "revng/Support/CommandLine.h" + +namespace cl = llvm::cl; + +cl::OptionCategory MainCategory("Options", ""); + +cl::opt UseDebugSymbols("use-debug-symbols", + cl::desc("use section and symbol function " + "informations, if available"), + cl::cat(MainCategory)); +static cl::alias A1("S", + cl::desc("Alias for -use-debug-symbols"), + cl::aliasopt(UseDebugSymbols), + cl::cat(MainCategory)); diff --git a/lib/Support/Debug.cpp b/lib/Support/Debug.cpp index 02ffa860e..efa91b875 100644 --- a/lib/Support/Debug.cpp +++ b/lib/Support/Debug.cpp @@ -15,7 +15,11 @@ #include "llvm/IR/Value.h" // Local libraries includes +#include "revng/Support/CommandLine.h" #include "revng/Support/Debug.h" +#include "revng/Support/revng.h" + +namespace cl = llvm::cl; size_t MaxLoggerNameLength = 0; LogTerminator DoLog; @@ -39,6 +43,55 @@ void Logger::emit() { } } +/// \brief Class for dynamically registering arguments options +template +class DynamicValuesClass { +private: + struct Alternative { + const char *Name; + int Value; + const char *Description; + }; + + std::vector Values; + +public: + void addOption(const char *Name, int Value, const char *Description) { + Values.push_back({ Name, Value, Description }); + } + + template + void apply(Opt &O) const { + for (const Alternative &A : Values) + O.getParser().addLiteralOption(A.Name, A.Value, A.Description); + } +}; + +enum PlaceholderEnum {}; +static std::unique_ptr> DebugLogging; +static std::unique_ptr DebugLoggingAlias; + +void LoggersRegistry::registerArguments() const { + DynamicValuesClass Values; + unsigned I = 0; + for (Logger *L : Loggers) + Values.addOption(L->name().data(), I++, L->description().data()); + auto *Opt = new cl::list("debug-log", + cl::desc("enable verbose logging"), + Values, + cl::cat(MainCategory)); + DebugLogging.reset(Opt); + DebugLoggingAlias.reset(new cl::alias("d", + cl::desc("Alias for -debug-log"), + cl::aliasopt(*DebugLogging), + cl::cat(MainCategory))); +} + +void LoggersRegistry::activateArguments() { + for (unsigned I : *DebugLogging) + Loggers[I]->enable(); +} + template unsigned Logger::IndentLevel; diff --git a/lib/Support/Statistics.cpp b/lib/Support/Statistics.cpp index 01461ead7..627128217 100644 --- a/lib/Support/Statistics.cpp +++ b/lib/Support/Statistics.cpp @@ -7,6 +7,21 @@ // Local libraries includes #include "revng/Support/Statistics.h" +#include "revng/Support/CommandLine.h" + +namespace cl = llvm::cl; + +// Was: -stats +static cl::opt Statistics("statistics", + cl::desc("print statistics upon exit or " + "SIGINT. Use " + "this argument, ignore -stats."), + cl::cat(MainCategory)); + +static cl::alias A1("T", + cl::desc("Alias for -statistics"), + cl::aliasopt(Statistics), + cl::cat(MainCategory)); struct Handler { int Signal; @@ -23,6 +38,11 @@ static std::array Handlers = { { { SIGINT, true, {}, {} }, llvm::ManagedStatic OnQuitStatistics; +void installStatistics() { + if (Statistics) + OnQuitStatistics->install(); +} + static void onQuit() { dbg << "\n"; OnQuitStatistics->dump(); diff --git a/lib/argparse/CMakeLists.txt b/lib/argparse/CMakeLists.txt deleted file mode 100644 index a9bc0dda9..000000000 --- a/lib/argparse/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_library(argparse STATIC argparse.c) diff --git a/lib/argparse/LICENSE b/lib/argparse/LICENSE deleted file mode 100644 index 3c7774976..000000000 --- a/lib/argparse/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2012-2013 Yecheng Fu - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/lib/argparse/argparse.c b/lib/argparse/argparse.c deleted file mode 100644 index 5301e2f33..000000000 --- a/lib/argparse/argparse.c +++ /dev/null @@ -1,351 +0,0 @@ -/** - * Copyright (C) 2012-2015 Yecheng Fu - * All rights reserved. - * - * Use of this source code is governed by a MIT-style license that can be found - * in the LICENSE file. - */ - -// Local libraries includes -#include "revng/argparse/argparse.h" - -#define OPT_UNSET 1 -#define OPT_LONG 1 << 1 - -static const char * -prefix_skip(const char *str, const char *prefix) -{ - size_t len = strlen(prefix); - return strncmp(str, prefix, len) ? NULL : str + len; -} - -static int -prefix_cmp(const char *str, const char *prefix) -{ - for (;; str++, prefix++) - if (!*prefix) - return 0; - else if (*str != *prefix) - return (unsigned char)*prefix - (unsigned char)*str; -} - -static void -argparse_error(struct argparse *self, const struct argparse_option *opt, - const char *reason, int flags) -{ - if (flags & OPT_LONG) { - fprintf(stderr, "error: option `--%s` %s\n", opt->long_name, reason); - } else { - fprintf(stderr, "error: option `-%c` %s\n", opt->short_name, reason); - } - exit(1); -} - -static int -argparse_getvalue(struct argparse *self, const struct argparse_option *opt, - int flags) -{ - const char *s = NULL; - if (!opt->value) - goto skipped; - switch (opt->type) { - case ARGPARSE_OPT_BOOLEAN: - if (flags & OPT_UNSET) { - *(int *)opt->value = *(int *)opt->value - 1; - } else { - *(int *)opt->value = *(int *)opt->value + 1; - } - if (*(int *)opt->value < 0) { - *(int *)opt->value = 0; - } - break; - case ARGPARSE_OPT_BIT: - if (flags & OPT_UNSET) { - *(int *)opt->value &= ~opt->data; - } else { - *(int *)opt->value |= opt->data; - } - break; - case ARGPARSE_OPT_STRING: - if (self->optvalue) { - *(const char **)opt->value = self->optvalue; - self->optvalue = NULL; - } else if (self->argc > 1) { - self->argc--; - *(const char **)opt->value = *++self->argv; - } else { - argparse_error(self, opt, "requires a value", flags); - } - break; - case ARGPARSE_OPT_INTEGER: - if (self->optvalue) { - *(int *)opt->value = strtol(self->optvalue, (char **)&s, 0); - self->optvalue = NULL; - } else if (self->argc > 1) { - self->argc--; - *(int *)opt->value = strtol(*++self->argv, (char **)&s, 0); - } else { - argparse_error(self, opt, "requires a value", flags); - } - if (s[0] != '\0') - argparse_error(self, opt, "expects a numerical value", flags); - break; - default: - assert(0); - } - -skipped: - if (opt->callback) { - return opt->callback(self, opt); - } - - return 0; -} - -static void -argparse_options_check(const struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - switch (options->type) { - case ARGPARSE_OPT_END: - case ARGPARSE_OPT_BOOLEAN: - case ARGPARSE_OPT_BIT: - case ARGPARSE_OPT_INTEGER: - case ARGPARSE_OPT_STRING: - case ARGPARSE_OPT_GROUP: - continue; - default: - fprintf(stderr, "wrong option type: %d", options->type); - break; - } - } -} - -static int -argparse_short_opt(struct argparse *self, const struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - if (options->short_name == *self->optvalue) { - self->optvalue = self->optvalue[1] ? self->optvalue + 1 : NULL; - return argparse_getvalue(self, options, 0); - } - } - return -2; -} - -static int -argparse_long_opt(struct argparse *self, const struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - const char *rest; - int opt_flags = 0; - if (!options->long_name) - continue; - - rest = prefix_skip(self->argv[0] + 2, options->long_name); - if (!rest) { - // negation disabled? - if (options->flags & OPT_NONEG) { - continue; - } - // only OPT_BOOLEAN/OPT_BIT supports negation - if (options->type != ARGPARSE_OPT_BOOLEAN && options->type != - ARGPARSE_OPT_BIT) { - continue; - } - - if (prefix_cmp(self->argv[0] + 2, "no-")) { - continue; - } - rest = prefix_skip(self->argv[0] + 2 + 3, options->long_name); - if (!rest) - continue; - opt_flags |= OPT_UNSET; - } - if (*rest) { - if (*rest != '=') - continue; - self->optvalue = rest + 1; - } - return argparse_getvalue(self, options, opt_flags | OPT_LONG); - } - return -2; -} - -int -argparse_init(struct argparse *self, struct argparse_option *options, - const char *const *usages, int flags) -{ - memset(self, 0, sizeof(*self)); - self->options = options; - self->usages = usages; - self->flags = flags; - self->description = NULL; - self->epilog = NULL; - return 0; -} - -void -argparse_describe(struct argparse *self, const char *description, - const char *epilog) -{ - self->description = description; - self->epilog = epilog; -} - -int -argparse_parse(struct argparse *self, int argc, const char **argv) -{ - self->argc = argc - 1; - self->argv = argv + 1; - self->out = argv; - - argparse_options_check(self->options); - - for (; self->argc; self->argc--, self->argv++) { - const char *arg = self->argv[0]; - if (arg[0] != '-' || !arg[1]) { - if (self->flags & ARGPARSE_STOP_AT_NON_OPTION) { - goto end; - } - // if it's not option or is a single char '-', copy verbatim - self->out[self->cpidx++] = self->argv[0]; - continue; - } - // short option - if (arg[1] != '-') { - self->optvalue = arg + 1; - switch (argparse_short_opt(self, self->options)) { - case -1: - break; - case -2: - goto unknown; - } - while (self->optvalue) { - switch (argparse_short_opt(self, self->options)) { - case -1: - break; - case -2: - goto unknown; - } - } - continue; - } - // if '--' presents - if (!arg[2]) { - self->argc--; - self->argv++; - break; - } - // long option - switch (argparse_long_opt(self, self->options)) { - case -1: - break; - case -2: - goto unknown; - } - continue; - -unknown: - fprintf(stderr, "error: unknown option `%s`\n", self->argv[0]); - argparse_usage(self); - exit(1); - } - -end: - memmove(self->out + self->cpidx, self->argv, - self->argc * sizeof(*self->out)); - self->out[self->cpidx + self->argc] = NULL; - - return self->cpidx + self->argc; -} - -void -argparse_usage(struct argparse *self) -{ - fprintf(stdout, "Usage: %s\n", *self->usages++); - while (*self->usages && **self->usages) - fprintf(stdout, " or: %s\n", *self->usages++); - - // print description - if (self->description) - fprintf(stdout, "%s\n", self->description); - - fputc('\n', stdout); - - const struct argparse_option *options; - - // figure out best width - size_t usage_opts_width = 0; - size_t len; - options = self->options; - for (; options->type != ARGPARSE_OPT_END; options++) { - len = 0; - if ((options)->short_name) { - len += 2; - } - if ((options)->short_name && (options)->long_name) { - len += 2; // separator ", " - } - if ((options)->long_name) { - len += strlen((options)->long_name) + 2; - } - if (options->type == ARGPARSE_OPT_INTEGER) { - len += strlen("="); - } else if (options->type == ARGPARSE_OPT_STRING) { - len += strlen("="); - } - len = ceil((float)len / 4) * 4; - if (usage_opts_width < len) { - usage_opts_width = len; - } - } - usage_opts_width += 4; // 4 spaces prefix - - options = self->options; - for (; options->type != ARGPARSE_OPT_END; options++) { - size_t pos = 0; - int pad = 0; - if (options->type == ARGPARSE_OPT_GROUP) { - fputc('\n', stdout); - fprintf(stdout, "%s", options->help); - fputc('\n', stdout); - continue; - } - pos = fprintf(stdout, " "); - if (options->short_name) { - pos += fprintf(stdout, "-%c", options->short_name); - } - if (options->long_name && options->short_name) { - pos += fprintf(stdout, ", "); - } - if (options->long_name) { - pos += fprintf(stdout, "--%s", options->long_name); - } - if (options->type == ARGPARSE_OPT_INTEGER) { - pos += fprintf(stdout, "="); - } else if (options->type == ARGPARSE_OPT_STRING) { - pos += fprintf(stdout, "="); - } - if (pos <= usage_opts_width) { - pad = usage_opts_width - pos; - } else { - fputc('\n', stdout); - pad = usage_opts_width; - } - fprintf(stdout, "%*s%s\n", pad + 2, "", options->help); - } - - // print epilog - if (self->epilog) - fprintf(stdout, "%s\n", self->epilog); -} - -int -argparse_help_cb(struct argparse *self, const struct argparse_option *option) -{ - (void)option; - argparse_usage(self); - exit(0); - return 0; -} diff --git a/scripts/check-conventions.sh b/scripts/check-conventions.sh index de8fa7d65..5578a87ed 100755 --- a/scripts/check-conventions.sh +++ b/scripts/check-conventions.sh @@ -35,7 +35,7 @@ while [[ $# > 0 ]]; do done if [[ $# -eq 0 ]]; then - FILES="$(git ls-files | grep -E '(\.cpp|\.c|\.h)$' | grep -v argparse)" + FILES="$(git ls-files | grep -E '(\.cpp|\.c|\.h)$')" else FILES="$@" fi @@ -66,7 +66,7 @@ fi done # Things should never be at the end of a line - for REGEXP in '::' '<' 'RegisterPass.*>' '(' '} else'; do + for REGEXP in '::' '<' 'RegisterPass.*>' '(' '} else' '\bopt\b.*>'; do $GREP "$REGEXP\$" $FILES | cat done diff --git a/scripts/translate b/scripts/translate index ff846507b..0c653f352 100755 --- a/scripts/translate +++ b/scripts/translate @@ -132,7 +132,7 @@ fi if [ "$SKIP" -eq 0 ]; then REVAMB_LOG="$LL.log" CSV="$LL.ll.li.csv" - "$REVAMB" -g ll --debug jtcount,osrjts --use-debug-symbols $BASE $EXTRA_OPTIONS "$INPUT" "$LL.ll" "$@" |& tee "$REVAMB_LOG" + "$REVAMB" -g ll --debug-log jtcount --debug-log osrjts --use-debug-symbols $BASE $EXTRA_OPTIONS "$INPUT" "$LL.ll" "$@" |& tee "$REVAMB_LOG" fi if [ "$ISOLATE" -eq 1 ]; then diff --git a/tests/Runtime/RuntimeTests.cmake b/tests/Runtime/RuntimeTests.cmake index 426b02752..7f999416e 100644 --- a/tests/Runtime/RuntimeTests.cmake +++ b/tests/Runtime/RuntimeTests.cmake @@ -67,7 +67,7 @@ foreach(TEST_NAME ${TESTS}) # Translate the dynamic native version add_test(NAME translate-native-dynamic-${TEST_NAME} - COMMAND sh -c "${CMAKE_BINARY_DIR}/translate $ -- --functions-boundaries -g ll") + COMMAND sh -c "${CMAKE_BINARY_DIR}/translate $") set_tests_properties(translate-native-dynamic-${TEST_NAME} PROPERTIES LABELS "runtime;translate-native-dynamic;${TEST_NAME}") @@ -127,13 +127,13 @@ foreach(ARCH ${SUPPORTED_ARCHITECTURES}) # Translate the compiled binary add_test(NAME translate-${TEST_NAME}-${ARCH} - COMMAND sh -c "${CMAKE_BINARY_DIR}/translate ${BINARY} -- --functions-boundaries -g ll") + COMMAND sh -c "${CMAKE_BINARY_DIR}/translate ${BINARY}") set_tests_properties(translate-${TEST_NAME}-${ARCH} PROPERTIES LABELS "runtime;translate;${TEST_NAME};${ARCH}") # Translate the compiled binary with function isolation add_test(NAME translate-with-isolation-${TEST_NAME}-${ARCH} - COMMAND sh -c "cp ${BINARY} ${BINARY}.isolated-functions && ${CMAKE_BINARY_DIR}/translate -i ${BINARY}.isolated-functions -- --functions-boundaries -g ll") + COMMAND sh -c "cp ${BINARY} ${BINARY}.isolated-functions && ${CMAKE_BINARY_DIR}/translate -i ${BINARY}.isolated-functions") set_tests_properties(translate-${TEST_NAME}-${ARCH} PROPERTIES LABELS "runtime;translate-with-isolation;${TEST_NAME};${ARCH}") diff --git a/tools/revamb-dump/CMakeLists.txt b/tools/revamb-dump/CMakeLists.txt index 6ca2cebe4..0c8289075 100644 --- a/tools/revamb-dump/CMakeLists.txt +++ b/tools/revamb-dump/CMakeLists.txt @@ -9,7 +9,6 @@ add_executable(revamb-dump CollectNoreturn.cpp IsolateFunctions.cpp) target_link_libraries(revamb-dump - argparse Support DebugHelper StackAnalysis diff --git a/tools/revamb-dump/Main.cpp b/tools/revamb-dump/Main.cpp index 0a7be88c8..c93c16108 100644 --- a/tools/revamb-dump/Main.cpp +++ b/tools/revamb-dump/Main.cpp @@ -1,4 +1,4 @@ -/// \file dump.cpp +/// \file main.cpp /// \brief Standalone program to extract various information from the LLVM IR /// generated by revamb @@ -6,6 +6,7 @@ #include #include #include +#include // LLVM includes #include "llvm/ADT/StringRef.h" @@ -20,9 +21,9 @@ #include "revng/DebugHelper/DebugHelper.h" #include "revng/StackAnalysis/StackAnalysis.h" #include "revng/Support/Callgrind.h" +#include "revng/Support/CommandLine.h" #include "revng/Support/Debug.h" #include "revng/Support/Statistics.h" -#include "revng/argparse/argparse.h" // Local includes #include "CollectCFG.h" @@ -31,126 +32,105 @@ #include "IsolateFunctions.h" using namespace llvm; +using namespace llvm::cl; -struct ProgramParameters { - const char *InputPath; - const char *CFGPath; - const char *NoreturnPath; - const char *FunctionBoundariesPath; - const char *StackAnalysisPath; - const char *FunctionIsolationPath; - bool PrintStats; -}; +using std::string; -static const char *const Usage[] = { - "revamb-dump [options] INFILE", - nullptr, -}; +namespace { -static bool parseArgs(int Argc, const char *Argv[], ProgramParameters &Result) { - // Initialize argument parser - const char *DebugLoggingString = nullptr; - struct argparse Arguments; - struct argparse_option Options[] = { - OPT_HELP(), - OPT_STRING('d', "debug", &DebugLoggingString, "enable verbose logging."), - OPT_STRING('c', - "cfg", - &Result.CFGPath, - "path where the CFG should be stored."), - OPT_STRING('n', - "noreturn", - &Result.NoreturnPath, - "path where the list of noreturn basic blocks should be " - "stored."), - OPT_STRING('f', - "functions-boundaries", - &Result.FunctionBoundariesPath, - "path where the list of function boundaries blocks should be " - "stored."), - OPT_STRING('s', - "stack-analysis", - &Result.StackAnalysisPath, - "path where the result of the stack analysis should be stored."), - OPT_BOOLEAN('T', - "stats", - &Result.PrintStats, - "print statistics upon exit or SIGINT."), - OPT_STRING('i', - "functions-isolation", - &Result.FunctionIsolationPath, - "path where a new LLVM module containing the reorganization of " - "the basic blocks into the corresponding functions identified " - "by function boundaries analysis performed by revamb should be " - "stored."), - OPT_BOOLEAN('T', - "stats", - &Result.PrintStats, - "print statistics upon exit or SIGINT."), - OPT_END(), - }; +opt CFGPath("cfg", + desc("path where the CFG should be stored"), + cat(MainCategory), + value_desc("path")); +alias A1("c", desc("Alias for -cfg"), aliasopt(CFGPath), cat(MainCategory)); - argparse_init(&Arguments, Options, Usage, 0); - argparse_describe(&Arguments, - "\nrevamb-dump.", - "\nDump several high-level information from the " - "revamb-generated LLVM IR.\n"); - Argc = argparse_parse(&Arguments, Argc, Argv); +opt NoreturnPath("noreturn", + desc("path where the list of noreturn " + "basic blocks should be stored"), + cat(MainCategory), + value_desc("path")); +alias A2("n", + desc("Alias for -noreturn"), + aliasopt(NoreturnPath), + cat(MainCategory)); - if (DebugLoggingString != nullptr) { - std::string Input(DebugLoggingString); - std::stringstream Stream(Input); - std::string Type; - while (std::getline(Stream, Type, ',')) - Loggers->enable(Type.c_str()); - } +#define DESCRIPTION \ + desc("path where the result of the stack analysis should be stored") +opt StackAnalysisPath("stack-analysis", + DESCRIPTION, + cat(MainCategory), + value_desc("path")); +#undef DESCRIPTION - if (Result.PrintStats) - OnQuitStatistics->install(); +alias A3("s", + desc("Alias for -stack-analysis"), + aliasopt(StackAnalysisPath), + cat(MainCategory)); - // Handle positional arguments - if (Argc != 1) { - fprintf(stderr, "Please specify one and only one input file.\n"); - return false; - } +#define DESCRIPTION \ + desc("path where a new LLVM module containing the reorganization of the " \ + "basic blocks into the corresponding functions identified by function " \ + "boundaries analysis performed by revamb should be stored") +opt FunctionIsolationPath("function-isolation", + DESCRIPTION, + cat(MainCategory), + value_desc("path")); +#undef DESCRIPTION - Result.InputPath = Argv[0]; +alias A4("i", + desc("Alias for -function-isolation"), + aliasopt(FunctionIsolationPath), + cat(MainCategory)); - return true; -} +#define DESCRIPTION \ + desc("path where a new LLVM module containing the reorganization of the " \ + "basic blocks into the corresponding functions identified by function " \ + "boundaries analysis performed by revamb should be stored") +opt FunctionBoundariesPath("functions-boundaries", + DESCRIPTION, + cat(MainCategory), + value_desc("path")); +#undef DESCRIPTION + +alias A5("b", + desc("Alias for -functions-boundaries"), + aliasopt(FunctionBoundariesPath), + cat(MainCategory)); + +opt InputPath(Positional, Required, desc("")); + +} // namespace class DumpPass : public FunctionPass { public: static char ID; public: - DumpPass(ProgramParameters &Parameters) : - FunctionPass(ID), - Parameters(Parameters) {} + DumpPass() : FunctionPass(ID) {} bool runOnFunction(Function &F) override; void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); - if (Parameters.CFGPath != nullptr) + if (CFGPath.size() != 0) AU.addRequired(); - if (Parameters.NoreturnPath != nullptr) + if (NoreturnPath.size() != 0) AU.addRequired(); - if (Parameters.FunctionBoundariesPath != nullptr) + if (FunctionBoundariesPath.size() != 0) AU.addRequired(); - if (Parameters.StackAnalysisPath != nullptr) + if (StackAnalysisPath.size() != 0) AU.addRequired>(); - if (Parameters.FunctionIsolationPath != nullptr) + if (FunctionIsolationPath.size() != 0) AU.addRequired(); } private: - std::ostream &pathToStream(const char *Path, std::ofstream &File) { + std::ostream &pathToStream(const std::string &Path, std::ofstream &File) { if (Path[0] == '-' && Path[1] == '\0') { return std::cout; } else { @@ -161,7 +141,7 @@ private: } } - void dumpModule(Module *Module, const char *Path) { + void dumpModule(Module *Module, std::string Path) { std::ofstream Output; // If output path is `-` print on stdout @@ -171,12 +151,9 @@ private: } // Initialize the debug helper object - DebugHelper Debug(Path, Path, Module, DebugInfoType::LLVMIR); + DebugHelper Debug(Path, Module, DebugInfoType::LLVMIR, Path); Debug.generateDebugInfo(); } - -private: - ProgramParameters &Parameters; }; char DumpPass::ID = 0; @@ -184,47 +161,48 @@ char DumpPass::ID = 0; bool DumpPass::runOnFunction(Function &) { std::ofstream Output; - if (Parameters.CFGPath != nullptr) { + if (CFGPath.size() != 0) { auto &Analysis = getAnalysis(); - Analysis.serialize(pathToStream(Parameters.CFGPath, Output)); + Analysis.serialize(pathToStream(CFGPath, Output)); } - if (Parameters.NoreturnPath != nullptr) { + if (NoreturnPath.size() != 0) { auto &Analysis = getAnalysis(); - Analysis.serialize(pathToStream(Parameters.NoreturnPath, Output)); + Analysis.serialize(pathToStream(NoreturnPath, Output)); } - if (Parameters.FunctionBoundariesPath != nullptr) { + if (FunctionBoundariesPath.size() != 0) { auto &Analysis = getAnalysis(); - Analysis.serialize(pathToStream(Parameters.FunctionBoundariesPath, Output)); + Analysis.serialize(pathToStream(FunctionBoundariesPath, Output)); } - if (Parameters.StackAnalysisPath != nullptr) { + if (StackAnalysisPath.size() != 0) { auto &Analysis = getAnalysis>(); - Analysis.serialize(pathToStream(Parameters.StackAnalysisPath, Output)); + Analysis.serialize(pathToStream(StackAnalysisPath, Output)); } - if (Parameters.FunctionIsolationPath != nullptr) { + if (FunctionIsolationPath.size() != 0) { auto &Analysis = getAnalysis(); Module *ModifiedModule = Analysis.getModule(); - dumpModule(ModifiedModule, Parameters.FunctionIsolationPath); + dumpModule(ModifiedModule, FunctionIsolationPath); } return false; } int main(int argc, const char *argv[]) { - ProgramParameters Parameters = {}; - - if (!parseArgs(argc, argv, Parameters)) - return EXIT_FAILURE; + Loggers->registerArguments(); + HideUnrelatedOptions({ &MainCategory }); + ParseCommandLineOptions(argc, argv); + Loggers->activateArguments(); + installStatistics(); LLVMContext &Context = getGlobalContext(); SMDiagnostic Err; std::unique_ptr TheModule; { Callgrind DisableCallgrind(false); - TheModule = parseIRFile(Parameters.InputPath, Err, Context); + TheModule = parseIRFile(InputPath, Err, Context); } if (!TheModule) { @@ -233,7 +211,7 @@ int main(int argc, const char *argv[]) { } legacy::FunctionPassManager FPM(TheModule.get()); - FPM.add(new DumpPass(Parameters)); + FPM.add(new DumpPass()); FPM.run(*TheModule->getFunction("root")); return EXIT_SUCCESS; diff --git a/tools/revamb/BinaryFile.cpp b/tools/revamb/BinaryFile.cpp index a3c588a9d..7592ab1b0 100644 --- a/tools/revamb/BinaryFile.cpp +++ b/tools/revamb/BinaryFile.cpp @@ -25,6 +25,7 @@ #include "llvm/Support/LEB128.h" // Local libraries includes +#include "revng/Support/CommandLine.h" #include "revng/Support/Debug.h" // Local includes @@ -37,9 +38,7 @@ using std::make_pair; static Logger<> EhFrameLog("ehframe"); -BinaryFile::BinaryFile(std::string FilePath, - bool UseSections, - uint64_t BaseAddress) : +BinaryFile::BinaryFile(std::string FilePath, uint64_t BaseAddress) : BaseAddress(0) { auto BinaryOrErr = object::createBinary(FilePath); revng_assert(BinaryOrErr, "Couldn't open the input file"); @@ -236,29 +235,29 @@ BinaryFile::BinaryFile(std::string FilePath, if (TheArchitecture.pointerSize() == 32) { if (TheArchitecture.isLittleEndian()) { if (TheArchitecture.hasRelocationAddend()) { - parseELF(TheBinary, UseSections, BaseAddress); + parseELF(TheBinary, BaseAddress); } else { - parseELF(TheBinary, UseSections, BaseAddress); + parseELF(TheBinary, BaseAddress); } } else { if (TheArchitecture.hasRelocationAddend()) { - parseELF(TheBinary, UseSections, BaseAddress); + parseELF(TheBinary, BaseAddress); } else { - parseELF(TheBinary, UseSections, BaseAddress); + parseELF(TheBinary, BaseAddress); } } } else if (TheArchitecture.pointerSize() == 64) { if (TheArchitecture.isLittleEndian()) { if (TheArchitecture.hasRelocationAddend()) { - parseELF(TheBinary, UseSections, BaseAddress); + parseELF(TheBinary, BaseAddress); } else { - parseELF(TheBinary, UseSections, BaseAddress); + parseELF(TheBinary, BaseAddress); } } else { if (TheArchitecture.hasRelocationAddend()) { - parseELF(TheBinary, UseSections, BaseAddress); + parseELF(TheBinary, BaseAddress); } else { - parseELF(TheBinary, UseSections, BaseAddress); + parseELF(TheBinary, BaseAddress); } } } else { @@ -352,9 +351,7 @@ struct RelocationHelper { }; template -void BinaryFile::parseELF(object::ObjectFile *TheBinary, - bool UseSections, - uint64_t BaseAddress) { +void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { // Parse the ELF file std::error_code EC; object::ELFFile TheELF(TheBinary->getData(), EC); @@ -434,7 +431,7 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, // If it's an executable segment, and we've been asked so, register // which sections actually contain code - if (UseSections && Segment.IsExecutable) { + if (UseDebugSymbols && Segment.IsExecutable) { using Elf_Shdr = const typename object::ELFFile::Elf_Shdr; auto Inserter = std::back_inserter(Segment.ExecutableSections); for (Elf_Shdr &SectionHeader : TheELF.sections()) { diff --git a/tools/revamb/BinaryFile.h b/tools/revamb/BinaryFile.h index 9ecbefff3..d515ca08a 100644 --- a/tools/revamb/BinaryFile.h +++ b/tools/revamb/BinaryFile.h @@ -175,7 +175,7 @@ public: /// \param UseSections whether information in sections, if available, should /// be employed or not. This is useful to precisely identify exeutable /// code. - BinaryFile(std::string FilePath, bool UseSections, uint64_t BaseAddress); + BinaryFile(std::string FilePath, uint64_t BaseAddress); llvm::Optional> getAddressData(uint64_t Address) const { @@ -235,9 +235,7 @@ private: /// \brief Parse an ELF file to load all the required information template - void parseELF(llvm::object::ObjectFile *TheBinary, - bool UseSections, - uint64_t BaseAddress); + void parseELF(llvm::object::ObjectFile *TheBinary, uint64_t BaseAddress); /// \brief Parse the .eh_frame_hdr section to obtain the address and the /// number of FDEs in .eh_frame diff --git a/tools/revamb/CMakeLists.txt b/tools/revamb/CMakeLists.txt index c14198007..c9d3cae42 100644 --- a/tools/revamb/CMakeLists.txt +++ b/tools/revamb/CMakeLists.txt @@ -23,7 +23,6 @@ target_link_libraries(revamb m Support DebugHelper - argparse BasicAnalyses ${LLVM_LIBRARIES}) add_custom_command(TARGET revamb POST_BUILD VERBATIM diff --git a/tools/revamb/CodeGenerator.cpp b/tools/revamb/CodeGenerator.cpp index 307309b0b..391d90e06 100644 --- a/tools/revamb/CodeGenerator.cpp +++ b/tools/revamb/CodeGenerator.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,7 @@ // Local libraries includes #include "revng/DebugHelper/DebugHelper.h" +#include "revng/Support/CommandLine.h" #include "revng/Support/Debug.h" #include "revng/Support/revng.h" @@ -55,6 +57,98 @@ using namespace llvm; using std::make_pair; +using std::string; + +// Register all the arguments + +// TODO: can we drop this and the associated functionality? +static cl::opt CoveragePath("coverage-path", + cl::desc("destination path for the CSV " + "containing " + "translated ranges"), + cl::value_desc("path"), + cl::cat(MainCategory)); +static cl::alias A1("c", + cl::desc("Alias for -coverage-path"), + cl::aliasopt(CoveragePath), + cl::cat(MainCategory)); + +// TODO: linking-info-path? +static cl::opt LinkingInfoPath("linking-info", + cl::desc("destination path for the CSV " + "containing linking info"), + cl::value_desc("path"), + cl::cat(MainCategory)); +static cl::alias A2("i", + cl::desc("Alias for -linking-info"), + cl::aliasopt(LinkingInfoPath), + cl::cat(MainCategory)); + +// TODO: can we drop this and the associated functionality? +static cl::opt BBSummaryPath("bb-summary", + cl::desc("destination path for the CSV " + "containing the statistics about " + "the translated basic blocks"), + cl::value_desc("path"), + cl::cat(MainCategory)); +static cl::alias A3("b", + cl::desc("Alias for -bb-summary"), + cl::aliasopt(BBSummaryPath), + cl::cat(MainCategory)); + +static cl::opt NoLink("no-link", + cl::desc("do not link the output to QEMU helpers"), + cl::cat(MainCategory)); +static cl::alias A4("L", + cl::desc("Alias for -no-link"), + cl::aliasopt(NoLink), + cl::cat(MainCategory)); + +// TODO: this will disappear once we integrate the stack analysis +static cl::opt DetectFunctionBoundaries("functions-boundaries", + cl::desc("enable functions " + "boundaries " + "detection"), + cl::cat(MainCategory)); +static cl::alias A5("f", + cl::desc("Alias for -functions-boundaries"), + cl::aliasopt(DetectFunctionBoundaries), + cl::cat(MainCategory)); + +// Enable Debug Options to be specified on the command line +auto X = cl::values(clEnumValN(DebugInfoType::None, + "none", + "no debug information"), + clEnumValN(DebugInfoType::OriginalAssembly, + "asm", + "debug information referred to the assembly " + "of the input file"), + clEnumValN(DebugInfoType::PTC, + "ptc", + "debug information referred to the Portable " + "Tiny Code"), + clEnumValN(DebugInfoType::LLVMIR, + "ll", + "debug information referred to the LLVM IR"), + clEnumValEnd); +static cl::opt DebugInfo("debug-info", + cl::desc("emit debug " + "information"), + X, + cl::cat(MainCategory)); + +static cl::alias A6("g", + cl::desc("Alias for -debug-info"), + cl::aliasopt(DebugInfo), + cl::cat(MainCategory)); + +// TODO: is this still active? +static cl::opt DebugPath("debug-path", + cl::desc("destination path for the generated " + "debug " + "source"), + cl::value_desc("path"), + cl::cat(MainCategory)); static Logger<> PTCLog("ptc"); @@ -83,28 +177,13 @@ CodeGenerator::CodeGenerator(BinaryFile &Binary, Architecture &Target, std::string Output, std::string Helpers, - std::string EarlyLinked, - DebugInfoType DebugInfo, - std::string Debug, - std::string LinkingInfo, - std::string Coverage, - std::string BBSummary, - bool EnableOSRA, - bool DetectFunctionBoundaries, - bool EnableLinking, - bool ExternalCSVs, - bool UseDebugSymbols) : + std::string EarlyLinked) : TargetArchitecture(Target), Context(getGlobalContext()), TheModule((new Module("top", Context))), OutputPath(Output), - Debug(new DebugHelper(Output, Debug, TheModule.get(), DebugInfo)), - Binary(Binary), - EnableOSRA(EnableOSRA), - DetectFunctionBoundaries(DetectFunctionBoundaries), - EnableLinking(EnableLinking), - ExternalCSVs(ExternalCSVs), - UseDebugSymbols(UseDebugSymbols) { + Debug(new DebugHelper(Output, TheModule.get(), DebugInfo, DebugPath)), + Binary(Binary) { OriginalInstrMDKind = Context.getMDKindID("oi"); PTCInstrMDKind = Context.getMDKindID("pi"); DbgMDKind = Context.getMDKindID("dbg"); @@ -112,18 +191,16 @@ CodeGenerator::CodeGenerator(BinaryFile &Binary, HelpersModule = parseIR(Helpers, Context); EarlyLinkedModule = parseIR(EarlyLinked, Context); - if (Coverage.size() == 0) - Coverage = Output + ".coverage.csv"; - this->CoveragePath = Coverage; + if (CoveragePath.size() == 0) + CoveragePath = Output + ".coverage.csv"; - if (BBSummary.size() == 0) - BBSummary = Output + ".bbsummary.csv"; - this->BBSummaryPath = BBSummary; + if (BBSummaryPath.size() == 0) + BBSummaryPath = Output + ".bbsummary.csv"; // Prepare the linking info CSV - if (LinkingInfo.size() == 0) - LinkingInfo = OutputPath + ".li.csv"; - std::ofstream LinkingInfoStream(LinkingInfo); + if (LinkingInfoPath.size() == 0) + LinkingInfoPath = OutputPath + ".li.csv"; + std::ofstream LinkingInfoStream(LinkingInfoPath); LinkingInfoStream << "name,start,end\n"; auto *Uint8Ty = Type::getInt8Ty(Context); @@ -268,7 +345,7 @@ public: char CpuLoopFunctionPass::ID = 0; using RegisterCLF = RegisterPass; -static RegisterCLF X("cpu-loop", "cpu_loop FunctionPass", false, false); +static RegisterCLF Y("cpu-loop", "cpu_loop FunctionPass", false, false); void CpuLoopFunctionPass::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); @@ -371,7 +448,7 @@ private: char CpuLoopExitPass::ID = 0; using RegisterCLE = RegisterPass; -static RegisterCLE Y("cpu-loop-exit", "cpu_loop_exit Pass", false, false); +static RegisterCLE Z("cpu-loop-exit", "cpu_loop_exit Pass", false, false); static void purgeNoReturn(Function *F) { auto &Context = F->getParent()->getContext(); @@ -624,7 +701,7 @@ void CodeGenerator::translate(uint64_t VirtualAddress) { InputArchMD->addOperand(Tuple); // Create an instance of JumpTargetManager - JumpTargetManager JumpTargets(MainFunction, PCReg, Binary, EnableOSRA); + JumpTargetManager JumpTargets(MainFunction, PCReg, Binary); if (VirtualAddress == 0) { JumpTargets.harvestGlobalData(); @@ -934,7 +1011,7 @@ void CodeGenerator::translate(uint64_t VirtualAddress) { GV.setLinkage(GlobalValue::InternalLinkage); } - if (EnableLinking) { + if (not NoLink) { Linker TheLinker(*TheModule); bool Result = TheLinker.linkInModule(std::move(HelpersModule), Linker::LinkOnlyNeeded); @@ -957,7 +1034,7 @@ void CodeGenerator::translate(uint64_t VirtualAddress) { if (DetectFunctionBoundaries) { legacy::FunctionPassManager FPM(&*TheModule); using FBDP = FunctionBoundariesDetectionPass; - FPM.add(new FBDP(&JumpTargets, "", UseDebugSymbols)); + FPM.add(new FBDP(&JumpTargets, "")); FPM.run(*MainFunction); } @@ -979,7 +1056,7 @@ void CodeGenerator::translate(uint64_t VirtualAddress) { Translator.finalizeNewPCMarkers(CoveragePath); - Variables.finalize(ExternalCSVs); + Variables.finalize(); Debug->generateDebugInfo(); } diff --git a/tools/revamb/CodeGenerator.h b/tools/revamb/CodeGenerator.h index daa951cf0..e0848a40f 100644 --- a/tools/revamb/CodeGenerator.h +++ b/tools/revamb/CodeGenerator.h @@ -49,36 +49,11 @@ public: /// \param Target target architecture. /// \param Output path where the generate LLVM IR must be saved. /// \param Helpers path of the LLVM IR file containing the QEMU helpers. - /// \param DebugInfo type of debug information to generate. - /// \param Debug path where the debugging source file must be written. If an - /// empty string, the output file name plus ".S", if \p DebugInfo is - /// DebugInfoType::OriginalAssembly, or ".ptc", if \p DebugInfo is - /// DebugInfoType::PTC. - /// \param LinkingInfo path where the information about how the linking should - /// be stored. If an empty string, the output file name with a - /// ".li.csv" suffix will be used. - /// \param Coverage path where the information about instruction coverage - /// should be stored. If an empty string, the output file name with a - /// ".coverage.csv" suffix will be used. - /// \param EnableOSRA specify whether OSRA should be used to discover - /// additional jump targets or not. - /// \param EnableLinking specifying whether linking to QEMU helpers should be - /// performed or not. CodeGenerator(BinaryFile &Binary, Architecture &Target, std::string Output, std::string Helpers, - std::string EarlyLinked, - DebugInfoType DebugInfo, - std::string Debug, - std::string LinkingInfo, - std::string Coverage, - std::string BBSummary, - bool EnableOSRA, - bool DetectFunctionBoundaries, - bool EnableLinking, - bool ExternalCSVs, - bool UseDebugSymbols); + std::string EarlyLinked); ~CodeGenerator(); @@ -103,9 +78,7 @@ private: /// \param TheBinary the LLVM ObjectFile representing the ELF file. /// \param LinkingInfo path where the .li.csv file should be created. template - void parseELF(llvm::object::ObjectFile *TheBinary, - std::string LinkingInfo, - bool UseSections); + void parseELF(llvm::object::ObjectFile *TheBinary, bool UseSections); /// \brief Import a helper function definition /// @@ -128,14 +101,7 @@ private: unsigned PTCInstrMDKind; unsigned DbgMDKind; - std::string CoveragePath; - bool EnableOSRA; - std::string BBSummaryPath; std::string FunctionListPath; - bool DetectFunctionBoundaries; - bool EnableLinking; - bool ExternalCSVs; - bool UseDebugSymbols; }; #endif // CODEGENERATOR_H diff --git a/tools/revamb/FunctionBoundariesDetectionPass.cpp b/tools/revamb/FunctionBoundariesDetectionPass.cpp index 15b9390ee..053466d35 100644 --- a/tools/revamb/FunctionBoundariesDetectionPass.cpp +++ b/tools/revamb/FunctionBoundariesDetectionPass.cpp @@ -28,6 +28,7 @@ // Local libraries includes #include "revng/ADT/Queue.h" +#include "revng/Support/CommandLine.h" #include "revng/Support/Debug.h" #include "revng/Support/IRHelpers.h" @@ -55,12 +56,9 @@ static RegisterFBDP X("fbdp", "Function Boundaries Detection Pass", true, true); class FunctionBoundariesDetectionImpl { public: - FunctionBoundariesDetectionImpl(Function &F, - JumpTargetManager *JTM, - bool UseDebugSymbols) : + FunctionBoundariesDetectionImpl(Function &F, JumpTargetManager *JTM) : F(F), - JTM(JTM), - UseDebugSymbols(UseDebugSymbols) {} + JTM(JTM) {} map> run(); @@ -182,7 +180,6 @@ private: private: Function &F; JumpTargetManager *JTM; - bool UseDebugSymbols; std::map FunctionCalls; std::map> CallPredecessors; @@ -632,7 +629,7 @@ std::string FBD::CFEPRelation::describe() const { } bool FBDP::runOnFunction(Function &F) { - FBD Impl(F, JTM, UseDebugSymbols); + FBD Impl(F, JTM); Functions = Impl.run(); serialize(); return false; diff --git a/tools/revamb/FunctionBoundariesDetectionPass.h b/tools/revamb/FunctionBoundariesDetectionPass.h index 60ab1fafa..3b6f62000 100644 --- a/tools/revamb/FunctionBoundariesDetectionPass.h +++ b/tools/revamb/FunctionBoundariesDetectionPass.h @@ -25,8 +25,7 @@ public: public: FunctionBoundariesDetectionPass() : llvm::FunctionPass(ID), JTM(nullptr) {} FunctionBoundariesDetectionPass(JumpTargetManager *JTM, - std::string SerializePath, - bool UseDebugSymbols) : + std::string SerializePath) : llvm::FunctionPass(ID), JTM(JTM), SerializePath(SerializePath) {} @@ -43,7 +42,6 @@ private: private: JumpTargetManager *JTM; std::string SerializePath; - bool UseDebugSymbols; std::map> Functions; }; diff --git a/tools/revamb/JumpTargetManager.cpp b/tools/revamb/JumpTargetManager.cpp index 55a56eace..6bf0d1acf 100644 --- a/tools/revamb/JumpTargetManager.cpp +++ b/tools/revamb/JumpTargetManager.cpp @@ -34,6 +34,7 @@ // Local libraries includes #include "revng/ADT/Queue.h" #include "revng/BasicAnalyses/GeneratedCodeBasicInfo.h" +#include "revng/Support/CommandLine.h" #include "revng/Support/Debug.h" #include "revng/Support/IRHelpers.h" #include "revng/Support/revng.h" @@ -46,20 +47,30 @@ using namespace llvm; +namespace { -static bool isSumJump(StoreInst *PCWrite); +Logger<> JTCountLog("jtcount"); + +cl::opt NoOSRA("no-osra", cl::desc(" OSRA"), cl::cat(MainCategory)); +cl::alias A1("O", + cl::desc("Alias for -no-osra"), + cl::aliasopt(NoOSRA), + cl::cat(MainCategory)); + +RegisterPass X("translate-db", + "Translate Direct Branches" + " Pass", + false, + false); + +// TODO: this is kind of an abuse +Logger<> Verify("verify"); + +} // namespace char TranslateDirectBranchesPass::ID = 0; -static RegisterPass X("translate-db", - "Translate Direct Branches" - " Pass", - false, - false); - -// TODO: this is kind of an abuse -static Logger<> Verify("verify"); -static Logger<> JTCountLog("jtcount"); +static bool isSumJump(StoreInst *PCWrite); void TranslateDirectBranchesPass::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); @@ -184,7 +195,7 @@ bool TranslateDirectBranchesPass::pinConstantStore(Function &F) { forceFallthroughAfterHelper(Call); } else { uint64_t NextPC = JTM->getNextPC(PCWrite); - if (NextPC != 0 && JTM->isOSRAEnabled() && isSumJump(PCWrite)) + if (NextPC != 0 && not NoOSRA && isSumJump(PCWrite)) JTM->registerJT(NextPC, JTReason::SumJump); auto *Address = dyn_cast(PCWrite->getValueOperand()); @@ -438,8 +449,7 @@ getOption(StringMap &Options, const char *Name) { JumpTargetManager::JumpTargetManager(Function *TheFunction, Value *PCReg, - const BinaryFile &Binary, - bool EnableOSRA) : + const BinaryFile &Binary) : TheModule(*TheFunction->getParent()), Context(TheModule.getContext()), TheFunction(TheFunction), @@ -450,7 +460,6 @@ JumpTargetManager::JumpTargetManager(Function *TheFunction, Dispatcher(nullptr), DispatcherSwitch(nullptr), Binary(Binary), - EnableOSRA(EnableOSRA), NoReturn(Binary.architecture()), CurrentCFGForm(UnknownFormCFG) { FunctionType *ExitTBTy = FunctionType::get(Type::getVoidTy(Context), @@ -984,7 +993,7 @@ void JumpTargetManager::translateIndirectJumps() { "Direct jumps should not be handled here"); } - if (PCWrite != nullptr && EnableOSRA && isSumJump(PCWrite)) + if (PCWrite != nullptr && not NoOSRA && isSumJump(PCWrite)) handleSumJump(PCWrite); if (getLimitedValue(Call->getArgOperand(0)) == 0) { @@ -1361,7 +1370,7 @@ void JumpTargetManager::harvest() { << NewBranches << " new branches were found"); } - if (EnableOSRA && empty()) { + if (not NoOSRA && empty()) { if (Verify.isEnabled()) revng_assert(not verifyModule(TheModule, &dbgs())); diff --git a/tools/revamb/JumpTargetManager.h b/tools/revamb/JumpTargetManager.h index 91f3906d7..727528f4b 100644 --- a/tools/revamb/JumpTargetManager.h +++ b/tools/revamb/JumpTargetManager.h @@ -183,11 +183,9 @@ public: /// \param PCReg the global variable representing the program counter. /// \param Binary reference to the information about a given binary, such as /// segments and symbols. - /// \param EnableOSRA whether OSRA is enabled or not. JumpTargetManager(llvm::Function *TheFunction, llvm::Value *PCReg, - const BinaryFile &Binary, - bool EnableOSRA); + const BinaryFile &Binary); /// \brief Transform the IR to represent the request form of CFG void setCFGForm(CFGForm NewForm); @@ -232,8 +230,6 @@ public: /// performed. llvm::Function *exitTB() { return ExitTB; } - bool isOSRAEnabled() { return EnableOSRA; } - /// \brief Pop from the list of program counters to explore /// /// \return a pair containing the PC and the initial block to use, or @@ -560,8 +556,6 @@ private: const BinaryFile &Binary; - bool EnableOSRA; - unsigned NewBranches = 0; std::set UnusedCodePointers; diff --git a/tools/revamb/Main.cpp b/tools/revamb/Main.cpp index c6251bcd5..80c07d46b 100644 --- a/tools/revamb/Main.cpp +++ b/tools/revamb/Main.cpp @@ -29,10 +29,10 @@ extern "C" { #include "llvm/Object/ELF.h" // Local libraries includes +#include "revng/Support/CommandLine.h" #include "revng/Support/Debug.h" #include "revng/Support/Statistics.h" #include "revng/Support/revng.h" -#include "revng/argparse/argparse.h" // Local includes #include "BinaryFile.h" @@ -40,28 +40,47 @@ extern "C" { #include "PTCInterface.h" PTCInterface ptc = {}; ///< The interface with the PTC library. + +using namespace llvm::cl; + +using std::string; + +// TODO: drop short aliases + +namespace { + +#define DESCRIPTION desc("virtual address of the entry point where to start") +opt EntryPointAddress("entry", + DESCRIPTION, + value_desc("address"), + cat(MainCategory)); +#undef DESCRIPTION +alias A1("e", + desc("Alias for -entry"), + aliasopt(EntryPointAddress), + cat(MainCategory)); + +#define DESCRIPTION desc("base address where dynamic objects should be loaded") +opt BaseAddress("base", + DESCRIPTION, + value_desc("address"), + cat(MainCategory), + init(0x50000000)); +#undef DESCRIPTION + +#define DESCRIPTION desc("Alias for -base") +alias A2("B", DESCRIPTION, aliasopt(BaseAddress), cat(MainCategory)); +#undef DESCRIPTION + +opt InputPath(Positional, Required, desc("")); +opt OutputPath(Positional, Required, desc("")); + +} // namespace + static std::string LibTinycodePath; static std::string LibHelpersPath; static std::string EarlyLinkedPath; -struct ProgramParameters { - const char *InputPath; - const char *OutputPath; - size_t EntryPointAddress; - DebugInfoType DebugInfo; - const char *DebugPath; - const char *LinkingInfoPath; - const char *CoveragePath; - const char *BBSummaryPath; - bool NoOSRA; - bool UseDebugSymbols; - bool DetectFunctionsBoundaries; - bool NoLink; - bool External; - bool PrintStats; - uint64_t BaseAddress; -}; - // When LibraryPointer is destroyed, the destructor calls // LibraryDestructor::operator()(LibraryPointer::get()). // The problem is that LibraryDestructor::operator() does not take arguments, @@ -74,24 +93,6 @@ using LibraryDestructor = std::integral_constant; using LibraryPointer = std::unique_ptr; -static const char *const Usage[] = { - "revamb [options] [--] INFILE OUTFILE", - nullptr, -}; - -static bool toNumber(const char *String, uint64_t *Destination) { - const char *End = String + strlen(String); - char *NumberEnd; - unsigned long long Result; - Result = strtoull(String, &NumberEnd, 0); - - if (End != NumberEnd) - return false; - - *Destination = static_cast(Result); - return true; -} - static void findFiles(const char *Architecture) { // TODO: make this optional char *FullPath = realpath("/proc/self/exe", nullptr); @@ -181,172 +182,14 @@ static int loadPTCLibrary(LibraryPointer &PTCLibrary) { return EXIT_SUCCESS; } -/// Parses the input arguments to the program. -/// -/// \param Argc number of arguments. -/// \param Argv array of strings containing the arguments. -/// \param Parameters where to store the parsed parameters. -/// -/// \return EXIT_SUCCESS if the parameters have been successfully parsed. -static int -parseArgs(int Argc, const char *Argv[], ProgramParameters *Parameters) { - const char *DebugString = nullptr; - const char *DebugLoggingString = nullptr; - const char *EntryPointAddressString = nullptr; - uint64_t EntryPointAddress = 0; - const char *BaseAddressString = nullptr; - uint64_t BaseAddress = 0x50000000; - - // Initialize argument parser - struct argparse Arguments; - struct argparse_option Options[] = { - OPT_HELP(), - OPT_GROUP("Input description"), - OPT_STRING('e', - "entry", - &EntryPointAddressString, - "virtual address of the entry point where to start."), - OPT_STRING('s', - "debug-path", - &Parameters->DebugPath, - "destination path for the generated debug source."), - OPT_STRING('c', - "coverage-path", - &Parameters->CoveragePath, - "destination path for the CSV containing translated ranges."), - OPT_STRING('i', - "linking-info", - &Parameters->LinkingInfoPath, - "destination path for the CSV containing linking info."), - OPT_STRING('g', - "debug-info", - &DebugString, - "emit debug information. Possible values are 'none' for no debug" - " information, 'asm' for debug information referring to the" - " assembly of the input file, 'ptc' for debug information" - " referred to the Portable Tiny Code, or 'll' for debug" - " information referred to the LLVM IR."), - OPT_STRING('d', "debug", &DebugLoggingString, "enable verbose logging."), - OPT_BOOLEAN('O', "no-osra", &Parameters->NoOSRA, "disable OSRA."), - OPT_BOOLEAN('L', - "no-link", - &Parameters->NoLink, - "do not link the output to QEMU helpers."), - OPT_BOOLEAN('E', - "external", - &Parameters->External, - "set CSVs linkage to external, useful for debugging purposes."), - OPT_BOOLEAN('S', - "use-debug-symbols", - &Parameters->UseDebugSymbols, - "use section and symbol function informations, if available."), - OPT_STRING('b', - "bb-summary", - &Parameters->BBSummaryPath, - "destination path for the CSV containing the statistics about " - "the translated basic blocks."), - OPT_BOOLEAN('f', - "functions-boundaries", - &Parameters->DetectFunctionsBoundaries, - "enable functions boundaries detection."), - OPT_BOOLEAN('T', - "stats", - &Parameters->PrintStats, - "print statistics upon exit or SIGINT."), - OPT_STRING('B', - "base", - &BaseAddressString, - "base address where dynamic objects should be loaded."), - OPT_END(), - }; - - argparse_init(&Arguments, Options, Usage, 0); - argparse_describe(&Arguments, - "\nrevamb.", - "\nTranslates a binary into a program for a different " - "architecture.\n"); - Argc = argparse_parse(&Arguments, Argc, Argv); - - // Handle positional arguments - if (Argc != 2) { - fprintf(stderr, "Too many arguments.\n"); - return EXIT_FAILURE; - } - - Parameters->InputPath = Argv[0]; - Parameters->OutputPath = Argv[1]; - - // Check parameters - if (EntryPointAddressString != nullptr) { - if (not toNumber(EntryPointAddressString, &EntryPointAddress)) { - fprintf(stderr, - "Entry point parameter (-e, --entry) is not a" - " number.\n"); - return EXIT_FAILURE; - } - } - Parameters->EntryPointAddress = static_cast(EntryPointAddress); - - if (BaseAddressString != nullptr) { - if (not toNumber(BaseAddressString, &BaseAddress)) { - fprintf(stderr, "Base address (-B, --base) is not a number.\n"); - return EXIT_FAILURE; - } - } - Parameters->BaseAddress = BaseAddress; - - if (DebugString != nullptr) { - if (strcmp("none", DebugString) == 0) { - Parameters->DebugInfo = DebugInfoType::None; - } else if (strcmp("asm", DebugString) == 0) { - Parameters->DebugInfo = DebugInfoType::OriginalAssembly; - } else if (strcmp("ptc", DebugString) == 0) { - Parameters->DebugInfo = DebugInfoType::PTC; - } else if (strcmp("ll", DebugString) == 0) { - Parameters->DebugInfo = DebugInfoType::LLVMIR; - } else { - fprintf(stderr, - "Unexpected value for the debug type parameter" - " (-g, --debug).\n"); - return EXIT_FAILURE; - } - } - - if (DebugLoggingString != nullptr) { - std::string Input(DebugLoggingString); - std::stringstream Stream(Input); - std::string Type; - while (std::getline(Stream, Type, ',')) - Loggers->enable(Type.c_str()); - } - - if (Parameters->DebugPath == nullptr) - Parameters->DebugPath = ""; - - if (Parameters->LinkingInfoPath == nullptr) - Parameters->LinkingInfoPath = ""; - - if (Parameters->CoveragePath == nullptr) - Parameters->CoveragePath = ""; - - if (Parameters->BBSummaryPath == nullptr) - Parameters->BBSummaryPath = ""; - - if (Parameters->PrintStats) - OnQuitStatistics->install(); - - return EXIT_SUCCESS; -} - int main(int argc, const char *argv[]) { - // Parse arguments - ProgramParameters Parameters{}; - if (parseArgs(argc, argv, &Parameters) != EXIT_SUCCESS) - return EXIT_FAILURE; + Loggers->registerArguments(); + HideUnrelatedOptions({ &MainCategory }); + ParseCommandLineOptions(argc, argv); + installStatistics(); + Loggers->activateArguments(); - BinaryFile TheBinary(Parameters.InputPath, - Parameters.UseDebugSymbols, - Parameters.BaseAddress); + BinaryFile TheBinary(InputPath, BaseAddress); findFiles(TheBinary.architecture().name()); @@ -359,21 +202,11 @@ int main(int argc, const char *argv[]) { Architecture TargetArchitecture; CodeGenerator Generator(TheBinary, TargetArchitecture, - std::string(Parameters.OutputPath), + std::string(OutputPath), LibHelpersPath, - EarlyLinkedPath, - Parameters.DebugInfo, - std::string(Parameters.DebugPath), - std::string(Parameters.LinkingInfoPath), - std::string(Parameters.CoveragePath), - std::string(Parameters.BBSummaryPath), - !Parameters.NoOSRA, - Parameters.DetectFunctionsBoundaries, - !Parameters.NoLink, - Parameters.External, - Parameters.UseDebugSymbols); + EarlyLinkedPath); - Generator.translate(Parameters.EntryPointAddress); + Generator.translate(EntryPointAddress); Generator.serialize(); diff --git a/tools/revamb/VariableManager.cpp b/tools/revamb/VariableManager.cpp index 5408a50b9..a1e182563 100644 --- a/tools/revamb/VariableManager.cpp +++ b/tools/revamb/VariableManager.cpp @@ -35,7 +35,15 @@ using namespace llvm; -static Logger<> TypeAtOffsetLog("type-at-offset"); +// TODO: rename +cl::opt External("external", + cl::desc("set CSVs linkage to external, useful for " + "debugging purposes"), + cl::cat(MainCategory)); +static cl::alias A1("E", + cl::desc("Alias for -external"), + cl::aliasopt(External), + cl::cat(MainCategory)); class OffsetValueStack { @@ -78,7 +86,7 @@ private: static std::pair getTypeAtOffset(const DataLayout *TheLayout, Type *VarType, intptr_t Offset) { - auto &Log = TypeAtOffsetLog; + static Logger<> Log("type-at-offset"); unsigned Depth = 0; while (1) { diff --git a/tools/revamb/VariableManager.h b/tools/revamb/VariableManager.h index de815f747..0b1d225cf 100644 --- a/tools/revamb/VariableManager.h +++ b/tools/revamb/VariableManager.h @@ -15,6 +15,7 @@ #include "llvm/Pass.h" // Local libraries includes +#include "revng/Support/CommandLine.h" #include "revng/Support/revng.h" // Local includes @@ -34,6 +35,9 @@ class Value; class VariableManager; class CPUStateAccessAnalysisPass; +// TODO: rename +extern llvm::cl::opt External; + /// \brief Maintain the list of variables required by PTC /// /// It can be queried for a variable, which, if not already existing, will be @@ -145,12 +149,10 @@ public: bool EnvIsSrc); /// \brief Perform finalization steps on variables - /// - /// \param ExternalCSVs true if CSVs linkage should not be turned into static. - void finalize(bool ExternalCSVs) { + void finalize() { using namespace llvm; - if (!ExternalCSVs) { + if (not External) { for (auto &P : CPUStateGlobals) P.second->setLinkage(GlobalValue::InternalLinkage); for (auto &P : OtherGlobals)