diff options
| author | Rusty Wagner <rusty@vector35.com> | 2019-03-19 15:41:08 -0400 |
|---|---|---|
| committer | Rusty Wagner <rusty@vector35.com> | 2019-03-20 13:00:17 -0400 |
| commit | 411acbaa4a1d217e731d3df0b189445117be3b26 (patch) | |
| tree | 49b5c5290058ffb98dd23ec9a7c1a49921254d15 | |
| parent | ca1bc587c22928bbd7198813064c9615c3c12771 (diff) | |
Add in progress UI API headers
46 files changed, 4092 insertions, 0 deletions
diff --git a/ui/action.h b/ui/action.h new file mode 100644 index 00000000..b3050717 --- /dev/null +++ b/ui/action.h @@ -0,0 +1,367 @@ +#pragma once + +#include <QtWidgets/QMenu> +#include <QtWidgets/QMenuBar> +#include <QtGui/QIcon> +#include <QtWidgets/QShortcut> +#include <QtCore/QPointer> +#include <functional> +#include <map> +#include <set> +#include <vector> +#include "uitypes.h" + +#define MENU_ORDER_FIRST 0 +#define MENU_ORDER_EARLY 64 +#define MENU_ORDER_NORMAL 128 +#define MENU_ORDER_LATE 192 +#define MENU_ORDER_LAST 255 + +class View; +class UIContext; + +struct BINARYNINJAUIAPI HighlightTokenState +{ + bool valid; + bool secondaryHighlight; + BNInstructionTextTokenType type; + BinaryNinja::InstructionTextToken token; + ArchitectureRef arch; + bool addrValid, localVarValid, isDest; + uint64_t addr; + BinaryNinja::Variable localVar; + + HighlightTokenState(); +}; + +struct BINARYNINJAUIAPI UIActionContext +{ + UIContext* context; + View* view; + QWidget* widget; + HighlightTokenState token; + + BinaryViewRef binaryView; + uint64_t address, length; + size_t instrIndex; + FunctionRef function; + LowLevelILFunctionRef lowLevelILFunction; + MediumLevelILFunctionRef mediumLevelILFunction; + + UIActionContext(); + UIActionContext(const BinaryNinja::PluginCommandContext& pluginContext); + operator BinaryNinja::PluginCommandContext() const; +}; + +struct BINARYNINJAUIAPI UIAction +{ + std::function<void (const UIActionContext& context)> activate; + std::function<bool (const UIActionContext& context)> isValid; + + UIAction(); + UIAction(const std::function<void (const UIActionContext& context)>& activate); + UIAction(const std::function<void()>& activate); + UIAction(const std::function<void (const UIActionContext& context)>& activate, + const std::function<bool (const UIActionContext& context)>& isValid); + UIAction(const std::function<void()>& activate, + const std::function<bool (const UIActionContext& context)>& isValid); + UIAction(const std::function<void (const UIActionContext& context)>& activate, + const std::function<bool()>& isValid); + UIAction(const std::function<void()>& activate, + const std::function<bool()>& isValid); + UIAction(const UIAction& other); + + static void registerAction(const QString& name, const QKeySequence& defaultKeyBinding = QKeySequence()); + static void registerAction(const QString& name, const QList<QKeySequence>& defaultKeyBinding); + + static void registerTransformActions(); + static void registerPluginCommandActions(); + static void registerPluginCommandActions(const QString& prefix); + static void registerHighlightColorActions(const QString& prefix); + + static void setActionDisplayName(const QString& registeredName, const QString& displayName); + static void setActionDisplayName(const QString& registeredName, const std::function<QString()>& displayNameFunc); + static void setActionDisplayName(const QString& registeredName, const std::function<QString(const UIActionContext&)>& displayNameFunc); + + static bool isActionRegistered(const QString& name); + static std::set<QString> getAllRegisteredActions(); + static QList<QKeySequence> getDefaultKeyBinding(const QString& name); + static QList<QKeySequence> getKeyBinding(const QString& name); + static QString getActionDisplayName(const QString& name, const UIActionContext& context); + + static int rawControl(); + static int rawMeta(); + + static void setUserKeyBinding(const QString& name, const QList<QKeySequence>& keyBinding); + static void resetKeyBindingToDefault(const QString& name); + static void readKeyBindingsFile(); + static void writeKeyBindingsFile(); +}; + +struct BINARYNINJAUIAPI UITransformAction +{ + std::function<void (const UIActionContext& context, TransformRef xform)> activate; + std::function<bool (const UIActionContext& context, TransformRef xform)> isValid; + + UITransformAction(); + UITransformAction(const std::function<void (const UIActionContext& context, TransformRef xform)>& activate); + UITransformAction(const std::function<void(TransformRef xform)>& activate); + UITransformAction(const std::function<void (const UIActionContext& context, TransformRef xform)>& activate, + const std::function<bool (const UIActionContext& context, TransformRef xform)>& isValid); + UITransformAction(const std::function<void(TransformRef xform)>& activate, + const std::function<bool (const UIActionContext& context, TransformRef xform)>& isValid); + UITransformAction(const std::function<void (const UIActionContext& context, TransformRef xform)>& activate, + const std::function<bool(TransformRef xform)>& isValid); + UITransformAction(const std::function<void(TransformRef xform)>& activate, + const std::function<bool(TransformRef xform)>& isValid); + UITransformAction(const UITransformAction& other); +}; + +struct BINARYNINJAUIAPI UIHighlightColorAction +{ + std::function<void (const UIActionContext& context, BNHighlightColor color)> activate; + std::function<bool (const UIActionContext& context)> isValid; + + UIHighlightColorAction(); + UIHighlightColorAction(const std::function<void (const UIActionContext& context, BNHighlightColor color)>& activate); + UIHighlightColorAction(const std::function<void(BNHighlightColor color)>& activate); + UIHighlightColorAction(const std::function<void (const UIActionContext& context, BNHighlightColor color)>& activate, + const std::function<bool (const UIActionContext& context)>& isValid); + UIHighlightColorAction(const std::function<void(BNHighlightColor color)>& activate, + const std::function<bool (const UIActionContext& context)>& isValid); + UIHighlightColorAction(const std::function<void (const UIActionContext& context, BNHighlightColor color)>& activate, + const std::function<bool()>& isValid); + UIHighlightColorAction(const std::function<void(BNHighlightColor color)>& activate, + const std::function<bool()>& isValid); + UIHighlightColorAction(const UIHighlightColorAction& other); +}; + +enum ActionPriority +{ + LowActionPriority, + NormalActionPriority, + HighActionPriority +}; + +class BINARYNINJAUIAPI UIActionHandler +{ + std::map<QString, UIAction> m_actions; + std::map<QString, ActionPriority> m_priority; + std::map<QString, std::function<QString(const UIActionContext&)>> m_actionDisplayNames; + std::map<QString, std::function<bool(const UIActionContext&)>> m_checked; + QWidget* m_handlerWidget; + std::map<QString, std::vector<QShortcut*>> m_handlerWidgetShortcuts; + UIActionHandler* m_parent; + std::set<UIActionHandler*> m_children; + bool m_isGlobal, m_inheritParentBindings; + std::function<UIActionContext()> m_actionContextOverride; + + static std::map<QString, std::set<UIActionHandler*>> m_actionBindings; + static std::set<QString> m_globalMenuActions; + + void bindActionShortcutToWidget(const QString& name); + void unbindActionShortcut(const QString& name); + void addActionToChildren(const QString& name); + void removeActionFromChildren(const QString& name); + +public: + UIActionHandler(bool isGlobal = false); + virtual ~UIActionHandler(); + void setupActionHandler(QWidget* obj, bool inheritParentBindings = true); + + static UIActionHandler* actionHandlerFromWidget(QWidget* widget); + static UIActionHandler* globalActions(); + + void bindAction(const QString& name, const UIAction& action); + void bindAction(const QString& name, const UIAction& action, ActionPriority priority); + void unbindAction(const QString& name); + + void executeAction(const QString& name); + void executeAction(const QString& name, const UIActionContext& context); + bool isBoundAction(const QString& name); + bool isValidAction(const QString& name); + bool isValidAction(const QString& name, const UIActionContext& context); + ActionPriority getPriority(const QString& name); + + void bindCopyAsActions(const UITransformAction& action); + void bindPasteFromActions(const UITransformAction& action); + void bindTransformActions(const UITransformAction& encode, const UITransformAction& decode); + void unbindCopyAsActions(); + void unbindPasteFromActions(); + void unbindTransformActions(); + + void bindPluginCommandActions(); + void bindPluginCommandActions(const QString& prefix, + const std::function<UIActionContext(const UIActionContext&, const BinaryNinja::PluginCommand&)>& context, + const std::function<bool(const UIActionContext&, const BinaryNinja::PluginCommand&)>& isValid); + void unbindPluginCommandActions(); + void unbindPluginCommandActions(const QString& prefix); + + void bindHighlightColorActions(const QString& prefix, const UIHighlightColorAction& action); + void unbindHighlightColorActions(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); + QString getActionDisplayName(const QString& name); + QString getActionDisplayName(const QString& name, const UIActionContext& context); + + void setChecked(const QString& name, bool checked); + void setChecked(const QString& name, const std::function<bool()>& checked); + void setChecked(const QString& name, const std::function<bool(const UIActionContext&)>& checked); + bool isChecked(const QString& name); + bool isChecked(const QString& name, const UIActionContext& context); + bool isCheckable(const QString& name); + + std::set<QString> getAllValidActions(); + std::set<QString> getAllValidActions(const UIActionContext& context); + + UIActionContext defaultActionContext(); + virtual UIActionContext actionContext(); + void setActionContext(const std::function<UIActionContext()>& contextFunc); + + QWidget* widget() { return m_handlerWidget; } + + static void updateActionBindings(const QString& name); + static void addGlobalMenuAction(const QString& name); + static void removeGlobalMenuAction(const QString& name); + + static void reparentWidget(QWidget* widget); +}; + +enum MenuItemVisibility +{ + DefaultMenuItemVisibility, + ShowMenuItemOnlyWhenActive, + AlwaysShowMenuItem, + NeverShowMenuItem +}; + +class MenuInstance; + +class BINARYNINJAUIAPI Menu +{ + std::map<QString, QString> m_actions; + std::map<QString, QString> m_groups; + std::map<QString, uint8_t> m_order, m_groupOrder; + std::map<QString, MenuItemVisibility> m_visibility; + std::map<QString, QAction::MenuRole> m_roles; + std::map<QString, QIcon> m_icons; + uint64_t m_version; + bool m_global; + + Menu(bool global); + void setParentOrdering(const QString& path, const QString& group, uint8_t order); + +public: + Menu(); + Menu(const Menu& menu); + + void addAction(const QString& action, const QString& group, uint8_t order = MENU_ORDER_NORMAL); + void addAction(const QString& submenu, const QString& action, const QString& group, uint8_t order = MENU_ORDER_NORMAL); + void removeAction(const QString& action); + void removeAction(const QString& submenu, const QString& action); + + void addCopyAsActions(const QString& group, uint8_t order = MENU_ORDER_NORMAL); + void addPasteFromActions(const QString& group, uint8_t order = MENU_ORDER_NORMAL); + void addTransformActions(const QString& group, uint8_t order = MENU_ORDER_NORMAL); + void removeCopyAsActions(); + void removePasteFromActions(); + void removeTransformActions(); + + void addPluginCommandActions(const QString& group); + void addPluginCommandActions(const QString& prefix, const QString& group, uint8_t order = MENU_ORDER_NORMAL); + void addPluginCommandSubmenuActions(const QString& submenu, const QString& group); + void addPluginCommandSubmenuActions(const QString& submenu, const QString& prefix, const QString& group, + uint8_t order = MENU_ORDER_NORMAL); + void removePluginCommandActions(); + void removePluginCommandSubmenuActions(const QString& submenu); + + void addHighlightColorActions(const QString& submenu, const QString& group, uint8_t order = MENU_ORDER_NORMAL); + void removeHighlightColorActions(const QString& submenu); + + void setOrdering(const QString& path, const QString& group, uint8_t order = MENU_ORDER_NORMAL); + void setGroupOrdering(const QString& group, uint8_t order); + + void setVisibility(const QString& path, MenuItemVisibility visibility); + void setRole(const QString& path, QAction::MenuRole role); + + void setIcon(const QString& path, const QIcon& icon); + + MenuInstance* create(QWidget* owner, UIActionHandler* handler, bool showInactiveActions = false); + MenuInstance* create(QWidget* owner, UIActionHandler* handler, const UIActionContext& context, + bool showInactiveActions = false); + + uint64_t getVersion(); + const std::map<QString, QString>& getActions(); + QString getGroupForAction(const QString& name); + uint8_t getOrderForAction(const QString& name); + uint8_t getOrderForGroup(const QString& name); + MenuItemVisibility getVisibility(const QString& name); + QAction::MenuRole getRole(const QString& name); + QIcon getIcon(const QString& name); + + static Menu* mainMenu(const QString& name); + static void setMainMenuOrder(const QString& name, uint8_t order); + static std::vector<QString> getMainMenus(); +}; + +class BINARYNINJAUIAPI MenuInstance +{ + Menu* m_menu; + QMenu* m_instance; + UIActionHandler* m_handler; + UIActionContext m_context; + uint64_t m_version; + std::map<QString, QPointer<QAction>> m_actions; + + struct Group; + + struct Item + { + QString name, action; + uint8_t order; + QAction::MenuRole role; + QIcon icon; + bool checkable; + std::vector<Group> submenu; + }; + + struct Group + { + QString name; + std::vector<Item> items; + uint8_t order; + }; + + static std::map<QString, std::set<MenuInstance*>> m_actionBindings; + + std::vector<Group> layoutMenu(const std::map<QString, QString>& actions, const QString& prefix, + bool showInactiveActions); + void addGroupsToMenu(QMenu* menu, const std::vector<Group>& groups); + +public: + MenuInstance(Menu* menu, QMenu* instance); + virtual ~MenuInstance(); + void update(UIActionHandler* handler, bool showInactiveActions = false); + void update(UIActionHandler* handler, const UIActionContext& context, bool showInactiveActions = false); + + Menu* source() const { return m_menu; } + QMenu* instance() const { return m_instance; } + + static void updateActionBindings(const QString& name); +}; + +class BINARYNINJAUIAPI MainMenuInstance +{ + QMenuBar* m_instance; + std::map<QString, MenuInstance*> m_menus; + +public: + MainMenuInstance(QMenuBar* instance); + ~MainMenuInstance(); + void update(UIActionHandler* handler); + void update(UIActionHandler* handler, const UIActionContext& context); +}; + +Q_DECLARE_METATYPE(UIActionHandler*) diff --git a/ui/addressindicator.h b/ui/addressindicator.h new file mode 100644 index 00000000..3ad40638 --- /dev/null +++ b/ui/addressindicator.h @@ -0,0 +1,24 @@ +#pragma once + +#include <QtWidgets/QLabel> +#include "viewframe.h" +#include "menus.h" +#include "uicontext.h" + +class BINARYNINJAUIAPI AddressIndicator: public QLabel +{ + Q_OBJECT + + uint64_t m_begin, m_end; + ContextMenuManager m_contextMenu; + +public: + AddressIndicator(QWidget* parent); + + void setOffsets(uint64_t begin, uint64_t end); + +protected: + virtual void mousePressEvent(QMouseEvent* event); + virtual void enterEvent(QEvent* event); + virtual void leaveEvent(QEvent* event); +}; diff --git a/ui/assembledialog.h b/ui/assembledialog.h new file mode 100644 index 00000000..8d1f1c45 --- /dev/null +++ b/ui/assembledialog.h @@ -0,0 +1,33 @@ +#pragma once + +#include <QtWidgets/QDialog> +#include <QtWidgets/QComboBox> +#include "binaryninjaapi.h" +#include "dialogtextedit.h" +#include "uicontext.h" + +class BINARYNINJAUIAPI AssembleDialog: public QDialog +{ + Q_OBJECT + + BinaryViewRef m_view; + uint64_t m_addr; + QComboBox* m_archSelection; + DialogTextEdit* m_code; + BinaryNinja::DataBuffer m_bytes; + bool m_setDefault; + +public: + AssembleDialog(QWidget* parent, BinaryViewRef data, uint64_t addr, ArchitectureRef prefArch = NULL, const QString& code = ""); + + ArchitectureRef getArchitecture(); + const BinaryNinja::DataBuffer& getBytes() const { return m_bytes; } + +private Q_SLOTS: + void saveOnFinish(int result); + void assemble(); + +protected: + virtual void accept() override; + +}; diff --git a/ui/commandpalette.h b/ui/commandpalette.h new file mode 100644 index 00000000..f009764d --- /dev/null +++ b/ui/commandpalette.h @@ -0,0 +1,110 @@ +#pragma once + +#include <QtWidgets/QListView> +#include <QtCore/QAbstractItemModel> +#include <QtWidgets/QLineEdit> +#include <QtWidgets/QFrame> +#include <QtCore/QPointer> +#include <vector> +#include "action.h" + +struct BINARYNINJAUIAPI CommandListItem +{ + QString name; + QString shortcut; + QString action; +}; + +class CommandPalette; +class CommandListFilter; + +class BINARYNINJAUIAPI CommandListModel: public QAbstractItemModel +{ + Q_OBJECT + + std::vector<CommandListItem> m_items; + std::vector<CommandListItem> m_allItems; + + bool isFilterMatch(const QString& name, const QString& filter); + int getFilterMatchScore(const QString& name, const QString& filter); + +public: + CommandListModel(QWidget* parent, const std::vector<CommandListItem>& items); + + 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 = QModelIndex()) const override; + virtual int columnCount(const QModelIndex& parent) const override; + virtual QVariant data(const QModelIndex& i, int role) const override; + + QString getActionForItem(int row); + void setFilterText(const QString& text); +}; + +class BINARYNINJAUIAPI CommandList: public QListView +{ + Q_OBJECT + + CommandPalette* m_palette; + CommandListModel* m_model; + CommandListFilter* m_filter; + +public: + CommandList(CommandPalette* parent, const std::vector<CommandListItem>& items); + void setFilter(CommandListFilter* filter) { m_filter = filter; } + void setFilterText(const QString& text); + + QString getActionForItem(int row); + + QModelIndex index(int row, int col, const QModelIndex& parent = QModelIndex()) const; + +protected: + virtual void keyPressEvent(QKeyEvent* event) override; + virtual void focusOutEvent(QFocusEvent* event) override; +}; + +class BINARYNINJAUIAPI CommandListFilter: public QLineEdit +{ + Q_OBJECT + + CommandPalette* m_palette; + CommandList* m_list; + +public: + CommandListFilter(CommandPalette* parent, CommandList* list); + +protected: + virtual void keyPressEvent(QKeyEvent* event) override; + virtual void focusOutEvent(QFocusEvent* event) override; +}; + +class BINARYNINJAUIAPI CommandPalette: public QFrame +{ + Q_OBJECT + + UIActionHandler* m_handler; + UIActionContext m_context; + QPointer<QWidget> m_previousWidget; + + CommandListFilter* m_filter; + CommandList* m_list; + + bool m_executing; + + std::vector<CommandListItem> getCommandList(); + void init(); + +public: + CommandPalette(QWidget* parent, UIActionHandler* handler); + CommandPalette(QWidget* parent, UIActionHandler* handler, const UIActionContext& context); + + void focusInput(); + void activateFirstItem(); + void selectFirstItem(); + void close(); + +private Q_SLOTS: + void itemClicked(const QModelIndex& idx); + void filterChanged(const QString& text); +}; diff --git a/ui/commands.h b/ui/commands.h new file mode 100644 index 00000000..0bc7d8f2 --- /dev/null +++ b/ui/commands.h @@ -0,0 +1,27 @@ +#pragma once + +#include <QtWidgets/QWidget> +#include "binaryninjaapi.h" +#include "render.h" +#include "uicontext.h" + +bool BINARYNINJAUIAPI undefineNameForAddress(BinaryViewRef data, uint64_t addr); +bool BINARYNINJAUIAPI undefineNameForLocalVariable(BinaryViewRef data, + FunctionRef func, const BinaryNinja::Variable& var); +bool BINARYNINJAUIAPI inputNameForAddress(QWidget* parent, BinaryViewRef data, uint64_t addr); +bool BINARYNINJAUIAPI inputNameForLocalVariable(QWidget* parent, BinaryViewRef data, + FunctionRef function, const BinaryNinja::Variable& var); +bool BINARYNINJAUIAPI inputNameForType(QWidget* parent, std::string& name, const QString& title = "Set Name", + const QString& msg = "Enter name:"); + +bool BINARYNINJAUIAPI askForNewType(QWidget* parent, BinaryViewRef data, FunctionRef func, const std::string& title, + TypeRef& type, BinaryNinja::QualifiedName& name); +bool BINARYNINJAUIAPI inputNewType(QWidget* parent, BinaryViewRef data, FunctionRef currentFunction, + uint64_t currentAddr, HighlightTokenState& highlight); + +bool BINARYNINJAUIAPI overwriteCode(BinaryViewRef data, ArchitectureRef arch, + uint64_t addr, const BinaryNinja::DataBuffer& buffer); + +StructureRef BINARYNINJAUIAPI getInnerMostStructureContaining( + StructureRef structure, size_t& memberIndex, const std::vector<std::string>& nameList, + size_t nameIndex); diff --git a/ui/commentdialog.h b/ui/commentdialog.h new file mode 100644 index 00000000..803fcd3b --- /dev/null +++ b/ui/commentdialog.h @@ -0,0 +1,18 @@ +#pragma once + +#include <QtWidgets/QDialog> +#include <QtWidgets/QComboBox> +#include "binaryninjaapi.h" +#include "dialogtextedit.h" +#include "uicontext.h" + +class BINARYNINJAUIAPI CommentDialog: public QDialog +{ + Q_OBJECT + + DialogTextEdit* m_comment; + +public: + CommentDialog(QWidget* parent, const QString& comment = ""); + QString getComment(); +}; diff --git a/ui/compiledialog.h b/ui/compiledialog.h new file mode 100644 index 00000000..c5d2123a --- /dev/null +++ b/ui/compiledialog.h @@ -0,0 +1,49 @@ +#pragma once + +#include <QtWidgets/QDialog> +#include <QtWidgets/QComboBox> +#include <QtWidgets/QLabel> +#include <set> +#include "binaryninjaapi.h" +#include "dialogtextedit.h" +#include "uicontext.h" + +enum CompileMode +{ + CompileStandalone, + CompilePatch +}; + +class BINARYNINJAUIAPI CompileDialog: public QDialog +{ + Q_OBJECT + + BinaryViewRef m_view; + uint64_t m_addr; + QComboBox* m_arch; + QComboBox* m_os; + DialogTextEdit* m_code; + QLabel* m_optionsText; + bool m_saveOSSetting; + std::map<std::string, std::string> m_options; + std::set<std::string> m_unsavedOptions; + BinaryNinja::DataBuffer m_bytes; + bool m_setDefault; + + void appendOptionString(std::string& out, const std::string& text); + void updateOptionsText(); + +public: + CompileDialog(QWidget* parent, BinaryViewRef data, uint64_t addr, CompileMode mode, const QString& code = ""); + + ArchitectureRef getArchitecture(); + const BinaryNinja::DataBuffer& getBytes() const { return m_bytes; } + +private Q_SLOTS: + void saveOnFinish(int result); + void compile(); + void options(); + +protected: + virtual void accept() override; +}; diff --git a/ui/compileoptions.h b/ui/compileoptions.h new file mode 100644 index 00000000..53a7e687 --- /dev/null +++ b/ui/compileoptions.h @@ -0,0 +1,46 @@ +#pragma once + +#include <QtWidgets/QDialog> +#include <QtWidgets/QCheckBox> +#include <QtWidgets/QRadioButton> +#include <QtWidgets/QLineEdit> +#include "binaryninjaapi.h" +#include "uicontext.h" + +class BINARYNINJAUIAPI CompileOptions: public QDialog +{ + Q_OBJECT + + QCheckBox* m_safeStack; + QLineEdit* m_blacklist; + QLineEdit* m_base; + QLineEdit* m_maxLength; + QCheckBox* m_pad; + QCheckBox* m_polymorph; + + QRadioButton* m_exit; + QRadioButton* m_allowReturn; + QRadioButton* m_concat; + + QLineEdit* m_stackReg; + QLineEdit* m_frameReg; + QLineEdit* m_baseReg; + QLineEdit* m_returnReg; + QLineEdit* m_returnHighReg; + QCheckBox* m_encodePointers; + QCheckBox* m_stackGrowsUp; + QCheckBox* m_antiDisasm; + QLineEdit* m_antiDisasmFreq; + QLineEdit* m_seed; + + QString optionValue(const std::map<std::string, std::string>& options, const std::string& name); + void updateOptions(const std::map<std::string, std::string>& options); + +public: + CompileOptions(QWidget* parent, const std::map<std::string, std::string>& initialOptions); + + std::map<std::string, std::string> getSettings(); + +private Q_SLOTS: + void reset(); +}; diff --git a/ui/createstructdialog.h b/ui/createstructdialog.h new file mode 100644 index 00000000..df117411 --- /dev/null +++ b/ui/createstructdialog.h @@ -0,0 +1,30 @@ +#pragma once + +#include <QtWidgets/QDialog> +#include <QtWidgets/QLineEdit> +#include "binaryninjaapi.h" +#include "uicontext.h" + +class BINARYNINJAUIAPI CreateStructDialog: public QDialog +{ + Q_OBJECT + + QLineEdit* m_name; + QLineEdit* m_size; + + BinaryNinja::QualifiedName m_resultName; + uint64_t m_resultSize; + +public: + CreateStructDialog(QWidget* parent); + + BinaryNinja::QualifiedName getName() { return m_resultName; } + uint64_t getSize() { return m_resultSize; } + +private Q_SLOTS: + void createStruct(); + +protected: + virtual void showEvent(QShowEvent* e) override; + +}; diff --git a/ui/createtypedialog.h b/ui/createtypedialog.h new file mode 100644 index 00000000..1d0effe3 --- /dev/null +++ b/ui/createtypedialog.h @@ -0,0 +1,28 @@ +#pragma once + +#include <QtWidgets/QDialog> +#include <QtWidgets/QLineEdit> +#include "binaryninjaapi.h" +#include "dialogtextedit.h" +#include "uicontext.h" + +class BINARYNINJAUIAPI CreateTypeDialog: public QDialog +{ + Q_OBJECT + + DialogTextEdit* m_code; + + BinaryViewRef m_data; + std::map<BinaryNinja::QualifiedName, TypeRef> m_results; + +public: + CreateTypeDialog(QWidget* parent, BinaryViewRef data, const QString& definition); + std::map<BinaryNinja::QualifiedName, TypeRef> getResults() { return m_results; } + +private Q_SLOTS: + void createType(); + +protected: + virtual void showEvent(QShowEvent* e) override; + +}; diff --git a/ui/dialogtextedit.h b/ui/dialogtextedit.h new file mode 100644 index 00000000..cc719aae --- /dev/null +++ b/ui/dialogtextedit.h @@ -0,0 +1,18 @@ +#pragma once + +#include <QtWidgets/QTextEdit> +#include "uicontext.h" + +class BINARYNINJAUIAPI DialogTextEdit: public QTextEdit +{ + Q_OBJECT + +public: + DialogTextEdit(QWidget* parent); + +protected: + virtual void keyPressEvent(QKeyEvent* event) override; + +Q_SIGNALS: + void contentAccepted(); +}; diff --git a/ui/disassemblyview.h b/ui/disassemblyview.h new file mode 100644 index 00000000..477081fb --- /dev/null +++ b/ui/disassemblyview.h @@ -0,0 +1,179 @@ +#pragma once + +#include <QtWidgets/QAbstractScrollArea> +#include <QtCore/QPointer> +#include <QtWidgets/QSplitter> +#include <QtWidgets/QLabel> +#include <mutex> +#include "binaryninjaapi.h" +#include "viewframe.h" +#include "instructionedit.h" +#include "render.h" +#include "progressindicator.h" +#include "commentdialog.h" +#include "menus.h" +#include "statusbarwidget.h" +#include "flowgraphwidget.h" + +#define FUNCTION_UPDATE_CHECK_INTERVAL 100 + +class BINARYNINJAUIAPI DisassemblyHistoryEntry: public FlowGraphHistoryEntry +{ + BNFunctionGraphType m_graphType; + +public: + BNFunctionGraphType getGraphType() const { return m_graphType; } + void setGraphType(BNFunctionGraphType type) { m_graphType = type; } +}; + +class DisassemblyContainer; + +class BINARYNINJAUIAPI DisassemblyView: public FlowGraphWidget +{ + Q_OBJECT + +friend class DisassemblyFunctionHeader; + +public: + explicit DisassemblyView(DisassemblyContainer* parent, BinaryViewRef data, FunctionRef func = nullptr, + bool navToAddr = false, uint64_t addr = 0); + + virtual bool navigate(uint64_t pos) override; + virtual bool navigateToFunction(FunctionRef func, uint64_t pos) override; + + virtual HistoryEntry* getHistoryEntry() override; + virtual void navigateToHistoryEntry(HistoryEntry* entry) override; + + virtual StatusBarWidget* getStatusBarWidget() override; + + void setGraphType(BNFunctionGraphType type); + void setOption(BNDisassemblyOption option, bool state = true); + void toggleOption(BNDisassemblyOption option); + + DisassemblySettingsRef getSettings(); + + virtual void onFunctionSelected(FunctionRef func) override; + virtual void onHighlightChanged(const HighlightTokenState& highlight) override; + + static void registerActions(); + +private: + class DisassemblyViewOptionsWidget: public QLabel + { + public: + DisassemblyViewOptionsWidget(DisassemblyView* parent); + + protected: + virtual void mousePressEvent(QMouseEvent* event); + virtual void enterEvent(QEvent* event); + virtual void leaveEvent(QEvent* event); + + private: + DisassemblyView* m_view; + Menu m_menu; + ContextMenuManager m_contextMenuManager; + }; + + class DisassemblyViewStatusBarWidget: public StatusBarWidget + { + public: + DisassemblyViewStatusBarWidget(DisassemblyView* parent); + virtual void updateStatus() override; + + private: + DisassemblyView* m_view; + DisassemblyViewOptionsWidget* m_options; + }; + + void bindActions(); + + BNFunctionGraphType m_graphType; + std::set<BNDisassemblyOption> m_options; + DisassemblyContainer* m_container; + +private Q_SLOTS: + void viewInHexEditor(); + void viewInLinearDisassembly(); +}; + + +class BINARYNINJAUIAPI DisassemblyFunctionHeader: public QWidget +{ + Q_OBJECT + + DisassemblyContainer* m_container; + + BinaryViewRef m_data; + FunctionRef m_func; + + QProgressIndicator* m_updateIndicator; + QTimer* m_updateTimer; + + RenderContext m_render; + std::vector<BinaryNinja::DisassemblyTextLine> m_lines; + size_t m_width; + HighlightTokenState m_highlight; + + void adjustSize(int width, int height); + +private Q_SLOTS: + void updateTimerEvent(); + +protected: + virtual void paintEvent(QPaintEvent* event) override; + virtual void resizeEvent(QResizeEvent* event) override; + + virtual void mousePressEvent(QMouseEvent* event) override; + virtual void mouseDoubleClickEvent(QMouseEvent* event) override; + +public: + DisassemblyFunctionHeader(DisassemblyContainer* parent, BinaryViewRef data); + + void updateFonts(); + void setCurrentFunction(FunctionRef func); + void setHighlightToken(const HighlightTokenState& state); + + virtual QSize sizeHint() const override; +}; + +class BINARYNINJAUIAPI DisassemblyContainer: public QWidget, public ViewContainer +{ + Q_OBJECT + + ViewFrame* m_viewFrame; + DisassemblyView* m_view; + DisassemblyFunctionHeader* m_funcHeader; + QWidget* m_analysisWarning; + QLabel* m_analysisWarningText; + +public: + explicit DisassemblyContainer(QWidget* parent, BinaryViewRef data, ViewFrame* view, FunctionRef func = nullptr, + bool navToAddr = false, uint64_t addr = 0); + virtual View* getView() override { return m_view; } + ViewFrame* getViewFrame() { return m_viewFrame; } + + DisassemblyView* getDisassembly() const { return m_view; } + DisassemblyFunctionHeader* getFunctionHeader() const { return m_funcHeader; } + + void updateFonts(); + void refreshHeader(FunctionRef func); + void setCurrentFunction(FunctionRef func); + void setHeaderHighlightToken(const HighlightTokenState& state); + +protected: + virtual void focusInEvent(QFocusEvent* event) override; + +private Q_SLOTS: + void linkActivatedEvent(const QString& link); +}; + +class DisassemblyViewType: public ViewType +{ + static DisassemblyViewType* m_instance; + +public: + DisassemblyViewType(); + virtual int getPriority(BinaryViewRef data, const QString& filename); + virtual QWidget* create(BinaryViewRef data, ViewFrame* viewFrame); + static void init(); +}; diff --git a/ui/dockhandler.h b/ui/dockhandler.h new file mode 100644 index 00000000..08392532 --- /dev/null +++ b/ui/dockhandler.h @@ -0,0 +1,112 @@ +#pragma once + +#include <QtCore/QObject> +#include <QtCore/QSettings> +#include <QtWidgets/QDockWidget> +#include <map> + +#include "binaryninjaapi.h" +#include "action.h" +#include "uitypes.h" + +class ContextMenuManager; +class DockHandler; +class Menu; +class View; +class ViewFrame; + +struct BINARYNINJAUIAPI DockProperties +{ + DockProperties() { }; + DockProperties(QDockWidget* dw, bool vis, Qt::DockWidgetArea dar, Qt::Orientation dor, bool dvis, bool vs) : + dockWidget(dw), visibleState(vis), defaultArea(dar), defaultOrientation(dor), defaultVisibility(dvis), + viewSensitive(vs), neverBeenVisible(true), sizeStash(0, 0), actionOnShow(nullptr) { } + DockProperties(const DockProperties &dp) : + dockWidget(dp.dockWidget), visibleState(dp.visibleState), defaultArea(dp.defaultArea), + defaultOrientation(dp.defaultOrientation), defaultVisibility(dp.defaultVisibility), + viewSensitive(dp.viewSensitive), neverBeenVisible(dp.neverBeenVisible), sizeStash(dp.sizeStash), actionOnShow(dp.actionOnShow) { } + + QDockWidget* dockWidget; + bool visibleState; + Qt::DockWidgetArea defaultArea; + Qt::Orientation defaultOrientation; + bool defaultVisibility; + bool viewSensitive; + bool neverBeenVisible; + QSize sizeStash; + std::function<void()> actionOnShow; +}; + +struct DockSizePrefs +{ + DockSizePrefs() { } + QList<QDockWidget*> docks; + QList<int> hDockSizes; + QList<int> vDockSizes; + bool nonUniformVisibility = false; +}; + +class BINARYNINJAUIAPI DockContextHandler +{ +protected: + QString m_name; + UIActionHandler m_actionHandler; + ContextMenuManager* m_contextMenuManager = nullptr; + Menu* m_menu = nullptr; + QWidget* m_parentWindow; + +public: + DockContextHandler(QWidget* widget, const QString& name); + virtual ~DockContextHandler(); + + QWidget* getParentWindow() { return m_parentWindow; } + + virtual void focusInput() { }; + virtual bool isAvailable(ViewFrame* /*frame*/) { return true; }; + virtual void notifyViewChanged(ViewFrame* /*frame*/) { }; + virtual bool shouldBeVisible(ViewFrame* /*frame*/) { return true; }; + virtual void updateFonts() { }; +}; + +class BINARYNINJAUIAPI DockHandler: public QObject +{ + Q_OBJECT + + int m_windowIndex = 0; + ViewFrame* m_viewFrame = nullptr; + View* m_view = nullptr; + BinaryViewRef m_data; + std::map<QString, DockProperties> m_docks; + bool m_resizeDocksRequest = false; + bool m_shouldResizeDocks = false; + std::map<Qt::DockWidgetArea, bool> m_enableHiddenGroupSave; + +public: + explicit DockHandler(QObject* parent, int windowIndex); + + void close(); + void notifyRestoredFromState(); + void reset(bool initial = false); + void reset(const QString& name); + void resizeDocksOnShow(bool resizeDocks) { m_resizeDocksRequest = resizeDocks; } + bool addDockWidget(const QString& name, QWidget* primaryWidget, Qt::DockWidgetArea area = Qt::BottomDockWidgetArea, Qt::Orientation orientation = Qt::Horizontal, bool defaultVisibility = false); + QDockWidget* getDockWidget(const QString& name); + ViewFrame* getViewFrame() { return m_viewFrame; } + bool isVisible(const QString& name); + void setVisible(const QString& name, bool visible); + + void saveState(QSettings& settings, const QString& windowStateName); + void restoreState(QSettings& settings, const QString& windowStateName); + void saveDockSizes(bool nullFrame = false); + void restoreDockSizes(); + + bool shouldResizeDocks(); + void updateFonts(); + void addActionOnShow(const QString& name, const std::function<void()>& action); + + static DockHandler* getActiveDockHandler(); + +public Q_SLOTS: + void viewChanged(ViewFrame* frame); + void topLevelChanged(bool topLevel); +}; diff --git a/ui/featuremap.h b/ui/featuremap.h new file mode 100644 index 00000000..bc2a13cd --- /dev/null +++ b/ui/featuremap.h @@ -0,0 +1,106 @@ +#pragma once + +#include <QtWidgets/QAction> +#include <QtGui/QColor> +#include <QtGui/QImage> +#include <QtWidgets/QMenu> +#include <QtGui/QPainter> +#include <QtCore/QRect> +#include <QtCore/QTimer> +#include <QtCore/QVector> +#include <QtWidgets/QWidget> +#include <mutex> +#include <tuple> +#include <vector> + +#include "binaryninjaapi.h" +#include "dockhandler.h" +#include "uitypes.h" + +class ContextMenuManager; +class Menu; +class View; +class ViewFrame; + +class BINARYNINJAUIAPI FeatureMap: public QWidget, public BinaryNinja::BinaryDataNotification, public DockContextHandler +{ + Q_OBJECT + + QImage* m_image = nullptr; + QImage* m_staticImage = nullptr; + std::vector<std::pair<uint64_t, uint64_t>> m_regions; + + ViewFrame* m_frame = nullptr; + BinaryViewRef m_data; + + bool m_updatesPending = false; + QTimer* m_updateTimer = nullptr; + size_t m_bvWidth = 0; + size_t m_bvHeight = 0; + uint64_t m_bvLength = 0; + + int m_defaultWidth = 100; + + int m_curLocX = 0; + int m_curLocY = 0; + uint64_t m_curAddr = 0; + bool m_navigationInProgress = false; + + QVector<QColor> m_colors; + QVector<QRgb> m_colorTable; + + class BackgroundRefresh: public BinaryNinja::RefCountObject + { + std::mutex m_mutex; + bool m_valid; + FeatureMap* m_featureMap; + + public: + BackgroundRefresh(FeatureMap* featureMap); + void start(); + void abort(); + }; + + BinaryNinja::Ref<BackgroundRefresh> m_backgroundRefresh; + +public: + FeatureMap(ViewFrame* frame, BinaryViewRef data); + virtual ~FeatureMap(); + + View* getBinaryDataNavigableView(bool preferGraphView = false); + void backgroundRefresh(); + std::pair<uint64_t, bool> getOffsetForAddress(uint64_t addr); + void setCurrentLocation(uint64_t address); + void updateTheme(); + + void renderDataVariable(const BinaryNinja::DataVariable& var, bool ignoreString = false); + + virtual void OnAnalysisFunctionAdded(BinaryNinja::BinaryView* data, BinaryNinja::Function* func) override; + virtual void OnAnalysisFunctionRemoved(BinaryNinja::BinaryView* data, BinaryNinja::Function* func) override; + virtual void OnAnalysisFunctionUpdated(BinaryNinja::BinaryView* data, BinaryNinja::Function* func) override; + virtual void OnDataVariableAdded(BinaryNinja::BinaryView* data, const BinaryNinja::DataVariable& var) override; + virtual void OnDataVariableRemoved(BinaryNinja::BinaryView* data, const BinaryNinja::DataVariable& var) override; + virtual void OnDataVariableUpdated(BinaryNinja::BinaryView* data, const BinaryNinja::DataVariable& var) override; + virtual void OnStringFound(BinaryNinja::BinaryView* data, BNStringType type, uint64_t offset, size_t len) override; + virtual void OnStringRemoved(BinaryNinja::BinaryView* data, BNStringType type, uint64_t offset, size_t len) override; + + void drawImageRect(uint64_t addr, size_t len, uint8_t color); + + virtual QSize sizeHint() const override; + +protected: + virtual void contextMenuEvent(QContextMenuEvent* event) override; + virtual void mouseMoveEvent(QMouseEvent* event) override; + virtual void mousePressEvent(QMouseEvent* event) override; + virtual void resizeEvent(QResizeEvent* event) override; + virtual void paintEvent(QPaintEvent* event) override; + void scrollTo(int x, int y, bool addHistoryEntry = false); + +Q_SIGNALS: + void notifyThemeUpdated(); + +private Q_SLOTS: + void refresh(); + void updateThemeInternal(); + void updateTimerEvent(); +}; diff --git a/ui/filecontext.h b/ui/filecontext.h new file mode 100644 index 00000000..bd11a4ff --- /dev/null +++ b/ui/filecontext.h @@ -0,0 +1,77 @@ +#pragma once + +#include <QtCore/QString> +#include <map> +#include <set> +#include <string> +#include "binaryninjaapi.h" +#include "uicontext.h" + +class ViewFrame; +class ViewType; + +// This base class is required for building the Python bindings. The other base classes of FileContext are +// ignored (as they have no functions that should be exported to Python), but this would leave the binding +// generator with a derived class with no base and a compiler error. +class FileContextBase +{ +public: + FileContextBase() {} +}; + +class BINARYNINJAUIAPI FileContext: public FileContextBase, public BinaryNinja::NavigationHandler +{ + QString m_filename; + bool m_isValidSaveFilename; + FileMetadataRef m_file; + + BinaryViewRef m_rawData; + std::map<QString, BinaryViewRef> m_dataViews; + + ViewFrame* m_currentViewFrame; + std::set<ViewFrame*> m_viewFrames; + + static std::set<FileContext*> m_openFiles; + + friend class ViewFrame; + void registerViewFrame(ViewFrame* frame); + void unregisterViewFrame(ViewFrame* frame); + +public: + FileContext(FileMetadataRef file, BinaryViewRef rawData, + const QString& filename = QString(), bool isValidSaveName = false); + virtual ~FileContext(); + + void close(); + static void closeAllOpenFiles(); + + BinaryViewRef getRawData() const { return m_rawData; } + QString getFilename() const { return m_filename; } + ViewFrame* getCurrentViewFrame() const { return m_currentViewFrame; } + + bool isValidSaveFilename() const { return m_isValidSaveFilename; } + void markAsSaved(const QString& filename); + + bool isModified(); + + BinaryViewRef getDataView(const QString& type, bool createView = false); + std::vector<BinaryViewRef> getAllDataViews(); + + void setCurrentViewFrame(ViewFrame* view); + + virtual std::string GetCurrentView() override; + virtual uint64_t GetCurrentOffset() override; + virtual bool Navigate(const std::string& view, uint64_t offset) override; + + void createBinaryViews(); + QString getBestType(); + std::vector<QString> getAvailableTypes(); + bool isTypeAvailable(const QString& type); + bool resolveType(const QString& type, ViewType*& viewType, BinaryViewTypeRef& data); + bool resolveTypeAndData(const QString& type, ViewType*& viewType, BinaryViewRef& data); + + void updateAnalysis(); + + static FileContext* newFile(); + static FileContext* openFilename(const QString& path); +}; diff --git a/ui/filter.h b/ui/filter.h new file mode 100644 index 00000000..5a43100f --- /dev/null +++ b/ui/filter.h @@ -0,0 +1,54 @@ +#pragma once + +#include <QtWidgets/QLineEdit> +#include "binaryninjaapi.h" +#include "uicontext.h" + +class BINARYNINJAUIAPI FilterTarget +{ +public: + virtual ~FilterTarget() {} + + virtual void setFilter(const std::string& filter) = 0; + virtual void scrollToFirstItem() = 0; + virtual void scrollToCurrentItem() = 0; + virtual void selectFirstItem() = 0; + virtual void activateFirstItem() = 0; + virtual void closeFilter(); +}; + +class BINARYNINJAUIAPI FilterEdit: public QLineEdit +{ + Q_OBJECT + + FilterTarget* m_target; + +public: + FilterEdit(QWidget* parent, FilterTarget* target); + +protected: + virtual void keyPressEvent(QKeyEvent* event) override; +}; + +class BINARYNINJAUIAPI FilteredView: public QWidget +{ + Q_OBJECT + + FilterTarget* m_target; + QWidget* m_widget; + FilterEdit* m_filter; + +public: + FilteredView(QWidget* parent, QWidget* filtered, FilterTarget* target); + void updateFonts(); + void clearFilter(); + void showFilter(const QString& initialText); + + static bool match(const std::string& name, const std::string& filter); + +protected: + virtual void keyPressEvent(QKeyEvent* event) override; + +private Q_SLOTS: + void filterChanged(const QString& filter); +}; diff --git a/ui/flowgraphwidget.h b/ui/flowgraphwidget.h new file mode 100644 index 00000000..1ebaded2 --- /dev/null +++ b/ui/flowgraphwidget.h @@ -0,0 +1,285 @@ +#pragma once + +#include <QtWidgets/QWidget> +#include <QtWidgets/QAbstractScrollArea> +#include "binaryninjaapi.h" +#include "render.h" +#include "viewframe.h" +#include "menus.h" +#include "uicontext.h" +#include "commentdialog.h" +#include "instructionedit.h" + +class BINARYNINJAUIAPI GraphLayoutCompleteEvent: public QEvent +{ + FlowGraphRef m_graph; +public: + GraphLayoutCompleteEvent(QEvent::Type type, const FlowGraphRef& graph); + FlowGraphRef GetGraph() { return m_graph; } +}; + +class BINARYNINJAUIAPI FlowGraphHistoryEntry: public HistoryEntry +{ + PlatformRef m_platform; + ArchitectureRef m_arch; + uint64_t m_func; + int m_scrollX, m_scrollY; + float m_scale; + uint64_t m_addr; + HighlightTokenState m_highlight; + +public: + PlatformRef getPlatform() const { return m_platform; } + ArchitectureRef getArchitecture() const { return m_arch; } + uint64_t getFunction() const { return m_func; } + int getScrollX() const { return m_scrollX; } + int getScrollY() const { return m_scrollY; } + float getScale() const { return m_scale; } + uint64_t getCurrentAddress() const { return m_addr; } + const HighlightTokenState& getHighlightTokenState() const { return m_highlight; } + + void setPlatform(PlatformRef platform) { m_platform = platform; } + void setArchitecture(ArchitectureRef arch) { m_arch = arch; } + void setFunction(uint64_t f) { m_func = f; } + void setScrollX(int x) { m_scrollX = x; } + void setScrollY(int y) { m_scrollY = y; } + void setScale(float s) { m_scale = s; } + void setCurrentAddress(uint64_t a) { m_addr = a; } + void setHighlightTokenState(const HighlightTokenState& state) { m_highlight = state; } +}; + +class BINARYNINJAUIAPI FlowGraphWidget: public QAbstractScrollArea, public View, public PreviewScrollHandler, + public BinaryNinja::BinaryDataNotification +{ + Q_OBJECT + + struct CursorPosition + { + size_t lineInNode; + uint64_t address; + size_t instrIndex; + size_t lineIndexForAddress; + }; + + BinaryViewRef m_data; + FlowGraphRef m_graph; + FlowGraphRef m_updateGraph; + FlowGraphLayoutRequestRef m_graphLayoutRequest; + FlowGraphLayoutRequestRef m_updateGraphLayoutRequest; + FunctionRef m_func; + BinaryNinja::AdvancedFunctionAnalysisDataRequestor m_advancedAnalysisData; + View* m_navigationTarget; + + bool m_ready; + QTimer* m_loadingTimer; + QTimer* m_updateTimer; + QTimer* m_zoomTimer; + QTimer* m_zoomPauseTimer; + + std::mutex m_updateMutex; + bool m_updated; + + RenderContext m_render; + int m_width, m_height; + int m_renderXOfs, m_renderYOfs, m_renderWidth, m_renderHeight; + float m_scale; + QRect m_renderRect; + QRect m_miniRenderRect; + + bool m_scrollMode; + int m_scrollBaseX, m_scrollBaseY; + + FlowGraphNodeRef m_selectedNode; + CursorPosition m_cursorPos, m_selectionStartPos; + HighlightTokenState m_highlight; + + ContextMenuManager m_contextMenuManager; + QPointer<CommentDialog> m_commentDialog; + + BinaryNinja::Ref<FlowGraphHistoryEntry> m_pendingHistoryEntry, m_layoutHistoryEntry; + bool m_useAddrAfterLayout; + uint64_t m_addrAfterLayout; + bool m_pendingXrefNavigation, m_xrefNavigation; + uint64_t m_xrefTarget; + + InstructionEdit* m_instrEdit; + + bool m_isPreview; + QPointF m_previewPos; + QTimer* m_hoverTimer; + + static int m_layoutCompleteEventType; + static int m_updateCompleteEventType; + + void adjustSize(int width, int height); + + void defineNameAtAddr(uint64_t addr); + + static std::string getValueStr(int64_t value); + static std::string getValueStr(uint64_t value); + + FlowGraphNodeRef findUpdatedNode(FlowGraphRef oldGraph, FlowGraphNodeRef oldNode, CursorPosition& pos); + bool updatePositionForNode(FlowGraphNodeRef oldNode, FlowGraphNodeRef newNode, CursorPosition& pos); + void recenterUpdatedGraph(FlowGraphRef oldGraph, int oldXOfs, int oldYOfs); + +protected: + virtual void paintEvent(QPaintEvent* event) override; + virtual void resizeEvent(QResizeEvent* event) override; + + virtual void mousePressEvent(QMouseEvent* event) override; + virtual void mouseReleaseEvent(QMouseEvent* event) override; + virtual void mouseMoveEvent(QMouseEvent* event) override; + virtual void mouseDoubleClickEvent(QMouseEvent* event) override; + virtual void wheelEvent(QWheelEvent* event) override; + + virtual void customEvent(QEvent* event) override; + + virtual void scrollContentsBy(int dx, int dy) override; + + bool getNodeForMouseEvent(QMouseEvent* event, FlowGraphNodeRef& node); + bool getLineForMouseEvent(QMouseEvent* event, CursorPosition& pos); + HighlightTokenState getTokenForMouseEvent(QMouseEvent* event); + + void showContextMenu(); + void bindActions(); + + void navigateToAddress(uint64_t addr); + + void setGraphInternal(FlowGraphRef graph, FlowGraphHistoryEntry* entry, bool useAddr, uint64_t addr, bool notify); + +public: + FlowGraphWidget(QWidget* parent, BinaryViewRef view, FlowGraphRef graph = FlowGraphRef()); + ~FlowGraphWidget(); + + virtual void OnAnalysisFunctionUpdated(BinaryNinja::BinaryView* data, BinaryNinja::Function* func) override; + virtual void OnAnalysisFunctionUpdateRequested(BinaryNinja::BinaryView* data, BinaryNinja::Function* func) override; + + void setInitialGraph(FlowGraphRef graph); + void setInitialGraph(FlowGraphRef graph, uint64_t addr); + + void setGraph(FlowGraphRef graph); + void setGraph(FlowGraphRef graph, uint64_t addr); + void setGraph(FlowGraphRef graph, FlowGraphHistoryEntry* entry); + void updateToGraph(FlowGraphRef graph); + virtual void updateFonts() override; + + virtual BinaryViewRef getData() override { return m_data; } + virtual uint64_t getCurrentOffset() override; + virtual void getSelectionOffsets(uint64_t& begin, uint64_t& end) override; + virtual void getSelectionForInfo(uint64_t& begin, uint64_t& end) override; + virtual bool navigate(uint64_t pos) override; + virtual bool navigateToFunction(FunctionRef func, uint64_t pos) override; + bool navigateWithHistoryEntry(uint64_t addr, FlowGraphHistoryEntry* entry); + bool navigateWithHistoryEntry(FunctionRef func, uint64_t addr, FlowGraphHistoryEntry* entry); + void setNavigationTarget(View* target) { m_navigationTarget = target; } + + virtual void zoom(bool direction); + virtual void zoomActual(); + virtual bool event(QEvent* event) override; + void disableZoom(); + virtual void sendWheelEvent(QWheelEvent* event) override; + + virtual void cut() override; + virtual void copy(TransformRef xform) override; + virtual void paste(TransformRef xform) override; + + virtual bool canAssemble() override; + virtual bool canCompile() override; + virtual bool canPaste() override; + + virtual void closing() override; + + virtual HistoryEntry* getHistoryEntry() override; + void populateDefaultHistoryEntry(FlowGraphHistoryEntry* entry); + virtual void navigateToHistoryEntry(HistoryEntry* entry) override; + + virtual FunctionRef getCurrentFunction() override; + virtual BasicBlockRef getCurrentBasicBlock() override; + virtual ArchitectureRef getCurrentArchitecture() override; + + virtual LowLevelILFunctionRef getCurrentLowLevelILFunction() override; + virtual MediumLevelILFunctionRef getCurrentMediumLevelILFunction() override; + virtual size_t getCurrentILInstructionIndex() override; + + void scrollToCursor(); + bool isUpdating(); + + QFont getFont() override { return m_render.getFont(); } + virtual HighlightTokenState getHighlightTokenState() override { return m_highlight; } + QRect getMiniRenderRect() const { return m_miniRenderRect; } + void paintMiniGraphAndViewport(QWidget* owner); + bool paintMiniGraph(QWidget* owner, QPainter& p); + + void showAddress(uint64_t addr, bool select = false); + void showTopNode(); + void showNode(FlowGraphNodeRef node); + void showLineInNode(FlowGraphNodeRef node, size_t lineIndex); + + void viewInTypesView(std::string typeName); + + void setInstructionHighlight(BNHighlightColor color); + void setBlockHighlight(BNHighlightColor color); + + virtual bool goToReference(FunctionRef func, uint64_t source, uint64_t target) override; + + void setHighlightToken(const HighlightTokenState& state, bool notify = true); + + virtual void onFunctionSelected(FunctionRef func); + virtual void onHighlightChanged(const HighlightTokenState& highlight); + + static std::string getPossibleValueSetStateName(BNRegisterValueType state); + static std::string getStringForRegisterValue(ArchitectureRef arch, BinaryNinja::RegisterValue value); + static std::string getStringForPossibleValueSet(ArchitectureRef arch, const BinaryNinja::PossibleValueSet& values); + +Q_SIGNALS: + void layoutComplete(); + void updateMiniGraph(); + +private Q_SLOTS: + void loadingTimerEvent(); + void updateTimerEvent(); + void hoverTimerEvent(); + void zoomTimerEvent(); + bool zoomDisabled(); + void zoomPauseTimerEvent(); + + void goToAddress(); + void followPointer(); + void defineName(); + void undefineName(); + void defineFuncName(); + void undefineFunc(); + void createFunc(); + void changeType(); + void comment(); + void functionComment(); + void commentAccepted(); + void functionCommentAccepted(); + + void convertToNop(); + void alwaysBranch(); + void invertBranch(); + void skipAndReturnZero(); + void skipAndReturnValue(); + + void displayAsDefault(); + void displayAsBinary(); + void displayAsSignedOctal(); + void displayAsUnsignedOctal(); + void displayAsSignedDecimal(); + void displayAsUnsignedDecimal(); + void displayAsSignedHexadecimal(); + void displayAsUnsignedHexadecimal(); + void displayAsCharacterConstant(); + void displayAsPointer(); + + void makePtr(); + void makeString(); + + void reanalyze(); + + void setStackAdjustment(); + + void editInstruction(); + void instrEditDoneEvent(); +}; diff --git a/ui/fontsettings.h b/ui/fontsettings.h new file mode 100644 index 00000000..ede68a24 --- /dev/null +++ b/ui/fontsettings.h @@ -0,0 +1,32 @@ +#pragma once + +#include <QtGui/QFont> +#include <QtWidgets/QWidget> +#include "uicontext.h" + +enum AntialiasingStyle +{ + SubpixelAntialiasing, + GrayscaleAntialiasing, + SubpixelAntialiasingUnlessHighDPI, + NoAntialiasing +}; + +QFont BINARYNINJAUIAPI getDefaultMonospaceFont(); +QFont BINARYNINJAUIAPI getMonospaceFont(QWidget* widget); +void BINARYNINJAUIAPI setMonospaceFont(const QFont& font); + +int BINARYNINJAUIAPI getDefaultExtraFontSpacing(); +int BINARYNINJAUIAPI getExtraFontSpacing(); +void BINARYNINJAUIAPI setExtraFontSpacing(int spacing); + +int BINARYNINJAUIAPI getFontVerticalOffset(); + +bool BINARYNINJAUIAPI allowBoldFonts(); +void BINARYNINJAUIAPI setAllowBoldFonts(bool allow); + +AntialiasingStyle BINARYNINJAUIAPI getAntialiasingStyle(); +void BINARYNINJAUIAPI setAntialiasingStyle(AntialiasingStyle style); +void BINARYNINJAUIAPI adjustFontForAntialiasingSettings(QFont& font, QWidget* widget); + +int BINARYNINJAUIAPI getFontWidthAndAdjustSpacing(QFont& font); diff --git a/ui/forminputdialog.h b/ui/forminputdialog.h new file mode 100644 index 00000000..1a46d2ea --- /dev/null +++ b/ui/forminputdialog.h @@ -0,0 +1,28 @@ +#pragma once + +#include <QtWidgets/QDialog> +#include <QtWidgets/QLineEdit> +#include <QtWidgets/QTextEdit> +#include <QtWidgets/QComboBox> +#include <QtWidgets/QLabel> +#include <vector> +#include "binaryninjaapi.h" +#include "uicontext.h" + +class BINARYNINJAUIAPI FormInputDialog: public QDialog +{ + Q_OBJECT + + std::vector<BinaryNinja::FormInputField>* m_fields; + std::vector<QWidget*> m_fieldControls; + + void openFileName(QLineEdit* edit, const std::string& ext); + void saveFileName(QLineEdit* edit, const std::string& ext, const std::string& defaultName); + void directoryName(QLineEdit* edit, const std::string& defaultName); + +public: + FormInputDialog(QWidget* parent, std::vector<BinaryNinja::FormInputField>* fields, const std::string& title); + +protected Q_SLOTS: + void finish(); +}; diff --git a/ui/functionlist.h b/ui/functionlist.h new file mode 100644 index 00000000..893a09ce --- /dev/null +++ b/ui/functionlist.h @@ -0,0 +1,135 @@ +#pragma once + +#include <QtWidgets/QListView> +#include <QtCore/QAbstractItemModel> +#include <QtCore/QTimer> +#include <QtWidgets/QLineEdit> +#include <vector> +#include <mutex> +#include "binaryninjaapi.h" +#include "viewframe.h" +#include "filter.h" +#include "uicontext.h" + +#define FUNCTION_LIST_UPDATE_INTERVAL 250 + +class BINARYNINJAUIAPI FunctionListModel: public QAbstractItemModel, public BinaryNinja::BinaryDataNotification +{ + Q_OBJECT + + enum FunctonListUpdateType + { + AddedToFunctionList, + RemovedFromFunctionList, + UpdatedInFunctionList + }; + + struct FunctionListUpdateEvent + { + FunctionRef func; + FunctonListUpdateType type; + }; + + struct NamedFunction + { + FunctionRef func; + std::string name; + bool named; + }; + + class FunctionListUpdate: public BinaryNinja::RefCountObject + { + std::mutex m_mutex; + bool m_valid; + FunctionListModel* m_model; + + public: + FunctionListUpdate(FunctionListModel* model); + void start(); + void abort(); + }; + + QWidget* m_funcList; + ViewFrame* m_view; + BinaryViewRef m_data; + std::vector<FunctionRef> m_funcs; + std::vector<NamedFunction> m_allFuncs; + FunctionRef m_currentFunc; + std::string m_filter; + + std::mutex m_updateMutex; + std::vector<FunctionListUpdateEvent> m_updates; + bool m_fullUpdate; + + BinaryNinja::Ref<FunctionListUpdate> m_backgroundUpdate; + volatile bool m_backgroundUpdateComplete; + std::vector<FunctionRef> m_backgroundUpdateFuncs; + + + static bool functionComparison(const FunctionRef& a, const FunctionRef& b); + static bool allFunctionComparison(const NamedFunction& a, const NamedFunction& b); + +public: + FunctionListModel(QWidget* parent, ViewFrame* view, BinaryViewRef data); + virtual ~FunctionListModel(); + + 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 = QModelIndex()) const override; + virtual int columnCount(const QModelIndex& parent) const override; + virtual QVariant data(const QModelIndex& i, int role) const override; + + virtual void OnAnalysisFunctionAdded(BinaryNinja::BinaryView* data, BinaryNinja::Function* func) override; + virtual void OnAnalysisFunctionRemoved(BinaryNinja::BinaryView* data, BinaryNinja::Function* func) override; + virtual void OnAnalysisFunctionUpdated(BinaryNinja::BinaryView* data, BinaryNinja::Function* func) override; + + void updateFonts(); + bool setCurrentFunction(FunctionRef func); + QModelIndex findFunction(FunctionRef func); + QModelIndex findCurrentFunction(); + FunctionRef getFunctionForIndex(int i); + + void updateFunctions(); + void backgroundUpdate(); + bool hasFunctions() const; + + void setFilter(const std::string& filter); +}; + +class BINARYNINJAUIAPI FunctionList: public QListView, public FilterTarget +{ + Q_OBJECT + + ViewFrame* m_view; + BinaryViewRef m_data; + FunctionListModel* m_list; + QTimer* m_updateTimer; + bool m_disableScrollToFunction; + +public: + FunctionList(QWidget* parent, ViewFrame* frame, BinaryViewRef data); + + void updateFonts(); + void setCurrentFunction(FunctionRef func); + + virtual void scrollToFirstItem() override; + virtual void scrollToCurrentItem() override; + virtual void selectFirstItem() override; + virtual void activateFirstItem() override; + virtual void setFilter(const std::string& filter) override; + + bool hasFunctions(); + + virtual void copy(); + virtual void paste(); + virtual bool canCopy(); + +protected: + virtual void focusOutEvent(QFocusEvent* event) override; + virtual void keyPressEvent(QKeyEvent* event) override; + +private Q_SLOTS: + void goToFunction(const QModelIndex& i); + void updateTimerEvent(); +}; diff --git a/ui/functionsview.h b/ui/functionsview.h new file mode 100644 index 00000000..02164079 --- /dev/null +++ b/ui/functionsview.h @@ -0,0 +1,41 @@ +#pragma once + +#include <QtCore/QTimer> +#include "binaryninjaapi.h" +#include "dockhandler.h" +#include "filter.h" + +class ViewFrame; +class FunctionList; + +class BINARYNINJAUIAPI FunctionsView: public QWidget, public DockContextHandler, public BinaryNinja::BinaryDataNotification +{ + Q_OBJECT + + BinaryViewRef m_data; + + FunctionList* m_funcList; + FilteredView* m_funcFilter; + + bool m_updatesPending; + QTimer* m_updateTimer; + +public: + FunctionsView(ViewFrame* frame, BinaryViewRef data); + virtual ~FunctionsView(); + + FunctionList* getFunctionList() { return m_funcList; } + FilteredView* getFunctionFilter() { return m_funcFilter; } + + virtual void OnBinaryDataWritten(BinaryNinja::BinaryView* data, uint64_t offset, size_t len) override; + virtual void OnBinaryDataInserted(BinaryNinja::BinaryView* data, uint64_t offset, size_t len) override; + virtual void OnBinaryDataRemoved(BinaryNinja::BinaryView* data, uint64_t offset, uint64_t len) override; + +protected: + virtual void contextMenuEvent(QContextMenuEvent* event) override; + virtual bool shouldBeVisible(ViewFrame* frame) override; + virtual void updateFonts() override; + +private Q_SLOTS: + void updateTimerEvent(); +}; diff --git a/ui/hexeditor.h b/ui/hexeditor.h new file mode 100644 index 00000000..26f877b9 --- /dev/null +++ b/ui/hexeditor.h @@ -0,0 +1,217 @@ +#pragma once + +#include <QtWidgets/QAbstractScrollArea> +#include <QtCore/QTimer> +#include "binaryninjaapi.h" +#include "viewframe.h" +#include "render.h" +#include "menus.h" +#include "statusbarwidget.h" +#include "uicontext.h" + +#define HEX_EDITOR_UPDATE_CHECK_INTERVAL 200 + +class BINARYNINJAUIAPI HexEditor : public QAbstractScrollArea, public View, public PreviewScrollHandler, + public BinaryNinja::BinaryDataNotification +{ + Q_OBJECT +public: + explicit HexEditor(BinaryViewRef data, ViewFrame* view, uint64_t startAddr = 0); + virtual ~HexEditor(); + + virtual bool canAssemble() override { return true; } + virtual bool canCompile() override { return true; } + + virtual BinaryViewRef getData() override { return m_data; } + virtual uint64_t getCurrentOffset() override; + virtual void getSelectionOffsets(uint64_t& begin, uint64_t& end) override; + virtual bool navigate(uint64_t pos) override; + + virtual void OnBinaryDataWritten(BinaryNinja::BinaryView* data, uint64_t offset, size_t len) override; + virtual void OnBinaryDataInserted(BinaryNinja::BinaryView* data, uint64_t offset, size_t len) override; + virtual void OnBinaryDataRemoved(BinaryNinja::BinaryView* data, uint64_t offset, uint64_t len) override; + + virtual void writeData(const BinaryNinja::DataBuffer& data) override; + virtual void selectAll(); + virtual void selectNone(); + + void setSelectionRange(uint64_t begin, uint64_t end); + + virtual void updateFonts() override; + + virtual StatusBarWidget* getStatusBarWidget() override; + + virtual void followPointer(); + + void setHighlightMode(HexEditorHighlightMode mode); + void setColorMode(HexEditorColorMode mode); + void setContrast(HexEditorHighlightContrast mode); + + virtual void sendWheelEvent(QWheelEvent* event) override; + + QFont getFont() override { return m_render.getFont(); } + + static void registerActions(); + +private: + class HexEditorHighlightWidget: public QLabel + { + public: + HexEditorHighlightWidget(HexEditor* parent); + + protected: + virtual void mousePressEvent(QMouseEvent* event); + virtual void enterEvent(QEvent* event); + virtual void leaveEvent(QEvent* event); + + private: + HexEditor* m_editor; + Menu m_menu; + ContextMenuManager m_contextMenuManager; + }; + + class HexEditorStatusBarWidget: public StatusBarWidget + { + public: + HexEditorStatusBarWidget(HexEditor* parent); + virtual void updateStatus() override; + + private: + HexEditor* m_editor; + HexEditorHighlightWidget* m_highlight; + }; + + struct HexEditorLine + { + bool separator; + uint64_t addr; + size_t len; + }; + + uint64_t getStart(); + uint64_t getEnd(); + uint64_t getLength(); + + void updateRanges(); + + void adjustSize(int width, int height); + + uint64_t getContiguousOffsetForAddress(uint64_t addr); + uint64_t getAddressForContiguousOffset(uint64_t offset); + + void setTopToAddress(uint64_t addr); + void refreshLines(); + void refreshAtCurrentLocation(); + bool cachePreviousLines(); + bool cacheNextLines(); + void updateCache(); + void scrollLines(int count); + + uint64_t getCursorPos(); + void setCursorPos(uint64_t pos); + void repositionCaret(); + void updateCaret(); + void bindActions(); + + std::pair<uint64_t, uint64_t> getSelectionRange(); + bool isSelectionActive(); + + void goToAddress(bool selection); + void searchRegEx(); + void findNext(); + + void inputByte(uint8_t byte); + void inputHexDigit(uint8_t digit); + + void adjustAddressAfterBackwardMovement(); + void adjustAddressAfterForwardMovement(); + + void left(size_t count, bool selecting); + void right(size_t count, bool selecting); + void up(bool selecting); + void down(bool selecting); + void pageUp(bool selecting); + void pageDown(bool selecting); + void moveToStartOfLine(bool selecting); + void moveToEndOfLine(bool selecting); + void moveToStartOfView(bool selecting); + void moveToEndOfView(bool selecting); + void toggleHexOrAscii(); + void toggleInsertMode(); + void deleteBack(); + void deleteForward(); + + BinaryViewRef m_data; + ViewFrame* m_view; + + std::vector<HexEditorLine> m_lines; + size_t m_topLine; + uint64_t m_topAddr, m_bottomAddr; + + std::vector<BNAddressRange> m_ranges; + uint64_t m_allocatedLength; + uint64_t m_scrollBarMultiplier; + int m_wheelDelta; + bool m_updatingScrollBar; + bool m_updatesRequired; + + uint64_t m_minAddr; + uint64_t m_cursorAddr, m_prevCursorAddr; + int m_cursorOffset; + uint64_t m_selectionStartAddr; + int m_cols, m_visibleRows; + int m_lastMouseX, m_lastMouseY; + bool m_selectionVisible; + bool m_cursorAscii; + bool m_caretVisible, m_caretBlink; + bool m_insertMode; + bool m_leftButtonDown; + QString m_status; + QTimer* m_cursorTimer; + QTimer* m_updateTimer; + Qt::KeyboardModifiers m_ctrl, m_command; + + RenderContext m_render; + HexEditorHighlightState m_highlightState; + + ContextMenuManager m_contextMenuManager; + +protected: + virtual void resizeEvent(QResizeEvent* event) override; + virtual void paintEvent(QPaintEvent* event) override; + virtual void focusInEvent(QFocusEvent* event) override; + virtual void focusOutEvent(QFocusEvent* event) override; + virtual void keyPressEvent(QKeyEvent* event) override; + virtual void keyReleaseEvent(QKeyEvent* event) override; + virtual void mousePressEvent(QMouseEvent* event) override; + virtual void mouseMoveEvent(QMouseEvent* event) override; + virtual void mouseReleaseEvent(QMouseEvent* event) override; + virtual bool event(QEvent* event) override; + virtual void wheelEvent(QWheelEvent* event) override; + +Q_SIGNALS: + +public Q_SLOTS: + void disassembly(); + void createFunc(); + void createFuncWithPlatform(PlatformRef platform); + +private Q_SLOTS: + void scrollBarMoved(int value); + void scrollBarAction(int action); + void cursorTimerEvent(); + void updateTimerEvent(); +}; + +class HexEditorViewType: public ViewType +{ + static HexEditorViewType* m_instance; + +public: + HexEditorViewType(); + virtual int getPriority(BinaryViewRef data, const QString& filename) override; + virtual QWidget* create(BinaryViewRef data, ViewFrame* viewFrame) override; + virtual QString getDisplayName(BinaryViewTypeRef type) override; + virtual QString getDisplayLongName(BinaryViewTypeRef type) override; + static void init(); +}; diff --git a/ui/instructionedit.h b/ui/instructionedit.h new file mode 100644 index 00000000..9e388210 --- /dev/null +++ b/ui/instructionedit.h @@ -0,0 +1,29 @@ +#pragma once + +#include <QtWidgets/QLineEdit> +#include "binaryninjaapi.h" +#include "uicontext.h" + +class BINARYNINJAUIAPI InstructionEdit: public QLineEdit +{ + Q_OBJECT + + BinaryViewRef m_data; + ArchitectureRef m_arch; + FunctionRef m_func; + uint64_t m_offset; + bool m_preventDismiss; + +public: + InstructionEdit(QWidget* parent, BinaryViewRef data, ArchitectureRef arch, FunctionRef func, uint64_t offset); + + void acceptInstruction(); + void rejectInstruction(); + +protected: + virtual void keyPressEvent(QKeyEvent* event); + virtual void focusOutEvent(QFocusEvent* event); + +Q_SIGNALS: + void done(); +}; diff --git a/ui/linearview.h b/ui/linearview.h new file mode 100644 index 00000000..4c67e8d8 --- /dev/null +++ b/ui/linearview.h @@ -0,0 +1,235 @@ +#pragma once + +#include <QtWidgets/QAbstractScrollArea> +#include <QtCore/QTimer> +#include "binaryninjaapi.h" +#include "viewframe.h" +#include "render.h" +#include "commentdialog.h" +#include "menus.h" +#include "statusbarwidget.h" +#include "uicontext.h" + +#define LINEAR_VIEW_UPDATE_CHECK_INTERVAL 200 +#define MAX_STRING_TYPE_LENGTH 1048576 +#define EDGE_GUTTER_WIDTH 4 + +class BINARYNINJAUIAPI LinearViewHistoryEntry: public HistoryEntry +{ + BinaryNinja::LinearDisassemblyPosition m_topPosition, m_cursorPosition; + size_t m_topLineOffset; + HighlightTokenState m_highlight; + +public: + const BinaryNinja::LinearDisassemblyPosition& getTopPosition() const { return m_topPosition; } + const BinaryNinja::LinearDisassemblyPosition& getCursorPosition() const { return m_cursorPosition; } + size_t getTopLineOffset() const { return m_topLineOffset; } + const HighlightTokenState& getHighlightTokenState() const { return m_highlight; } + + void setTopPosition(const BinaryNinja::LinearDisassemblyPosition& pos) { m_topPosition = pos; } + void setCursorPosition(const BinaryNinja::LinearDisassemblyPosition& pos) { m_cursorPosition = pos; } + void setTopLineOffset(size_t offset) { m_topLineOffset = offset; } + void setHighlightTokenState(const HighlightTokenState& state) { m_highlight = state; } +}; + +class BINARYNINJAUIAPI LinearView: public QAbstractScrollArea, public View, public BinaryNinja::BinaryDataNotification +{ + Q_OBJECT + + class LinearViewOptionsWidget: public QLabel + { + public: + LinearViewOptionsWidget(LinearView* parent); + + protected: + virtual void mousePressEvent(QMouseEvent* event); + virtual void enterEvent(QEvent* event); + virtual void leaveEvent(QEvent* event); + + private: + LinearView* m_view; + Menu m_menu; + ContextMenuManager m_contextMenuManager; + }; + + class LinearViewStatusBarWidget: public StatusBarWidget + { + public: + LinearViewStatusBarWidget(LinearView* parent); + virtual void updateStatus() override; + + private: + LinearView* m_view; + LinearViewOptionsWidget* m_options; + }; + + BinaryViewRef m_data; + ViewFrame* m_view; + std::vector<BNAddressRange> m_ranges; + uint64_t m_allocatedLength; + + RenderContext m_render; + int m_cols, m_rows; + uint64_t m_scrollBarMultiplier; + int m_wheelDelta; + bool m_updatingScrollBar; + + bool m_updatesRequired; + bool m_updateBounds, m_updateBlockRef; + + BinaryNinja::LinearDisassemblyPosition m_cursorPosition; + bool m_cursorPositionHasOffset = false; + size_t m_cursorPositionOffset = 0; + HighlightTokenState m_highlight; + uint64_t m_navByRefTarget; + bool m_navByRef = false; + + DisassemblySettingsRef m_settings; + + BinaryNinja::LinearDisassemblyPosition m_topPosition, m_bottomPosition; + std::vector<BinaryNinja::LinearDisassemblyLine> m_lines; + size_t m_topLine; + + QTimer* m_updateTimer; + + ContextMenuManager m_contextMenuManager; + QPointer<CommentDialog> m_commentDialog; + + void adjustSize(int width, int height); + + uint64_t getContiguousOffsetForAddress(uint64_t addr); + uint64_t getAddressForContiguousOffset(uint64_t offset); + + void setTopToAddress(uint64_t addr); + void refreshLines(size_t lineOffset = 0, bool refreshUIContext = true); + bool cachePreviousLines(); + bool cacheNextLines(size_t& topLineAdjustment); + void updateCache(); + void refreshAtCurrentLocation(); + bool navigateToAddress(uint64_t addr, bool center, bool updateHighlight, bool navByRef = false); + + void scrollLines(int count); + + void bindActions(); + void getHexDumpLineBytes(const BinaryNinja::LinearDisassemblyLine& line, size_t& skippedBytes, size_t& totalBytes, + size_t& totalCols); + + void setSectionSemantics(const std::string& name, BNSectionSemantics semantics); + +private Q_SLOTS: + void viewInHexEditor(); + void viewInGraph(); + void viewInTypesView(std::string typeName = ""); + void copyAddressSlot(); + void goToAddress(); + void defineNameAtAddr(uint64_t addr); + void defineName(); + void undefineName(); + void createFunc(); + void defineFuncName(); + void undefineFunc(); + void reanalyze(); + void comment(); + void commentAccepted(); + + void convertToNop(); + void alwaysBranch(); + void invertBranch(); + void skipAndReturnZero(); + void skipAndReturnValue(); + + void makeInt8(); + void makeInt16(); + void makeInt32(); + void makeInt64(); + void toggleIntSize(); + void makePtr(); + void makeString(); + void changeType(); + size_t getStringLength(uint64_t startAddr); + + void displayAsDefault(); + void displayAsBinary(); + void displayAsSignedOctal(); + void displayAsUnsignedOctal(); + void displayAsSignedDecimal(); + void displayAsUnsignedDecimal(); + void displayAsSignedHexadecimal(); + void displayAsUnsignedHexadecimal(); + void displayAsCharacterConstant(); + void displayAsPointer(); + + void setInstructionHighlight(BNHighlightColor color); + void setBlockHighlight(BNHighlightColor color); + + void scrollBarMoved(int value); + void scrollBarAction(int action); + void updateTimerEvent(); + +public: + explicit LinearView(BinaryViewRef data, ViewFrame* view); + virtual ~LinearView(); + + virtual bool canAssemble() override { return true; } + virtual bool canCompile() override { return true; } + + virtual BinaryViewRef getData() override { return m_data; } + virtual uint64_t getCurrentOffset() override; + virtual void getSelectionOffsets(uint64_t& begin, uint64_t& end) override; + virtual void getSelectionForInfo(uint64_t& begin, uint64_t& end) override; + virtual FunctionRef getCurrentFunction() override; + virtual BasicBlockRef getCurrentBasicBlock() override; + virtual ArchitectureRef getCurrentArchitecture() override; + virtual bool navigate(uint64_t pos) override; + + virtual HistoryEntry* getHistoryEntry() override; + virtual void navigateToHistoryEntry(HistoryEntry* entry) override; + + virtual void OnBinaryDataWritten(BinaryNinja::BinaryView* data, uint64_t offset, size_t len) override; + virtual void OnBinaryDataInserted(BinaryNinja::BinaryView* data, uint64_t offset, size_t len) override; + virtual void OnBinaryDataRemoved(BinaryNinja::BinaryView* data, uint64_t offset, uint64_t len) override; + virtual void OnAnalysisFunctionAdded(BinaryNinja::BinaryView* view, BinaryNinja::Function* func) override; + virtual void OnAnalysisFunctionRemoved(BinaryNinja::BinaryView* view, BinaryNinja::Function* func) override; + virtual void OnAnalysisFunctionUpdated(BinaryNinja::BinaryView* view, BinaryNinja::Function* func) override; + virtual void OnDataVariableAdded(BinaryNinja::BinaryView* view, const BinaryNinja::DataVariable& var) override; + virtual void OnDataVariableRemoved(BinaryNinja::BinaryView* view, const BinaryNinja::DataVariable& var) override; + virtual void OnDataVariableUpdated(BinaryNinja::BinaryView* view, const BinaryNinja::DataVariable& var) override; + + virtual void updateFonts() override; + + virtual StatusBarWidget* getStatusBarWidget() override; + + virtual void followPointer(); + + virtual void cut() override; + virtual void copy(TransformRef xform = nullptr) override; + virtual void paste(TransformRef xform = nullptr) override; + virtual void copyAddress() override; + + virtual HighlightTokenState getHighlightTokenState() override { return m_highlight; } + + void toggleOption(BNDisassemblyOption option); + + virtual bool goToReference(FunctionRef func, uint64_t source, uint64_t target) override; + QFont getFont() override { return m_render.getFont(); } + + static void registerActions(); + +protected: + virtual void resizeEvent(QResizeEvent* event) override; + virtual void paintEvent(QPaintEvent* event) override; + virtual void wheelEvent(QWheelEvent* event) override; + virtual void mousePressEvent(QMouseEvent* event) override; + virtual void mouseDoubleClickEvent(QMouseEvent* event) override; +}; + +class LinearViewType: public ViewType +{ + static LinearViewType* m_instance; + +public: + LinearViewType(); + virtual int getPriority(BinaryViewRef data, const QString& filename) override; + virtual QWidget* create(BinaryViewRef data, ViewFrame* viewFrame) override; + static void init(); +}; diff --git a/ui/logview.h b/ui/logview.h new file mode 100644 index 00000000..b8566ee7 --- /dev/null +++ b/ui/logview.h @@ -0,0 +1,165 @@ +#pragma once + +#include <QtWidgets/QListView> +#include <QtCore/QItemSelection> +#include <QtCore/QPointer> +#include <QtCore/QTimer> +#include <QtWidgets/QStyledItemDelegate> +#include <QtWidgets/QLabel> +#include <QtWidgets/QToolButton> +#include <mutex> +#include <string> +#include <utility> +#include <vector> + +#include "binaryninjaapi.h" +#include "action.h" +#include "dockhandler.h" + +#define DEFAULT_MAX_LOG_SIZE 10000 +#define LOG_UPDATE_INTERVAL 100 + +class LogStatus; +class View; +class ViewFrame; + +struct BINARYNINJAUIAPI LogListItem +{ + BNLogLevel level; + std::string text; + bool selected; + + LogListItem(BNLogLevel level, std::string text, bool selected = false) : level(level), text(text), selected(selected) { }; +}; + + +class BINARYNINJAUIAPI LogListModel: public QAbstractItemModel, public BinaryNinja::LogListener +{ + Q_OBJECT + + QWidget* m_owner; + std::deque<LogListItem> m_items; + std::deque<LogListItem> m_visibleItems; + size_t m_maxSize; + + std::vector<LogListItem> m_pendingItems; + std::mutex m_mutex; + std::mutex m_pendingMutex; + +public: + LogListModel(QWidget* parent); + ~LogListModel(); + + void addPendingItems(); + void clear(); + std::vector<LogListItem> getSelectedItems(); + bool hasSelectedItems(); + + virtual void LogMessage(BNLogLevel level, const std::string& msg) override; + virtual BNLogLevel GetLogLevel() override; + + 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; + virtual bool setData(const QModelIndex& i, const QVariant& value, int role) override; +}; + + +class BINARYNINJAUIAPI LogItemDelegate: public QStyledItemDelegate +{ + Q_OBJECT + + QWidget* m_owner; + ViewFrame* m_viewFrame = nullptr; + View* m_view = nullptr; + BinaryViewRef m_data; + + QFont m_font; + int m_height; + + bool IsNavigable(const QString& str, const std::pair<int, int>& offsetLen, uint64_t& value, bool highlight) const; + +public: + LogItemDelegate(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; + +protected: + bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) override; + +public Q_SLOTS: + void viewChanged(QWidget* frame); +}; + + +class BINARYNINJAUIAPI LogView: public QListView, public DockContextHandler +{ + Q_OBJECT + + QPointer<LogStatus> m_logStatus; + std::vector<std::pair<QAction*, bool>> m_actionEnableList; + LogListModel* m_listModel; + LogItemDelegate* m_itemDelegate; + QTimer* m_updateTimer; + + bool m_doClear; + bool m_scrolledToEnd; + bool m_hasSelection = false; + +public: + LogView(QWidget* parent, LogStatus* logStatus); + + virtual void copy(); + virtual bool canCopy(); + + static void SetLogLevel(BNLogLevel level); + +protected: + void contextMenuEvent(QContextMenuEvent* event) override; + void focusInput() override; + void notifyViewChanged(ViewFrame* frame) override; + void updateFonts() override; + +Q_SIGNALS: + void notifyUiStatus(); + void viewChanged(QWidget* frame); + +public Q_SLOTS: + void clear(); + +private Q_SLOTS: + void scrollRangeChanged(int minimum, int maximum); + void scrollValueChanged(int value); + void updateSelection(const QItemSelection& selected, const QItemSelection& deselected); + void updateTimerEvent(); + void updateUiStatus(); +}; + + +class BINARYNINJAUIAPI LogStatus: public QWidget +{ + Q_OBJECT + + QToolButton* m_errorIndicator; + QToolButton* m_warnIndicator; + + int m_errorCount = 0; + int m_warnCount = 0; + +public: + LogStatus(QWidget* parent); + + void incrementErrorCount(int count); + void incrementWarningCount(int count); + void clearIndicators(); + + void updateTheme(); + +private Q_SLOTS: + void clearStatus(); +}; diff --git a/ui/menus.h b/ui/menus.h new file mode 100644 index 00000000..0a455243 --- /dev/null +++ b/ui/menus.h @@ -0,0 +1,25 @@ +#pragma once + +#include <QtCore/QPointer> +#include <QtWidgets/QMenu> +#include <QtWidgets/QWidget> +#include <functional> +#include <map> +#include <string> +#include "binaryninjaapi.h" +#include "viewframe.h" + +class BINARYNINJAUIAPI ContextMenuManager +{ + QWidget* m_parent; + QPointer<QMenu> m_menu; + MenuInstance* m_instance; + +public: + ContextMenuManager(QWidget* parent); + ~ContextMenuManager(); + QMenu* create(); + MenuInstance* show(View* view); + MenuInstance* show(Menu* source, UIActionHandler* handler); + bool isActive() { return !m_menu.isNull(); } +}; diff --git a/ui/minigraph.h b/ui/minigraph.h new file mode 100644 index 00000000..25baa58c --- /dev/null +++ b/ui/minigraph.h @@ -0,0 +1,39 @@ +#pragma once + +#include <QtGui/QMouseEvent> +#include <QtGui/QPaintEvent> +#include <QtWidgets/QWidget> + +#include "binaryninjaapi.h" +#include "dockhandler.h" +#include "uitypes.h" + +class ContextMenuManager; +class DisassemblyView; +class Menu; +class ViewFrame; + +class BINARYNINJAUIAPI MiniGraph: public QWidget, public DockContextHandler +{ + Q_OBJECT + + DisassemblyView* m_disassemblyView = nullptr; + +public: + MiniGraph(QWidget* parent); + ~MiniGraph(); + + virtual bool isAvailable(ViewFrame* frame) override; + virtual void notifyViewChanged(ViewFrame* frame) override; + virtual bool shouldBeVisible(ViewFrame* frame) override; + +protected: + virtual void contextMenuEvent(QContextMenuEvent* event) override; + virtual void mouseMoveEvent(QMouseEvent* event) override; + virtual void mousePressEvent(QMouseEvent* event) override; + virtual void paintEvent(QPaintEvent* event) override; + virtual void scrollTo(int x, int y); + +public Q_SLOTS: + void notifyUpdate(); +}; diff --git a/ui/platformdialog.h b/ui/platformdialog.h new file mode 100644 index 00000000..01f2c75f --- /dev/null +++ b/ui/platformdialog.h @@ -0,0 +1,30 @@ +#pragma once + +#include <QtWidgets/QDialog> +#include <QtWidgets/QComboBox> +#include "binaryninjaapi.h" +#include "uicontext.h" + +class BINARYNINJAUIAPI PlatformDialog: public QDialog +{ + Q_OBJECT + + QComboBox* m_arch; + QComboBox* m_os; + QComboBox* m_platform; + + std::map<QString, PlatformRef> m_platformsByName; + PlatformRef m_selectedPlatform; + +public: + PlatformDialog(QWidget* parent, ArchitectureRef defaultArch = nullptr); + + PlatformRef getPlatform(); + void saveDefaults(); + +private Q_SLOTS: + void architectureChanged(const QString& name); + void osChanged(const QString& name); + + void selectPlatform(); +}; diff --git a/ui/preview.h b/ui/preview.h new file mode 100644 index 00000000..670e8fb9 --- /dev/null +++ b/ui/preview.h @@ -0,0 +1,35 @@ +#pragma once + +#include <QtWidgets/QLabel> +#include <QtWidgets/QWidget> +#include "uitypes.h" + +class BINARYNINJAUIAPI PreviewScrollHandler +{ +public: + virtual ~PreviewScrollHandler() {} + virtual void sendWheelEvent(QWheelEvent* event) = 0; +}; + +class BINARYNINJAUIAPI PreviewWidget: public QFrame +{ + Q_OBJECT + + QWidget* m_contents; + PreviewScrollHandler* m_scrollHandler; + +protected: + virtual bool eventFilter(QObject* obj, QEvent* event) override; + virtual void wheelEvent(QWheelEvent* event) override; + +public: + PreviewWidget(); + virtual ~PreviewWidget(); + + void setContents(QWidget* widget); + void setScrollHandler(PreviewScrollHandler* handler); + void sendWheelEvent(QWheelEvent* event); + void closePreview(); + + static bool isPreviewWidget(QWidget* widget); +}; diff --git a/ui/progressindicator.h b/ui/progressindicator.h new file mode 100644 index 00000000..91932d3b --- /dev/null +++ b/ui/progressindicator.h @@ -0,0 +1,111 @@ +// Copyright (c) 2011 Morgan Leborgne +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef QPROGRESSINDICATOR_H +#define QPROGRESSINDICATOR_H + +#include <QtWidgets/QWidget> +#include <QtGui/QColor> +#include "uicontext.h" + +/*! + \class QProgressIndicator + \brief The QProgressIndicator class lets an application display a progress indicator to show that a lengthy task is under way. + + Progress indicators are indeterminate and do nothing more than spin to show that the application is busy. + \sa QProgressBar +*/ +class BINARYNINJAUIAPI QProgressIndicator : public QWidget +{ + Q_OBJECT + Q_PROPERTY(int delay READ animationDelay WRITE setAnimationDelay) + Q_PROPERTY(bool displayedWhenStopped READ isDisplayedWhenStopped WRITE setDisplayedWhenStopped) + Q_PROPERTY(QColor color READ color WRITE setColor) + int m_width = 18; + +public: + QProgressIndicator(QWidget* parent = 0); + + /*! Returns the delay between animation steps. + \return The number of milliseconds between animation steps. By default, the animation delay is set to 40 milliseconds. + \sa setAnimationDelay + */ + int animationDelay() const { return m_delay; } + + /*! Returns a Boolean value indicating whether the component is currently animated. + \return Animation state. + \sa startAnimation stopAnimation + */ + bool isAnimated () const; + + /*! Returns a Boolean value indicating whether the receiver shows itself even when it is not animating. + \return Return true if the progress indicator shows itself even when it is not animating. By default, it returns false. + \sa setDisplayedWhenStopped + */ + bool isDisplayedWhenStopped() const; + + /*! Returns the color of the component. + \sa setColor + */ + const QColor & color() const { return m_color; } + + virtual QSize sizeHint() const { return QSize(m_width, m_width); }; + void setWidth(int width) { m_width = width; }; + int heightForWidth(int w) const; +public Q_SLOTS: + /*! Starts the spin animation. + \sa stopAnimation isAnimated + */ + void startAnimation(); + + /*! Stops the spin animation. + \sa startAnimation isAnimated + */ + void stopAnimation(); + + /*! Sets the delay between animation steps. + Setting the \a delay to a value larger than 40 slows the animation, while setting the \a delay to a smaller value speeds it up. + \param delay The delay, in milliseconds. + \sa animationDelay + */ + void setAnimationDelay(int delay); + + /*! Sets whether the component hides itself when it is not animating. + \param state The animation state. Set false to hide the progress indicator when it is not animating; otherwise true. + \sa isDisplayedWhenStopped + */ + void setDisplayedWhenStopped(bool state); + + /*! Sets the color of the components to the given color. + \sa color + */ + void setColor(const QColor & color); +protected: + virtual void timerEvent(QTimerEvent * event); + virtual void paintEvent(QPaintEvent * event); +private: + int m_angle; + int m_timerId; + int m_delay; + bool m_displayedWhenStopped; + QColor m_color; +}; + +#endif // QPROGRESSINDICATOR_H diff --git a/ui/qfileaccessor.h b/ui/qfileaccessor.h new file mode 100644 index 00000000..f04e0bdd --- /dev/null +++ b/ui/qfileaccessor.h @@ -0,0 +1,22 @@ +#pragma once + +#include <QtCore/QFile> +#include "binaryninjaapi.h" +#include "action.h" + +class BINARYNINJAUIAPI QFileAccessor : public BinaryNinja::FileAccessor +{ + QFile* m_file; + +public: + QFileAccessor(const QString& name, bool write = false); + virtual ~QFileAccessor(); + + virtual bool IsValid() const; + virtual uint64_t GetLength() const; + + virtual size_t Read(void* dest, uint64_t offset, size_t len); + virtual size_t Write(uint64_t offset, const void* src, size_t len); + + void Close(); +}; diff --git a/ui/render.h b/ui/render.h new file mode 100644 index 00000000..2ae59d63 --- /dev/null +++ b/ui/render.h @@ -0,0 +1,94 @@ +#pragma once + +#include <QtGui/QPainter> +#include "binaryninjaapi.h" +#include "uicontext.h" +#include "action.h" + +enum HexEditorHighlightMode +{ + NoHighlight, + ColumnHighlight, + ByteValueHighlight +}; + +enum HexEditorColorMode +{ + NoColorization, + AsciiColorization, + ModificationColorization +}; + +enum HexEditorHighlightContrast +{ + NormalContrastHighlight, + MediumContrastHighlight, + HighContrastHighlight +}; + +struct BINARYNINJAUIAPI HexEditorHighlightState +{ + HexEditorHighlightMode mode; + HexEditorColorMode color; + HexEditorHighlightContrast contrast; + + void restoreSettings(); + void saveSettings(); +}; + +class BINARYNINJAUIAPI FontParameters +{ + QWidget* m_owner; + QFont m_font; + int m_baseline, m_charWidth, m_charHeight, m_charOffset; + float m_fontScale; + bool m_customFont; + +public: + FontParameters(QWidget* parent, float fontScale = 1.0f); + void update(); + + QFont& getFont() { return m_font; } + void setFont(const QFont& font); + int getBaseline() const { return m_baseline; } + int getWidth() const { return m_charWidth; } + int getHeight() const { return m_charHeight; } + int getOffset() const { return m_charOffset; } +}; + +class BINARYNINJAUIAPI RenderContext +{ + QWidget* m_owner; + FontParameters m_fontParams; + +public: + RenderContext(QWidget* parent, float fontScale = 1.0f); + void update(); + + FontParameters& getFontParamters() { return m_fontParams; } + int getFontWidth() const { return m_fontParams.getWidth(); } + int getFontHeight() const { return m_fontParams.getHeight(); } + + void init(QPainter& p); + + QColor getColorForHexDumpByte(const HexEditorHighlightState& state, BNModificationStatus modification, uint8_t byte); + QColor getHighlightColor(BNHighlightColor color); + + HighlightTokenState getTokenForDisassemblyLinePosition(size_t col, const std::vector<BinaryNinja::InstructionTextToken>& tokens); + + void drawText(QPainter& p, int x, int y, QColor color, const QString& text); + + void drawSeparatorLine(QPainter& p, QColor top, QColor bottom, QColor line, const QRect& rect); + void drawInstructionHighlight(QPainter& p, const QRect& rect); + + void drawLinearDisassemblyLineBackground(QPainter& p, BNLinearDisassemblyLineType type, const QRect& rect, + int gutterWidth); + void drawDisassemblyLine(QPainter& p, int left, int top, const std::vector<BinaryNinja::InstructionTextToken>& tokens, + HighlightTokenState& highlight, bool highlightOnly=false); + + void drawHexEditorLine(QPainter& p, int left, int top, const HexEditorHighlightState& highlight, + BinaryViewRef view, uint64_t lineStartAddr, size_t cols, size_t firstCol, size_t count, + bool cursorVisible, bool cursorAscii, size_t cursorPos, bool byteCursor); + QFont getFont() { return m_fontParams.getFont(); } + void setFont(const QFont& font); +}; diff --git a/ui/reportcollectionwidget.h b/ui/reportcollectionwidget.h new file mode 100644 index 00000000..95dc9262 --- /dev/null +++ b/ui/reportcollectionwidget.h @@ -0,0 +1,32 @@ +#pragma once + +#include <QtWidgets/QWidget> +#include <QtWidgets/QSplitter> +#include <QtWidgets/QListWidget> +#include <QtWidgets/QVBoxLayout> +#include "binaryninjaapi.h" +#include "viewframe.h" +#include "uicontext.h" + +class BINARYNINJAUIAPI ReportCollectionWidget: public QWidget, public ViewContainer +{ + Q_OBJECT + + QSplitter* m_splitter; + QListWidget* m_list; + QWidget* m_report; + QWidget* m_reportContainer; + QVBoxLayout* m_reportLayout; + + ReportCollectionRef m_collection; + int m_currentReportIndex; + std::string m_title; + +public: + ReportCollectionWidget(QWidget* parent, ReportCollectionRef reports, const std::string& title); + + virtual View* getView() override; + +private Q_SLOTS: + void selectReport(int i); +}; diff --git a/ui/reportwidget.h b/ui/reportwidget.h new file mode 100644 index 00000000..22d51604 --- /dev/null +++ b/ui/reportwidget.h @@ -0,0 +1,33 @@ +#pragma once + +#include <QtWidgets/QWidget> +#include <QtWidgets/QTextBrowser> +#include <QtWidgets/QScrollArea> +#include "binaryninjaapi.h" +#include "action.h" + +class BINARYNINJAUIAPI ReportWidget: public QScrollArea, public UIActionHandler +{ + Q_OBJECT + + QTextBrowser* m_contents; + BinaryViewRef m_view; + std::string m_original; + std::string m_title; + BNReportType m_type; + std::string m_plaintext; + +private Q_SLOTS: + void onLinkClicked(QUrl url); + +public: + ReportWidget(QWidget* parent, BinaryViewRef view, const std::string& contents, + BNReportType type, const std::string& title, const std::string& plaintext = ""); + std::string getContents() const { return m_original; } + std::string getTitle() const { return m_title; } + BNReportType getType() const { return m_type; } + std::string getPlainText() const { return m_plaintext; } + + void save(); + void saveAs(); +}; diff --git a/ui/scriptingconsole.h b/ui/scriptingconsole.h new file mode 100644 index 00000000..430e4b21 --- /dev/null +++ b/ui/scriptingconsole.h @@ -0,0 +1,115 @@ +#pragma once + +#include <QtCore/QTimer> +#include <QtWidgets/QLabel> +#include <QtWidgets/QLineEdit> +#include <QtWidgets/QPushButton> +#include <QtWidgets/QTextEdit> +#include <QtWidgets/QWidget> +#include <mutex> +#include <string> +#include <utility> +#include <vector> +#include "binaryninjaapi.h" +#include "action.h" +#include "dockhandler.h" +#include "uitypes.h" + +#define SCRIPT_OUTPUT_UPDATE_INTERVAL 100 +#define SCRIPT_HISTORY_LENGTH 100 + +class ScriptingConsole; + +class BINARYNINJAUIAPI ScriptingConsoleEdit: public QTextEdit +{ + Q_OBJECT + + ScriptingConsole* m_console; + int m_charHeight; + bool m_continuation; + +public: + ScriptingConsoleEdit(ScriptingConsole* parent); + void setCharHeight(int height); + void setContinutation(bool cont); + +protected: + virtual void keyPressEvent(QKeyEvent* event) override; +}; + +class BINARYNINJAUIAPI ScriptingConsoleOutput: public QTextEdit +{ + Q_OBJECT + + ScriptingConsole* m_console; + QAction* m_outputActionClear; + +public: + ScriptingConsoleOutput(ScriptingConsole* parent); + +protected: + virtual void contextMenuEvent(QContextMenuEvent *event) override; +}; + +class ScriptingConsoleWidget; + +class BINARYNINJAUIAPI ScriptingConsole: public QWidget, public DockContextHandler, BinaryNinja::ScriptingOutputListener +{ + Q_OBJECT + + struct ScriptOutput + { + std::string text; + bool isError; + }; + + QString m_providerName; + QString m_instanceName; + ScriptingInstanceRef m_instance; + ScriptingConsoleOutput* m_output; + ScriptingConsoleEdit* m_input; + QLabel* m_prompt; + QPushButton* m_button; + QTimer* m_runTimer; + + std::mutex m_mutex; + std::vector<ScriptOutput> m_pendingOutput; + QTimer* m_updateTimer; + + BNScriptingProviderInputReadyState m_currentState; + + QStringList m_history; + QString m_inputOutsideHistory; + int m_currentHistoryEntry; + + static int m_stateUpdatedEventType; + +private Q_SLOTS: + void updateTimerEvent(); + void cancel(); + void showCancelButton(); + +protected: + void customEvent(QEvent* event) override; + void focusInput() override; + void updateFonts() override; + +public: + ScriptingConsole(QWidget* parent, const QString& providerName, const QString& instanceName, ScriptingInstanceRef instance); + virtual ~ScriptingConsole(); + + QString getProviderName() const { return m_providerName; } + QString getInstanceName() const { return m_instanceName; } + ScriptingInstanceRef getInstance() { return m_instance; } + + void hideConsole(); + + void addInput(const std::string& text); + + virtual void NotifyOutput(const std::string& text) override; + virtual void NotifyError(const std::string& text) override; + virtual void NotifyInputReadyStateChanged(BNScriptingProviderInputReadyState state) override; + + void moveUpInHistory(); + void moveDownInHistory(); +}; diff --git a/ui/statusbarwidget.h b/ui/statusbarwidget.h new file mode 100644 index 00000000..b41391a0 --- /dev/null +++ b/ui/statusbarwidget.h @@ -0,0 +1,23 @@ +#pragma once + +#include <QtWidgets/QFrame> +#include <QtWidgets/QLabel> +#include "uicontext.h" + +class BINARYNINJAUIAPI StatusBarWidget: public QWidget +{ + Q_OBJECT + +public: + StatusBarWidget(QWidget* parent); + virtual void updateStatus(); +}; + +class BINARYNINJAUIAPI DisabledOptionsStatusBarWidget: public StatusBarWidget +{ +public: + DisabledOptionsStatusBarWidget(QFrame* parent); + +private: + QLabel* m_label; +}; diff --git a/ui/stringsview.h b/ui/stringsview.h new file mode 100644 index 00000000..dd3d54ff --- /dev/null +++ b/ui/stringsview.h @@ -0,0 +1,149 @@ +#pragma once + +#include <QtWidgets/QListView> +#include <QtWidgets/QStyledItemDelegate> +#include <mutex> +#include "viewframe.h" +#include "filter.h" +#include "uicontext.h" + +#define STRINGS_LIST_UPDATE_INTERVAL 250 + +class BINARYNINJAUIAPI StringsListModel: public QAbstractItemModel, public BinaryNinja::BinaryDataNotification +{ + Q_OBJECT + + struct StringUpdateEvent + { + BNStringReference ref; + bool added; + }; + + QWidget* m_stringsList; + BinaryViewRef m_data; + std::vector<BNStringReference> m_allStrings; + std::vector<BNStringReference> m_strings; + std::string m_filter; + + std::mutex m_updateMutex; + std::vector<StringUpdateEvent> m_updates; + + static bool stringComparison(const BNStringReference& a, const BNStringReference& b); + bool matchString(const BNStringReference& stringRef); + + std::vector<StringUpdateEvent> getQueuedStringUpdates(); + +public: + StringsListModel(QWidget* parent, BinaryViewRef data); + virtual ~StringsListModel(); + + 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; + + BNStringReference getStringAt(const QModelIndex& i); + QModelIndex findString(const BNStringReference& ref); + + virtual void OnStringFound(BinaryNinja::BinaryView* data, BNStringType type, uint64_t offset, size_t len) override; + virtual void OnStringRemoved(BinaryNinja::BinaryView* data, BNStringType type, uint64_t offset, size_t len) override; + void updateStrings(); + + void setFilter(const std::string& filter); +}; + +class BINARYNINJAUIAPI StringItemDelegate: public QStyledItemDelegate +{ + Q_OBJECT + + QWidget* m_owner; + QFont m_font; + int m_baseline, m_charWidth, m_charHeight, m_charOffset; + + void initFont(); + +public: + StringItemDelegate(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; + QFont getFont() const { return m_font; } +}; + +class StringsContainer; + +class BINARYNINJAUIAPI StringsView: public QListView, public View, public FilterTarget +{ + Q_OBJECT + + BinaryViewRef m_data; + ViewFrame* m_view; + StringsContainer* m_container; + + StringsListModel* m_list; + StringItemDelegate* m_itemDelegate; + QTimer* m_updateTimer; + + uint64_t m_selectionBegin, m_selectionEnd; + +public: + StringsView(BinaryViewRef data, ViewFrame* view, StringsContainer* container); + + virtual BinaryViewRef getData() override { return m_data; } + virtual uint64_t getCurrentOffset() override; + virtual void getSelectionOffsets(uint64_t& begin, uint64_t& end) override; + virtual bool navigate(uint64_t offset) override; + + virtual void updateFonts() override; + + virtual StatusBarWidget* getStatusBarWidget() override; + + virtual void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) override; + + virtual void setFilter(const std::string& filter) override; + virtual void scrollToFirstItem() override; + virtual void scrollToCurrentItem() override; + virtual void selectFirstItem() override; + virtual void activateFirstItem() override; + virtual QFont getFont() override { return m_itemDelegate->getFont(); } +protected: + virtual void keyPressEvent(QKeyEvent* event) override; + +private Q_SLOTS: + void goToString(const QModelIndex& idx); + void updateTimerEvent(); +}; + +class BINARYNINJAUIAPI StringsContainer: public QWidget, public ViewContainer +{ + Q_OBJECT + + ViewFrame* m_view; + StringsView* m_strings; + FilteredView* m_filter; + +public: + StringsContainer(BinaryViewRef data, ViewFrame* view); + virtual View* getView() override { return m_strings; } + + StringsView* getStringsView() { return m_strings; } + FilteredView* getFilter() { return m_filter; } + +protected: + virtual void focusInEvent(QFocusEvent* event) override; +}; + +class StringsViewType: public ViewType +{ + static StringsViewType* m_instance; + +public: + StringsViewType(); + virtual int getPriority(BinaryViewRef data, const QString& filename); + virtual QWidget* create(BinaryViewRef data, ViewFrame* viewFrame); + static void init(); +}; diff --git a/ui/textdialog.h b/ui/textdialog.h new file mode 100644 index 00000000..b9771cc0 --- /dev/null +++ b/ui/textdialog.h @@ -0,0 +1,28 @@ +#pragma once + +#include <QtWidgets/QDialog> +#include "binaryninjaapi.h" +#include "uitypes.h" + +class BINARYNINJAUIAPI TextDialog: public QDialog +{ + Q_OBJECT + QWidget* m_parent; + QString m_title; + QString m_msg; + QStringList m_options; + Qt::WindowFlags m_flags; + QString m_qSettingsListName; + int m_historySize; + QString m_historyEntry; + QString m_initialText; + +public: + TextDialog(QWidget* parent, const QString& title, const QString& msg, const QString& qSettingsListName, + const std::string& initialText = ""); + TextDialog(QWidget* parent, const QString& title, const QString& msg, const QString& qSettingsListName, + const QString& initialText); + QString getItem(bool& ok); + void setInitialText(const std::string& initialText) { m_initialText = QString::fromStdString(initialText); } + void commitHistory(); +};
\ No newline at end of file diff --git a/ui/theme.h b/ui/theme.h new file mode 100644 index 00000000..8cebf40d --- /dev/null +++ b/ui/theme.h @@ -0,0 +1,119 @@ +#pragma once + +#include <QtGui/QPalette> +#include <QtWidgets/QProxyStyle> +#include <vector> +#include "binaryninjaapi.h" +#include "uicontext.h" + +class BINARYNINJAUIAPI CustomFusionStyle: public QProxyStyle +{ +public: + CustomFusionStyle(QStyle* parent); + virtual int pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget) const override; + virtual QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption* option, + const QWidget* widget) const override; + virtual QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption* option, + const QWidget* widget) const override; +}; + +enum ThemeColor +{ + // Hex dump colors + AddressColor, + ModifiedColor, + InsertedColor, + NotPresentColor, + SelectionColor, + OutlineColor, + BackgroundHighlightDarkColor, + BackgroundHighlightLightColor, + BoldBackgroundHighlightDarkColor, + BoldBackgroundHighlightLightColor, + AlphanumericHighlightColor, + PrintableHighlightColor, + + // Graph colors + GraphBackgroundDarkColor, + GraphBackgroundLightColor, + GraphNodeDarkColor, + GraphNodeLightColor, + GraphNodeOutlineColor, + TrueBranchColor, + FalseBranchColor, + UnconditionalBranchColor, + AltTrueBranchColor, + AltFalseBranchColor, + AltUnconditionalBranchColor, + + // Disassembly colors + RegisterColor, + NumberColor, + CodeSymbolColor, + DataSymbolColor, + StackVariableColor, + ImportColor, + InstructionHighlightColor, + TokenHighlightColor, + AnnotationColor, + OpcodeColor, + LinearDisassemblyFunctionHeaderColor, + LinearDisassemblyBlockColor, + LinearDisassemblyNoteColor, + LinearDisassemblySeparatorColor, + StringColor, + TypeNameColor, + FieldNameColor, + KeywordColor, + UncertainColor, + NameSpaceColor, + NameSpaceSeparatorColor, + + // Script console colors + ScriptConsoleOutputColor, + ScriptConsoleErrorColor, + ScriptConsoleEchoColor, + + // Highlighting colors + BlueStandardHighlightColor, + GreenStandardHighlightColor, + CyanStandardHighlightColor, + RedStandardHighlightColor, + MagentaStandardHighlightColor, + YellowStandardHighlightColor, + OrangeStandardHighlightColor, + WhiteStandardHighlightColor, + BlackStandardHighlightColor, + + // MiniGraph + MiniGraphOverlayColor, + + // FeatureMap + FeatureMapBaseColor, + FeatureMapNavLineColor, + FeatureMapNavHighlightColor, + FeatureMapDataVariableColor, + FeatureMapAsciiStringColor, + FeatureMapUnicodeStringColor, + FeatureMapFunctionColor, + FeatureMapImportColor, + FeatureMapExternColor +}; + +void BINARYNINJAUIAPI initThemes(); +void BINARYNINJAUIAPI resetUserThemes(); +void BINARYNINJAUIAPI refreshUserThemes(); +std::vector<QString> BINARYNINJAUIAPI getAvailableThemes(); +QString BINARYNINJAUIAPI getActiveTheme(); +void BINARYNINJAUIAPI setActiveTheme(const QString& name, bool saveToSettings = true); + +bool BINARYNINJAUIAPI isColorBlindMode(); +void BINARYNINJAUIAPI setColorBlindMode(bool active); + +QColor BINARYNINJAUIAPI getThemeColor(ThemeColor color); +QColor BINARYNINJAUIAPI getTokenColor(QWidget* widget, BNInstructionTextTokenType token); + +QColor BINARYNINJAUIAPI avgColor(QColor a, QColor b); +QColor BINARYNINJAUIAPI mixColor(QColor a, QColor b, uint8_t mix); + +QColor BINARYNINJAUIAPI getThemeHighlightColor(BNHighlightStandardColor color); diff --git a/ui/transformparam.h b/ui/transformparam.h new file mode 100644 index 00000000..042a38c3 --- /dev/null +++ b/ui/transformparam.h @@ -0,0 +1,18 @@ +#pragma once + +#include <QtWidgets/QDialog> +#include "binaryninjaapi.h" +#include "uicontext.h" + +class BINARYNINJAUIAPI TransformParameterDialog: public QDialog +{ + Q_OBJECT + + std::vector<BinaryNinja::TransformParameter> m_params; + std::map<std::string, BinaryDataRef> m_paramData; + +public: + TransformParameterDialog(QWidget* parent, TransformRef xform, + const std::vector<BinaryNinja::TransformParameter>& params); + std::map<std::string, BinaryNinja::DataBuffer> getParameterData(); +}; diff --git a/ui/typeview.h b/ui/typeview.h new file mode 100644 index 00000000..558954ee --- /dev/null +++ b/ui/typeview.h @@ -0,0 +1,253 @@ +#pragma once + +#include <QtWidgets/QAbstractScrollArea> +#include <QtWidgets/QAction> +#include <QtCore/QTimer> +#include <string> +#include <utility> +#include <vector> +#include "binaryninjaapi.h" +#include "viewframe.h" +#include "render.h" +#include "menus.h" + +#define TYPE_VIEW_UPDATE_CHECK_INTERVAL 200 + +class BINARYNINJAUIAPI TypeViewHistoryEntry: public HistoryEntry +{ + BinaryNinja::QualifiedName m_cursorType; + size_t m_cursorLine; + size_t m_cursorOffset; + bool m_selectionValid; + std::string m_selectionStartType; + size_t m_selectionStartLine; + size_t m_selectionStartOffset; + HighlightTokenState m_highlight; + +public: + const BinaryNinja::QualifiedName& getCursorType() const { return m_cursorType; } + size_t getCursorLine() const { return m_cursorLine; } + size_t getCursorOffset() const { return m_cursorOffset; } + + bool isSelectionValid() const { return m_selectionValid; } + const std::string& getSelectionStartType() const { return m_selectionStartType; } + size_t getSelectionStartLine() const { return m_selectionStartLine; } + size_t getSelectionStartOffset() const { return m_selectionStartOffset; } + + const HighlightTokenState& getHighlightTokenState() const { return m_highlight; } + + void setCursorType(const BinaryNinja::QualifiedName& type) { m_cursorType = type; } + void setCursorLine(size_t line) { m_cursorLine = line; } + void setCursorOffset(size_t offset) { m_cursorOffset = offset; } + + void setSelectionValid(bool valid) { m_selectionValid = valid; } + void setSelectionStartType(const std::string& type) { m_selectionStartType = type; } + void setSelectionStartLine(size_t line) { m_selectionStartLine = line; } + void setSelectionStartOffset(size_t offset) { m_selectionStartOffset = offset; } + + void setHighlightTokenState(const HighlightTokenState& state) { m_highlight = state; } +}; + +class BINARYNINJAUIAPI TypeView: public QAbstractScrollArea, public View, public BinaryNinja::BinaryDataNotification +{ + Q_OBJECT + + enum TypeDefinitionLineType + { + TypedefLineType, + StructDefinitionLineType, + StructFieldLineType, + StructDefinitionEndLineType, + EnumDefinitionLineType, + EnumMemberLineType, + EnumDefinitionEndLineType, + PaddingLineType + }; + + struct TypeDefinitionLine + { + TypeDefinitionLineType lineType; + std::vector<BinaryNinja::InstructionTextToken> tokens; + TypeRef type, rootType; + uint64_t offset; + size_t fieldIndex; + }; + + struct TypeLineIndex + { + BinaryNinja::QualifiedName name; + int line, end; + }; + + BinaryViewRef m_data; + ViewFrame* m_view; + + RenderContext m_render; + QWidget* m_lineNumberArea; + int m_lineNumberAreaWidth = 0; + int m_lineCount = 0; + int m_cols, m_rows, m_paddingCols; + uint64_t m_maxOffset; + size_t m_offsetWidth; + HighlightTokenState m_highlight; + BinaryNinja::QualifiedName m_cursorType; + size_t m_cursorTypeIndex; + size_t m_cursorLine; + size_t m_cursorOffset; + std::string m_navigationMode = "TypeNavigation"; + + bool m_selectionValid; + size_t m_selectionStartTypeIndex; + size_t m_selectionStartLine; + size_t m_selectionStartOffset; + bool m_leftButtonDown; + + std::map<BinaryNinja::QualifiedName, std::vector<TypeDefinitionLine>> m_typeLines; + std::vector<TypeLineIndex> m_types; + + bool m_updatesRequired; + QTimer* m_updateTimer; + + Qt::KeyboardModifiers m_ctrl, m_command; + + ContextMenuManager m_contextMenuManager; + QAction* m_actionCopy; + QAction* m_actionSelectAll; + + void adjustSize(int width, int height); + + std::vector<TypeDefinitionLine> getLinesForType(const std::string& name, const std::string& varName, size_t index, + TypeRef type, TypeRef parent); + void refreshAllTypes(); + void ensureCursorVisible(); + void focusOnCursor(); + + void changeToSpecificType(TypeRef type); + bool canCreateMembersInSelectedRegion(); + void createMembersInSelectedRegion(TypeRef type); + void deleteMembersInSelectedRegion(); + + void moveUp(bool selecting); + void moveDown(bool selecting); + void moveLeft(size_t count, bool selecting); + void moveRight(size_t count, bool selecting); + void pageUp(bool selecting); + void pageDown(bool selecting); + void setCursorAbsoluteLine(size_t line); + void moveToStartOfLine(bool selecting); + void moveToEndOfLine(bool selecting); + void moveToStartOfView(bool selecting); + void moveToEndOfView(bool selecting); + void goToAddress(bool selecting); + + void moveCursorToMouse(QMouseEvent* event, bool selecting); + void createNewTypes(const QString& definition = ""); + void bindActions(); + + void checkForValidSelection(); + +public: + explicit TypeView(BinaryViewRef data, ViewFrame* view); + virtual ~TypeView(); + + virtual bool findNextData(uint64_t start, uint64_t end, const BinaryNinja::DataBuffer& data, uint64_t& addr, BNFindFlag flags, + const std::function<bool (size_t current, size_t total)>& cb) override; + virtual bool findNextText(uint64_t start, uint64_t end, const std::string& text, uint64_t& addr, + DisassemblySettingsRef settings, BNFindFlag flags, + const std::function<bool (size_t current, size_t total)>& cb) override; + virtual BinaryViewRef getData() override { return m_data; } + virtual uint64_t getCurrentOffset() override; + virtual void getSelectionOffsets(uint64_t& begin, uint64_t& end) override; + virtual bool navigate(uint64_t) override; + + virtual std::string getNavigationMode() override; + virtual void setNavigationMode(std::string mode) override; + virtual std::vector<std::string> getNavigationModes() override; + + bool navigateToType(const std::string& name); + + virtual void OnTypeDefined(BinaryNinja::BinaryView* view, const BinaryNinja::QualifiedName& name, + BinaryNinja::Type* type) override; + virtual void OnTypeUndefined(BinaryNinja::BinaryView* view, const BinaryNinja::QualifiedName& name, + BinaryNinja::Type* type) override; + + virtual void updateFonts() override; + + virtual StatusBarWidget* getStatusBarWidget() override; + + virtual HistoryEntry* getHistoryEntry() override; + virtual void navigateToHistoryEntry(HistoryEntry* entry) override; + + void lineNumberAreaPaintEvent(QPaintEvent *event); + int lineNumberAreaWidth(); + + virtual bool canCut() override { return false; } + virtual bool canCopy() override; + virtual bool canCopyWithTransform() override { return false; } + virtual bool canPaste() override { return false; } + virtual bool canPasteWithTransform() override { return false; } + virtual bool canTransform() override { return false; } + virtual bool canCopyAddress() override { return false; } + + virtual void copy(TransformRef xform = nullptr) override; + virtual QFont getFont() override { return m_render.getFont(); } + + virtual HighlightTokenState getHighlightTokenState() override { return m_highlight; } + + static void registerActions(); + +protected: + virtual void resizeEvent(QResizeEvent* event) override; + virtual void paintEvent(QPaintEvent* event) override; + virtual void mousePressEvent(QMouseEvent* event) override; + virtual void mouseMoveEvent(QMouseEvent* event) override; + virtual void mouseReleaseEvent(QMouseEvent* event) override; + virtual void mouseDoubleClickEvent(QMouseEvent* event) override; + virtual void scrollContentsBy(int dx, int dy) override; + +private Q_SLOTS: + void copySelection(); + void selectAll(); + void updateTimerEvent(); + void defineName(); + void undefine(); + void changeType(); + void makeInt8(); + void makeInt16(); + void makeInt32(); + void makeInt64(); + void makePtr(); + void makeString(); + void makeArray(); + void newTypes(); + void createStructure(); + void createUnion(); + void setStructureSize(); + void updateLineNumberAreaWidth(size_t lineCount); +}; + + +class BINARYNINJAUIAPI LineNumberArea : public QWidget +{ +public: + LineNumberArea(TypeView *editor) : QWidget(editor), m_typeEditor(editor) { } + + QSize sizeHint() const override { return QSize(m_typeEditor->lineNumberAreaWidth(), 0); } + +protected: + void paintEvent(QPaintEvent *event) override { m_typeEditor->lineNumberAreaPaintEvent(event); } + +private: + TypeView* m_typeEditor; +}; + +class TypeViewType: public ViewType +{ + static TypeViewType* m_instance; + +public: + TypeViewType(); + virtual int getPriority(BinaryViewRef data, const QString& filename) override; + virtual QWidget* create(BinaryViewRef data, ViewFrame* viewFrame) override; + static void init(); +}; diff --git a/ui/uicontext.h b/ui/uicontext.h new file mode 100644 index 00000000..e65a603f --- /dev/null +++ b/ui/uicontext.h @@ -0,0 +1,76 @@ +#pragma once + +#include <QtWidgets/QWidget> +#include <QtCore/QMetaType> +#include <QtWidgets/QMainWindow> +#include <QtGui/QWheelEvent> +#include "binaryninjaapi.h" +#include "action.h" +#include "preview.h" + +#define PREVIEW_HOVER_TIME 500 + +typedef bool (*UIPluginInitFunction)(void); +typedef void (*UIPluginDependencyFunction)(void); + +class ViewFrame; +class UIActionHandler; +class FileContext; + +class BINARYNINJAUIAPI UIContextHandler +{ +public: + virtual ~UIContextHandler(); + virtual void updateStatus(bool updateInfo) = 0; + virtual void notifyThemeChanged() = 0; +}; + +class BINARYNINJAUIAPI UIContext +{ + static UIContextHandler* m_handler; + static std::set<UIContext*> m_contexts; + UIActionHandler m_globalActions; + + static QPointer<PreviewWidget> m_currentPreview; + +protected: + void setupUIContext(QWidget* obj); + +public: + UIContext(); + virtual ~UIContext(); + + virtual QMainWindow* mainWindow() = 0; + virtual void viewChanged(ViewFrame* frame, const QString& type); + virtual bool navigateForBinaryView(BinaryViewRef view, uint64_t addr); + virtual void createTabForWidget(const QString& name, QWidget* widget) = 0; + virtual bool openFilename(const QString& path, bool openOptions = false); + virtual ViewFrame* openFileContext(FileContext* file, const QString& forcedView = "", bool addTab = true); + + UIActionHandler* globalActions() { return &m_globalActions; } + virtual UIActionHandler* contentActionHandler() = 0; + + static void setHandler(UIContextHandler* handler); + + static QSize getScaledWindowSize(int x, int y); + static void updateStatus(bool updateInfo = true); + static void notifyThemeChanged(); + static void showPreview(QWidget* parent, PreviewWidget* preview, QPoint localPos); + static void closePreview(); + static bool sendPreviewWheelEvent(QWheelEvent* event); + static void closeOtherActiveModalWidget(QWidget* current); + + static UIContext* contextForWidget(QWidget* widget); + static UIContext* activeContext(); + static std::set<UIContext*> allContexts(); +}; + +Q_DECLARE_METATYPE(UIContext*) + +void BINARYNINJAUIAPI InitUIViews(); +void BINARYNINJAUIAPI InitUIActions(); + +void BINARYNINJAUIAPI InitUIPlugins(); +void BINARYNINJAUIAPI SetCurrentUIPluginLoadOrder(BNPluginLoadOrder order); +void BINARYNINJAUIAPI AddRequiredUIPluginDependency(const std::string& name); +void BINARYNINJAUIAPI AddOptionalUIPluginDependency(const std::string& name); diff --git a/ui/uitypes.h b/ui/uitypes.h new file mode 100644 index 00000000..1ebdc373 --- /dev/null +++ b/ui/uitypes.h @@ -0,0 +1,56 @@ +#pragma once + +#include "binaryninjaapi.h" + +#ifdef __GNUC__ +# ifdef BINARYNINJAUI_LIBRARY +# define BINARYNINJAUIAPI __attribute__((visibility("default"))) +# else +# define BINARYNINJAUIAPI +# endif +#else +#ifdef _MSC_VER +# ifdef BINARYNINJAUI_LIBRARY +# define BINARYNINJAUIAPI __declspec(dllexport) +# else +# define BINARYNINJAUIAPI __declspec(dllimport) +# endif +#else +#define BINARYNINJAUIAPI +#endif +#endif + +#ifdef BINARYNINJAUI_PYTHON_BINDINGS +#include "bindings.h" +#endif + +// The Python bindings generator does not recognize automatic conversion of API types into their +// Python equivalents if using templates (Ref<*>), so we typedef all API references so that +// the Python bindings can be easily generated for them. +typedef BinaryNinja::Ref<BinaryNinja::Architecture> ArchitectureRef; +typedef BinaryNinja::Ref<BinaryNinja::BackgroundTask> BackgroundTaskRef; +typedef BinaryNinja::Ref<BinaryNinja::BasicBlock> BasicBlockRef; +typedef BinaryNinja::Ref<BinaryNinja::BinaryData> BinaryDataRef; +typedef BinaryNinja::Ref<BinaryNinja::BinaryView> BinaryViewRef; +typedef BinaryNinja::Ref<BinaryNinja::BinaryViewType> BinaryViewTypeRef; +typedef BinaryNinja::Ref<BinaryNinja::DisassemblySettings> DisassemblySettingsRef; +typedef BinaryNinja::Ref<BinaryNinja::DownloadProvider> DownloadProviderRef; +typedef BinaryNinja::Ref<BinaryNinja::FileMetadata> FileMetadataRef; +typedef BinaryNinja::Ref<BinaryNinja::FlowGraph> FlowGraphRef; +typedef BinaryNinja::Ref<BinaryNinja::FlowGraphLayoutRequest> FlowGraphLayoutRequestRef; +typedef BinaryNinja::Ref<BinaryNinja::FlowGraphNode> FlowGraphNodeRef; +typedef BinaryNinja::Ref<BinaryNinja::Function> FunctionRef; +typedef BinaryNinja::Ref<BinaryNinja::LowLevelILFunction> LowLevelILFunctionRef; +typedef BinaryNinja::Ref<BinaryNinja::MainThreadAction> MainThreadActionRef; +typedef BinaryNinja::Ref<BinaryNinja::MediumLevelILFunction> MediumLevelILFunctionRef; +typedef BinaryNinja::Ref<BinaryNinja::Platform> PlatformRef; +typedef BinaryNinja::Ref<BinaryNinja::ReportCollection> ReportCollectionRef; +typedef BinaryNinja::Ref<BinaryNinja::ScriptingInstance> ScriptingInstanceRef; +typedef BinaryNinja::Ref<BinaryNinja::ScriptingProvider> ScriptingProviderRef; +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::TemporaryFile> TemporaryFileRef; +typedef BinaryNinja::Ref<BinaryNinja::Transform> TransformRef; +typedef BinaryNinja::Ref<BinaryNinja::Type> TypeRef; diff --git a/ui/viewframe.h b/ui/viewframe.h new file mode 100644 index 00000000..402c95c9 --- /dev/null +++ b/ui/viewframe.h @@ -0,0 +1,262 @@ +#pragma once + +#include <QtWidgets/QAction> +#include <QtWidgets/QGestureEvent> +#include <QtWidgets/QLabel> +#include <QtCore/QPointer> +#include <QtWidgets/QVBoxLayout> +#include <QtWidgets/QWidget> +#include <map> +#include <stack> +#include <utility> +#include <vector> +#include "filecontext.h" +#include "viewtype.h" +#include "action.h" + +class BINARYNINJAUIAPI HistoryEntry: public BinaryNinja::RefCountObject +{ + QString m_viewType; + +public: + virtual ~HistoryEntry() {} + + QString getViewType() const { return m_viewType; } + void setViewType(const QString& type) { m_viewType = type; } +}; + +class AssembleDialog; +class CompileDialog; +class FeatureMap; +class StatusBarWidget; +class ViewNavigationMode; + +class BINARYNINJAUIAPI View +{ +protected: + Menu m_contextMenu; + UIActionHandler m_actionHandler; + + bool writeDataToClipboard(const BinaryNinja::DataBuffer& data, bool binary, TransformRef xform); + BinaryNinja::DataBuffer readDataFromClipboard(TransformRef xform); + + // FIXME: Support for typeview, where the default navigation mode is not compatible with the navigation interface + // The view concept and navigation interface needs to be revisited at some point + // New interface/design should be pushed to NavigationHandler and through API + // The empty string is global navigation (inside view) by default, allows offset to be interpreted by mode + friend class ViewNavigationMode; + virtual std::string getNavigationMode() { return ""; } + virtual void setNavigationMode(std::string mode) { (void)mode; } + virtual std::vector<std::string> getNavigationModes() { return {}; } + +public: + View(); + virtual ~View() {} + + void setupView(QWidget* widget); + + virtual bool canAssemble() { return false; } + virtual bool canCompile() { return false; } + + virtual bool findNextData(uint64_t start, uint64_t end, const BinaryNinja::DataBuffer& data, uint64_t& addr, BNFindFlag flags, + const std::function<bool (size_t current, size_t total)>& cb); + virtual bool findNextText(uint64_t start, uint64_t end, const std::string& text, uint64_t& addr, + DisassemblySettingsRef settings, BNFindFlag flags, + const std::function<bool (size_t current, size_t total)>& cb); + virtual bool findNextConstant(uint64_t start, uint64_t end, uint64_t constant, uint64_t& addr, DisassemblySettingsRef settings, + const std::function<bool (size_t current, size_t total)>& cb); + + virtual BinaryViewRef getData() = 0; + virtual uint64_t getCurrentOffset() = 0; + virtual void getSelectionOffsets(uint64_t& begin, uint64_t& end); + virtual void getSelectionForInfo(uint64_t& begin, uint64_t& end); + virtual bool navigate(uint64_t offset) = 0; + virtual bool navigateToFunction(FunctionRef func, uint64_t offset); + virtual bool goToReference(FunctionRef func, uint64_t source, uint64_t target); + + virtual bool closeRequest() { return true; } + virtual void closing() {} + virtual void updateFonts() {} + + virtual void undo(); + virtual void redo(); + virtual bool canUndo(); + virtual bool canRedo(); + + virtual void cut(); + virtual void copy(TransformRef xform = nullptr); + virtual void copyAddress(); + virtual void paste(TransformRef xform = nullptr); + virtual bool canCut(); + virtual bool canCopy(); + virtual bool canCopyWithTransform(); + virtual bool canCopyAddress(); + virtual bool canPaste(); + virtual bool canPasteWithTransform(); + + virtual void transform(TransformRef xform, bool encode); + virtual bool canTransform(); + + virtual void writeData(const BinaryNinja::DataBuffer& data); + + virtual bool canDisplayAs(const UIActionContext& context); + virtual void displayAs(const UIActionContext& context, BNIntegerDisplayType type); + + virtual HistoryEntry* getHistoryEntry(); + virtual void navigateToHistoryEntry(HistoryEntry* entry); + + virtual StatusBarWidget* getStatusBarWidget() { return nullptr; } + + static View* getViewFromWidget(QWidget* widget); + + virtual FunctionRef getCurrentFunction() { return nullptr; } + virtual BasicBlockRef getCurrentBasicBlock() { return nullptr; } + virtual ArchitectureRef getCurrentArchitecture() { return nullptr; } + + virtual LowLevelILFunctionRef getCurrentLowLevelILFunction() { return nullptr; } + virtual MediumLevelILFunctionRef getCurrentMediumLevelILFunction() { return nullptr; } + virtual size_t getCurrentILInstructionIndex() { return BN_INVALID_EXPR; } + + virtual QFont getFont() = 0; + DisassemblySettingsRef getDisassemblySettings(); + + virtual HighlightTokenState getHighlightTokenState(); + + virtual UIActionContext actionContext(); + Menu& contextMenu() { return m_contextMenu; } + UIActionHandler* actionHandler() { return &m_actionHandler; } + QWidget* widget() { return m_actionHandler.widget(); } + + static void registerActions(); +}; + + +class BINARYNINJAUIAPI ViewNavigationMode +{ + View* m_view; + std::string m_mode; + + ViewNavigationMode(); + +public: + ViewNavigationMode(View* view, std::string mode) : m_view(view) { m_mode = m_view->getNavigationMode(); m_view->setNavigationMode(mode); } + ~ViewNavigationMode() { m_view->setNavigationMode(m_mode); } +}; + +class BINARYNINJAUIAPI ViewContainer +{ +public: + virtual ~ViewContainer() {} + virtual View* getView() = 0; +}; + +class FunctionsView; + +class BINARYNINJAUIAPI ViewFrame : public QWidget +{ + Q_OBJECT + +private: + QWidget* createView(const QString& typeName, ViewType* type, BinaryViewRef data); + HistoryEntry* getHistoryEntry(); + + FileContext* m_context; + BinaryViewRef m_data; + QWidget* m_view; + QWidget* m_viewContainer; + QVBoxLayout* m_viewLayout; + std::map<QString, QPointer<QWidget>> m_extendedViewCache; + std::map<QString, QWidget*> m_viewCache; + std::stack<BinaryNinja::Ref<HistoryEntry>> m_back, m_forward; + bool m_graphViewPreferred = false; + std::vector<QString> m_viewTypePriority; + + FunctionsView* m_funcs = nullptr; + FeatureMap* m_featureMap = nullptr; + + UIActionHandler m_actionHandler; + +protected: + QPointer<CompileDialog> compileDialog; + + bool event(QEvent* event) override; + virtual void mousePressEvent(QMouseEvent* event) override; + bool gestureEvent(QGestureEvent* event); + + void setView(QWidget* view); + +public: + explicit ViewFrame(QWidget* parent, FileContext* file, const QString& type, bool createExtendedViews = false); + virtual ~ViewFrame(); + + FileContext* getFileContext() const { return m_context; } + FunctionsView* getFunctionsView() const { return m_funcs; } + + QString getTabName(); + QString getShortFileName(); + std::vector<QString> getAvailableTypes() const; + + QString getCurrentView(); + QString getCurrentDataType(); + uint64_t getCurrentOffset(); + void getSelectionOffsets(uint64_t& begin, uint64_t& end); + + View* getCurrentViewInterface() const { return View::getViewFromWidget(m_view); } + QWidget* getCurrentWidget() const { return m_view; } + + bool setViewType(const QString& type); + bool isGraphViewPreferred() { return m_graphViewPreferred; } + void setGraphViewPreferred(bool graphViewPreferred) { m_graphViewPreferred = graphViewPreferred; } + void focus(); + void closeFeatureMap(); + QWidget* createFeatureMap(); + void refreshFeatureMap(); + + QWidget* getExtendedView(const QString& name, bool create = false); + + bool navigate(const QString& type, uint64_t offset, bool updateInfo = true); + bool navigate(const QString& type, const std::function<bool(View*)>& handler, bool updateInfo = true); + bool navigate(BinaryViewRef data, uint64_t offset, bool updateInfo = true); + bool navigateToFunction(FunctionRef func, uint64_t offset, bool updateInfo = true); + bool goToReference(BinaryViewRef data, FunctionRef func, uint64_t source, uint64_t target); + QString getTypeForView(QWidget* view); + QString getDataTypeForView(QWidget* view); + + bool closeRequest(); + void closing(); + + void updateFonts(); + void updateTheme(); + void addHistoryEntry(); + void back(); + void forward(); + + static bool getAddressFromString(QWidget* parent, BinaryViewRef data, uint64_t& offset, + uint64_t currentAddress, const QString& addrStr, std::string& errorString); + static bool getAddressFromInput(QWidget* parent, BinaryViewRef data, uint64_t& offset, + uint64_t currentAddress, const QString& title = "Go to Address", const QString& msg = "Address:"); + + void setCurrentFunction(FunctionRef func); + void updateFeatureMapLocation(View* view); + void updateCrossReferences(); + void showCrossReferences(); + + virtual UIActionContext actionContext(); + void bindActions(); + static void registerActions(); + + static ViewFrame* viewFrameForWidget(QWidget* widget); + +public Q_SLOTS: + virtual void assemble(); + virtual void compile(); + +private Q_SLOTS: + void deleteFeatureMap(); + +Q_SIGNALS: + void notifyCloseFeatureMap(); + void nofifyViewChanged(ViewFrame* frame); +}; + +Q_DECLARE_METATYPE(View*) diff --git a/ui/viewtype.h b/ui/viewtype.h new file mode 100644 index 00000000..2216b9dd --- /dev/null +++ b/ui/viewtype.h @@ -0,0 +1,40 @@ +#pragma once + +#include <QtCore/QString> +#include <QtWidgets/QWidget> +#include <vector> +#include "binaryninjaapi.h" +#include "uicontext.h" + +class ViewFrame; + +class BINARYNINJAUIAPI ViewType +{ + QString m_name, m_longName; + +public: + ViewType(const QString& name, const QString& longName); + virtual ~ViewType(); + + const QString& getName() { return m_name; } + const QString& getLongName() { return m_longName; } + virtual int getPriority(BinaryViewRef data, const QString& filename) = 0; + virtual QWidget* create(BinaryViewRef data, ViewFrame* viewFrame) = 0; + + virtual QString getDisplayName(BinaryViewTypeRef type); + virtual QString getDisplayLongName(BinaryViewTypeRef type); + + static ViewType* getTypeByName(const QString& name); + static const std::vector<ViewType*>& getTypes(); + + static void registerViewType(ViewType* type); +}; + + +class BINARYNINJAUIAPI ViewTypeContainer +{ +public: + std::vector<ViewType*> m_types; + + static ViewTypeContainer& GetViewTypeContainer(); +}; diff --git a/ui/xreflist.h b/ui/xreflist.h new file mode 100644 index 00000000..961e1238 --- /dev/null +++ b/ui/xreflist.h @@ -0,0 +1,87 @@ +#pragma once + +#include <QtCore/QAbstractItemModel> +#include <QtCore/QItemSelectionModel> +#include <QtWidgets/QListView> +#include <QtWidgets/QStyledItemDelegate> +#include "binaryninjaapi.h" +#include "dockhandler.h" +#include "viewframe.h" + + +class BINARYNINJAUIAPI CrossReferenceListModel: public QAbstractItemModel +{ + Q_OBJECT + + QWidget* m_owner; + BinaryViewRef m_data; + std::vector<BinaryNinja::ReferenceSource> m_refs; + +public: + CrossReferenceListModel(QWidget* parent, BinaryViewRef data); + + 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; + + bool setModelData(const std::vector<BinaryNinja::ReferenceSource>& refs, QItemSelectionModel* selectionModel, bool& selectionUpdated); +}; + + +class BINARYNINJAUIAPI CrossReferenceItemDelegate: public QStyledItemDelegate +{ + Q_OBJECT + + QFont m_font; + int m_baseline, m_charWidth, m_charHeight, m_charOffset; + + void initFont(); + +public: + CrossReferenceItemDelegate(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 CrossReferenceList: public QListView, public DockContextHandler +{ + Q_OBJECT + + ViewFrame* m_view; + CrossReferenceListModel* m_list; + CrossReferenceItemDelegate* m_itemDelegate; + BinaryViewRef m_data; + + QTimer* m_hoverTimer; + QPoint m_hoverPos; + + uint64_t m_curRefTarget = 0; + +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 bool shouldBeVisible(ViewFrame* frame) override; + virtual void updateFonts() override; + virtual void wheelEvent(QWheelEvent* e) override; + +private Q_SLOTS: + void goToReference(const QModelIndex& idx); + void hoverTimerEvent(); + +public: + CrossReferenceList(ViewFrame* view, BinaryViewRef data); + virtual ~CrossReferenceList(); + + void setCurrentSelection(uint64_t begin, uint64_t end); + + bool hasSelection(); +}; |
