summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Smith <glenn@vector35.com>2023-11-07 18:55:32 -0500
committerGlenn Smith <glenn@vector35.com>2023-11-13 17:22:16 -0500
commit1716451033063812056349156332128984540962 (patch)
tree7a12ab7cdb9c15ffadfaa42651e7fe044ff7befa
parent0cc0b1ce9f7e1bcf4b8fac581ab4e5a354906ba4 (diff)
Add fmt library to api
-rw-r--r--.gitmodules3
-rw-r--r--CMakeLists.txt3
-rw-r--r--architecture.cpp28
-rw-r--r--binaryninjaapi.cpp154
-rw-r--r--binaryninjaapi.h363
-rw-r--r--binaryninjacore.h3
-rw-r--r--docs/about/open-source.md3
-rw-r--r--log.cpp98
-rw-r--r--metadata.cpp4
-rw-r--r--type.cpp5
-rw-r--r--ui/util.h12
m---------vendor/fmt0
12 files changed, 644 insertions, 32 deletions
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<uint8_t>& 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<BinaryNinja::Metadata>::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<BinaryNinja::NameList>::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 <atomic>
#include <memory>
#include <cstdint>
+#include <typeinfo>
#include <type_traits>
#include <variant>
#include <optional>
@@ -45,6 +46,9 @@
#include "binaryninjacore.h"
#include "exceptions.h"
#include "json/json.h"
+#include <fmt/format.h>
+#include <fmt/ranges.h>
+#include <fmt/core.h>
#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<typename... T>
+ void LogF(BNLogLevel level, fmt::format_string<T...> 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<typename... T>
+ void LogTraceF(fmt::format_string<T...> 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<typename... T>
+ void LogDebugF(fmt::format_string<T...> 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<typename... T>
+ void LogInfoF(fmt::format_string<T...> 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<typename... T>
+ void LogWarnF(fmt::format_string<T...> 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<typename... T>
+ void LogErrorF(fmt::format_string<T...> 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<typename... T>
+ void LogAlertF(fmt::format_string<T...> 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<BNLogger, BNNewLoggerReference, BNFreeLogger>
{
size_t GetThreadId() const;
+ std::unordered_map<BNLogLevel, std::string> 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<typename... T>
+ void LogF(BNLogLevel level, fmt::format_string<T...> 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<typename... T>
+ void LogTraceF(fmt::format_string<T...> 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<typename... T>
+ void LogDebugF(fmt::format_string<T...> 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<typename... T>
+ void LogInfoF(fmt::format_string<T...> 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<typename... T>
+ void LogWarnF(fmt::format_string<T...> 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<typename... T>
+ void LogErrorF(fmt::format_string<T...> 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<typename... T>
+ void LogAlertF(fmt::format_string<T...> 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<typename T>
+ 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<typename T>
+ std::optional<std::string> CoreEnumToString(T value)
+ {
+ auto name = CoreEnumName<T>();
+ char* result;
+ if (!BNCoreEnumToString(name.c_str(), (size_t)value, &result))
+ return std::nullopt;
+ auto cppResult = std::string(result);
+ BNFreeString(result);
+ return cppResult;
+ }
+
+ template<typename T>
+ std::optional<T> CoreEnumFromString(const std::string& value)
+ {
+ auto name = CoreEnumName<T>();
+ 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<int64_t> GetSignedIntegerList() const;
std::vector<double> GetDoubleList() const;
std::vector<uint8_t> GetRaw() const;
- std::vector<Ref<Metadata>> GetArray();
- std::map<std::string, Ref<Metadata>> GetKeyValueStore();
+ std::vector<Ref<Metadata>> GetArray() const;
+ std::map<std::string, Ref<Metadata>> 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<std::string>& name, const std::string& join);
NameList(const NameList& name, const std::string& join);
@@ -16034,3 +16309,83 @@ namespace std
}
};
} // namespace std
+
+
+template<typename T> struct fmt::formatter<BinaryNinja::Ref<T>>
+{
+ format_context::iterator format(const BinaryNinja::Ref<T>& obj, format_context& ctx) const
+ {
+ return fmt::formatter<T>().format(*obj.GetPtr(), ctx);
+ }
+ constexpr auto parse(format_parse_context& ctx) -> format_parse_context::iterator { return ctx.begin(); }
+};
+
+template<typename T> struct fmt::formatter<BinaryNinja::Confidence<T>>
+{
+ format_context::iterator format(const BinaryNinja::Confidence<T>& obj, format_context& ctx) const
+ {
+ fmt::formatter<T>().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<typename T> struct fmt::formatter<BinaryNinja::Confidence<BinaryNinja::Ref<T>>>
+{
+ format_context::iterator format(const BinaryNinja::Confidence<BinaryNinja::Ref<T>>& obj, format_context& ctx) const
+ {
+ fmt::formatter<T>().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<BinaryNinja::Metadata>
+{
+ 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<BinaryNinja::NameList>
+{
+ 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<typename T>
+struct fmt::formatter<T, char, std::enable_if_t<std::is_enum_v<T>, 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<T>(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<T>(), *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<uint8_t> Metadata::GetRaw() const
return result;
}
-vector<Ref<Metadata>> Metadata::GetArray()
+vector<Ref<Metadata>> Metadata::GetArray() const
{
size_t size = 0;
BNMetadata** data = BNMetadataGetArray(m_object, &size);
@@ -311,7 +311,7 @@ vector<Ref<Metadata>> Metadata::GetArray()
return result;
}
-map<string, Ref<Metadata>> Metadata::GetKeyValueStore()
+map<string, Ref<Metadata>> Metadata::GetKeyValueStore() const
{
BNMetadataValueStore* data = BNMetadataGetValueStore(m_object);
map<string, Ref<Metadata>> 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<TypeDefinitionLine> 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<BinaryNinja::PossibleValueSet> 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<typename... T>
+ QString qformat(format_string<T...> fmt, T&&... args)
+ {
+ return QString::fromStdString(vformat(fmt, make_format_args(args...)));
+ }
+}
+
/*!
@}
*/
diff --git a/vendor/fmt b/vendor/fmt
new file mode 160000
+Subproject f5e54359df4c26b6230fc61d38aa29458139308