diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e56ff895..9dd10e573 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ # dev +* Enhancement: Unified logging on stdout/stderr. Added option `--silent`. Printed text is colored only when output is a terminal ([#791](https://github.com/avast/retdec/issues/791). * Enhancement: Support all the CMake build types (i.e. `Debug`, `Release`, `RelWithDebInfo` and `MinSizeRel`) on all systems ([#774](https://github.com/avast/retdec/issues/774)). * Enhancement: YARA updated to version 4.0.1 ([#758](https://github.com/avast/retdec/issues/758)), fixed Mach-O parsing issue ([#283](https://github.com/avast/retdec/issues/283)). * Enhancement: Improved detection of many packers/installers/compilers in `retdec-fileinfo`, including Armadillo ([#733](https://github.com/avast/retdec/pull/733)), VMProtect ([#734](https://github.com/avast/retdec/pull/734), [#778](https://github.com/avast/retdec/pull/778)), Petite ([#735](https://github.com/avast/retdec/pull/735)), Enigma ([#741](https://github.com/avast/retdec/pull/741)), ASPack ([#743](https://github.com/avast/retdec/pull/743)), Eziriz ([#746](https://github.com/avast/retdec/pull/746)), PyInstaller ([#748](https://github.com/avast/retdec/pull/748)), Astrum InstallWizard ([#753](https://github.com/avast/retdec/pull/753)), AutoHotKey ([#756](https://github.com/avast/retdec/pull/756)), AutoIt ([#757](https://github.com/avast/retdec/pull/757)), BAT to PE-EXE script compilers ([#761](https://github.com/avast/retdec/pull/761)), Bero ([#764](https://github.com/avast/retdec/pull/764)), CExe ([#781](https://github.com/avast/retdec/pull/781)), MoleBox ([#815](https://github.com/avast/retdec/pull/815)), and other improvements ([#804](https://github.com/avast/retdec/pull/804)). diff --git a/cmake/options.cmake b/cmake/options.cmake index 6cf65382d..6f5980020 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -84,7 +84,6 @@ foreach(t ${RETDEC_ENABLE}) set_if_equal(${t} "fileinfo" RETDEC_ENABLE_FILEINFO) set_if_equal(${t} "getsig" RETDEC_ENABLE_GETSIG) set_if_equal(${t} "idr2pat" RETDEC_ENABLE_IDR2PAT) - set_if_equal(${t} "llvm-support" RETDEC_ENABLE_LLVM_SUPPORT) set_if_equal(${t} "llvmir-emul" RETDEC_ENABLE_LLVMIR_EMUL) set_if_equal(${t} "llvmir2hll" RETDEC_ENABLE_LLVMIR2HLL) set_if_equal(${t} "loader" RETDEC_ENABLE_LOADER) diff --git a/include/retdec/config/parameters.h b/include/retdec/config/parameters.h index 9a6fcc517..65d4f12aa 100644 --- a/include/retdec/config/parameters.h +++ b/include/retdec/config/parameters.h @@ -60,6 +60,8 @@ class Parameters void setOutputConfigFile(const std::string& file); void setOutputUnpackedFile(const std::string& file); void setOutputFormat(const std::string& format); + void setLogFile(const std::string& file); + void setErrFile(const std::string& file); void setMaxMemoryLimit(uint64_t limit); void setIsMaxMemoryLimitHalfRam(bool f); void setTimeout(uint64_t seconds); @@ -95,6 +97,8 @@ class Parameters const std::string& getOutputConfigFile() const; const std::string& getOutputUnpackedFile() const; const std::string& getOutputFormat() const; + const std::string& getLogFile() const; + const std::string& getErrFile() const; uint64_t getMaxMemoryLimit() const; uint64_t getTimeout() const; retdec::common::Address getEntryPoint() const; @@ -136,7 +140,7 @@ class Parameters private: /// Decompilation will verbosely inform about the /// decompilation process. - bool _verboseOutput = false; + bool _verboseOutput = true; /// Keep all functions in the decompiler's output. /// Otherwise, only functions reachable from main are kept. @@ -158,6 +162,8 @@ class Parameters std::string _outputConfigFile; std::string _outputUnpackedFile; std::string _outputFormat; + std::string _logFile; + std::string _errFile; uint64_t _maxMemoryLimit = 0; bool _maxMemoryLimitHalfRam = true; uint64_t _timeout = 0; diff --git a/include/retdec/llvm-support/diagnostics.h b/include/retdec/llvm-support/diagnostics.h deleted file mode 100644 index 1ecab7e44..000000000 --- a/include/retdec/llvm-support/diagnostics.h +++ /dev/null @@ -1,132 +0,0 @@ -/** -* @file include/retdec/llvm-support/diagnostics.h -* @brief Functions concerning emission of diagnostics messages, like error or -* warning messages. -* @copyright (c) 2017 Avast Software, licensed under the MIT license -*/ - -#ifndef RETDEC_LLVM_SUPPORT_DIAGNOSTICS_H -#define RETDEC_LLVM_SUPPORT_DIAGNOSTICS_H - -#include - -#include - -namespace retdec { -namespace llvm_support { - -/// @name Internal (For Internal Use Only) -/// @{ - -/** -* @brief A base case for printInto(). For internal use only. -*/ -inline void printInto(llvm::raw_ostream &) {} - -/** -* @brief Prints the given arguments to the given stream. For internal use only. -*/ -template -void printInto(llvm::raw_ostream &stream, T &&arg, Args &&... args) { - stream << arg; - printInto(stream, std::forward(args)...); -} - -/** -* @brief Prints a colored line with the given arguments to the given stream. -* For internal use only. -*/ -template -void printColoredLine(llvm::raw_ostream &stream, llvm::raw_ostream::Colors color, - bool bold, Args &&... args) { - stream.changeColor(color, bold); - printInto(stream, std::forward(args)...); - stream.resetColor(); - stream << "\n"; -} - -/// @} - -/// @name Phases -/// @{ - -void printPhase( - const std::string &phaseName, - bool print = true, - llvm::raw_ostream &stream = llvm::outs() -); -void printSubPhase( - const std::string &phaseName, - bool print = true, - llvm::raw_ostream &stream = llvm::outs() -); -void printSubSubPhase( - const std::string &phaseName, - bool print = true, - llvm::raw_ostream &stream = llvm::outs() -); -void printSubSubSubPhase( - const std::string &phaseName, - bool print = true, - llvm::raw_ostream &stream = llvm::outs() -); - -/// @} - -/// @name Messages -/// @{ - -/** -* @brief Prints the given error message to the standard error. -* -* A new line is automatically appended after the message. -* -* Usage example: -* @code -* printErrorMessage("Function ", funcName, " does not exist.")); -* @endcode -*/ -template -void printErrorMessage(const std::string &message, Args &&... args) { - printColoredLine(llvm::errs(), llvm::raw_ostream::RED, /* bold */ false, - "Error: ", message, std::forward(args)...); -} - -/** -* @brief Prints the given warning message to the standard error. -* -* A new line is automatically appended after the message. -* -* Usage example: -* @code -* printWarningMessage("Function ", funcName, " does not exist.")); -* @endcode -*/ -template -void printWarningMessage(const std::string &message, Args &&... args) { - printColoredLine(llvm::errs(), llvm::raw_ostream::CYAN, /* bold */ false, - "Warning: ", message, std::forward(args)...); -} - -/** -* @brief Prints the given info message to the standard error. -* -* A new line is automatically appended after the message. -* -* Usage example: -* @code -* printInfoMessage("Function ", funcName, " does not exist.")); -* @endcode -*/ -template -void printInfoMessage(const std::string &message, Args &&... args) { - printColoredLine(llvm::errs(), llvm::raw_ostream::GREEN, /* bold */ false, - "Info: ", message, std::forward(args)...); -} - -/// @} - -} // namespace llvm_support -} // namespace retdec - -#endif diff --git a/include/retdec/llvmir2hll/llvmir2hll.h b/include/retdec/llvmir2hll/llvmir2hll.h index 7edcb25fa..224ea5278 100644 --- a/include/retdec/llvmir2hll/llvmir2hll.h +++ b/include/retdec/llvmir2hll/llvmir2hll.h @@ -73,7 +73,6 @@ #include "retdec/llvmir2hll/var_name_gen/var_name_gens/num_var_name_gen.h" #include "retdec/llvmir2hll/var_renamer/var_renamer.h" #include "retdec/llvmir2hll/var_renamer/var_renamer_factory.h" -#include "retdec/llvm-support/diagnostics.h" #include "retdec/utils/container.h" #include "retdec/utils/conversion.h" #include "retdec/utils/memory.h" diff --git a/include/retdec/llvmir2hll/optimizer/optimizer_manager.h b/include/retdec/llvmir2hll/optimizer/optimizer_manager.h index 21f675279..cd694fcc5 100644 --- a/include/retdec/llvmir2hll/optimizer/optimizer_manager.h +++ b/include/retdec/llvmir2hll/optimizer/optimizer_manager.h @@ -10,7 +10,6 @@ #include "retdec/llvmir2hll/optimizer/optimizer.h" #include "retdec/llvmir2hll/support/smart_ptr.h" #include "retdec/llvmir2hll/support/types.h" -#include "retdec/llvm-support/diagnostics.h" #include "retdec/utils/non_copyable.h" namespace retdec { diff --git a/include/retdec/llvmir2hll/pattern/pattern_finder_runners/cli_pattern_finder_runner.h b/include/retdec/llvmir2hll/pattern/pattern_finder_runners/cli_pattern_finder_runner.h index 462347de8..6868a34ec 100644 --- a/include/retdec/llvmir2hll/pattern/pattern_finder_runners/cli_pattern_finder_runner.h +++ b/include/retdec/llvmir2hll/pattern/pattern_finder_runners/cli_pattern_finder_runner.h @@ -10,6 +10,7 @@ #include #include "retdec/llvmir2hll/pattern/pattern_finder_runner.h" +#include "retdec/utils/io/log.h" namespace retdec { namespace llvmir2hll { @@ -23,7 +24,7 @@ namespace llvmir2hll { */ class CLIPatternFinderRunner: public PatternFinderRunner { public: - CLIPatternFinderRunner(llvm::raw_ostream &os); + CLIPatternFinderRunner(utils::io::Logger &os); private: virtual void doActionsBeforePatternFinderRuns(ShPtr pf) override; @@ -34,7 +35,7 @@ class CLIPatternFinderRunner: public PatternFinderRunner { private: /// Output stream, into which the patterns will be emitted. - llvm::raw_ostream &os; + utils::io::Logger &os; }; } // namespace llvmir2hll diff --git a/include/retdec/llvmir2hll/validator/validator.h b/include/retdec/llvmir2hll/validator/validator.h index 9a840df8c..213d77d93 100644 --- a/include/retdec/llvmir2hll/validator/validator.h +++ b/include/retdec/llvmir2hll/validator/validator.h @@ -11,7 +11,9 @@ #include "retdec/llvmir2hll/support/smart_ptr.h" #include "retdec/llvmir2hll/support/visitors/ordered_all_visitor.h" -#include "retdec/llvm-support/diagnostics.h" +#include "retdec/utils/io/log.h" + +using namespace retdec::utils::io; namespace retdec { namespace llvmir2hll { @@ -45,12 +47,10 @@ class Validator: protected OrderedAllVisitor { /** * @brief Function to be called when there is a validation error. */ - template - void validationError(const std::string &warningMessage, Args &&... args) { + void validationError(const std::string &warningMessage) { moduleIsCorrect = false; if (printMessageOnError) { - retdec::llvm_support::printWarningMessage(warningMessage, - std::forward(args)...); + Log::error() << Log::Warning << warningMessage << std::endl; } } diff --git a/include/retdec/unpacker/plugin.h b/include/retdec/unpacker/plugin.h index 23ff58d19..010d6b1a2 100644 --- a/include/retdec/unpacker/plugin.h +++ b/include/retdec/unpacker/plugin.h @@ -7,15 +7,17 @@ #ifndef RETDEC_UNPACKER_PLUGIN_H #define RETDEC_UNPACKER_PLUGIN_H -#include #include #include #include +#include "retdec/utils/io/log.h" #include "retdec/unpacker/unpacker_exception.h" #define plugin(T) retdec::unpackertool::Plugin::instance() +using namespace retdec::utils::io; + namespace retdec { namespace unpackertool { @@ -171,7 +173,7 @@ class Plugin */ template void log(const Args&... args) { - Plugin::logImpl(std::cout, "[", getInfo()->name, "] ", args...); + Plugin::logImpl(Log::get(Log::Type::Info), "[", getInfo()->name, "] ", args...); } /** @@ -184,7 +186,7 @@ class Plugin */ template void error(const Args&... args) { - Plugin::logImpl(std::cerr, "[ERROR] [", getInfo()->name, "] ", args...); + Plugin::logImpl(Log::get(Log::Type::Error), "[ERROR] [", getInfo()->name, "] ", args...); } /** @@ -211,13 +213,13 @@ class Plugin private: PluginExitCode _cachedExitCode; ///< Cached exit code of the plugin for the unpacked file. - template static void logImpl(std::ostream& out, const T& data, const Args&... args) + template static void logImpl(Logger& out, const T& data, const Args&... args) { out << data; logImpl(out, args...); } - static void logImpl(std::ostream& out) + static void logImpl(Logger& out) { out << std::endl; } diff --git a/include/retdec/utils/io/log.h b/include/retdec/utils/io/log.h new file mode 100644 index 000000000..84cfe2ed5 --- /dev/null +++ b/include/retdec/utils/io/log.h @@ -0,0 +1,142 @@ +/** +* @file include/retdec/utils/io/logger.h +* @brief Provides unified logging interface. +* @copyright (c) 2020 Avast Software, licensed under the MIT license +*/ + +#ifndef RETDEC_UTILS_IO_LOG_H +#define RETDEC_UTILS_IO_LOG_H + +#include "retdec/utils/io/logger.h" + +namespace retdec { +namespace utils { +namespace io { + +class Log { +public: + /** + * Each type represents different logging style. For each + * type is provided a logger by calling Log::get function + */ + enum class Type : int { + Info = 0, + Debug, + Error, + Undefined + }; + + using Color = Logger::Color; + using Action = Logger::Action; + +public: + /** + * Returns corresponding initialized logger for logType provided + * as parameter. At the beginning all the logger types are initialized + * to default logger. + * + * For debug/info: + * - verbose + * - logs to std::out + * + * For error: + * - verbose + * - logs to std::err + */ + static Logger& get(const Type& logType); + + /** + * Sets appropriate logger based on logType value. + */ + static void set(const Type& logType, Logger::Ptr&& logger); + + /** + * Shortcut for Logger(Log::get(Log::Type::Info)). + * + * Creates temporary copy of Info logger. This is particularly + * useful when changing color of the output. On destruction + * color is changed to default. + */ + static Logger info(); + + /** + * Shortcut for Logger(Log::get(Log::Type::Debug)). + * + * Creates temporary copy of Debug logger. This is particularly + * useful when changing color of the output. On destruction + * color is changed to default. + */ + static Logger debug(); + + /** + * Shortcut for Logger(Log::get(Log::Type::Error)). + * + * Creates temporary copy of Error logger. This is particularly + * useful when changing color of the output. On destruction + * color is changed to default. + */ + static Logger error(); + + /** + * Shortcut for Log::info() << action << phaseId << Log::Action::ElapsedTime << std::endl. + */ + static void phase( + const std::string& phaseId, + const Log::Action& action = Log::Action::Phase); + +public: + /** + * Representation of Error Action that can be inserted into logger. + * Shortcut for Log::Action::Error + */ + static const Action Error; + + /** + * Representation of Warning Action that can be inserted into logger. + * Shortcut for Log::Action::Warning + */ + static const Action Warning; + + /** + * Representation of Phase Action that can be inserted into logger. + * Shortcut for Log::Action::Phase + */ + static const Action Phase; + + /** + * Representation of SubPhase Action that can be inserted into logger. + * Shortcut for Log::Action::SubPhase + */ + static const Action SubPhase; + + /** + * Representation of SubSubPhase Action that can be inserted into logger. + * Shortcut for Log::Action::SubSubPhase + */ + static const Action SubSubPhase; + + /** + * Representation of ElapsedTime Action that can be inserted into logger. + * Shortcut for Log::Action::ElapsedTime + */ + static const Action ElapsedTime; + +private: + /** + * Structure containing initialized/default loggers. + */ + static Logger::Ptr writers[static_cast(Type::Undefined)+1]; + + /** + * Fallback logger. In case of bad initialization of the writers + * this logger is used as fallback to log (calling set with nullptr). + */ + static Logger defaultLogger; +}; + +} +} +} + + +#endif diff --git a/include/retdec/utils/io/logger.h b/include/retdec/utils/io/logger.h new file mode 100644 index 000000000..9fa8837be --- /dev/null +++ b/include/retdec/utils/io/logger.h @@ -0,0 +1,107 @@ +/** +* @file include/retdec/utils/io/logger.h +* @brief Implementation of a logging class. +* @copyright (c) 2020 Avast Software, licensed under the MIT license +*/ + +#ifndef RETDEC_UTILS_IO_LOGGER_H +#define RETDEC_UTILS_IO_LOGGER_H + +#include +#include +#include +#include + +namespace retdec { +namespace utils { +namespace io { + +/** + * @brief Provides Logger inteface that is used for logging events during decompilation. + */ +class Logger { +public: + using Ptr = std::unique_ptr; + +public: + enum Action: int { + Phase, + SubPhase, + SubSubPhase, + ElapsedTime, + Error, + Warning, + NoAction + }; + + enum class Color: int { + Red, + Green, + Blue, + Yellow, + DarkCyan, + Default + }; + +protected: + typedef std::ostream& (*StreamManipulator) (std::ostream&); + +public: + Logger(std::ostream& stream, bool verbose = true); + Logger(const Logger& logger); + ~Logger(); + + template + Logger& operator << (const T& p); + + Logger& operator << (const StreamManipulator& manip); + Logger& operator << (const Action& ia); + Logger& operator << (const Color& lc); + +private: + bool isRedirected(const std::ostream& stream) const; + +protected: + std::ostream& _out; + + bool _verbose = true; + Color _currentBrush = Color::Default; + + bool _modifiedTerminalProperty = false; + bool _terminalNotSupported = false; +}; + +class FileLogger : public Logger { +public: + FileLogger(const std::string& file, bool verbose = true); + +private: + std::ofstream _file; +}; + +template +inline Logger& Logger::operator << (const T& p) +{ + if (!_verbose) + return *this; + + _out << p; + + return *this; +} + +inline Logger& Logger::operator << (const Logger::StreamManipulator& p) +{ + if (!_verbose) + return *this; + + _out << p; + + return *this; +} + +} +} +} + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e3635ae12..9897541c5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,7 +16,6 @@ cond_add_subdirectory(fileformat RETDEC_ENABLE_FILEFORMAT) cond_add_subdirectory(fileinfo RETDEC_ENABLE_FILEINFO) cond_add_subdirectory(getsig RETDEC_ENABLE_GETSIG) cond_add_subdirectory(idr2pat RETDEC_ENABLE_IDR2PAT) -cond_add_subdirectory(llvm-support RETDEC_ENABLE_LLVM_SUPPORT) cond_add_subdirectory(llvmir-emul RETDEC_ENABLE_LLVMIR_EMUL) cond_add_subdirectory(llvmir2hll RETDEC_ENABLE_LLVMIR2HLL) cond_add_subdirectory(loader RETDEC_ENABLE_LOADER) diff --git a/src/ar-extractortool/ar_extractor.cpp b/src/ar-extractortool/ar_extractor.cpp index 7e919d990..d446505f6 100644 --- a/src/ar-extractortool/ar_extractor.cpp +++ b/src/ar-extractortool/ar_extractor.cpp @@ -4,7 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include #include #include @@ -12,10 +11,12 @@ #include #include "retdec/utils/filesystem.h" +#include "retdec/utils/io/log.h" #include "retdec/ar-extractor/archive_wrapper.h" #include "retdec/ar-extractor/detection.h" using namespace retdec::utils; +using namespace retdec::utils::io; using namespace retdec::ar_extractor; using namespace rapidjson; @@ -43,13 +44,12 @@ bool isJson = false; /** * Print usage. * - * @param outputStream target stream + * @param log usage logger object */ -void printUsage( - std::ostream &outputStream) +void printUsage(Logger& log) { - outputStream << "Usage: ar_extractor [OPTIONS] FILE\n\n" + log << "Usage: ar_extractor [OPTIONS] FILE\n\n" "Options:\n\n" "--arch-magic\n" " Check if file starts with archive magic constants.\n" @@ -99,7 +99,7 @@ void printUsage( void printErrorPlainText( const std::string &message) { - std::cerr << "Error: " << message << ".\n"; + Log::error() << Log::Error << message << ".\n"; } /** @@ -120,7 +120,7 @@ void printErrorJson( PrettyWriter writer(buffer); errorFile.Accept(writer); - std::cerr << buffer.GetString() << "\n"; + Log::error() << buffer.GetString() << "\n"; } /** @@ -163,7 +163,7 @@ int printTable( } } - std::cout << result; + Log::info() << result; return 0; } @@ -213,7 +213,7 @@ int processArguments( const auto &arg = args[i]; if (arg == "-h" || arg == "--help") { - printUsage(std::cout); + printUsage(Log::get(Log::Type::Info)); return 0; } else if (arg == "-o" || arg == "--output") { @@ -339,7 +339,7 @@ int processArguments( return printTable(archive, fixNames, isNum); case ACTION::OBJECT_COUNT: - std::cout << archive.getNumberOfObjects() << "\n"; + Log::info() << archive.getNumberOfObjects() << "\n"; return 0; case ACTION::EXTRACT_NAME: diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index a941377e7..de1e63317 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -136,7 +136,6 @@ target_link_libraries(bin2llvmir retdec::ctypesparser retdec::common retdec::utils - retdec::llvm-support retdec::deps::llvm ) diff --git a/src/bin2llvmir/analyses/ctor_dtor.cpp b/src/bin2llvmir/analyses/ctor_dtor.cpp index ebf1d7d77..013fcb73c 100644 --- a/src/bin2llvmir/analyses/ctor_dtor.cpp +++ b/src/bin2llvmir/analyses/ctor_dtor.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include - #include #include #include diff --git a/src/bin2llvmir/analyses/reaching_definitions.cpp b/src/bin2llvmir/analyses/reaching_definitions.cpp index a3c3c8ba4..6c791a7ec 100644 --- a/src/bin2llvmir/analyses/reaching_definitions.cpp +++ b/src/bin2llvmir/analyses/reaching_definitions.cpp @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/src/bin2llvmir/analyses/symbolic_tree.cpp b/src/bin2llvmir/analyses/symbolic_tree.cpp index 9207ad256..cdc61d624 100644 --- a/src/bin2llvmir/analyses/symbolic_tree.cpp +++ b/src/bin2llvmir/analyses/symbolic_tree.cpp @@ -4,7 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include #include #include diff --git a/src/bin2llvmir/optimizations/asm_inst_remover/asm_inst_remover.cpp b/src/bin2llvmir/optimizations/asm_inst_remover/asm_inst_remover.cpp index 5f260235e..a657f970e 100644 --- a/src/bin2llvmir/optimizations/asm_inst_remover/asm_inst_remover.cpp +++ b/src/bin2llvmir/optimizations/asm_inst_remover/asm_inst_remover.cpp @@ -5,8 +5,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include - #include "retdec/bin2llvmir/optimizations/asm_inst_remover/asm_inst_remover.h" #include "retdec/bin2llvmir/providers/asm_instruction.h" #include "retdec/bin2llvmir/providers/names.h" diff --git a/src/bin2llvmir/optimizations/class_hierarchy/hierarchy_analysis.cpp b/src/bin2llvmir/optimizations/class_hierarchy/hierarchy_analysis.cpp index 00dc1a768..fba0fc948 100644 --- a/src/bin2llvmir/optimizations/class_hierarchy/hierarchy_analysis.cpp +++ b/src/bin2llvmir/optimizations/class_hierarchy/hierarchy_analysis.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include - #include "retdec/bin2llvmir/utils/llvm.h" #include "retdec/bin2llvmir/optimizations/class_hierarchy/hierarchy_analysis.h" #include "retdec/bin2llvmir/utils/debug.h" diff --git a/src/bin2llvmir/optimizations/constants/constants.cpp b/src/bin2llvmir/optimizations/constants/constants.cpp index 22b3aeb7b..38ba873de 100644 --- a/src/bin2llvmir/optimizations/constants/constants.cpp +++ b/src/bin2llvmir/optimizations/constants/constants.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/src/bin2llvmir/optimizations/decoder/decoder.cpp b/src/bin2llvmir/optimizations/decoder/decoder.cpp index f8e87cee9..5015b634a 100644 --- a/src/bin2llvmir/optimizations/decoder/decoder.cpp +++ b/src/bin2llvmir/optimizations/decoder/decoder.cpp @@ -9,6 +9,7 @@ #include "retdec/utils/conversion.h" #include "retdec/utils/string.h" +#include "retdec/utils/io/log.h" #include "retdec/bin2llvmir/optimizations/decoder/decoder.h" #include "retdec/bin2llvmir/utils/llvm.h" #include "retdec/bin2llvmir/utils/capstone.h" @@ -17,6 +18,7 @@ using namespace retdec::capstone2llvmir; using namespace retdec::common; using namespace retdec::bin2llvmir::st_match; using namespace retdec::fileformat; +using namespace retdec::utils::io; namespace retdec { namespace bin2llvmir { @@ -88,7 +90,7 @@ bool Decoder::runCatcher() } catch (const BaseError& e) { - std::cerr << "[capstone2llvmir]: " << e.what() << std::endl; + Log::error() << "[capstone2llvmir]: " << e.what() << std::endl; exit(1); } } diff --git a/src/bin2llvmir/optimizations/idioms/idioms.cpp b/src/bin2llvmir/optimizations/idioms/idioms.cpp index 502802dd5..58056c4f4 100644 --- a/src/bin2llvmir/optimizations/idioms/idioms.cpp +++ b/src/bin2llvmir/optimizations/idioms/idioms.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include - #include "retdec/bin2llvmir/optimizations/idioms/idioms.h" #include "retdec/bin2llvmir/optimizations/idioms/idioms_borland.h" #include "retdec/bin2llvmir/optimizations/idioms/idioms_common.h" diff --git a/src/bin2llvmir/optimizations/idioms/idioms_magicdivmod.cpp b/src/bin2llvmir/optimizations/idioms/idioms_magicdivmod.cpp index c899aa050..65009ca29 100644 --- a/src/bin2llvmir/optimizations/idioms/idioms_magicdivmod.cpp +++ b/src/bin2llvmir/optimizations/idioms/idioms_magicdivmod.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include - #include #include "retdec/bin2llvmir/optimizations/idioms/idioms_magicdivmod.h" diff --git a/src/bin2llvmir/optimizations/idioms_libgcc/idioms_libgcc.cpp b/src/bin2llvmir/optimizations/idioms_libgcc/idioms_libgcc.cpp index 9369d2b95..ee1ece014 100644 --- a/src/bin2llvmir/optimizations/idioms_libgcc/idioms_libgcc.cpp +++ b/src/bin2llvmir/optimizations/idioms_libgcc/idioms_libgcc.cpp @@ -4,7 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include #include #include diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 44ada88cf..e40da74f2 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include diff --git a/src/bin2llvmir/optimizations/provider_init/provider_init.cpp b/src/bin2llvmir/optimizations/provider_init/provider_init.cpp index 17fc0a64c..1a4bb5c1a 100644 --- a/src/bin2llvmir/optimizations/provider_init/provider_init.cpp +++ b/src/bin2llvmir/optimizations/provider_init/provider_init.cpp @@ -4,11 +4,11 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include #include #include +#include "retdec/utils/io/log.h" #include "retdec/bin2llvmir/analyses/symbolic_tree.h" #include "retdec/bin2llvmir/optimizations/provider_init/provider_init.h" #include "retdec/bin2llvmir/providers/abi/abi.h" @@ -25,6 +25,7 @@ #include "retdec/yaracpp/yara_detector.h" using namespace llvm; +using namespace retdec::utils::io; namespace retdec { namespace bin2llvmir { @@ -340,7 +341,7 @@ bool ProviderInitialization::runOnModule(Module& m) { if (l.bytecode) { - std::cerr << "Warning: Detected " << l.name + Log::error() << Log::Warning << "Detected " << l.name << " bytecode, which cannot be decompiled by our " "machine-code decompiler. " "The decompilation result may be inaccurate."; diff --git a/src/bin2llvmir/optimizations/select_functions/select_functions.cpp b/src/bin2llvmir/optimizations/select_functions/select_functions.cpp index b5572bab6..80d54f81b 100644 --- a/src/bin2llvmir/optimizations/select_functions/select_functions.cpp +++ b/src/bin2llvmir/optimizations/select_functions/select_functions.cpp @@ -6,7 +6,6 @@ */ #include -#include #include #include diff --git a/src/bin2llvmir/optimizations/simple_types/simple_types.cpp b/src/bin2llvmir/optimizations/simple_types/simple_types.cpp index 80bd72fc8..e8a7a5854 100644 --- a/src/bin2llvmir/optimizations/simple_types/simple_types.cpp +++ b/src/bin2llvmir/optimizations/simple_types/simple_types.cpp @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/src/bin2llvmir/optimizations/stack_pointer_ops/stack_pointer_ops.cpp b/src/bin2llvmir/optimizations/stack_pointer_ops/stack_pointer_ops.cpp index 46cc29111..bcbdc699d 100644 --- a/src/bin2llvmir/optimizations/stack_pointer_ops/stack_pointer_ops.cpp +++ b/src/bin2llvmir/optimizations/stack_pointer_ops/stack_pointer_ops.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include diff --git a/src/bin2llvmir/optimizations/syscalls/arm.cpp b/src/bin2llvmir/optimizations/syscalls/arm.cpp index 38f018cca..486a6be57 100644 --- a/src/bin2llvmir/optimizations/syscalls/arm.cpp +++ b/src/bin2llvmir/optimizations/syscalls/arm.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include - #include #include "retdec/bin2llvmir/optimizations/syscalls/syscalls.h" diff --git a/src/bin2llvmir/optimizations/syscalls/mips.cpp b/src/bin2llvmir/optimizations/syscalls/mips.cpp index 232d47fd8..4cbf76f56 100644 --- a/src/bin2llvmir/optimizations/syscalls/mips.cpp +++ b/src/bin2llvmir/optimizations/syscalls/mips.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include - #include #include "retdec/bin2llvmir/optimizations/syscalls/syscalls.h" diff --git a/src/bin2llvmir/optimizations/syscalls/x86.cpp b/src/bin2llvmir/optimizations/syscalls/x86.cpp index e6eb7c3cd..6527818e6 100644 --- a/src/bin2llvmir/optimizations/syscalls/x86.cpp +++ b/src/bin2llvmir/optimizations/syscalls/x86.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include - #include #include "retdec/bin2llvmir/optimizations/syscalls/syscalls.h" diff --git a/src/bin2llvmir/optimizations/types_propagator/types_propagator.cpp b/src/bin2llvmir/optimizations/types_propagator/types_propagator.cpp index dff20fdb7..7d32ceaf1 100644 --- a/src/bin2llvmir/optimizations/types_propagator/types_propagator.cpp +++ b/src/bin2llvmir/optimizations/types_propagator/types_propagator.cpp @@ -4,12 +4,14 @@ * @copyright (c) 2020 Avast Software, licensed under the MIT license */ -#include #include #include +#include "retdec/utils/io/log.h" #include "retdec/bin2llvmir/optimizations/types_propagator/types_propagator.h" +using namespace retdec::utils::io; + namespace retdec { namespace bin2llvmir { @@ -59,13 +61,13 @@ bool TypesPropagator::run() unsigned cntr = 0; for (auto& eq : _eqSets) { - std::cout << "set #" << cntr++ << std::endl; + Log::info() << "set #" << cntr++ << std::endl; for (auto& v : eq) { if (llvm::isa(v)) - std::cout << "\t\t" << v->getName().str() << std::endl; + Log::info() << "\t\t" << v->getName().str() << std::endl; else - std::cout << "\t\t" << llvmObjToString(v) << std::endl; + Log::info() << "\t\t" << llvmObjToString(v) << std::endl; } } exit(1); diff --git a/src/bin2llvmir/optimizations/unreachable_funcs/unreachable_funcs.cpp b/src/bin2llvmir/optimizations/unreachable_funcs/unreachable_funcs.cpp index f660202c8..14c39e2e9 100644 --- a/src/bin2llvmir/optimizations/unreachable_funcs/unreachable_funcs.cpp +++ b/src/bin2llvmir/optimizations/unreachable_funcs/unreachable_funcs.cpp @@ -4,7 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include #include #include diff --git a/src/bin2llvmir/optimizations/writer_dsm/writer_dsm.cpp b/src/bin2llvmir/optimizations/writer_dsm/writer_dsm.cpp index b1258e0d7..191bf8623 100644 --- a/src/bin2llvmir/optimizations/writer_dsm/writer_dsm.cpp +++ b/src/bin2llvmir/optimizations/writer_dsm/writer_dsm.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/src/bin2llvmir/optimizations/x87_fpu/x87_fpu.cpp b/src/bin2llvmir/optimizations/x87_fpu/x87_fpu.cpp index bb05adda0..eaac8f07e 100644 --- a/src/bin2llvmir/optimizations/x87_fpu/x87_fpu.cpp +++ b/src/bin2llvmir/optimizations/x87_fpu/x87_fpu.cpp @@ -11,6 +11,7 @@ #include #include +#include "retdec/utils/io/log.h" #include "retdec/bin2llvmir/optimizations/x87_fpu/x87_fpu.h" #include "retdec/utils/string.h" #include "retdec/bin2llvmir/providers/asm_instruction.h" @@ -23,6 +24,7 @@ using namespace llvm; using namespace retdec::bin2llvmir::llvm_utils; +using namespace retdec::utils::io; namespace retdec { namespace bin2llvmir { diff --git a/src/bin2llvmir/providers/config.cpp b/src/bin2llvmir/providers/config.cpp index e9de98baf..650e2d055 100644 --- a/src/bin2llvmir/providers/config.cpp +++ b/src/bin2llvmir/providers/config.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include - #include #include diff --git a/src/bin2llvmir/providers/lti.cpp b/src/bin2llvmir/providers/lti.cpp index e0b23019b..0246811df 100644 --- a/src/bin2llvmir/providers/lti.cpp +++ b/src/bin2llvmir/providers/lti.cpp @@ -5,7 +5,6 @@ */ #include -#include #include "retdec/ctypes/floating_point_type.h" #include "retdec/ctypes/function_type.h" diff --git a/src/bin2llvmir/retdec-bin2llvmir-config.cmake b/src/bin2llvmir/retdec-bin2llvmir-config.cmake index 7403e795d..99037aab9 100644 --- a/src/bin2llvmir/retdec-bin2llvmir-config.cmake +++ b/src/bin2llvmir/retdec-bin2llvmir-config.cmake @@ -15,7 +15,6 @@ if(NOT TARGET retdec::bin2llvmir) ctypesparser common utils - llvm-support llvm ) diff --git a/src/bin2llvmir/utils/ir_modifier.cpp b/src/bin2llvmir/utils/ir_modifier.cpp index fc1b7c54d..b44fc1b98 100644 --- a/src/bin2llvmir/utils/ir_modifier.cpp +++ b/src/bin2llvmir/utils/ir_modifier.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include - #include #include "retdec/utils/string.h" diff --git a/src/bin2pat/bin2pat.cpp b/src/bin2pat/bin2pat.cpp index bd8745393..f26669bf2 100644 --- a/src/bin2pat/bin2pat.cpp +++ b/src/bin2pat/bin2pat.cpp @@ -6,11 +6,11 @@ #include #include -#include #include #include #include "retdec/utils/filesystem.h" +#include "retdec/utils/io/log.h" #include "retdec/patterngen/pattern_extractor/pattern_extractor.h" #include "yaramod/yaramod.h" @@ -21,12 +21,12 @@ * Output is set of yara rules (http://yara.readthedocs.io/en/v3.5.0/). */ +using namespace retdec::utils::io; using namespace retdec::patterngen; -void printUsage( - std::ostream &outputStream) +void printUsage(Logger &log) { - outputStream << "Usage: bin2pat [-o OUTPUT_FILE] [-n NOTE]" + log << "Usage: bin2pat [-o OUTPUT_FILE] [-n NOTE]" << " \n\n" << "-o --output OUTPUT_FILE\n" << " Output file path (if not given, stdout is used).\n" @@ -42,8 +42,8 @@ void printUsage( void printErrorAndDie( const std::string &message) { - std::cerr << "Error: " << message << ".\n"; - printUsage(std::cerr); + Log::error() << Log::Error << message << ".\n"; + printUsage(Log::get(Log::Type::Error)); std::exit(1); } @@ -62,7 +62,7 @@ void processArgs( for (std::size_t i = 0, e = args.size(); i < e; ++i) { if (args[i] == "--help" || args[i] == "-h") { - printUsage(std::cout); + printUsage(Log::get(Log::Type::Info)); return; } else if (args[i] == "-o" || args[i] == "--output") { @@ -143,8 +143,8 @@ void processArgs( if (!extractor.isValid()) { // Sometimes, non-supported files are present in archives. We will // only print warning if such a file is encountered. - std::cerr << "Error: file '" << path << "' was not processed.\n"; - std::cerr << "Problem: " << extractor.getErrorMessage() << ".\n\n"; + Log::error() << Log::Error << "file '" << path << "' was not processed.\n"; + Log::error() << "Problem: " << extractor.getErrorMessage() << ".\n\n"; continue; } else { @@ -154,11 +154,11 @@ void processArgs( // Print warnings if any. const auto &warnings = extractor.getWarnings(); if (!warnings.empty()) { - std::cerr << "Warning: problems with file '" << path << "'\n"; + Log::error() << Log::Warning << "problems with file '" << path << "'\n"; for (const auto &warning : warnings) { - std::cerr << "Problem: " << warning << ".\n"; + Log::error() << "Problem: " << warning << ".\n"; } - std::cerr << "\n"; + Log::error() << "\n"; } } } @@ -179,7 +179,7 @@ void processArgs( outputFile << builder.get(false)->getText() << "\n"; } else { - std::cout << builder.get(false)->getText() << "\n"; + Log::info() << builder.get(false)->getText() << "\n"; } } diff --git a/src/capstone2llvmir/arm/arm.cpp b/src/capstone2llvmir/arm/arm.cpp index aa9b3edbd..b18c90421 100644 --- a/src/capstone2llvmir/arm/arm.cpp +++ b/src/capstone2llvmir/arm/arm.cpp @@ -5,7 +5,6 @@ */ #include -#include #include "capstone2llvmir/arm/arm_impl.h" diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 30a5ee782..a5e7c7e8d 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -5,10 +5,13 @@ */ #include -#include + +#include "retdec/utils/io/log.h" #include "capstone2llvmir/arm64/arm64_impl.h" +using namespace retdec::utils::io; + namespace retdec { namespace capstone2llvmir { @@ -704,7 +707,7 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadRegister( // If we dont find the register type, try to recover from this returning at // least the number of register // Maybe solve this better - std::cerr << e.what() << std::endl; + Log::error() << e.what() << std::endl; return llvm::ConstantInt::get(dstType ? dstType : getDefaultType(), r); } @@ -818,7 +821,7 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeRegister( if (llvmReg == nullptr) { // Maybe return xchg eax, eax? - std::cerr << "storeRegister() unhandled reg." << std::endl; + Log::error() << "storeRegister() unhandled reg." << std::endl; return nullptr; } diff --git a/src/capstone2llvmir/capstone2llvmir_impl.cpp b/src/capstone2llvmir/capstone2llvmir_impl.cpp index 3f10248ba..20231525d 100644 --- a/src/capstone2llvmir/capstone2llvmir_impl.cpp +++ b/src/capstone2llvmir/capstone2llvmir_impl.cpp @@ -6,7 +6,6 @@ */ #include -#include #include "capstone2llvmir/capstone2llvmir_impl.h" diff --git a/src/capstone2llvmir/llvmir_utils.cpp b/src/capstone2llvmir/llvmir_utils.cpp index 99769bb6a..d35ffecfe 100644 --- a/src/capstone2llvmir/llvmir_utils.cpp +++ b/src/capstone2llvmir/llvmir_utils.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2018 Avast Software, licensed under the MIT license */ -#include - #include "capstone2llvmir/llvmir_utils.h" #include "retdec/capstone2llvmir/exceptions.h" diff --git a/src/capstone2llvmir/mips/mips.cpp b/src/capstone2llvmir/mips/mips.cpp index 695aa8b8f..bd16706a1 100644 --- a/src/capstone2llvmir/mips/mips.cpp +++ b/src/capstone2llvmir/mips/mips.cpp @@ -5,7 +5,6 @@ */ #include -#include #include "capstone2llvmir/mips/mips_impl.h" diff --git a/src/capstone2llvmir/powerpc/powerpc.cpp b/src/capstone2llvmir/powerpc/powerpc.cpp index 9696a055d..886bc3283 100644 --- a/src/capstone2llvmir/powerpc/powerpc.cpp +++ b/src/capstone2llvmir/powerpc/powerpc.cpp @@ -5,7 +5,6 @@ */ #include -#include #include "capstone2llvmir/powerpc/powerpc_impl.h" diff --git a/src/capstone2llvmir/x86/x86.cpp b/src/capstone2llvmir/x86/x86.cpp index ced4fc3ff..83717eb28 100644 --- a/src/capstone2llvmir/x86/x86.cpp +++ b/src/capstone2llvmir/x86/x86.cpp @@ -5,7 +5,6 @@ */ #include -#include #include "capstone2llvmir/x86/x86_impl.h" diff --git a/src/capstone2llvmirtool/capstone2llvmir.cpp b/src/capstone2llvmirtool/capstone2llvmir.cpp index e59020bab..0f1dbe837 100644 --- a/src/capstone2llvmirtool/capstone2llvmir.cpp +++ b/src/capstone2llvmirtool/capstone2llvmir.cpp @@ -5,7 +5,6 @@ */ #include -#include #include #include @@ -15,9 +14,12 @@ #include "retdec/common/address.h" #include "retdec/utils/conversion.h" #include "retdec/utils/string.h" +#include "retdec/utils/io/log.h" #include "retdec/capstone2llvmir/capstone2llvmir.h" +using namespace retdec::utils::io; + // byte ptr [0x12345678], 0x11 std::vector CODE = retdec::utils::hexStringToBytes("80 05 78 56 34 12 11 00"); @@ -143,7 +145,7 @@ class ProgramOptions case CS_ARCH_MAX: case CS_ARCH_ALL: default: - std::cerr << "Can not get Capstone arch to default Capstone basic mode." << std::endl; + Log::error() << "Can not get Capstone arch to default Capstone basic mode." << std::endl; exit(1); } } @@ -152,23 +154,23 @@ class ProgramOptions { std::string tmp; retdec::utils::bytesToHexString(code, tmp, 0, 0, false, true); - std::cout << std::endl; - std::cout << "Program Options:" << std::endl; - std::cout << "\t" << "arch : " << arch << " (" << _arch << ")" << std::endl; - std::cout << "\t" << "base : " << std::hex << base << " (" << _base << ")" << std::endl; - std::cout << "\t" << "code : " << tmp << " (" << _code << ")" << std::endl; - std::cout << "\t" << "asm text : " << text << std::endl; - std::cout << "\t" << "b mode : " << std::hex << basicMode << " (" << _basicMode << ")" << std::endl; - std::cout << "\t" << "e mode : " << std::hex << extraMode << " (" << _extraMode << ")" << std::endl; - std::cout << "\t" << "out : " << outFile << std::endl; - std::cout << std::endl; + Log::info() << std::endl; + Log::info() << "Program Options:" << std::endl; + Log::info() << "\t" << "arch : " << arch << " (" << _arch << ")" << std::endl; + Log::info() << "\t" << "base : " << std::hex << base << " (" << _base << ")" << std::endl; + Log::info() << "\t" << "code : " << tmp << " (" << _code << ")" << std::endl; + Log::info() << "\t" << "asm text : " << text << std::endl; + Log::info() << "\t" << "b mode : " << std::hex << basicMode << " (" << _basicMode << ")" << std::endl; + Log::info() << "\t" << "e mode : " << std::hex << extraMode << " (" << _extraMode << ")" << std::endl; + Log::info() << "\t" << "out : " << outFile << std::endl; + Log::info() << std::endl; } void printHelpAndDie() { std::string tmp; retdec::utils::bytesToHexString(CODE, tmp, 0, 0, false, true); - std::cout << _programName << ":\n" + Log::info() << _programName << ":\n" "\t-a name Set architecture name.\n" "\t Possible values: arm, arm64, mips, x86, ppc, sparc, sysz, xcore\n" "\t Default value: x86.\n" @@ -220,8 +222,8 @@ void printVersion() int minor = 0; int version = cs_version(&major, &minor); - std::cout << std::endl; - std::cout << "Capstone version: " << version << " (major: " << major + Log::info() << std::endl; + Log::info() << "Capstone version: " << version << " (major: " << major << ", minor: " << minor << ")" << std::endl; } @@ -240,7 +242,7 @@ ks_arch capstoneArchToKeystoneArch(cs_arch a) case CS_ARCH_MAX: case CS_ARCH_ALL: default: - std::cerr << "Can not convert Capstone arch to Keystone arch." << std::endl; + Log::error() << "Can not convert Capstone arch to Keystone arch." << std::endl; exit(1); } } @@ -283,7 +285,7 @@ ks_mode capstoneModeBasicToKeystoneMode(cs_arch a, cs_mode m) } else { - std::cerr << "Can not convert Capstone basic mode to Keystone mode." << std::endl; + Log::error() << "Can not convert Capstone basic mode to Keystone mode." << std::endl; exit(1); } } @@ -316,7 +318,7 @@ ks_mode capstoneModeExtraToKeystoneMode(cs_arch a, cs_mode m) } else { - std::cerr << "Can not convert Capstone extra mode to Keystone mode." << std::endl; + Log::error() << "Can not convert Capstone extra mode to Keystone mode." << std::endl; exit(1); } } @@ -335,7 +337,7 @@ void assemble(ProgramOptions& po) if (ks_open(arch, basic | extra, &ks) != KS_ERR_OK) { ks_err err = ks_errno(ks); - std::cerr << "Keystone Error: " << ks_strerror(err) << std::endl; + Log::error() << Log::Error << "Keystone: " << ks_strerror(err) << std::endl; exit(1); } @@ -346,7 +348,7 @@ void assemble(ProgramOptions& po) if (ks_asm(ks, po.text.data(), po.base, &enc, &sz, &cnt) != KS_ERR_OK) { ks_err err = ks_errno(ks); - std::cerr << "Keystone Error: " << ks_strerror(err) << std::endl; + Log::error() << Log::Error << "Keystone: " << ks_strerror(err) << std::endl; exit(1); } @@ -361,7 +363,7 @@ void assemble(ProgramOptions& po) if (ks_close(ks) != KS_ERR_OK) { ks_err err = ks_errno(ks); - std::cerr << "Keystone Error: " << ks_strerror(err) << std::endl; + Log::error() << Log::Error << "Keystone : " << ks_strerror(err) << std::endl; exit(1); } } @@ -404,12 +406,12 @@ int main(int argc, char *argv[]) } catch (const BaseError& e) { - std::cerr << e.what() << std::endl; + Log::error() << e.what() << std::endl; assert(false); } catch (...) { - std::cerr << "Some unhandled exception" << std::endl; + Log::error() << "Some unhandled exception" << std::endl; } std::error_code ec; diff --git a/src/common/address.cpp b/src/common/address.cpp index 6edfd591f..510eb0a0c 100644 --- a/src/common/address.cpp +++ b/src/common/address.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include "retdec/common/address.h" diff --git a/src/config/parameters.cpp b/src/config/parameters.cpp index e49044520..e9f922de0 100644 --- a/src/config/parameters.cpp +++ b/src/config/parameters.cpp @@ -40,6 +40,8 @@ const std::string JSON_outputLlFile = "outputLlFile"; const std::string JSON_outputConfigFile = "outputConfigFile"; const std::string JSON_outputUnpackedFile = "outputUnpackedFile"; const std::string JSON_outputFormat = "outputFormat"; +const std::string JSON_logFile = "logFile"; +const std::string JSON_errFile = "errFile"; const std::string JSON_detectStaticCode = "detectStaticCode"; const std::string JSON_backendDisabledOpts = "backendDisabledOpts"; @@ -215,6 +217,16 @@ void Parameters::setOutputFormat(const std::string& format) _outputFormat = format; } +void Parameters::setLogFile(const std::string &file) +{ + _logFile = file; +} + +void Parameters::setErrFile(const std::string &file) +{ + _errFile = file; +} + void Parameters::setOrdinalNumbersDirectory(const std::string& n) { _ordinalNumbersDirectory = n; @@ -384,6 +396,16 @@ const std::string& Parameters::getOutputFormat() const return _outputFormat; } +const std::string& Parameters::getLogFile() const +{ + return _logFile; +} + +const std::string& Parameters::getErrFile() const +{ + return _errFile; +} + uint64_t Parameters::getMaxMemoryLimit() const { return _maxMemoryLimit; @@ -486,6 +508,8 @@ void Parameters::serialize(Writer& writer) const serdes::serializeString(writer, JSON_outputConfigFile, getOutputConfigFile()); serdes::serializeString(writer, JSON_outputUnpackedFile, getOutputUnpackedFile()); serdes::serializeString(writer, JSON_outputFormat, getOutputFormat()); + serdes::serializeString(writer, JSON_logFile, getLogFile()); + serdes::serializeString(writer, JSON_errFile, getErrFile()); serdes::serializeString(writer, JSON_backendDisabledOpts, getBackendDisabledOpts()); serdes::serializeString(writer, JSON_backendEnabledOpts, getBackendEnabledOpts()); @@ -553,6 +577,8 @@ void Parameters::deserialize(const rapidjson::Value& val) setOutputConfigFile( serdes::deserializeString(val, JSON_outputConfigFile) ); setOutputUnpackedFile( serdes::deserializeString(val, JSON_outputUnpackedFile) ); setOutputFormat( serdes::deserializeString(val, JSON_outputFormat) ); + setLogFile( serdes::deserializeString(val, JSON_logFile) ); + setErrFile( serdes::deserializeString(val, JSON_errFile) ); setIsDetectStaticCode( serdes::deserializeBool(val, JSON_detectStaticCode, true) ); setBackendDisabledOpts( serdes::deserializeString(val, JSON_backendDisabledOpts) ); diff --git a/src/debugformat/debugformat.cpp b/src/debugformat/debugformat.cpp index dcceb7857..b4e397ca1 100644 --- a/src/debugformat/debugformat.cpp +++ b/src/debugformat/debugformat.cpp @@ -6,7 +6,6 @@ #define LOG_ENABLED false -#include #include #include "retdec/utils/debug.h" diff --git a/src/debugformat/dwarf.cpp b/src/debugformat/dwarf.cpp index cb8875f97..387867e75 100644 --- a/src/debugformat/dwarf.cpp +++ b/src/debugformat/dwarf.cpp @@ -6,8 +6,6 @@ #define LOG_ENABLED false -#include - #include #include "retdec/demangler/demangler.h" diff --git a/src/debugformat/pdb.cpp b/src/debugformat/pdb.cpp index 2415b77e8..2397f38cd 100644 --- a/src/debugformat/pdb.cpp +++ b/src/debugformat/pdb.cpp @@ -6,8 +6,6 @@ #define LOG_ENABLED false -#include - #include "retdec/debugformat/debugformat.h" namespace retdec { diff --git a/src/demanglertool/demangler.cpp b/src/demanglertool/demangler.cpp index c2bc0eb6f..ef7a72ba1 100644 --- a/src/demanglertool/demangler.cpp +++ b/src/demanglertool/demangler.cpp @@ -9,6 +9,10 @@ #include "retdec/demangler/demangler.h" +#include "retdec/utils/io/log.h" + +using namespace retdec::utils::io; + using ItaniumDemangler = retdec::demangler::ItaniumDemangler; using MicrosoftDemangler = retdec::demangler::MicrosoftDemangler; using BorlandDemangler = retdec::demangler::BorlandDemangler; @@ -35,7 +39,7 @@ int main(int argc, char *argv[]) std::string demangledBorland; if (argc <= 1 || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { - std::cout << helpmsg; + Log::info() << helpmsg; return 0; } @@ -47,13 +51,13 @@ int main(int argc, char *argv[]) demangledBorland = dem_borland->demangleToString(argv[i]); if (!demangledGcc.empty()) { - std::cout << "gcc: " << demangledGcc << std::endl; + Log::info() << "gcc: " << demangledGcc << std::endl; } if (!demangledMs.empty()) { - std::cout << "ms: " << demangledMs << std::endl; + Log::info() << "ms: " << demangledMs << std::endl; } if (!demangledBorland.empty()) { - std::cout << "borland: " << demangledBorland << std::endl; + Log::info() << "borland: " << demangledBorland << std::endl; } } diff --git a/src/fileformat/file_format/file_format.cpp b/src/fileformat/file_format/file_format.cpp index f0c74dc1e..70aeb87a3 100644 --- a/src/fileformat/file_format/file_format.cpp +++ b/src/fileformat/file_format/file_format.cpp @@ -9,13 +9,13 @@ #include #include #include -#include #include #include "retdec/utils/conversion.h" #include "retdec/utils/file_io.h" #include "retdec/utils/string.h" #include "retdec/utils/system.h" +#include "retdec/utils/io/log.h" #include "retdec/fileformat/file_format/file_format.h" #include "retdec/fileformat/utils/byte_array_buffer.h" #include "retdec/fileformat/file_format/intel_hex/intel_hex_format.h" @@ -28,6 +28,7 @@ #include "retdec/pelib/PeLibInc.h" using namespace retdec::utils; +using namespace retdec::utils::io; using namespace PeLib; namespace retdec { @@ -2336,7 +2337,7 @@ void FileFormat::dump() { std::string output; dump(output); - std::cout << output; + Log::info() << output; } /** @@ -2561,7 +2562,7 @@ void FileFormat::dumpRegionsValidity() { std::string output; dumpRegionsValidity(output); - std::cout << output; + Log::info() << output; } /** @@ -2603,7 +2604,7 @@ void FileFormat::dumpResourceTree() { std::string output; dumpResourceTree(output); - std::cout << output; + Log::info() << output; } void FileFormat::dumpResourceTree(std::string &dumpStr) diff --git a/src/fileformat/types/dotnet_types/dotnet_type_reconstructor.cpp b/src/fileformat/types/dotnet_types/dotnet_type_reconstructor.cpp index 89eb68dfd..e498cbd2e 100644 --- a/src/fileformat/types/dotnet_types/dotnet_type_reconstructor.cpp +++ b/src/fileformat/types/dotnet_types/dotnet_type_reconstructor.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include - #include "retdec/utils/conversion.h" #include "retdec/utils/string.h" #include "retdec/fileformat/types/dotnet_headers/metadata_tables.h" diff --git a/src/fileformat/types/resource_table/resource_table.cpp b/src/fileformat/types/resource_table/resource_table.cpp index 6874e07bd..aab94fb5a 100644 --- a/src/fileformat/types/resource_table/resource_table.cpp +++ b/src/fileformat/types/resource_table/resource_table.cpp @@ -5,7 +5,6 @@ */ #include -#include #include "retdec/utils/conversion.h" #include "retdec/utils/dynamic_buffer.h" diff --git a/src/fileformat/utils/byte_array_buffer.cpp b/src/fileformat/utils/byte_array_buffer.cpp index a42472911..c40da9d8e 100644 --- a/src/fileformat/utils/byte_array_buffer.cpp +++ b/src/fileformat/utils/byte_array_buffer.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2019 Avast Software, licensed under the MIT license */ -#include - #include #include #include diff --git a/src/fileinfo/file_presentation/json_presentation.cpp b/src/fileinfo/file_presentation/json_presentation.cpp index de25779eb..d2597e71e 100644 --- a/src/fileinfo/file_presentation/json_presentation.cpp +++ b/src/fileinfo/file_presentation/json_presentation.cpp @@ -4,10 +4,9 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include - #include "retdec/utils/conversion.h" #include "retdec/utils/string.h" +#include "retdec/utils/io/log.h" #include "retdec/fileformat/utils/conversions.h" #include "retdec/serdes/pattern.h" #include "retdec/serdes/std.h" @@ -17,6 +16,7 @@ using namespace retdec; using namespace retdec::utils; +using namespace retdec::utils::io; using namespace retdec::cpdetect; using namespace retdec::fileformat; @@ -1285,7 +1285,7 @@ bool JsonPresentation::present() presentIterativeSubtitle(writer, StringsJsonGetter(fileinfo)); writer.EndObject(); - std::cout << sb.GetString() << std::endl; + Log::info() << sb.GetString() << std::endl; return true; } diff --git a/src/fileinfo/file_presentation/plain_presentation.cpp b/src/fileinfo/file_presentation/plain_presentation.cpp index d78140b5d..dbea59ebb 100644 --- a/src/fileinfo/file_presentation/plain_presentation.cpp +++ b/src/fileinfo/file_presentation/plain_presentation.cpp @@ -4,15 +4,15 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include - #include "retdec/utils/string.h" +#include "retdec/utils/io/log.h" #include "retdec/fileformat/utils/conversions.h" #include "fileinfo/file_presentation/getters/format.h" #include "fileinfo/file_presentation/getters/plain_getters.h" #include "fileinfo/file_presentation/plain_presentation.h" using namespace retdec::utils; +using namespace retdec::utils::io; using namespace retdec::cpdetect; using namespace retdec::fileformat; @@ -33,7 +33,7 @@ void presentTitle(const std::string &title) const auto pos = title.find_first_not_of(" "); if(pos != std::string::npos) { - std::cout << "\n\n" << title << "\n" << std::string(pos, ' ') << std::string(title.length() - pos, '-') << "\n"; + Log::info() << "\n\n" << title << "\n" << std::string(pos, ' ') << std::string(title.length() - pos, '-') << "\n"; } } @@ -62,10 +62,10 @@ void presentSimple(const std::vector &desc, const std::vector(tool.agreeCount) / tool.impCount * 100; - std::cout << ", " << tool.agreeCount << " from " << tool.impCount << " significant " << nibbles; - std::cout << " (" << ratio << "%)"; + Log::info() << ", " << tool.agreeCount << " from " << tool.impCount << " significant " << nibbles; + Log::info() << " (" << ratio << "%)"; } else { - std::cout << ", " << detectionMetodToString(tool.source); + Log::info() << ", " << detectionMetodToString(tool.source); } - std::cout << "\n"; + Log::info() << "\n"; } } @@ -394,26 +394,26 @@ void PlainPresentation::presentLanguages() const { return; } - std::cout << "Original language : "; + Log::info() << "Original language : "; for(std::size_t i = 0; i < noOfLanguages; ) { - std::cout << fileinfo.toolInfo.detectedLanguages[i].name; + Log::info() << fileinfo.toolInfo.detectedLanguages[i].name; if(fileinfo.toolInfo.detectedLanguages[i].additionalInfo.length()) { - std::cout << " (" << fileinfo.toolInfo.detectedLanguages[i].additionalInfo << ")"; + Log::info() << " (" << fileinfo.toolInfo.detectedLanguages[i].additionalInfo << ")"; } if(fileinfo.toolInfo.detectedLanguages[i].bytecode) { - std::cout << " (bytecode)"; + Log::info() << " (bytecode)"; } if(++i < noOfLanguages) { - std::cout << ", "; + Log::info() << ", "; } } - std::cout << "\n"; + Log::info() << "\n"; } /** @@ -426,11 +426,11 @@ void PlainPresentation::presentRichHeader() const const auto sig = toLower(fileinfo.getRichHeaderSignature()); if(!offset.empty()) { - std::cout << "Rich header offset : " << offset << "\n"; + Log::info() << "Rich header offset : " << offset << "\n"; } if(!key.empty()) { - std::cout << "Rich header key : " << key << "\n"; + Log::info() << "Rich header key : " << key << "\n"; } if(!sig.empty()) { @@ -441,7 +441,7 @@ void PlainPresentation::presentRichHeader() const for(std::size_t i = 0, e = sig.length(); i < e; i += signLineLen) { - std::cout << (i ? std::string(signDesc.length(), ' ') : signDesc) << sig.substr(i, signLineLen) << "\n"; + Log::info() << (i ? std::string(signDesc.length(), ' ') : signDesc) << sig.substr(i, signLineLen) << "\n"; } } } @@ -456,15 +456,15 @@ void PlainPresentation::presentOverlay() const const auto entropy = fileinfo.getOverlayEntropyStr(truncFloat); if(!offset.empty()) { - std::cout << "Overlay offset : " << offset << "\n"; + Log::info() << "Overlay offset : " << offset << "\n"; } if(!size.empty()) { - std::cout << "Overlay size : " << size << "\n"; + Log::info() << "Overlay size : " << size << "\n"; } if(!entropy.empty()) { - std::cout << "Overlay entropy : " << entropy << "\n"; + Log::info() << "Overlay entropy : " << entropy << "\n"; } } @@ -474,7 +474,7 @@ void PlainPresentation::presentOverlay() const void PlainPresentation::presentPackingInfo() const { const auto packed = fileinfo.toolInfo.isPacked(); - std::cout << "Packed : " << packedToString(packed) << "\n"; + Log::info() << "Packed : " << packedToString(packed) << "\n"; } /** @@ -491,18 +491,18 @@ void PlainPresentation::presentSimpleFlags(const std::string &title, const std:: return; } - std::cout << title << flags; + Log::info() << title << flags; const std::string abbreviations = abbvSerialization(abbv); if(!abbreviations.empty()) { - flags.empty() ? std::cout << abbreviations : std::cout << " (" << abbreviations << ")"; + flags.empty() ? Log::info() << abbreviations : Log::info() << " (" << abbreviations << ")"; } - std::cout << "\n"; + Log::info() << "\n"; if(explanatory) { for(std::size_t i = 0, e = abbv.size(); i < e; ++i) { - std::cout << " " << abbv[i] << " - " << desc[i] << "\n"; + Log::info() << " " << abbv[i] << " - " << desc[i] << "\n"; } } } @@ -520,31 +520,31 @@ void PlainPresentation::presentPatterns(const std::string &title, const std::vec } presentTitle(title); - std::cout << "Number of detected patterns: " << patterns.size() << "\n\n"; + Log::info() << "Number of detected patterns: " << patterns.size() << "\n\n"; for(std::size_t i = 0, e = patterns.size(); i < e; ++i) { - std::cout << patterns[i].getYaraRuleName() << "\n"; + Log::info() << patterns[i].getYaraRuleName() << "\n"; const auto description = patterns[i].getDescription(); if(!description.empty()) { - std::cout << " description: " << description << "\n"; + Log::info() << " description: " << description << "\n"; } if(patterns[i].isLittle() || patterns[i].isBig()) { const std::string end = patterns[i].isLittle() ? "little" : "big"; - std::cout << " endianness: " << end << "\n"; + Log::info() << " endianness: " << end << "\n"; } - std::cout << " number of matches: " << patterns[i].getNumberOfMatches(); + Log::info() << " number of matches: " << patterns[i].getNumberOfMatches(); const auto &matches = patterns[i].getMatches(); presentIterativeDistribution(PatternMatchesPlainGetter(fileinfo, matches), explanatory); if(matches.empty()) { - std::cout << "\n"; + Log::info() << "\n"; } if(i + 1 != e) { - std::cout << "\n"; + Log::info() << "\n"; } } } @@ -555,10 +555,10 @@ void PlainPresentation::presentDotnetClasses() const if (classes.empty()) return; - std::cout << '\n'; + Log::info() << '\n'; for (const auto& dotnetClass : classes) { - std::cout << dotnetClass->getVisibilityString() << ' ' + Log::info() << dotnetClass->getVisibilityString() << ' ' << (dotnetClass->isAbstract() ? "abstract " : "") << (dotnetClass->isSealed() ? "sealed " : "") << dotnetClass->getTypeString() << ' ' @@ -566,23 +566,23 @@ void PlainPresentation::presentDotnetClasses() const if (!dotnetClass->getBaseTypes().empty()) { - std::cout << " : "; + Log::info() << " : "; for (auto itr = dotnetClass->getBaseTypes().begin(), end = dotnetClass->getBaseTypes().end(); itr != end; ++itr) { - std::cout << (*itr)->getText(); + Log::info() << (*itr)->getText(); if (itr + 1 != end) - std::cout << ", "; + Log::info() << ", "; } } - std::cout << '\n'; + Log::info() << '\n'; if (!dotnetClass->getMethods().empty()) - std::cout << " // Methods\n"; + Log::info() << " // Methods\n"; for (const auto& dotnetMethod : dotnetClass->getMethods()) { - std::cout << " " << dotnetMethod->getVisibilityString() << ' ' + Log::info() << " " << dotnetMethod->getVisibilityString() << ' ' << (dotnetMethod->isStatic() ? "static " : "") << (dotnetMethod->isVirtual() ? "virtual " : "") << (dotnetMethod->isFinal() ? "sealed " : "") @@ -593,31 +593,31 @@ void PlainPresentation::presentDotnetClasses() const for (auto itr = dotnetMethod->getParameters().begin(), end = dotnetMethod->getParameters().end(); itr != end; ++itr) { - std::cout << (*itr)->getDataType()->getText() << ' ' << (*itr)->getName(); + Log::info() << (*itr)->getDataType()->getText() << ' ' << (*itr)->getName(); if (itr + 1 != end) - std::cout << ", "; + Log::info() << ", "; } - std::cout << ")\n"; + Log::info() << ")\n"; } if (!dotnetClass->getFields().empty()) - std::cout << " // Fields\n"; + Log::info() << " // Fields\n"; for (const auto& dotnetField : dotnetClass->getFields()) { - std::cout << " " << dotnetField->getVisibilityString() << ' ' + Log::info() << " " << dotnetField->getVisibilityString() << ' ' << dotnetField->getDataType()->getText() << ' ' << dotnetField->getName() << '\n'; } if (!dotnetClass->getProperties().empty()) - std::cout << " // Properties\n"; + Log::info() << " // Properties\n"; for (const auto& dotnetProperty : dotnetClass->getProperties()) { - std::cout << " " << dotnetProperty->getVisibilityString() << ' ' + Log::info() << " " << dotnetProperty->getVisibilityString() << ' ' << dotnetProperty->getDataType()->getText() << ' ' << dotnetProperty->getName() << '\n'; @@ -634,14 +634,14 @@ void PlainPresentation::presentVisualBasicObjects() const return; } - std::cout << "\n"; - std::cout << "Visual Basic Object table" << "\n"; - std::cout << "-------------------------" << "\n"; - std::cout << "CRC32 : " << fileinfo.getVisualBasicObjectTableHashCrc32() << "\n"; - std::cout << "MD5 : " << fileinfo.getVisualBasicObjectTableHashMd5() << "\n"; - std::cout << "SHA256 : " << fileinfo.getVisualBasicObjectTableHashSha256() << "\n"; - std::cout << "GUID : " << guid << "\n"; - std::cout << "\n"; + Log::info() << "\n"; + Log::info() << "Visual Basic Object table" << "\n"; + Log::info() << "-------------------------" << "\n"; + Log::info() << "CRC32 : " << fileinfo.getVisualBasicObjectTableHashCrc32() << "\n"; + Log::info() << "MD5 : " << fileinfo.getVisualBasicObjectTableHashMd5() << "\n"; + Log::info() << "SHA256 : " << fileinfo.getVisualBasicObjectTableHashSha256() << "\n"; + Log::info() << "GUID : " << guid << "\n"; + Log::info() << "\n"; std::size_t cnt = 0; for (std::size_t i = 0; i < nObjs; i++) @@ -656,10 +656,10 @@ void PlainPresentation::presentVisualBasicObjects() const { continue; } - std::cout << cnt << ". " << "object name: " << objName << "\n"; + Log::info() << cnt << ". " << "object name: " << objName << "\n"; for (const auto &m : obj->getMethods()) { - std::cout << " method name: " << m << "\n"; + Log::info() << " method name: " << m << "\n"; } cnt++; } @@ -698,7 +698,7 @@ void PlainPresentation::presentCore() const bool PlainPresentation::present() { - std::cout << "Input file : " << fileinfo.getPathToFile() << "\n"; + Log::info() << "Input file : " << fileinfo.getPathToFile() << "\n"; presentSimple(BasicPlainGetter(fileinfo), false); presentCompiler(); presentLanguages(); @@ -706,12 +706,12 @@ bool PlainPresentation::present() presentOverlay(); if(returnCode != ReturnCode::OK) { - std::cerr << getErrorMessage(returnCode, fileinfo.getFileFormatEnum()) << "\n"; + Log::error() << getErrorMessage(returnCode, fileinfo.getFileFormatEnum()) << "\n"; } for(std::size_t i = 0, e = fileinfo.messages.size(); i < e; ++i) { - std::cerr << fileinfo.messages[i] << "\n"; + Log::error() << fileinfo.messages[i] << "\n"; } if(verbose) @@ -721,13 +721,13 @@ bool PlainPresentation::present() errorMessage = fileinfo.getLoaderStatusMessage(); if(!errorMessage.empty()) { - std::cerr << "Warning: " << errorMessage << "\n"; + Log::error() << Log::Warning << errorMessage << "\n"; } errorMessage = fileinfo.getDepsListFailedToLoad(); if (!errorMessage.empty()) { - std::cerr << "Warning: Failed to load the dependency list (\"" << errorMessage << "\")\n"; + Log::error() << Log::Warning << "Failed to load the dependency list (\"" << errorMessage << "\")\n"; } std::string flags, title; @@ -768,13 +768,13 @@ bool PlainPresentation::present() presentTitle("Manifest"); if(manifest[0] != '\n') { - std::cout << "\n"; + Log::info() << "\n"; } if(manifest[manifest.length() - 1] != '\n') { manifest += '\n'; } - std::cout << replaceNonasciiChars(manifest); + Log::info() << replaceNonasciiChars(manifest); } presentIterativeSimple(CertificateTablePlainGetter(fileinfo)); diff --git a/src/fileinfo/fileinfo.cpp b/src/fileinfo/fileinfo.cpp index 5a8b52aa8..a08807880 100644 --- a/src/fileinfo/fileinfo.cpp +++ b/src/fileinfo/fileinfo.cpp @@ -4,13 +4,13 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include #include #include #include "retdec/utils/conversion.h" #include "retdec/utils/memory.h" +#include "retdec/utils/io/log.h" #include "retdec/utils/string.h" #include "retdec/ar-extractor/detection.h" #include "retdec/cpdetect/errors.h" @@ -25,6 +25,7 @@ #include "fileinfo/pattern_detector/pattern_detector.h" using namespace retdec::utils; +using namespace retdec::utils::io; using namespace retdec::ar_extractor; using namespace retdec::cpdetect; using namespace retdec::fileformat; @@ -108,7 +109,7 @@ void fatalErrorHandler(void *user_data, const std::string& /*reason*/, bool /*ge */ void printHelp() { - std::cout << "fileinfo - dumper of information about executable file\n\n" + Log::info() << "fileinfo - dumper of information about executable file\n\n" << "For compiler detection, program looks in the input file for YARA patterns.\n" << "According to them, it determines compiler or packer used for file creation.\n" << "Supported file formats are: " + joinStrings(getSupportedFileFormats()) + ".\n\n" @@ -188,7 +189,7 @@ std::string getParamOrDie(std::vector &argv, std::size_t &i) } else { - std::cerr << getErrorMessage(ReturnCode::ARG) << "\n\n"; + Log::error() << getErrorMessage(ReturnCode::ARG) << "\n\n"; printHelp(); exit(static_cast(ReturnCode::ARG)); } @@ -413,7 +414,7 @@ int main(int argc, char* argv[]) ProgParams params; if(!doParams(argc, argv, params)) { - std::cerr << getErrorMessage(ReturnCode::ARG) << "\n\n"; + Log::error() << getErrorMessage(ReturnCode::ARG) << "\n\n"; printHelp(); return static_cast(ReturnCode::ARG); } @@ -517,7 +518,7 @@ int main(int argc, char* argv[]) auto config = ConfigPresentation(fileinfo, params.configFile); if(!config.present()) { - std::cerr << "Error: loading of config failed: " << config.getErrorMessage() << "\n"; + Log::error() << "Error: loading of config failed: " << config.getErrorMessage() << "\n"; res = ReturnCode::FILE_PROBLEM; } } diff --git a/src/getsig/getsig.cpp b/src/getsig/getsig.cpp index 78794857b..fbf42782f 100644 --- a/src/getsig/getsig.cpp +++ b/src/getsig/getsig.cpp @@ -5,22 +5,23 @@ */ #include -#include #include #include "retdec/fileformat/format_factory.h" #include "retdec/utils/conversion.h" #include "retdec/utils/string.h" +#include "retdec/utils/io/log.h" using namespace retdec::fileformat; using namespace retdec::utils; +using namespace retdec::utils::io; /** * Print usage. */ void printUsage() { - std::cout << + Log::info() << "getsig - generator of YARA tool signatures\n\n" "Program takes executable files, compares their content at given\n" "offset and prints signature representing contents of all files.\n\n" @@ -93,7 +94,7 @@ struct Options int printError( const std::string& message) { - std::cerr << "Error: " << message << ".\n"; + Log::error() << Log::Error << message << ".\n"; return 1; } @@ -104,7 +105,7 @@ int printError( void printWarning( const std::string& message) { - std::cerr << "Warning: " << message << ".\n"; + Log::error() << Log::Warning << message << ".\n"; } /** @@ -121,7 +122,7 @@ std::string getParamOrDie(std::vector &argv, std::size_t &i) } else { - std::cerr << "Error: missing argument value.\n\n"; + Log::error() << Log::Error << "missing argument value.\n\n"; printUsage(); exit(1); } @@ -512,7 +513,7 @@ int main(int argc, char** argv) { // create detection rule const auto rule = getYaraRule(signature, format, options); - std::cout << rule; + Log::info() << rule; if (!options.outputFile.empty()) { diff --git a/src/idr2pat/idr2pat.cpp b/src/idr2pat/idr2pat.cpp index 50e86c2e3..8e42cad4c 100644 --- a/src/idr2pat/idr2pat.cpp +++ b/src/idr2pat/idr2pat.cpp @@ -7,18 +7,19 @@ #include #include #include -#include #include #include #include #include #include "retdec/utils/conversion.h" +#include "retdec/utils/io/log.h" #include "yaramod/builder/yara_expression_builder.h" #include "yaramod/builder/yara_hex_string_builder.h" #include "yaramod/builder/yara_rule_builder.h" using namespace retdec::utils; +using namespace retdec::utils::io; using namespace yaramod; /** @@ -217,7 +218,7 @@ void readFunction( ruleBuilder.withHexString("$1", hexBuilder.get()); ruleBuilder.withCondition(stringRef("$1").get()); - std::cout << ruleBuilder.get()->getText() << "\n"; + Log::info() << ruleBuilder.get()->getText() << "\n"; } /** @@ -298,7 +299,7 @@ bool readDatabase( */ int printError(const std::string &message) { - std::cerr << "Error: " << message << ".\n"; + Log::error() << Log::Error << message << ".\n"; return 1; } diff --git a/src/llvm-support/CMakeLists.txt b/src/llvm-support/CMakeLists.txt deleted file mode 100644 index f1e4de11f..000000000 --- a/src/llvm-support/CMakeLists.txt +++ /dev/null @@ -1,58 +0,0 @@ - -add_library(llvm-support STATIC - diagnostics.cpp -) -add_library(retdec::llvm-support ALIAS llvm-support) - -target_compile_features(llvm-support PUBLIC cxx_std_17) - -target_include_directories(llvm-support - PUBLIC - $ - $ -) - -target_link_libraries(llvm-support - PUBLIC - retdec::deps::llvm - PRIVATE - retdec::utils -) - -set_target_properties(llvm-support - PROPERTIES - OUTPUT_NAME "retdec-llvm-support" -) - -# Install includes. -install( - DIRECTORY ${RETDEC_INCLUDE_DIR}/retdec/llvm-support - DESTINATION ${RETDEC_INSTALL_INCLUDE_DIR}/retdec -) - -# Install libs. -install(TARGETS llvm-support - EXPORT llvm-support-targets - ARCHIVE DESTINATION ${RETDEC_INSTALL_LIB_DIR} - LIBRARY DESTINATION ${RETDEC_INSTALL_LIB_DIR} -) - -# Export targets. -install(EXPORT llvm-support-targets - FILE "retdec-llvm-support-targets.cmake" - NAMESPACE retdec:: - DESTINATION ${RETDEC_INSTALL_CMAKE_DIR} -) - -# Install CMake files. -configure_file( - "retdec-llvm-support-config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/retdec-llvm-support-config.cmake" - @ONLY -) -install( - FILES - "${CMAKE_CURRENT_BINARY_DIR}/retdec-llvm-support-config.cmake" - DESTINATION - "${RETDEC_INSTALL_CMAKE_DIR}" -) diff --git a/src/llvm-support/diagnostics.cpp b/src/llvm-support/diagnostics.cpp deleted file mode 100644 index 555398d48..000000000 --- a/src/llvm-support/diagnostics.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/** -* @file src/llvm-support/diagnostics.cpp -* @brief Implementation of the functions concerning emission of diagnostics -* messages, like error or warning messages. -* @copyright (c) 2017 Avast Software, licensed under the MIT license -*/ - -#include -#include - -#include "retdec/llvm-support/diagnostics.h" -#include "retdec/utils/conversion.h" -#include "retdec/utils/time.h" - -using retdec::utils::getElapsedTime; - -namespace retdec { -namespace llvm_support { - -namespace { - -/** -* @brief Formats the given elapsed time so it can be printed. -* -* The resulting string is a representation of @a elapsedTime with fixed two -* numbers after the decimal point. For example, number @c 1.16397 is formatted -* as @c 1.16. -*/ -std::string formatElapsedTime(double elapsedTime) { - std::stringstream formatted; - formatted << std::fixed << std::setprecision(2) << elapsedTime; - return formatted.str(); -} - -/** -* @brief Prints the given phase to the given stream with the given prefix. -* -* This function is used to implement the print*Phase() functions. -*/ -void printPrefixedPhase(const std::string &prefix, const std::string &phaseName, - llvm::raw_ostream &stream) { - printColoredLine(stream, llvm::raw_ostream::YELLOW, /* bold */ true, prefix, - phaseName, " ( ", formatElapsedTime(getElapsedTime()), "s )"); - - // Make it appear as soon as possible to keep the user updated. - stream.flush(); -} - -} // anonymous namespace - -/** -* @brief Prints the given phase to the given stream. -* -* A new line is appended after the emitted text and the stream is flushed. -*/ -void printPhase( - const std::string &phaseName, - bool print, - llvm::raw_ostream &stream) -{ - if (print) - { - printPrefixedPhase("Running phase: ", phaseName, stream); - } -} - -/** -* @brief Prints the given sub-phase to the given stream. -* -* A new line is appended after the emitted text and the stream is flushed. -*/ -void printSubPhase( - const std::string &phaseName, - bool print, - llvm::raw_ostream &stream) -{ - if (print) - { - printPrefixedPhase(" -> ", phaseName, stream); - } -} - -/** -* @brief Prints the given sub-sub-phase to the given stream. -* -* A new line is appended after the emitted text and the stream is flushed. -*/ -void printSubSubPhase( - const std::string &phaseName, - bool print, - llvm::raw_ostream &stream) -{ - if (print) - { - printPrefixedPhase(" -> ", phaseName, stream); - } -} - -/** -* @brief Prints the given sub-sub-sub-phase to the given stream. -* -* A new line is appended after the emitted text and the stream is flushed. -*/ -void printSubSubSubPhase( - const std::string &phaseName, - bool print, - llvm::raw_ostream &stream) -{ - if (print) - { - printPrefixedPhase(" -> ", phaseName, stream); - } -} - -} // namespace llvm_support -} // namespace retdec diff --git a/src/llvm-support/retdec-llvm-support-config.cmake b/src/llvm-support/retdec-llvm-support-config.cmake deleted file mode 100644 index 7f9d08996..000000000 --- a/src/llvm-support/retdec-llvm-support-config.cmake +++ /dev/null @@ -1,11 +0,0 @@ - -if(NOT TARGET retdec::llvm-support) - find_package(retdec @PROJECT_VERSION@ - REQUIRED - COMPONENTS - utils - llvm - ) - - include(${CMAKE_CURRENT_LIST_DIR}/retdec-llvm-support-targets.cmake) -endif() diff --git a/src/llvmir-emul/llvmir_emul.cpp b/src/llvmir-emul/llvmir_emul.cpp index 0ff55faef..558751b7b 100644 --- a/src/llvmir-emul/llvmir_emul.cpp +++ b/src/llvmir-emul/llvmir_emul.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include - #include #include #include diff --git a/src/llvmir2hll/CMakeLists.txt b/src/llvmir2hll/CMakeLists.txt index 6573f63e0..36985792a 100644 --- a/src/llvmir2hll/CMakeLists.txt +++ b/src/llvmir2hll/CMakeLists.txt @@ -310,7 +310,6 @@ target_link_libraries(llvmir2hll PUBLIC retdec::config retdec::utils - retdec::llvm-support retdec::deps::rapidjson retdec::deps::llvm ) diff --git a/src/llvmir2hll/graphs/cfg/cfg_builders/non_recursive_cfg_builder.cpp b/src/llvmir2hll/graphs/cfg/cfg_builders/non_recursive_cfg_builder.cpp index 0113e3c20..c110ddf04 100644 --- a/src/llvmir2hll/graphs/cfg/cfg_builders/non_recursive_cfg_builder.cpp +++ b/src/llvmir2hll/graphs/cfg/cfg_builders/non_recursive_cfg_builder.cpp @@ -28,11 +28,10 @@ #include "retdec/llvmir2hll/support/debug.h" #include "retdec/llvmir2hll/support/expression_negater.h" #include "retdec/llvmir2hll/utils/ir.h" -#include "retdec/llvm-support/diagnostics.h" #include "retdec/utils/container.h" +#include "retdec/utils/io/log.h" -using namespace retdec::llvm_support; - +using namespace retdec::utils::io; using retdec::utils::clear; namespace retdec { @@ -392,8 +391,8 @@ void NonRecursiveCFGBuilder::addEdgeFromVector(const EdgeToAdd &edge) { // TODO This is the same problem as in the TODO below. if (i == emptyStmtToNodeMap.end()) { - printWarningMessage("[NonRecursiveCFGBuilder] there is no node for" - " an edge to `", edge.succStmt, "` -> skipping this edge"); + Log::error() << Log::Warning << "[NonRecursiveCFGBuilder] there is no node for" + " an edge to `" << edge.succStmt << "` -> skipping this edge" << std::endl; return; } @@ -431,8 +430,8 @@ void NonRecursiveCFGBuilder::addEdgeFromVector(const EdgeToAdd &edge) { // - binaries-suite/arm-elf/O2/gnuarm-elf-gcc-O2--gzip // if (!targetNode) { - printWarningMessage("[NonRecursiveCFGBuilder] there is no node for" - " an edge to `", edge.succStmt, "` -> skipping this edge"); + Log::error() << Log::Warning << "[NonRecursiveCFGBuilder] there is no node for" + " an edge to `" << edge.succStmt << "` -> skipping this edge" << std::endl; return; } diff --git a/src/llvmir2hll/hll/hll_writers/c_hll_writer.cpp b/src/llvmir2hll/hll/hll_writers/c_hll_writer.cpp index 57c741c10..86d7c6afe 100644 --- a/src/llvmir2hll/hll/hll_writers/c_hll_writer.cpp +++ b/src/llvmir2hll/hll/hll_writers/c_hll_writer.cpp @@ -100,12 +100,9 @@ #include "retdec/llvmir2hll/support/struct_types_sorter.h" #include "retdec/llvmir2hll/support/types.h" #include "retdec/llvmir2hll/utils/ir.h" -#include "retdec/llvm-support/diagnostics.h" #include "retdec/utils/container.h" #include "retdec/utils/conversion.h" -using namespace retdec::llvm_support; - using retdec::utils::addToSet; namespace retdec { diff --git a/src/llvmir2hll/llvm/llvmir2bir_converter.cpp b/src/llvmir2hll/llvm/llvmir2bir_converter.cpp index ccb4d0891..612956350 100644 --- a/src/llvmir2hll/llvm/llvmir2bir_converter.cpp +++ b/src/llvmir2hll/llvm/llvmir2bir_converter.cpp @@ -6,7 +6,6 @@ #include -#include "retdec/llvm-support/diagnostics.h" #include "retdec/llvmir2hll/config/config.h" #include "retdec/llvmir2hll/ir/expression.h" #include "retdec/llvmir2hll/ir/function.h" @@ -20,8 +19,9 @@ #include "retdec/llvmir2hll/support/debug.h" #include "retdec/llvmir2hll/utils/ir.h" #include "retdec/llvmir2hll/utils/string.h" +#include "retdec/utils/io/log.h" -using namespace retdec::llvm_support; +using namespace retdec::utils::io; namespace retdec { namespace llvmir2hll { @@ -148,7 +148,7 @@ ShPtr LLVMIR2BIRConverter::convertGlobalVariableInitializer( */ void LLVMIR2BIRConverter::convertAndAddGlobalVariables() { if (enableDebug) { - printSubPhase("converting global variables"); + Log::phase("converting global variables", Log::SubPhase); } for (auto &globVar: llvmModule->globals()) { @@ -198,7 +198,7 @@ ShPtr LLVMIR2BIRConverter::convertFuncDeclaration( void LLVMIR2BIRConverter::updateFuncToDefinition(llvm::Function &func) { auto name = func.getName(); if (enableDebug) { - printSubPhase("converting function " + name.str()); + Log::phase("converting function " + name.str(), Log::SubPhase); } auto birFunc = resModule->getFuncByName(name); diff --git a/src/llvmir2hll/llvm/llvmir2bir_converter/labels_handler.cpp b/src/llvmir2hll/llvm/llvmir2bir_converter/labels_handler.cpp index 3cbd7132b..05c88439c 100644 --- a/src/llvmir2hll/llvm/llvmir2bir_converter/labels_handler.cpp +++ b/src/llvmir2hll/llvm/llvmir2bir_converter/labels_handler.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -// #include - #include #include "retdec/llvmir2hll/ir/statement.h" diff --git a/src/llvmir2hll/llvmir2hll.cpp b/src/llvmir2hll/llvmir2hll.cpp index 056363429..bd176dde0 100644 --- a/src/llvmir2hll/llvmir2hll.cpp +++ b/src/llvmir2hll/llvmir2hll.cpp @@ -1,13 +1,13 @@ #include -#include #include #include #include "retdec/llvmir2hll/llvmir2hll.h" -#include "retdec/llvm-support/diagnostics.h" +#include "retdec/utils/io/log.h" using namespace llvm; +using namespace retdec::utils::io; using retdec::llvmir2hll::ShPtr; using retdec::utils::hasItem; using retdec::utils::joinStrings; @@ -50,7 +50,7 @@ std::unique_ptr getOutputStream( ); if (ec) { - errs() << ec.message() << '\n'; + Log::error() << ec.message() << '\n'; return {}; } return out; @@ -90,21 +90,18 @@ void printErrorUnsupportedObject( std::string supportedObjects(getListOfSupportedObjects()); if (!supportedObjects.empty()) { - retdec::llvm_support::printErrorMessage( - "Invalid name of the ", - typeOfObjectsSingular, - " (supported names are: ", - supportedObjects, - ")." - ); + Log::error() << Log::Error + << "Invalid name of the " << typeOfObjectsSingular + << " (supported names are: " << supportedObjects << ")." + << std::endl; } else { - retdec::llvm_support::printErrorMessage( - "There are no available ", - typeOfObjectsPlural, - ". Please SHIT, recompile the backend and try it again." - ); + Log::error() << Log::Error + << "There are no available " + << typeOfObjectsPlural + << ". Please SHIT, recompile the backend and try it again." + << std::endl; } } @@ -152,7 +149,7 @@ void LlvmIr2Hll::getAnalysisUsage(llvm::AnalysisUsage &au) const bool LlvmIr2Hll::runOnModule(llvm::Module &m) { - llvm_support::printPhase("initialization", Debug); + Log::phase("initialization"); bool decompilationShouldContinue = initialize(m); if (!decompilationShouldContinue) @@ -160,7 +157,7 @@ bool LlvmIr2Hll::runOnModule(llvm::Module &m) return false; } - llvm_support::printPhase("conversion of LLVM IR into BIR", Debug); + Log::phase("conversion of LLVM IR into BIR"); decompilationShouldContinue = convertLLVMIRToBIR(); if (!decompilationShouldContinue) { @@ -169,10 +166,7 @@ bool LlvmIr2Hll::runOnModule(llvm::Module &m) if (!globalConfig->parameters.isBackendKeepLibraryFuncs()) { - llvm_support::printPhase( - "removing functions from standard libraries", - Debug - ); + Log::phase("removing functions from standard libraries"); removeLibraryFuncs(); } @@ -181,94 +175,73 @@ bool LlvmIr2Hll::runOnModule(llvm::Module &m) // the conversion of LLVM IR to BIR is not perfect, so it may introduce // unreachable code. This causes problems later during optimizations // because the code exists in BIR, but not in a CFG. - llvm_support::printPhase( - "removing code that is not reachable in a CFG", - Debug - ); + Log::phase("removing code that is not reachable in a CFG"); removeCodeUnreachableInCFG(); - llvm_support::printPhase("signed/unsigned types fixing", Debug); + Log::phase("signed/unsigned types fixing"); fixSignedUnsignedTypes(); - llvm_support::printPhase( - "converting LLVM intrinsic functions to standard functions", - Debug - ); + Log::phase("converting LLVM intrinsic functions to standard functions"); convertLLVMIntrinsicFunctions(); if (resModule->isDebugInfoAvailable()) { - llvm_support::printPhase("obtaining debug information", Debug); + Log::phase("obtaining debug information"); obtainDebugInfo(); } if (!globalConfig->parameters.isBackendNoOpts()) { - llvm_support::printPhase( - "alias analysis [" + aliasAnalysis->getId() + "]", - Debug - ); + Log::phase("alias analysis [" + aliasAnalysis->getId() + "]"); initAliasAnalysis(); - llvm_support::printPhase( - "optimizations [" + getTypeOfRunOptimizations() + "]", - Debug - ); + Log::phase("optimizations [" + getTypeOfRunOptimizations() + "]"); runOptimizations(); } if (!globalConfig->parameters.isBackendNoVarRenaming()) { - llvm_support::printPhase( - "variable renaming [" + varRenamer->getId() + "]", - Debug - ); + Log::phase("variable renaming [" + varRenamer->getId() + "]"); renameVariables(); } if (!globalConfig->parameters.isBackendNoSymbolicNames()) { - llvm_support::printPhase( - "converting constants to symbolic names", - Debug - ); + Log::phase("converting constants to symbolic names"); convertConstantsToSymbolicNames(); } if (ValidateModule) { - llvm_support::printPhase("module validation", Debug); + Log::phase("module validation"); validateResultingModule(); } if (!FindPatterns.empty()) { - llvm_support::printPhase("finding patterns", Debug); + Log::phase("finding patterns"); findPatterns(); } if (globalConfig->parameters.isBackendEmitCfg()) { - llvm_support::printPhase("emission of control-flow graphs", Debug); + Log::phase("emission of control-flow graphs"); emitCFGs(); } if (globalConfig->parameters.isBackendEmitCg()) { - llvm_support::printPhase("emission of a call graph", Debug); + Log::phase("emission of a call graph"); emitCG(); } - llvm_support::printPhase( - "emission of the target code [" + hllWriter->getId() + "]", - Debug - ); + Log::phase("emission of the target code [" + hllWriter->getId() + "]"); emitTargetHLLCode(); - llvm_support::printPhase("finalization", Debug); + Log::phase("finalization"); finalize(); - llvm_support::printPhase("cleanup", Debug); + Log::phase("cleanup"); cleanup(); return false; @@ -293,9 +266,9 @@ bool LlvmIr2Hll::initialize(llvm::Module &m) // Instantiate the requested HLL writer and make sure it exists. We need to // explicitly specify template parameters because raw_pwrite_stream has // a private copy constructor, so it needs to be passed by reference. - llvm_support::printSubPhase( - "creating the used HLL writer [" + TargetHLL + "]", - Debug + Log::phase( + "creating the used HLL writer [" + TargetHLL + "]", + Log::SubPhase ); // Output stream into which the generated code will be emitted. @@ -325,9 +298,9 @@ bool LlvmIr2Hll::initialize(llvm::Module &m) } // Instantiate the requested alias analysis and make sure it exists. - llvm_support::printSubPhase( - "creating the used alias analysis [" + oAliasAnalysis + "]", - Debug + Log::phase( + "creating the used alias analysis [" + oAliasAnalysis + "]", + Log::SubPhase ); aliasAnalysis = llvmir2hll::AliasAnalysisFactory::getInstance().createObject( oAliasAnalysis @@ -342,10 +315,10 @@ bool LlvmIr2Hll::initialize(llvm::Module &m) // Instantiate the requested obtainer of information about function // calls and make sure it exists. - llvm_support::printSubPhase( - "creating the used call info obtainer [" - + globalConfig->parameters.getBackendCallInfoObtainer() + "]", - Debug + Log::phase( + "creating the used call info obtainer [" + + globalConfig->parameters.getBackendCallInfoObtainer() + "]", + Log::SubPhase ); cio = llvmir2hll::CallInfoObtainerFactory::getInstance().createObject( globalConfig->parameters.getBackendCallInfoObtainer() @@ -360,10 +333,10 @@ bool LlvmIr2Hll::initialize(llvm::Module &m) // Instantiate the requested evaluator of arithmetical expressions and make // sure it exists. - llvm_support::printSubPhase( - "creating the used evaluator of arithmetical expressions [" + - oArithmExprEvaluator + "]", - Debug + Log::phase( + "creating the used evaluator of arithmetical expressions [" + + oArithmExprEvaluator + "]", + Log::SubPhase ); auto& aeef = llvmir2hll::ArithmExprEvaluatorFactory::getInstance(); arithmExprEvaluator = aeef.createObject(oArithmExprEvaluator); @@ -378,9 +351,9 @@ bool LlvmIr2Hll::initialize(llvm::Module &m) // Instantiate the requested variable names generator and make sure it // exists. - llvm_support::printSubPhase( - "creating the used variable names generator [" + oVarNameGen + "]", - Debug + Log::phase( + "creating the used variable names generator [" + oVarNameGen + "]", + Log::SubPhase ); varNameGen = llvmir2hll::VarNameGenFactory::getInstance().createObject( oVarNameGen, @@ -395,10 +368,10 @@ bool LlvmIr2Hll::initialize(llvm::Module &m) } // Instantiate the requested variable renamer and make sure it exists. - llvm_support::printSubPhase( - "creating the used variable renamer [" - + globalConfig->parameters.getBackendVarRenamer() + "]", - Debug + Log::phase( + "creating the used variable renamer [" + + globalConfig->parameters.getBackendVarRenamer() + "]", + Log::SubPhase ); varRenamer = llvmir2hll::VarRenamerFactory::getInstance().createObject( globalConfig->parameters.getBackendVarRenamer(), @@ -445,18 +418,18 @@ void LlvmIr2Hll::createSemanticsFromParameter() if (oSemantics.empty() || oSemantics == "-") { // Do no use any semantics. - llvm_support::printSubPhase( - "creating the used semantics [none]", - Debug + Log::phase( + "creating the used semantics [none]", + Log::SubPhase ); semantics = llvmir2hll::DefaultSemantics::create(); } else { // Use the given semantics. - llvm_support::printSubPhase( - "creating the used semantics [" + oSemantics + "]", - Debug + Log::phase( + "creating the used semantics [" + oSemantics + "]", + Log::SubPhase ); semantics = llvmir2hll::CompoundSemanticsBuilder::build( split(oSemantics, ',') @@ -474,9 +447,9 @@ void LlvmIr2Hll::createSemanticsFromLLVMIR() std::string usedSemantics("libc,gcc-general,win-api"); // Use the list to create the semantics. - llvm_support::printSubPhase( - "creating the used semantics [" + usedSemantics + "]", - Debug + Log::phase( + "creating the used semantics [" + usedSemantics + "]", + Log::SubPhase ); semantics = llvmir2hll::CompoundSemanticsBuilder::build( split(usedSemantics, ',') @@ -493,12 +466,12 @@ bool LlvmIr2Hll::loadConfig() // Currently, we always use the JSON config. if (globalConfig == nullptr) { - llvm_support::printSubPhase("creating a new config", Debug); + Log::phase("creating a new config", Log::SubPhase); config = llvmir2hll::JSONConfig::empty(); return true; } - llvm_support::printSubPhase("loading the input config", Debug); + Log::phase("loading the input config", Log::SubPhase); try { config = llvmir2hll::JSONConfig::fromString( @@ -508,9 +481,9 @@ bool LlvmIr2Hll::loadConfig() } catch (const llvmir2hll::ConfigError &ex) { - llvm_support::printErrorMessage( - "Loading of the config failed: " + ex.getMessage() + "." - ); + Log::error() << Log::Error + << "Loading of the config failed: " << ex.getMessage() << "." + << std::endl; return false; } } @@ -570,7 +543,7 @@ void LlvmIr2Hll::removeLibraryFuncs() llvmir2hll::sortByName(removedFuncs); for (const auto &func : removedFuncs) { - llvm_support::printSubPhase("removing " + func->getName() + "()"); + Log::phase("removing " + func->getName() + "()"); } } } @@ -667,7 +640,7 @@ void LlvmIr2Hll::validateResultingModule() std::sort(regValidatorIDs.begin(), regValidatorIDs.end()); for (const auto &id : regValidatorIDs) { - llvm_support::printSubPhase("running " + id + "Validator", Debug); + Log::phase("running " + id + "Validator", Log::SubPhase); ShPtr validator( llvmir2hll::ValidatorFactory::getInstance().createObject(id) ); @@ -738,9 +711,10 @@ void LlvmIr2Hll::emitCFGs() { if (globalConfig->parameters.getOutputFile().empty()) { - llvm_support::printErrorMessage( - "Output file not set, cannot generate output CFG files." - ); + Log::error() << Log::Error + << "Output file not set, cannot generate output CFG files." + << std::endl; + return; } @@ -777,9 +751,9 @@ void LlvmIr2Hll::emitCFGs() std::ofstream out(fileName.c_str()); if (!out) { - llvm_support::printErrorMessage( - "Cannot open " + fileName + " for writing." - ); + Log::error() << Log::Error + << "Cannot open " + fileName + " for writing." + << std::endl; return; } // Create a CFG for the current function and emit it into the opened @@ -808,9 +782,9 @@ void LlvmIr2Hll::emitCG() { if (globalConfig->parameters.getOutputFile().empty()) { - llvm_support::printErrorMessage( - "Output file not set, cannot generate output CG file." - ); + Log::error() << Log::Error + << "Output file not set, cannot generate output CG file." + << std::endl; return; } @@ -838,9 +812,9 @@ void LlvmIr2Hll::emitCG() std::ofstream out(fileName.c_str()); if (!out) { - llvm_support::printErrorMessage( - "Cannot open " + fileName + " for writing." - ); + Log::error() << Log::Error + << "Cannot open " + fileName + " for writing." + << std::endl; return; } @@ -925,8 +899,9 @@ LlvmIr2Hll::instantiatePatternFinders( ); if (!pf && Debug) { - llvm_support::printWarningMessage( - "the requested pattern finder '" + pfId + "' does not exist"); + Log::error() << Log::Warning + << "the requested pattern finder '" + pfId + "' does not exist" + << std::endl; } else { @@ -945,7 +920,7 @@ LlvmIr2Hll::instantiatePatternFinderRunner() const if (Debug) { return ShPtr( - new llvmir2hll::CLIPatternFinderRunner(llvm::errs())); + new llvmir2hll::CLIPatternFinderRunner(Log::get(Log::Type::Error))); } return ShPtr( new llvmir2hll::NoActionPatternFinderRunner() diff --git a/src/llvmir2hll/obtainer/call_info_obtainer.cpp b/src/llvmir2hll/obtainer/call_info_obtainer.cpp index 3df40680e..9c9c08071 100644 --- a/src/llvmir2hll/obtainer/call_info_obtainer.cpp +++ b/src/llvmir2hll/obtainer/call_info_obtainer.cpp @@ -14,11 +14,10 @@ #include "retdec/llvmir2hll/ir/variable.h" #include "retdec/llvmir2hll/obtainer/call_info_obtainer.h" #include "retdec/llvmir2hll/support/debug.h" -#include "retdec/llvm-support/diagnostics.h" #include "retdec/utils/container.h" +#include "retdec/utils/io/log.h" -using namespace retdec::llvm_support; - +using namespace retdec::utils::io; using retdec::utils::hasItem; using retdec::utils::setDifference; using retdec::utils::setUnion; @@ -256,7 +255,7 @@ CallInfoObtainer::SCCWithRepresent CallInfoObtainer::findNextSCC( } // TODO Can this happen? - printWarningMessage("[SCCComputer] No viable SCC has been found."); + Log::error() << Log::Warning << "[SCCComputer] No viable SCC has been found." << std::endl; FuncSet scc; ShPtr func(*(remainingFuncs.begin())); scc.insert(func); diff --git a/src/llvmir2hll/obtainer/call_info_obtainers/optim_call_info_obtainer.cpp b/src/llvmir2hll/obtainer/call_info_obtainers/optim_call_info_obtainer.cpp index 36b1983b1..b2142fae8 100644 --- a/src/llvmir2hll/obtainer/call_info_obtainers/optim_call_info_obtainer.cpp +++ b/src/llvmir2hll/obtainer/call_info_obtainers/optim_call_info_obtainer.cpp @@ -13,12 +13,14 @@ #include "retdec/llvmir2hll/ir/variable.h" #include "retdec/llvmir2hll/obtainer/call_info_obtainer_factory.h" #include "retdec/llvmir2hll/obtainer/call_info_obtainers/optim_call_info_obtainer.h" -#include "retdec/llvmir2hll/support/debug.h" #include "retdec/utils/container.h" +#include "retdec/llvmir2hll/support/debug.h" +#include "retdec/utils/io/log.h" using retdec::utils::addToSet; using retdec::utils::hasItem; using retdec::utils::setIntersection; +using namespace retdec::utils::io; namespace retdec { namespace llvmir2hll { @@ -38,33 +40,33 @@ OptimCallInfo::OptimCallInfo(ShPtr call): CallInfo(call) {} * Only for debugging purposes. */ void OptimCallInfo::debugPrint() { - llvm::errs() << "[OptimCallInfo] Debug info for '" << call << "':\n"; + Log::error() << "[OptimCallInfo] Debug info for '" << call << "':\n"; - llvm::errs() << " neverReadVars: "; + Log::error() << " neverReadVars: "; dump(neverReadVars, dumpFuncGetName>); - llvm::errs() << " mayBeReadVars: "; + Log::error() << " mayBeReadVars: "; dump(mayBeReadVars, dumpFuncGetName>); - llvm::errs() << " alwaysReadVars: "; + Log::error() << " alwaysReadVars: "; dump(alwaysReadVars, dumpFuncGetName>); - llvm::errs() << " neverModifiedVars: "; + Log::error() << " neverModifiedVars: "; dump(neverModifiedVars, dumpFuncGetName>); - llvm::errs() << " mayBeModifiedVars: "; + Log::error() << " mayBeModifiedVars: "; dump(mayBeModifiedVars, dumpFuncGetName>); - llvm::errs() << " alwaysModifiedVars: "; + Log::error() << " alwaysModifiedVars: "; dump(alwaysModifiedVars, dumpFuncGetName>); - llvm::errs() << " varsWithNeverChangedValue: "; + Log::error() << " varsWithNeverChangedValue: "; dump(varsWithNeverChangedValue, dumpFuncGetName>); - llvm::errs() << " varsAlwaysModifiedBeforeRead: "; + Log::error() << " varsAlwaysModifiedBeforeRead: "; dump(varsAlwaysModifiedBeforeRead, dumpFuncGetName>); - llvm::errs() << "\n"; + Log::error() << "\n"; } bool OptimCallInfo::isNeverRead(ShPtr var) const { @@ -111,33 +113,33 @@ OptimFuncInfo::OptimFuncInfo(ShPtr func): FuncInfo(func) {} * Only for debugging purposes. */ void OptimFuncInfo::debugPrint() { - llvm::errs() << "[OptimFuncInfo] Debug info for function '" << func->getName() << "':\n"; + Log::error() << "[OptimFuncInfo] Debug info for function '" << func->getName() << "':\n"; - llvm::errs() << " neverReadVars: "; + Log::error() << " neverReadVars: "; dump(neverReadVars, dumpFuncGetName>); - llvm::errs() << " mayBeReadVars: "; + Log::error() << " mayBeReadVars: "; dump(mayBeReadVars, dumpFuncGetName>); - llvm::errs() << " alwaysReadVars: "; + Log::error() << " alwaysReadVars: "; dump(alwaysReadVars, dumpFuncGetName>); - llvm::errs() << " neverModifiedVars: "; + Log::error() << " neverModifiedVars: "; dump(neverModifiedVars, dumpFuncGetName>); - llvm::errs() << " mayBeModifiedVars: "; + Log::error() << " mayBeModifiedVars: "; dump(mayBeModifiedVars, dumpFuncGetName>); - llvm::errs() << " alwaysModifiedVars: "; + Log::error() << " alwaysModifiedVars: "; dump(alwaysModifiedVars, dumpFuncGetName>); - llvm::errs() << " varsWithNeverChangedValue: "; + Log::error() << " varsWithNeverChangedValue: "; dump(varsWithNeverChangedValue, dumpFuncGetName>); - llvm::errs() << " varsAlwaysModifiedBeforeRead: "; + Log::error() << " varsAlwaysModifiedBeforeRead: "; dump(varsAlwaysModifiedBeforeRead, dumpFuncGetName>); - llvm::errs() << "\n"; + Log::error() << "\n"; } bool OptimFuncInfo::isNeverRead(ShPtr var) const { diff --git a/src/llvmir2hll/optimizer/optimizer_manager.cpp b/src/llvmir2hll/optimizer/optimizer_manager.cpp index 0dce37b8d..806fd6f02 100644 --- a/src/llvmir2hll/optimizer/optimizer_manager.cpp +++ b/src/llvmir2hll/optimizer/optimizer_manager.cpp @@ -50,8 +50,9 @@ #include "retdec/utils/container.h" #include "retdec/utils/string.h" #include "retdec/utils/system.h" +#include "retdec/utils/io/log.h" -using namespace retdec::llvm_support; +using namespace retdec::utils::io; using namespace std::string_literals; using retdec::utils::hasItem; @@ -309,7 +310,7 @@ void OptimizerManager::runOptimizerProvidedItShouldBeRun(ShPtr optimi try { optimizer->optimize(); } catch (const std::bad_alloc &) { - printWarningMessage("out of memory; trying to recover"); + Log::error() << Log::Warning << "out of memory; trying to recover" << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); } } else { @@ -328,7 +329,7 @@ void OptimizerManager::runOptimizerProvidedItShouldBeRun(ShPtr optimi */ void OptimizerManager::printOptimization(const std::string &optId) const { if (enableDebug) { - printSubPhase("running "s + optId + OPT_SUFFIX); + Log::phase("running "s + optId + OPT_SUFFIX, Log::SubPhase); } } diff --git a/src/llvmir2hll/pattern/pattern_finder_runners/cli_pattern_finder_runner.cpp b/src/llvmir2hll/pattern/pattern_finder_runners/cli_pattern_finder_runner.cpp index 98be961dd..d4099bee1 100644 --- a/src/llvmir2hll/pattern/pattern_finder_runners/cli_pattern_finder_runner.cpp +++ b/src/llvmir2hll/pattern/pattern_finder_runners/cli_pattern_finder_runner.cpp @@ -9,9 +9,8 @@ #include "retdec/llvmir2hll/ir/statement.h" #include "retdec/llvmir2hll/pattern/pattern_finder_runners/cli_pattern_finder_runner.h" #include "retdec/llvmir2hll/support/debug.h" -#include "retdec/llvm-support/diagnostics.h" -using namespace retdec::llvm_support; +using namespace retdec::utils::io; namespace retdec { namespace llvmir2hll { @@ -28,7 +27,7 @@ const std::string PATTERN_INFO_INDENT = " "; * * @param[out] os Output stream, into which the patterns will be emited. */ -CLIPatternFinderRunner::CLIPatternFinderRunner(llvm::raw_ostream &os): +CLIPatternFinderRunner::CLIPatternFinderRunner(utils::io::Logger &os): os(os) {} /** @@ -38,7 +37,7 @@ CLIPatternFinderRunner::CLIPatternFinderRunner(llvm::raw_ostream &os): */ void CLIPatternFinderRunner::doActionsBeforePatternFinderRuns( ShPtr pf) { - printSubPhase("running " + pf->getId() + "PatternFinder", true, os); + os << "running " + pf->getId() + "PatternFinder"; } /** @@ -55,8 +54,11 @@ void CLIPatternFinderRunner::doActionsAfterPatternFinderHasRun( * @brief Prints information about the given pattern. */ void CLIPatternFinderRunner::printPatternInfo(const ShPtr &p) { - os << PATTERN_INFO_INDENT << "Found pattern:" << "\n"; - p->print(os, PATTERN_INFO_INDENT + " "); + os << PATTERN_INFO_INDENT << "Found pattern:" << std::endl; + std::string str; + llvm::raw_string_ostream ss(str); + p->print(ss); + os << PATTERN_INFO_INDENT << " " << str; } } // namespace llvmir2hll diff --git a/src/llvmir2hll/pattern/pattern_finders/api_call_seq_pattern_finder.cpp b/src/llvmir2hll/pattern/pattern_finders/api_call_seq_pattern_finder.cpp index 3c2e20de8..513ceeb43 100644 --- a/src/llvmir2hll/pattern/pattern_finders/api_call_seq_pattern_finder.cpp +++ b/src/llvmir2hll/pattern/pattern_finders/api_call_seq_pattern_finder.cpp @@ -25,9 +25,9 @@ #include "retdec/llvmir2hll/pattern/patterns/stmts_pattern.h" #include "retdec/llvmir2hll/support/debug.h" #include "retdec/llvmir2hll/utils/ir.h" -#include "retdec/llvm-support/diagnostics.h" +#include "retdec/utils/io/log.h" -using namespace retdec::llvm_support; +using namespace retdec::utils::io; namespace retdec { namespace llvmir2hll { @@ -57,9 +57,9 @@ void parseAndAddAPICallInfoSeqToMap(APICallInfoSeqMap &map, if (seq) { map.insert(std::make_pair(funcName, seq.value())); } else { - printErrorMessage( - "APICallInfoSeqParser failed to parse the following pattern: ", - seqTextRepr); + Log::error() << Log::Error + << "APICallInfoSeqParser failed to parse the following pattern: " + << seqTextRepr; } } diff --git a/src/llvmir2hll/retdec-llvmir2hll-config.cmake b/src/llvmir2hll/retdec-llvmir2hll-config.cmake index 8e751efb4..b3b389462 100644 --- a/src/llvmir2hll/retdec-llvmir2hll-config.cmake +++ b/src/llvmir2hll/retdec-llvmir2hll-config.cmake @@ -5,7 +5,6 @@ if(NOT TARGET retdec::llvmir2hll) COMPONENTS config utils - llvm-support rapidjson llvm ) diff --git a/src/llvmir2hll/semantics/semantics/compound_semantics_builder.cpp b/src/llvmir2hll/semantics/semantics/compound_semantics_builder.cpp index a6226b5e3..76658b784 100644 --- a/src/llvmir2hll/semantics/semantics/compound_semantics_builder.cpp +++ b/src/llvmir2hll/semantics/semantics/compound_semantics_builder.cpp @@ -8,9 +8,9 @@ #include "retdec/llvmir2hll/semantics/semantics/compound_semantics_builder.h" #include "retdec/llvmir2hll/semantics/semantics_factory.h" #include "retdec/llvmir2hll/support/debug.h" -#include "retdec/llvm-support/diagnostics.h" +#include "retdec/utils/io/log.h" -using namespace retdec::llvm_support; +using namespace retdec::utils::io; namespace retdec { namespace llvmir2hll { @@ -38,8 +38,9 @@ ShPtr CompoundSemanticsBuilder::build( if (semantics) { compoundSemantics->appendSemantics(semantics); } else { - printWarningMessage("There is no registered semantics with ID \"", - id, "\", skipping."); + Log::error() << Log::Warning + << "There is no registered semantics with ID \"" << id << "\", skipping." + << std::endl; } } diff --git a/src/llvmir2hll/validator/validators/break_outside_loop_validator.cpp b/src/llvmir2hll/validator/validators/break_outside_loop_validator.cpp index ac6502ea7..6e32dc8fc 100644 --- a/src/llvmir2hll/validator/validators/break_outside_loop_validator.cpp +++ b/src/llvmir2hll/validator/validators/break_outside_loop_validator.cpp @@ -35,8 +35,10 @@ void BreakOutsideLoopValidator::visit(ShPtr stmt) { // this end, get the innermost loop or switch. ShPtr innLoopOrSwitch(getInnermostLoopOrSwitch(stmt)); if (!innLoopOrSwitch) { - validationError("In ", func->getName(), "(), found `", stmt, - "` outside of a loop or a switch statement."); + std::ostringstream stmtStr; + stmtStr << stmt; + validationError("In " + func->getName() + "(), found `" + stmtStr.str() + + "` outside of a loop or a switch statement."); } OrderedAllVisitor::visit(stmt); } @@ -46,8 +48,10 @@ void BreakOutsideLoopValidator::visit(ShPtr stmt) { // innermost loop. ShPtr innLoop(getInnermostLoop(stmt)); if (!innLoop) { - validationError("In ", func->getName(), "(), found `", stmt, - "` outside of a loop."); + std::ostringstream stmtStr; + stmtStr << stmt; + validationError("In " + func->getName() + "(), found `" + stmtStr.str() + +"` outside of a loop."); } OrderedAllVisitor::visit(stmt); } diff --git a/src/llvmir2hll/validator/validators/no_global_var_def_validator.cpp b/src/llvmir2hll/validator/validators/no_global_var_def_validator.cpp index 116fa5544..4a22fae8a 100644 --- a/src/llvmir2hll/validator/validators/no_global_var_def_validator.cpp +++ b/src/llvmir2hll/validator/validators/no_global_var_def_validator.cpp @@ -35,9 +35,11 @@ std::string NoGlobalVarDefValidator::getId() const { void NoGlobalVarDefValidator::visit(ShPtr stmt) { // The left-hand side of a VarDefStmt cannot be a global variable. + std::ostringstream stmtStr; + stmtStr << stmt; if (module->isGlobalVar(stmt->getVar())) { - validationError("In ", func->getName(), "(), found a VarDefStmt `", - stmt, "` that defines a global variable."); + validationError("In "+func->getName()+"(), found a VarDefStmt `"+ + stmtStr.str()+"` that defines a global variable."); } OrderedAllVisitor::visit(stmt); } diff --git a/src/llvmir2hll/validator/validators/return_validator.cpp b/src/llvmir2hll/validator/validators/return_validator.cpp index d403d35a6..2d1384f08 100644 --- a/src/llvmir2hll/validator/validators/return_validator.cpp +++ b/src/llvmir2hll/validator/validators/return_validator.cpp @@ -37,14 +37,18 @@ std::string ReturnValidator::getId() const { void ReturnValidator::visit(ShPtr stmt) { // If the function is non-void, there has to be a return value. if (!isa(func->getRetType()) && !stmt->getRetVal()) { - validationError("In ", func->getName(), "(), which is non-void, ", - "found a ReturnStmt `", stmt, "` without a return value."); + std::ostringstream stmtStr; + stmtStr << stmt; + validationError("In "+func->getName()+"(), which is non-void, " + "found a ReturnStmt `"+stmtStr.str()+"` without a return value."); } // If the function is void, there cannot be a return value. if (isa(func->getRetType()) && stmt->getRetVal()) { - validationError("In ", func->getName(), "(), which returns void, ", - "found a ReturnStmt `", stmt, "` with a return value."); + std::ostringstream stmtStr; + stmtStr << stmt; + validationError("In "+func->getName()+"(), which returns void, " + "found a ReturnStmt `"+stmtStr.str()+"` with a return value."); } OrderedAllVisitor::visit(stmt); diff --git a/src/macho-extractor/break_fat.cpp b/src/macho-extractor/break_fat.cpp index 302569f0d..3988b999e 100644 --- a/src/macho-extractor/break_fat.cpp +++ b/src/macho-extractor/break_fat.cpp @@ -4,7 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include #include #include @@ -13,6 +12,7 @@ #include "retdec/macho-extractor/break_fat.h" #include "retdec/utils/conversion.h" +#include "retdec/utils/io/log.h" #include "retdec/utils/string.h" using namespace llvm; @@ -21,6 +21,7 @@ using namespace llvm::object; using namespace llvm::sys; using namespace rapidjson; using namespace retdec::utils; +using namespace retdec::utils::io; namespace { @@ -337,7 +338,7 @@ bool BreakMachOUniversal::listArchitectures( // Write warning when --object option is used on non-archive target. if(!isStatic && withObjects) { - std::cerr << "Warning: input file is not an archive! (--objects)\n"; + Log::error() << Log::Warning << "input file is not an archive! (--objects)\n"; } return output.good(); diff --git a/src/macho-extractortool/macho_extractor.cpp b/src/macho-extractortool/macho_extractor.cpp index 1cd39ee2a..32f88a4e3 100644 --- a/src/macho-extractortool/macho_extractor.cpp +++ b/src/macho-extractortool/macho_extractor.cpp @@ -4,7 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include #include #include @@ -13,8 +12,10 @@ #include "retdec/utils/conversion.h" #include "retdec/utils/string.h" +#include "retdec/utils/io/log.h" #include "retdec/macho-extractor/break_fat.h" +using namespace retdec::utils::io; using namespace retdec::macho_extractor; using namespace rapidjson; @@ -24,7 +25,7 @@ enum class Mode { All, Best, Arch, Family, Index }; void printUsage() { - std::cerr << + Log::error() << "\nExtract objects from Mach-O Universal Binaries.\n" "Usage: retdec-macho-extractor [OPTIONS] FILE\n\n" "Extraction options:\n\n" @@ -73,7 +74,7 @@ std::string getParamOrDie( } else { - std::cerr << "Error: missing argument value.\n\n"; + Log::error() << Log::Error << "missing argument value.\n\n"; printUsage(); exit(1); } @@ -98,11 +99,11 @@ void printError( StringBuffer outBuffer; PrettyWriter outWriter(outBuffer); outDoc.Accept(outWriter); - std::cout << outBuffer.GetString(); + Log::info() << outBuffer.GetString(); } else { - std::cerr << "Error: " << message << ".\n"; + Log::error() << Log::Error << message << ".\n"; } } @@ -117,7 +118,7 @@ int handleArguments( if(args.size() < 1) { printUsage(); - std::cerr << "Error: not enough arguments!\n"; + Log::error() << Log::Error << "not enough arguments!\n"; return 1; } @@ -254,25 +255,31 @@ int handleArguments( { if(binary.isStaticLibrary()) { - std::cout << "Input file is a static library.\n"; + Log::info() << "Input file is a static library.\n"; return 0; } - std::cout << "Input file is NOT a static library.\n"; + Log::info() << "Input file is NOT a static library.\n"; return 3; } // List mode if(listOnly) { + std::stringstream ss; + bool ret; + if(jsonOut) { - return binary.listArchitecturesJson(std::cout, addObjects) ? 0 : 1; + ret = binary.listArchitecturesJson(ss, addObjects) ? 0 : 1; } else { - return binary.listArchitectures(std::cout, addObjects) ? 0 : 1; + ret = binary.listArchitectures(ss, addObjects) ? 0 : 1; } + + Log::info() << ss.str(); + return ret; } // Set default name if no name was given diff --git a/src/pat2yara/pat2yara.cpp b/src/pat2yara/pat2yara.cpp index 3b792892b..7b0b89e6c 100644 --- a/src/pat2yara/pat2yara.cpp +++ b/src/pat2yara/pat2yara.cpp @@ -5,10 +5,10 @@ */ #include -#include #include #include "retdec/utils/filesystem.h" +#include "retdec/utils/io/log.h" #include "pat2yara/processing.h" #include "yaramod/builder/yara_file_builder.h" #include "yaramod/builder/yara_rule_builder.h" @@ -18,17 +18,17 @@ * Application for further processing of raw yara rules from bin2pat. */ +using namespace retdec::utils::io; using namespace yaramod; /** * Print application usage. * - * @param outputStream stream to write usage to + * @param log logger object to write usage with */ -void printUsage( - std::ostream &outputStream) +void printUsage(Logger& log) { - outputStream << + log << "Usage: pat2yara [-o OUTPUT_FILE] [--max-size VALUE] [--min-size VALUE]\n" " [--min-pure VALUE] [-o OUTPUT_FILE] INPUT_FILE [INPUT_FILE...]\n\n" "-o --output OUTPUT_FILE\n" @@ -60,7 +60,7 @@ void printUsage( int dieWithError( const std::string &message) { - std::cerr << "Error: " << message << "\n"; + Log::error() << Log::Error << message << "\n"; return 1; } @@ -72,7 +72,7 @@ int dieWithError( void printWarning( const std::string &message) { - std::cerr << "Warning: " << message << "\n"; + Log::error() << Log::Warning << message << "\n"; } /** @@ -113,7 +113,7 @@ int processArguments(std::vector &args) for (std::size_t i = 0; i < args.size(); ++i) { if (args[i] == "--help" || args[i] == "-h") { - printUsage(std::cout); + printUsage(Log::get(Log::Type::Info)); return 0; } else if (args[i] == "--delphi") { @@ -190,7 +190,7 @@ int processArguments(std::vector &args) } else { processFiles(fileBuilder, logBuilder, options); - std::cout << fileBuilder.get(false)->getText() << std::endl; + Log::info() << fileBuilder.get(false)->getText() << std::endl; } // Write log-file. diff --git a/src/pdbparser/pdb_types.cpp b/src/pdbparser/pdb_types.cpp index 54cec734c..bf10954f3 100644 --- a/src/pdbparser/pdb_types.cpp +++ b/src/pdbparser/pdb_types.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include "retdec/pdbparser/pdb_types.h" diff --git a/src/pelib/ResourceDirectory.cpp b/src/pelib/ResourceDirectory.cpp index 7e8d9b5e6..cec9d7a8c 100644 --- a/src/pelib/ResourceDirectory.cpp +++ b/src/pelib/ResourceDirectory.cpp @@ -355,7 +355,7 @@ namespace PeLib **/ void ResourceLeaf::rebuild(OutputBuffer& obBuffer, unsigned int uiOffset, unsigned int uiRva, const std::string&) const { -// std::cout << std::hex << pad << "Leaf: " << uiOffset << std::endl; +// Log::debug() << std::hex << pad << "Leaf: " << uiOffset << std::endl; // obBuffer << entry.OffsetToData; // obBuffer << uiOffset; @@ -374,7 +374,7 @@ namespace PeLib obBuffer.insert(entry.OffsetToData - uiRva + i, m_data[i]); } -// std::cout << "LeafChild: " << std::endl; +// Log::debug() << "LeafChild: " << std::endl; } /** @@ -537,20 +537,20 @@ namespace PeLib **/ void ResourceNode::rebuild(OutputBuffer& obBuffer, unsigned int uiOffset, unsigned int uiRva, const std::string& pad) const { -/* std::cout << std::hex << pad << uiOffset << std::endl; +/* Log::debug() << std::hex << pad << uiOffset << std::endl; - std::cout << std::hex << pad << "header.Characteristics: " << header.Characteristics << std::endl; - std::cout << std::hex << pad << "header.TimeDateStamp: " << header.TimeDateStamp << std::endl; - std::cout << std::hex << pad << "header.MajorVersion: " << header.MajorVersion << std::endl; - std::cout << std::hex << pad << "header.MinorVersion: " << header.MinorVersion << std::endl; - std::cout << std::hex << pad << "header.NumberOfNamedEntries: " << header.NumberOfNamedEntries << std::endl; - std::cout << std::hex << pad << "header.NumberOfIdEntries: " << header.NumberOfIdEntries << std::endl; + Log::debug() << std::hex << pad << "header.Characteristics: " << header.Characteristics << std::endl; + Log::debug() << std::hex << pad << "header.TimeDateStamp: " << header.TimeDateStamp << std::endl; + Log::debug() << std::hex << pad << "header.MajorVersion: " << header.MajorVersion << std::endl; + Log::debug() << std::hex << pad << "header.MinorVersion: " << header.MinorVersion << std::endl; + Log::debug() << std::hex << pad << "header.NumberOfNamedEntries: " << header.NumberOfNamedEntries << std::endl; + Log::debug() << std::hex << pad << "header.NumberOfIdEntries: " << header.NumberOfIdEntries << std::endl; */ obBuffer.insert(uiOffset, header.Characteristics); obBuffer.insert(uiOffset + 4, header.TimeDateStamp); obBuffer.insert(uiOffset + 8, header.MajorVersion); obBuffer.insert(uiOffset + 10, header.MinorVersion); - //std::cout << pad << "Children: " << children.size() << std::endl; + //Log::debug() << pad << "Children: " << children.size() << std::endl; obBuffer.insert(uiOffset + 12, header.NumberOfNamedEntries); obBuffer.insert(uiOffset + 14, header.NumberOfIdEntries); @@ -971,7 +971,7 @@ namespace PeLib { if (children.size()) { - std::cout << std::accumulate(children.begin(), children.end(), 0, accumulate) << std::endl; + Log::debug() << std::accumulate(children.begin(), children.end(), 0, accumulate) << std::endl; return PELIB_IMAGE_RESOURCE_DIRECTORY::size() + std::accumulate(children.begin(), children.end(), 0, accumulate); } @@ -1072,7 +1072,7 @@ namespace PeLib { OutputBuffer obBuffer(vBuffer); unsigned int offs = 0; -// std::cout << "Root: " << m_rnRoot.children.size() << std::endl; +// Log::debug() << "Root: " << m_rnRoot.children.size() << std::endl; m_rnRoot.rebuild(obBuffer, offs, uiRva, ""); } @@ -1434,10 +1434,10 @@ namespace PeLib unsigned int ResourceDirectory::getNumberOfResources(std::uint32_t dwId) const { // std::vector::const_iterator IterD = m_rnRoot.children.begin(); -// std::cout << dwId << std::endl; +// Log::debug() << dwId << std::endl; // while (IterD != m_rnRoot.children.end()) // { -// std::cout << IterD->entry.irde.Name << std::endl; +// Log::debug() << IterD->entry.irde.Name << std::endl; // ++IterD; // } diff --git a/src/retdec-decompiler/retdec-decompiler.cpp b/src/retdec-decompiler/retdec-decompiler.cpp index 64dd29de6..97336e978 100644 --- a/src/retdec-decompiler/retdec-decompiler.cpp +++ b/src/retdec-decompiler/retdec-decompiler.cpp @@ -4,7 +4,6 @@ * @copyright (c) 2020 Avast Software, licensed under the MIT license */ -#include #include #include #include @@ -40,7 +39,6 @@ #include "retdec/ar-extractor/archive_wrapper.h" #include "retdec/ar-extractor/detection.h" #include "retdec/config/config.h" -#include "retdec/llvm-support/diagnostics.h" #include "retdec/retdec/retdec.h" #include "retdec/macho-extractor/break_fat.h" #include "retdec/unpackertool/unpackertool.h" @@ -49,6 +47,10 @@ #include "retdec/utils/string.h" #include "retdec/utils/memory.h" +#include "retdec/utils/io/log.h" + +using namespace retdec::utils::io; + const int EXIT_TIMEOUT = 137; const int EXIT_BAD_ALLOC = 135; @@ -512,6 +514,10 @@ void ProgramOptions::loadOption(std::list::iterator& i) ); } } + else if (isParam(i, "-s", "--silent")) + { + params.setIsVerboseOutput(false); + } // Input file is the only argument that does not have -x or --xyz // before it. But only one input is expected. else if (params.getInputFile().empty()) @@ -605,11 +611,12 @@ std::string ProgramOptions::checkFile( void ProgramOptions::printHelpAndDie() { - std::cout << programName << R"(: + Log::info() << programName << R"(: Mandatory arguments: INPUT_FILE File to decompile. General arguments: [-o|--output FILE] Output file (default: INPUT_FILE.c if OUTPUT_FORMAT is plain, INPUT_FILE.c.json if OUTPUT_FORMAT is json|json-human). + [-s|--silent] Turns off informative output of the decompilation. [-f|--output-format OUTPUT_FORMAT] Output format [plain|json|json-human] (default: plain). [-m|--mode MODE] Force the type of decompilation mode [bin|raw] (default: bin). [-p|--pdb FILE] File with PDB debug information. @@ -750,8 +757,42 @@ void limitMaximalMemoryIfRequested(const retdec::config::Parameters& params) //============================================================================== // +/** + * TODO: this function is exact copy of the function located in retdec/retdec.cpp. + * The reason for this is that right now creation of correct interface that + * would hold this function is much more time expensive than hard copy. + * + * This function should be located in utils/io/log.{cpp,h}. For that it should + * now retdec::config::Parameters object. Inclusion of this object would be, + * however, only possible after linking rapidjson library to the retdec::utils. + * This is not wanted. Best solution would be making Parameters unaware of + * rapidjson. + */ +void setLogsFrom(const retdec::config::Parameters& params) +{ + auto logFile = params.getLogFile(); + auto errFile = params.getErrFile(); + auto verbose = params.isVerboseOutput(); + + Logger::Ptr outLog = nullptr; + + outLog.reset( + logFile.empty() + ? new Logger(std::cout, verbose) + : new FileLogger(logFile, verbose) + ); + + Log::set(Log::Type::Info, std::move(outLog)); + + if (!errFile.empty()) { + Log::set(Log::Type::Error, Logger::Ptr(new FileLogger(errFile))); + } +} + int decompile(retdec::config::Config& config, ProgramOptions& po) { + setLogsFrom(config.parameters); + // Macho-O extraction. // retdec::macho_extractor::BreakMachOUniversal fat( @@ -759,7 +800,7 @@ int decompile(retdec::config::Config& config, ProgramOptions& po) ); if (fat.isValid()) { - retdec::llvm_support::printPhase("Mach-O extraction"); + Log::phase("Mach-O extraction"); auto extractedFile = po.arExtractPath + "_m"; @@ -797,7 +838,7 @@ int decompile(retdec::config::Config& config, ProgramOptions& po) // if (po.arIdx || !po.arName.empty()) { - retdec::llvm_support::printPhase("Archive extraction"); + Log::phase("Archive extraction"); bool ok = true; std::string errMsg; @@ -855,39 +896,40 @@ int decompile(retdec::config::Config& config, ProgramOptions& po) ); if (ok && arw.isThinArchive()) { - std::cerr << "This file is an archive!" << std::endl; - std::cerr << "Error: File is a thin archive and cannot be decompiled." << std::endl; + Log::error() << "This file is an archive!" << std::endl; + Log::error() << "Error: File is a thin archive and cannot be decompiled." << std::endl; return EXIT_FAILURE; } else if (ok && arw.isEmptyArchive()) { - std::cerr << "This file is an archive!" << std::endl; - std::cerr << "Error: The input archive is empty." << std::endl; + Log::error() << "This file is an archive!" << std::endl; + Log::error() << "Error: The input archive is empty." << std::endl; return EXIT_FAILURE; } else if (ok) { - std::cerr << "This file is an archive!" << std::endl; + Log::error() << "This file is an archive!" << std::endl; std::string result; if (arw.getPlainTextList(result, errMsg, false, true)) { - std::cerr << result << std::endl; + Log::error() << result << std::endl; } return EXIT_FAILURE; } if (!ok && retdec::ar_extractor::isArchive(config.parameters.getInputFile())) { - std::cerr << "This file is an archive!" << std::endl; - std::cerr << "Error: The input archive has invalid format." << std::endl; + Log::error() << "This file is an archive!" << std::endl; + Log::error() << "Error: The input archive has invalid format." << std::endl; return EXIT_FAILURE; } } // Unpacking // - retdec::llvm_support::printPhase("Unpacking"); + + Log::phase("Unpacking"); std::vector unpackArgs; unpackArgs.push_back("whatever_program_name"); unpackArgs.push_back(config.parameters.getInputFile()); @@ -970,7 +1012,7 @@ int main(int argc, char **argv) } catch (const std::runtime_error& e) { - std::cerr << "Error: " << e.what() << std::endl; + Log::error() << Log::Error << e.what() << std::endl; return EXIT_FAILURE; } @@ -1001,7 +1043,7 @@ int main(int argc, char **argv) else { thr.detach(); // we leave the thread still running - std::cerr << "timeout after: " << config.parameters.getTimeout() + Log::error() << "timeout after: " << config.parameters.getTimeout() << " seconds" << std::endl; ret = EXIT_TIMEOUT; } @@ -1013,12 +1055,12 @@ int main(int argc, char **argv) } catch (const std::runtime_error& e) { - std::cerr << "Error: " << e.what() << std::endl; + Log::error() << Log::Error << e.what() << std::endl; ret = EXIT_FAILURE; } catch (const std::bad_alloc& e) { - std::cerr << "catched std::bad_alloc" << std::endl; + Log::error() << "catched std::bad_alloc" << std::endl; ret = EXIT_BAD_ALLOC; } diff --git a/src/retdec/retdec.cpp b/src/retdec/retdec.cpp index 8fb91962b..89b38f3f1 100644 --- a/src/retdec/retdec.cpp +++ b/src/retdec/retdec.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2019 Avast Software, licensed under the MIT license */ -#include - #include #include #include @@ -50,9 +48,11 @@ #include "retdec/llvmir2hll/llvmir2hll.h" #include "retdec/config/config.h" -#include "retdec/llvm-support/diagnostics.h" #include "retdec/retdec/retdec.h" #include "retdec/utils/memory.h" +#include "retdec/utils/io/log.h" + +using namespace retdec::utils::io; // extern llvm::cl::opt PrintAfterAll; @@ -376,7 +376,7 @@ class ModulePassPrinter : public ModulePass { if (utils::startsWith(PhaseArg, "retdec")) { - llvm_support::printPhase(PhaseName); + Log::phase(PhaseName); LastPhase = PhaseArg; } else @@ -384,12 +384,12 @@ class ModulePassPrinter : public ModulePass // aggregate LLVM if (LastPhase != LlvmAggregatePhaseName) { - llvm_support::printPhase(LlvmAggregatePhaseName); + Log::phase(LlvmAggregatePhaseName); LastPhase = LlvmAggregatePhaseName; } // print all - // llvm_support::printPhase(PhaseName); + // Log::phase(PhaseName); // LastPhase = PhaseArg; } return false; @@ -430,9 +430,41 @@ static inline void addPass( } + +/** + * TODO: this function has exact copy located in retdec-decompiler.cpp. + * The reason for this is that right now creation of correct interface that + * would hold this function is much more time expensive than hard copy. + * + * Before merging these two methods (providing them suitable interface) + * each change in one of them must be reflected to both. + */ +void setLogsFrom(const retdec::config::Parameters& params) +{ + auto logFile = params.getLogFile(); + auto errFile = params.getErrFile(); + auto verbose = params.isVerboseOutput(); + + Logger::Ptr outLog = nullptr; + + outLog.reset( + logFile.empty() + ? new Logger(std::cout, verbose) + : new FileLogger(logFile, verbose) + ); + + Log::set(Log::Type::Info, std::move(outLog)); + + if (!errFile.empty()) { + Log::set(Log::Type::Error, Logger::Ptr(new FileLogger(errFile))); + } +} + bool decompile(retdec::config::Config& config, std::string* outString) { - llvm_support::printPhase("Initialization"); + setLogsFrom(config.parameters); + + Log::phase("Initialization"); auto& passRegistry = initializeLlvmPasses(); // limitMaximalMemoryIfRequested(params); diff --git a/src/retdectool/retdec.cpp b/src/retdectool/retdec.cpp index 45ffe35bf..357efd5af 100644 --- a/src/retdectool/retdec.cpp +++ b/src/retdectool/retdec.cpp @@ -5,9 +5,11 @@ */ #include -#include #include "retdec/retdec/retdec.h" +#include "retdec/utils/io/log.h" + +using namespace retdec::utils::io; class ProgramOptions { @@ -53,14 +55,14 @@ class ProgramOptions void dump() { - std::cout << std::endl; - std::cout << "Program Options:" << std::endl; - std::cout << "\t" << "input file : " << inputFile << std::endl; + Log::info() << std::endl; + Log::info() << "Program Options:" << std::endl; + Log::info() << "\t" << "input file : " << inputFile << std::endl; } void printHelpAndDie() { - std::cout << _programName << ":\n" + Log::info() << _programName << ":\n" << "\t-i inputFile\n"; exit(EXIT_SUCCESS); @@ -83,52 +85,52 @@ int main(int argc, char **argv) for (auto& f : fs) { - std::cout << std::endl; - std::cout << f.getName() << " @ " << f << std::endl; + Log::info() << std::endl; + Log::info() << f.getName() << " @ " << f << std::endl; - std::cout << std::endl; - std::cout << "\t" << "code refs (insns referencing this function):" + Log::info() << std::endl; + Log::info() << "\t" << "code refs (insns referencing this function):" << std::endl; for (auto& r : f.codeReferences) { auto* f = fs.getRange(r); - std::cout << "\t\t" << r + Log::info() << "\t\t" << r << " ( @ " << (f ? f->getName() : "unknown") << " )" << std::endl; } for (auto& bb : f.basicBlocks) { - std::cout << std::endl; - std::cout << "\t" << "bb @ " << bb << std::endl; + Log::info() << std::endl; + Log::info() << "\t" << "bb @ " << bb << std::endl; - std::cout << "\t\t" << "preds:" << std::endl; + Log::info() << "\t\t" << "preds:" << std::endl; for (auto p : bb.preds) { - std::cout << "\t\t\t" << p << std::endl; + Log::info() << "\t\t\t" << p << std::endl; } - std::cout << "\t\t" << "succs:" << std::endl; + Log::info() << "\t\t" << "succs:" << std::endl; for (auto s : bb.succs) { - std::cout << "\t\t\t" << s << std::endl; + Log::info() << "\t\t\t" << s << std::endl; } - std::cout << "\t\t" << "calls:" << std::endl; + Log::info() << "\t\t" << "calls:" << std::endl; for (auto c : bb.calls) { auto* f = fs.getRange(c.targetAddr); - std::cout << "\t\t\t" << c.srcAddr << " -> " << c.targetAddr + Log::info() << "\t\t\t" << c.srcAddr << " -> " << c.targetAddr << " ( @ " << (f ? f->getName() : "unknown") << " )" << std::endl; } // These are not only text entries!!! // There is a full Capstone representation for every instruction. - std::cout << "\t\t" << "instructions:" << std::endl; + Log::info() << "\t\t" << "instructions:" << std::endl; for (auto* insn : bb.instructions) { - std::cout << "\t\t\t" << retdec::common::Address(insn->address) + Log::info() << "\t\t\t" << retdec::common::Address(insn->address) << " @ " << insn->mnemonic << " " << insn->op_str << std::endl; } diff --git a/src/stacofin/stacofin.cpp b/src/stacofin/stacofin.cpp index f8a189d61..39b3eedcd 100644 --- a/src/stacofin/stacofin.cpp +++ b/src/stacofin/stacofin.cpp @@ -4,7 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include #include #include diff --git a/src/stacofintool/stacofin.cpp b/src/stacofintool/stacofin.cpp index a127ac8c7..d962adfae 100644 --- a/src/stacofintool/stacofin.cpp +++ b/src/stacofintool/stacofin.cpp @@ -5,15 +5,16 @@ */ #include -#include #include #include #include "retdec/utils/filesystem.h" +#include "retdec/utils/io/log.h" #include "retdec/stacofin/stacofin.h" #include "retdec/loader/image_factory.h" using namespace retdec::utils; +using namespace retdec::utils::io; using namespace retdec::stacofin; using namespace retdec::loader; @@ -22,7 +23,7 @@ using namespace retdec::loader; */ void printUsage() { - std::cout << "\nStatic code detection tool.\n" + Log::info() << "\nStatic code detection tool.\n" << "Usage: stacofin -b BINARY_FILE YARA_FILE [YARA_FILE ...]\n\n"; } @@ -35,7 +36,7 @@ void printUsage() int printError( const std::string &errorMessage) { - std::cerr << "Error: " << errorMessage << "\n"; + Log::error() << Log::Error << errorMessage << "\n"; return 1; } @@ -69,16 +70,16 @@ void printDetectionsDebug( auto& detected = p.second; if (detected.getAddress() == lastAddress) { for (const auto &name : detected.names) { - std::cout << "or " << name << "\n"; + Log::info() << "or " << name << "\n"; } continue; } lastAddress = detected.getAddress(); - std::cout << "0x" << std::setfill('0') << std::setw(8) << std::hex + Log::info() << "0x" << std::setfill('0') << std::setw(8) << std::hex << detected.getAddress() << " " << detected.names[0] << "\n"; for (std::size_t i = 1; i < detected.names.size(); ++i) { - std::cout << "or " << detected.names[i] << "\n"; + Log::info() << "or " << detected.names[i] << "\n"; } } } @@ -96,18 +97,18 @@ void printDetections( auto& detected = p.second; if (detected.getAddress() == lastAddress) { for (const auto &name : detected.names) { - std::cout << "\t\t\t" << name << " " + Log::info() << "\t\t\t" << name << " " << referencesToString(detected.references) << "\n";; } continue; } lastAddress = detected.getAddress(); - std::cout << "0x" << std::hex << detected.getAddress() << " \t" + Log::info() << "0x" << std::hex << detected.getAddress() << " \t" << std::dec << detected.size << "\t" << detected.names[0] << " " << referencesToString(detected.references) << "\n"; for (std::size_t i = 1; i < detected.names.size(); ++i) { - std::cout << "\t\t\t" << detected.names[i] << " " + Log::info() << "\t\t\t" << detected.names[i] << " " << referencesToString(detected.references) << "\n";; } } @@ -173,7 +174,7 @@ int doActions( for (auto it = coverage.begin(), e = coverage.end(); it != e; ++it) { totalCoverage += it->getSize(); } - std::cout << "\nTotal code coverage is " << totalCoverage << " bytes.\n"; + Log::info() << "\nTotal code coverage is " << totalCoverage << " bytes.\n"; return 0; } diff --git a/src/unpackertool/plugin_mgr.cpp b/src/unpackertool/plugin_mgr.cpp index 347c79759..385fda469 100644 --- a/src/unpackertool/plugin_mgr.cpp +++ b/src/unpackertool/plugin_mgr.cpp @@ -4,7 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include #include #include "retdec/utils/string.h" diff --git a/src/unpackertool/unpacker.cpp b/src/unpackertool/unpacker.cpp index a75d8edc6..8ffafa490 100644 --- a/src/unpackertool/unpacker.cpp +++ b/src/unpackertool/unpacker.cpp @@ -5,11 +5,11 @@ */ #include -#include #include #include "retdec/utils/conversion.h" #include "retdec/utils/filesystem.h" +#include "retdec/utils/io/log.h" #include "retdec/utils/memory.h" #include "retdec/cpdetect/cpdetect.h" #include "retdec/fileformat/fileformat.h" @@ -19,6 +19,7 @@ #include "plugin_mgr.h" using namespace retdec::utils; +using namespace retdec::utils::io; using namespace retdec::unpacker; using namespace retdec::unpackertool; @@ -48,17 +49,17 @@ bool detectPackers(const std::string& inputFile, std::vectorused) { - std::cout << handler << std::endl; + Log::info() << handler << std::endl; } // -p|--plugins else if (handler["plugins"]->used) { - std::cout << "List of available plugins:" << std::endl; + Log::info() << "List of available plugins:" << std::endl; for (const auto& plugin : PluginMgr::plugins) { const Plugin::Info* info = plugin->getInfo(); - std::cout << info->name << " " << info->pluginVersion + Log::info() << info->name << " " << info->pluginVersion << " for packer '" << info->name << " " << info->packerVersion << "' (" << info->author << ")" << std::endl; } @@ -192,7 +193,7 @@ ExitCode processArgs(ArgHandler& handler, char argc, char** argv) } // Nothing else, just print the help else - std::cout << handler << std::endl; + Log::info() << handler << std::endl; return EXIT_CODE_OK; } diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index 36eed5f69..90ec2a70d 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -13,6 +13,8 @@ add_library(utils STATIC system.cpp time.cpp ${RETDEC_DEPS_DIR}/whereami/whereami/whereami.c + io/log.cpp + io/logger.cpp ) add_library(retdec::utils ALIAS utils) diff --git a/src/utils/io/log.cpp b/src/utils/io/log.cpp new file mode 100644 index 000000000..16b5d455c --- /dev/null +++ b/src/utils/io/log.cpp @@ -0,0 +1,76 @@ +/** +* @file src/utils/io/logger.cpp +* @brief Provides unified logging interface. +* @copyright (c) 2020 Avast Software, licensed under the MIT license +*/ + +#include + +#include "retdec/utils/io/log.h" + +namespace retdec { +namespace utils { +namespace io { + +// Initialization of shortcuts +const Log::Action Log::Error = Log::Action::Error; +const Log::Action Log::Warning = Log::Action::Warning; +const Log::Action Log::Phase = Log::Action::Phase; +const Log::Action Log::SubPhase = Log::Action::SubPhase; +const Log::Action Log::SubSubPhase = Log::Action::SubSubPhase; +const Log::Action Log::ElapsedTime = Log::Action::ElapsedTime; + +Logger::Ptr Log::writers[] = { + /*Info*/ /*default*/ nullptr, + /*Debug*/ /*default*/ nullptr, + /*Error*/ Logger::Ptr(new Logger(std::cerr)), + /*Undefined*/ Logger::Ptr(new Logger(std::cout, false)) +}; + +Logger Log::defaultLogger(std::cout, true); + +Logger& Log::get(const Log::Type& logType) +{ + // This can happen only after adding new Log::Type + // after Log::Type::Undefined in Log::Type enum. + assert(static_cast(logType) <= static_cast(Log::Type::Undefined)); + + if (auto logger = writers[static_cast(logType)].get()) + return *logger; + + // Fallback usage of logger. + return defaultLogger; +} + +void Log::set(const Log::Type& lt, Logger::Ptr&& logger) +{ + // This can happen only after adding new Log::Type + // after Log::Type::Undefined in Log::Type enum. + assert(static_cast(lt) <= static_cast(Log::Type::Undefined)); + + writers[static_cast(lt)] = std::move(logger); +} + +Logger Log::info() +{ + return get(Log::Type::Info); +} + +void Log::phase(const std::string& phase, const Log::Action& action) +{ + Log::info() << action << phase << Log::ElapsedTime << std::endl; +} + +Logger Log::debug() +{ + return Logger(get(Log::Type::Debug)); +} + +Logger Log::error() +{ + return Logger(get(Log::Type::Error)); +} + +} +} +} diff --git a/src/utils/io/logger.cpp b/src/utils/io/logger.cpp new file mode 100644 index 000000000..1131e76ce --- /dev/null +++ b/src/utils/io/logger.cpp @@ -0,0 +1,157 @@ +/** +* @file src/utils/io/logger.cpp +* @brief Implementation of a logging class. +* @copyright (c) 2020 Avast Software, licensed under the MIT license +*/ + +#include +#include +#include + +#include "retdec/utils/io/logger.h" +#include "retdec/utils/os.h" +#include "retdec/utils/time.h" + +#ifdef OS_WINDOWS +#include +#include +#else +#include +#endif + +namespace retdec { +namespace utils { +namespace io { + +////////// +// +// Logger +// +////// + +Logger::Logger(std::ostream& stream, bool verbose): + _out(stream), + _verbose(verbose) +{ +#ifdef OS_WINDOWS + // On windows we need to try to set ENABLE_VIRTUAL_TERMINAL_PROCESSING. + // This will enable ANSI support in terminal. This is best effort + // implementation approach. + // + // Source: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences + _terminalNotSupported = true; + HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); + if (hOut == INVALID_HANDLE_VALUE) + return; + + DWORD dwMode = 0; + if (!GetConsoleMode(hOut, &dwMode)) + return; + + _modifiedTerminalProperty = dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING; + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if (!SetConsoleMode(hOut, dwMode)) + return; + + _terminalNotSupported = false; +#endif +} + +Logger::Logger(const Logger& from): + Logger(from._out, from._verbose) +{ + _currentBrush = from._currentBrush; +} + +Logger::~Logger() +{ + if (_currentBrush != Color::Default) + *this << Color::Default; +} + +Logger& Logger::operator << (const Action& p) +{ + if (p == Phase) { + return *this << Color::Yellow << "Running phase: "; + } + if (p == SubPhase) { + return *this << Color::Yellow << " -> "; + } + if (p == SubSubPhase) { + return *this << Color::Yellow << " -> "; + } + if (p == SubSubPhase) { + return *this << Color::Yellow << " -> "; + } + if (p == Error) { + return *this << "Error: "; + } + if (p == Warning) { + return *this << Color::DarkCyan << "Warning: "; + } + if (p == ElapsedTime) { + std::stringstream formatted; + formatted << std::fixed << std::setprecision(2) << getElapsedTime(); + return *this << " ( " << formatted.str() << "s )"; + } + + return *this; +} + +Logger& Logger::operator << (const Color& lc) +{ + static std::string ansiMap[static_cast(Color::Default)+1] = { + /*Color::Red*/ "\u001b[0;1;31m", + /*Color::Green*/ "\u001b[0;1;32m", + /*Color::Blue*/ "\u001b[0;1;34m", + /*Color::Yellow*/ "\u001b[0;1;33m", + /*Color::DarkCyan*/"\u001b[0;1;36m", + /*Color::Default*/ "\u001b[0m" + }; + + if (_terminalNotSupported || isRedirected(_out)) + return *this; + + _currentBrush = lc; + return *this << ansiMap[static_cast(lc)]; +} + +bool Logger::isRedirected(const std::ostream& stream) const +{ +#ifdef OS_WINDOWS + // On windows POSIX functions isatty and fileno + // generate Warning. + auto isConsole = _isatty; + auto fileDescriptor = _fileno; +#else + auto isConsole = isatty; + auto fileDescriptor = fileno; +#endif + + if (stream.rdbuf() == std::cout.rdbuf()) { + return isConsole(fileDescriptor(stdout)) == 0; + } + else if (stream.rdbuf() == std::cerr.rdbuf()) { + return isConsole(fileDescriptor(stderr)) == 0; + } + + return true; +} + +////////// +// +// FileLogger +// +////// + +FileLogger::FileLogger(const std::string& file, bool verbose): + Logger(_file, verbose) +{ + _file.open(file, std::ofstream::out); + if (!_file) + throw std::runtime_error("unable to open file \""+file+"\" for writing."); +} + +} +} +} diff --git a/support/decompiler-config.json b/support/decompiler-config.json index 6f08f59c8..c5ec87077 100644 --- a/support/decompiler-config.json +++ b/support/decompiler-config.json @@ -1,6 +1,6 @@ { "decompParams": { - "verboseOut": false, + "verboseOut": true, "outputFormat": "plain", "keepAllFuncs": false, "selectedDecodeOnly": false, diff --git a/tests/llvmir2hll/pattern/pattern_finder_runners/cli_pattern_finder_runner_tests.cpp b/tests/llvmir2hll/pattern/pattern_finder_runners/cli_pattern_finder_runner_tests.cpp index 58a5f6184..73c100d5e 100644 --- a/tests/llvmir2hll/pattern/pattern_finder_runners/cli_pattern_finder_runner_tests.cpp +++ b/tests/llvmir2hll/pattern/pattern_finder_runners/cli_pattern_finder_runner_tests.cpp @@ -14,8 +14,10 @@ #include "retdec/llvmir2hll/pattern/pattern_finder_runners/cli_pattern_finder_runner.h" #include "llvmir2hll/pattern/pattern_finder_mock.h" #include "llvmir2hll/pattern/pattern_mock.h" +#include "retdec/utils/io/log.h" using namespace ::testing; +using namespace retdec::utils::io; namespace retdec { namespace llvmir2hll { @@ -37,8 +39,8 @@ RunWithOnePatternFinderCallsFindPatternAndPrintOnThatFinder) { NiceMock *pfMock(new NiceMock(va, cio)); ShPtr pf(pfMock); - std::string outputStr; - llvm::raw_string_ostream os(outputStr); + std::stringstream outputStr; + Logger os(outputStr); // Expectations. PatternFinder::Patterns patterns; @@ -54,9 +56,9 @@ RunWithOnePatternFinderCallsFindPatternAndPrintOnThatFinder) { // Test. pfr->run(pf, module); - ASSERT_FALSE(os.str().empty()); + ASSERT_FALSE(outputStr.str().empty()); // The ID of the pattern finder should be present in the output. - EXPECT_TRUE(os.str().find(PF_MOCK_ID) != std::string::npos); + EXPECT_TRUE(outputStr.str().find(PF_MOCK_ID) != std::string::npos); } TEST_F(CLIPatternFinderRunnerTests, @@ -64,8 +66,8 @@ RunWithTwoPatternFindersCallsFindPatternAndPrintOnTheseFinders) { INSTANTIATE_ALIAS_ANALYSIS_AND_VALUE_ANALYSIS(module); INSTANTIATE_CALL_INFO_OBTAINER_MOCK(); - std::string outputStr; - llvm::raw_string_ostream os(outputStr); + std::stringstream outputStr; + Logger os(outputStr); // Mocks. NiceMock *p1Mock(new NiceMock()); @@ -102,10 +104,10 @@ RunWithTwoPatternFindersCallsFindPatternAndPrintOnTheseFinders) { // Test. pfr->run(pfs, module); - ASSERT_FALSE(os.str().empty()); + ASSERT_FALSE(outputStr.str().empty()); // The IDs of the pattern finders should be present in the output. - EXPECT_TRUE(os.str().find(PF1_MOCK_ID) != std::string::npos); - EXPECT_TRUE(os.str().find(PF2_MOCK_ID) != std::string::npos); + EXPECT_TRUE(outputStr.str().find(PF1_MOCK_ID) != std::string::npos); + EXPECT_TRUE(outputStr.str().find(PF2_MOCK_ID) != std::string::npos); } } // namespace tests