]> git.siccegge.de Git - frida/frida.git/blob - src/gui/Mainwindow.cxx
Properly move Functionality into FunctionWidget
[frida/frida.git] / src / gui / Mainwindow.cxx
1 #include "Mainwindow.hxx"
2 #include "qt.hxx"
3 #include "bindings/Guile.hxx"
4 #include "disassembler/llvm/LLVMDisassembler.hxx"
5 #include "core/Function.hxx"
6 #include "core/BasicBlock.hxx"
7 #include "core/InformationManager.hxx"
8 #include "core/events/RenameFunctionEvent.hxx"
9 #include "widgets/ScriptingDock.hxx"
10 #include "widgets/CFGScene.hxx"
11 #include "widgets/FunctionWidget.hxx"
12 #include "dialogs/NewFunctionDialog.hxx"
13 #include "dialogs/SimpleStringDialog.hxx"
14
15 #include <sstream>
16
17 Mainwindow::Mainwindow(InformationManager* mgr)
18 : manager(mgr)
19 , logger(log4cxx::Logger::getLogger("Mainwindow")) {
20 openAction = new QAction(tr("&Open"), this);
21 loadAction = new QAction(tr("&Load"), this);
22 saveAction = new QAction(tr("&Save"), this);
23 exitAction = new QAction(tr("E&xit"), this);
24
25 connect(openAction, &QAction::triggered,
26 this, &Mainwindow::open);
27 connect(loadAction, &QAction::triggered,
28 this, &Mainwindow::load);
29 connect(saveAction, &QAction::triggered,
30 this, &Mainwindow::save);
31 connect(exitAction, &QAction::triggered,
32 qApp, &QApplication::quit);
33
34 fileMenu = menuBar()->addMenu(tr("&File"));
35 fileMenu->addAction(openAction);
36 fileMenu->addAction(loadAction);
37 fileMenu->addAction(saveAction);
38 fileMenu->addSeparator();
39 fileMenu->addAction(exitAction);
40
41 QMenu* interpretermenu = menuBar()->addMenu(tr("&Interpreter"));
42
43 interpreter["GUILE"] = new GuileInterpreter;
44 scripting = new ScriptingDock(interpreter["GUILE"], tr("Scripting"), this);
45 scripting->setAllowedAreas(Qt::BottomDockWidgetArea);
46 addDockWidget(Qt::BottomDockWidgetArea, scripting);
47 QAction* guileLoad = new QAction(tr("&GUILE"), this);
48 interpretermenu->addAction(guileLoad);
49 connect(guileLoad, &QAction::triggered,
50 [&]() {
51 QString fileName = QFileDialog::getOpenFileName(this, tr("Open Script"), "",
52 tr("Binaries") + " (*." +
53 interpreter["GUILE"]->fileExtension().c_str() + ")");
54 std::stringstream a, b;
55 std::string c;
56 interpreter["GUILE"]->loadFile(fileName.toStdString(), a, b, c);
57 });
58
59 listWidget = new QTreeWidget();
60 listWidget->setColumnCount(1);
61 listWidget->setDragDropMode(QAbstractItemView::InternalMove);
62 listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
63 connect(listWidget, SIGNAL(customContextMenuRequested(const QPoint&)),
64 this, SLOT(showListContextMenu(const QPoint&)));
65
66 stackedWidget = new QStackedWidget();
67 dockWidget = new QDockWidget(tr("Functions"), this);
68 dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea |
69 Qt::RightDockWidgetArea);
70 dockWidget->setWidget(listWidget);
71 addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
72 setCentralWidget(stackedWidget);
73
74 connect(listWidget, &QTreeWidget::currentItemChanged,
75 [=] (QTreeWidgetItem* current, QTreeWidgetItem*) {
76 switchMainPlane(current);
77 });
78
79 setWindowTitle(tr("FRIDA"));
80
81 QTreeWidgetItem * external = new QTreeWidgetItem(listWidget, QStringList("External Functions"));
82 external->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
83 external->setBackground(0, QBrush(QColor(0xff, 0xdd, 0xdd)));
84 mgr->connect_new_function_signal([&] (Function* fun) {addFunction(fun);});
85 mgr->connect_new_dyn_symbol_signal([=] (const std::string& name) {
86 auto item = new QTreeWidgetItem(external, QStringList(name.c_str()));
87 item->setBackground(0, QBrush(QColor(0xff, 0xdd, 0xdd)));
88 });
89 mgr->connect_rename_function_signal([&](RenameFunctionEvent* event) {
90 if (objects_list_by_address.find(event->address) == objects_list_by_address.end())
91 return;
92 auto item = objects_list_by_address[event->address];
93 if (item) item->setText(0, event->new_name.c_str());
94 });
95 setGlobalHotkeys();
96 }
97
98 void Mainwindow::setGlobalHotkeys() {
99 QShortcut *shortcut = new QShortcut(QKeySequence("f"), this);
100 connect(shortcut, &QShortcut::activated, this, &Mainwindow::requestNewFunction);
101
102 shortcut = new QShortcut(QKeySequence("r"), listWidget);
103 connect(shortcut, &QShortcut::activated, [=]() {
104 QTreeWidgetItem * item = listWidget->currentItem();
105 if (item) renameFunction(objects_list[item]->getFunction());
106 });
107 }
108
109 void Mainwindow::quit()
110 {
111 QMessageBox messageBox;
112 messageBox.setWindowTitle(tr("Frida"));
113 messageBox.setText(tr("Do you really want to quit?"));
114 messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
115 messageBox.setDefaultButton(QMessageBox::No);
116 if (messageBox.exec() == QMessageBox::Yes)
117 qApp->quit();
118 }
119
120 void Mainwindow::open() {
121 QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "",
122 tr("Binaries (*)"));
123 manager->reset(fileName.toStdString());
124 }
125
126 void Mainwindow::load() {
127 QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "",
128 tr("Frida Archives (*.frida)"));
129 manager->load(fileName.toStdString());
130 }
131
132 void Mainwindow::save() {
133 QString filename = QFileDialog::getSaveFileName(this, tr("Save File"), "", tr("Frida Archives (*.frida)"));
134 manager->save(filename.toStdString());
135 }
136
137 void Mainwindow::switchMainPlaneToAddress(uint64_t address) {
138 if (objects_list_by_address.find(address) != objects_list_by_address.end()) {
139 LOG4CXX_DEBUG(logger, "Switching to function " << std::hex << address);
140 QTreeWidgetItem * item = objects_list_by_address[address];
141 listWidget->setCurrentItem(item);
142 stackedWidget->setCurrentWidget(objects_list[item]);
143 } else {
144 LOG4CXX_DEBUG(logger, "No function at " << std::hex << address
145 << " -- it's probably an imported Symbol");
146 }
147 }
148
149 void Mainwindow::switchMainPlane(QTreeWidgetItem* to) {
150 if (objects_list.end() != objects_list.find(to))
151 stackedWidget->setCurrentWidget(objects_list[to]);
152 }
153
154 void Mainwindow::showListContextMenu(const QPoint& point) {
155 QAction * act;
156 QTreeWidgetItem * item = listWidget->itemAt(point);
157 QMenu menu(this);
158
159 act = menu.addAction("Add Function");
160 connect(act, &QAction::triggered, this, &Mainwindow::requestNewFunction);
161
162 act = menu.addAction("Add Group");
163 connect(act, &QAction::triggered, this, &Mainwindow::requestNewGroup);
164
165 if (item) {
166 if (objects_list.find(item) != objects_list.end()) {
167 act = menu.addAction("Rename Function");
168 connect(act, &QAction::triggered, [=]() {this->renameFunction(objects_list[item]->getFunction());});
169 } else {
170 act = menu.addAction("Rename Group");
171 connect(act, &QAction::triggered, [=]() {renameGroup(item);});
172 }
173
174
175 QMenu* submenu = menu.addMenu("Move to group");
176
177 for (QTreeWidgetItem* groupitem : group_list) {
178 act = submenu->addAction(groupitem->text(0));
179 connect(act, &QAction::triggered,
180 [=] () {
181 listWidget->invisibleRootItem()->removeChild(item);
182 groupitem->addChild(item);
183 });
184 }
185 }
186
187 menu.exec(listWidget->mapToGlobal(point));
188 }
189
190 void Mainwindow::requestNewFunction() {
191 NewFunctionDialog dialog;
192 int result = dialog.exec();
193 if (QDialog::Accepted == result) {
194 requestNewFunctionByAddress(dialog.result());
195 } else {
196 LOG4CXX_DEBUG(logger, "requestNewFunction aborted");
197 }
198 }
199
200 void Mainwindow::requestNewGroup() {
201 SimpleStringDialog dialog("New Group");
202 int result = dialog.exec();
203 if (QDialog::Accepted == result) {
204 QTreeWidgetItem * external = new QTreeWidgetItem(listWidget, QStringList(dialog.result()));
205 external->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
206 group_list.push_back(external);
207 } else {
208 LOG4CXX_DEBUG(logger, "requestNewGroup aborted");
209 }
210 }
211
212 void Mainwindow::requestNewFunctionByAddress(uint64_t address) {
213 LOG4CXX_DEBUG(logger, "requesting Function at " << std::hex << address);
214 manager->getDisassembler()->disassembleFunctionAt(address);
215 switchMainPlaneToAddress(address);
216 }
217
218 void Mainwindow::renameFunction(Function* function) {
219 SimpleStringDialog dialog("New name");
220 int result = dialog.exec();
221 if (QDialog::Accepted == result) {
222 LOG4CXX_DEBUG(logger, "renaming Function " << function->getName()
223 << " to " << dialog.result().toStdString());
224 function->setName(dialog.result().toStdString());
225 } else {
226 LOG4CXX_DEBUG(logger, "renameFunction aborted");
227 }
228 }
229
230 void Mainwindow::renameGroup(QTreeWidgetItem* item) {
231 SimpleStringDialog dialog("New name");
232 int result = dialog.exec();
233 if (QDialog::Accepted == result) {
234 LOG4CXX_DEBUG(logger, "renaming group " << item->text(0).toStdString()
235 << " to " << dialog.result().toStdString());
236 item->setText(0, dialog.result());
237 } else {
238 LOG4CXX_DEBUG(logger, "renameFunction aborted");
239 }
240 }
241
242 void Mainwindow::addFunction(Function* fun) {
243 if (functions.find(fun->getStartAddress()) != functions.end())
244 return;
245
246 functions.insert(std::make_pair(fun->getStartAddress(), fun));
247
248 FunctionWidget * w = new FunctionWidget(fun, this);
249
250 QTreeWidgetItem * item = new QTreeWidgetItem(listWidget, QStringList(fun->getName().c_str()));
251 stackedWidget->addWidget(w);
252 objects_list.insert(std::make_pair(item, w));
253 LOG4CXX_DEBUG(logger, "Adding function widget at " << std::hex
254 << fun->getStartAddress());
255 objects_list_by_address.insert(std::make_pair(fun->getStartAddress(), item));
256 }