diff options
| author | Josh Ferrell <josh@vector35.com> | 2020-02-07 20:06:11 -0500 |
|---|---|---|
| committer | Josh Ferrell <josh@vector35.com> | 2020-03-31 13:29:35 -0400 |
| commit | 95b145165e424d69554d03d4ebcf4cc13d43ec88 (patch) | |
| tree | 18e40ebfbb940986d8bbc990281f317fc88f0091 | |
| parent | fa1de9cc465473fb00f0f47f91aba0a1792a60ee (diff) | |
Undobuffer merging and mergetool
| -rw-r--r-- | binaryninjaapi.h | 68 | ||||
| -rw-r--r-- | binaryninjacore.h | 51 | ||||
| -rw-r--r-- | binaryview.cpp | 6 | ||||
| -rw-r--r-- | filemetadata.cpp | 166 | ||||
| -rw-r--r-- | python/filemetadata.py | 5 | ||||
| -rw-r--r-- | undoaction.cpp | 48 | ||||
| -rw-r--r-- | user.cpp | 49 |
7 files changed, 240 insertions, 153 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index a3bf8578..8267cbb8 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -832,46 +832,46 @@ __attribute__ ((format (printf, 1, 2))) class BinaryView; - class UndoAction + class User : public CoreRefCountObject<BNUser, BNNewUserReference, BNFreeUser> { - private: - std::string m_typeName; - BNActionType m_actionType; - - static void FreeCallback(void* ctxt); - static void UndoCallback(void* ctxt, BNBinaryView* data); - static void RedoCallback(void* ctxt, BNBinaryView* data); - static char* SerializeCallback(void* ctxt); - - public: - UndoAction(const std::string& name, BNActionType action); - virtual ~UndoAction() {} + private: + std::string m_id; + std::string m_name; + std::string m_email; + public: + User(BNUser* user); + std::string GetName(); + std::string GetEmail(); + std::string GetId(); + }; - const std::string& GetTypeName() const { return m_typeName; } - BNActionType GetActionType() const { return m_actionType; } - BNUndoAction GetCallbacks(); + struct InstructionTextToken; - void Add(BNBinaryView* view); + struct UndoAction + { + BNActionType actionType; + std::string summaryText; + std::vector<InstructionTextToken> summaryTokens; - virtual void Undo(BinaryView* data) = 0; - virtual void Redo(BinaryView* data) = 0; - virtual Json::Value Serialize() = 0; + UndoAction() {}; + UndoAction(const BNUndoAction& action); }; - class UndoActionType + struct UndoEntry { - protected: - std::string m_nameForRegister; - - static bool DeserializeCallback(void* ctxt, const char* data, BNUndoAction* result); - - public: - UndoActionType(const std::string& name); - virtual ~UndoActionType() {} + Ref<User> user; + std::string hash; + std::vector<UndoAction> actions; + uint64_t timestamp; + }; - static void Register(UndoActionType* type); + struct MergeResult + { + BNMergeStatus status; + UndoAction action; + std::string hash; - virtual UndoAction* Deserialize(const Json::Value& data) = 0; + MergeResult(const BNMergeResult& result); }; class FileMetadata: public CoreRefCountObject<BNFileMetadata, BNNewFileReference, BNFreeFileMetadata> @@ -911,12 +911,18 @@ __attribute__ ((format (printf, 1, 2))) bool Rebase(BinaryView* data, uint64_t address); bool Rebase(BinaryView* data, uint64_t address, const std::function<void(size_t progress, size_t total)>& progressCallback); + MergeResult MergeUserAnalysis(const std::string& name, const std::function<void(size_t, size_t)>& progress, + const std::vector<std::string> excludedHashes = {} ); + void BeginUndoActions(); void CommitUndoActions(); bool Undo(); bool Redo(); + std::vector<Ref<User>> GetUsers(); + std::vector<UndoEntry> GetUndoEntries(); + std::string GetCurrentView(); uint64_t GetCurrentOffset(); bool Navigate(const std::string& view, uint64_t offset); diff --git a/binaryninjacore.h b/binaryninjacore.h index 2a6f782b..bb872f8d 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -142,6 +142,7 @@ extern "C" struct BNTagType; struct BNTag; struct BNTagReference; + struct BNUser; struct BNNamedTypeReference; struct BNEnumeration; struct BNEnumerationBuilder; @@ -1438,12 +1439,33 @@ extern "C" struct BNUndoAction { - BNActionType type; - void* context; - void (*freeObject)(void* ctxt); - void (*undo)(void* ctxt, BNBinaryView* data); - void (*redo)(void* ctxt, BNBinaryView* data); - char* (*serialize)(void* ctxt); + BNActionType actionType; + char* summaryText; + BNInstructionTextToken* summaryTokens; + size_t summaryTokenCount; + }; + + struct BNUndoEntry + { + BNUser* user; + char* hash; + BNUndoAction* actions; + uint64_t actionCount; + uint64_t timestamp; + }; + + enum BNMergeStatus + { + NOT_APPLICABLE = 0, + OK = 1, + CONFLICT = 2 + }; + + struct BNMergeResult + { + BNMergeStatus status; + BNUndoAction action; + const char* hash; }; struct BNCallingConventionWithConfidence @@ -2221,21 +2243,32 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI bool BNRebase(BNBinaryView* data, uint64_t address); BINARYNINJACOREAPI bool BNRebaseWithProgress(BNBinaryView* data, uint64_t address, void* ctxt, void (*progress)(void* ctxt, size_t progress, size_t total)); + BINARYNINJACOREAPI BNMergeResult BNMergeUserAnalysis(BNFileMetadata* file, const char* name, void* ctxt, void (*progress)(void* ctxt, size_t progress, size_t total), + char** excludedHashes, size_t excludedHashesCount); + BINARYNINJACOREAPI char* BNGetOriginalFilename(BNFileMetadata* file); BINARYNINJACOREAPI void BNSetOriginalFilename(BNFileMetadata* file, const char* name); BINARYNINJACOREAPI char* BNGetFilename(BNFileMetadata* file); BINARYNINJACOREAPI void BNSetFilename(BNFileMetadata* file, const char* name); - BINARYNINJACOREAPI void BNRegisterUndoActionType(const char* name, void* typeContext, - bool (*deserialize)(void* ctxt, const char* data, BNUndoAction* result)); BINARYNINJACOREAPI void BNBeginUndoActions(BNFileMetadata* file); - BINARYNINJACOREAPI void BNAddUndoAction(BNBinaryView* view, const char* type, BNUndoAction* action); BINARYNINJACOREAPI void BNCommitUndoActions(BNFileMetadata* file); BINARYNINJACOREAPI bool BNUndo(BNFileMetadata* file); BINARYNINJACOREAPI bool BNRedo(BNFileMetadata* file); + BINARYNINJACOREAPI BNUndoEntry* BNGetUndoEntries(BNFileMetadata* file, size_t* count); + BINARYNINJACOREAPI void BNFreeUndoEntries(BNUndoEntry* entries, size_t count); + + BINARYNINJACOREAPI BNUser* BNNewUserReference(BNUser* user); + BINARYNINJACOREAPI void BNFreeUser(BNUser* user); + BINARYNINJACOREAPI BNUser** BNGetUsers(BNFileMetadata* file, size_t* count); + BINARYNINJACOREAPI void BNFreeUserList(BNUser** users, size_t count); + BINARYNINJACOREAPI char* BNGetUserName(BNUser* user); + BINARYNINJACOREAPI char* BNGetUserEmail(BNUser* user); + BINARYNINJACOREAPI char* BNGetUserId(BNUser* user); + BINARYNINJACOREAPI char* BNGetCurrentView(BNFileMetadata* file); BINARYNINJACOREAPI uint64_t BNGetCurrentOffset(BNFileMetadata* file); BINARYNINJACOREAPI bool BNNavigate(BNFileMetadata* file, const char* view, uint64_t offset); diff --git a/binaryview.cpp b/binaryview.cpp index b05f4d02..5c0dd951 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1154,12 +1154,6 @@ void BinaryView::BeginUndoActions() } -void BinaryView::AddUndoAction(UndoAction* action) -{ - action->Add(m_object); -} - - void BinaryView::CommitUndoActions() { m_file->CommitUndoActions(); diff --git a/filemetadata.cpp b/filemetadata.cpp index a8fb8889..e9433b15 100644 --- a/filemetadata.cpp +++ b/filemetadata.cpp @@ -69,113 +69,6 @@ NavigationHandler::NavigationHandler() } -void UndoAction::FreeCallback(void* ctxt) -{ - UndoAction* action = (UndoAction*)ctxt; - delete action; -} - - -void UndoAction::UndoCallback(void* ctxt, BNBinaryView* data) -{ - UndoAction* action = (UndoAction*)ctxt; - Ref<BinaryView> view = new BinaryView(BNNewViewReference(data)); - action->Undo(view); -} - - -void UndoAction::RedoCallback(void* ctxt, BNBinaryView* data) -{ - UndoAction* action = (UndoAction*)ctxt; - Ref<BinaryView> view = new BinaryView(BNNewViewReference(data)); - action->Redo(view); -} - - -char* UndoAction::SerializeCallback(void* ctxt) -{ - try - { - UndoAction* action = (UndoAction*)ctxt; - Value data = action->Serialize(); - Json::StreamWriterBuilder builder; - builder["indentation"] = ""; - string json = Json::writeString(builder, data); - return BNAllocString(json.c_str()); - } - catch (exception& e) - { - LogError("Undo action failed to serialize: %s", e.what()); - return nullptr; - } -} - - -UndoAction::UndoAction(const string& name, BNActionType action): m_typeName(name), m_actionType(action) -{ -} - - -BNUndoAction UndoAction::GetCallbacks() -{ - BNUndoAction action; - action.type = m_actionType; - action.context = this; - action.freeObject = FreeCallback; - action.undo = UndoCallback; - action.redo = RedoCallback; - action.serialize = SerializeCallback; - return action; -} - - -void UndoAction::Add(BNBinaryView* view) -{ - BNUndoAction action = GetCallbacks(); - BNAddUndoAction(view, m_typeName.c_str(), &action); -} - - -bool UndoActionType::DeserializeCallback(void* ctxt, const char* data, BNUndoAction* result) -{ - try - { - UndoActionType* type = (UndoActionType*)ctxt; - unique_ptr<CharReader> reader(CharReaderBuilder().newCharReader()); - Value val; - string errors; - if (!reader->parse(data, data + strlen(data), &val, &errors)) - { - LogError("Invalid JSON while deserializing undo action"); - return false; - } - - UndoAction* action = type->Deserialize(val); - if (!action) - return false; - - *result = action->GetCallbacks(); - return true; - } - catch (exception& e) - { - LogError("Error while deserializing undo action: %s", e.what()); - return false; - } -} - - -UndoActionType::UndoActionType(const string& name): m_nameForRegister(name) -{ -} - - -void UndoActionType::Register(UndoActionType* type) -{ - BNRegisterUndoActionType(type->m_nameForRegister.c_str(), type, DeserializeCallback); -} - - FileMetadata::FileMetadata() { m_object = BNCreateFileMetadata(); @@ -344,6 +237,25 @@ bool FileMetadata::Rebase(BinaryView* data, uint64_t address, const function<voi } +MergeResult FileMetadata::MergeUserAnalysis(const std::string& name, const std::function<void(size_t, size_t)>& progress, std::vector<string> excludedHashes) +{ + size_t numHashes = excludedHashes.size(); + char** tempList = new char*[numHashes]; + for (size_t i = 0; i < numHashes; i++) + { + tempList[i] = BNAllocString(excludedHashes[i].c_str()); + } + + DatabaseProgressCallbackContext cb; + cb.func = progress; + + BNMergeResult bnResult = BNMergeUserAnalysis(m_object, name.c_str(), &cb, DatabaseProgressCallback, tempList, numHashes); + //BNFreeStringList(hashList, numHashes); + MergeResult result(bnResult); + return result; +} + + void FileMetadata::BeginUndoActions() { BNBeginUndoActions(m_object); @@ -367,6 +279,46 @@ bool FileMetadata::Redo() return BNRedo(m_object); } +vector<Ref<User>> FileMetadata::GetUsers() +{ + size_t count; + BNUser** users = BNGetUsers(m_object, &count); + + vector<Ref<User>> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.push_back(new User(BNNewUserReference(users[i]))); + + BNFreeUserList(users, count); + return result; +} + + +vector<UndoEntry> FileMetadata::GetUndoEntries() +{ + size_t numEntries; + BNUndoEntry* entries = BNGetUndoEntries(m_object, &numEntries); + + vector<UndoEntry> result; + result.reserve(numEntries); + for (size_t i = 0; i < numEntries; i++) + { + UndoEntry temp; + temp.timestamp = entries[i].timestamp; + temp.hash = entries[i].hash; + temp.user = new User(BNNewUserReference(entries[i].user)); + size_t actionCount = entries[i].actionCount; + for (size_t actionIndex = 0; actionIndex < actionCount; actionIndex++) + { + temp.actions.emplace_back(entries[i].actions[actionIndex]); + } + result.push_back(temp); + } + + //BNFreeUndoEntries(entries, count); + return result; +} + string FileMetadata::GetCurrentView() { diff --git a/python/filemetadata.py b/python/filemetadata.py index 9e6e6fd1..ce88fdce 100644 --- a/python/filemetadata.py +++ b/python/filemetadata.py @@ -358,6 +358,11 @@ class FileMetadata(object): ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)( lambda ctxt, cur, total: progress_func(cur, total)), clean) + def merge_database(self, path, progress_func = None): + return core.BNMergeUndo(self.handle, str(path), None, + ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)( + lambda ctxt, cur, total: progress_func(cur, total))) + def get_view_of_type(self, name): view = core.BNGetFileViewOfType(self.handle, str(name)) if view is None: diff --git a/undoaction.cpp b/undoaction.cpp new file mode 100644 index 00000000..4489eb5a --- /dev/null +++ b/undoaction.cpp @@ -0,0 +1,48 @@ +// Copyright (c) 2015-2020 Vector 35 Inc +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +#include <cstring> +#include "binaryninjaapi.h" + +using namespace BinaryNinja; +using namespace Json; +using namespace std; + + +UndoAction::UndoAction(const BNUndoAction& action) +{ + actionType = action.actionType; + summaryText = action.summaryText; + summaryTokens.reserve(action.summaryTokenCount); + for (size_t i = 0; i < action.summaryTokenCount; i++) + { + summaryTokens.push_back(action.summaryTokens[i]); + } +} + + +MergeResult::MergeResult(const BNMergeResult& result) +{ + status = result.status; + if (status == BNMergeStatus::CONFLICT) + { + action = result.action; + hash = result.hash; + } +}; diff --git a/user.cpp b/user.cpp new file mode 100644 index 00000000..206238ed --- /dev/null +++ b/user.cpp @@ -0,0 +1,49 @@ +// Copyright (c) 2015-2020 Vector 35 Inc +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +#include <cstring> +#include "binaryninjaapi.h" + +using namespace BinaryNinja; +using namespace Json; +using namespace std; + + +User::User(BNUser* user) +{ + m_object = user; +} + + +string User::GetName() +{ + return BNGetUserName(m_object); +} + + +string User::GetEmail() +{ + return BNGetUserEmail(m_object); +} + + +string User::GetId() +{ + return BNGetUserId(m_object); +} |
