diff options
| author | Glenn Smith <couleeapps@gmail.com> | 2019-05-28 13:47:14 -0400 |
|---|---|---|
| committer | Glenn Smith <glenn@vector35.com> | 2019-08-01 18:36:03 -0400 |
| commit | 087fdd83b85dd894d5b895557a378bb01828d0ff (patch) | |
| tree | 8f9846be65885fa97cf934aa2e7dbd22cf150765 | |
| parent | 9bb1a15b800da0ac5b60c40e3b10321e4efc5a1b (diff) | |
Tags
| -rw-r--r-- | architecture.cpp | 45 | ||||
| -rw-r--r-- | basicblock.cpp | 1 | ||||
| -rw-r--r-- | binaryninjaapi.h | 135 | ||||
| -rw-r--r-- | binaryninjacore.h | 97 | ||||
| -rw-r--r-- | binaryview.cpp | 459 | ||||
| -rw-r--r-- | datarenderer.cpp | 4 | ||||
| -rw-r--r-- | flowgraphnode.cpp | 2 | ||||
| -rw-r--r-- | function.cpp | 232 | ||||
| -rw-r--r-- | python/binaryview.py | 297 | ||||
| -rw-r--r-- | python/function.py | 250 | ||||
| -rw-r--r-- | ui/action.h | 12 | ||||
| -rw-r--r-- | ui/flowgraphwidget.h | 5 | ||||
| -rw-r--r-- | ui/linearview.h | 5 | ||||
| -rw-r--r-- | ui/taglist.h | 231 | ||||
| -rw-r--r-- | ui/tagtypelist.h | 142 | ||||
| -rw-r--r-- | ui/uitypes.h | 2 | ||||
| -rw-r--r-- | ui/viewframe.h | 5 |
17 files changed, 1905 insertions, 19 deletions
diff --git a/architecture.cpp b/architecture.cpp index ae665e08..cd84dd05 100644 --- a/architecture.cpp +++ b/architecture.cpp @@ -49,38 +49,54 @@ void InstructionInfo::AddBranch(BNBranchType type, uint64_t target, Architecture } -InstructionTextToken::InstructionTextToken(): type(TextToken), value(0), confidence(BN_FULL_CONFIDENCE) +InstructionTextToken::InstructionTextToken(): type(TextToken), value(0), width(WidthIsByteCount), confidence(BN_FULL_CONFIDENCE) { + if (width == WidthIsByteCount) + { + width = text.size(); + } } InstructionTextToken::InstructionTextToken(BNInstructionTextTokenType t, const std::string& txt, uint64_t val, - size_t s, size_t o, uint8_t c, const vector<string>& n) : type(t), text(txt), value(val), size(s), operand(o), context(NoTokenContext), - confidence(c), address(0), typeNames(n) + size_t s, size_t o, uint8_t c, const vector<string>& n, uint64_t w) : type(t), text(txt), value(val), width(w), size(s), operand(o), + context(NoTokenContext), confidence(c), address(0), typeNames(n) { + if (width == WidthIsByteCount) + { + width = text.size(); + } } InstructionTextToken::InstructionTextToken(BNInstructionTextTokenType t, BNInstructionTextTokenContext ctxt, - const string& txt, uint64_t a, uint64_t val, size_t s, size_t o, uint8_t c, const vector<string>& n): - type(t), text(txt), value(val), size(s), operand(o), context(ctxt), confidence(c), address(a), typeNames(n) + const string& txt, uint64_t a, uint64_t val, size_t s, size_t o, uint8_t c, const vector<string>& n, uint64_t w): + type(t), text(txt), value(val), width(w), size(s), operand(o), context(ctxt), confidence(c), address(a), typeNames(n) { + if (width == WidthIsByteCount) + { + width = text.size(); + } } InstructionTextToken::InstructionTextToken(const BNInstructionTextToken& token): - type(token.type), text(token.text), value(token.value), size(token.size), operand(token.operand), - context(token.context), confidence(token.confidence), address(token.address) + type(token.type), text(token.text), value(token.value), width(token.width), size(token.size), + operand(token.operand), context(token.context), confidence(token.confidence), address(token.address) { typeNames.reserve(token.namesCount); for (size_t j = 0; j < token.namesCount; j++) typeNames.push_back(token.typeNames[j]); + if (width == WidthIsByteCount) + { + width = text.size(); + } } InstructionTextToken InstructionTextToken::WithConfidence(uint8_t conf) { - return InstructionTextToken(type, context, text, address, value, size, operand, conf, typeNames); + return InstructionTextToken(type, context, text, address, value, size, operand, conf, typeNames, width); } @@ -89,6 +105,7 @@ static void ConvertInstructionTextToken(const InstructionTextToken& token, BNIns result->type = token.type; result->text = BNAllocString(token.text.c_str()); result->value = token.value; + result->width = token.width; result->size = token.size; result->operand = token.operand; result->context = token.context; @@ -2322,6 +2339,7 @@ bool DisassemblyTextRenderer::GetDisassemblyText(uint64_t addr, size_t& len, vec line.instrIndex = result[i].instrIndex; line.highlight = result[i].highlight; line.tokens = InstructionTextToken::ConvertAndFreeInstructionTextTokenList(result[i].tokens, result[i].count); + line.tags = Tag::ConvertAndFreeTagList(result[i].tags, result[i].tagCount); lines.push_back(line); } @@ -2405,6 +2423,7 @@ void DisassemblyTextRenderer::WrapComment(DisassemblyTextLine& line, vector<Disa inLine.highlight = line.highlight; inLine.count = line.tokens.size(); inLine.tokens = InstructionTextToken::CreateInstructionTextTokenList(line.tokens); + inLine.tags = Tag::CreateTagList(line.tags, &inLine.tagCount); size_t count = 0; BNDisassemblyTextLine* result = BNDisassemblyTextRendererWrapComment(m_object, &inLine, &count, @@ -2417,16 +2436,10 @@ void DisassemblyTextRenderer::WrapComment(DisassemblyTextLine& line, vector<Disa line.instrIndex = result[i].instrIndex; line.highlight = result[i].highlight; line.tokens = InstructionTextToken::ConvertAndFreeInstructionTextTokenList(result[i].tokens, result[i].count); + line.tags = Tag::ConvertAndFreeTagList(result[i].tags, result[i].tagCount); lines.push_back(line); } BNFreeDisassemblyTextLines(result, count); - for (size_t i = 0; i < inLine.count; i++) - { - BNFreeString(inLine.tokens[i].text); - for (size_t j = 0; j < inLine.tokens[j].namesCount; j++) - BNFreeString(inLine.tokens[i].typeNames[j]); - delete[] inLine.tokens[i].typeNames; - } - delete[] inLine.tokens; + BNFreeInstructionText(inLine.tokens, inLine.count); } diff --git a/basicblock.cpp b/basicblock.cpp index c34a4bb7..03a2386f 100644 --- a/basicblock.cpp +++ b/basicblock.cpp @@ -296,6 +296,7 @@ vector<DisassemblyTextLine> BasicBlock::GetDisassemblyText(DisassemblySettings* line.instrIndex = lines[i].instrIndex; line.highlight = lines[i].highlight; line.tokens = InstructionTextToken::ConvertAndFreeInstructionTextTokenList(lines[i].tokens, lines[i].count); + line.tags = Tag::ConvertAndFreeTagList(lines[i].tags, lines[i].tagCount); result.push_back(line); } diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 25c32b1c..02dc26c2 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -881,6 +881,7 @@ namespace BinaryNinja class Function; struct DataVariable; class Symbol; + class Tag; class BinaryDataNotification { @@ -1090,9 +1091,15 @@ namespace BinaryNinja struct InstructionTextToken { + enum + { + WidthIsByteCount = 0 + }; + BNInstructionTextTokenType type; std::string text; uint64_t value; + uint64_t width; size_t size, operand; BNInstructionTextTokenContext context; uint8_t confidence; @@ -1103,10 +1110,10 @@ namespace BinaryNinja InstructionTextToken(uint8_t confidence, BNInstructionTextTokenType t, const std::string& txt); InstructionTextToken(BNInstructionTextTokenType type, const std::string& text, uint64_t value = 0, size_t size = 0, size_t operand = BN_INVALID_OPERAND, uint8_t confidence = BN_FULL_CONFIDENCE, - const std::vector<std::string>& typeName={}); + const std::vector<std::string>& typeName={}, uint64_t width = WidthIsByteCount); InstructionTextToken(BNInstructionTextTokenType type, BNInstructionTextTokenContext context, const std::string& text, uint64_t address, uint64_t value = 0, size_t size = 0, - size_t operand = BN_INVALID_OPERAND, uint8_t confidence = BN_FULL_CONFIDENCE, const std::vector<std::string>& typeName={}); + size_t operand = BN_INVALID_OPERAND, uint8_t confidence = BN_FULL_CONFIDENCE, const std::vector<std::string>& typeName={}, uint64_t width = WidthIsByteCount); InstructionTextToken(const BNInstructionTextToken& token); InstructionTextToken WithConfidence(uint8_t conf); @@ -1116,12 +1123,14 @@ namespace BinaryNinja }; + class Tag; struct DisassemblyTextLine { uint64_t addr; size_t instrIndex; std::vector<InstructionTextToken> tokens; BNHighlightColor highlight; + std::vector<Ref<Tag>> tags; DisassemblyTextLine(); }; @@ -1187,6 +1196,67 @@ namespace BinaryNinja bool autoDiscovered; }; + class TagType: public CoreRefCountObject<BNTagType, BNNewTagTypeReference, BNFreeTagType> + { + public: + typedef BNTagTypeType Type; + + TagType(BNTagType* tagType); + TagType(BinaryView* view); + TagType(BinaryView* view, const std::string& name, const std::string& icon, bool visible = true, Type type = UserTagType); + + BinaryView* GetView() const; + std::string GetName() const; + void SetName(const std::string& name); + std::string GetIcon() const; + void SetIcon(const std::string& icon); + bool GetVisible() const; + void SetVisible(bool visible); + Type GetType() const; + void SetType(Type type); + }; + + class Tag: public CoreRefCountObject<BNTag, BNNewTagReference, BNFreeTag> + { + public: + Tag(BNTag* tag); + Tag(Ref<TagType> type, const std::string& data = ""); + + Ref<TagType> GetType() const; + std::string GetData() const; + void SetData(const std::string& data); + + static BNTag** CreateTagList(const std::vector<Ref<Tag>>& tags, size_t* count); + static std::vector<Ref<Tag>> ConvertTagList(BNTag** tags, size_t count); + static std::vector<Ref<Tag>> ConvertAndFreeTagList(BNTag** tags, size_t count); + }; + + class Architecture; + class Function; + struct TagReference + { + typedef BNTagReferenceType RefType; + + RefType refType; + bool autoDefined; + Ref<Tag> tag; + Ref<Architecture> arch; + Ref<Function> func; + uint64_t addr; + + TagReference(); + TagReference(const BNTagReference& ref); + + bool operator==(const TagReference& other) const; + bool operator!=(const TagReference& other) const; + + operator BNTagReference() const; + + static BNTagReference* CreateTagReferenceList(const std::vector<TagReference>& tags, size_t* count); + static std::vector<TagReference> ConvertTagReferenceList(BNTagReference* tags, size_t count); + static std::vector<TagReference> ConvertAndFreeTagReferenceList(BNTagReference* tags, size_t count); + }; + class Relocation; class Segment: public CoreRefCountObject<BNSegment, BNNewSegmentReference, BNFreeSegment> { @@ -1456,6 +1526,38 @@ namespace BinaryNinja void DefineImportedFunction(Ref<Symbol> importAddressSym, Ref<Function> func); + void AddTagType(Ref<TagType> tagType); + void RemoveTagType(Ref<TagType> tagType); + Ref<TagType> GetTagType(const std::string& name); + Ref<TagType> GetTagType(const std::string& name, TagType::Type type); + std::vector<Ref<TagType>> GetTagTypes(); + + void AddTag(Ref<Tag> tag); + void RemoveTag(Ref<Tag> tag); + Ref<Tag> GetTag(uint64_t tagId); + + std::vector<TagReference> GetAllTagReferences(); + std::vector<TagReference> GetAllAddressTagReferences(); + std::vector<TagReference> GetAllFunctionTagReferences(); + std::vector<TagReference> GetAllTagReferencesOfType(Ref<TagType> tagType); + std::vector<TagReference> GetTagReferencesOfType(Ref<TagType> tagType); + + std::vector<TagReference> GetDataTagReferences(); + std::vector<Ref<Tag>> GetDataTags(uint64_t addr); + std::vector<Ref<Tag>> GetDataTagsOfType(uint64_t addr, Ref<TagType> tagType); + std::vector<Ref<Tag>> GetDataTagsInRange(uint64_t start, uint64_t end); + void AddAutoDataTag(uint64_t addr, Ref<Tag> tag); + void RemoveAutoDataTag(uint64_t addr, Ref<Tag> tag); + void AddUserDataTag(uint64_t addr, Ref<Tag> tag); + void RemoveUserDataTag(uint64_t addr, Ref<Tag> tag); + void RemoveTagReference(const TagReference& ref); + + Ref<Tag> CreateAutoDataTag(uint64_t addr, const std::string& tagTypeName, const std::string& data, bool unique = false); + Ref<Tag> CreateUserDataTag(uint64_t addr, const std::string& tagTypeName, const std::string& data, bool unique = false); + + Ref<Tag> CreateAutoDataTag(uint64_t addr, Ref<TagType> tagType, const std::string& data, bool unique = false); + Ref<Tag> CreateUserDataTag(uint64_t addr, Ref<TagType> tagType, const std::string& data, bool unique = false); + bool IsNeverBranchPatchAvailable(Architecture* arch, uint64_t addr); bool IsAlwaysBranchPatchAvailable(Architecture* arch, uint64_t addr); bool IsInvertBranchPatchAvailable(Architecture* arch, uint64_t addr); @@ -2748,6 +2850,35 @@ namespace BinaryNinja void SetUserInstructionHighlight(Architecture* arch, uint64_t addr, uint8_t r, uint8_t g, uint8_t b, uint8_t alpha = 255); + std::vector<TagReference> GetAllTagReferences(); + std::vector<TagReference> GetTagReferencesOfType(Ref<TagType> tagType); + + std::vector<TagReference> GetAddressTagReferences(); + std::vector<Ref<Tag>> GetAddressTags(Architecture* arch, uint64_t addr); + std::vector<Ref<Tag>> GetAddressTagsOfType(Architecture* arch, uint64_t addr, Ref<TagType> tagType); + void AddAutoAddressTag(Architecture* arch, uint64_t addr, Ref<Tag> tag); + void RemoveAutoAddressTag(Architecture* arch, uint64_t addr, Ref<Tag> tag); + void AddUserAddressTag(Architecture* arch, uint64_t addr, Ref<Tag> tag); + void RemoveUserAddressTag(Architecture* arch, uint64_t addr, Ref<Tag> tag); + + std::vector<TagReference> GetFunctionTagReferences(); + std::vector<Ref<Tag>> GetFunctionTags(); + std::vector<Ref<Tag>> GetFunctionTagsOfType(Ref<TagType> tagType); + void AddAutoFunctionTag(Ref<Tag> tag); + void RemoveAutoFunctionTag(Ref<Tag> tag); + void AddUserFunctionTag(Ref<Tag> tag); + void RemoveUserFunctionTag(Ref<Tag> tag); + + Ref<Tag> CreateAutoAddressTag(Architecture* arch, uint64_t addr, const std::string& tagTypeName, const std::string& data, bool unique = false); + Ref<Tag> CreateUserAddressTag(Architecture* arch, uint64_t addr, const std::string& tagTypeName, const std::string& data, bool unique = false); + Ref<Tag> CreateAutoFunctionTag(const std::string& tagTypeName, const std::string& data, bool unique = false); + Ref<Tag> CreateUserFunctionTag(const std::string& tagTypeName, const std::string& data, bool unique = false); + + Ref<Tag> CreateAutoAddressTag(Architecture* arch, uint64_t addr, Ref<TagType> tagType, const std::string& data, bool unique = false); + Ref<Tag> CreateUserAddressTag(Architecture* arch, uint64_t addr, Ref<TagType> tagType, const std::string& data, bool unique = false); + Ref<Tag> CreateAutoFunctionTag(Ref<TagType> tagType, const std::string& data, bool unique = false); + Ref<Tag> CreateUserFunctionTag(Ref<TagType> tagType, const std::string& data, bool unique = false); + void Reanalyze(); void RequestAdvancedAnalysisData(); diff --git a/binaryninjacore.h b/binaryninjacore.h index 903e6a45..7dc1f8c2 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -136,6 +136,8 @@ extern "C" struct BNMediumLevelILFunction; struct BNType; struct BNStructure; + struct BNTagType; + struct BNTag; struct BNNamedTypeReference; struct BNEnumeration; struct BNCallingConvention; @@ -238,6 +240,7 @@ extern "C" FieldNameToken = 21, NameSpaceToken = 22, NameSpaceSeparatorToken = 23, + TagToken = 24, // The following are output by the analysis system automatically, these should // not be used directly by the architecture plugins CodeSymbolToken = 64, @@ -1198,6 +1201,7 @@ extern "C" BNInstructionTextTokenType type; char* text; uint64_t value; + uint64_t width; size_t size, operand; BNInstructionTextTokenContext context; uint8_t confidence; @@ -1361,6 +1365,8 @@ extern "C" BNInstructionTextToken* tokens; size_t count; BNHighlightColor highlight; + BNTag** tags; + size_t tagCount; }; struct BNLinearDisassemblyLine @@ -1386,6 +1392,30 @@ extern "C" uint64_t addr; }; + enum BNTagTypeType + { + UserTagType, + NotificationTagType, + BookmarksTagType + }; + + enum BNTagReferenceType + { + AddressTagReference, + FunctionTagReference, + DataTagReference + }; + + struct BNTagReference + { + BNTagReferenceType refType; + bool autoDefined; + BNTag* tag; + BNArchitecture* arch; + BNFunction* func; + uint64_t addr; + }; + struct BNUndoAction { BNActionType type; @@ -2902,6 +2932,73 @@ extern "C" BINARYNINJACOREAPI void BNSetAutoBasicBlockHighlight(BNBasicBlock* block, BNHighlightColor color); BINARYNINJACOREAPI void BNSetUserBasicBlockHighlight(BNBasicBlock* block, BNHighlightColor color); + BINARYNINJACOREAPI BNTagType* BNCreateTagType(BNBinaryView* view); + BINARYNINJACOREAPI BNTagType* BNNewTagTypeReference(BNTagType* tagType); + BINARYNINJACOREAPI void BNFreeTagType(BNTagType* tagType); + BINARYNINJACOREAPI void BNFreeTagTypeList(BNTagType** tagTypes, size_t count); + BINARYNINJACOREAPI BNBinaryView* BNTagTypeGetView(BNTagType* tagType); + BINARYNINJACOREAPI char* BNTagTypeGetName(BNTagType* tagType); + BINARYNINJACOREAPI void BNTagTypeSetName(BNTagType* tagType, const char* name); + BINARYNINJACOREAPI char* BNTagTypeGetIcon(BNTagType* tagType); + BINARYNINJACOREAPI void BNTagTypeSetIcon(BNTagType* tagType, const char* icon); + BINARYNINJACOREAPI bool BNTagTypeGetVisible(BNTagType* tagType); + BINARYNINJACOREAPI void BNTagTypeSetVisible(BNTagType* tagType, bool visible); + BINARYNINJACOREAPI BNTagTypeType BNTagTypeGetType(BNTagType* tagType); + BINARYNINJACOREAPI void BNTagTypeSetType(BNTagType* tagType, BNTagTypeType type); + + BINARYNINJACOREAPI BNTag* BNCreateTag(BNTagType* type, const char* data); + BINARYNINJACOREAPI BNTag* BNNewTagReference(BNTag* tag); + BINARYNINJACOREAPI void BNFreeTag(BNTag* tag); + BINARYNINJACOREAPI void BNFreeTagList(BNTag** tags, size_t count); + BINARYNINJACOREAPI BNTagType* BNTagGetType(BNTag* tag); + BINARYNINJACOREAPI char* BNTagGetData(BNTag* tag); + BINARYNINJACOREAPI void BNTagSetData(BNTag* tag, const char* data); + + BINARYNINJACOREAPI void BNAddTagType(BNBinaryView* view, BNTagType* tagType); + BINARYNINJACOREAPI void BNRemoveTagType(BNBinaryView* view, BNTagType* tagType); + BINARYNINJACOREAPI BNTagType* BNGetTagType(BNBinaryView* view, const char* name); + BINARYNINJACOREAPI BNTagType* BNGetTagTypeWithType(BNBinaryView* view, const char* name, BNTagTypeType type); + BINARYNINJACOREAPI BNTagType** BNGetTagTypes(BNBinaryView* view, size_t* count); + + BINARYNINJACOREAPI void BNAddTag(BNBinaryView* view, BNTag* tag); + BINARYNINJACOREAPI BNTag* BNGetTag(BNBinaryView* view, uint64_t tagId); + BINARYNINJACOREAPI void BNRemoveTag(BNBinaryView* view, BNTag* tag); + + BINARYNINJACOREAPI BNTagReference* BNGetAllTagReferences(BNBinaryView* view, size_t* count); + BINARYNINJACOREAPI BNTagReference* BNGetAllAddressTagReferences(BNBinaryView* view, size_t* count); + BINARYNINJACOREAPI BNTagReference* BNGetAllFunctionTagReferences(BNBinaryView* view, size_t* count); + BINARYNINJACOREAPI BNTagReference* BNGetAllTagReferencesOfType(BNBinaryView* view, BNTagType* tagType, size_t* count); + BINARYNINJACOREAPI BNTagReference* BNGetTagReferencesOfType(BNBinaryView* view, BNTagType* tagType, size_t* count); + BINARYNINJACOREAPI BNTagReference* BNGetDataTagReferences(BNBinaryView* view, size_t* count); + BINARYNINJACOREAPI void BNFreeTagReferences(BNTagReference* refs, size_t count); + BINARYNINJACOREAPI BNTag** BNGetDataTags(BNBinaryView* view, uint64_t addr, size_t* count); + BINARYNINJACOREAPI BNTag** BNGetDataTagsOfType(BNBinaryView* view, uint64_t addr, BNTagType* tagType, size_t* count); + BINARYNINJACOREAPI BNTag** BNGetDataTagsInRange(BNBinaryView* view, uint64_t start, uint64_t end, size_t* count); + BINARYNINJACOREAPI void BNAddAutoDataTag(BNBinaryView* view, uint64_t addr, BNTag* tag); + BINARYNINJACOREAPI void BNRemoveAutoDataTag(BNBinaryView* view, uint64_t addr, BNTag* tag); + BINARYNINJACOREAPI void BNAddUserDataTag(BNBinaryView* view, uint64_t addr, BNTag* tag); + BINARYNINJACOREAPI void BNRemoveUserDataTag(BNBinaryView* view, uint64_t addr, BNTag* tag); + BINARYNINJACOREAPI void BNRemoveTagReference(BNBinaryView* view, BNTagReference ref); + + BINARYNINJACOREAPI BNTagReference* BNGetFunctionAllTagReferences(BNFunction* func, size_t* count); + BINARYNINJACOREAPI BNTagReference* BNGetFunctionTagReferencesOfType(BNFunction* func, BNTagType* tagType, size_t* count); + + BINARYNINJACOREAPI BNTagReference* BNGetAddressTagReferences(BNFunction* func, size_t* count); + BINARYNINJACOREAPI BNTag** BNGetAddressTags(BNFunction* func, BNArchitecture* arch, uint64_t addr, size_t* count); + BINARYNINJACOREAPI BNTag** BNGetAddressTagsOfType(BNFunction* func, BNArchitecture* arch, uint64_t addr, BNTagType* tagType, size_t* count); + BINARYNINJACOREAPI void BNAddAutoAddressTag(BNFunction* func, BNArchitecture* arch, uint64_t addr, BNTag* tag); + BINARYNINJACOREAPI void BNRemoveAutoAddressTag(BNFunction* func, BNArchitecture* arch, uint64_t addr, BNTag* tag); + BINARYNINJACOREAPI void BNAddUserAddressTag(BNFunction* func, BNArchitecture* arch, uint64_t addr, BNTag* tag); + BINARYNINJACOREAPI void BNRemoveUserAddressTag(BNFunction* func, BNArchitecture* arch, uint64_t addr, BNTag* tag); + + BINARYNINJACOREAPI BNTagReference* BNGetFunctionTagReferences(BNFunction* func, size_t* count); + BINARYNINJACOREAPI BNTag** BNGetFunctionTags(BNFunction* func, size_t* count); + BINARYNINJACOREAPI BNTag** BNGetFunctionTagsOfType(BNFunction* func, BNTagType* tagType, size_t* count); + BINARYNINJACOREAPI void BNAddAutoFunctionTag(BNFunction* func, BNTag* tag); + BINARYNINJACOREAPI void BNRemoveAutoFunctionTag(BNFunction* func, BNTag* tag); + BINARYNINJACOREAPI void BNAddUserFunctionTag(BNFunction* func, BNTag* tag); + BINARYNINJACOREAPI void BNRemoveUserFunctionTag(BNFunction* func, BNTag* tag); + BINARYNINJACOREAPI BNPerformanceInfo* BNGetFunctionAnalysisPerformanceInfo(BNFunction* func, size_t* count); BINARYNINJACOREAPI void BNFreeAnalysisPerformanceInfo(BNPerformanceInfo* info, size_t count); diff --git a/binaryview.cpp b/binaryview.cpp index fd93b340..553ce251 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -342,6 +342,230 @@ void AnalysisCompletionEvent::Cancel() } +TagType::TagType(BNTagType* tagType) +{ + m_object = tagType; +} + + +TagType::TagType(BinaryView* view) +{ + m_object = BNCreateTagType(view->GetObject()); +} + + +TagType::TagType(BinaryView* view, const std::string& name, const std::string& icon, bool visible, TagType::Type type) +{ + m_object = BNCreateTagType(view->GetObject()); + SetName(name); + SetIcon(icon); + SetVisible(visible); + SetType(type); +} + + +BinaryView* TagType::GetView() const +{ + return new BinaryView(BNTagTypeGetView(m_object)); +} + + +std::string TagType::GetName() const +{ + return BNTagTypeGetName(m_object); +} + + +void TagType::SetName(const std::string& name) +{ + BNTagTypeSetName(m_object, name.c_str()); +} + + +std::string TagType::GetIcon() const +{ + return BNTagTypeGetIcon(m_object); +} + + +void TagType::SetIcon(const std::string& icon) +{ + BNTagTypeSetIcon(m_object, icon.c_str()); +} + + +bool TagType::GetVisible() const +{ + return BNTagTypeGetVisible(m_object); +} + + +void TagType::SetVisible(bool visible) +{ + BNTagTypeSetVisible(m_object, visible); +} + + +TagType::Type TagType::GetType() const +{ + return BNTagTypeGetType(m_object); +} + + +void TagType::SetType(TagType::Type type) +{ + BNTagTypeSetType(m_object, type); +} + + +Tag::Tag(BNTag* tag) +{ + m_object = tag; +} + + +Tag::Tag(Ref<TagType> type, const std::string& data) +{ + m_object = BNCreateTag(type->GetObject(), data.c_str()); +} + + +Ref<TagType> Tag::GetType() const +{ + return new TagType(BNTagGetType(m_object)); +} + + +std::string Tag::GetData() const +{ + return BNTagGetData(m_object); +} + + +void Tag::SetData(const std::string& data) +{ + BNTagSetData(m_object, data.c_str()); +} + + +BNTag** Tag::CreateTagList(const std::vector<Ref<Tag>>& tags, size_t* count) +{ + *count = tags.size(); + BNTag** result = new BNTag*[tags.size()]; + for (size_t i = 0; i < tags.size(); i++) + result[i] = tags[i]->GetObject(); + return result; +} + + +std::vector<Ref<Tag>> Tag::ConvertTagList(BNTag** tags, size_t count) +{ + std::vector<Ref<Tag>> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.emplace_back(new Tag(BNNewTagReference(tags[i]))); + return result; +} + + +std::vector<Ref<Tag>> Tag::ConvertAndFreeTagList(BNTag** tags, size_t count) +{ + auto result = ConvertTagList(tags, count); + BNFreeTagList(tags, count); + return result; +} + + +TagReference::TagReference() +{ +} + + +TagReference::TagReference(const BNTagReference& ref) +{ + refType = ref.refType; + autoDefined = ref.autoDefined; + tag = ref.tag ? new Tag(BNNewTagReference(ref.tag)) : nullptr; + arch = ref.arch ? new CoreArchitecture(ref.arch) : nullptr; + func = ref.func ? new Function(BNNewFunctionReference(ref.func)) : nullptr; + addr = ref.addr; +} + + +bool TagReference::operator==(const TagReference& other) const +{ + if (refType != other.refType) + return false; + if (autoDefined != other.autoDefined) + return false; + if (tag != other.tag) + return false; + switch (refType) + { + case AddressTagReference: + return func == other.func && arch == other.arch && addr == other.addr; + case FunctionTagReference: + return func == other.func; + case DataTagReference: + return addr == other.addr; + } +} + + +bool TagReference::operator!=(const TagReference& other) const +{ + return !((*this) == other); +} + + +TagReference::operator BNTagReference() const +{ + BNTagReference ret; + ret.refType = refType; + ret.autoDefined = autoDefined; + ret.tag = tag->GetObject(); + ret.arch = arch ? arch->GetObject() : nullptr; + ret.func = func ? func->GetObject() : nullptr; + ret.addr = addr; + return ret; +} + + +BNTagReference* TagReference::CreateTagReferenceList(const std::vector<TagReference>& tags, size_t* count) +{ + *count = tags.size(); + + BNTagReference* refs = new BNTagReference[*count]; + + for (size_t i = 0; i < *count; i ++) + { + refs[i] = tags[i]; + } + + return refs; +} + + +std::vector<TagReference> TagReference::ConvertTagReferenceList(BNTagReference* tags, size_t count) +{ + std::vector<TagReference> result; + result.reserve(count); + for (size_t i = 0; i < count; i ++) + { + result.emplace_back(tags[i]); + } + return result; +} + + +std::vector<TagReference> TagReference::ConvertAndFreeTagReferenceList(BNTagReference* tags, size_t count) +{ + auto result = ConvertTagReferenceList(tags, count); + BNFreeTagReferences(tags, count); + return result; +} + + Segment::Segment(BNSegment* seg) { m_object = seg; @@ -1757,6 +1981,239 @@ void BinaryView::DefineImportedFunction(Ref<Symbol> importAddressSym, Ref<Functi } +void BinaryView::AddTagType(Ref<TagType> tagType) +{ + BNAddTagType(m_object, tagType->GetObject()); +} + + +void BinaryView::RemoveTagType(Ref<TagType> tagType) +{ + BNRemoveTagType(m_object, tagType->GetObject()); +} + + +Ref<TagType> BinaryView::GetTagType(const std::string& name) +{ + BNTagType* tagType = BNGetTagType(m_object, name.c_str()); + if (!tagType) + return nullptr; + + return Ref<TagType>(new TagType(tagType)); +} + + +Ref<TagType> BinaryView::GetTagType(const std::string& name, TagType::Type type) +{ + BNTagType* tagType = BNGetTagTypeWithType(m_object, name.c_str(), type); + if (!tagType) + return nullptr; + + return Ref<TagType>(new TagType(tagType)); +} + + +std::vector<Ref<TagType>> BinaryView::GetTagTypes() +{ + size_t count; + BNTagType** tagTypes = BNGetTagTypes(m_object, &count); + + std::vector<Ref<TagType>> result; + result.reserve(count); + for (size_t i = 0; i < count; i ++) + { + result.push_back(new TagType(BNNewTagTypeReference(tagTypes[i]))); + } + BNFreeTagTypeList(tagTypes, count); + + return result; +} + + +void BinaryView::AddTag(Ref<Tag> tag) +{ + BNAddTag(m_object, tag->GetObject()); +} + + +void BinaryView::RemoveTag(Ref<Tag> tag) +{ + BNRemoveTag(m_object, tag->GetObject()); +} + + +Ref<Tag> BinaryView::GetTag(uint64_t tagId) +{ + BNTag* tag = BNGetTag(m_object, tagId); + if (!tag) + return nullptr; + + return Ref<Tag>(new Tag(tag)); +} + + +std::vector<TagReference> BinaryView::GetAllTagReferences() +{ + size_t count; + BNTagReference* refs = BNGetAllTagReferences(m_object, &count); + return TagReference::ConvertAndFreeTagReferenceList(refs, count); +} + + +std::vector<TagReference> BinaryView::GetAllAddressTagReferences() +{ + size_t count; + BNTagReference* refs = BNGetAllAddressTagReferences(m_object, &count); + return TagReference::ConvertAndFreeTagReferenceList(refs, count); +} + + +std::vector<TagReference> BinaryView::GetAllFunctionTagReferences() +{ + size_t count; + BNTagReference* refs = BNGetAllFunctionTagReferences(m_object, &count); + return TagReference::ConvertAndFreeTagReferenceList(refs, count); +} + + +std::vector<TagReference> BinaryView::GetAllTagReferencesOfType(Ref<TagType> tagType) +{ + size_t count; + BNTagReference* refs = BNGetAllTagReferencesOfType(m_object, tagType->GetObject(), &count); + return TagReference::ConvertAndFreeTagReferenceList(refs, count); +} + + +std::vector<TagReference> BinaryView::GetTagReferencesOfType(Ref<TagType> tagType) +{ + size_t count; + BNTagReference* refs = BNGetTagReferencesOfType(m_object, tagType->GetObject(), &count); + return TagReference::ConvertAndFreeTagReferenceList(refs, count); +} + + +std::vector<TagReference> BinaryView::GetDataTagReferences() +{ + size_t count; + BNTagReference* refs = BNGetDataTagReferences(m_object, &count); + return TagReference::ConvertAndFreeTagReferenceList(refs, count); +} + + +std::vector<Ref<Tag>> BinaryView::GetDataTags(uint64_t addr) +{ + size_t count; + BNTag** tags = BNGetDataTags(m_object, addr, &count); + return Tag::ConvertAndFreeTagList(tags, count); +} + + +std::vector<Ref<Tag>> BinaryView::GetDataTagsOfType(uint64_t addr, Ref<TagType> tagType) +{ + size_t count; + BNTag** tags = BNGetDataTagsOfType(m_object, addr, tagType->GetObject(), &count); + return Tag::ConvertAndFreeTagList(tags, count); +} + + +std::vector<Ref<Tag>> BinaryView::GetDataTagsInRange(uint64_t start, uint64_t end) +{ + size_t count; + BNTag** tags = BNGetDataTagsInRange(m_object, start, end, &count); + return Tag::ConvertAndFreeTagList(tags, count); +} + + +void BinaryView::AddAutoDataTag(uint64_t addr, Ref<Tag> tag) +{ + BNAddAutoDataTag(m_object, addr, tag->GetObject()); +} + + +void BinaryView::RemoveAutoDataTag(uint64_t addr, Ref<Tag> tag) +{ + BNRemoveAutoDataTag(m_object, addr, tag->GetObject()); +} + + +void BinaryView::AddUserDataTag(uint64_t addr, Ref<Tag> tag) +{ + BNAddUserDataTag(m_object, addr, tag->GetObject()); +} + + +void BinaryView::RemoveUserDataTag(uint64_t addr, Ref<Tag> tag) +{ + BNRemoveUserDataTag(m_object, addr, tag->GetObject()); +} + + +void BinaryView::RemoveTagReference(const TagReference& ref) +{ + BNRemoveTagReference(m_object, (BNTagReference)ref); +} + + +Ref<Tag> BinaryView::CreateAutoDataTag(uint64_t addr, const std::string& tagTypeName, const std::string& data, bool unique) +{ + Ref<TagType> tagType = GetTagType(tagTypeName); + if (!tagType) + return nullptr; + + return CreateAutoDataTag(addr, tagType, data, unique); +} + + +Ref<Tag> BinaryView::CreateUserDataTag(uint64_t addr, const std::string& tagTypeName, const std::string& data, bool unique) +{ + Ref<TagType> tagType = GetTagType(tagTypeName); + if (!tagType) + return nullptr; + + return CreateUserDataTag(addr, tagType, data, unique); +} + + +Ref<Tag> BinaryView::CreateAutoDataTag(uint64_t addr, Ref<TagType> tagType, const std::string& data, bool unique) +{ + if (unique) + { + auto tags = GetDataTags(addr); + for (const auto& tag : tags) + { + if (tag->GetType() == tagType && tag->GetData() == data) + return nullptr; + } + } + + Ref<Tag> tag = new Tag(tagType, data); + AddTag(tag); + + AddAutoDataTag(addr, tag); + return tag; +} + + +Ref<Tag> BinaryView::CreateUserDataTag(uint64_t addr, Ref<TagType> tagType, const std::string& data, bool unique) +{ + if (unique) + { + auto tags = GetDataTags(addr); + for (const auto& tag : tags) + { + if (tag->GetType() == tagType && tag->GetData() == data) + return nullptr; + } + } + + Ref<Tag> tag = new Tag(tagType, data); + AddTag(tag); + + AddUserDataTag(addr, tag); + return tag; +} + + bool BinaryView::IsNeverBranchPatchAvailable(Architecture* arch, uint64_t addr) { return BNIsNeverBranchPatchAvailable(m_object, arch->GetObject(), addr); @@ -1957,6 +2414,7 @@ vector<LinearDisassemblyLine> BinaryView::GetPreviousLinearDisassemblyLines(Line line.contents.instrIndex = lines[i].contents.instrIndex; line.contents.highlight = lines[i].contents.highlight; line.contents.tokens = InstructionTextToken::ConvertInstructionTextTokenList(lines[i].contents.tokens, lines[i].contents.count); + line.contents.tags = Tag::ConvertTagList(lines[i].contents.tags, lines[i].contents.tagCount); result.push_back(line); } @@ -1994,6 +2452,7 @@ vector<LinearDisassemblyLine> BinaryView::GetNextLinearDisassemblyLines(LinearDi line.contents.instrIndex = lines[i].contents.instrIndex; line.contents.highlight = lines[i].contents.highlight; line.contents.tokens = InstructionTextToken::ConvertInstructionTextTokenList(lines[i].contents.tokens, lines[i].contents.count); + line.contents.tags = Tag::ConvertTagList(lines[i].contents.tags, lines[i].contents.tagCount); result.push_back(line); } diff --git a/datarenderer.cpp b/datarenderer.cpp index c0536a6a..4004b7d4 100644 --- a/datarenderer.cpp +++ b/datarenderer.cpp @@ -76,6 +76,7 @@ BNDisassemblyTextLine* DataRenderer::GetLinesForDataCallback(void* ctxt, BNBinar buf[i].highlight = line.highlight; buf[i].tokens = InstructionTextToken::CreateInstructionTextTokenList(line.tokens); buf[i].count = line.tokens.size(); + buf[i].tags = Tag::CreateTagList(line.tags, &(buf[i].tagCount)); } return buf; } @@ -130,6 +131,7 @@ vector<DisassemblyTextLine> DataRenderer::GetLinesForData(BinaryView* data, uint line.instrIndex = lines[i].instrIndex; line.highlight = lines[i].highlight; line.tokens = InstructionTextToken::ConvertAndFreeInstructionTextTokenList(lines[i].tokens, lines[i].count); + line.tags = Tag::ConvertAndFreeTagList(lines[i].tags, lines[i].tagCount); result.push_back(line); } return result; @@ -145,4 +147,4 @@ void DataRendererContainer::RegisterGenericDataRenderer(DataRenderer* renderer) void DataRendererContainer::RegisterTypeSpecificDataRenderer(DataRenderer* renderer) { BNRegisterTypeSpecificDataRenderer(BNGetDataRendererContainer(), renderer->GetObject()); -}
\ No newline at end of file +} diff --git a/flowgraphnode.cpp b/flowgraphnode.cpp index 4a1729ff..2457ebb9 100644 --- a/flowgraphnode.cpp +++ b/flowgraphnode.cpp @@ -107,6 +107,7 @@ const vector<DisassemblyTextLine>& FlowGraphNode::GetLines() line.instrIndex = lines[i].instrIndex; line.highlight = lines[i].highlight; line.tokens = InstructionTextToken::ConvertInstructionTextTokenList(lines[i].tokens, lines[i].count); + line.tags = Tag::ConvertTagList(lines[i].tags, lines[i].tagCount); result.push_back(line); } @@ -126,6 +127,7 @@ void FlowGraphNode::SetLines(const vector<DisassemblyTextLine>& lines) buf[i].highlight = lines[i].highlight; buf[i].tokens = InstructionTextToken::CreateInstructionTextTokenList(lines[i].tokens); buf[i].count = lines[i].tokens.size(); + buf[i].tags = Tag::CreateTagList(lines[i].tags, &(buf[i].tagCount)); } BNSetFlowGraphNodeLines(m_object, buf, lines.size()); diff --git a/function.cpp b/function.cpp index 752d0bd1..0d5cb2ba 100644 --- a/function.cpp +++ b/function.cpp @@ -1300,6 +1300,237 @@ void Function::SetUserInstructionHighlight(Architecture* arch, uint64_t addr, ui } +std::vector<TagReference> Function::GetAllTagReferences() +{ + size_t count; + BNTagReference* refs = BNGetFunctionAllTagReferences(m_object, &count); + return TagReference::ConvertAndFreeTagReferenceList(refs, count); +} + + +std::vector<TagReference> Function::GetTagReferencesOfType(Ref<TagType> tagType) +{ + size_t count; + BNTagReference* refs = BNGetFunctionTagReferencesOfType(m_object, tagType->GetObject(), &count); + return TagReference::ConvertAndFreeTagReferenceList(refs, count); +} + + +std::vector<TagReference> Function::GetAddressTagReferences() +{ + size_t count; + BNTagReference* refs = BNGetAddressTagReferences(m_object, &count); + return TagReference::ConvertAndFreeTagReferenceList(refs, count); +} + + +std::vector<Ref<Tag>> Function::GetAddressTags(Architecture* arch, uint64_t addr) +{ + size_t count; + BNTag** tags = BNGetAddressTags(m_object, arch->GetObject(), addr, &count); + return Tag::ConvertAndFreeTagList(tags, count); +} + + +std::vector<Ref<Tag>> Function::GetAddressTagsOfType(Architecture* arch, uint64_t addr, Ref<TagType> tagType) +{ + size_t count; + BNTag** tags = BNGetAddressTagsOfType(m_object, arch->GetObject(), addr, tagType->GetObject(), &count); + return Tag::ConvertAndFreeTagList(tags, count); +} + + +void Function::AddAutoAddressTag(Architecture* arch, uint64_t addr, Ref<Tag> tag) +{ + BNAddAutoAddressTag(m_object, arch->GetObject(), addr, tag->GetObject()); +} + + +void Function::RemoveAutoAddressTag(Architecture* arch, uint64_t addr, Ref<Tag> tag) +{ + BNRemoveAutoAddressTag(m_object, arch->GetObject(), addr, tag->GetObject()); +} + + +void Function::AddUserAddressTag(Architecture* arch, uint64_t addr, Ref<Tag> tag) +{ + BNAddUserAddressTag(m_object, arch->GetObject(), addr, tag->GetObject()); +} + + +void Function::RemoveUserAddressTag(Architecture* arch, uint64_t addr, Ref<Tag> tag) +{ + BNRemoveUserAddressTag(m_object, arch->GetObject(), addr, tag->GetObject()); +} + + +std::vector<TagReference> Function::GetFunctionTagReferences() +{ + size_t count; + BNTagReference* refs = BNGetFunctionTagReferences(m_object, &count); + return TagReference::ConvertAndFreeTagReferenceList(refs, count); +} + + +std::vector<Ref<Tag>> Function::GetFunctionTags() +{ + size_t count; + BNTag** tags = BNGetFunctionTags(m_object, &count); + return Tag::ConvertAndFreeTagList(tags, count); +} + + +std::vector<Ref<Tag>> Function::GetFunctionTagsOfType(Ref<TagType> tagType) +{ + size_t count; + BNTag** tags = BNGetFunctionTagsOfType(m_object, tagType->GetObject(), &count); + return Tag::ConvertAndFreeTagList(tags, count); +} + + +void Function::AddAutoFunctionTag(Ref<Tag> tag) +{ + BNAddAutoFunctionTag(m_object, tag->GetObject()); +} + + +void Function::RemoveAutoFunctionTag(Ref<Tag> tag) +{ + BNRemoveAutoFunctionTag(m_object, tag->GetObject()); +} + + +void Function::AddUserFunctionTag(Ref<Tag> tag) +{ + BNAddUserFunctionTag(m_object, tag->GetObject()); +} + + +void Function::RemoveUserFunctionTag(Ref<Tag> tag) +{ + BNRemoveUserFunctionTag(m_object, tag->GetObject()); +} + + +Ref<Tag> Function::CreateAutoAddressTag(Architecture* arch, uint64_t addr, const std::string& tagTypeName, const std::string& data, bool unique) +{ + Ref<TagType> tagType = GetView()->GetTagType(tagTypeName); + if (!tagType) + return nullptr; + + return CreateAutoAddressTag(arch, addr, tagType, data, unique); +} + + +Ref<Tag> Function::CreateAutoAddressTag(Architecture* arch, uint64_t addr, Ref<TagType> tagType, const std::string& data, bool unique) +{ + if (unique) + { + auto tags = GetAddressTags(arch, addr); + for (const auto& tag : tags) + { + if (tag->GetType() == tagType && tag->GetData() == data) + return nullptr; + } + } + + Ref<Tag> tag = new Tag(tagType, data); + GetView()->AddTag(tag); + + AddAutoAddressTag(arch, addr, tag); + return tag; +} + + +Ref<Tag> Function::CreateUserAddressTag(Architecture* arch, uint64_t addr, const std::string& tagTypeName, const std::string& data, bool unique) +{ + Ref<TagType> tagType = GetView()->GetTagType(tagTypeName); + if (!tagType) + return nullptr; + + return CreateUserAddressTag(arch, addr, tagType, data, unique); +} + + +Ref<Tag> Function::CreateUserAddressTag(Architecture* arch, uint64_t addr, Ref<TagType> tagType, const std::string& data, bool unique) +{ + if (unique) + { + auto tags = GetAddressTags(arch, addr); + for (const auto& tag : tags) + { + if (tag->GetType() == tagType && tag->GetData() == data) + return nullptr; + } + } + Ref<Tag> tag = new Tag(tagType, data); + GetView()->AddTag(tag); + + AddUserAddressTag(arch, addr, tag); + return tag; +} + + +Ref<Tag> Function::CreateAutoFunctionTag(const std::string& tagTypeName, const std::string& data, bool unique) +{ + Ref<TagType> tagType = GetView()->GetTagType(tagTypeName); + if (!tagType) + return nullptr; + + return CreateAutoFunctionTag(tagType, data, unique); +} + + +Ref<Tag> Function::CreateAutoFunctionTag(Ref<TagType> tagType, const std::string& data, bool unique) +{ + if (unique) + { + auto tags = GetFunctionTags(); + for (const auto& tag : tags) + { + if (tag->GetType() == tagType && tag->GetData() == data) + return nullptr; + } + } + + Ref<Tag> tag = new Tag(tagType, data); + GetView()->AddTag(tag); + + AddAutoFunctionTag(tag); + return tag; +} + + +Ref<Tag> Function::CreateUserFunctionTag(const std::string& tagTypeName, const std::string& data, bool unique) +{ + Ref<TagType> tagType = GetView()->GetTagType(tagTypeName); + if (!tagType) + return nullptr; + + return CreateUserFunctionTag(tagType, data, unique); +} + + +Ref<Tag> Function::CreateUserFunctionTag(Ref<TagType> tagType, const std::string& data, bool unique) +{ + if (unique) + { + auto tags = GetFunctionTags(); + for (const auto& tag : tags) + { + if (tag->GetType() == tagType && tag->GetData() == data) + return nullptr; + } + } + + Ref<Tag> tag = new Tag(tagType, data); + GetView()->AddTag(tag); + + AddUserFunctionTag(tag); + return tag; +} + + Confidence<RegisterValue> Function::GetGlobalPointerValue() const { BNRegisterValueWithConfidence value = BNGetFunctionGlobalPointerValue(m_object); @@ -1370,6 +1601,7 @@ vector<DisassemblyTextLine> Function::GetTypeTokens(DisassemblySettings* setting line.instrIndex = lines[i].instrIndex; line.highlight = lines[i].highlight; line.tokens = InstructionTextToken::ConvertInstructionTextTokenList(lines[i].tokens, lines[i].count); + line.tags = Tag::ConvertTagList(lines[i].tags, lines[i].tagCount); result.push_back(line); } diff --git a/python/binaryview.py b/python/binaryview.py index c197e585..fe8fde76 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -1,3 +1,4 @@ +# coding=utf-8 # Copyright (c) 2015-2019 Vector 35 Inc # # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -900,6 +901,98 @@ class AddressRange(object): self._end = value +class TagType(object): + def __init__(self, handle): + self.handle = core.handle_of_type(handle, core.BNTagType) + + @property + def name(self): + return core.BNTagTypeGetName(self.handle) + + @name.setter + def name(self, value): + core.BNTagTypeSetName(self.handle, value) + + @property + def icon(self): + return core.BNTagTypeGetIcon(self.handle) + + @icon.setter + def icon(self, value): + core.BNTagTypeSetIcon(self.handle, value) + + @property + def visible(self): + return core.BNTagTypeGetVisible(self.handle) + + @visible.setter + def visible(self, value): + core.BNTagTypeSetVisible(self.handle, value) + + @property + def type(self): + return core.BNTagTypeGetType(self.handle) + + @type.setter + def type(self, value): + core.BNTagTypeSetType(self.handle, value) + + def __del__(self): + core.BNFreeTagType(self.handle) + + def __eq__(self, other): + if not isinstance(other, TagType): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(other.handle.contents) + + def __ne__(self, other): + if not isinstance(other, TagType): + return False + return ctypes.addressof(self.handle.contents) != ctypes.addressof(other.handle.contents) + + def __hash__(self): + return hash(self.handle.contents) + + def __repr__(self): + return "<tag type %s: %s>" % (self.name, self.icon) + + +class Tag(object): + def __init__(self, handle): + self.handle = core.handle_of_type(handle, core.BNTag) + + @property + def type(self): + return TagType(core.BNTagGetType(self.handle)) + + @property + def data(self): + return core.BNTagGetData(self.handle) + + @data.setter + def data(self, value): + core.BNTagSetData(self.handle, value) + + def __del__(self): + core.BNFreeTag(self.handle) + + def __eq__(self, other): + if not isinstance(other, Tag): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(other.handle.contents) + + def __ne__(self, other): + if not isinstance(other, Tag): + return False + return ctypes.addressof(self.handle.contents) != ctypes.addressof(other.handle.contents) + + def __hash__(self): + return hash(self.handle.contents) + + def __repr__(self): + return "<tag %s %s: %s>" % (self.type.icon, self.type.name, self.data) + + class _BinaryViewAssociatedDataStore(associateddatastore._AssociatedDataStore): _defaults = {} @@ -3223,6 +3316,210 @@ class BinaryView(object): """ core.BNDefineImportedFunction(self.handle, import_addr_sym.handle, func.handle) + def create_tag_type(self, name, icon): + """ + ``create_tag_type`` creates a new Tag Type and adds it to the view + + :param str name: The name for the tag + :param str icon: The icon (recommended 1 emoji or 2 chars) for the tag + :return The created tag type + :rtype TagType + :Example: + + >>> tt = bv.create_tag_type("Crabby Functions", "🦀") + >>> current_function.create_user_address_tag(here, tt, "Get Crabbed") + >>> + """ + tag_type = TagType(core.BNCreateTagType(self.handle, name, icon)) + tag_type.name = name + tag_type.icon = icon + core.BNAddTagType(self.handle, tag_type.handle) + return tag_type + + def remove_tag_type(self, tag_type): + """ + ``remove_tag_type`` removes a new Tag Type and all tags that use it + + :param TagType tag_type: The Tag Type to remove + :rtype None + """ + core.BNRemoveTagType(self.handle, tag_type.handle) + + @property + def tag_types(self): + """ + ``tag_types`` gets a dictionary of all Tag Types present for the view, + structured as {Tag Type Name => Tag Type}. + + :type {str => TagType} + """ + count = ctypes.c_ulonglong(0) + types = core.BNGetTagTypes(self.handle, count) + result = {} + for i in range(0, count.value): + tag = TagType(core.BNNewTagTypeReference(types[i])) + if tag.name in result: + result[tag.name] = [result[tag.name], tag] + else: + result[tag.name] = tag + core.BNFreeTagTypeList(types, count.value) + return result + + def create_tag(self, type, data): + """ + ``create_tag`` creates a new Tag object but does not add it anywhere + + :param TagType type: The Tag Type for this Tag + :param str data: Additional data for the Tag + :return The created Tag + :rtype Tag + :Example: + + >>> tt = bv.tag_types["Crabby Functions"] + >>> tag = bv.create_tag(tt, "Get Crabbed") + >>> bv.add_user_data_tag(here, tag) + >>> + """ + tag = Tag(core.BNCreateTag(type.handle, data)) + core.BNAddTag(self.handle, tag.handle) + return tag + + @property + def data_tags(self): + """ + ``data_tags`` gets a list of all data Tags in the view. + Tags are returned as a list of (address, Tag) pairs. + + :type [(int, Tag)] + """ + count = ctypes.c_ulonglong() + tags = core.BNGetDataTagReferences(self.handle, count) + result = [] + for i in range(0, count.value): + tag = Tag(core.BNNewTagReference(tags[i].tag)) + result.append((tags[i].addr, tag)) + core.BNFreeTagReferences(tags, count.value) + return result + + def get_data_tags_at(self, addr): + """ + ``get_data_tags_at`` gets a list of all Tags for a data address. + + :param int addr: Address to get tags at + :return A list of data Tags + :rtype [Tag] + """ + count = ctypes.c_ulonglong() + tags = core.BNGetDataTags(self.handle, addr, count) + result = [] + for i in range(0, count.value): + result.append(Tag(core.BNNewTagReference(tags[i]))) + core.BNFreeTagList(tags, count.value) + return result + + def get_data_tags_in_range(self, range): + """ + ``get_data_tags_in_range`` gets a list of all data Tags in a given range. + Range is inclusive at the start, exclusive at the end. + + :param AddressRange range: Address range from which to get tags + :return A list of data Tags + :rtype [Tag] + """ + count = ctypes.c_ulonglong() + tags = core.BNGetDataTagsInRange(self.handle, range.start, range.end, count) + result = [] + for i in range(0, count.value): + result.append(Tag(core.BNNewTagReference(tags[i]))) + core.BNFreeTagList(tags, count.value) + return result + + def add_user_data_tag(self, addr, tag): + """ + ``add_user_data_tag`` adds an already-created Tag object at a data address. + Since this adds a user tag, it will be added to the current undo buffer. + + :param int addr: Address at which to add the tag + :param Tag tag: Tag object to be added + :rtype None + """ + core.BNAddUserDataTag(self.handle, addr, tag.handle) + + def create_user_data_tag(self, addr, type, data, unique=False): + """ + ``create_user_data_tag`` creates and adds a Tag object at a data address. + Since this adds a user tag, it will be added to the current undo buffer. + + :param int addr: Address at which to add the tag + :param TagType type: Tag Type for the Tag that is created + :param str data: Additional data for the Tag + :param bool unique: If a tag already exists at this location with this data, don't add another + :return The created Tag + :rtype Tag + """ + if unique: + tags = self.get_data_tags_at(addr) + for tag in tags: + if tag.type == type and tag.data == data: + return + + tag = self.create_tag(type, data) + core.BNAddUserDataTag(self.handle, addr, tag.handle) + return tag + + def remove_user_data_tag(self, addr, tag): + """ + ``remove_user_data_tag`` removes a Tag object at a data address. + Since this removes a user tag, it will be added to the current undo buffer. + + :param int addr: Address at which to add the tag + :param Tag tag: Tag object to be added + :rtype None + """ + core.BNRemoveUserDataTag(self.handle, addr, tag.handle) + + def add_auto_data_tag(self, addr, tag): + """ + ``add_auto_data_tag`` adds an already-created Tag object at a data address. + + :param int addr: Address at which to add the tag + :param Tag tag: Tag object to be added + :rtype None + """ + core.BNAddAutoDataTag(self.handle, addr, tag.handle) + + def create_auto_data_tag(self, addr, type, data, unique=False): + """ + ``create_auto_data_tag`` creates and adds a Tag object at a data address. + + :param int addr: Address at which to add the tag + :param TagType type: Tag Type for the Tag that is created + :param str data: Additional data for the Tag + :param bool unique: If a tag already exists at this location with this data, don't add another + :return The created Tag + :rtype Tag + """ + if unique: + tags = self.get_data_tags_at(addr) + for tag in tags: + if tag.type == type and tag.data == data: + return + + tag = self.create_tag(type, data) + core.BNAddAutoDataTag(self.handle, addr, tag.handle) + return tag + + def remove_auto_data_tag(self, addr, tag): + """ + ``remove_auto_data_tag`` removes a Tag object at a data address. + Since this removes a user tag, it will be added to the current undo buffer. + + :param int addr: Address at which to add the tag + :param Tag tag: Tag object to be added + :rtype None + """ + core.BNRemoveAutoDataTag(self.handle, addr, tag.handle) + def is_never_branch_patch_available(self, addr, arch=None): """ ``is_never_branch_patch_available`` queries the architecture plugin to determine if the instruction at the diff --git a/python/function.py b/python/function.py index d7b03cf8..58565838 100644 --- a/python/function.py +++ b/python/function.py @@ -1,3 +1,4 @@ +# coding=utf-8 # Copyright (c) 2015-2019 Vector 35 Inc # # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -908,6 +909,255 @@ class Function(object): core.BNFreeAddressList(addrs) return result + def create_tag(self, type, data): + """ + ``create_tag`` creates a new Tag object but does not add it anywhere + + :param TagType type: The Tag Type for this Tag + :param str data: Additional data for the Tag + :return The created Tag + :rtype Tag + :Example: + + >>> tt = bv.tag_types["Crabby Functions"] + >>> tag = current_function.create_tag(tt, "Get Crabbed") + >>> current_function.add_user_address_tag(here, tag) + >>> + """ + return self.view.create_tag(type, data) + + @property + def address_tags(self): + """ + ``address_tags`` gets a list of all address Tags in the function. + Tags are returned as a list of (arch, address, Tag) tuples. + + :type [(Architecture, int, Tag)] + """ + count = ctypes.c_ulonglong() + tags = core.BNGetAddressTagReferences(self.handle, count) + result = [] + for i in range(0, count.value): + arch = binaryninja.architecture.CoreArchitecture(tags[i].arch) + tag = binaryninja.binaryview.Tag(core.BNNewTagReference(tags[i].tag)) + result.append((arch, tags[i].addr, tag)) + core.BNFreeTagReferences(tags, count.value) + return result + + def get_address_tags_at(self, addr, arch=None): + """ + ``get_address_tags_at`` gets a list of all Tags in the function at a given address. + + :param int addr: Address to get tags at + :param Architecture arch: Architecture for the block in which the Tag is added (optional) + :return A list of Tags + :rtype [Tag] + """ + if arch is None: + arch = self.arch + count = ctypes.c_ulonglong() + tags = core.BNGetAddressTags(self.handle, arch.handle, addr, count) + result = [] + for i in range(0, count.value): + result.append(binaryninja.binaryview.Tag(core.BNNewTagReference(tags[i]))) + core.BNFreeTagList(tags, count.value) + return result + + def add_user_address_tag(self, addr, tag, arch=None): + """ + ``add_user_address_tag`` adds an already-created Tag object at a given address. + Since this adds a user tag, it will be added to the current undo buffer. + + :param int addr: Address at which to add the tag + :param Tag tag: Tag object to be added + :param Architecture arch: Architecture for the block in which the Tag is added (optional) + :rtype None + """ + if arch is None: + arch = self.arch + core.BNAddUserAddressTag(self.handle, arch.handle, addr, tag.handle) + + def create_user_address_tag(self, addr, type, data, unique=False, arch=None): + """ + ``create_user_address_tag`` creates and adds a Tag object at a given address. + Since this adds a user tag, it will be added to the current undo buffer. + + :param int addr: Address at which to add the tag + :param TagType type: Tag Type for the Tag that is created + :param str data: Additional data for the Tag + :param bool unique: If a tag already exists at this location with this data, don't add another + :param Architecture arch: Architecture for the block in which the Tag is added (optional) + :return The created Tag + :rtype Tag + """ + if arch is None: + arch = self.arch + if unique: + tags = self.get_address_tags_at(addr, arch) + for tag in tags: + if tag.type == type and tag.data == data: + return + + tag = self.create_tag(type, data) + core.BNAddUserAddressTag(self.handle, arch.handle, addr, tag.handle) + return tag + + def remove_user_address_tag(self, addr, tag, arch=None): + """ + ``remove_user_address_tag`` removes a Tag object at a given address. + Since this removes a user tag, it will be added to the current undo buffer. + + :param int addr: Address at which to add the tag + :param Tag tag: Tag object to be added + :param Architecture arch: Architecture for the block in which the Tag is added (optional) + :rtype None + """ + if arch is None: + arch = self.arch + core.BNRemoveUserAddressTag(self.handle, arch.handle, addr, tag.handle) + + def add_auto_address_tag(self, addr, tag, arch=None): + """ + ``add_auto_address_tag`` adds an already-created Tag object at a given address. + + :param int addr: Address at which to add the tag + :param Tag tag: Tag object to be added + :param Architecture arch: Architecture for the block in which the Tag is added (optional) + :rtype None + """ + if arch is None: + arch = self.arch + core.BNAddAutoAddressTag(self.handle, arch.handle, addr, tag.handle) + + def create_auto_address_tag(self, addr, type, data, unique=False, arch=None): + """ + ``create_auto_address_tag`` creates and adds a Tag object at a given address. + + :param int addr: Address at which to add the tag + :param TagType type: Tag Type for the Tag that is created + :param str data: Additional data for the Tag + :param bool unique: If a tag already exists at this location with this data, don't add another + :param Architecture arch: Architecture for the block in which the Tag is added (optional) + :return The created Tag + :rtype Tag + """ + if arch is None: + arch = self.arch + if unique: + tags = self.get_address_tags_at(addr, arch) + for tag in tags: + if tag.type == type and tag.data == data: + return + + tag = self.create_tag(type, data) + core.BNAddAutoAddressTag(self.handle, arch.handle, addr, tag.handle) + return tag + + def remove_auto_address_tag(self, addr, tag, arch=None): + """ + ``remove_auto_address_tag`` removes a Tag object at a given address. + + :param int addr: Address at which to add the tag + :param Tag tag: Tag object to be added + :param Architecture arch: Architecture for the block in which the Tag is added (optional) + :rtype None + """ + if arch is None: + arch = self.arch + core.BNRemoveAutoAddressTag(self.handle, arch.handle, addr, tag.handle) + + @property + def function_tags(self): + """ + ``function_tags`` gets a list of all function Tags for the function. + + :type [Tag] + """ + count = ctypes.c_ulonglong() + tags = core.BNGetFunctionTags(self.handle, count) + result = [] + for i in range(0, count.value): + result.append(binaryninja.binaryview.Tag(core.BNNewTagReference(tags[i]))) + core.BNFreeTagList(tags, count.value) + return result + + def add_user_function_tag(self, tag): + """ + ``add_user_function_tag`` adds an already-created Tag object as a function tag. + Since this adds a user tag, it will be added to the current undo buffer. + + :param Tag tag: Tag object to be added + :rtype None + """ + core.BNAddUserFunctionTag(self.handle, tag.handle) + + def create_user_function_tag(self, type, data, unique=False): + """ + ``add_user_function_tag`` creates and adds a Tag object as a function tag. + Since this adds a user tag, it will be added to the current undo buffer. + + :param TagType type: Tag Type for the Tag that is created + :param str data: Additional data for the Tag + :param bool unique: If a tag already exists with this data, don't add another + :return The created Tag + :rtype Tag + """ + if unique: + for tag in self.function_tags: + if tag.type == type and tag.data == data: + return + + tag = self.create_tag(type, data) + core.BNAddUserFunctionTag(self.handle, tag.handle) + return tag + + def remove_user_function_tag(self, tag): + """ + ``remove_user_function_tag`` removes a Tag object as a function tag. + Since this removes a user tag, it will be added to the current undo buffer. + + :param Tag tag: Tag object to be added + :rtype None + """ + core.BNRemoveUserFunctionTag(self.handle, tag.handle) + + def add_auto_function_tag(self, tag): + """ + ``add_user_function_tag`` adds an already-created Tag object as a function tag. + + :param Tag tag: Tag object to be added + :rtype None + """ + core.BNAddAutoFunctionTag(self.handle, tag.handle) + + def create_auto_function_tag(self, type, data, unique=False): + """ + ``add_user_function_tag`` creates and adds a Tag object as a function tag. + + :param TagType type: Tag Type for the Tag that is created + :param str data: Additional data for the Tag + :param bool unique: If a tag already exists with this data, don't add another + :return The created Tag + :rtype Tag + """ + if unique: + for tag in self.function_tags: + if tag.type == type and tag.data == data: + return + + tag = self.create_tag(type, data) + core.BNAddAutoFunctionTag(self.handle, tag.handle) + return tag + + def remove_auto_function_tag(self, tag): + """ + ``remove_user_function_tag`` removes a Tag object as a function tag. + + :param Tag tag: Tag object to be added + :rtype None + """ + core.BNRemoveAutoFunctionTag(self.handle, tag.handle) + @property def low_level_il(self): """Deprecated property provided for compatibility. Use llil instead.""" diff --git a/ui/action.h b/ui/action.h index 7770a016..8559e887 100644 --- a/ui/action.h +++ b/ui/action.h @@ -81,6 +81,7 @@ struct BINARYNINJAUIAPI UIAction static void registerPluginCommandActions(); static void registerPluginCommandActions(const QString& prefix); static void registerHighlightColorActions(const QString& prefix); + static void registerBookmarkActions(const QString& prefix); static void setActionDisplayName(const QString& registeredName, const QString& displayName); static void setActionDisplayName(const QString& registeredName, const std::function<QString()>& displayNameFunc); @@ -139,6 +140,14 @@ struct BINARYNINJAUIAPI UIHighlightColorAction UIHighlightColorAction(const UIHighlightColorAction& other); }; +struct BINARYNINJAUIAPI UIBookmarkAction +{ + std::function<void (const UIActionContext& context, int index)> activate; + std::function<bool (const UIActionContext& context, int index)> isValid; + + UIBookmarkAction(const std::function<void (const UIActionContext& context, int index)>& activate, const std::function<bool (const UIActionContext& context, int index)>& isValid); +}; + enum ActionPriority { LowActionPriority, @@ -203,6 +212,9 @@ public: void bindHighlightColorActions(const QString& prefix, const UIHighlightColorAction& action); void unbindHighlightColorActions(const QString& prefix); + void bindBookmarkActions(const QString& prefix, const UIBookmarkAction& action); + void unbindBookmarkActions(const QString& prefix); + void setActionDisplayName(const QString& registeredName, const QString& displayName); void setActionDisplayName(const QString& registeredName, const std::function<QString()>& displayNameFunc); void setActionDisplayName(const QString& registeredName, const std::function<QString(const UIActionContext&)>& displayNameFunc); diff --git a/ui/flowgraphwidget.h b/ui/flowgraphwidget.h index a519ed97..3ec61019 100644 --- a/ui/flowgraphwidget.h +++ b/ui/flowgraphwidget.h @@ -288,6 +288,11 @@ private Q_SLOTS: void functionComment(); void commentAccepted(); void functionCommentAccepted(); + void bookmarkAddress(); + void unbookmarkAddress(); + void tagAddress(); + void tagAddressAccepted(TagTypeRef tt); + void manageAddressTags(); void convertToNop(); void alwaysBranch(); diff --git a/ui/linearview.h b/ui/linearview.h index 85586ca8..486b2326 100644 --- a/ui/linearview.h +++ b/ui/linearview.h @@ -142,6 +142,11 @@ private Q_SLOTS: void comment(); void commentAccepted(); void addUserXref(); + void bookmarkAddress(); + void unbookmarkAddress(); + void tagAddress(); + void tagAddressAccepted(TagTypeRef tt); + void manageAddressTags(); void convertToNop(); void alwaysBranch(); diff --git a/ui/taglist.h b/ui/taglist.h new file mode 100644 index 00000000..c2a5bd8a --- /dev/null +++ b/ui/taglist.h @@ -0,0 +1,231 @@ +#pragma once + +#include <QtCore/QAbstractItemModel> +#include <QtCore/QItemSelectionModel> +#include <QtWidgets/QTableView> +#include <QtWidgets/QTabWidget> +#include <QtWidgets/QStyledItemDelegate> +#include <QtWidgets/QDialog> +#include "binaryninjaapi.h" +#include "dockhandler.h" +#include "viewframe.h" +#include "filter.h" +#include "tagtypelist.h" + + +class BINARYNINJAUIAPI TagListModel: public QAbstractItemModel +{ + Q_OBJECT + +protected: + QWidget* m_owner; + BinaryViewRef m_data; + std::vector<BinaryNinja::TagReference> m_refs; + DisassemblySettingsRef m_settings; + +private: + void AddDisassemblyTokens(QList<QVariant>& line, std::vector<BinaryNinja::InstructionTextToken> tokens) const; + + void TrimLeadingWhitespace(QList<QVariant>& line) const; + + QVariant GetIconColumn(const BinaryNinja::TagReference& ref) const; + QVariant GetLocationColumn(const BinaryNinja::TagReference& ref) const; + QVariant GetDataColumn(const BinaryNinja::TagReference& ref) const; + QVariant GetPreviewColumn(const BinaryNinja::TagReference& ref) const; + +public: + TagListModel(QWidget* parent, BinaryViewRef data); + + BinaryNinja::TagReference& GetRef(int index) { return m_refs[index]; } + const BinaryNinja::TagReference& GetRef(int index) const { return m_refs[index]; } + + virtual QModelIndex index(int row, int col, const QModelIndex& parent) const override; + virtual QModelIndex parent(const QModelIndex& i) const override; + virtual bool hasChildren(const QModelIndex& parent) const override; + virtual int rowCount(const QModelIndex& parent) const override; + virtual int columnCount(const QModelIndex& parent) const override; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + virtual QVariant data(const QModelIndex& i, int role) const override; + virtual bool setData(const QModelIndex& i, const QVariant& value, int role = Qt::EditRole) override; + virtual Qt::ItemFlags flags(const QModelIndex& i) const override; + virtual void sort(int column, Qt::SortOrder order) override; + + bool setModelData(const std::vector<BinaryNinja::TagReference>& refs, QItemSelectionModel* selectionModel, int sortColumn, Qt::SortOrder sortOrder, bool& selectionUpdated); +}; + + +class BINARYNINJAUIAPI BookmarkListModel: public TagListModel +{ +public: + BookmarkListModel(QWidget* parent, BinaryViewRef data); + + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + virtual void sort(int column, Qt::SortOrder order) override; +}; + + +class BINARYNINJAUIAPI TagItemDelegate: public QStyledItemDelegate +{ + Q_OBJECT + +protected: + QFont m_font; + int m_baseline, m_charWidth, m_charHeight, m_charOffset; + + void initFont(); + +public: + TagItemDelegate(QWidget* parent); + + void updateFonts(); + + virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& idx) const override; + virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& idx) const override; + virtual void setEditorData(QWidget* editor, const QModelIndex& index) const override; +}; + + +class BINARYNINJAUIAPI BookmarkListItemDelegate: public TagItemDelegate +{ +public: + BookmarkListItemDelegate(QWidget* parent); + + virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& idx) const override; +}; + + +class BINARYNINJAUIAPI TagList: public QTableView, + public BinaryNinja::BinaryDataNotification, public FilterTarget +{ + Q_OBJECT + + ViewFrame* m_view; + TagListModel* m_list; + TagItemDelegate* m_itemDelegate; + BinaryViewRef m_data; + UIActionHandler* m_handler; + UIActionHandler m_actionHandler; + ContextMenuManager* m_contextMenuManager; + FilteredView* m_filterView; + Menu* m_menu; + +public: + typedef std::function<bool(const BinaryNinja::TagReference&)> FilterFn; + +private: + bool m_hasFilter; + FilterFn m_filter; + std::string m_searchFilter; + + QTimer* m_hoverTimer; + QTimer* m_updateTimer; + QPoint m_hoverPos; + + uint64_t m_curRefTarget = 0; + bool m_needsUpdate; + bool m_navToNextOrPrevStarted = false; + +protected: + virtual void contextMenuEvent(QContextMenuEvent* event) override; + virtual void keyPressEvent(QKeyEvent* e) override; + virtual void mouseMoveEvent(QMouseEvent* e) override; + virtual void mousePressEvent(QMouseEvent* e) override; + virtual void wheelEvent(QWheelEvent* e) override; + virtual void resizeEvent(QResizeEvent *event) override; + void goToReference(const QModelIndex& idx); + + void setFilter(const std::string& filter) override; + void scrollToFirstItem() override; + void scrollToCurrentItem() override; + void selectFirstItem() override; + void activateFirstItem() override; + + virtual void OnDataMetadataUpdated(BinaryNinja::BinaryView*, uint64_t) override; + +private Q_SLOTS: + void hoverTimerEvent(); + void updateTimerEvent(); + void referenceActivated(const QModelIndex& idx); + +public: + TagList(QWidget* parent, ViewFrame* view, BinaryViewRef data, TagListModel* model = nullptr, Menu* menu = nullptr); + virtual ~TagList(); + + static void registerActions(); + virtual void setModel(QAbstractItemModel* model) override; + + void notifyFontChanged(); + void removeSelection(); + + void clearFilter(); + void setFilter(FilterFn filter); + void setFilterView(FilteredView* filterView) { m_filterView = filterView; } + + void updateTags(); + + bool hasSelection(); + void navigateToNext(); + void navigateToPrev(); +}; + + +class BINARYNINJAUIAPI TagListWidget: public QWidget, public DockContextHandler +{ + Q_OBJECT + Q_INTERFACES(DockContextHandler) + + ViewFrame* m_view; + QTabWidget* m_tabs; + + TagList* m_bookmarkList; + FilteredView* m_bookmarkFilter; + + TagList* m_notificationList; + FilteredView* m_notificationFilter; + + TagTypeList* m_typeList; + + BinaryViewRef m_data; + UIActionHandler* m_handler; + +protected: + virtual void notifyFontChanged() override; + +private Q_SLOTS: + void bookmarkListUpdate(); + +public: + TagList* GetList(); + void editTag(TagRef tag); + + TagListWidget(QWidget* parent, ViewFrame* view, BinaryViewRef data); + virtual ~TagListWidget(); +}; + + +class BINARYNINJAUIAPI TagListDialog: public QDialog +{ + Q_OBJECT + +public: + typedef std::function<void(const TagRef&)> AddFn; + +private: + BinaryViewRef m_data; + TagList* m_list; + FilteredView* m_filter; + + AddFn m_addFn; + + QPushButton* m_removeButton; + +public: + TagListDialog(QWidget* parent, ViewFrame* frame, BinaryViewRef data, AddFn addFn); + void setFilter(TagList::FilterFn filter); + +private Q_SLOTS: + void updateActive(const QItemSelection&, const QItemSelection&); + void createTag(); + void createTagAccept(TagTypeRef tt); + void removeTag(); +}; diff --git a/ui/tagtypelist.h b/ui/tagtypelist.h new file mode 100644 index 00000000..cc7015a9 --- /dev/null +++ b/ui/tagtypelist.h @@ -0,0 +1,142 @@ +#pragma once + +#include <QtCore/QAbstractItemModel> +#include <QtCore/QItemSelectionModel> +#include <QtWidgets/QTableView> +#include <QtWidgets/QItemDelegate> +#include <QtWidgets/QDialog> +#include <QtWidgets/QComboBox> +#include "binaryninjaapi.h" +#include "dockhandler.h" +#include "viewframe.h" + + +class BINARYNINJAUIAPI TagTypeListModel: public QAbstractItemModel +{ + Q_OBJECT + + QWidget* m_owner; + BinaryViewRef m_data; + std::vector<TagTypeRef> m_refs; + +public: + TagTypeListModel(QWidget* parent, BinaryViewRef data); + + TagTypeRef& GetRef(int index) { return m_refs[index]; } + const TagTypeRef& GetRef(int index) const { return m_refs[index]; } + + virtual QModelIndex index(int row, int col, const QModelIndex& parent) const override; + virtual QModelIndex parent(const QModelIndex& i) const override; + virtual bool hasChildren(const QModelIndex& parent) const override; + virtual int rowCount(const QModelIndex& parent) const override; + virtual int columnCount(const QModelIndex& parent) const override; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + virtual QVariant data(const QModelIndex& i, int role) const override; + virtual bool setData(const QModelIndex& i, const QVariant& value, int role = Qt::EditRole) override; + virtual void sort(int column, Qt::SortOrder order) override; + virtual Qt::ItemFlags flags(const QModelIndex& i) const override; + + bool setModelData(const std::vector<TagTypeRef>& refs, QItemSelectionModel* selectionModel, int sortColumn, Qt::SortOrder sortOrder, bool& selectionUpdated); +}; + + +class BINARYNINJAUIAPI TagTypeItemDelegate: public QItemDelegate +{ + Q_OBJECT + + QFont m_font; + int m_baseline, m_charWidth, m_charHeight, m_charOffset; + + void initFont(); + +public: + TagTypeItemDelegate(QWidget* parent); + + void updateFonts(); + + virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& idx) const override; + virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& idx) const override; + virtual void setEditorData(QWidget* editor, const QModelIndex& index) const override; + virtual bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override; +}; + + +class BINARYNINJAUIAPI TagTypeList: public QTableView, public DockContextHandler, public BinaryNinja::BinaryDataNotification +{ + Q_OBJECT + Q_INTERFACES(DockContextHandler) + + ViewFrame* m_view; + TagTypeListModel* m_list; + TagTypeItemDelegate* m_itemDelegate; + BinaryViewRef m_data; + UIActionHandler* m_handler; + UIActionHandler m_actionHandler; + ContextMenuManager* m_contextMenuManager; + Menu* m_menu; + + QTimer* m_updateTimer; + bool m_needsUpdate; + +protected: + virtual void contextMenuEvent(QContextMenuEvent* event) override; + + virtual void OnDataMetadataUpdated(BinaryNinja::BinaryView*, uint64_t) override; + +private: + void createTagType(); + void removeTagType(); + +private Q_SLOTS: + void updateTimerEvent(); + +public: + TagTypeList(QWidget* parent, ViewFrame* view, BinaryViewRef data, Menu* menu = nullptr); + virtual ~TagTypeList(); + virtual void notifyFontChanged() override; + + static void registerActions(); + + void updateData(); + bool hasSelection(); +}; + +class BINARYNINJAUIAPI TagTypeDialogModel: public QAbstractItemModel +{ + Q_OBJECT + + QWidget* m_owner; + BinaryViewRef m_data; + std::vector<TagTypeRef> m_refs; + +public: + TagTypeDialogModel(QWidget* parent, BinaryViewRef data); + + TagTypeRef& GetRef(int index) { return m_refs[index]; } + const TagTypeRef& GetRef(int index) const { return m_refs[index]; } + + virtual QModelIndex index(int row, int col, const QModelIndex& parent) const override; + virtual QModelIndex parent(const QModelIndex& i) const override; + virtual bool hasChildren(const QModelIndex& parent) const override; + virtual int rowCount(const QModelIndex& parent) const override; + virtual int columnCount(const QModelIndex& parent) const override; + virtual QVariant data(const QModelIndex& i, int role) const override; +}; + +class BINARYNINJAUIAPI TagTypeSelectDialog: public QDialog +{ + Q_OBJECT + + BinaryViewRef m_data; + TagTypeDialogModel* m_model; + QComboBox* m_tagTypeList; + +private Q_SLOTS: + void select(); + +public: + TagTypeSelectDialog(QWidget* parent, BinaryViewRef data); + +Q_SIGNALS: + void selected(TagTypeRef tagType); +}; diff --git a/ui/uitypes.h b/ui/uitypes.h index 557063f3..9859cdb2 100644 --- a/ui/uitypes.h +++ b/ui/uitypes.h @@ -55,6 +55,8 @@ typedef BinaryNinja::Ref<BinaryNinja::Section> SectionRef; typedef BinaryNinja::Ref<BinaryNinja::Segment> SegmentRef; typedef BinaryNinja::Ref<BinaryNinja::Structure> StructureRef; typedef BinaryNinja::Ref<BinaryNinja::Symbol> SymbolRef; +typedef BinaryNinja::Ref<BinaryNinja::Tag> TagRef; +typedef BinaryNinja::Ref<BinaryNinja::TagType> TagTypeRef; typedef BinaryNinja::Ref<BinaryNinja::TemporaryFile> TemporaryFileRef; typedef BinaryNinja::Ref<BinaryNinja::Transform> TransformRef; typedef BinaryNinja::Ref<BinaryNinja::Type> TypeRef; diff --git a/ui/viewframe.h b/ui/viewframe.h index 0a73ad89..fefc72d2 100644 --- a/ui/viewframe.h +++ b/ui/viewframe.h @@ -246,6 +246,11 @@ public: void nextCrossReference(); void prevCrossReference(); + void showTags(); + void editTag(TagRef tag); + void nextTag(); + void prevTag(); + virtual UIActionContext actionContext(); void bindActions(); static void registerActions(); |
