From 1716451033063812056349156332128984540962 Mon Sep 17 00:00:00 2001 From: Glenn Smith Date: Tue, 7 Nov 2023 18:55:32 -0500 Subject: Add fmt library to api --- .gitmodules | 3 + CMakeLists.txt | 3 + architecture.cpp | 28 +--- binaryninjaapi.cpp | 154 ++++++++++++++++++++ binaryninjaapi.h | 363 +++++++++++++++++++++++++++++++++++++++++++++- binaryninjacore.h | 3 + docs/about/open-source.md | 3 + log.cpp | 98 +++++++++++++ metadata.cpp | 4 +- type.cpp | 5 +- ui/util.h | 12 +- vendor/fmt | 1 + 12 files changed, 645 insertions(+), 32 deletions(-) create mode 160000 vendor/fmt diff --git a/.gitmodules b/.gitmodules index f3489ad4..30817521 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "suite/binaries"] path = suite/binaries url = https://github.com/Vector35/BinaryTestCases.git +[submodule "vendor/fmt"] + path = vendor/fmt + url = https://github.com/fmtlib/fmt.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d918a23..7f4c62e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,9 @@ target_link_libraries(binaryninjaapi PUBLIC ${BinaryNinjaCore_LIBRARIES}) target_link_directories(binaryninjaapi PUBLIC ${BinaryNinjaCore_LIBRARY_DIRS}) target_compile_definitions(binaryninjaapi PUBLIC ${BinaryNinjaCore_DEFINITIONS}) +add_subdirectory(vendor/fmt) +target_link_libraries(binaryninjaapi PUBLIC fmt::fmt) + set_target_properties(binaryninjaapi PROPERTIES CXX_STANDARD 17 CXX_VISIBILITY_PRESET hidden diff --git a/architecture.cpp b/architecture.cpp index d0147dc0..0e09230a 100644 --- a/architecture.cpp +++ b/architecture.cpp @@ -899,25 +899,19 @@ bool Architecture::GetInstructionLowLevelIL(const uint8_t*, uint64_t, size_t&, L string Architecture::GetRegisterName(uint32_t reg) { - char regStr[32]; - snprintf(regStr, sizeof(regStr), "r%" PRIu32, reg); - return regStr; + return fmt::format("r{}", reg); } string Architecture::GetFlagName(uint32_t flag) { - char flagStr[32]; - snprintf(flagStr, sizeof(flagStr), "flag%" PRIu32, flag); - return flagStr; + return fmt::format("flag{}", flag); } string Architecture::GetFlagWriteTypeName(uint32_t flags) { - char flagStr[32]; - snprintf(flagStr, sizeof(flagStr), "update%" PRIu32, flags); - return flagStr; + return fmt::format("update{}", flags); } @@ -925,17 +919,13 @@ string Architecture::GetSemanticFlagClassName(uint32_t semClass) { if (semClass == 0) return ""; - char flagStr[32]; - snprintf(flagStr, sizeof(flagStr), "semantic%" PRIu32, semClass); - return flagStr; + return fmt::format("semantic{}", semClass); } string Architecture::GetSemanticFlagGroupName(uint32_t semGroup) { - char flagStr[32]; - snprintf(flagStr, sizeof(flagStr), "group%" PRIu32, semGroup); - return flagStr; + return fmt::format("group{}", semGroup); } @@ -1097,9 +1087,7 @@ bool Architecture::IsSystemRegister(uint32_t reg) string Architecture::GetRegisterStackName(uint32_t regStack) { - char regStr[32]; - snprintf(regStr, sizeof(regStr), "reg_stack_%" PRIu32, regStack); - return regStr; + return fmt::format("reg_stack_{}", regStack); } @@ -1129,9 +1117,7 @@ uint32_t Architecture::GetRegisterStackForRegister(uint32_t reg) string Architecture::GetIntrinsicName(uint32_t intrinsic) { - char intrinsicStr[32]; - snprintf(intrinsicStr, sizeof(intrinsicStr), "intrinsic_%" PRIu32, intrinsic); - return intrinsicStr; + return fmt::format("intrinsic_{}", intrinsic); } diff --git a/binaryninjaapi.cpp b/binaryninjaapi.cpp index a456f8c2..89827c73 100644 --- a/binaryninjaapi.cpp +++ b/binaryninjaapi.cpp @@ -431,3 +431,157 @@ bool BinaryNinja::ProgressCallback(void* ctxt, size_t current, size_t total) return true; return pctxt->callback(current, total); } + + +fmt::format_context::iterator fmtByteString(const std::vector& string, fmt::format_context& ctx) +{ + *ctx.out()++ = 'b'; + *ctx.out()++ = '\"'; + for (uint8_t ch: string) + { + if (ch == '\n') + { + *ctx.out()++ = '\\'; + *ctx.out()++ = 'n'; + } + else if (ch == '\r') + { + *ctx.out()++ = '\\'; + *ctx.out()++ = 'r'; + } + else if (ch == '\t') + { + *ctx.out()++ = '\\'; + *ctx.out()++ = 't'; + } + else if (ch == '\"') + { + *ctx.out()++ = '\\'; + *ctx.out()++ = '\"'; + } + else if (ch == '\\') + { + *ctx.out()++ = '\\'; + *ctx.out()++ = '\\'; + } + else if (ch < 0x20 || ch >= 0x7f) + { + fmt::format_to(ctx.out(), "\\x{:02x}", ch); + } + else + { + *ctx.out()++ = ch; + } + } + *ctx.out()++ = '\"'; + return ctx.out(); +} + + +fmt::format_context::iterator fmtQuotedString(const std::string& string, fmt::format_context& ctx) +{ + *ctx.out()++ = '\"'; + for (char ch: string) + { + if (ch == '\n') + { + *ctx.out()++ = '\\'; + *ctx.out()++ = 'n'; + } + else if (ch == '\r') + { + *ctx.out()++ = '\\'; + *ctx.out()++ = 'r'; + } + else if (ch == '\t') + { + *ctx.out()++ = '\\'; + *ctx.out()++ = 't'; + } + else if (ch == '\"') + { + *ctx.out()++ = '\\'; + *ctx.out()++ = '\"'; + } + else if (ch == '\\') + { + *ctx.out()++ = '\\'; + *ctx.out()++ = '\\'; + } + else if (ch < 0x20 || ch >= 0x7f) + { + fmt::format_to(ctx.out(), "\\x{:02x}", ch); + } + else + { + *ctx.out()++ = ch; + } + } + *ctx.out()++ = '\"'; + return ctx.out(); +} + + +fmt::format_context::iterator fmt::formatter::format(const BinaryNinja::Metadata& obj, format_context& ctx) const +{ + switch (obj.GetType()) + { + default: + case InvalidDataType: + return fmt::format_to(ctx.out(), "(invalid)"); + case BooleanDataType: + return fmt::format_to(ctx.out(), "{}", obj.GetBoolean()); + case StringDataType: + return fmt::format_to(ctx.out(), "{}", obj.GetString()); + case UnsignedIntegerDataType: + return fmt::format_to(ctx.out(), "{}", obj.GetUnsignedInteger()); + case SignedIntegerDataType: + return fmt::format_to(ctx.out(), "{}", obj.GetSignedInteger()); + case DoubleDataType: + return fmt::format_to(ctx.out(), "{}", obj.GetDouble()); + case RawDataType: + return fmtByteString(obj.GetRaw(), ctx); + case KeyValueDataType: + { + *ctx.out()++ = '{'; + bool first = true; + for (auto& [name, value]: obj.GetKeyValueStore()) + { + if (!first) + { + *ctx.out()++ = ','; + *ctx.out()++ = ' '; + } + first = false; + + fmtQuotedString(name, ctx); + *ctx.out()++ = ':'; + *ctx.out()++ = ' '; + fmt::format_to(ctx.out(), "{}", value); + } + *ctx.out()++ = '}'; + return ctx.out(); + } + case ArrayDataType: + *ctx.out()++ = '['; + bool first = true; + for (auto& value: obj.GetArray()) + { + if (!first) + { + *ctx.out()++ = ','; + *ctx.out()++ = ' '; + } + first = false; + fmt::format_to(ctx.out(), "{}", value); + } + *ctx.out()++ = ']'; + return ctx.out(); + } +} + + +fmt::format_context::iterator fmt::formatter::format(const BinaryNinja::NameList& obj, format_context& ctx) const +{ + return fmt::format_to(ctx.out(), "{}", obj.GetString()); +} diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 485a01d6..32db3582 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,9 @@ #include "binaryninjacore.h" #include "exceptions.h" #include "json/json.h" +#include +#include +#include #ifdef _MSC_VER #define NOEXCEPT @@ -638,7 +642,7 @@ namespace BinaryNinja { BN_PRINTF_ATTRIBUTE(1, 2) void LogWarn(const char* fmt, ...); - /*! LogError writes text to the error console and pops up the error console. Additionall, + /*! LogError writes text to the error console and pops up the error console. Additionally, Errors in the console log include a error icon. LogError corresponds to the log level: ErrorLog. @threadsafe @@ -664,6 +668,127 @@ namespace BinaryNinja { BN_PRINTF_ATTRIBUTE(1, 2) void LogAlert(const char* fmt, ...); + // Implementation detail + void LogFV(BNLogLevel level, fmt::string_view format, fmt::format_args args); + void LogTraceFV(fmt::string_view format, fmt::format_args args); + void LogDebugFV(fmt::string_view format, fmt::format_args args); + void LogInfoFV(fmt::string_view format, fmt::format_args args); + void LogWarnFV(fmt::string_view format, fmt::format_args args); + void LogErrorFV(fmt::string_view format, fmt::format_args args); + void LogAlertFV(fmt::string_view format, fmt::format_args args); + + /*! Logs to the error console with the given BNLogLevel. + + @threadsafe + + \ingroup logging + + \param level BNLogLevel debug log level + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template + void LogF(BNLogLevel level, fmt::format_string format, T&&... args) + { + LogFV(level, format, fmt::make_format_args(args...)); + } + + /*! LogTrace only writes text to the error console if the console is set to log level: DebugLog + Log level and the build is not a DEBUG build (i.e. the preprocessor directive _DEBUG is defined) + + @threadsafe + + \ingroup logging + + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template + void LogTraceF(fmt::format_string format, T&&... args) + { + LogTraceFV(format, fmt::make_format_args(args...)); + } + + /*! LogDebug only writes text to the error console if the console is set to log level: DebugLog + Log level DebugLog is the most verbose logging level in release builds. + + @threadsafe + + \ingroup logging + + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template + void LogDebugF(fmt::format_string format, T&&... args) + { + LogDebugFV(format, fmt::make_format_args(args...)); + } + + /*! LogInfo always writes text to the error console, and corresponds to the log level: InfoLog. + Log level InfoLog is the second most verbose logging level. + + @threadsafe + + \ingroup logging + + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template + void LogInfoF(fmt::format_string format, T&&... args) + { + LogInfoFV(format, fmt::make_format_args(args...)); + } + + /*! LogWarn writes text to the error console including a warning icon, + and also shows a warning icon in the bottom pane. LogWarn corresponds to the log level: WarningLog. + + @threadsafe + + \ingroup logging + + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template + void LogWarnF(fmt::format_string format, T&&... args) + { + LogWarnFV(format, fmt::make_format_args(args...)); + } + + /*! LogError writes text to the error console and pops up the error console. Additionally, + Errors in the console log include a error icon. LogError corresponds to the log level: ErrorLog. + + @threadsafe + + \ingroup logging + + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template + void LogErrorF(fmt::format_string format, T&&... args) + { + LogErrorFV(format, fmt::make_format_args(args...)); + } + + /*! LogAlert pops up a message box displaying the alert message and logs to the error console. + LogAlert corresponds to the log level: AlertLog. + + @threadsafe + + \ingroup logging + + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template + void LogAlertF(fmt::format_string format, T&&... args) + { + LogAlertFV(format, fmt::make_format_args(args...)); + } + /*! Redirects the minimum level passed to standard out @threadsafe @@ -711,6 +836,17 @@ namespace BinaryNinja { class Logger: public CoreRefCountObject { size_t GetThreadId() const; + std::unordered_map m_iterBuffer; + friend struct Iterator; + + void LogFV(BNLogLevel level, fmt::string_view format, fmt::format_args args); + void LogTraceFV(fmt::string_view format, fmt::format_args args); + void LogDebugFV(fmt::string_view format, fmt::format_args args); + void LogInfoFV(fmt::string_view format, fmt::format_args args); + void LogWarnFV(fmt::string_view format, fmt::format_args args); + void LogErrorFV(fmt::string_view format, fmt::format_args args); + void LogAlertFV(fmt::string_view format, fmt::format_args args); + public: Logger(BNLogger* logger); @@ -804,6 +940,104 @@ namespace BinaryNinja { */ void LogAlert(const char* fmt, ...); + /*! Logs to the error console with the given BNLogLevel. + + @threadsafe + + \param level BNLogLevel debug log level + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template + void LogF(BNLogLevel level, fmt::format_string format, T&&... args) + { + LogFV(level, format, fmt::make_format_args(args...)); + } + + /*! LogTrace only writes text to the error console if the console is set to log level: DebugLog + Log level and the build is not a DEBUG build (i.e. the preprocessor directive _DEBUG is defined) + + @threadsafe + + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template + void LogTraceF(fmt::format_string format, T&&... args) + { + LogTraceFV(format, fmt::make_format_args(args...)); + } + + /*! LogDebug only writes text to the error console if the console is set to log level: DebugLog + Log level DebugLog is the most verbose logging level in release builds. + + @threadsafe + + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template + void LogDebugF(fmt::format_string format, T&&... args) + { + LogDebugFV(format, fmt::make_format_args(args...)); + } + + /*! LogInfo always writes text to the error console, and corresponds to the log level: InfoLog. + Log level InfoLog is the second most verbose logging level. + + @threadsafe + + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template + void LogInfoF(fmt::format_string format, T&&... args) + { + LogInfoFV(format, fmt::make_format_args(args...)); + } + + /*! LogWarn writes text to the error console including a warning icon, + and also shows a warning icon in the bottom pane. LogWarn corresponds to the log level: WarningLog. + + @threadsafe + + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template + void LogWarnF(fmt::format_string format, T&&... args) + { + LogWarnFV(format, fmt::make_format_args(args...)); + } + + /*! LogError writes text to the error console and pops up the error console. Additionally, + Errors in the console log include a error icon. LogError corresponds to the log level: ErrorLog. + + @threadsafe + + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template + void LogErrorF(fmt::format_string format, T&&... args) + { + LogErrorFV(format, fmt::make_format_args(args...)); + } + + /*! LogAlert pops up a message box displaying the alert message and logs to the error console. + LogAlert corresponds to the log level: AlertLog. + + @threadsafe + + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template + void LogAlertF(fmt::format_string format, T&&... args) + { + LogAlertFV(format, fmt::make_format_args(args...)); + } + /*! Get the name registered for this Logger @threadsafe @@ -938,6 +1172,47 @@ namespace BinaryNinja { void SetCurrentPluginLoadOrder(BNPluginLoadOrder order); void AddRequiredPluginDependency(const std::string& name); void AddOptionalPluginDependency(const std::string& name); + + template + std::string CoreEnumName() + { + // Extremely implementation-defined. Best-effort is made for our relevant platforms +#ifdef WIN32 + // "enum TestEnum" + return std::string(typeid(T).name()).substr(5); +#else + // "19BNWhateverItsCalled" + auto name = std::string(typeid(T).name()); + while (std::isdigit(name[0])) + { + name.erase(0, 1); + } + return name; +#endif + } + + template + std::optional CoreEnumToString(T value) + { + auto name = CoreEnumName(); + char* result; + if (!BNCoreEnumToString(name.c_str(), (size_t)value, &result)) + return std::nullopt; + auto cppResult = std::string(result); + BNFreeString(result); + return cppResult; + } + + template + std::optional CoreEnumFromString(const std::string& value) + { + auto name = CoreEnumName(); + size_t result; + if (!BNCoreEnumFromString(name.c_str(), value.c_str(), &result)) + return std::nullopt; + return result; + } + /*! @} */ @@ -1087,8 +1362,8 @@ namespace BinaryNinja { std::vector GetSignedIntegerList() const; std::vector GetDoubleList() const; std::vector GetRaw() const; - std::vector> GetArray(); - std::map> GetKeyValueStore(); + std::vector> GetArray() const; + std::map> GetKeyValueStore() const; // For key-value data only /*! Get a Metadata object by key. Only for if IsKeyValueStore == true @@ -2897,7 +3172,7 @@ namespace BinaryNinja { public: NameList(const BNQualifiedName* name); - NameList(const std::string& join, size_t size = 0); + explicit NameList(const std::string& join, size_t size = 0); NameList(const std::string& name, const std::string& join); NameList(const std::vector& name, const std::string& join); NameList(const NameList& name, const std::string& join); @@ -16034,3 +16309,83 @@ namespace std } }; } // namespace std + + +template struct fmt::formatter> +{ + format_context::iterator format(const BinaryNinja::Ref& obj, format_context& ctx) const + { + return fmt::formatter().format(*obj.GetPtr(), ctx); + } + constexpr auto parse(format_parse_context& ctx) -> format_parse_context::iterator { return ctx.begin(); } +}; + +template struct fmt::formatter> +{ + format_context::iterator format(const BinaryNinja::Confidence& obj, format_context& ctx) const + { + fmt::formatter().format(obj.GetValue(), ctx); + return fmt::format_to(ctx.out(), " ({} confidence)", ctx); + } + constexpr auto parse(format_parse_context& ctx) -> format_parse_context::iterator { return ctx.begin(); } +}; + +template struct fmt::formatter>> +{ + format_context::iterator format(const BinaryNinja::Confidence>& obj, format_context& ctx) const + { + fmt::formatter().format(*obj.GetValue().GetPtr(), ctx); + return fmt::format_to(ctx.out(), " ({} confidence)", ctx); + } + constexpr auto parse(format_parse_context& ctx) -> format_parse_context::iterator { return ctx.begin(); } +}; + +template<> struct fmt::formatter +{ + format_context::iterator format(const BinaryNinja::Metadata& obj, format_context& ctx) const; + constexpr auto parse(format_parse_context& ctx) -> format_parse_context::iterator { return ctx.begin(); } +}; + +template<> struct fmt::formatter +{ + format_context::iterator format(const BinaryNinja::NameList& obj, format_context& ctx) const; + constexpr auto parse(format_parse_context& ctx) -> format_parse_context::iterator { return ctx.begin(); } +}; + +template +struct fmt::formatter, void>> +{ + // s -> name, S -> scoped::name, d -> int, x -> hex + char presentation = 's'; + format_context::iterator format(const T& obj, format_context& ctx) const + { + auto stringed = BinaryNinja::CoreEnumToString(obj); + if (stringed.has_value()) + { + switch (presentation) + { + default: + case 's': + return fmt::format_to(ctx.out(), "{}", *stringed); + case 'S': + return fmt::format_to(ctx.out(), "{}::{}", BinaryNinja::CoreEnumName(), *stringed); + case 'd': + return fmt::format_to(ctx.out(), "{}", (size_t)obj); + case 'x': + return fmt::format_to(ctx.out(), "{:#x}", (size_t)obj); + } + } + else + { + return fmt::format_to(ctx.out(), "{}", (size_t)obj); + } + } + + constexpr auto parse(format_parse_context& ctx) -> format_parse_context::iterator + { + auto it = ctx.begin(), end = ctx.end(); + if (it != end && (*it == 's' || *it == 'S' || *it == 'd' || *it == 'x')) presentation = *it++; + if (it != end && *it != '}') detail::throw_format_error("invalid format"); + return it; + } +}; diff --git a/binaryninjacore.h b/binaryninjacore.h index 30e34b81..57ee5eb6 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -6634,6 +6634,9 @@ extern "C" void (*add)(void* ctxt, BNSymbol* symbol, BNType* type), void* addContext); BINARYNINJACOREAPI void BNProcessSymbolQueue(BNSymbolQueue* queue); + BINARYNINJACOREAPI bool BNCoreEnumToString(const char* enumName, size_t value, char** result); + BINARYNINJACOREAPI bool BNCoreEnumFromString(const char* enumName, const char* value, size_t* result); + #ifdef __cplusplus } #endif diff --git a/docs/about/open-source.md b/docs/about/open-source.md index 9f9f70e3..65780aec 100644 --- a/docs/about/open-source.md +++ b/docs/about/open-source.md @@ -37,6 +37,7 @@ The previous tools are used in the generation of our documentation, but are not - [curl] ([curl license] - MIT) - [xxHash] ([xxHash License] - 2-clause BSD) - [botan] ([botan license] - 2-clause BSD) + - [fmt] ([fmt license] - MIT) * Core (Rust) - [Rust] ([Rust license] - Apache 2.0 / MIT) @@ -423,6 +424,8 @@ Please note that we offer no support for running Binary Ninja with modified Qt l [fallible-iterator license]: https://github.com/sfackler/rust-fallible-iterator/blob/master/LICENSE-MIT [flate2]: https://github.com/rust-lang/flate2-rs [flate2 license]: https://github.com/rust-lang/flate2-rs/blob/main/LICENSE-MIT +[fmt]: https://github.com/fmtlib/fmt +[fmt license]: https://github.com/fmtlib/fmt/blob/master/LICENSE [fnv]: https://github.com/servo/rust-fnv [fnv license]: https://github.com/servo/rust-fnv/blob/master/LICENSE-MIT [form_urlencoded]: https://github.com/servo/rust-url diff --git a/log.cpp b/log.cpp index f8318cc3..e35b3663 100644 --- a/log.cpp +++ b/log.cpp @@ -162,6 +162,55 @@ void BinaryNinja::LogAlert(const char* fmt, ...) } +void BinaryNinja::LogFV(BNLogLevel level, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + Log(level, "%s", value.c_str()); +} + + +void BinaryNinja::LogTraceFV(fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogTrace("%s", value.c_str()); +} + + +void BinaryNinja::LogDebugFV(fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogDebug("%s", value.c_str()); +} + + +void BinaryNinja::LogInfoFV(fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogInfo("%s", value.c_str()); +} + + +void BinaryNinja::LogWarnFV(fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogWarn("%s", value.c_str()); +} + + +void BinaryNinja::LogErrorFV(fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogError("%s", value.c_str()); +} + + +void BinaryNinja::LogAlertFV(fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogAlert("%s", value.c_str()); +} + + void BinaryNinja::LogToStdout(BNLogLevel minimumLevel) { BNLogToStdout(minimumLevel); @@ -267,6 +316,55 @@ void Logger::LogAlert(const char* fmt, ...) } +void Logger::LogFV(BNLogLevel level, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + Log(level, "%s", value.c_str()); +} + + +void Logger::LogTraceFV(fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogTrace("%s", value.c_str()); +} + + +void Logger::LogDebugFV(fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogDebug("%s", value.c_str()); +} + + +void Logger::LogInfoFV(fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogInfo("%s", value.c_str()); +} + + +void Logger::LogWarnFV(fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogWarn("%s", value.c_str()); +} + + +void Logger::LogErrorFV(fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogError("%s", value.c_str()); +} + + +void Logger::LogAlertFV(fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogAlert("%s", value.c_str()); +} + + string Logger::GetName() { char* name = BNLoggerGetName(m_object); diff --git a/metadata.cpp b/metadata.cpp index 253d03de..c1ba34a3 100644 --- a/metadata.cpp +++ b/metadata.cpp @@ -299,7 +299,7 @@ vector Metadata::GetRaw() const return result; } -vector> Metadata::GetArray() +vector> Metadata::GetArray() const { size_t size = 0; BNMetadata** data = BNMetadataGetArray(m_object, &size); @@ -311,7 +311,7 @@ vector> Metadata::GetArray() return result; } -map> Metadata::GetKeyValueStore() +map> Metadata::GetKeyValueStore() const { BNMetadataValueStore* data = BNMetadataGetValueStore(m_object); map> result; diff --git a/type.cpp b/type.cpp index 383ef3e8..0e686a0a 100644 --- a/type.cpp +++ b/type.cpp @@ -1233,8 +1233,6 @@ std::vector Type::GetLines(const TypeContainer& types, const string Type::GetSizeSuffix(size_t size) { - char sizeStr[32]; - switch (size) { case 0: @@ -1252,8 +1250,7 @@ string Type::GetSizeSuffix(size_t size) case 16: return ".o"; default: - snprintf(sizeStr, sizeof(sizeStr), ".%" PRIuPTR, size); - return sizeStr; + return fmt::format(".{}", size); } } diff --git a/ui/util.h b/ui/util.h index c3e5ece5..e6b6fdb2 100644 --- a/ui/util.h +++ b/ui/util.h @@ -18,7 +18,7 @@ std::string BINARYNINJAUIAPI getStringForLocalVariable(ArchitectureRef arch, Fun std::string BINARYNINJAUIAPI getStringForRegisterValue(ArchitectureRef arch, BinaryNinja::RegisterValue value); std::string BINARYNINJAUIAPI getPossibleValueSetStateName(BNRegisterValueType state); std::string BINARYNINJAUIAPI getStringForIntegerValue(int64_t value); -std::string BINARYNINJAUIAPI getStringForIntegerValue(uint64_t value); +std::string BINARYNINJAUIAPI getStringForUIntegerValue(uint64_t value); std::string BINARYNINJAUIAPI getStringForPossibleValueSet(ArchitectureRef arch, const BinaryNinja::PossibleValueSet& values); std::string BINARYNINJAUIAPI getStringForInstructionDataflowDetails(BinaryViewRef data, ArchitectureRef arch, FunctionRef func, uint64_t address); std::optional BINARYNINJAUIAPI getPossibleValueSetForToken(View* view, BinaryViewRef data, ArchitectureRef arch, @@ -34,6 +34,16 @@ bool BINARYNINJAUIAPI isBinaryNinjaDataBase(QFileInfo& info, QFileAccessor& acce PlatformRef BINARYNINJAUIAPI getOrAskForPlatform(QWidget* parent, BinaryViewRef data); PlatformRef BINARYNINJAUIAPI getOrAskForPlatform(QWidget* parent, PlatformRef defaultValue); + +namespace fmt +{ + template + QString qformat(format_string fmt, T&&... args) + { + return QString::fromStdString(vformat(fmt, make_format_args(args...))); + } +} + /*! @} */ diff --git a/vendor/fmt b/vendor/fmt new file mode 160000 index 00000000..f5e54359 --- /dev/null +++ b/vendor/fmt @@ -0,0 +1 @@ +Subproject commit f5e54359df4c26b6230fc61d38aa294581393084 -- cgit v1.3.1