diff options
| -rw-r--r-- | binaryninjaapi.h | 8 | ||||
| -rw-r--r-- | binaryninjacore.h | 22 | ||||
| -rw-r--r-- | function.cpp | 93 | ||||
| -rw-r--r-- | mediumlevelil.cpp | 14 | ||||
| -rw-r--r-- | python/function.py | 58 | ||||
| -rw-r--r-- | python/mediumlevelil.py | 22 | ||||
| -rw-r--r-- | python/variable.py | 9 | ||||
| -rw-r--r-- | suite/testcommon.py | 45 | ||||
| -rw-r--r-- | ui/flowgraphwidget.h | 1 | ||||
| -rw-r--r-- | ui/linearview.h | 39 | ||||
| -rw-r--r-- | ui/mergevariablesdialog.h | 76 | ||||
| -rw-r--r-- | ui/uitypes.h | 2 |
12 files changed, 364 insertions, 25 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 8af70be6..7c73d066 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -5736,6 +5736,8 @@ namespace BinaryNinja { bool IsVariableUserDefinded(const Variable& var); Confidence<Ref<Type>> GetVariableType(const Variable& var); std::string GetVariableName(const Variable& var); + std::string GetVariableNameOrDefault(const Variable& var); + std::string GetLastSeenVariableNameOrDefault(const Variable& var); void SetAutoIndirectBranches( Architecture* sourceArch, uint64_t source, const std::vector<ArchAndAddr>& branches); @@ -5880,6 +5882,10 @@ namespace BinaryNinja { BNDeadStoreElimination GetVariableDeadStoreElimination(const Variable& var); void SetVariableDeadStoreElimination(const Variable& var, BNDeadStoreElimination mode); + std::map<Variable, std::set<Variable>> GetMergedVariables(); + void MergeVariables(const Variable& target, const std::set<Variable>& sources); + void UnmergeVariables(const Variable& target, const std::set<Variable>& sources); + uint64_t GetHighestAddress(); uint64_t GetLowestAddress(); std::vector<BNAddressRange> GetAddressRanges(); @@ -6755,6 +6761,8 @@ namespace BinaryNinja { } Ref<FlowGraph> CreateFunctionGraph(DisassemblySettings* settings = nullptr); + + std::set<size_t> GetLiveInstructionsForVariable(const Variable& var, bool includeLastUse = true); }; struct HighLevelILInstruction; diff --git a/binaryninjacore.h b/binaryninjacore.h index 6c830729..082dd4aa 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -36,14 +36,14 @@ // Current ABI version for linking to the core. This is incremented any time // there are changes to the API that affect linking, including new functions, // new types, or modifications to existing functions or types. -#define BN_CURRENT_CORE_ABI_VERSION 23 +#define BN_CURRENT_CORE_ABI_VERSION 24 // Minimum ABI version that is supported for loading of plugins. Plugins that // are linked to an ABI version less than this will not be able to load and // will require rebuilding. The minimum version is increased when there are // incompatible changes that break binary compatibility, such as changes to // existing types or functions. -#define BN_MINIMUM_CORE_ABI_VERSION 22 +#define BN_MINIMUM_CORE_ABI_VERSION 24 #ifdef __GNUC__ #ifdef BINARYNINJACORE_LIBRARY @@ -2849,6 +2849,13 @@ extern "C" const char* channel; }; + struct BNMergedVariable + { + BNVariable target; + BNVariable* sources; + size_t sourceCount; + }; + BINARYNINJACOREAPI char* BNAllocString(const char* contents); BINARYNINJACOREAPI void BNFreeString(char* str); BINARYNINJACOREAPI char** BNAllocStringList(const char** contents, size_t size); @@ -3989,13 +3996,20 @@ extern "C" BINARYNINJACOREAPI bool BNIsVariableUserDefined(BNFunction* func, const BNVariable* var); BINARYNINJACOREAPI BNTypeWithConfidence BNGetVariableType(BNFunction* func, const BNVariable* var); BINARYNINJACOREAPI char* BNGetVariableName(BNFunction* func, const BNVariable* var); - BINARYNINJACOREAPI char* BNGetRealVariableName(BNFunction* func, BNArchitecture* arch, const BNVariable* var); + BINARYNINJACOREAPI char* BNGetVariableNameOrDefault(BNFunction* func, const BNVariable* var); + BINARYNINJACOREAPI char* BNGetLastSeenVariableNameOrDefault(BNFunction* func, const BNVariable* var); BINARYNINJACOREAPI uint64_t BNToVariableIdentifier(const BNVariable* var); BINARYNINJACOREAPI BNVariable BNFromVariableIdentifier(uint64_t id); BINARYNINJACOREAPI BNDeadStoreElimination BNGetFunctionVariableDeadStoreElimination( BNFunction* func, const BNVariable* var); BINARYNINJACOREAPI void BNSetFunctionVariableDeadStoreElimination( BNFunction* func, const BNVariable* var, BNDeadStoreElimination mode); + BINARYNINJACOREAPI BNMergedVariable* BNGetMergedVariables(BNFunction* func, size_t* count); + BINARYNINJACOREAPI void BNFreeMergedVariableList(BNMergedVariable* vars, size_t count); + BINARYNINJACOREAPI void BNMergeVariables(BNFunction* func, const BNVariable* target, const BNVariable* sources, + size_t sourceCount); + BINARYNINJACOREAPI void BNUnmergeVariables(BNFunction* func, const BNVariable* target, const BNVariable* sources, + size_t sourceCount); BINARYNINJACOREAPI BNReferenceSource* BNGetFunctionCallSites(BNFunction* func, size_t* count); BINARYNINJACOREAPI uint64_t* BNGetCallees(BNBinaryView* view, BNReferenceSource* callSite, size_t* count); @@ -4892,6 +4906,8 @@ extern "C" BNMediumLevelILFunction* func, const BNVariable* var, size_t* count); BINARYNINJACOREAPI size_t* BNGetMediumLevelILVariableUses( BNMediumLevelILFunction* func, const BNVariable* var, size_t* count); + BINARYNINJACOREAPI size_t* BNGetMediumLevelILLiveInstructionsForVariable( + BNMediumLevelILFunction* func, const BNVariable* var, bool includeLastUse, size_t* count); BINARYNINJACOREAPI BNRegisterValue BNGetMediumLevelILSSAVarValue( BNMediumLevelILFunction* func, const BNVariable* var, size_t version); diff --git a/function.cpp b/function.cpp index c93a8329..06815c39 100644 --- a/function.cpp +++ b/function.cpp @@ -1496,6 +1496,24 @@ string Function::GetVariableName(const Variable& var) } +string Function::GetVariableNameOrDefault(const Variable& var) +{ + char* name = BNGetVariableNameOrDefault(m_object, &var); + string result = name; + BNFreeString(name); + return result; +} + + +string Function::GetLastSeenVariableNameOrDefault(const Variable& var) +{ + char* name = BNGetLastSeenVariableNameOrDefault(m_object, &var); + string result = name; + BNFreeString(name); + return result; +} + + void Function::SetAutoIndirectBranches( Architecture* sourceArch, uint64_t source, const std::vector<ArchAndAddr>& branches) { @@ -2518,6 +2536,81 @@ void Function::SetVariableDeadStoreElimination(const Variable& var, BNDeadStoreE } +std::map<Variable, std::set<Variable>> Function::GetMergedVariables() +{ + size_t count; + BNMergedVariable* mergedVars = BNGetMergedVariables(m_object, &count); + + std::map<Variable, std::set<Variable>> result; + for (size_t i = 0; i < count; i++) + { + Variable target; + target.type = mergedVars[i].target.type; + target.index = mergedVars[i].target.index; + target.storage = mergedVars[i].target.storage; + + set<Variable> sources; + for (size_t j = 0; j < mergedVars[i].sourceCount; j++) + { + Variable source; + source.type = mergedVars[i].sources[j].type; + source.index = mergedVars[i].sources[j].index; + source.storage = mergedVars[i].sources[j].storage; + sources.insert(source); + } + + result[target] = sources; + } + + BNFreeMergedVariableList(mergedVars, count); + return result; +} + + +void Function::MergeVariables(const Variable& target, const std::set<Variable>& sources) +{ + BNVariable targetData; + targetData.type = target.type; + targetData.index = target.index; + targetData.storage = target.storage; + + BNVariable* sourceData = new BNVariable[sources.size()]; + size_t i = 0; + for (auto& var : sources) + { + sourceData[i].type = var.type; + sourceData[i].index = var.index; + sourceData[i].storage = var.storage; + i++; + } + + BNMergeVariables(m_object, &targetData, sourceData, sources.size()); + delete[] sourceData; +} + + +void Function::UnmergeVariables(const Variable& target, const std::set<Variable>& sources) +{ + BNVariable targetData; + targetData.type = target.type; + targetData.index = target.index; + targetData.storage = target.storage; + + BNVariable* sourceData = new BNVariable[sources.size()]; + size_t i = 0; + for (auto& var : sources) + { + sourceData[i].type = var.type; + sourceData[i].index = var.index; + sourceData[i].storage = var.storage; + i++; + } + + BNUnmergeVariables(m_object, &targetData, sourceData, sources.size()); + delete[] sourceData; +} + + vector<ILReferenceSource> Function::GetMediumLevelILVariableReferences(const Variable& var) { size_t count; diff --git a/mediumlevelil.cpp b/mediumlevelil.cpp index 71604caf..6827c356 100644 --- a/mediumlevelil.cpp +++ b/mediumlevelil.cpp @@ -847,3 +847,17 @@ Ref<FlowGraph> MediumLevelILFunction::CreateFunctionGraph(DisassemblySettings* s BNFlowGraph* graph = BNCreateMediumLevelILFunctionGraph(m_object, settings ? settings->GetObject() : nullptr); return new CoreFlowGraph(graph); } + + +set<size_t> MediumLevelILFunction::GetLiveInstructionsForVariable(const Variable& var, bool includeLastUse) +{ + size_t count; + size_t* instrs = BNGetMediumLevelILLiveInstructionsForVariable(m_object, &var, includeLastUse, &count); + + set<size_t> result; + for (size_t i = 0; i < count; i++) + result.insert(instrs[i]); + + BNFreeILInstructionList(instrs); + return result; +} diff --git a/python/function.py b/python/function.py index 9a0f099a..d2855234 100644 --- a/python/function.py +++ b/python/function.py @@ -1377,6 +1377,26 @@ class Function: return None return flowgraph.CoreFlowGraph(graph) + @property + def merged_vars(self) -> Dict['variable.Variable', List['variable.Variable']]: + """ + Map of merged variables, organized by target variable (read-only). Use ``merge_vars`` and + ``unmerge_vars`` to update merged variables. + """ + count = ctypes.c_ulonglong() + data = core.BNGetMergedVariables(self.handle, count) + + result = {} + for i in range(count.value): + target = Variable.from_BNVariable(self, data[i].target) + sources = [] + for j in range(data[i].sourceCount): + sources.append(Variable.from_BNVariable(self, data[i].sources[j])) + result[target] = sources + + core.BNFreeMergedVariableList(data, count.value) + return result + def mark_recent_use(self) -> None: core.BNMarkFunctionAsRecentlyUsed(self.handle) @@ -3316,6 +3336,44 @@ class Function: return start.value return None + def merge_vars( + self, target: 'variable.Variable', sources: Union[List['variable.Variable'], 'variable.Variable'] + ) -> None: + """ + ``merge_vars`` merges one or more varibles in ``sources`` into the ``target`` variable. All + variable accesses to the variables in ``sources`` will be rewritten to use ``target``. + + :param Variable target: target variable + :param list(Variable) sources: list of source variables + """ + if isinstance(sources, variable.Variable): + sources = [sources] + source_list = (core.BNVariable * len(sources))() + for i in range(0, len(sources)): + source_list[i].type = sources[i].source_type + source_list[i].index = sources[i].index + source_list[i].storage = sources[i].storage + core.BNMergeVariables(self.handle, target.to_BNVariable(), source_list, len(sources)) + + def unmerge_vars( + self, target: 'variable.Variable', sources: Union[List['variable.Variable'], 'variable.Variable'] + ) -> None: + """ + ``unmerge_vars`` undoes variable merging performed with ``merge_vars``. The variables in + ``sources`` will no longer be merged into the ``target`` variable. + + :param Variable target: target variable + :param list(Variable) sources: list of source variables + """ + if isinstance(sources, variable.Variable): + sources = [sources] + source_list = (core.BNVariable * len(sources))() + for i in range(0, len(sources)): + source_list[i].type = sources[i].source_type + source_list[i].index = sources[i].index + source_list[i].storage = sources[i].storage + core.BNUnmergeVariables(self.handle, target.to_BNVariable(), source_list, len(sources)) + class AdvancedFunctionAnalysisDataRequestor: def __init__(self, func: 'Function' = None): diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 07ca7a22..ceb33f50 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -3024,6 +3024,28 @@ class MediumLevelILFunction: finally: core.BNFreeILInstructionList(instrs) + def get_live_instructions_for_var(self, var: 'variable.Variable', include_last_use: bool = True) -> List[MediumLevelILInstruction]: + """ + ``get_live_instructions_for_var`` computes the list of instructions for which ``var`` is live. + If ``include_last_use`` is False, the last use of the variable will not be included in the + list (this allows for easier computation of overlaps in liveness between two variables). + If the variable is never used, this function will return an empty list. + + :param SSAVariable var: the variable to query + :param bool include_last_use: whether to include the last use of the variable in the list of instructions + :return: list of instructions for which ``var`` is live + :rtype: list(MediumLevelILInstruction) + """ + count = ctypes.c_ulonglong() + var_data = var.to_BNVariable() + instrs = core.BNGetMediumLevelILLiveInstructionsForVariable(self.handle, var_data, include_last_use, count) + assert instrs is not None, "core.BNGetMediumLevelILLiveInstructionsForVariable returned None" + result = [] + for i in range(0, count.value): + result.append(self[instrs[i]]) + core.BNFreeILInstructionList(instrs) + return result + def get_ssa_var_value(self, ssa_var: SSAVariable) -> 'variable.RegisterValue': var_data = ssa_var.var.to_BNVariable() value = core.BNGetMediumLevelILSSAVarValue(self.handle, var_data, ssa_var.version) diff --git a/python/variable.py b/python/variable.py index 07b8863c..839e87ce 100644 --- a/python/variable.py +++ b/python/variable.py @@ -663,7 +663,7 @@ class Variable(CoreVariable): if self.type is not None: return f"<var {self.type.get_string_before_name()} {self.name}{self.type.get_string_after_name()}>" else: - return repr(super()) + return f"<var {self.name}>" def __str__(self): return self.name @@ -712,7 +712,7 @@ class Variable(CoreVariable): @property def name(self) -> str: """Name of the variable, Settings thisslow because it ensures that analysis has been updated. """ - return core.BNGetRealVariableName(self._function.handle, self._function.arch.handle, self.to_BNVariable()) + return core.BNGetVariableNameOrDefault(self._function.handle, self.to_BNVariable()) @name.setter def name(self, name: Optional[str]) -> None: @@ -720,6 +720,11 @@ class Variable(CoreVariable): self._function.view.update_analysis_and_wait() @property + def last_seen_name(self) -> str: + """Name of the variable, or the name most recently assigned if the variable has since been removed (read-only). """ + return core.BNGetLastSeenVariableNameOrDefault(self._function.handle, self.to_BNVariable()) + + @property def type(self) -> Optional['binaryninja.types.Type']: var_type_conf = core.BNGetVariableType(self._function.handle, self.to_BNVariable()) if var_type_conf.type: diff --git a/suite/testcommon.py b/suite/testcommon.py index a2c77037..f77d3cf6 100644 --- a/suite/testcommon.py +++ b/suite/testcommon.py @@ -1447,6 +1447,51 @@ class TestBuilder(Builder): assert code1 != code2 assert text1 != text2, f"{asm1} and {asm2} are different but both disassemble to {text1}" + def test_merge_vars(self): + """Variable merging produced different output""" + file_name = self.unpackage_file("array_test.bndb") + try: + with binja.BinaryViewType.get_view_of_file(file_name) as bv: + func = bv.get_function_at(0x100003920) + target = None + sources = [] + for var in func.vars: + if var.storage == -0x758: + target = var + func.delete_user_var(var) + if var.storage in [-0x760, -0x768, -0x778]: + sources.append(var) + func.delete_user_var(var) + + func.merge_vars(target, sources) + bv.update_analysis_and_wait() + + retinfo = ["HLIL after merge: " + x for x in str(func.hlil).split("\n")] + + sources = sources[1:] + func.unmerge_vars(target, sources) + bv.update_analysis_and_wait() + + retinfo += ["HLIL after unmerge: " + x for x in str(func.hlil).split("\n")] + return retinfo + finally: + self.delete_package("array_test.bndb") + + def test_live_instrs_for_var(self): + """Live instructions for variable produced different output""" + file_name = self.unpackage_file("array_test.bndb") + try: + with binja.BinaryViewType.get_view_of_file(file_name) as bv: + func = bv.get_function_at(0x100003920) + retinfo = [] + for var in func.vars: + instrs = func.mlil.get_live_instructions_for_var(var) + for instr in instrs: + retinfo += [f"MLIL live instr for {var}: {repr(instr)}"] + return retinfo + finally: + self.delete_package("array_test.bndb") + class VerifyBuilder(Builder): """ The VerifyBuilder is for tests that verify diff --git a/ui/flowgraphwidget.h b/ui/flowgraphwidget.h index f6a38a85..f4751dea 100644 --- a/ui/flowgraphwidget.h +++ b/ui/flowgraphwidget.h @@ -338,6 +338,7 @@ class BINARYNINJAUIAPI FlowGraphWidget : void tagAddress(); void tagAddressAccepted(TagTypeRef tt); void manageAddressTags(); + void mergeVariables(); void convertToNop(); void alwaysBranch(); diff --git a/ui/linearview.h b/ui/linearview.h index 6bec459c..38d8dfaf 100644 --- a/ui/linearview.h +++ b/ui/linearview.h @@ -66,7 +66,7 @@ class BINARYNINJAUIAPI LinearViewHistoryEntry : public HistoryEntry bool m_inFunc = false; HighlightTokenState m_highlight; - public: +public: const std::vector<BinaryNinja::LinearViewObjectIdentifier>& getTopPath() const { return m_topPath; } size_t getTopLineIndex() const { return m_topLineIndex; } uint64_t getTopAddress() const { return m_topAddr; } @@ -99,22 +99,22 @@ class BINARYNINJAUIAPI LinearView : public QAbstractScrollArea, public View, pub class LinearViewOptionsWidget : public MenuHelper { - public: + public: LinearViewOptionsWidget(LinearView* parent); - protected: + protected: virtual void showMenu(); - private: + private: LinearView* m_view; }; class LinearViewOptionsIconWidget : public QWidget { - public: + public: LinearViewOptionsIconWidget(LinearView* parent); - private: + private: LinearView* m_view; ContextMenuManager* m_contextMenuManager; Menu m_menu; @@ -124,11 +124,11 @@ class BINARYNINJAUIAPI LinearView : public QAbstractScrollArea, public View, pub class LinearViewStatusBarWidget : public StatusBarWidget { - public: + public: LinearViewStatusBarWidget(LinearView* parent); virtual void updateStatus() override; - private: + private: LinearView* m_view; LinearViewOptionsWidget* m_options; ILChooserWidget* m_chooser; @@ -199,7 +199,7 @@ class BINARYNINJAUIAPI LinearView : public QAbstractScrollArea, public View, pub void refreshAtCurrentLocation(bool cursorFixup = false); bool navigateToAddress(uint64_t addr, bool center, bool updateHighlight, bool navByRef = false); bool navigateToLine( - FunctionRef func, uint64_t offset, size_t instrIndex, bool center, bool updateHighlight, bool navByRef = false); + FunctionRef func, uint64_t offset, size_t instrIndex, bool center, bool updateHighlight, bool navByRef = false); bool navigateToGotoLabel(uint64_t label); void viewData(); @@ -209,7 +209,7 @@ class BINARYNINJAUIAPI LinearView : public QAbstractScrollArea, public View, pub static void addOptionsMenuActions(Menu& menu); void getHexDumpLineBytes( - const BinaryNinja::LinearDisassemblyLine& line, size_t& skippedBytes, size_t& totalBytes, size_t& totalCols); + const BinaryNinja::LinearDisassemblyLine& line, size_t& skippedBytes, size_t& totalBytes, size_t& totalCols); void paintHexDumpLine(QPainter& p, const LinearViewLine& line, int xoffset, int y, uint32_t addrLen, int tagOffset); void paintAnalysisWarningLine(QPainter& p, const LinearViewLine& line, int xoffset, int y); @@ -223,9 +223,9 @@ class BINARYNINJAUIAPI LinearView : public QAbstractScrollArea, public View, pub TypeRef createStructure(BinaryNinja::QualifiedName& name, uint64_t size); TypeRef getInnerType(TypeRef type, uint64_t offset, uint64_t size, std::set<TypeRef>& seen); StructureRef defineInnerType( - TypeRef type, TypeRef baseType, uint64_t offset, uint64_t size, std::set<TypeRef>& seen); + TypeRef type, TypeRef baseType, uint64_t offset, uint64_t size, std::set<TypeRef>& seen); StructureRef defineInnerPointer(TypeRef type, ArchitectureRef arch, uint64_t baseAddress, uint64_t offset, - uint64_t size, std::set<TypeRef>& seen); + uint64_t size, std::set<TypeRef>& seen); StructureRef defineInnerStruct(TypeRef type, uint64_t offset, uint64_t size, std::set<TypeRef>& seen); StructureRef defineInnerArray(TypeRef type, uint64_t offset, uint64_t size, std::set<TypeRef>& seen); StructureRef defineInnerName(TypeRef type, uint64_t offset, uint64_t size, std::set<TypeRef>& seen); @@ -239,7 +239,7 @@ class BINARYNINJAUIAPI LinearView : public QAbstractScrollArea, public View, pub bool updateCursor(LinearViewCursorPosition& cursorToUpdate, BinaryNinja::LinearViewCursor* matched, bool fullMatch); bool updateCursor(LinearViewCursorPosition& cursorToUpdate, BinaryNinja::LinearViewCursor* newCursor); bool updateCursor(LinearViewCursorPosition& cursorToUpdate, - const std::vector<BinaryNinja::LinearViewObjectIdentifier>& path, BinaryNinja::LinearViewCursor* newCursor); + const std::vector<BinaryNinja::LinearViewObjectIdentifier>& path, BinaryNinja::LinearViewCursor* newCursor); uint64_t getOrderingIndexForLine(const LinearViewLine& line); void updateAnalysisRequestorsForCache(); @@ -250,13 +250,13 @@ class BINARYNINJAUIAPI LinearView : public QAbstractScrollArea, public View, pub BNAnalysisWarningActionType getAnalysisWarningActionAtPos(const LinearViewLine& line, int x); void getCurrentOffsetByTypeInternal( - TypeRef resType, uint64_t baseAddr, uint64_t& begin, uint64_t& end, bool singleLine, std::set<TypeRef>& seen); + TypeRef resType, uint64_t baseAddr, uint64_t& begin, uint64_t& end, bool singleLine, std::set<TypeRef>& seen); BNDeadStoreElimination getCurrentVariableDeadStoreElimination(); void setDataButtonVisible(bool visible); - private Q_SLOTS: +private Q_SLOTS: void adjustSize(int width, int height); void viewInHexEditor(); void viewInGraph(); @@ -310,6 +310,7 @@ class BINARYNINJAUIAPI LinearView : public QAbstractScrollArea, public View, pub void createArray(); void createStruct(); void createNewTypes(); + void mergeVariables(); //! Get the length of of the string (if there is one) starting at the //! given address. String type is assumed to be UTF-8 by default, but the @@ -335,10 +336,10 @@ class BINARYNINJAUIAPI LinearView : public QAbstractScrollArea, public View, pub void setCurrentVariableDeadStoreElimination(BNDeadStoreElimination elimination); - Q_SIGNALS: +Q_SIGNALS: void notifyResizeEvent(int width, int height); - public: +public: explicit LinearView(BinaryViewRef data, ViewFrame* view); virtual ~LinearView(); @@ -423,7 +424,7 @@ class BINARYNINJAUIAPI LinearView : public QAbstractScrollArea, public View, pub static void registerActions(); - protected: +protected: virtual void resizeEvent(QResizeEvent* event) override; virtual void paintEvent(QPaintEvent* event) override; virtual void wheelEvent(QWheelEvent* event) override; @@ -452,7 +453,7 @@ class LinearViewType : public ViewType { static LinearViewType* m_instance; - public: +public: LinearViewType(); virtual int getPriority(BinaryViewRef data, const QString& filename) override; virtual QWidget* create(BinaryViewRef data, ViewFrame* viewFrame) override; diff --git a/ui/mergevariablesdialog.h b/ui/mergevariablesdialog.h new file mode 100644 index 00000000..b4c81c06 --- /dev/null +++ b/ui/mergevariablesdialog.h @@ -0,0 +1,76 @@ +#pragma once + +#include <QtWidgets/QDialog> +#include <QtWidgets/QComboBox> +#include <QtWidgets/QListWidget> +#include <QtWidgets/QListWidgetItem> +#include <QtWidgets/QStyledItemDelegate> + +#include <string> +#include "binaryninjaapi.h" +#include "uicontext.h" +#include "render.h" + +class BINARYNINJAUIAPI MergeVariableHeader : public QWidget +{ + std::vector<BinaryNinja::InstructionTextToken> m_tokens; + RenderContext m_renderContext; + int m_length; + +protected: + void paintEvent(QPaintEvent* event) override; + QSize sizeHint() const override; + +public: + MergeVariableHeader(const std::vector<BinaryNinja::InstructionTextToken>& tokens, QWidget* parent = nullptr); +}; + +class BINARYNINJAUIAPI MergeVariableListItem : public QListWidgetItem +{ + QWidget* m_owner; + FunctionRef m_func; + BinaryNinja::Variable m_var; + std::string m_name; + BinaryNinja::Confidence<BinaryNinja::Ref<BinaryNinja::Type>> m_type; + bool m_grayed; + +public: + MergeVariableListItem(QWidget* parent, BinaryNinja::Function* func, const BinaryNinja::Variable& var, + const std::string& name, BinaryNinja::Confidence<BinaryNinja::Ref<BinaryNinja::Type>> type, + const QString& warnings, bool grayed); + const BinaryNinja::Variable& variable() const { return m_var; } + virtual QVariant data(int role) const override; + + static std::vector<BinaryNinja::InstructionTextToken> tokensForVariable(BinaryNinja::Function* func, + const BinaryNinja::Variable& var, BinaryNinja::Confidence<BinaryNinja::Ref<BinaryNinja::Type>> type, + const std::string& name); +}; + +class BINARYNINJAUIAPI MergeVariableItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT + + QWidget* m_parent; + QFont m_font; + int m_baseline, m_charWidth, m_charHeight, m_charOffset; + +public: + MergeVariableItemDelegate(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; +}; + +class BINARYNINJAUIAPI MergeVariablesDialog : public QDialog +{ + Q_OBJECT + QListWidget* m_list; + std::set<BinaryNinja::Variable> m_existingVariables; + +public: + MergeVariablesDialog(QWidget* parent, FunctionRef func, BinaryNinja::Variable target); + + std::set<BinaryNinja::Variable> mergedVariables(); + std::set<BinaryNinja::Variable> unmergedVariables(); +}; diff --git a/ui/uitypes.h b/ui/uitypes.h index f16a84eb..b47444e4 100644 --- a/ui/uitypes.h +++ b/ui/uitypes.h @@ -6,7 +6,7 @@ // there are changes to the API that affect linking, including new functions, // new types, modifications to existing functions or types, or new versions // of the Qt libraries. -#define BN_CURRENT_UI_ABI_VERSION 5 +#define BN_CURRENT_UI_ABI_VERSION 6 // Minimum ABI version that is supported for loading of plugins. Plugins that // are linked to an ABI version less than this will not be able to load and |
