diff --git a/CMakeLists.txt b/CMakeLists.txt index 08c776f..06b3a17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,9 @@ cmake_minimum_required(VERSION 3.16) project(fxos LANGUAGES C CXX) find_package(FLEX 2.6) -add_compile_options(-Wall -Wextra -D_GNU_SOURCE -std=c++17 -O0 -g) +add_compile_options( + -Wall -Wextra -D_GNU_SOURCE -std=c++17 -O0 -g + -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/=) #--- # fxos core @@ -15,7 +17,6 @@ set(fxos_core_SOURCES lib/disassembly.cpp lib/domains/relconst.cpp lib/lang.cpp - lib/log.cpp lib/memory.cpp lib/os.cpp lib/passes/cfg.cpp @@ -27,6 +28,7 @@ set(fxos_core_SOURCES lib/vspace.cpp lib/util/Buffer.cpp + lib/util/log.cpp lib/util/Timer.cpp) add_library(fxos-core ${fxos_core_SOURCES} ${FLEX_LoadAsm_OUTPUTS}) diff --git a/include/fxos/log.h b/include/fxos/log.h deleted file mode 100644 index 6866dce..0000000 --- a/include/fxos/log.h +++ /dev/null @@ -1,41 +0,0 @@ -//--- -// fxos.log: Logging functions -//--- - -#ifndef FXOS_LOG_H -#define FXOS_LOG_H - -#include - -namespace FxOS::Log { - -/* Message levels, used for masking and statistics */ -#define LEVEL_LOG 0 -#define LEVEL_WRN 1 -#define LEVEL_ERR 4 - -/* Prefixes to set in the call to log() for brevity. The comma is included. - Typical usage would be log(ERR "logic is inconsistent"). */ -#define LOG LEVEL_LOG, -#define WRN LEVEL_WRN, -#define ERR LEVEL_ERR, - -/* Select the log level */ -void log_setminlevel(int level); - -/* Get the minimum log level */ -int log_getminlevel(); - -/* General message logger */ -void logmsg(int level, char const *function, std::string message); - -/* Automatically apply format strings. Also force the first argument to be - expanded first, since this causes a comma to appear. */ -#define log(level, ...) \ - loghelper(level, __VA_ARGS__) -#define loghelper(level, fmtstr, ...) \ - FxOS::Log::logmsg(level, __func__, format(fmtstr __VA_OPT__(,)__VA_ARGS__)) - -} /* namespace FxOS::Log */ - -#endif /* FXOS_LOG_H */ diff --git a/include/fxos/util/log.h b/include/fxos/util/log.h new file mode 100644 index 0000000..9c619de --- /dev/null +++ b/include/fxos/util/log.h @@ -0,0 +1,50 @@ +//---------------------------------------------------------------------------// +// 1100101 |_ mov #0, r4 __ // +// 11 |_ <0xb380 %5c4> / _|_ _____ ___ // +// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< // +// |_ base# + offset |_| /_\_\___/__/ // +//---------------------------------------------------------------------------// +// fxos/util/log: Basic logging utilities +// +// This header exposes a single macro +// FxOS_log(LEVEL, FORMAT, ...) +// where LEVEL should be "LOG", "WRN" or "ERR", FORMAT is a printf()-style +// format and variable arguments are provided as needed. +// +// The log level can be set with log_getminlevel() and log_setminlevel(). The +// point of this header is to report runtime warnings and errors caused by +// invalid input or flawed internal logic, and print performance metrics in +// debug mode. +// +// The log level can also be set with the FXOS_LOG environment variable. +//--- + +#ifndef FXOS_UTIL_LOG_H +#define FXOS_UTIL_LOG_H + +#include + +namespace FxOS { + +/* Message levels, for masking */ +constexpr int LOG_LEVEL_LOG = 0; +constexpr int LOG_LEVEL_WRN = 1; +constexpr int LOG_LEVEL_ERR = 2; + +/* Select the log level */ +void log_setminlevel(int level); + +/* Get the minimum log level */ +int log_getminlevel(); + +/* General message logger */ +void logmsg(int level, char const *file, int line, char const *func, + std::string message); + +} /* namespace FxOS */ + +#define FxOS_log(level, fmt, ...) \ + FxOS::logmsg(LOG_LEVEL_ ## level, __FILE__, __LINE__, __func__, \ + format(fmt, ##__VA_ARGS__)) + +#endif /* FXOS_UTIL_LOG_H */ diff --git a/lib/log.cpp b/lib/log.cpp deleted file mode 100644 index 02bf9e1..0000000 --- a/lib/log.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include -#include - -namespace FxOS::Log { - -/* Currently configured log level */ -static int loglevel = LEVEL_WRN; -/* Level of the last message */ -static int lastlevel = -1; - -/* Prefixes for each level */ -static std::map prefixes = { - { LEVEL_WRN, "warning: " }, - { LEVEL_ERR, "error: " }, -}; - -/* Select the log level */ -void log_setminlevel(int level) -{ - loglevel = level; -} - -/* Get the minimum log level */ -int log_getminlevel() -{ - return loglevel; -} - -/* General message logger */ -void logmsg(int level, char const *function, std::string message) -{ - if(level < loglevel) return; - - bool endline = true; - bool prefix = true; - - /* Add a newline if last line was unfinished, but level changed */ - if(lastlevel >= 0 && lastlevel != level) std::cerr << '\n'; - else if(lastlevel >= 0) prefix = false; - - if(message.size() && message.back() == '\\') - { - endline = false; - message.pop_back(); - } - - if(prefix) - { - if(level == LEVEL_LOG) std::cerr << "[" << function << "] "; - std::cerr << prefixes[level]; - } - else std::cerr << " "; - - std::cerr << message; - - lastlevel = -1; - if(endline) std::cerr << '\n'; - else lastlevel = level; -} - -} /* namespace FxOS::Log */ diff --git a/lib/passes/cfg.cpp b/lib/passes/cfg.cpp index 458c20f..18eabac 100644 --- a/lib/passes/cfg.cpp +++ b/lib/passes/cfg.cpp @@ -5,11 +5,8 @@ #include #include #include -#include #include -using namespace FxOS::Log; - namespace FxOS { CfgPass::CfgPass(Disassembly &disasm): diff --git a/lib/util/log.cpp b/lib/util/log.cpp new file mode 100644 index 0000000..4d0be64 --- /dev/null +++ b/lib/util/log.cpp @@ -0,0 +1,85 @@ +//---------------------------------------------------------------------------// +// 1100101 |_ mov #0, r4 __ // +// 11 |_ <0xb380 %5c4> / _|_ _____ ___ // +// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< // +// |_ base# + offset |_| /_\_\___/__/ // +//---------------------------------------------------------------------------// + +#include +#include +#include +#include + +namespace FxOS { + +/* Currently configured log level */ +static int loglevel = LOG_LEVEL_WRN; +/* Level of the last message */ +static int lastlevel = -1; + +/* Initialize log level depending on environment variable at startup */ +__attribute__((constructor)) +static void init_log_level(void) +{ + char const *FXOS_LOG = std::getenv("FXOS_LOG"); + if(!FXOS_LOG) + return; + + if(!strcmp(FXOS_LOG, "LOG")) + loglevel = LOG_LEVEL_LOG; + else if(!strcmp(FXOS_LOG, "WRN")) + loglevel = LOG_LEVEL_WRN; + else if(!strcmp(FXOS_LOG, "ERR")) + loglevel = LOG_LEVEL_ERR; + else FxOS_log(WRN, "invalid FXOS_LOG value: %s", FXOS_LOG); +} + +void log_setminlevel(int level) +{ + loglevel = level; +} + +int log_getminlevel() +{ + return loglevel; +} + +void logmsg(int level, char const *file, int line, char const *func, + std::string message) +{ + if(level < loglevel) return; + + bool endline = true; + bool prefix = true; + + /* Add a newline if last line was unfinished, but level changed */ + if(lastlevel >= 0 && lastlevel != level) std::cerr << '\n'; + else if(lastlevel >= 0) prefix = false; + + if(message.size() > 0 && message.back() == '\\') { + endline = false; + message.pop_back(); + } + + if(prefix) { + if(level == LOG_LEVEL_LOG) + std::cerr << "[" << file << ":" << line << "@" << func << "] "; + if(level == LOG_LEVEL_WRN) + std::cerr << "warning: "; + if(level == LOG_LEVEL_ERR) + std::cerr << "err: "; + } + else std::cerr << " "; + + std::cerr << message; + + if(endline) { + std::cerr << '\n'; + lastlevel = -1; + } + else { + lastlevel = level; + } +} + +} /* namespace FxOS */ diff --git a/shell/d.cpp b/shell/d.cpp index 83da042..5b72595 100644 --- a/shell/d.cpp +++ b/shell/d.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include @@ -20,7 +20,6 @@ static void disassemble(Session &session, Disassembly &disasm, { Timer timer; timer.start(); - log(LOG "Running pass %s...\\", pass); if(pass == "cfg") { @@ -55,7 +54,7 @@ static void disassemble(Session &session, Disassembly &disasm, p.run(); } timer.stop(); - log(LOG "%s", timer.format_time()); + FxOS_log(LOG, "Finished pass <%s> in %s", pass, timer.format_time()); } }