summaryrefslogtreecommitdiff
path: root/view/sharedcache/api
diff options
context:
space:
mode:
Diffstat (limited to 'view/sharedcache/api')
-rw-r--r--view/sharedcache/api/CMakeLists.txt55
-rw-r--r--view/sharedcache/api/MetadataSerializable.hpp500
-rw-r--r--view/sharedcache/api/python/CMakeLists.txt50
-rw-r--r--view/sharedcache/api/python/__init__.py8
-rw-r--r--view/sharedcache/api/python/_sharedcachecore.py659
-rw-r--r--view/sharedcache/api/python/_sharedcachecore_template.py43
-rw-r--r--view/sharedcache/api/python/generator.cpp617
-rw-r--r--view/sharedcache/api/python/sharedcache.py260
-rw-r--r--view/sharedcache/api/python/sharedcache_enums.py14
-rw-r--r--view/sharedcache/api/sharedcache.cpp224
-rw-r--r--view/sharedcache/api/sharedcacheapi.h820
-rw-r--r--view/sharedcache/api/sharedcachecore.h156
12 files changed, 3406 insertions, 0 deletions
diff --git a/view/sharedcache/api/CMakeLists.txt b/view/sharedcache/api/CMakeLists.txt
new file mode 100644
index 00000000..b09ae321
--- /dev/null
+++ b/view/sharedcache/api/CMakeLists.txt
@@ -0,0 +1,55 @@
+cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
+
+project(sharedcacheapi)
+file(GLOB BN_MACHO_API_SOURCES *.cpp *.h)
+add_library(sharedcacheapi OBJECT ${BN_MACHO_API_SOURCES})
+
+if (VIEW_NAME)
+ target_compile_definitions(sharedcacheapi PRIVATE VIEW_NAME="${VIEW_NAME}")
+else()
+ error("VIEW_NAME must be defined")
+endif()
+
+function(get_recursive_include_dirs target result)
+ # Initialize an empty list to store include directories
+ set(include_dirs "")
+
+ # Get the include directories of the current target
+ get_target_property(current_target_includes ${target} INTERFACE_INCLUDE_DIRECTORIES)
+ if(current_target_includes)
+ list(APPEND include_dirs ${current_target_includes})
+ endif()
+
+ # Get the libraries that this target links to
+ get_target_property(linked_libraries ${target} INTERFACE_LINK_LIBRARIES)
+ if(linked_libraries)
+ foreach(linked_library IN LISTS linked_libraries)
+ # Skip plain library names (non-target libraries)
+ if(TARGET ${linked_library})
+ # Recursively get include directories from linked libraries
+ get_recursive_include_dirs(${linked_library} linked_library_includes)
+ list(APPEND include_dirs ${linked_library_includes})
+ endif()
+ endforeach()
+ endif()
+
+ # Set the result to the collected include directories
+ set(${result} ${include_dirs} PARENT_SCOPE)
+endfunction()
+
+get_recursive_include_dirs(binaryninjaapi INCLUDES)
+
+target_include_directories(sharedcacheapi
+ PUBLIC ${PROJECT_SOURCE_DIR} ${INCLUDES})
+
+set_target_properties(sharedcacheapi PROPERTIES
+ CXX_STANDARD 17
+ CXX_VISIBILITY_PRESET hidden
+ CXX_STANDARD_REQUIRED ON
+ VISIBILITY_INLINES_HIDDEN ON
+ POSITION_INDEPENDENT_CODE ON
+ ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/out)
+
+if (NOT DEMO)
+ add_subdirectory(python)
+endif() \ No newline at end of file
diff --git a/view/sharedcache/api/MetadataSerializable.hpp b/view/sharedcache/api/MetadataSerializable.hpp
new file mode 100644
index 00000000..dd3951ea
--- /dev/null
+++ b/view/sharedcache/api/MetadataSerializable.hpp
@@ -0,0 +1,500 @@
+//
+// Created by kat on 5/31/23.
+//
+
+/*
+ * Welcome to, this file.
+ *
+ * This is a metadata serialization helper.
+ *
+ * Have you ever wished turning a complex datastructure into a Metadata object was as easy in C++ as it is in python?
+ * Do you like macros and templates?
+ *
+ * Great news.
+ *
+ * Implement these on your `public MetadataSerializable` subclass:
+ * ```
+ void Store() override {
+ MSS(m_someVariable);
+ MSS(m_someOtherVariable);
+ }
+ void Load() override {
+ MSL(m_someVariable);
+ MSL(m_someOtherVariable);
+ }
+ ```
+ * Then, you can turn your object into a Metadata object with `AsMetadata()`, and load it back with
+ `LoadFromMetadata()`.
+ *
+ * Serialized fields will be automatically repopulated.
+ *
+ * Other ser/deser formats (rapidjson objects, strings) also exist. You can use these to achieve nesting, but probably
+ avoid that.
+ * */
+
+#include "binaryninjaapi.h"
+#include "rapidjson/document.h"
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/prettywriter.h"
+
+#ifndef SHAREDCACHE_METADATASERIALIZABLE_HPP
+#define SHAREDCACHE_METADATASERIALIZABLE_HPP
+
+#define MSS(name) store(#name, name)
+#define MSS_CAST(name, type) store(#name, (type) name)
+#define MSS_SUBCLASS(name) Serialize(#name, name)
+#define MSL(name) name = load(#name, name)
+#define MSL_CAST(name, storedType, type) name = (type)load(#name, (storedType) name)
+#define MSL_SUBCLASS(name) Deserialize(#name, name)
+
+using namespace BinaryNinja;
+
+class MetadataSerializable
+{
+protected:
+ struct SerialContext
+ {
+ rapidjson::Document doc;
+ rapidjson::Document::AllocatorType allocator;
+ };
+ struct DeserContext
+ {
+ rapidjson::Document doc;
+ };
+
+ DeserContext m_activeDeserContext;
+ SerialContext m_activeContext;
+
+public:
+ MetadataSerializable()
+ {
+ m_activeContext.doc.SetObject();
+ m_activeContext.allocator = m_activeContext.doc.GetAllocator();
+ }
+
+ // copy constructor
+ MetadataSerializable(const MetadataSerializable& other)
+ {
+ m_activeContext.doc.CopyFrom(other.m_activeContext.doc, m_activeContext.doc.GetAllocator());
+ }
+
+ // copy assignment
+ MetadataSerializable& operator=(const MetadataSerializable& other)
+ {
+ m_activeContext.doc.CopyFrom(other.m_activeContext.doc, m_activeContext.doc.GetAllocator());
+ return *this;
+ }
+
+ virtual ~MetadataSerializable()
+ {
+ }
+
+ void SetupSerContext(rapidjson::Document::AllocatorType* alloc = nullptr)
+ {
+ m_activeContext.doc.SetObject();
+ m_activeContext.allocator = m_activeContext.doc.GetAllocator();
+ }
+ void S()
+ {
+ // fixme factor out
+ }
+ void Serialize(std::string& name, bool b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, b, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, bool& b) { b = m_activeDeserContext.doc[name.c_str()].GetBool(); }
+
+ void Serialize(std::string& name, uint8_t b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, b, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, uint8_t& b)
+ {
+ b = static_cast<uint8_t>(m_activeDeserContext.doc[name.c_str()].GetUint64());
+ }
+
+ void Serialize(std::string& name, uint16_t b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, b, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, uint16_t& b)
+ {
+ b = static_cast<uint16_t>(m_activeDeserContext.doc[name.c_str()].GetUint64());
+ }
+
+ void Serialize(std::string& name, uint32_t b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, b, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, uint32_t& b)
+ {
+ b = static_cast<uint32_t>(m_activeDeserContext.doc[name.c_str()].GetUint64());
+ }
+
+ void Serialize(std::string& name, uint64_t b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, b, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, uint64_t& b)
+ {
+ b = m_activeDeserContext.doc[name.c_str()].GetUint64();
+ }
+
+ void Serialize(std::string& name, int8_t b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, b, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, int8_t& b)
+ {
+ b = m_activeDeserContext.doc[name.c_str()].GetInt64();
+ }
+
+ void Serialize(std::string& name, int16_t b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, b, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, int16_t& b)
+ {
+ b = m_activeDeserContext.doc[name.c_str()].GetInt64();
+ }
+
+ void Serialize(std::string& name, int32_t b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, b, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, int32_t& b)
+ {
+ b = m_activeDeserContext.doc[name.c_str()].GetInt();
+ }
+
+ void Serialize(std::string& name, int64_t b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, b, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, int64_t& b)
+ {
+ b = m_activeDeserContext.doc[name.c_str()].GetInt64();
+ }
+
+ void Serialize(std::string& name, std::string b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value value(b.c_str(), m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, value, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, std::string& b)
+ {
+ b = m_activeDeserContext.doc[name.c_str()].GetString();
+ }
+
+ void Serialize(std::string& name, std::map<uint64_t, std::string> b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ for (auto& i : b)
+ {
+ rapidjson::Value p(rapidjson::kArrayType);
+ p.PushBack(i.first, m_activeContext.allocator);
+ rapidjson::Value value(i.second.c_str(), m_activeContext.allocator);
+ p.PushBack(value, m_activeContext.allocator);
+ bArr.PushBack(p, m_activeContext.allocator);
+ }
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, std::map<uint64_t, std::string>& b)
+ {
+ for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray())
+ b[i.GetArray()[0].GetUint64()] = i.GetArray()[1].GetString();
+ }
+
+ void Serialize(std::string& name, std::unordered_map<uint64_t, std::string> b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ for (auto& i : b)
+ {
+ rapidjson::Value p(rapidjson::kArrayType);
+ p.PushBack(i.first, m_activeContext.allocator);
+ rapidjson::Value value(i.second.c_str(), m_activeContext.allocator);
+ p.PushBack(value, m_activeContext.allocator);
+ bArr.PushBack(p, m_activeContext.allocator);
+ }
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+
+ void Serialize(std::string& name, std::unordered_map<std::string, std::string> b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ for (auto& i : b)
+ {
+ rapidjson::Value p(rapidjson::kArrayType);
+ rapidjson::Value key(i.first.c_str(), m_activeContext.allocator);
+ rapidjson::Value value(i.second.c_str(), m_activeContext.allocator);
+ p.PushBack(key, m_activeContext.allocator);
+ p.PushBack(value, m_activeContext.allocator);
+ bArr.PushBack(p, m_activeContext.allocator);
+ }
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, std::unordered_map<uint64_t, std::string>& b)
+ {
+ for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray())
+ b[i.GetArray()[0].GetUint64()] = i.GetArray()[1].GetString();
+ }
+
+ void Serialize(std::string& name, std::unordered_map<uint64_t, uint64_t> b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ for (auto& i : b)
+ {
+ rapidjson::Value p(rapidjson::kArrayType);
+ p.PushBack(i.first, m_activeContext.allocator);
+ p.PushBack(i.second, m_activeContext.allocator);
+ bArr.PushBack(p, m_activeContext.allocator);
+ }
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, std::unordered_map<uint64_t, uint64_t>& b)
+ {
+ for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray())
+ b[i.GetArray()[0].GetUint64()] = i.GetArray()[1].GetUint64();
+ }
+
+ // std::unordered_map<std::string, std::unordered_map<uint64_t, uint64_t>>
+ void Serialize(std::string& name, std::unordered_map<std::string, std::unordered_map<uint64_t, uint64_t>> b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value classes(rapidjson::kArrayType);
+ for (auto& i : b)
+ {
+ rapidjson::Value classArr(rapidjson::kArrayType);
+ rapidjson::Value classKey(i.first.c_str(), m_activeContext.allocator);
+ classArr.PushBack(classKey, m_activeContext.allocator);
+ rapidjson::Value membersArr(rapidjson::kArrayType);
+ for (auto& j : i.second)
+ {
+ rapidjson::Value member(rapidjson::kArrayType);
+ member.PushBack(j.first, m_activeContext.allocator);
+ member.PushBack(j.second, m_activeContext.allocator);
+ membersArr.PushBack(member, m_activeContext.allocator);
+ }
+ classArr.PushBack(membersArr, m_activeContext.allocator);
+ classes.PushBack(classArr, m_activeContext.allocator);
+ }
+ m_activeContext.doc.AddMember(key, classes, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, std::unordered_map<std::string, std::unordered_map<uint64_t, uint64_t>>& b)
+ {
+ for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray())
+ {
+ std::string key = i.GetArray()[0].GetString();
+ std::unordered_map<uint64_t, uint64_t> memArray;
+ for (auto& member : i.GetArray()[1].GetArray())
+ {
+ memArray[member.GetArray()[0].GetUint64()] = member.GetArray()[1].GetUint64();
+ }
+ b[key] = memArray;
+ }
+ }
+
+ void Deserialize(std::string& name, std::unordered_map<std::string, std::string>& b)
+ {
+ for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray())
+ b[i.GetArray()[0].GetString()] = i.GetArray()[1].GetString();
+ }
+
+ void Serialize(std::string& name, std::vector<std::string> b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ for (const auto& s : b)
+ {
+ rapidjson::Value value(s.c_str(), m_activeContext.allocator);
+ bArr.PushBack(value, m_activeContext.allocator);
+ }
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, std::vector<std::string>& b)
+ {
+ for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray())
+ b.emplace_back(i.GetString());
+ }
+
+ void Serialize(std::string& name, std::vector<std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ for (auto& i : b)
+ {
+ rapidjson::Value segV(rapidjson::kArrayType);
+ segV.PushBack(i.first, m_activeContext.allocator);
+ segV.PushBack(i.second.first, m_activeContext.allocator);
+ segV.PushBack(i.second.second, m_activeContext.allocator);
+ bArr.PushBack(segV, m_activeContext.allocator);
+ }
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, std::vector<std::pair<uint64_t, std::pair<uint64_t, uint64_t>>>& b)
+ {
+ for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray())
+ {
+ std::pair<uint64_t, std::pair<uint64_t, uint64_t>> j;
+ j.first = i.GetArray()[0].GetUint64();
+ j.second.first = i.GetArray()[1].GetUint64();
+ j.second.second = i.GetArray()[2].GetUint64();
+ b.push_back(j);
+ }
+ }
+
+ void Serialize(std::string& name, std::vector<std::pair<uint64_t, bool>> b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ for (auto& i : b)
+ {
+ rapidjson::Value segV(rapidjson::kArrayType);
+ segV.PushBack(i.first, m_activeContext.allocator);
+ segV.PushBack(i.second, m_activeContext.allocator);
+ bArr.PushBack(segV, m_activeContext.allocator);
+ }
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, std::vector<std::pair<uint64_t, bool>>& b)
+ {
+ for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray())
+ {
+ std::pair<uint64_t, bool> j;
+ j.first = i.GetArray()[0].GetUint64();
+ j.second = i.GetArray()[1].GetBool();
+ b.push_back(j);
+ }
+ }
+
+ void Serialize(std::string& name, std::vector<uint64_t> b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ for (auto& i : b)
+ {
+ bArr.PushBack(i, m_activeContext.allocator);
+ }
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, std::vector<uint64_t>& b)
+ {
+ for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray())
+ {
+ b.push_back(i.GetUint64());
+ }
+ }
+
+ // std::unordered_map<std::string, uint64_t>
+ void Serialize(std::string& name, std::unordered_map<std::string, uint64_t> b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ for (auto& i : b)
+ {
+ rapidjson::Value p(rapidjson::kArrayType);
+ rapidjson::Value key(i.first.c_str(), m_activeContext.allocator);
+ p.PushBack(key, m_activeContext.allocator);
+ p.PushBack(i.second, m_activeContext.allocator);
+ bArr.PushBack(p, m_activeContext.allocator);
+ }
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+ void Deserialize(std::string& name, std::unordered_map<std::string, uint64_t>& b)
+ {
+ for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray())
+ {
+ b[i.GetArray()[0].GetString()] = i.GetArray()[1].GetUint64();
+ }
+ }
+
+ template <typename T>
+ void store(std::string x, T y)
+ {
+ Serialize(x, y);
+ }
+
+ template <typename T>
+ T load(std::string x, T y)
+ {
+ T val;
+ Deserialize(x, val);
+ return val;
+ }
+
+ rapidjson::Document& GetDoc()
+ {
+ S();
+ Store();
+ return m_activeContext.doc;
+ }
+
+public:
+ virtual void Store() = 0;
+ virtual void Load() = 0;
+
+ std::string AsString()
+ {
+ rapidjson::StringBuffer strbuf;
+ rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(strbuf);
+ GetDoc().Accept(writer);
+
+ std::string s = strbuf.GetString();
+ return s;
+ }
+ rapidjson::Document& AsDocument() { return GetDoc(); }
+ void LoadFromString(const std::string& s)
+ {
+ m_activeDeserContext.doc.Parse(s.c_str());
+ Load();
+ }
+ void LoadFromValue(rapidjson::Value& s)
+ {
+ m_activeDeserContext.doc.CopyFrom(s, m_activeDeserContext.doc.GetAllocator());
+ Load();
+ }
+ Ref<Metadata> AsMetadata() { return new Metadata(AsString()); }
+ bool LoadFromMetadata(const Ref<Metadata>& meta)
+ {
+ if (!meta->IsString())
+ return false;
+ LoadFromString(meta->GetString());
+ return true;
+ }
+};
+
+#endif // SHAREDCACHE_METADATASERIALIZABLE_HPP
diff --git a/view/sharedcache/api/python/CMakeLists.txt b/view/sharedcache/api/python/CMakeLists.txt
new file mode 100644
index 00000000..c04a57ff
--- /dev/null
+++ b/view/sharedcache/api/python/CMakeLists.txt
@@ -0,0 +1,50 @@
+cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
+
+project(sharedcache-python-api)
+
+file(GLOB PYTHON_SOURCES ${PROJECT_SOURCE_DIR}/*.py)
+list(REMOVE_ITEM PYTHON_SOURCES ${PROJECT_SOURCE_DIR}/_sharedcachecore.py)
+list(REMOVE_ITEM PYTHON_SOURCES ${PROJECT_SOURCE_DIR}/enums.py)
+
+add_executable(sharedcache_generator
+ ${PROJECT_SOURCE_DIR}/generator.cpp)
+target_link_libraries(sharedcache_generator binaryninjaapi)
+target_include_directories(sharedcache_generator PUBLIC {PROJECT_SOURCE_DIR}/../../api)
+
+set_target_properties(sharedcache_generator PROPERTIES
+ CXX_STANDARD 17
+ CXX_STANDARD_REQUIRED ON
+ BUILD_WITH_INSTALL_RPATH OFF
+ RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+
+if(BN_INTERNAL_BUILD)
+ set(PYTHON_OUTPUT_DIRECTORY ${BN_RESOURCE_DIR}/python/binaryninja/sharedcache/)
+else()
+ set(PYTHON_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out/plugins/sharedcache/)
+endif()
+
+if(WIN32)
+ if (BN_INTERNAL_BUILD)
+ add_custom_command(TARGET sharedcache_generator PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${BN_CORE_OUTPUT_DIR}/binaryninjacore.dll ${PROJECT_BINARY_DIR}/)
+ else()
+ add_custom_command(TARGET sharedcache_generator PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${BN_INSTALL_DIR}/binaryninjacore.dll ${PROJECT_BINARY_DIR}/)
+ endif()
+endif()
+
+add_custom_target(sharedcache_generator_copy ALL
+ BYPRODUCTS ${PROJECT_SOURCE_DIR}/_sharedcachecore.py ${PROJECT_SOURCE_DIR}/enums.py
+ DEPENDS ${PYTHON_SOURCES} ${PROJECT_SOURCE_DIR}/../sharedcachecore.h $<TARGET_FILE:sharedcache_generator>
+ COMMAND ${CMAKE_COMMAND} -E echo "Copying SharedCache Python Sources"
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${PYTHON_OUTPUT_DIRECTORY}
+ COMMAND ${CMAKE_COMMAND} -E env ASAN_OPTIONS=detect_leaks=0 $<TARGET_FILE:sharedcache_generator>
+ ${PROJECT_SOURCE_DIR}/../sharedcachecore.h
+ ${PROJECT_SOURCE_DIR}/_sharedcachecore.py
+ ${PROJECT_SOURCE_DIR}/_sharedcachecore_template.py
+ ${PROJECT_SOURCE_DIR}/sharedcache_enums.py
+
+ COMMAND ${CMAKE_COMMAND} -E copy ${PYTHON_SOURCES} ${PYTHON_OUTPUT_DIRECTORY}
+ COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/_sharedcachecore.py ${PYTHON_OUTPUT_DIRECTORY}
+ COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/sharedcache_enums.py ${PYTHON_OUTPUT_DIRECTORY})
+
diff --git a/view/sharedcache/api/python/__init__.py b/view/sharedcache/api/python/__init__.py
new file mode 100644
index 00000000..1f65af93
--- /dev/null
+++ b/view/sharedcache/api/python/__init__.py
@@ -0,0 +1,8 @@
+import os
+
+from binaryninja._binaryninjacore import BNGetUserPluginDirectory
+user_plugin_dir = os.path.realpath(BNGetUserPluginDirectory())
+current_path = os.path.realpath(__file__)
+
+from .sharedcache import *
+
diff --git a/view/sharedcache/api/python/_sharedcachecore.py b/view/sharedcache/api/python/_sharedcachecore.py
new file mode 100644
index 00000000..93228468
--- /dev/null
+++ b/view/sharedcache/api/python/_sharedcachecore.py
@@ -0,0 +1,659 @@
+import binaryninja
+import ctypes, os
+
+from typing import Optional
+from . import sharedcache_enums
+# Load core module
+import platform
+core = None
+core_platform = platform.system()
+
+# By the time the debugger is loaded, binaryninja has not fully initialized.
+# So we cannot call binaryninja.bundled_plugin_path()
+from binaryninja._binaryninjacore import BNGetBundledPluginDirectory, BNFreeString
+if core_platform == "Darwin":
+ _base_path = BNGetBundledPluginDirectory()
+ core = ctypes.CDLL(os.path.join(_base_path, "libsharedcache.dylib"))
+
+elif core_platform == "Linux":
+ _base_path = BNGetBundledPluginDirectory()
+ core = ctypes.CDLL(os.path.join(_base_path, "libsharedcache.so"))
+
+elif (core_platform == "Windows") or (core_platform.find("CYGWIN_NT") == 0):
+ _base_path = BNGetBundledPluginDirectory()
+ core = ctypes.CDLL(os.path.join(_base_path, "sharedcache.dll"))
+else:
+ raise Exception("OS not supported")
+
+def cstr(var) -> Optional[ctypes.c_char_p]:
+ if var is None:
+ return None
+ if isinstance(var, bytes):
+ return var
+ return var.encode("utf-8")
+
+def pyNativeStr(arg):
+ if isinstance(arg, str):
+ return arg
+ else:
+ return arg.decode('utf8')
+
+def free_string(value:ctypes.c_char_p) -> None:
+ BNFreeString(ctypes.cast(value, ctypes.POINTER(ctypes.c_byte)))
+
+# Type definitions
+from binaryninja._binaryninjacore import BNBinaryView, BNBinaryViewHandle
+class BNDSCBackingCache(ctypes.Structure):
+ @property
+ def path(self):
+ return pyNativeStr(self._path)
+ @path.setter
+ def path(self, value):
+ self._path = cstr(value)
+BNDSCBackingCacheHandle = ctypes.POINTER(BNDSCBackingCache)
+class BNDSCBackingCacheMapping(ctypes.Structure):
+ pass
+BNDSCBackingCacheMappingHandle = ctypes.POINTER(BNDSCBackingCacheMapping)
+class BNDSCImage(ctypes.Structure):
+ @property
+ def name(self):
+ return pyNativeStr(self._name)
+ @name.setter
+ def name(self, value):
+ self._name = cstr(value)
+BNDSCImageHandle = ctypes.POINTER(BNDSCImage)
+class BNDSCImageMemoryMapping(ctypes.Structure):
+ @property
+ def filePath(self):
+ return pyNativeStr(self._filePath)
+ @filePath.setter
+ def filePath(self, value):
+ self._filePath = cstr(value)
+ @property
+ def name(self):
+ return pyNativeStr(self._name)
+ @name.setter
+ def name(self, value):
+ self._name = cstr(value)
+BNDSCImageMemoryMappingHandle = ctypes.POINTER(BNDSCImageMemoryMapping)
+class BNDSCMappedMemoryRegion(ctypes.Structure):
+ @property
+ def name(self):
+ return pyNativeStr(self._name)
+ @name.setter
+ def name(self, value):
+ self._name = cstr(value)
+BNDSCMappedMemoryRegionHandle = ctypes.POINTER(BNDSCMappedMemoryRegion)
+class BNDSCMemoryUsageInfo(ctypes.Structure):
+ pass
+BNDSCMemoryUsageInfoHandle = ctypes.POINTER(BNDSCMemoryUsageInfo)
+class BNDSCSymbolRep(ctypes.Structure):
+ @property
+ def name(self):
+ return pyNativeStr(self._name)
+ @name.setter
+ def name(self, value):
+ self._name = cstr(value)
+ @property
+ def image(self):
+ return pyNativeStr(self._image)
+ @image.setter
+ def image(self, value):
+ self._image = cstr(value)
+BNDSCSymbolRepHandle = ctypes.POINTER(BNDSCSymbolRep)
+DSCViewLoadProgressEnum = ctypes.c_int
+DSCViewStateEnum = ctypes.c_int
+class BNSharedCache(ctypes.Structure):
+ pass
+BNSharedCacheHandle = ctypes.POINTER(BNSharedCache)
+
+# Structure definitions
+BNDSCBackingCache._fields_ = [
+ ("_path", ctypes.c_char_p),
+ ("isPrimary", ctypes.c_bool),
+ ("mappings", ctypes.POINTER(BNDSCBackingCacheMapping)),
+ ("mappingCount", ctypes.c_ulonglong),
+ ]
+BNDSCBackingCacheMapping._fields_ = [
+ ("vmAddress", ctypes.c_ulonglong),
+ ("size", ctypes.c_ulonglong),
+ ("fileOffset", ctypes.c_ulonglong),
+ ]
+BNDSCImage._fields_ = [
+ ("_name", ctypes.c_char_p),
+ ("headerAddress", ctypes.c_ulonglong),
+ ("mappings", ctypes.POINTER(BNDSCImageMemoryMapping)),
+ ("mappingCount", ctypes.c_ulonglong),
+ ]
+BNDSCImageMemoryMapping._fields_ = [
+ ("_filePath", ctypes.c_char_p),
+ ("_name", ctypes.c_char_p),
+ ("vmAddress", ctypes.c_ulonglong),
+ ("size", ctypes.c_ulonglong),
+ ("loaded", ctypes.c_bool),
+ ("rawViewOffset", ctypes.c_ulonglong),
+ ]
+BNDSCMappedMemoryRegion._fields_ = [
+ ("vmAddress", ctypes.c_ulonglong),
+ ("size", ctypes.c_ulonglong),
+ ("_name", ctypes.c_char_p),
+ ]
+BNDSCMemoryUsageInfo._fields_ = [
+ ("sharedCacheRefs", ctypes.c_ulonglong),
+ ("mmapRefs", ctypes.c_ulonglong),
+ ]
+BNDSCSymbolRep._fields_ = [
+ ("address", ctypes.c_ulonglong),
+ ("_name", ctypes.c_char_p),
+ ("_image", ctypes.c_char_p),
+ ]
+
+# Function definitions
+# -------------------------------------------------------
+# _BNDSCFindSymbolAtAddressAndApplyToAddress
+
+_BNDSCFindSymbolAtAddressAndApplyToAddress = core.BNDSCFindSymbolAtAddressAndApplyToAddress
+_BNDSCFindSymbolAtAddressAndApplyToAddress.restype = None
+_BNDSCFindSymbolAtAddressAndApplyToAddress.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ctypes.c_ulonglong,
+ ctypes.c_ulonglong,
+ ctypes.c_bool,
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCFindSymbolAtAddressAndApplyToAddress(
+ cache: ctypes.POINTER(BNSharedCache),
+ symbolLocation: int,
+ targetLocation: int,
+ triggerReanalysis: bool
+ ) -> None:
+ return _BNDSCFindSymbolAtAddressAndApplyToAddress(cache, symbolLocation, targetLocation, triggerReanalysis)
+
+
+# -------------------------------------------------------
+# _BNDSCViewFastGetBackingCacheCount
+
+_BNDSCViewFastGetBackingCacheCount = core.BNDSCViewFastGetBackingCacheCount
+_BNDSCViewFastGetBackingCacheCount.restype = ctypes.c_ulonglong
+_BNDSCViewFastGetBackingCacheCount.argtypes = [
+ ctypes.POINTER(BNBinaryView),
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewFastGetBackingCacheCount(
+ view: ctypes.POINTER(BNBinaryView)
+ ) -> int:
+ return _BNDSCViewFastGetBackingCacheCount(view)
+
+
+# -------------------------------------------------------
+# _BNDSCViewFreeAllImages
+
+_BNDSCViewFreeAllImages = core.BNDSCViewFreeAllImages
+_BNDSCViewFreeAllImages.restype = None
+_BNDSCViewFreeAllImages.argtypes = [
+ ctypes.POINTER(BNDSCImage),
+ ctypes.c_ulonglong,
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewFreeAllImages(
+ images: ctypes.POINTER(BNDSCImage),
+ count: int
+ ) -> None:
+ return _BNDSCViewFreeAllImages(images, count)
+
+
+# -------------------------------------------------------
+# _BNDSCViewFreeBackingCaches
+
+_BNDSCViewFreeBackingCaches = core.BNDSCViewFreeBackingCaches
+_BNDSCViewFreeBackingCaches.restype = None
+_BNDSCViewFreeBackingCaches.argtypes = [
+ ctypes.POINTER(BNDSCBackingCache),
+ ctypes.c_ulonglong,
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewFreeBackingCaches(
+ caches: ctypes.POINTER(BNDSCBackingCache),
+ count: int
+ ) -> None:
+ return _BNDSCViewFreeBackingCaches(caches, count)
+
+
+# -------------------------------------------------------
+# _BNDSCViewFreeLoadedRegions
+
+_BNDSCViewFreeLoadedRegions = core.BNDSCViewFreeLoadedRegions
+_BNDSCViewFreeLoadedRegions.restype = None
+_BNDSCViewFreeLoadedRegions.argtypes = [
+ ctypes.POINTER(BNDSCMappedMemoryRegion),
+ ctypes.c_ulonglong,
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewFreeLoadedRegions(
+ images: ctypes.POINTER(BNDSCMappedMemoryRegion),
+ count: int
+ ) -> None:
+ return _BNDSCViewFreeLoadedRegions(images, count)
+
+
+# -------------------------------------------------------
+# _BNDSCViewFreeSymbols
+
+_BNDSCViewFreeSymbols = core.BNDSCViewFreeSymbols
+_BNDSCViewFreeSymbols.restype = None
+_BNDSCViewFreeSymbols.argtypes = [
+ ctypes.POINTER(BNDSCSymbolRep),
+ ctypes.c_ulonglong,
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewFreeSymbols(
+ symbols: ctypes.POINTER(BNDSCSymbolRep),
+ count: int
+ ) -> None:
+ return _BNDSCViewFreeSymbols(symbols, count)
+
+
+# -------------------------------------------------------
+# _BNDSCViewGetAllImages
+
+_BNDSCViewGetAllImages = core.BNDSCViewGetAllImages
+_BNDSCViewGetAllImages.restype = ctypes.POINTER(BNDSCImage)
+_BNDSCViewGetAllImages.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ctypes.POINTER(ctypes.c_ulonglong),
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewGetAllImages(
+ cache: ctypes.POINTER(BNSharedCache),
+ count: ctypes.POINTER(ctypes.c_ulonglong)
+ ) -> Optional[ctypes.POINTER(BNDSCImage)]:
+ result = _BNDSCViewGetAllImages(cache, count)
+ if not result:
+ return None
+ return result
+
+
+# -------------------------------------------------------
+# _BNDSCViewGetBackingCaches
+
+_BNDSCViewGetBackingCaches = core.BNDSCViewGetBackingCaches
+_BNDSCViewGetBackingCaches.restype = ctypes.POINTER(BNDSCBackingCache)
+_BNDSCViewGetBackingCaches.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ctypes.POINTER(ctypes.c_ulonglong),
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewGetBackingCaches(
+ cache: ctypes.POINTER(BNSharedCache),
+ count: ctypes.POINTER(ctypes.c_ulonglong)
+ ) -> Optional[ctypes.POINTER(BNDSCBackingCache)]:
+ result = _BNDSCViewGetBackingCaches(cache, count)
+ if not result:
+ return None
+ return result
+
+
+# -------------------------------------------------------
+# _BNDSCViewGetImageHeaderForAddress
+
+_BNDSCViewGetImageHeaderForAddress = core.BNDSCViewGetImageHeaderForAddress
+_BNDSCViewGetImageHeaderForAddress.restype = ctypes.POINTER(ctypes.c_byte)
+_BNDSCViewGetImageHeaderForAddress.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ctypes.c_ulonglong,
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewGetImageHeaderForAddress(
+ cache: ctypes.POINTER(BNSharedCache),
+ address: int
+ ) -> Optional[Optional[str]]:
+ result = _BNDSCViewGetImageHeaderForAddress(cache, address)
+ if not result:
+ return None
+ string = str(pyNativeStr(ctypes.cast(result, ctypes.c_char_p).value))
+ BNFreeString(result)
+ return string
+
+
+# -------------------------------------------------------
+# _BNDSCViewGetImageHeaderForName
+
+_BNDSCViewGetImageHeaderForName = core.BNDSCViewGetImageHeaderForName
+_BNDSCViewGetImageHeaderForName.restype = ctypes.POINTER(ctypes.c_byte)
+_BNDSCViewGetImageHeaderForName.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ctypes.c_char_p,
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewGetImageHeaderForName(
+ cache: ctypes.POINTER(BNSharedCache),
+ name: Optional[str]
+ ) -> Optional[Optional[str]]:
+ result = _BNDSCViewGetImageHeaderForName(cache, cstr(name))
+ if not result:
+ return None
+ string = str(pyNativeStr(ctypes.cast(result, ctypes.c_char_p).value))
+ BNFreeString(result)
+ return string
+
+
+# -------------------------------------------------------
+# _BNDSCViewGetImageNameForAddress
+
+_BNDSCViewGetImageNameForAddress = core.BNDSCViewGetImageNameForAddress
+_BNDSCViewGetImageNameForAddress.restype = ctypes.POINTER(ctypes.c_byte)
+_BNDSCViewGetImageNameForAddress.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ctypes.c_ulonglong,
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewGetImageNameForAddress(
+ cache: ctypes.POINTER(BNSharedCache),
+ address: int
+ ) -> Optional[Optional[str]]:
+ result = _BNDSCViewGetImageNameForAddress(cache, address)
+ if not result:
+ return None
+ string = str(pyNativeStr(ctypes.cast(result, ctypes.c_char_p).value))
+ BNFreeString(result)
+ return string
+
+
+# -------------------------------------------------------
+# _BNDSCViewGetInstallNames
+
+_BNDSCViewGetInstallNames = core.BNDSCViewGetInstallNames
+_BNDSCViewGetInstallNames.restype = ctypes.POINTER(ctypes.c_char_p)
+_BNDSCViewGetInstallNames.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ctypes.POINTER(ctypes.c_ulonglong),
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewGetInstallNames(
+ cache: ctypes.POINTER(BNSharedCache),
+ count: ctypes.POINTER(ctypes.c_ulonglong)
+ ) -> Optional[ctypes.POINTER(ctypes.c_char_p)]:
+ result = _BNDSCViewGetInstallNames(cache, count)
+ if not result:
+ return None
+ return result
+
+
+# -------------------------------------------------------
+# _BNDSCViewGetLoadProgress
+
+_BNDSCViewGetLoadProgress = core.BNDSCViewGetLoadProgress
+_BNDSCViewGetLoadProgress.restype = DSCViewLoadProgressEnum
+_BNDSCViewGetLoadProgress.argtypes = [
+ ctypes.c_ulonglong,
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewGetLoadProgress(
+ sessionID: int
+ ) -> DSCViewLoadProgressEnum:
+ return _BNDSCViewGetLoadProgress(sessionID)
+
+
+# -------------------------------------------------------
+# _BNDSCViewGetLoadedRegions
+
+_BNDSCViewGetLoadedRegions = core.BNDSCViewGetLoadedRegions
+_BNDSCViewGetLoadedRegions.restype = ctypes.POINTER(BNDSCMappedMemoryRegion)
+_BNDSCViewGetLoadedRegions.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ctypes.POINTER(ctypes.c_ulonglong),
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewGetLoadedRegions(
+ cache: ctypes.POINTER(BNSharedCache),
+ count: ctypes.POINTER(ctypes.c_ulonglong)
+ ) -> Optional[ctypes.POINTER(BNDSCMappedMemoryRegion)]:
+ result = _BNDSCViewGetLoadedRegions(cache, count)
+ if not result:
+ return None
+ return result
+
+
+# -------------------------------------------------------
+# _BNDSCViewGetMemoryUsageInfo
+
+_BNDSCViewGetMemoryUsageInfo = core.BNDSCViewGetMemoryUsageInfo
+_BNDSCViewGetMemoryUsageInfo.restype = BNDSCMemoryUsageInfo
+_BNDSCViewGetMemoryUsageInfo.argtypes = [
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewGetMemoryUsageInfo(
+ ) -> BNDSCMemoryUsageInfo:
+ return _BNDSCViewGetMemoryUsageInfo()
+
+
+# -------------------------------------------------------
+# _BNDSCViewGetNameForAddress
+
+_BNDSCViewGetNameForAddress = core.BNDSCViewGetNameForAddress
+_BNDSCViewGetNameForAddress.restype = ctypes.POINTER(ctypes.c_byte)
+_BNDSCViewGetNameForAddress.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ctypes.c_ulonglong,
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewGetNameForAddress(
+ cache: ctypes.POINTER(BNSharedCache),
+ address: int
+ ) -> Optional[Optional[str]]:
+ result = _BNDSCViewGetNameForAddress(cache, address)
+ if not result:
+ return None
+ string = str(pyNativeStr(ctypes.cast(result, ctypes.c_char_p).value))
+ BNFreeString(result)
+ return string
+
+
+# -------------------------------------------------------
+# _BNDSCViewGetState
+
+_BNDSCViewGetState = core.BNDSCViewGetState
+_BNDSCViewGetState.restype = DSCViewStateEnum
+_BNDSCViewGetState.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewGetState(
+ cache: ctypes.POINTER(BNSharedCache)
+ ) -> DSCViewStateEnum:
+ return _BNDSCViewGetState(cache)
+
+
+# -------------------------------------------------------
+# _BNDSCViewLoadAllSymbolsAndWait
+
+_BNDSCViewLoadAllSymbolsAndWait = core.BNDSCViewLoadAllSymbolsAndWait
+_BNDSCViewLoadAllSymbolsAndWait.restype = ctypes.POINTER(BNDSCSymbolRep)
+_BNDSCViewLoadAllSymbolsAndWait.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ctypes.POINTER(ctypes.c_ulonglong),
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewLoadAllSymbolsAndWait(
+ cache: ctypes.POINTER(BNSharedCache),
+ count: ctypes.POINTER(ctypes.c_ulonglong)
+ ) -> Optional[ctypes.POINTER(BNDSCSymbolRep)]:
+ result = _BNDSCViewLoadAllSymbolsAndWait(cache, count)
+ if not result:
+ return None
+ return result
+
+
+# -------------------------------------------------------
+# _BNDSCViewLoadImageContainingAddress
+
+_BNDSCViewLoadImageContainingAddress = core.BNDSCViewLoadImageContainingAddress
+_BNDSCViewLoadImageContainingAddress.restype = ctypes.c_bool
+_BNDSCViewLoadImageContainingAddress.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ctypes.c_ulonglong,
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewLoadImageContainingAddress(
+ cache: ctypes.POINTER(BNSharedCache),
+ address: int
+ ) -> bool:
+ return _BNDSCViewLoadImageContainingAddress(cache, address)
+
+
+# -------------------------------------------------------
+# _BNDSCViewLoadImageWithInstallName
+
+_BNDSCViewLoadImageWithInstallName = core.BNDSCViewLoadImageWithInstallName
+_BNDSCViewLoadImageWithInstallName.restype = ctypes.c_bool
+_BNDSCViewLoadImageWithInstallName.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ctypes.c_char_p,
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewLoadImageWithInstallName(
+ cache: ctypes.POINTER(BNSharedCache),
+ name: Optional[str]
+ ) -> bool:
+ return _BNDSCViewLoadImageWithInstallName(cache, cstr(name))
+
+
+# -------------------------------------------------------
+# _BNDSCViewLoadSectionAtAddress
+
+_BNDSCViewLoadSectionAtAddress = core.BNDSCViewLoadSectionAtAddress
+_BNDSCViewLoadSectionAtAddress.restype = ctypes.c_bool
+_BNDSCViewLoadSectionAtAddress.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ctypes.c_ulonglong,
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewLoadSectionAtAddress(
+ cache: ctypes.POINTER(BNSharedCache),
+ name: int
+ ) -> bool:
+ return _BNDSCViewLoadSectionAtAddress(cache, name)
+
+
+# -------------------------------------------------------
+# _BNDSCViewLoadedImageCount
+
+_BNDSCViewLoadedImageCount = core.BNDSCViewLoadedImageCount
+_BNDSCViewLoadedImageCount.restype = ctypes.c_ulonglong
+_BNDSCViewLoadedImageCount.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ]
+
+
+# noinspection PyPep8Naming
+def BNDSCViewLoadedImageCount(
+ cache: ctypes.POINTER(BNSharedCache)
+ ) -> int:
+ return _BNDSCViewLoadedImageCount(cache)
+
+
+# -------------------------------------------------------
+# _BNFreeSharedCacheReference
+
+_BNFreeSharedCacheReference = core.BNFreeSharedCacheReference
+_BNFreeSharedCacheReference.restype = None
+_BNFreeSharedCacheReference.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ]
+
+
+# noinspection PyPep8Naming
+def BNFreeSharedCacheReference(
+ cache: ctypes.POINTER(BNSharedCache)
+ ) -> None:
+ return _BNFreeSharedCacheReference(cache)
+
+
+# -------------------------------------------------------
+# _BNGetSharedCache
+
+_BNGetSharedCache = core.BNGetSharedCache
+_BNGetSharedCache.restype = ctypes.POINTER(BNSharedCache)
+_BNGetSharedCache.argtypes = [
+ ctypes.POINTER(BNBinaryView),
+ ]
+
+
+# noinspection PyPep8Naming
+def BNGetSharedCache(
+ data: ctypes.POINTER(BNBinaryView)
+ ) -> Optional[ctypes.POINTER(BNSharedCache)]:
+ result = _BNGetSharedCache(data)
+ if not result:
+ return None
+ return result
+
+
+# -------------------------------------------------------
+# _BNNewSharedCacheReference
+
+_BNNewSharedCacheReference = core.BNNewSharedCacheReference
+_BNNewSharedCacheReference.restype = ctypes.POINTER(BNSharedCache)
+_BNNewSharedCacheReference.argtypes = [
+ ctypes.POINTER(BNSharedCache),
+ ]
+
+
+# noinspection PyPep8Naming
+def BNNewSharedCacheReference(
+ cache: ctypes.POINTER(BNSharedCache)
+ ) -> Optional[ctypes.POINTER(BNSharedCache)]:
+ result = _BNNewSharedCacheReference(cache)
+ if not result:
+ return None
+ return result
+
+
+
+# Helper functions
+def handle_of_type(value, handle_type):
+ if isinstance(value, ctypes.POINTER(handle_type)) or isinstance(value, ctypes.c_void_p):
+ return ctypes.cast(value, ctypes.POINTER(handle_type))
+ raise ValueError('expected pointer to %s' % str(handle_type))
diff --git a/view/sharedcache/api/python/_sharedcachecore_template.py b/view/sharedcache/api/python/_sharedcachecore_template.py
new file mode 100644
index 00000000..6b5b174f
--- /dev/null
+++ b/view/sharedcache/api/python/_sharedcachecore_template.py
@@ -0,0 +1,43 @@
+import binaryninja
+import ctypes, os
+
+from typing import Optional
+from . import sharedcache_enums
+# Load core module
+import platform
+core = None
+core_platform = platform.system()
+
+# By the time the debugger is loaded, binaryninja has not fully initialized.
+# So we cannot call binaryninja.bundled_plugin_path()
+from binaryninja._binaryninjacore import BNGetBundledPluginDirectory, BNFreeString
+if core_platform == "Darwin":
+ _base_path = BNGetBundledPluginDirectory()
+ core = ctypes.CDLL(os.path.join(_base_path, "libsharedcache.dylib"))
+
+elif core_platform == "Linux":
+ _base_path = BNGetBundledPluginDirectory()
+ core = ctypes.CDLL(os.path.join(_base_path, "libsharedcache.so"))
+
+elif (core_platform == "Windows") or (core_platform.find("CYGWIN_NT") == 0):
+ _base_path = BNGetBundledPluginDirectory()
+ core = ctypes.CDLL(os.path.join(_base_path, "sharedcache.dll"))
+else:
+ raise Exception("OS not supported")
+
+def cstr(var) -> Optional[ctypes.c_char_p]:
+ if var is None:
+ return None
+ if isinstance(var, bytes):
+ return var
+ return var.encode("utf-8")
+
+def pyNativeStr(arg):
+ if isinstance(arg, str):
+ return arg
+ else:
+ return arg.decode('utf8')
+
+def free_string(value:ctypes.c_char_p) -> None:
+ BNFreeString(ctypes.cast(value, ctypes.POINTER(ctypes.c_byte)))
+
diff --git a/view/sharedcache/api/python/generator.cpp b/view/sharedcache/api/python/generator.cpp
new file mode 100644
index 00000000..91ff88c0
--- /dev/null
+++ b/view/sharedcache/api/python/generator.cpp
@@ -0,0 +1,617 @@
+/*
+Copyright 2020-2024 Vector 35 Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+
+
+#include <stdio.h>
+#include <inttypes.h>
+#include "binaryninjaapi.h"
+
+using namespace BinaryNinja;
+using namespace std;
+
+
+map<string, string> g_pythonKeywordReplacements = {
+ {"False", "False_"},
+ {"True", "True_"},
+ {"None", "None_"},
+ {"and", "and_"},
+ {"as", "as_"},
+ {"assert", "assert_"},
+ {"async", "async_"},
+ {"await", "await_"},
+ {"break", "break_"},
+ {"class", "class_"},
+ {"continue", "continue_"},
+ {"def", "def_"},
+ {"del", "del_"},
+ {"elif", "elif_"},
+ {"else", "else_"},
+ {"except", "except_"},
+ {"finally", "finally_"},
+ {"for", "for_"},
+ {"from", "from_"},
+ {"global", "global_"},
+ {"if", "if_"},
+ {"import", "import_"},
+ {"in", "in_"},
+ {"is", "is_"},
+ {"lambda", "lambda_"},
+ {"nonlocal", "nonlocal_"},
+ {"not", "not_"},
+ {"or", "or_"},
+ {"pass", "pass_"},
+ {"raise", "raise_"},
+ {"return", "return_"},
+ {"try", "try_"},
+ {"while", "while_"},
+ {"with", "with_"},
+ {"yield", "yield_"},
+};
+
+
+void OutputType(FILE* out, Type* type, bool isReturnType = false, bool isCallback = false)
+{
+ switch (type->GetClass())
+ {
+ case BoolTypeClass:
+ fprintf(out, "ctypes.c_bool");
+ break;
+ case IntegerTypeClass:
+ switch (type->GetWidth())
+ {
+ case 1:
+ if (type->IsSigned())
+ fprintf(out, "ctypes.c_byte");
+ else
+ fprintf(out, "ctypes.c_ubyte");
+ break;
+ case 2:
+ if (type->IsSigned())
+ fprintf(out, "ctypes.c_short");
+ else
+ fprintf(out, "ctypes.c_ushort");
+ break;
+ case 4:
+ if (type->IsSigned())
+ fprintf(out, "ctypes.c_int");
+ else
+ fprintf(out, "ctypes.c_uint");
+ break;
+ default:
+ if (type->IsSigned())
+ fprintf(out, "ctypes.c_longlong");
+ else
+ fprintf(out, "ctypes.c_ulonglong");
+ break;
+ }
+ break;
+ case FloatTypeClass:
+ if (type->GetWidth() == 4)
+ fprintf(out, "ctypes.c_float");
+ else
+ fprintf(out, "ctypes.c_double");
+ break;
+ case NamedTypeReferenceClass:
+ if (type->GetNamedTypeReference()->GetTypeReferenceClass() == EnumNamedTypeClass)
+ {
+ string name = type->GetNamedTypeReference()->GetName().GetString();
+ if (name.size() > 16 && name.substr(0, 11) == "_BNDebugger")
+ name = name.substr(3);
+ else if (name.size() > 15 && name.substr(0, 10) == "BNDebugger")
+ name = name.substr(2);
+ else if (name.size() > 15 && name.substr(0, 7) == "BNDebug")
+ name = name.substr(2);
+ else if (name.size() > 2 && name.substr(0, 2) == "BN")
+ name = name.substr(2);
+ fprintf(out, "%sEnum", name.c_str());
+ }
+ else
+ {
+ fprintf(out, "%s", type->GetNamedTypeReference()->GetName().GetString().c_str());
+ }
+ break;
+ case PointerTypeClass:
+ if (isCallback || (type->GetChildType()->GetClass() == VoidTypeClass))
+ {
+ fprintf(out, "ctypes.c_void_p");
+ break;
+ }
+ else if ((type->GetChildType()->GetClass() == IntegerTypeClass) &&
+ (type->GetChildType()->GetWidth() == 1) && (type->GetChildType()->IsSigned()))
+ {
+ if (isReturnType)
+ fprintf(out, "ctypes.POINTER(ctypes.c_byte)");
+ else
+ fprintf(out, "ctypes.c_char_p");
+ break;
+ }
+ else if (type->GetChildType()->GetClass() == FunctionTypeClass)
+ {
+ fprintf(out, "ctypes.CFUNCTYPE(");
+ OutputType(out, type->GetChildType()->GetChildType(), true, true);
+ for (auto& i : type->GetChildType()->GetParameters())
+ {
+ fprintf(out, ", ");
+ OutputType(out, i.type);
+ }
+ fprintf(out, ")");
+ break;
+ }
+ fprintf(out, "ctypes.POINTER(");
+ OutputType(out, type->GetChildType());
+ fprintf(out, ")");
+ break;
+ case ArrayTypeClass:
+ OutputType(out, type->GetChildType());
+ fprintf(out, " * %" PRId64, type->GetElementCount());
+ break;
+ default:
+ fprintf(out, "None");
+ break;
+ }
+}
+
+
+void OutputSwizzledType(FILE* out, Type* type)
+{
+ switch (type->GetClass())
+ {
+ case BoolTypeClass:
+ fprintf(out, "bool");
+ break;
+ case IntegerTypeClass:
+ fprintf(out, "int");
+ break;
+ case FloatTypeClass:
+ fprintf(out, "float");
+ break;
+ case NamedTypeReferenceClass:
+ if (type->GetNamedTypeReference()->GetTypeReferenceClass() == EnumNamedTypeClass)
+ {
+ string name = type->GetNamedTypeReference()->GetName().GetString();
+ if (name.size() > 16 && name.substr(0, 11) == "_BNDebugger")
+ name = name.substr(3);
+ else if (name.size() > 15 && name.substr(0, 10) == "BNDebugger")
+ name = name.substr(2);
+ else if (name.size() > 15 && name.substr(0, 7) == "BNDebug")
+ name = name.substr(2);
+ else if (name.size() > 2 && name.substr(0, 2) == "BN")
+ name = name.substr(2);
+ fprintf(out, "%sEnum", name.c_str());
+ }
+ else
+ {
+ fprintf(out, "%s", type->GetNamedTypeReference()->GetName().GetString().c_str());
+ }
+ break;
+ case PointerTypeClass:
+ if (type->GetChildType()->GetClass() == VoidTypeClass)
+ {
+ fprintf(out, "Optional[ctypes.c_void_p]");
+ break;
+ }
+ else if ((type->GetChildType()->GetClass() == IntegerTypeClass) &&
+ (type->GetChildType()->GetWidth() == 1) && (type->GetChildType()->IsSigned()))
+ {
+ fprintf(out, "Optional[str]");
+ break;
+ }
+ else if (type->GetChildType()->GetClass() == FunctionTypeClass)
+ {
+ fprintf(out, "ctypes.CFUNCTYPE(");
+ OutputType(out, type->GetChildType()->GetChildType(), true, true);
+ for (auto& i : type->GetChildType()->GetParameters())
+ {
+ fprintf(out, ", ");
+ OutputType(out, i.type);
+ }
+ fprintf(out, ")");
+ break;
+ }
+ fprintf(out, "ctypes.POINTER(");
+ OutputType(out, type->GetChildType());
+ fprintf(out, ")");
+ break;
+ case ArrayTypeClass:
+ OutputType(out, type->GetChildType());
+ fprintf(out, " * %" PRId64, type->GetElementCount());
+ break;
+ default:
+ fprintf(out, "None");
+ break;
+ }
+}
+
+
+int main(int argc, char* argv[])
+{
+ if (argc < 5)
+ {
+ fprintf(stderr, "Usage: generator <header> <output> <output_template> <output_enum>\n");
+ return 1;
+ }
+
+ // Parse API header to get type and function information
+ map<QualifiedName, Ref<Type>> types, vars, funcs;
+ string errors;
+ auto arch = new CoreArchitecture(BNGetNativeTypeParserArchitecture());
+
+ // Enable ephemeral settings
+ Settings::Instance()->LoadSettingsFile("");
+ Settings::Instance()->Set("analysis.types.parserName", "ClangTypeParser");
+ bool ok = arch->GetStandalonePlatform()->ParseTypesFromSourceFile(argv[1], types, vars, funcs, errors);
+
+ if (!ok)
+ {
+ fprintf(stderr, "Errors: %s\n", errors.c_str());
+ return 1;
+ }
+
+ FILE* out = fopen(argv[2], "w");
+ FILE* out_template = fopen(argv[3], "r");
+ FILE* enums = fopen(argv[4], "w");
+
+ fprintf(enums, "import enum\n");
+
+ // Copy the content of the template to the output file
+ int c;
+ while((c = fgetc(out_template)) != EOF)
+ fputc(c, out);
+
+ // Create type objects
+ fprintf(out, "# Type definitions\n");
+ for (auto& i : types)
+ {
+ string name;
+ if (i.first.size() != 1)
+ continue;
+ name = i.first[0];
+ if (name == "BNBinaryView")
+ {
+ fprintf(out, "from binaryninja._binaryninjacore import BNBinaryView, BNBinaryViewHandle\n");
+ continue;
+ }
+ if (i.second->GetClass() == StructureTypeClass)
+ {
+ fprintf(out, "class %s(ctypes.Structure):\n", name.c_str());
+
+ // python uses str's, C uses byte-arrays
+ bool stringField = false;
+ for (auto& arg : i.second->GetStructure()->GetMembers())
+ {
+ if ((arg.type->GetClass() == PointerTypeClass) &&
+ (arg.type->GetChildType()->GetWidth() == 1) &&
+ (arg.type->GetChildType()->IsSigned()))
+ {
+ fprintf(out, "\t@property\n\tdef %s(self):\n\t\treturn pyNativeStr(self._%s)\n", arg.name.c_str(), arg.name.c_str());
+ fprintf(out, "\t@%s.setter\n\tdef %s(self, value):\n\t\tself._%s = cstr(value)\n", arg.name.c_str(), arg.name.c_str(), arg.name.c_str());
+ stringField = true;
+ }
+ }
+
+ if (!stringField)
+ fprintf(out, "\tpass\n");
+
+ fprintf(out, "%sHandle = ctypes.POINTER(%s)\n", name.c_str(), name.c_str());
+ }
+ else if (i.second->GetClass() == EnumerationTypeClass)
+ {
+ bool isBNAPIEnum = false;
+ if (name.size() > 16 && name.substr(0, 11) == "_BNDebugger")
+ name = name.substr(3);
+ else if (name.size() > 15 && name.substr(0, 10) == "BNDebugger")
+ name = name.substr(2);
+ else if (name.size() > 15 && name.substr(0, 7) == "BNDebug")
+ name = name.substr(2);
+ else if (name.size() > 2 && name.substr(0, 2) == "BN")
+ {
+ name = name.substr(2);
+ isBNAPIEnum = false;
+ }
+ else
+ continue;
+
+ if (isBNAPIEnum)
+ {
+ fprintf(out, "from binaryninja._binaryninjacore import %sEnum\n", name.c_str());
+ continue;
+ }
+
+ fprintf(out, "%sEnum = ctypes.c_int\n", name.c_str());
+
+ fprintf(enums, "\n\nclass %s(enum.IntEnum):\n", name.c_str());
+ for (auto& j : i.second->GetEnumeration()->GetMembers())
+ {
+ fprintf(enums, "\t%s = %" PRId64 "\n", j.name.c_str(), j.value);
+ }
+ }
+ else if ((i.second->GetClass() == BoolTypeClass) || (i.second->GetClass() == IntegerTypeClass) ||
+ (i.second->GetClass() == FloatTypeClass) || (i.second->GetClass() == ArrayTypeClass))
+ {
+ fprintf(out, "%s = ", name.c_str());
+ OutputType(out, i.second);
+ fprintf(out, "\n");
+ }
+ }
+
+
+ fprintf(out, "\n# Structure definitions\n");
+ set<QualifiedName> structsToProcess;
+ set<QualifiedName> finishedStructs;
+ for (auto& i : types)
+ structsToProcess.insert(i.first);
+ while (structsToProcess.size() != 0)
+ {
+ set<QualifiedName> currentStructList = structsToProcess;
+ structsToProcess.clear();
+ bool processedSome = false;
+ for (auto& i : currentStructList)
+ {
+ string name;
+ if (i.size() != 1)
+ continue;
+ Ref<Type> type = types[i];
+ name = i[0];
+ if ((type->GetClass() == StructureTypeClass) && (type->GetStructure()->GetMembers().size() != 0))
+ {
+ bool requiresDependency = false;
+ for (auto& j : type->GetStructure()->GetMembers())
+ {
+ if ((j.type->GetClass() == NamedTypeReferenceClass) &&
+ (types[j.type->GetNamedTypeReference()->GetName()]->GetClass() == StructureTypeClass) &&
+ (finishedStructs.count(j.type->GetNamedTypeReference()->GetName()) == 0))
+ {
+ // This structure needs another structure that isn't fully defined yet, need to wait
+ // for the dependencies to be defined
+ structsToProcess.insert(i);
+ requiresDependency = true;
+ break;
+ }
+ }
+
+ if (requiresDependency)
+ continue;
+ fprintf(out, "%s._fields_ = [\n", name.c_str());
+ for (auto& j : type->GetStructure()->GetMembers())
+ {
+ // To help the python->C wrappers
+ if ((j.type->GetClass() == PointerTypeClass) &&
+ (j.type->GetChildType()->GetWidth() == 1) &&
+ (j.type->GetChildType()->IsSigned()))
+ {
+ fprintf(out, "\t\t(\"_%s\", ", j.name.c_str());
+ }
+ else
+ fprintf(out, "\t\t(\"%s\", ", j.name.c_str());
+ OutputType(out, j.type);
+ fprintf(out, "),\n");
+ }
+ fprintf(out, "\t]\n");
+ finishedStructs.insert(i);
+ processedSome = true;
+ }
+ else if (type->GetClass() == NamedTypeReferenceClass)
+ {
+ if (type->GetNamedTypeReference()->GetTypeReferenceClass() == StructNamedTypeClass)
+ {
+ fprintf(out, "%s = %s\n", name.c_str(), type->GetNamedTypeReference()->GetName().GetString().c_str());
+ fprintf(out, "%sHandle = %sHandle\n", name.c_str(), type->GetNamedTypeReference()->GetName().GetString().c_str());
+ }
+ else if (type->GetNamedTypeReference()->GetTypeReferenceClass() == EnumNamedTypeClass)
+ {
+ fprintf(out, "%s = ctypes.c_int\n", name.c_str());
+ }
+ finishedStructs.insert(i);
+ processedSome = true;
+ }
+ }
+
+ if (!processedSome && structsToProcess.size() != 0)
+ {
+ fprintf(stderr, "Detected dependency cycle in structures\n");
+ for (auto& i : structsToProcess)
+ fprintf(stderr, "%s\n", i.GetString().c_str());
+ return 1;
+ }
+ }
+
+ fprintf(out, "\n# Function definitions\n");
+ for (auto& i : funcs)
+ {
+ string name;
+ if (i.first.size() != 1)
+ continue;
+ name = i.first[0];
+
+ // Check for a string result, these will be automatically wrapped to free the string
+ // memory and return a Python string
+ bool stringResult = (i.second->GetChildType()->GetClass() == PointerTypeClass) &&
+ (i.second->GetChildType()->GetChildType()->GetWidth() == 1) &&
+ (i.second->GetChildType()->GetChildType()->IsSigned());
+ // Pointer returns will be automatically wrapped to return None on null pointer
+ bool pointerResult = (i.second->GetChildType()->GetClass() == PointerTypeClass);
+
+ // From python -> C python3 requires str -> str.encode('charmap')
+ bool swizzleArgs = true;
+ if (name == "BNFreeString")
+ swizzleArgs = false;
+
+ bool callbackConvention = false;
+ if (name == "BNAllocString")
+ {
+ // Don't perform automatic wrapping of string allocation, and return a void
+ // pointer so that callback functions (which is the only valid use of BNDebuggerAllocString)
+ // can properly return the result
+ stringResult = false;
+ callbackConvention = true;
+ swizzleArgs = false;
+ }
+
+ string funcName = string("_") + name;
+
+ fprintf(out, "# -------------------------------------------------------\n");
+ fprintf(out, "# %s\n\n", funcName.c_str());
+ fprintf(out, "%s = core.%s\n", funcName.c_str(), name.c_str());
+ fprintf(out, "%s.restype = ", funcName.c_str());
+ OutputType(out, i.second->GetChildType(), true, callbackConvention);
+ fprintf(out, "\n");
+ if (!i.second->HasVariableArguments())
+ {
+ fprintf(out, "%s.argtypes = [\n", funcName.c_str());
+ for (auto& j : i.second->GetParameters())
+ {
+ fprintf(out, "\t\t");
+ if (name == "BNFreeString")
+ {
+ // BNDebuggerFreeString expects a pointer to a string allocated by the core, so do not use
+ // a c_char_p here, as that would be allocated by the Python runtime. This can
+ // be enforced by outputting like a return value.
+ OutputType(out, j.type, true);
+ }
+ else
+ {
+ OutputType(out, j.type);
+ }
+ fprintf(out, ",\n");
+ }
+ fprintf(out, "\t]");
+ }
+ else
+ {
+ // As of writing this, only BNLog's have variable instruction lengths, but in an attempt not to break in the future:
+ if (funcName.compare(0, 6, "_BNLog") == 0)
+ {
+ if (funcName != "_BNLog")
+ {
+ fprintf(out, "def %s(*args):\n", name.c_str());
+ fprintf(out, "\treturn %s(*[cstr(arg) for arg in args])\n\n", funcName.c_str());
+ continue;
+ }
+ else
+ {
+ fprintf(out, "def %s(level, *args):\n", name.c_str());
+ fprintf(out, "\treturn %s(level, *[cstr(arg) for arg in args])\n\n", funcName.c_str());
+ continue;
+ }
+ }
+ }
+ fprintf(out, "\n\n\n# noinspection PyPep8Naming\n");
+ fprintf(out, "def %s(", name.c_str());
+ if (!i.second->HasVariableArguments())
+ {
+ size_t argN = 0;
+ for (auto& arg: i.second->GetParameters())
+ {
+ string argName = arg.name;
+ if (g_pythonKeywordReplacements.find(argName) != g_pythonKeywordReplacements.end())
+ argName = g_pythonKeywordReplacements[argName];
+
+ if (argName.empty())
+ argName = "arg" + to_string(argN);
+
+ if (argN > 0)
+ fprintf(out, ", ");
+ fprintf(out, "\n\t\t");
+ fprintf(out, "%s: ", argName.c_str());
+ if (swizzleArgs)
+ OutputSwizzledType(out, arg.type);
+ else
+ OutputType(out, arg.type);
+ argN ++;
+ }
+ }
+ fprintf(out, "\n\t\t) -> ");
+ if (swizzleArgs)
+ {
+ if (stringResult || pointerResult)
+ fprintf(out, "Optional[");
+ OutputSwizzledType(out, i.second->GetChildType());
+ if (stringResult || pointerResult)
+ fprintf(out, "]");
+ }
+ else
+ {
+ OutputType(out, i.second->GetChildType());
+ }
+ fprintf(out, ":\n");
+
+ string stringArgFuncCall = funcName + "(";
+ size_t argN = 0;
+ for (auto& arg : i.second->GetParameters())
+ {
+ string argName = arg.name;
+ if (g_pythonKeywordReplacements.find(argName) != g_pythonKeywordReplacements.end())
+ argName = g_pythonKeywordReplacements[argName];
+
+ if (argName.empty())
+ argName = "arg" + to_string(argN);
+
+ if (swizzleArgs && (arg.type->GetClass() == PointerTypeClass) &&
+ (arg.type->GetChildType()->GetClass() == IntegerTypeClass) &&
+ (arg.type->GetChildType()->GetWidth() == 1) &&
+ (arg.type->GetChildType()->IsSigned()))
+ {
+ stringArgFuncCall += string("cstr(") + argName + "), ";
+ }
+ else
+ {
+ stringArgFuncCall += argName + ", ";
+ }
+ argN++;
+ }
+ if (argN > 0)
+ stringArgFuncCall = stringArgFuncCall.substr(0, stringArgFuncCall.size()-2);
+ stringArgFuncCall += ")";
+
+ if (stringResult)
+ {
+ // Emit wrapper to get Python string and free native memory
+ fprintf(out, "\tresult = ");
+ fprintf(out, "%s\n", stringArgFuncCall.c_str());
+ fprintf(out, "\tif not result:\n");
+ fprintf(out, "\t\treturn None\n");
+ fprintf(out, "\tstring = str(pyNativeStr(ctypes.cast(result, ctypes.c_char_p).value))\n");
+ fprintf(out, "\tBNFreeString(result)\n");
+ fprintf(out, "\treturn string\n");
+ }
+ else if (pointerResult)
+ {
+ // Emit wrapper to return None on null pointer
+ fprintf(out, "\tresult = ");
+ fprintf(out, "%s\n", stringArgFuncCall.c_str());
+ fprintf(out, "\tif not result:\n");
+ fprintf(out, "\t\treturn None\n");
+ fprintf(out, "\treturn result\n");
+ }
+ else
+ {
+ fprintf(out, "\treturn ");
+ fprintf(out, "%s\n", stringArgFuncCall.c_str());
+ }
+ fprintf(out, "\n\n");
+ }
+
+ fprintf(out, "\n# Helper functions\n");
+ fprintf(out, "def handle_of_type(value, handle_type):\n");
+ fprintf(out, "\tif isinstance(value, ctypes.POINTER(handle_type)) or isinstance(value, ctypes.c_void_p):\n");
+ fprintf(out, "\t\treturn ctypes.cast(value, ctypes.POINTER(handle_type))\n");
+ fprintf(out, "\traise ValueError('expected pointer to %%s' %% str(handle_type))\n");
+
+ fclose(out);
+ fclose(enums);
+ return 0;
+}
diff --git a/view/sharedcache/api/python/sharedcache.py b/view/sharedcache/api/python/sharedcache.py
new file mode 100644
index 00000000..ca031e03
--- /dev/null
+++ b/view/sharedcache/api/python/sharedcache.py
@@ -0,0 +1,260 @@
+import os
+import ctypes
+import dataclasses
+import traceback
+
+import binaryninja
+from binaryninja._binaryninjacore import BNFreeStringList, BNAllocString, BNFreeString
+
+from . import _sharedcachecore as sccore
+from .sharedcache_enums import *
+
+
+@dataclasses.dataclass
+class DSCMemoryMapping:
+ filePath: str
+ name: str
+ vmAddress: int
+ rawViewOffset: int
+ size: int
+
+ def __str__(self):
+ return repr(self)
+
+ def __repr__(self):
+ return f"<DSCMemoryMapping '{self.name}' {os.path.basename(self.filePath)} raw<{self.rawViewOffset:x}>: {self.vmAddress:x}+{self.size:x}>"
+
+
+@dataclasses.dataclass
+class LoadedRegion:
+ name: str
+ headerAddress: int
+ mappings: list[DSCMemoryMapping]
+
+ def __str__(self):
+ return repr(self)
+
+ def __repr__(self):
+ return f"<LoadedRegion {self.name} @ {self.headerAddress:x}>"
+
+
+@dataclasses.dataclass
+class DSCBackingCacheMapping:
+ vmAddress: int
+ size: int
+ fileOffset: int
+
+ def __str__(self):
+ return repr(self)
+
+ def __repr__(self):
+ return f"<DSCBackingCacheMapping {self.vmAddress:x}+{self.size:x} @ {self.fileOffset:x}"
+
+
+@dataclasses.dataclass
+class DSCBackingCache:
+ path: str
+ isPrimary: bool
+ mappings: list[DSCBackingCacheMapping]
+
+ def __str__(self):
+ return repr(self)
+
+ def __repr__(self):
+ return f"<DSCBackingCache {self.path} {'Primary' if self.isPrimary else 'Secondary'} | {len(self.mappings)} mappings>"
+
+
+@dataclasses.dataclass
+class DSCImageMemoryMapping:
+ filePath: str
+ name: str
+ vmAddress: int
+ size: int
+ loaded: bool
+ rawViewOffset: int
+
+ def __str__(self):
+ return repr(self)
+
+ def __repr__(self):
+ return f"<DSCImageMemoryMapping '{self.name}' {os.path.basename(self.filePath)} raw<{self.rawViewOffset:x}>: {self.vmAddress:x}+{self.size:x}>"
+
+
+@dataclasses.dataclass
+class DSCImage:
+ name: str
+ headerAddress: int
+ mappings: list[DSCImageMemoryMapping]
+
+ def __str__(self):
+ return repr(self)
+
+ def __repr__(self):
+ return f"<DSCImage {self.name} @ {self.headerAddress:x}>"
+
+
+@dataclasses.dataclass
+class DSCSymbol:
+ name: str
+ image: str
+ address: int
+
+ def __str__(self):
+ return repr(self)
+
+ def __repr__(self):
+ return f"<DSCSymbol {self.name} @ {self.address:x} ({self.image}>"
+
+
+class SharedCache:
+ def __init__(self, view):
+ self.handle = sccore.BNGetSharedCache(view.handle)
+
+ def load_image_with_install_name(self, installName):
+ str = BNAllocString(installName.encode('utf-8'))
+ return sccore.BNDSCViewLoadImageWithInstallName(self.handle, str)
+
+ def load_section_at_address(self, addr):
+ return sccore.BNDSCViewLoadSectionAtAddress(self.handle, addr)
+
+ def load_image_containing_address(self, addr):
+ return sccore.BNDSCViewLoadImageContainingAddress(self.handle, addr)
+
+ @property
+ def caches(self):
+ count = ctypes.c_ulonglong()
+ value = sccore.BNDSCViewGetBackingCaches(self.handle, count)
+ if value is None:
+ return []
+
+ result = []
+ for i in range(count.value):
+ mappings = []
+ for j in range(value[i].mappingCount):
+ mapping = DSCBackingCacheMapping(
+ value[i].mappings[j].vmAddress,
+ value[i].mappings[j].size,
+ value[i].mappings[j].fileOffset
+ )
+ mappings.append(mapping)
+ result.append(DSCBackingCache(
+ value[i].path,
+ value[i].isPrimary,
+ mappings
+ ))
+
+ sccore.BNDSCViewFreeBackingCaches(value, count)
+ return result
+
+ @property
+ def images(self):
+ count = ctypes.c_ulonglong()
+ value = sccore.BNDSCViewGetAllImages(self.handle, count)
+ if value is None:
+ return []
+
+ result = []
+ for i in range(count.value):
+ mappings = []
+ for j in range(value[i].mappingCount):
+ mapping = DSCImageMemoryMapping(
+ value[i].mappings[j].filePath,
+ value[i].mappings[j].name,
+ value[i].mappings[j].vmAddress,
+ value[i].mappings[j].size,
+ value[i].mappings[j].loaded,
+ value[i].mappings[j].rawViewOffset
+ )
+ mappings.append(mapping)
+ result.append(DSCImage(
+ value[i].name,
+ value[i].headerAddress,
+ mappings
+ ))
+
+ sccore.BNDSCViewFreeAllImages(value, count)
+ return result
+
+ @property
+ def loaded_images(self):
+ count = ctypes.c_ulonglong()
+ value = sccore.BNDSCViewGetLoadedImages(self.handle, count)
+ if value is None:
+ return []
+
+ result = []
+ for i in range(count.value):
+ mappings = []
+ for j in range(value[i].mappingCount):
+ mapping = DSCMemoryMapping(
+ value[i].mappings[j].filePath,
+ value[i].mappings[j].name,
+ value[i].mappings[j].vmAddress,
+ value[i].mappings[j].rawViewOffset,
+ value[i].mappings[j].size
+ )
+ mappings.append(mapping)
+ result.append(LoadedRegion(
+ value[i].name,
+ value[i].headerAddress,
+ mappings
+ ))
+
+ sccore.BNDSCViewFreeLoadedImages(value, count)
+ return result
+
+ def load_all_symbols_and_wait(self):
+ count = ctypes.c_ulonglong()
+ value = sccore.BNDSCViewLoadAllSymbolsAndWait(self.handle, count)
+ if value is None:
+ return []
+ result = []
+ for i in range(count.value):
+ sym = DSCSymbol(
+ value[i].name,
+ value[i].image,
+ value[i].address
+ )
+ result.append(sym)
+
+ sccore.BNDSCViewFreeSymbols(value, count)
+ return result
+
+ @property
+ def image_names(self):
+ count = ctypes.c_ulonglong()
+ value = sccore.BNDSCViewGetInstallNames(self.handle, count)
+ if value is None:
+ return []
+
+ result = []
+ for i in range(count.value):
+ result.append(value[i].decode('utf-8'))
+
+ BNFreeStringList(value, count)
+ return result
+
+ @property
+ def image_count(self):
+ return sccore.BNDSCViewLoadedImageCount(self.handle)
+
+ @property
+ def state(self):
+ return DSCViewState(sccore.BNDSCViewGetState(self.handle))
+
+ def get_name_for_address(self, address):
+ name = sccore.BNDSCViewGetNameForAddress(self.handle, address)
+ if name is None:
+ return ""
+ result = name
+ return result
+
+ def get_image_name_for_address(self, address):
+ name = sccore.BNDSCViewGetImageNameForAddress(self.handle, address)
+ if name is None:
+ return ""
+ result = name
+ return result
+
+ def find_symbol_at_addr_and_apply_to_addr(self, symbolAddress, targetAddress, triggerReanalysis) -> None:
+ sccore.BNDSCFindSymbolAtAddressAndApplyToAddress(self.handle, symbolAddress, targetAddress, triggerReanalysis)
diff --git a/view/sharedcache/api/python/sharedcache_enums.py b/view/sharedcache/api/python/sharedcache_enums.py
new file mode 100644
index 00000000..34668424
--- /dev/null
+++ b/view/sharedcache/api/python/sharedcache_enums.py
@@ -0,0 +1,14 @@
+import enum
+
+
+class DSCViewLoadProgress(enum.IntEnum):
+ LoadProgressNotStarted = 0
+ LoadProgressLoadingCaches = 1
+ LoadProgressLoadingImages = 2
+ LoadProgressFinished = 3
+
+
+class DSCViewState(enum.IntEnum):
+ Unloaded = 0
+ Loaded = 1
+ LoadedWithImages = 2
diff --git a/view/sharedcache/api/sharedcache.cpp b/view/sharedcache/api/sharedcache.cpp
new file mode 100644
index 00000000..5ca7c480
--- /dev/null
+++ b/view/sharedcache/api/sharedcache.cpp
@@ -0,0 +1,224 @@
+//
+// Created by kat on 5/21/23.
+//
+
+#include "sharedcacheapi.h"
+
+namespace SharedCacheAPI {
+
+ SharedCache::SharedCache(Ref<BinaryView> view) {
+ m_object = BNGetSharedCache(view->GetObject());
+ }
+
+ BNDSCViewLoadProgress SharedCache::GetLoadProgress(Ref<BinaryView> view)
+ {
+ return BNDSCViewGetLoadProgress(view->GetFile()->GetSessionId());
+ }
+
+ uint64_t SharedCache::FastGetBackingCacheCount(Ref<BinaryView> view)
+ {
+ return BNDSCViewFastGetBackingCacheCount(view->GetObject());
+ }
+
+ bool SharedCache::LoadImageWithInstallName(std::string installName)
+ {
+ char* str = BNAllocString(installName.c_str());
+ return BNDSCViewLoadImageWithInstallName(m_object, str);
+ }
+
+ bool SharedCache::LoadSectionAtAddress(uint64_t addr)
+ {
+ return BNDSCViewLoadSectionAtAddress(m_object, addr);
+ }
+
+ bool SharedCache::LoadImageContainingAddress(uint64_t addr)
+ {
+ return BNDSCViewLoadImageContainingAddress(m_object, addr);
+ }
+
+ std::vector<std::string> SharedCache::GetAvailableImages()
+ {
+ size_t count;
+ char** value = BNDSCViewGetInstallNames(m_object, &count);
+ if (value == nullptr)
+ {
+ return {};
+ }
+
+ std::vector<std::string> result;
+ for (size_t i = 0; i < count; i++)
+ {
+ result.push_back(value[i]);
+ }
+
+ BNFreeStringList(value, count);
+ return result;
+ }
+
+ std::vector<DSCMemoryRegion> SharedCache::GetLoadedMemoryRegions()
+ {
+ size_t count;
+ BNDSCMappedMemoryRegion* value = BNDSCViewGetLoadedRegions(m_object, &count);
+ if (value == nullptr)
+ {
+ return {};
+ }
+
+ std::vector<DSCMemoryRegion> result;
+ for (size_t i = 0; i < count; i++)
+ {
+ DSCMemoryRegion region;
+ region.vmAddress = value[i].vmAddress;
+ region.size = value[i].size;
+ region.prettyName = value[i].name;
+ result.push_back(region);
+ }
+
+ BNDSCViewFreeLoadedRegions(value, count);
+ return result;
+ }
+ std::vector<BackingCache> SharedCache::GetBackingCaches()
+ {
+ size_t count;
+ BNDSCBackingCache* value = BNDSCViewGetBackingCaches(m_object, &count);
+ if (value == nullptr)
+ {
+ return {};
+ }
+
+ std::vector<BackingCache> result;
+ for (size_t i = 0; i < count; i++)
+ {
+ BackingCache cache;
+ cache.path = value[i].path;
+ cache.isPrimary = value[i].isPrimary;
+ for (size_t j = 0; j < value[i].mappingCount; j++)
+ {
+ BackingCacheMapping mapping;
+ mapping.vmAddress = value[i].mappings[j].vmAddress;
+ mapping.size = value[i].mappings[j].size;
+ mapping.fileOffset = value[i].mappings[j].fileOffset;
+ cache.mappings.push_back(mapping);
+ }
+ result.push_back(cache);
+ }
+
+ BNDSCViewFreeBackingCaches(value, count);
+ return result;
+ }
+
+ std::vector<DSCImage> SharedCache::GetImages()
+ {
+ size_t count;
+ BNDSCImage* value = BNDSCViewGetAllImages(m_object, &count);
+ if (value == nullptr)
+ {
+ return {};
+ }
+
+ std::vector<DSCImage> result;
+ for (size_t i = 0; i < count; i++)
+ {
+ DSCImage img;
+ img.name = value[i].name;
+ img.headerAddress = value[i].headerAddress;
+ for (size_t j = 0; j < value[i].mappingCount; j++)
+ {
+ DSCImageMemoryMapping mapping;
+ mapping.filePath = value[i].mappings[j].filePath;
+ mapping.name = value[i].mappings[j].name;
+ mapping.vmAddress = value[i].mappings[j].vmAddress;
+ mapping.rawViewOffset = value[i].mappings[j].rawViewOffset;
+ mapping.size = value[i].mappings[j].size;
+ mapping.loaded = value[i].mappings[j].loaded;
+ img.mappings.push_back(mapping);
+ }
+ result.push_back(img);
+ }
+
+ BNDSCViewFreeAllImages(value, count);
+ return result;
+ }
+
+ std::vector<DSCSymbol> SharedCache::LoadAllSymbolsAndWait()
+ {
+ size_t count;
+ BNDSCSymbolRep* value = BNDSCViewLoadAllSymbolsAndWait(m_object, &count);
+ if (value == nullptr)
+ {
+ return {};
+ }
+
+ std::vector<DSCSymbol> result;
+ for (size_t i = 0; i < count; i++)
+ {
+ DSCSymbol sym;
+ sym.address = value[i].address;
+ sym.name = value[i].name;
+ sym.image = value[i].image;
+ result.push_back(sym);
+ }
+
+ BNDSCViewFreeSymbols(value, count);
+ return result;
+ }
+
+ std::string SharedCache::GetNameForAddress(uint64_t address)
+ {
+ char* name = BNDSCViewGetNameForAddress(m_object, address);
+ if (name == nullptr)
+ return {};
+ std::string result = name;
+ BNFreeString(name);
+ return result;
+ }
+
+ std::string SharedCache::GetImageNameForAddress(uint64_t address)
+ {
+ char* name = BNDSCViewGetImageNameForAddress(m_object, address);
+ if (name == nullptr)
+ return {};
+ std::string result = name;
+ BNFreeString(name);
+ return result;
+ }
+
+ std::optional<SharedCacheMachOHeader> SharedCache::GetMachOHeaderForImage(std::string name)
+ {
+ char* str = BNAllocString(name.c_str());
+ char* outputStr = BNDSCViewGetImageHeaderForName(m_object, str);
+ if (outputStr == nullptr)
+ return {};
+ std::string output = outputStr;
+ BNFreeString(outputStr);
+ if (output.empty())
+ return {};
+ SharedCacheMachOHeader header;
+ header.LoadFromString(output);
+ return header;
+ }
+
+ std::optional<SharedCacheMachOHeader> SharedCache::GetMachOHeaderForAddress(uint64_t address)
+ {
+ char* outputStr = BNDSCViewGetImageHeaderForAddress(m_object, address);
+ if (outputStr == nullptr)
+ return {};
+ std::string output = outputStr;
+ BNFreeString(outputStr);
+ if (output.empty())
+ return {};
+ SharedCacheMachOHeader header;
+ header.LoadFromString(output);
+ return header;
+ }
+
+ BNDSCViewState SharedCache::GetState()
+ {
+ return BNDSCViewGetState(m_object);
+ }
+
+ void SharedCache::FindSymbolAtAddrAndApplyToAddr(uint64_t symbolLocation, uint64_t targetLocation, bool triggerReanalysis) const
+ {
+ BNDSCFindSymbolAtAddressAndApplyToAddress(m_object, symbolLocation, targetLocation, triggerReanalysis);
+ }
+} // namespace SharedCacheAPI
diff --git a/view/sharedcache/api/sharedcacheapi.h b/view/sharedcache/api/sharedcacheapi.h
new file mode 100644
index 00000000..efd38532
--- /dev/null
+++ b/view/sharedcache/api/sharedcacheapi.h
@@ -0,0 +1,820 @@
+#pragma once
+
+#include <binaryninjaapi.h>
+#include "MetadataSerializable.hpp"
+#include "view/macho/machoview.h"
+#include "sharedcachecore.h"
+
+using namespace BinaryNinja;
+
+namespace SharedCacheAPI {
+ template<class T>
+ class SCRefCountObject {
+ void AddRefInternal() { m_refs.fetch_add(1); }
+
+ void ReleaseInternal() {
+ if (m_refs.fetch_sub(1) == 1)
+ delete this;
+ }
+
+ public:
+ std::atomic<int> m_refs;
+ T *m_object;
+
+ SCRefCountObject() : m_refs(0), m_object(nullptr) {}
+
+ virtual ~SCRefCountObject() {}
+
+ T *GetObject() const { return m_object; }
+
+ static T *GetObject(SCRefCountObject *obj) {
+ if (!obj)
+ return nullptr;
+ return obj->GetObject();
+ }
+
+ void AddRef() { AddRefInternal(); }
+
+ void Release() { ReleaseInternal(); }
+
+ void AddRefForRegistration() { AddRefInternal(); }
+ };
+
+
+ template<class T, T *(*AddObjectReference)(T *), void (*FreeObjectReference)(T *)>
+ class SCCoreRefCountObject {
+ void AddRefInternal() { m_refs.fetch_add(1); }
+
+ void ReleaseInternal() {
+ if (m_refs.fetch_sub(1) == 1) {
+ if (!m_registeredRef)
+ delete this;
+ }
+ }
+
+ public:
+ std::atomic<int> m_refs;
+ bool m_registeredRef = false;
+ T *m_object;
+
+ SCCoreRefCountObject() : m_refs(0), m_object(nullptr) {}
+
+ virtual ~SCCoreRefCountObject() {}
+
+ T *GetObject() const { return m_object; }
+
+ static T *GetObject(SCCoreRefCountObject *obj) {
+ if (!obj)
+ return nullptr;
+ return obj->GetObject();
+ }
+
+ void AddRef() {
+ if (m_object && (m_refs != 0))
+ AddObjectReference(m_object);
+ AddRefInternal();
+ }
+
+ void Release() {
+ if (m_object)
+ FreeObjectReference(m_object);
+ ReleaseInternal();
+ }
+
+ void AddRefForRegistration() { m_registeredRef = true; }
+
+ void ReleaseForRegistration() {
+ m_object = nullptr;
+ m_registeredRef = false;
+ if (m_refs == 0)
+ delete this;
+ }
+ };
+
+
+ template<class T>
+ class SCRef {
+ T *m_obj;
+#ifdef BN_REF_COUNT_DEBUG
+ void* m_assignmentTrace = nullptr;
+#endif
+
+ public:
+ SCRef<T>() : m_obj(NULL) {}
+
+ SCRef<T>(T *obj) : m_obj(obj) {
+ if (m_obj) {
+ m_obj->AddRef();
+#ifdef BN_REF_COUNT_DEBUG
+ m_assignmentTrace = BNRegisterObjectRefDebugTrace(typeid(T).name());
+#endif
+ }
+ }
+
+ SCRef<T>(const SCRef<T> &obj) : m_obj(obj.m_obj) {
+ if (m_obj) {
+ m_obj->AddRef();
+#ifdef BN_REF_COUNT_DEBUG
+ m_assignmentTrace = BNRegisterObjectRefDebugTrace(typeid(T).name());
+#endif
+ }
+ }
+
+ SCRef<T>(SCRef<T> &&other) : m_obj(other.m_obj) {
+ other.m_obj = 0;
+#ifdef BN_REF_COUNT_DEBUG
+ m_assignmentTrace = other.m_assignmentTrace;
+#endif
+ }
+
+ ~SCRef<T>() {
+ if (m_obj) {
+ m_obj->Release();
+#ifdef BN_REF_COUNT_DEBUG
+ BNUnregisterObjectRefDebugTrace(typeid(T).name(), m_assignmentTrace);
+#endif
+ }
+ }
+
+ SCRef<T> &operator=(const Ref<T> &obj) {
+#ifdef BN_REF_COUNT_DEBUG
+ if (m_obj)
+ BNUnregisterObjectRefDebugTrace(typeid(T).name(), m_assignmentTrace);
+ if (obj.m_obj)
+ m_assignmentTrace = BNRegisterObjectRefDebugTrace(typeid(T).name());
+#endif
+ T *oldObj = m_obj;
+ m_obj = obj.m_obj;
+ if (m_obj)
+ m_obj->AddRef();
+ if (oldObj)
+ oldObj->Release();
+ return *this;
+ }
+
+ SCRef<T> &operator=(SCRef<T> &&other) {
+ if (m_obj) {
+#ifdef BN_REF_COUNT_DEBUG
+ BNUnregisterObjectRefDebugTrace(typeid(T).name(), m_assignmentTrace);
+#endif
+ m_obj->Release();
+ }
+ m_obj = other.m_obj;
+ other.m_obj = 0;
+#ifdef BN_REF_COUNT_DEBUG
+ m_assignmentTrace = other.m_assignmentTrace;
+#endif
+ return *this;
+ }
+
+ SCRef<T> &operator=(T *obj) {
+#ifdef BN_REF_COUNT_DEBUG
+ if (m_obj)
+ BNUnregisterObjectRefDebugTrace(typeid(T).name(), m_assignmentTrace);
+ if (obj)
+ m_assignmentTrace = BNRegisterObjectRefDebugTrace(typeid(T).name());
+#endif
+ T *oldObj = m_obj;
+ m_obj = obj;
+ if (m_obj)
+ m_obj->AddRef();
+ if (oldObj)
+ oldObj->Release();
+ return *this;
+ }
+
+ operator T *() const {
+ return m_obj;
+ }
+
+ T *operator->() const {
+ return m_obj;
+ }
+
+ T &operator*() const {
+ return *m_obj;
+ }
+
+ bool operator!() const {
+ return m_obj == NULL;
+ }
+
+ bool operator==(const T *obj) const {
+ return T::GetObject(m_obj) == T::GetObject(obj);
+ }
+
+ bool operator==(const SCRef<T> &obj) const {
+ return T::GetObject(m_obj) == T::GetObject(obj.m_obj);
+ }
+
+ bool operator!=(const T *obj) const {
+ return T::GetObject(m_obj) != T::GetObject(obj);
+ }
+
+ bool operator!=(const SCRef<T> &obj) const {
+ return T::GetObject(m_obj) != T::GetObject(obj.m_obj);
+ }
+
+ bool operator<(const T *obj) const {
+ return T::GetObject(m_obj) < T::GetObject(obj);
+ }
+
+ bool operator<(const SCRef<T> &obj) const {
+ return T::GetObject(m_obj) < T::GetObject(obj.m_obj);
+ }
+
+ T *GetPtr() const {
+ return m_obj;
+ }
+ };
+
+ struct DSCMemoryRegion {
+ uint64_t vmAddress;
+ uint64_t size;
+ std::string prettyName;
+ };
+
+ struct BackingCacheMapping {
+ uint64_t vmAddress;
+ uint64_t size;
+ uint64_t fileOffset;
+ };
+
+ struct BackingCache {
+ std::string path;
+ bool isPrimary;
+ std::vector<BackingCacheMapping> mappings;
+ };
+
+ struct DSCImageMemoryMapping {
+ std::string filePath;
+ std::string name;
+ uint64_t vmAddress;
+ uint64_t size;
+ bool loaded;
+ uint64_t rawViewOffset;
+ };
+
+ struct DSCImage {
+ std::string name;
+ uint64_t headerAddress;
+ std::vector<DSCImageMemoryMapping> mappings;
+ };
+
+ struct DSCSymbol {
+ uint64_t address;
+ std::string name;
+ std::string image;
+ };
+
+ using namespace BinaryNinja;
+ struct SharedCacheMachOHeader : public MetadataSerializable {
+ uint64_t textBase = 0;
+ uint64_t loadCommandOffset = 0;
+ mach_header_64 ident;
+ std::string identifierPrefix;
+ std::string installName;
+
+ std::vector<std::pair<uint64_t, bool>> entryPoints;
+ std::vector<uint64_t> m_entryPoints; //list of entrypoints
+
+ symtab_command symtab;
+ dysymtab_command dysymtab;
+ dyld_info_command dyldInfo;
+ routines_command_64 routines64;
+ function_starts_command functionStarts;
+ std::vector<section_64> moduleInitSections;
+ linkedit_data_command exportTrie;
+ linkedit_data_command chainedFixups {};
+
+ uint64_t relocationBase;
+ // Section and program headers, internally use 64-bit form as it is a superset of 32-bit
+ std::vector<segment_command_64> segments; //only three types of sections __TEXT, __DATA, __IMPORT
+ segment_command_64 linkeditSegment;
+ std::vector<section_64> sections;
+ std::vector<std::string> sectionNames;
+
+ std::vector<section_64> symbolStubSections;
+ std::vector<section_64> symbolPointerSections;
+
+ std::vector<std::string> dylibs;
+
+ build_version_command buildVersion;
+ std::vector<build_tool_version> buildToolVersions;
+
+ std::string exportTriePath;
+
+ bool dysymPresent = false;
+ bool dyldInfoPresent = false;
+ bool exportTriePresent = false;
+ bool chainedFixupsPresent = false;
+ bool routinesPresent = false;
+ bool functionStartsPresent = false;
+ bool relocatable = false;
+ void Serialize(const std::string& name, mach_header_64 b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ bArr.PushBack(b.magic, m_activeContext.allocator);
+ bArr.PushBack(b.cputype, m_activeContext.allocator);
+ bArr.PushBack(b.cpusubtype, m_activeContext.allocator);
+ bArr.PushBack(b.filetype, m_activeContext.allocator);
+ bArr.PushBack(b.ncmds, m_activeContext.allocator);
+ bArr.PushBack(b.sizeofcmds, m_activeContext.allocator);
+ bArr.PushBack(b.flags, m_activeContext.allocator);
+ bArr.PushBack(b.reserved, m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+
+ void Deserialize(const std::string& name, mach_header_64& b)
+ {
+ auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray();
+ b.magic = bArr[0].GetInt64();
+ b.cputype = bArr[1].GetInt64();
+ b.cpusubtype = bArr[2].GetInt64();
+ b.filetype = bArr[3].GetInt64();
+ b.ncmds = bArr[4].GetInt64();
+ b.sizeofcmds = bArr[5].GetInt64();
+ b.flags = bArr[6].GetInt64();
+ b.reserved = bArr[7].GetInt64();
+ }
+
+ void Serialize(const std::string& name, symtab_command b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ bArr.PushBack(b.cmd, m_activeContext.allocator);
+ bArr.PushBack(b.cmdsize, m_activeContext.allocator);
+ bArr.PushBack(b.symoff, m_activeContext.allocator);
+ bArr.PushBack(b.nsyms, m_activeContext.allocator);
+ bArr.PushBack(b.stroff, m_activeContext.allocator);
+ bArr.PushBack(b.strsize, m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+
+ void Deserialize(const std::string& name, symtab_command& b)
+ {
+ auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray();
+ b.cmd = bArr[0].GetUint();
+ b.cmdsize = bArr[1].GetUint();
+ b.symoff = bArr[2].GetUint();
+ b.nsyms = bArr[3].GetUint();
+ b.stroff = bArr[4].GetUint();
+ b.strsize = bArr[5].GetUint();
+ }
+
+ void Serialize(const std::string& name, dysymtab_command b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ bArr.PushBack(b.cmd, m_activeContext.allocator);
+ bArr.PushBack(b.cmdsize, m_activeContext.allocator);
+ bArr.PushBack(b.ilocalsym, m_activeContext.allocator);
+ bArr.PushBack(b.nlocalsym, m_activeContext.allocator);
+ bArr.PushBack(b.iextdefsym, m_activeContext.allocator);
+ bArr.PushBack(b.nextdefsym, m_activeContext.allocator);
+ bArr.PushBack(b.iundefsym, m_activeContext.allocator);
+ bArr.PushBack(b.nundefsym, m_activeContext.allocator);
+ bArr.PushBack(b.tocoff, m_activeContext.allocator);
+ bArr.PushBack(b.ntoc, m_activeContext.allocator);
+ bArr.PushBack(b.modtaboff, m_activeContext.allocator);
+ bArr.PushBack(b.nmodtab, m_activeContext.allocator);
+ bArr.PushBack(b.extrefsymoff, m_activeContext.allocator);
+ bArr.PushBack(b.nextrefsyms, m_activeContext.allocator);
+ bArr.PushBack(b.indirectsymoff, m_activeContext.allocator);
+ bArr.PushBack(b.nindirectsyms, m_activeContext.allocator);
+ bArr.PushBack(b.extreloff, m_activeContext.allocator);
+ bArr.PushBack(b.nextrel, m_activeContext.allocator);
+ bArr.PushBack(b.locreloff, m_activeContext.allocator);
+ bArr.PushBack(b.nlocrel, m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+
+ void Deserialize(const std::string& name, dysymtab_command& b)
+ {
+ auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray();
+ b.cmd = bArr[0].GetUint();
+ b.cmdsize = bArr[1].GetUint();
+ b.ilocalsym = bArr[2].GetUint();
+ b.nlocalsym = bArr[3].GetUint();
+ b.iextdefsym = bArr[4].GetUint();
+ b.nextdefsym = bArr[5].GetUint();
+ b.iundefsym = bArr[6].GetUint();
+ b.nundefsym = bArr[7].GetUint();
+ b.tocoff = bArr[8].GetUint();
+ b.ntoc = bArr[9].GetUint();
+ b.modtaboff = bArr[10].GetUint();
+ b.nmodtab = bArr[11].GetUint();
+ b.extrefsymoff = bArr[12].GetUint();
+ b.nextrefsyms = bArr[13].GetUint();
+ b.indirectsymoff = bArr[14].GetUint();
+ b.nindirectsyms = bArr[15].GetUint();
+ b.extreloff = bArr[16].GetUint();
+ b.nextrel = bArr[17].GetUint();
+ b.locreloff = bArr[18].GetUint();
+ b.nlocrel = bArr[19].GetUint();
+ }
+
+ void Serialize(const std::string& name, dyld_info_command b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ bArr.PushBack(b.cmd, m_activeContext.allocator);
+ bArr.PushBack(b.cmdsize, m_activeContext.allocator);
+ bArr.PushBack(b.rebase_off, m_activeContext.allocator);
+ bArr.PushBack(b.rebase_size, m_activeContext.allocator);
+ bArr.PushBack(b.bind_off, m_activeContext.allocator);
+ bArr.PushBack(b.bind_size, m_activeContext.allocator);
+ bArr.PushBack(b.weak_bind_off, m_activeContext.allocator);
+ bArr.PushBack(b.weak_bind_size, m_activeContext.allocator);
+ bArr.PushBack(b.lazy_bind_off, m_activeContext.allocator);
+ bArr.PushBack(b.lazy_bind_size, m_activeContext.allocator);
+ bArr.PushBack(b.export_off, m_activeContext.allocator);
+ bArr.PushBack(b.export_size, m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+
+ void Deserialize(const std::string& name, dyld_info_command& b)
+ {
+ auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray();
+ b.cmd = bArr[0].GetUint();
+ b.cmdsize = bArr[1].GetUint();
+ b.rebase_off = bArr[2].GetUint();
+ b.rebase_size = bArr[3].GetUint();
+ b.bind_off = bArr[4].GetUint();
+ b.bind_size = bArr[5].GetUint();
+ b.weak_bind_off = bArr[6].GetUint();
+ b.weak_bind_size = bArr[7].GetUint();
+ b.lazy_bind_off = bArr[8].GetUint();
+ b.lazy_bind_size = bArr[9].GetUint();
+ b.export_off = bArr[10].GetUint();
+ b.export_size = bArr[11].GetUint();
+ }
+
+ void Serialize(const std::string& name, routines_command_64 b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ bArr.PushBack(b.cmd, m_activeContext.allocator);
+ bArr.PushBack(b.cmdsize, m_activeContext.allocator);
+ bArr.PushBack(b.init_address, m_activeContext.allocator);
+ bArr.PushBack(b.init_module, m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+
+ void Deserialize(const std::string& name, routines_command_64& b)
+ {
+ auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray();
+ b.cmd = bArr[0].GetUint();
+ b.cmdsize = bArr[1].GetUint();
+ b.init_address = bArr[2].GetUint();
+ b.init_module = bArr[3].GetUint();
+ }
+
+ void Serialize(const std::string& name, function_starts_command b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ bArr.PushBack(b.cmd, m_activeContext.allocator);
+ bArr.PushBack(b.cmdsize, m_activeContext.allocator);
+ bArr.PushBack(b.funcoff, m_activeContext.allocator);
+ bArr.PushBack(b.funcsize, m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+
+ void Deserialize(const std::string& name, function_starts_command& b)
+ {
+ auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray();
+ b.cmd = bArr[0].GetUint();
+ b.cmdsize = bArr[1].GetUint();
+ b.funcoff = bArr[2].GetUint();
+ b.funcsize = bArr[3].GetUint();
+ }
+
+ void Serialize(const std::string& name, std::vector<section_64> b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ for (auto& s : b)
+ {
+ rapidjson::Value sArr(rapidjson::kArrayType);
+ std::string sectNameStr;
+ char sectName[16];
+ memcpy(sectName, s.sectname, 16);
+ sectName[15] = 0;
+ sectNameStr = std::string(sectName);
+ sArr.PushBack(rapidjson::Value(sectNameStr.c_str(), m_activeContext.allocator), m_activeContext.allocator);
+ std::string segNameStr;
+ char segName[16];
+ memcpy(segName, s.segname, 16);
+ segName[15] = 0;
+ segNameStr = std::string(segName);
+ sArr.PushBack(rapidjson::Value(segNameStr.c_str(), m_activeContext.allocator), m_activeContext.allocator);
+ sArr.PushBack(s.addr, m_activeContext.allocator);
+ sArr.PushBack(s.size, m_activeContext.allocator);
+ sArr.PushBack(s.offset, m_activeContext.allocator);
+ sArr.PushBack(s.align, m_activeContext.allocator);
+ sArr.PushBack(s.reloff, m_activeContext.allocator);
+ sArr.PushBack(s.nreloc, m_activeContext.allocator);
+ sArr.PushBack(s.flags, m_activeContext.allocator);
+ sArr.PushBack(s.reserved1, m_activeContext.allocator);
+ sArr.PushBack(s.reserved2, m_activeContext.allocator);
+ sArr.PushBack(s.reserved3, m_activeContext.allocator);
+ bArr.PushBack(sArr, m_activeContext.allocator);
+ }
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+
+ void Deserialize(const std::string& name, std::vector<section_64>& b)
+ {
+ auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray();
+ for (auto& s : bArr)
+ {
+ section_64 sec;
+ auto s2 = s.GetArray();
+ std::string sectNameStr = s2[0].GetString();
+ memcpy(sec.sectname, sectNameStr.c_str(), sectNameStr.size());
+ std::string segNameStr = s2[1].GetString();
+ memcpy(sec.segname, segNameStr.c_str(), segNameStr.size());
+ sec.addr = s2[2].GetUint64();
+ sec.size = s2[3].GetUint64();
+ sec.offset = s2[4].GetUint();
+ sec.align = s2[5].GetUint();
+ sec.reloff = s2[6].GetUint();
+ sec.nreloc = s2[7].GetUint();
+ sec.flags = s2[8].GetUint();
+ sec.reserved1 = s2[9].GetUint();
+ sec.reserved2 = s2[10].GetUint();
+ sec.reserved3 = s2[11].GetUint();
+ b.push_back(sec);
+ }
+ }
+
+ void Serialize(const std::string& name, linkedit_data_command b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ bArr.PushBack(b.cmd, m_activeContext.allocator);
+ bArr.PushBack(b.cmdsize, m_activeContext.allocator);
+ bArr.PushBack(b.dataoff, m_activeContext.allocator);
+ bArr.PushBack(b.datasize, m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+
+ void Deserialize(const std::string& name, linkedit_data_command& b)
+ {
+ auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray();
+ b.cmd = bArr[0].GetUint();
+ b.cmdsize = bArr[1].GetUint();
+ b.dataoff = bArr[2].GetUint();
+ b.datasize = bArr[3].GetUint();
+ }
+
+ void Serialize(const std::string& name, segment_command_64 b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ std::string segNameStr;
+ char segName[16];
+ memcpy(segName, b.segname, 16);
+ segName[15] = 0;
+ segNameStr = std::string(segName);
+ bArr.PushBack(rapidjson::Value(segNameStr.c_str(), m_activeContext.allocator), m_activeContext.allocator);
+ bArr.PushBack(b.vmaddr, m_activeContext.allocator);
+ bArr.PushBack(b.vmsize, m_activeContext.allocator);
+ bArr.PushBack(b.fileoff, m_activeContext.allocator);
+ bArr.PushBack(b.filesize, m_activeContext.allocator);
+ bArr.PushBack(b.maxprot, m_activeContext.allocator);
+ bArr.PushBack(b.initprot, m_activeContext.allocator);
+ bArr.PushBack(b.nsects, m_activeContext.allocator);
+ bArr.PushBack(b.flags, m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+
+ void Deserialize(const std::string& name, segment_command_64& b)
+ {
+ auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray();
+ std::string segNameStr = bArr[0].GetString();
+ memcpy(b.segname, segNameStr.c_str(), segNameStr.size());
+ b.vmaddr = bArr[1].GetUint64();
+ b.vmsize = bArr[2].GetUint64();
+ b.fileoff = bArr[3].GetUint64();
+ b.filesize = bArr[4].GetUint64();
+ b.maxprot = bArr[5].GetUint();
+ b.initprot = bArr[6].GetUint();
+ b.nsects = bArr[7].GetUint();
+ b.flags = bArr[8].GetUint();
+ }
+
+ void Serialize(const std::string& name, std::vector<segment_command_64> b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ for (auto& s : b)
+ {
+ rapidjson::Value sArr(rapidjson::kArrayType);
+ std::string segNameStr;
+ char segName[16];
+ memcpy(segName, s.segname, 16);
+ segName[15] = 0;
+ segNameStr = std::string(segName);
+ sArr.PushBack(rapidjson::Value(segNameStr.c_str(), m_activeContext.allocator), m_activeContext.allocator);
+ sArr.PushBack(s.vmaddr, m_activeContext.allocator);
+ sArr.PushBack(s.vmsize, m_activeContext.allocator);
+ sArr.PushBack(s.fileoff, m_activeContext.allocator);
+ sArr.PushBack(s.filesize, m_activeContext.allocator);
+ sArr.PushBack(s.maxprot, m_activeContext.allocator);
+ sArr.PushBack(s.initprot, m_activeContext.allocator);
+ sArr.PushBack(s.nsects, m_activeContext.allocator);
+ sArr.PushBack(s.flags, m_activeContext.allocator);
+ bArr.PushBack(sArr, m_activeContext.allocator);
+ }
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+
+ void Deserialize(const std::string& name, std::vector<segment_command_64>& b)
+ {
+ auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray();
+ for (auto& s : bArr)
+ {
+ segment_command_64 sec;
+ auto s2 = s.GetArray();
+ std::string segNameStr = s2[0].GetString();
+ memcpy(sec.segname, segNameStr.c_str(), segNameStr.size());
+ sec.vmaddr = s2[1].GetUint64();
+ sec.vmsize = s2[2].GetUint64();
+ sec.fileoff = s2[3].GetUint64();
+ sec.filesize = s2[4].GetUint64();
+ sec.maxprot = s2[5].GetUint();
+ sec.initprot = s2[6].GetUint();
+ sec.nsects = s2[7].GetUint();
+ sec.flags = s2[8].GetUint();
+ b.push_back(sec);
+ }
+ }
+
+ void Serialize(const std::string& name, build_version_command b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ bArr.PushBack(b.cmd, m_activeContext.allocator);
+ bArr.PushBack(b.cmdsize, m_activeContext.allocator);
+ bArr.PushBack(b.platform, m_activeContext.allocator);
+ bArr.PushBack(b.minos, m_activeContext.allocator);
+ bArr.PushBack(b.sdk, m_activeContext.allocator);
+ bArr.PushBack(b.ntools, m_activeContext.allocator);
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+
+ void Deserialize(const std::string& name, build_version_command& b)
+ {
+ auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray();
+ b.cmd = bArr[0].GetUint();
+ b.cmdsize = bArr[1].GetUint();
+ b.platform = bArr[2].GetUint();
+ b.minos = bArr[3].GetUint();
+ b.sdk = bArr[4].GetUint();
+ b.ntools = bArr[5].GetUint();
+ }
+
+ void Serialize(const std::string& name, std::vector<build_tool_version> b)
+ {
+ S();
+ rapidjson::Value key(name.c_str(), m_activeContext.allocator);
+ rapidjson::Value bArr(rapidjson::kArrayType);
+ for (auto& s : b)
+ {
+ rapidjson::Value sArr(rapidjson::kArrayType);
+ sArr.PushBack(s.tool, m_activeContext.allocator);
+ sArr.PushBack(s.version, m_activeContext.allocator);
+ bArr.PushBack(sArr, m_activeContext.allocator);
+ }
+ m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator);
+ }
+
+ void Deserialize(const std::string& name, std::vector<build_tool_version>& b)
+ {
+ auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray();
+ for (auto& s : bArr)
+ {
+ build_tool_version sec;
+ auto s2 = s.GetArray();
+ sec.tool = s2[0].GetUint();
+ sec.version = s2[1].GetUint();
+ b.push_back(sec);
+ }
+ }
+
+ void Store() override {
+ MSS(textBase);
+ MSS(loadCommandOffset);
+ MSS_SUBCLASS(ident);
+ MSS(identifierPrefix);
+ MSS(installName);
+ MSS(entryPoints);
+ MSS(m_entryPoints);
+ MSS_SUBCLASS(symtab);
+ MSS_SUBCLASS(dysymtab);
+ MSS_SUBCLASS(dyldInfo);
+ // MSS_SUBCLASS(routines64);
+ MSS_SUBCLASS(functionStarts);
+ MSS_SUBCLASS(moduleInitSections);
+ MSS_SUBCLASS(exportTrie);
+ MSS_SUBCLASS(chainedFixups);
+ MSS(relocationBase);
+ MSS_SUBCLASS(segments);
+ MSS_SUBCLASS(linkeditSegment);
+ MSS_SUBCLASS(sections);
+ MSS(sectionNames);
+ MSS_SUBCLASS(symbolStubSections);
+ MSS_SUBCLASS(symbolPointerSections);
+ MSS(dylibs);
+ MSS_SUBCLASS(buildVersion);
+ MSS_SUBCLASS(buildToolVersions);
+ MSS(exportTriePath);
+ MSS(dysymPresent);
+ MSS(dyldInfoPresent);
+ MSS(exportTriePresent);
+ MSS(chainedFixupsPresent);
+ MSS(routinesPresent);
+ MSS(functionStartsPresent);
+ MSS(relocatable);
+ }
+ void Load() override {
+ MSL(textBase);
+ MSL(loadCommandOffset);
+ MSL_SUBCLASS(ident);
+ MSL(identifierPrefix);
+ MSL(installName);
+ MSL(entryPoints);
+ MSL(m_entryPoints);
+ MSL_SUBCLASS(symtab);
+ MSL_SUBCLASS(dysymtab);
+ MSL_SUBCLASS(dyldInfo);
+ // MSL_SUBCLASS(routines64); // FIXME CRASH but also do we even use this?
+ MSL_SUBCLASS(functionStarts);
+ MSL_SUBCLASS(moduleInitSections);
+ MSL_SUBCLASS(exportTrie);
+ MSL_SUBCLASS(chainedFixups);
+ MSL(relocationBase);
+ MSL_SUBCLASS(segments);
+ MSL_SUBCLASS(linkeditSegment);
+ MSL_SUBCLASS(sections);
+ MSL(sectionNames);
+ MSL_SUBCLASS(symbolStubSections);
+ MSL_SUBCLASS(symbolPointerSections);
+ MSL(dylibs);
+ MSL_SUBCLASS(buildVersion);
+ MSL_SUBCLASS(buildToolVersions);
+ MSL(exportTriePath);
+ MSL(dysymPresent);
+ MSL(dyldInfoPresent);
+ MSL(exportTriePresent);
+ MSL(chainedFixupsPresent);
+ // MSL(routinesPresent);
+ MSL(functionStartsPresent);
+ MSL(relocatable);
+ }
+ };
+
+
+ class SharedCache : public SCCoreRefCountObject<BNSharedCache, BNNewSharedCacheReference, BNFreeSharedCacheReference> {
+ public:
+ SharedCache(Ref<BinaryView> view);
+
+ BNDSCViewState GetState();
+ static BNDSCViewLoadProgress GetLoadProgress(Ref<BinaryView> view);
+ static uint64_t FastGetBackingCacheCount(Ref<BinaryView> view);
+
+ bool LoadImageWithInstallName(std::string installName);
+ bool LoadSectionAtAddress(uint64_t addr);
+ bool LoadImageContainingAddress(uint64_t addr);
+ std::vector<std::string> GetAvailableImages();
+
+ std::vector<DSCSymbol> LoadAllSymbolsAndWait();
+
+ std::string GetNameForAddress(uint64_t address);
+ std::string GetImageNameForAddress(uint64_t address);
+
+ std::vector<BackingCache> GetBackingCaches();
+ std::vector<DSCImage> GetImages();
+
+ std::optional<SharedCacheMachOHeader> GetMachOHeaderForImage(std::string name);
+ std::optional<SharedCacheMachOHeader> GetMachOHeaderForAddress(uint64_t address);
+
+ std::vector<DSCMemoryRegion> GetLoadedMemoryRegions();
+
+ void FindSymbolAtAddrAndApplyToAddr(uint64_t symbolLocation, uint64_t targetLocation, bool triggerReanalysis = true) const;
+ };
+} \ No newline at end of file
diff --git a/view/sharedcache/api/sharedcachecore.h b/view/sharedcache/api/sharedcachecore.h
new file mode 100644
index 00000000..1c382e48
--- /dev/null
+++ b/view/sharedcache/api/sharedcachecore.h
@@ -0,0 +1,156 @@
+#pragma once
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef __GNUC__
+ #ifdef SHAREDCACHE_LIBRARY
+ #define SHAREDCACHE_FFI_API __attribute__((visibility("default")))
+ #else // SHAREDCACHE_LIBRARY
+ #define SHAREDCACHE_FFI_API
+ #endif // SHAREDCACHE_LIBRARY
+#else // __GNUC__
+ #ifdef _MSC_VER
+ #ifndef DEMO_VERSION
+ #ifdef SHAREDCACHE_LIBRARY
+ #define SHAREDCACHE_FFI_API __declspec(dllexport)
+ #else // SHAREDCACHE_LIBRARY
+ #define SHAREDCACHE_FFI_API __declspec(dllimport)
+ #endif // SHAREDCACHE_LIBRARY
+ #else
+ #define SHAREDCACHE_FFI_API
+ #endif
+ #else // _MSC_VER
+ #define SHAREDCACHE_FFI_API
+ #endif // _MSC_VER
+#endif // __GNUC__C
+
+#define CORE_ALLOCATED_STRUCT(T)
+
+#define CORE_ALLOCATED_CLASS(T) \
+ public: \
+ CORE_ALLOCATED_STRUCT(T) \
+ private:
+
+#define DECLARE_SHAREDCACHE_API_OBJECT_INTERNAL(handle, cls, ns) \
+ namespace ns { class cls; } struct handle { ns::cls* object; }
+
+#define DECLARE_SHAREDCACHE_API_OBJECT(handle, cls) DECLARE_SHAREDCACHE_API_OBJECT_INTERNAL(handle, cls, SharedCacheCore)
+
+#define IMPLEMENT_SHAREDCACHE_API_OBJECT(handle) \
+ CORE_ALLOCATED_CLASS(handle) \
+ private: \
+ handle m_apiObject; \
+ public: \
+ typedef handle* APIHandle; \
+ handle* GetAPIObject() { return &m_apiObject; } \
+ private:
+#define INIT_SHAREDCACHE_API_OBJECT() \
+ m_apiObject.object = this;
+
+ typedef enum BNDSCViewState {
+ Unloaded,
+ Loaded,
+ LoadedWithImages,
+ } BNDSCViewState;
+
+ typedef enum BNDSCViewLoadProgress {
+ LoadProgressNotStarted,
+ LoadProgressLoadingCaches,
+ LoadProgressLoadingImages,
+ LoadProgressFinished,
+ } BNDSCViewLoadProgress;
+
+ typedef struct BNBinaryView BNBinaryView;
+ typedef struct BNSharedCache BNSharedCache;
+
+ typedef struct BNDSCImageMemoryMapping {
+ char* filePath;
+ char* name;
+ uint64_t vmAddress;
+ uint64_t size;
+ bool loaded;
+ uint64_t rawViewOffset;
+ } BNDSCImageMemoryMapping;
+
+ typedef struct BNDSCImage {
+ char* name;
+ uint64_t headerAddress;
+ BNDSCImageMemoryMapping* mappings;
+ size_t mappingCount;
+ } BNDSCImage;
+
+ typedef struct BNDSCMappedMemoryRegion {
+ uint64_t vmAddress;
+ uint64_t size;
+ char* name;
+ } BNDSCMappedMemoryRegion;
+
+ typedef struct BNDSCBackingCacheMapping {
+ uint64_t vmAddress;
+ uint64_t size;
+ uint64_t fileOffset;
+ } BNDSCBackingCacheMapping;
+
+ typedef struct BNDSCBackingCache {
+ char* path;
+ bool isPrimary;
+ BNDSCBackingCacheMapping* mappings;
+ size_t mappingCount;
+ } BNDSCBackingCache;
+
+ typedef struct BNDSCMemoryUsageInfo {
+ uint64_t sharedCacheRefs;
+ uint64_t mmapRefs;
+ } BNDSCMemoryUsageInfo;
+
+ typedef struct BNDSCSymbolRep {
+ uint64_t address;
+ char* name;
+ char* image;
+ } BNDSCSymbolRep;
+
+ SHAREDCACHE_FFI_API BNSharedCache* BNGetSharedCache(BNBinaryView* data);
+
+ SHAREDCACHE_FFI_API BNSharedCache* BNNewSharedCacheReference(BNSharedCache* cache);
+ SHAREDCACHE_FFI_API void BNFreeSharedCacheReference(BNSharedCache* cache);
+
+ SHAREDCACHE_FFI_API char** BNDSCViewGetInstallNames(BNSharedCache* cache, size_t* count);
+ SHAREDCACHE_FFI_API uint64_t BNDSCViewLoadedImageCount(BNSharedCache* cache);
+
+ SHAREDCACHE_FFI_API bool BNDSCViewLoadImageWithInstallName(BNSharedCache* cache, char* name);
+ SHAREDCACHE_FFI_API bool BNDSCViewLoadSectionAtAddress(BNSharedCache* cache, uint64_t name);
+ SHAREDCACHE_FFI_API bool BNDSCViewLoadImageContainingAddress(BNSharedCache* cache, uint64_t address);
+
+ SHAREDCACHE_FFI_API char* BNDSCViewGetNameForAddress(BNSharedCache* cache, uint64_t address);
+ SHAREDCACHE_FFI_API char* BNDSCViewGetImageNameForAddress(BNSharedCache* cache, uint64_t address);
+
+ SHAREDCACHE_FFI_API BNDSCViewState BNDSCViewGetState(BNSharedCache* cache);
+ SHAREDCACHE_FFI_API BNDSCViewLoadProgress BNDSCViewGetLoadProgress(uint64_t sessionID);
+ SHAREDCACHE_FFI_API uint64_t BNDSCViewFastGetBackingCacheCount(BNBinaryView* view);
+
+ SHAREDCACHE_FFI_API BNDSCSymbolRep* BNDSCViewLoadAllSymbolsAndWait(BNSharedCache* cache, size_t* count);
+ SHAREDCACHE_FFI_API void BNDSCViewFreeSymbols(BNDSCSymbolRep* symbols, size_t count);
+
+ SHAREDCACHE_FFI_API BNDSCMappedMemoryRegion* BNDSCViewGetLoadedRegions(BNSharedCache* cache, size_t* count);
+ SHAREDCACHE_FFI_API void BNDSCViewFreeLoadedRegions(BNDSCMappedMemoryRegion* images, size_t count);
+
+ SHAREDCACHE_FFI_API BNDSCImage* BNDSCViewGetAllImages(BNSharedCache* cache, size_t* count);
+ SHAREDCACHE_FFI_API void BNDSCViewFreeAllImages(BNDSCImage* images, size_t count);
+
+ SHAREDCACHE_FFI_API BNDSCBackingCache* BNDSCViewGetBackingCaches(BNSharedCache* cache, size_t* count);
+ SHAREDCACHE_FFI_API void BNDSCViewFreeBackingCaches(BNDSCBackingCache* caches, size_t count);
+
+ SHAREDCACHE_FFI_API void BNDSCFindSymbolAtAddressAndApplyToAddress(BNSharedCache* cache, uint64_t symbolLocation, uint64_t targetLocation, bool triggerReanalysis);
+
+ SHAREDCACHE_FFI_API char* BNDSCViewGetImageHeaderForAddress(BNSharedCache* cache, uint64_t address);
+ SHAREDCACHE_FFI_API char* BNDSCViewGetImageHeaderForName(BNSharedCache* cache, char* name);
+
+ [[maybe_unused]] SHAREDCACHE_FFI_API BNDSCMemoryUsageInfo BNDSCViewGetMemoryUsageInfo();
+
+#ifdef __cplusplus
+}
+#endif