diff options
| author | Mason Reed <mason@vector35.com> | 2025-08-26 23:59:38 -0400 |
|---|---|---|
| committer | Mason Reed <mason@vector35.com> | 2025-10-01 21:38:39 -0400 |
| commit | ede39aee7e00c40a43b67ca18dd8ab80ee863d85 (patch) | |
| tree | 67c5eda347ece2282e3c888f38066b496e06dec8 /plugins/warp/api | |
| parent | a1c46813e7f279aa4cfdb9dbb91c45b559ebeacd (diff) | |
[WARP] Enhanced network support
Diffstat (limited to 'plugins/warp/api')
| -rw-r--r-- | plugins/warp/api/python/warp.py | 122 | ||||
| -rw-r--r-- | plugins/warp/api/python/warp_enums.py | 7 | ||||
| -rw-r--r-- | plugins/warp/api/warp.cpp | 113 | ||||
| -rw-r--r-- | plugins/warp/api/warp.h | 96 | ||||
| -rw-r--r-- | plugins/warp/api/warpcore.h | 40 |
5 files changed, 356 insertions, 22 deletions
diff --git a/plugins/warp/api/python/warp.py b/plugins/warp/api/python/warp.py index 66fef872..29537895 100644 --- a/plugins/warp/api/python/warp.py +++ b/plugins/warp/api/python/warp.py @@ -8,6 +8,7 @@ from binaryninja import BinaryView, Function, BasicBlock, Architecture, Platform from binaryninja._binaryninjacore import BNFreeString, BNAllocString, BNType from . import _warpcore as warpcore +from .warp_enums import WARPContainerSearchItemKind class WarpUUID: @@ -195,6 +196,108 @@ class WarpFunction: warpcore.BNWARPFunctionApply(self.handle, function.handle) +class WarpContainerSearchQuery: + def __init__(self, query: str, offset: Optional[int] = None, limit: Optional[int] = None, source: Optional[Source] = None, source_tags: Optional[List[str]] = None): + self.query = query + self.source = source + self.offset = offset + self.limit = limit + offset_ptr = None + if offset is not None: + self._c_offset = ctypes.c_size_t(offset) + offset_ptr = ctypes.byref(self._c_offset) + limit_ptr = None + if limit is not None: + self._c_limit = ctypes.c_size_t(limit) + limit_ptr = ctypes.byref(self._c_limit) + source_ptr = None + if source is not None: + self._c_source = source.uuid + source_ptr = ctypes.byref(self._c_source) + source_tags_len = 0 + source_tags_array_ptr = None + if source_tags is not None: + source_tags_ptr = (ctypes.c_char_p * len(source_tags))() + source_tags_len = len(source_tags) + for i in range(len(source_tags)): + source_tags_ptr[i] = source_tags[i].encode('utf-8') + source_tags_array_ptr = ctypes.cast(source_tags_ptr, ctypes.POINTER(ctypes.c_char_p)) + self.handle = warpcore.BNWARPNewContainerSearchQuery(query, offset_ptr, limit_ptr, source_ptr, source_tags_array_ptr, source_tags_len) + + def __del__(self): + if self.handle is not None: + warpcore.BNWARPFreeContainerSearchQueryReference(self.handle) + + def __repr__(self): + # TODO: Display offset and limit in a pythonic way. + if self.source is None: + return f"<WarpContainerSearchQuery '{self.query}'>" + return f"<WarpContainerSearchQuery '{self.query}': '{self.source}'>" + + +class WarpContainerSearchItem: + def __init__(self, handle: warpcore.BNWARPContainerSearchItem): + self.handle = handle + + def __del__(self): + if self.handle is not None: + warpcore.BNWARPFreeContainerSearchItemReference(self.handle) + + @property + def kind(self) -> WARPContainerSearchItemKind: + return WARPContainerSearchItemKind(warpcore.BNWARPContainerSearchItemGetKind(self.handle)) + + @property + def source(self) -> Source: + return Source(warpcore.BNWARPContainerSearchItemGetSource(self.handle)) + + @property + def name(self) -> str: + return warpcore.BNWARPContainerSearchItemGetName(self.handle) + + def get_type(self, arch: Architecture) -> Optional[Type]: + ty = warpcore.BNWARPContainerSearchItemGetType(arch.handle, self.handle) + if not ty: + return None + return Type(ty) + + @property + def function(self) -> Optional[WarpFunction]: + func = warpcore.BNWARPContainerSearchItemGetFunction(self.handle) + if not func: + return None + return WarpFunction(func) + + def __repr__(self): + return f"<WarpContainerSearchItem '{self.name}': '{self.source}'>" + + +class WarpContainerResponse: + def __init__(self, items: List[WarpContainerSearchItem], offset: int, total: int): + self.items = items + self.offset = offset + self.total = total + + def __iter__(self): + return iter(self.items) + + def __len__(self): + return len(self.items) + + def __repr__(self): + return f"<WarpContainerResponse items={len(self.items)} offset={self.offset} total={self.total}>" + + @staticmethod + def from_api(response: warpcore.BNWARPContainerSearchResponse) -> 'WarpContainerResponse': + try: + items = [] + for i in range(response.count): + items.append(WarpContainerSearchItem(warpcore.BNWARPNewContainerSearchItemReference(response.items[i]))) + return WarpContainerResponse(items=items, offset=response.offset, total=response.total) + finally: + warpcore.BNWARPFreeContainerSearchResponse(response) + + class _WarpContainerMetaclass(type): def __iter__(self): binaryninja._init_plugins() @@ -305,12 +408,19 @@ class WarpContainer(metaclass=_WarpContainerMetaclass): core_guids[i] = guids[i].uuid return warpcore.BNWARPContainerRemoveTypes(self.handle, source.uuid, core_guids, count) - def fetch_functions(self, target: WarpTarget, guids: List[FunctionGUID]): + def fetch_functions(self, target: WarpTarget, guids: List[FunctionGUID], source_tags: Optional[List[str]] = None): count = len(guids) core_guids = (warpcore.BNWARPFunctionGUID * count)() for i in range(count): core_guids[i] = guids[i].uuid - warpcore.BNWARPContainerFetchFunctions(self.handle, target.handle, core_guids, count) + if source_tags is None: + source_tags = [] + source_tags_ptr = (ctypes.c_char_p * len(source_tags))() + source_tags_len = len(source_tags) + for i in range(len(source_tags)): + source_tags_ptr[i] = source_tags[i].encode('utf-8') + source_tags_array_ptr = ctypes.cast(source_tags_ptr, ctypes.POINTER(ctypes.c_char_p)) + warpcore.BNWARPContainerFetchFunctions(self.handle, target.handle, source_tags_array_ptr, source_tags_len, core_guids, count) def get_sources_with_function_guid(self, target: WarpTarget, guid: FunctionGUID) -> List[Source]: count = ctypes.c_size_t() @@ -346,7 +456,7 @@ class WarpContainer(metaclass=_WarpContainerMetaclass): return result def get_type_with_guid(self, arch: Architecture, source: Source, guid: TypeGUID) -> Optional[Type]: - ty = warpcore.BNWARPContainerGetTypeWithGUID(self.handle, arch.handle, source.uuid, guid.uuid) + ty = warpcore.BNWARPContainerGetTypeWithGUID(arch.handle, self.handle, source.uuid, guid.uuid) if not ty: return None return Type(ty) @@ -362,6 +472,12 @@ class WarpContainer(metaclass=_WarpContainerMetaclass): warpcore.BNWARPFreeUUIDList(guids, count.value) return result + def search(self, query: WarpContainerSearchQuery) -> Optional[WarpContainerResponse]: + response = warpcore.BNWARPContainerSearch(self.handle, query.handle) + if not response: + return None + return WarpContainerResponse.from_api(response.contents) + def run_matcher(view: BinaryView): warpcore.BNWARPRunMatcher(view.handle) diff --git a/plugins/warp/api/python/warp_enums.py b/plugins/warp/api/python/warp_enums.py index e47ff1c3..86be3a6c 100644 --- a/plugins/warp/api/python/warp_enums.py +++ b/plugins/warp/api/python/warp_enums.py @@ -1 +1,8 @@ import enum + + +class WARPContainerSearchItemKind(enum.IntEnum): + WARPContainerSearchItemKindSource = 0 + WARPContainerSearchItemKindFunction = 1 + WARPContainerSearchItemKindType = 2 + WARPContainerSearchItemKindSymbol = 3 diff --git a/plugins/warp/api/warp.cpp b/plugins/warp/api/warp.cpp index 52c7ea9d..f6106605 100644 --- a/plugins/warp/api/warp.cpp +++ b/plugins/warp/api/warp.cpp @@ -5,6 +5,14 @@ using namespace Warp; +std::optional<WarpUUID> WarpUUID::FromString(const std::string &str) +{ + BNWARPUUID uuid = {}; + if (!BNWARPUUIDFromString(str.c_str(), &uuid)) + return std::nullopt; + return WarpUUID(uuid); +} + std::string WarpUUID::ToString() const { char *str = BNWARPUUIDGetString(&uuid); @@ -133,6 +141,94 @@ void Function::RemoveMatch(const BinaryNinja::Function &function) BNWARPFunctionApply(nullptr, function.m_object); } +ContainerSearchQuery::ContainerSearchQuery(BNWARPContainerSearchQuery *query) +{ + m_object = query; +} + +ContainerSearchQuery::ContainerSearchQuery(const std::string &query) +{ + m_object = BNWARPNewContainerSearchQuery(query.c_str(), nullptr, nullptr, nullptr, nullptr, 0); +} + +ContainerSearchQuery::ContainerSearchQuery(const std::string &query, const Source &source) +{ + m_object = BNWARPNewContainerSearchQuery(query.c_str(), nullptr, nullptr, source.Raw(), nullptr, 0); +} + +ContainerSearchQuery::ContainerSearchQuery(const std::string &query, size_t offset, size_t limit, const std::optional<Source> &source, const std::vector<SourceTag> &tags) +{ + size_t tagCount = tags.size(); + const char** rawTags = new const char*[tagCount]; + for (size_t i = 0; i < tagCount; i++) + rawTags[i] = tags[i].c_str(); + if (source) + m_object = BNWARPNewContainerSearchQuery(query.c_str(), &offset, &limit, source.value().Raw(), rawTags, tagCount); + else + m_object = BNWARPNewContainerSearchQuery(query.c_str(), &offset, &limit, nullptr, rawTags, tagCount); + delete[] rawTags; +} + +ContainerSearchItem::ContainerSearchItem(BNWARPContainerSearchItem *item) +{ + m_object = item; +} + +BNWARPContainerSearchItemKind ContainerSearchItem::GetKind() const +{ + return BNWARPContainerSearchItemGetKind(m_object); +} + +Source ContainerSearchItem::GetSource() const +{ + return BNWARPContainerSearchItemGetSource(m_object); +} + +BinaryNinja::Ref<BinaryNinja::Type> ContainerSearchItem::GetType(const BinaryNinja::Ref<BinaryNinja::Architecture> &arch) const +{ + BNType *type = BNWARPContainerSearchItemGetType(arch ? arch->m_object : nullptr, m_object); + if (!type) + return nullptr; + return new BinaryNinja::Type(type); +} + +std::string ContainerSearchItem::GetName() const +{ + // NOTE: In the future we may want the name to be optional, see rust core side for more info. + char *rawName = BNWARPContainerSearchItemGetName(m_object); + std::string name = rawName; + BNFreeString(rawName); + return name; +} + +Ref<Function> ContainerSearchItem::GetFunction() const +{ + BNWARPFunction *function = BNWARPContainerSearchItemGetFunction(m_object); + if (!function) + return nullptr; + return new Function(function); +} + + +ContainerSearchResponse::ContainerSearchResponse(std::vector<Ref<ContainerSearchItem>>&& items, size_t offset, + size_t total) +{ + this->items = std::move(items); + this->offset = offset; + this->total = total; +} + +ContainerSearchResponse ContainerSearchResponse::FromAPIObject(BNWARPContainerSearchResponse *response) +{ + std::vector<Ref<ContainerSearchItem>> items; + items.reserve(response->count); + for (int i = 0; i < response->count; i++) + items.push_back(new ContainerSearchItem(BNWARPNewContainerSearchItemReference(response->items[i]))); + ContainerSearchResponse resp = {std::move(items), response->offset, response->total}; + BNWARPFreeContainerSearchResponse(response); + return resp; +} + Container::Container(BNWARPContainer *container) { m_object = container; @@ -249,14 +345,19 @@ bool Container::RemoveTypes(const Source &source, const std::vector<TypeGUID> &g return result; } -void Container::FetchFunctions(const Target &target, const std::vector<FunctionGUID> &guids) const +void Container::FetchFunctions(const Target &target, const std::vector<FunctionGUID> &guids, const std::vector<SourceTag> &tags) const { size_t count = guids.size(); BNWARPFunctionGUID *apiGuids = new BNWARPFunctionGUID[count]; for (size_t i = 0; i < count; i++) apiGuids[i] = *guids[i].Raw(); - BNWARPContainerFetchFunctions(m_object, target.m_object, apiGuids, count); + size_t tagCount = tags.size(); + const char** rawTags = new const char*[tagCount]; + for (size_t i = 0; i < tagCount; i++) + rawTags[i] = tags[i].c_str(); + BNWARPContainerFetchFunctions(m_object, target.m_object, rawTags, tagCount, apiGuids, count); delete[] apiGuids; + delete[] rawTags; } std::vector<Source> Container::GetSourcesWithFunctionGUID(const Target& target, const FunctionGUID &guid) const @@ -314,6 +415,14 @@ std::vector<TypeGUID> Container::GetTypeGUIDsWithName(const Source &source, cons return result; } +std::optional<ContainerSearchResponse> Container::Search(const ContainerSearchQuery &query) const +{ + BNWARPContainerSearchResponse *response = BNWARPContainerSearch(m_object, query.m_object); + if (!response) + return std::nullopt; + return ContainerSearchResponse::FromAPIObject(response); +} + void Warp::RunMatcher(const BinaryNinja::BinaryView &view) { BNWARPRunMatcher(view.m_object); diff --git a/plugins/warp/api/warp.h b/plugins/warp/api/warp.h index 807ba998..14be9a0d 100644 --- a/plugins/warp/api/warp.h +++ b/plugins/warp/api/warp.h @@ -68,7 +68,7 @@ namespace Warp { { T *m_obj; #ifdef BN_REF_COUNT_DEBUG - void* m_assignmentTrace = nullptr; + void *m_assignmentTrace = nullptr; #endif public: @@ -230,8 +230,12 @@ namespace Warp { public: WarpUUID() = default; - - WarpUUID(BNWARPUUID uuid) : uuid(uuid) {} + + WarpUUID(BNWARPUUID uuid) : uuid(uuid) + { + } + + static std::optional<WarpUUID> FromString(const std::string &str); std::string ToString() const; @@ -245,12 +249,12 @@ namespace Warp { return !(*this == other); } - BNWARPUUID* RawMut() + BNWARPUUID *RawMut() { return &uuid; } - const BNWARPUUID* Raw() const + const BNWARPUUID *Raw() const { return &uuid; } @@ -261,6 +265,7 @@ namespace Warp { typedef WarpUUID FunctionGUID; typedef WarpUUID ConstraintGUID; typedef WarpUUID TypeGUID; + typedef std::string SourceTag; class Target : public WarpRefCountObject<BNWARPTarget, BNWARPNewTargetReference, BNWARPFreeTargetReference> @@ -268,9 +273,9 @@ namespace Warp { public: explicit Target(BNWARPTarget *target); - static Ref<Target> FromPlatform(const BinaryNinja::Platform& platform); + static Ref<Target> FromPlatform(const BinaryNinja::Platform &platform); }; - + struct Constraint { ConstraintGUID guid; @@ -278,7 +283,7 @@ namespace Warp { Constraint(ConstraintGUID guid, std::optional<int64_t> offset); - static Constraint FromAPIObject(BNWARPConstraint* constraint); + static Constraint FromAPIObject(BNWARPConstraint *constraint); }; struct FunctionComment @@ -288,7 +293,7 @@ namespace Warp { FunctionComment(std::string text, int64_t offset); - static FunctionComment FromAPIObject(BNWARPFunctionComment* comment); + static FunctionComment FromAPIObject(BNWARPFunctionComment *comment); }; class Function : public WarpRefCountObject<BNWARPFunction, BNWARPNewFunctionReference, BNWARPFreeFunctionReference> @@ -322,6 +327,51 @@ namespace Warp { static void RemoveMatch(const BinaryNinja::Function &function); }; + class ContainerSearchQuery : public WarpRefCountObject<BNWARPContainerSearchQuery, + BNWARPNewContainerSearchQueryReference, + BNWARPFreeContainerSearchQueryReference> + { + public: + explicit ContainerSearchQuery(BNWARPContainerSearchQuery *query); + + explicit ContainerSearchQuery(const std::string &query); + + ContainerSearchQuery(const std::string &query, const Source &source); + + ContainerSearchQuery(const std::string &query, size_t offset, size_t limit, + const std::optional<Source> &source = std::nullopt, + const std::vector<SourceTag> &tags = {}); + }; + + class ContainerSearchItem : public WarpRefCountObject<BNWARPContainerSearchItem, + BNWARPNewContainerSearchItemReference, + BNWARPFreeContainerSearchItemReference> + { + public: + explicit ContainerSearchItem(BNWARPContainerSearchItem *item); + + BNWARPContainerSearchItemKind GetKind() const; + + Source GetSource() const; + + BinaryNinja::Ref<BinaryNinja::Type> GetType(const BinaryNinja::Ref<BinaryNinja::Architecture> &arch) const; + + std::string GetName() const; + + Ref<Function> GetFunction() const; + }; + + struct ContainerSearchResponse + { + std::vector<Ref<ContainerSearchItem> > items; + size_t offset; + size_t total; + + ContainerSearchResponse(std::vector<Ref<ContainerSearchItem> > &&items, size_t offset, size_t total); + + static ContainerSearchResponse FromAPIObject(BNWARPContainerSearchResponse *response); + }; + class Container : public WarpRefCountObject<BNWARPContainer, BNWARPNewContainerReference, BNWARPFreeContainerReference> { @@ -345,36 +395,50 @@ namespace Warp { std::optional<std::string> SourcePath(const Source &source) const; - bool AddFunctions(const Target &target, const Source &source, const std::vector<Ref<Function> > &functions) const; + bool AddFunctions(const Target &target, const Source &source, + const std::vector<Ref<Function> > &functions) const; bool AddTypes(const BinaryNinja::BinaryView &view, const Source &source, const std::vector<BinaryNinja::Ref<BinaryNinja::Type> > &types) const; - bool RemoveFunctions(const Target &target, const Source &source, const std::vector<Ref<Function> > &functions) const; + bool RemoveFunctions(const Target &target, const Source &source, + const std::vector<Ref<Function> > &functions) const; bool RemoveTypes(const Source &source, const std::vector<TypeGUID> &guids) const; - void FetchFunctions(const Target& target, const std::vector<FunctionGUID> &guids) const; + void FetchFunctions(const Target &target, const std::vector<FunctionGUID> &guids, const std::vector<SourceTag> &tags = {}) const; - std::vector<Source> GetSourcesWithFunctionGUID(const Target& target, const FunctionGUID &guid) const; + std::vector<Source> GetSourcesWithFunctionGUID(const Target &target, const FunctionGUID &guid) const; std::vector<Source> GetSourcesWithTypeGUID(const TypeGUID &guid) const; - std::vector<Ref<Function> > GetFunctionsWithGUID(const Target& target, const Source &source, const FunctionGUID &guid) const; + std::vector<Ref<Function> > GetFunctionsWithGUID(const Target &target, const Source &source, + const FunctionGUID &guid) const; BinaryNinja::Ref<BinaryNinja::Type> GetTypeWithGUID(const BinaryNinja::Architecture &arch, const Source &source, const TypeGUID &guid) const; std::vector<TypeGUID> GetTypeGUIDsWithName(const Source &source, const std::string &name) const; + + std::optional<ContainerSearchResponse> Search(const ContainerSearchQuery &query) const; }; - void RunMatcher(const BinaryNinja::BinaryView& view); + void RunMatcher(const BinaryNinja::BinaryView &view); bool IsInstructionVariant(const BinaryNinja::LowLevelILFunction &function, BinaryNinja::ExprId idx); bool IsInstructionBlacklisted(const BinaryNinja::LowLevelILFunction &function, BinaryNinja::ExprId idx); - + std::optional<FunctionGUID> GetAnalysisFunctionGUID(const BinaryNinja::Function &function); std::optional<BasicBlockGUID> GetBasicBlockGUID(const BinaryNinja::BasicBlock &basicBlock); } + +template<> struct std::hash<Warp::WarpUUID> +{ + size_t operator()(Warp::WarpUUID const& item) const noexcept + { + // TODO: Use the raw bytes instead. + return std::hash<std::string>()(item.ToString()); + } +};
\ No newline at end of file diff --git a/plugins/warp/api/warpcore.h b/plugins/warp/api/warpcore.h index 20a59b7b..b62f2427 100644 --- a/plugins/warp/api/warpcore.h +++ b/plugins/warp/api/warpcore.h @@ -61,6 +61,7 @@ extern "C" }; char* BNWARPUUIDGetString(const BNWARPUUID* uuid); + bool BNWARPUUIDFromString(const char* str, BNWARPUUID* uuid); bool BNWARPUUIDEqual(const BNWARPUUID* a, const BNWARPUUID* b); void BNWARPFreeUUIDList(BNWARPUUID* uuids, size_t count); @@ -74,6 +75,24 @@ extern "C" typedef struct BNWARPContainer BNWARPContainer; typedef struct BNWARPFunction BNWARPFunction; typedef struct BNWARPConstraint BNWARPConstraint; + typedef struct BNWARPContainerSearchQuery BNWARPContainerSearchQuery; + typedef struct BNWARPContainerSearchItem BNWARPContainerSearchItem; + + enum BNWARPContainerSearchItemKind + { + WARPContainerSearchItemKindSource = 0, + WARPContainerSearchItemKindFunction = 1, + WARPContainerSearchItemKindType = 2, + WARPContainerSearchItemKindSymbol = 3, + }; + + struct BNWARPContainerSearchResponse + { + size_t count; + BNWARPContainerSearchItem** items; + size_t offset; + size_t total; + }; struct BNWARPConstraint { @@ -108,7 +127,7 @@ extern "C" WARP_FFI_API bool BNWARPContainerRemoveFunctions(BNWARPContainer* container, const BNWARPTarget* target, const BNWARPSource* source, BNWARPFunction** functions, size_t count); WARP_FFI_API bool BNWARPContainerRemoveTypes(BNWARPContainer* container, const BNWARPSource* source, BNWARPTypeGUID* types, size_t count); - WARP_FFI_API void BNWARPContainerFetchFunctions(BNWARPContainer* container, BNWARPTarget* target, const BNWARPTypeGUID* guids, size_t count); + WARP_FFI_API void BNWARPContainerFetchFunctions(BNWARPContainer* container, BNWARPTarget* target, const char** sourceTags, size_t sourceTagCount, const BNWARPTypeGUID* guids, size_t count); WARP_FFI_API BNWARPSource* BNWARPContainerGetSourcesWithFunctionGUID(BNWARPContainer* container, const BNWARPTarget* target, const BNWARPFunctionGUID* guid, size_t* count); WARP_FFI_API BNWARPSource* BNWARPContainerGetSourcesWithTypeGUID(BNWARPContainer* container, const BNWARPTypeGUID* guid, size_t* count); @@ -120,6 +139,25 @@ extern "C" WARP_FFI_API void BNWARPFreeContainerReference(BNWARPContainer* container); WARP_FFI_API void BNWARPFreeContainerList(BNWARPContainer** containers, size_t count); + WARP_FFI_API BNWARPContainerSearchQuery* BNWARPNewContainerSearchQuery(const char* query, const size_t* offset, const size_t* limit, const BNWARPSource* source, const char** sourceTags, size_t sourceTagCount); + + WARP_FFI_API BNWARPContainerSearchResponse* BNWARPContainerSearch(BNWARPContainer* container, const BNWARPContainerSearchQuery* query); + + WARP_FFI_API BNWARPContainerSearchItemKind BNWARPContainerSearchItemGetKind(BNWARPContainerSearchItem* item); + WARP_FFI_API BNWARPSource BNWARPContainerSearchItemGetSource(BNWARPContainerSearchItem* item); + WARP_FFI_API BNType* BNWARPContainerSearchItemGetType(BNArchitecture* arch, BNWARPContainerSearchItem* item); + WARP_FFI_API char* BNWARPContainerSearchItemGetName(BNWARPContainerSearchItem* item); + WARP_FFI_API BNWARPFunction* BNWARPContainerSearchItemGetFunction(BNWARPContainerSearchItem* item); + + WARP_FFI_API BNWARPContainerSearchQuery* BNWARPNewContainerSearchQueryReference(BNWARPContainerSearchQuery* query); + WARP_FFI_API void BNWARPFreeContainerSearchQueryReference(BNWARPContainerSearchQuery* query); + + WARP_FFI_API BNWARPContainerSearchItem* BNWARPNewContainerSearchItemReference(BNWARPContainerSearchItem* item); + WARP_FFI_API void BNWARPFreeContainerSearchItemReference(BNWARPContainerSearchItem* item); + WARP_FFI_API void BNWARPFreeContainerSearchItemList(BNWARPContainerSearchItem** items, size_t count); + + WARP_FFI_API void BNWARPFreeContainerSearchResponse(BNWARPContainerSearchResponse* response); + WARP_FFI_API void BNWARPFunctionApply(BNWARPFunction* function, BNFunction* analysisFunction); WARP_FFI_API BNWARPFunctionGUID BNWARPFunctionGetGUID(BNWARPFunction* function); WARP_FFI_API BNSymbol* BNWARPFunctionGetSymbol(BNWARPFunction* function, BNFunction* analysisFunction); |
