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