summaryrefslogtreecommitdiff
path: root/ui/flowgraphwidget.h
blob: a519ed97afdafea722ec41cf107e9ecceca4d0b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
#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;
		size_t tokenIndex;
	};

	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;
	bool m_mouseSelectMode = false;

	FlowGraphNodeRef m_selectedNode, m_selectedEdgeSource;
	bool m_selectedEdgeIncoming = false;
	std::map<FlowGraphNodeRef, FlowGraphNodeRef> m_selectedEdgeIncomingPriority, m_selectedEdgeOutgoingPriority;
	BinaryNinja::FlowGraphEdge m_selectedEdge;
	CursorPosition m_cursorPos, m_selectionStartPos;
	HighlightTokenState m_highlight;
	bool m_tokenSelection = false;

	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;

	FlowGraphRef m_recenterWithGraph;
	int m_recenterXofs, m_recenterYofs;

	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);
	bool getEdgeForMouseEvent(QMouseEvent* event, FlowGraphNodeRef& source,
		BinaryNinja::FlowGraphEdge& edge, bool& incoming);
	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,
		bool recenterWithPreviousGraph);

	void up(bool selecting, size_t count = 1);
	void down(bool selecting, size_t count = 1);
	void left(bool selecting);
	void right(bool selecting);
	void leftToSymbol(bool selecting);
	void rightToSymbol(bool selecting);
	void pageUp(bool selecting);
	void pageDown(bool selecting);
	void moveToStartOfLine(bool selecting);
	void moveToEndOfLine(bool selecting);
	void moveToStartOfView();
	void moveToEndOfView();
	void selectAll();
	void selectNone();
	void navigateToHighlightedToken();

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;
	virtual void OnDataMetadataUpdated(BinaryNinja::BinaryView* data, uint64_t offset) 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 setRelatedGraph(FlowGraphRef graph);
	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 ensureCursorVisible();

	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 notifyUpdateInProgress(FunctionRef func);
	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 addUserXref();
	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();
};