#pragma once #include #include #include #include #include #include #include #include #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& stringList, size_t* count); void AllocApiStringList(const std::vector& stringList, char BN_API_PTR* BN_API_PTR** output, size_t* count); char BN_API_PTR* BN_API_PTR* AllocApiStringList(const std::set& stringList, size_t* count); void AllocApiStringList(const std::set& stringList, char BN_API_PTR* BN_API_PTR** output, size_t* count); char BN_API_PTR* BN_API_PTR* AllocApiStringList(const std::unordered_set& stringList, size_t* count); void AllocApiStringList(const std::unordered_set& stringList, char BN_API_PTR* BN_API_PTR** output, size_t* count); void AllocApiStringPairList(const std::vector>& 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& 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& 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 ParseStringList(const char* const* stringList, size_t count); std::set ParseStringSet(const char* const* stringList, size_t count); std::unordered_set ParseStringUnorderedSet(const char* const* stringList, size_t count); std::vector> ParseStringPairList(const char* const* keys, const char* const* values, size_t count); std::map ParseStringMap(const char* const* keys, const char* const* values, size_t count); std::unordered_map 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 T WrapThrowable(F&& func, C&& catcher) { try { return func(); } catch (...) { if constexpr (std::is_invocable::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 T WrapThrowablePointer(F&& func, typename std::enable_if::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 bool WrapThrowableBool(F&& func) { try { if constexpr (std::is_same::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 }