summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Smith <glenn@vector35.com>2024-07-25 18:25:29 -0400
committerGlenn Smith <glenn@vector35.com>2024-10-14 16:59:10 -0400
commit6222101365828410769950281422115789136654 (patch)
tree51f2a7a4c78bf96c9818490afe5ac2b68e3fd885
parent2161816481322887864999289688022906323855 (diff)
FFI helpers in the api too now
-rw-r--r--ffi.cpp295
-rw-r--r--ffi.h169
2 files changed, 464 insertions, 0 deletions
diff --git a/ffi.cpp b/ffi.cpp
new file mode 100644
index 00000000..6dee0a9d
--- /dev/null
+++ b/ffi.cpp
@@ -0,0 +1,295 @@
+
+#include "ffi.h"
+#include "binaryninjaapi.h"
+
+using namespace BinaryNinja;
+using namespace std;
+
+
+char BN_API_PTR* BinaryNinja::AllocApiString(const char* string)
+{
+ return strdup(string);
+}
+
+
+void BinaryNinja::AllocApiString(const char* string, char BN_API_PTR** output)
+{
+ *output = AllocApiString(string);
+}
+
+
+char BN_API_PTR* BinaryNinja::AllocApiString(const string& string)
+{
+ return AllocApiString(string.c_str());
+}
+
+
+void BinaryNinja::AllocApiString(const string& string, char BN_API_PTR** output)
+{
+ AllocApiString(string.c_str(), output);
+}
+
+
+char BN_API_PTR* BN_API_PTR* BinaryNinja::AllocApiStringList(const char* const* stringList, size_t count)
+{
+ char BN_API_PTR* BN_API_PTR* result = new char*[count];
+ for (size_t i = 0; i < count; i++)
+ {
+ result[i] = AllocApiString(stringList[i]);
+ }
+ return result;
+}
+
+
+void BinaryNinja::AllocApiStringList(const char* const* stringList, size_t count, char BN_API_PTR* BN_API_PTR** output)
+{
+ *output = AllocApiStringList(stringList, count);
+}
+
+
+char BN_API_PTR* BN_API_PTR* BinaryNinja::AllocApiStringList(const vector<string>& stringList, size_t* count)
+{
+ *count = stringList.size();
+ vector<const char*> intermediate;
+ intermediate.reserve(*count);
+ for (const auto& string: stringList)
+ {
+ intermediate.push_back(string.c_str());
+ }
+ return AllocApiStringList(intermediate.data(), *count);
+}
+
+
+void BinaryNinja::AllocApiStringList(const vector<string>& stringList, char BN_API_PTR* BN_API_PTR** output, size_t* count)
+{
+ *count = stringList.size();
+ vector<const char*> intermediate;
+ intermediate.reserve(*count);
+ for (const auto& string: stringList)
+ {
+ intermediate.push_back(string.c_str());
+ }
+ AllocApiStringList(intermediate.data(), *count, output);
+}
+
+
+char BN_API_PTR* BN_API_PTR* BinaryNinja::AllocApiStringList(const set<string>& stringList, size_t* count)
+{
+ *count = stringList.size();
+ vector<const char*> intermediate;
+ intermediate.reserve(*count);
+ for (const auto& string: stringList)
+ {
+ intermediate.push_back(string.c_str());
+ }
+ return AllocApiStringList(intermediate.data(), *count);
+}
+
+
+void BinaryNinja::AllocApiStringList(const set<string>& stringList, char BN_API_PTR* BN_API_PTR** output, size_t* count)
+{
+ *count = stringList.size();
+ vector<const char*> intermediate;
+ intermediate.reserve(*count);
+ for (const auto& string: stringList)
+ {
+ intermediate.push_back(string.c_str());
+ }
+ AllocApiStringList(intermediate.data(), *count, output);
+}
+
+
+char BN_API_PTR* BN_API_PTR* BinaryNinja::AllocApiStringList(const unordered_set<string>& stringList, size_t* count)
+{
+ *count = stringList.size();
+ vector<const char*> intermediate;
+ intermediate.reserve(*count);
+ for (const auto& string: stringList)
+ {
+ intermediate.push_back(string.c_str());
+ }
+ return AllocApiStringList(intermediate.data(), *count);
+}
+
+
+void BinaryNinja::AllocApiStringList(const unordered_set<string>& stringList, char BN_API_PTR* BN_API_PTR** output, size_t* count)
+{
+ *count = stringList.size();
+ vector<const char*> intermediate;
+ intermediate.reserve(*count);
+ for (const auto& string: stringList)
+ {
+ intermediate.push_back(string.c_str());
+ }
+ AllocApiStringList(intermediate.data(), *count, output);
+}
+
+
+void BinaryNinja::AllocApiStringPairList(const vector<pair<string, string>>& stringPairList, char BN_API_PTR* BN_API_PTR** outputKeys, char BN_API_PTR* BN_API_PTR** outputValues, size_t* count)
+{
+ *count = stringPairList.size();
+ vector<const char*> intermediateKeys;
+ vector<const char*> intermediateValues;
+ intermediateKeys.reserve(*count);
+ intermediateValues.reserve(*count);
+ for (const auto& pair: stringPairList)
+ {
+ intermediateKeys.push_back(pair.first.c_str());
+ intermediateValues.push_back(pair.second.c_str());
+ }
+ AllocApiStringList(intermediateKeys.data(), *count, outputKeys);
+ AllocApiStringList(intermediateValues.data(), *count, outputValues);
+}
+
+
+void BinaryNinja::AllocApiStringPairList(const map<string, string>& stringPairList, char BN_API_PTR* BN_API_PTR** outputKeys, char BN_API_PTR* BN_API_PTR** outputValues, size_t* count)
+{
+ *count = stringPairList.size();
+ vector<const char*> intermediateKeys;
+ vector<const char*> intermediateValues;
+ intermediateKeys.reserve(*count);
+ intermediateValues.reserve(*count);
+ for (const auto& pair: stringPairList)
+ {
+ intermediateKeys.push_back(pair.first.c_str());
+ intermediateValues.push_back(pair.second.c_str());
+ }
+ AllocApiStringList(intermediateKeys.data(), *count, outputKeys);
+ AllocApiStringList(intermediateValues.data(), *count, outputValues);
+}
+
+
+void BinaryNinja::AllocApiStringPairList(const unordered_map<string, string>& stringPairList, char BN_API_PTR* BN_API_PTR** outputKeys, char BN_API_PTR* BN_API_PTR** outputValues, size_t* count)
+{
+ *count = stringPairList.size();
+ vector<const char*> intermediateKeys;
+ vector<const char*> intermediateValues;
+ intermediateKeys.reserve(*count);
+ intermediateValues.reserve(*count);
+ for (const auto& pair: stringPairList)
+ {
+ intermediateKeys.push_back(pair.first.c_str());
+ intermediateValues.push_back(pair.second.c_str());
+ }
+ AllocApiStringList(intermediateKeys.data(), *count, outputKeys);
+ AllocApiStringList(intermediateValues.data(), *count, outputValues);
+}
+
+
+string BinaryNinja::ParseString(const char* string)
+{
+ return string;
+}
+
+
+vector<string> BinaryNinja::ParseStringList(const char* const* stringList, size_t count)
+{
+ vector<string> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i ++)
+ {
+ result.push_back(stringList[i]);
+ }
+ return result;
+}
+
+
+set<string> BinaryNinja::ParseStringSet(const char* const* stringList, size_t count)
+{
+ set<string> result;
+ for (size_t i = 0; i < count; i ++)
+ {
+ result.insert(stringList[i]);
+ }
+ return result;
+}
+
+
+unordered_set<string> BinaryNinja::ParseStringUnorderedSet(const char* const* stringList, size_t count)
+{
+ unordered_set<string> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i ++)
+ {
+ result.insert(stringList[i]);
+ }
+ return result;
+}
+
+
+vector<pair<string, string>> BinaryNinja::ParseStringPairList(const char* const* keys, const char* const* values, size_t count)
+{
+ vector<pair<string, string>> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i ++)
+ {
+ result.push_back({keys[i], values[i]});
+ }
+ return result;
+}
+
+
+map<string, string> BinaryNinja::ParseStringMap(const char* const* keys, const char* const* values, size_t count)
+{
+ map<string, string> result;
+ for (size_t i = 0; i < count; i ++)
+ {
+ result.insert({keys[i], values[i]});
+ }
+ return result;
+}
+
+
+unordered_map<string, string> BinaryNinja::ParseStringUnorderedMap(const char* const* keys, const char* const* values, size_t count)
+{
+ unordered_map<string, string> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i ++)
+ {
+ result.insert({keys[i], values[i]});
+ }
+ return result;
+}
+
+
+void BinaryNinja::FreeApiString(char BN_API_PTR* string)
+{
+ // Allocated with strdup()
+ free(string);
+}
+
+
+void BinaryNinja::FreeApiStringList(char BN_API_PTR* BN_API_PTR* stringList, size_t count)
+{
+ for (size_t i = 0; i < count; i++)
+ {
+ FreeApiString(stringList[i]);
+ }
+ delete[] stringList;
+}
+
+
+void BinaryNinja::FreeApiStringPairList(char BN_API_PTR* BN_API_PTR* keys, char BN_API_PTR* BN_API_PTR* values, size_t count)
+{
+ FreeApiStringList(keys, count);
+ FreeApiStringList(values, count);
+}
+
+
+void BinaryNinja::FreeCoreString(char BN_CORE_PTR* string)
+{
+ BNFreeString(string);
+}
+
+
+void BinaryNinja::FreeCoreStringList(char BN_CORE_PTR* BN_CORE_PTR* stringList, size_t count)
+{
+ BNFreeStringList(stringList, count);
+}
+
+
+void BinaryNinja::FreeCoreStringPairList(char BN_CORE_PTR* BN_CORE_PTR* keys, char BN_CORE_PTR* BN_CORE_PTR* values, size_t count)
+{
+ FreeCoreStringList(keys, count);
+ FreeCoreStringList(values, count);
+}
diff --git a/ffi.h b/ffi.h
new file mode 100644
index 00000000..f9686cb5
--- /dev/null
+++ b/ffi.h
@@ -0,0 +1,169 @@
+
+#pragma once
+
+#include <optional>
+#include <string>
+#include <vector>
+#include <set>
+#include <unordered_set>
+#include <map>
+#include <unordered_map>
+#include <type_traits>
+#include "binaryninjacore.h"
+
+// FFI Helpers
+
+#ifdef __clang__
+/*! Pointer is allocated by the core */
+#define BN_CORE_PTR __attribute__((annotate("bn_core_ptr")))
+/*! Pointer is allocated by the api */
+#define BN_API_PTR __attribute__((annotate("bn_api_ptr")))
+#else
+#define BN_CORE_PTR
+#define BN_API_PTR
+#endif
+
+namespace BinaryNinja
+{
+ //------------------------------------------------------------------------------------
+ //region string <-> char*
+
+ char BN_API_PTR* AllocApiString(const char* string);
+ void AllocApiString(const char* string, char BN_API_PTR** output);
+ char BN_API_PTR* AllocApiString(const std::string& string);
+ void AllocApiString(const std::string& string, char BN_API_PTR** output);
+
+ char BN_API_PTR* BN_API_PTR* AllocApiStringList(const char* const* stringList, size_t count);
+ void AllocApiStringList(const char* const* stringList, size_t count, char BN_API_PTR* BN_API_PTR** output);
+ char BN_API_PTR* BN_API_PTR* AllocApiStringList(const std::vector<std::string>& stringList, size_t* count);
+ void AllocApiStringList(const std::vector<std::string>& stringList, char BN_API_PTR* BN_API_PTR** output, size_t* count);
+ char BN_API_PTR* BN_API_PTR* AllocApiStringList(const std::set<std::string>& stringList, size_t* count);
+ void AllocApiStringList(const std::set<std::string>& stringList, char BN_API_PTR* BN_API_PTR** output, size_t* count);
+ char BN_API_PTR* BN_API_PTR* AllocApiStringList(const std::unordered_set<std::string>& stringList, size_t* count);
+ void AllocApiStringList(const std::unordered_set<std::string>& stringList, char BN_API_PTR* BN_API_PTR** output, size_t* count);
+
+ void AllocApiStringPairList(const std::vector<std::pair<std::string, std::string>>& stringPairList, char BN_API_PTR* BN_API_PTR** outputKeys, char BN_API_PTR* BN_API_PTR** outputValues, size_t* count);
+ void AllocApiStringPairList(const std::map<std::string, std::string>& stringPairList, char BN_API_PTR* BN_API_PTR** outputKeys, char BN_API_PTR* BN_API_PTR** outputValues, size_t* count);
+ void AllocApiStringPairList(const std::unordered_map<std::string, std::string>& stringPairList, char BN_API_PTR* BN_API_PTR** outputKeys, char BN_API_PTR* BN_API_PTR** outputValues, size_t* count);
+
+ std::string ParseString(const char* string);
+ std::vector<std::string> ParseStringList(const char* const* stringList, size_t count);
+ std::set<std::string> ParseStringSet(const char* const* stringList, size_t count);
+ std::unordered_set<std::string> ParseStringUnorderedSet(const char* const* stringList, size_t count);
+
+ std::vector<std::pair<std::string, std::string>> ParseStringPairList(const char* const* keys, const char* const* values, size_t count);
+ std::map<std::string, std::string> ParseStringMap(const char* const* keys, const char* const* values, size_t count);
+ std::unordered_map<std::string, std::string> ParseStringUnorderedMap(const char* const* keys, const char* const* values, size_t count);
+
+ void FreeApiString(char BN_API_PTR* string);
+ void FreeApiStringList(char BN_API_PTR* BN_API_PTR* stringList, size_t count);
+ void FreeApiStringPairList(char BN_API_PTR* BN_API_PTR* keys, char BN_API_PTR* BN_API_PTR* values, size_t count);
+
+ void FreeCoreString(char BN_CORE_PTR* string);
+ void FreeCoreStringList(char BN_CORE_PTR* BN_CORE_PTR* stringList, size_t count);
+ void FreeCoreStringPairList(char BN_CORE_PTR* BN_CORE_PTR* keys, char BN_CORE_PTR* BN_CORE_PTR* values, size_t count);
+
+ //endregion
+
+ //------------------------------------------------------------------------------------
+ //region Try/Catch Helpers
+
+ // Forward declare this, so we don't have to depend on binaryninjaapi.h
+ void LogError(const char*, ...);
+
+ /*!
+ Wrap a throwable block in a try/catch, passing through the return value on success, and
+ calling a catch handler and passing through its return value on an exception
+ \tparam T Return type
+ \tparam F Throwable block
+ \tparam C Catch handler
+ \param func Throwable block to execute
+ \param catcher Catch handler to execute if `func` throws
+ \return Either the func's result or the handler's result
+ */
+ template<typename T, typename F, typename C>
+ T WrapThrowable(F&& func, C&& catcher)
+ {
+ try
+ {
+ return func();
+ }
+ catch (...)
+ {
+ if constexpr (std::is_invocable<C, std::exception_ptr>::value)
+ {
+ return catcher(std::current_exception());
+ }
+ else
+ {
+ return catcher();
+ }
+ }
+ }
+
+ /*!
+ Wrap a throwable block in a try/catch, passing through the return value on success.
+ Specialized for pointers, where nullptr will be returned if an exception is thrown.
+ \tparam T Return type
+ \tparam F Throwable block
+ \param func Throwable block to execute
+ \return Either the func's result or nullptr
+ */
+ template<typename T, typename F>
+ T WrapThrowablePointer(F&& func, typename std::enable_if<std::is_pointer<T>::value, int>::type _ = 0)
+ {
+ try
+ {
+ return func();
+ }
+ catch (const std::exception& e)
+ {
+ // TODO: How to handle this?
+ // g_lastExceptionMessage = e.what();
+ LogError("%s", e.what());
+ return nullptr;
+ }
+ catch (...)
+ {
+ return nullptr;
+ }
+ }
+
+ /*!
+ Wrap a throwable block in a try/catch, passing through the return value on success.
+ Specialized for bool and void functions, returning false if the function throws, or
+ - if the function returns a bool, passing through that value.
+ - if the function returns void, returning true on completion.
+ \tparam F Throwable block
+ \param func Throwable block to execute
+ \return Bool as described above
+ */
+ template<typename F>
+ bool WrapThrowableBool(F&& func)
+ {
+ try
+ {
+ if constexpr (std::is_same<typename std::invoke_result<F>::type, bool>::value)
+ {
+ return func();
+ }
+ else
+ {
+ func();
+ return true;
+ }
+ }
+ catch (const std::exception& e)
+ {
+ // TODO: How to handle this?
+ // g_lastExceptionMessage = e.what();
+ LogError("%s", e.what());
+ return false;
+ }
+ catch (...)
+ {
+ return false;
+ }
+ }
+ //endregion
+} \ No newline at end of file