]> git.siccegge.de Git - frida/frida.git/blob - src/gui/Mainwindow.cxx
Move ScriptingDock contructor to cxx file
[frida/frida.git] / src / gui / Mainwindow.cxx
1 #include "Mainwindow.hxx"
2 #include "qt.hxx"
3 #include "disassembler/llvm/LLVMDisassembler.hxx"
4 #include "core/Function.hxx"
5 #include "core/BasicBlock.hxx"
6 #include "core/InformationManager.hxx"
7 #include "widgets/ScriptingDock.hxx"
8 #include "widgets/CFGScene.hxx"
9 #include "widgets/FunctionWidget.hxx"
10 #include "dialogs/NewFunctionDialog.hxx"
11 #include "dialogs/SimpleStringDialog.hxx"
12
13 #include <sstream>
14
15 namespace {
16 BasicBlockWidget *
17 local__add_basic_block(BasicBlock * block,
18 Mainwindow * mainwindow, InformationManager * manager,
19 std::map<uint64_t, BasicBlockWidget*>& known_blocks,
20 CFGScene * scene, uint64_t starty, uint64_t startx);
21 }
22
23 Mainwindow::Mainwindow(InformationManager* mgr)
24 : manager(mgr)
25 , logger(log4cxx::Logger::getLogger("Mainwindow")) {
26 openAction = new QAction(tr("&Open"), this);
27 loadAction = new QAction(tr("&Load"), this);
28 saveAction = new QAction(tr("&Save"), this);
29 exitAction = new QAction(tr("E&xit"), this);
30
31 connect(openAction, &QAction::triggered,
32 this, &Mainwindow::open);
33 connect(loadAction, &QAction::triggered,
34 this, &Mainwindow::load);
35 connect(saveAction, &QAction::triggered,
36 this, &Mainwindow::save);
37 connect(exitAction, &QAction::triggered,
38 qApp, &QApplication::quit);
39
40 fileMenu = menuBar()->addMenu(tr("&File"));
41 fileMenu->addAction(openAction);
42 fileMenu->addAction(loadAction);
43 fileMenu->addAction(saveAction);
44 fileMenu->addSeparator();
45 fileMenu->addAction(exitAction);
46
47 scripting = new ScriptingDock(tr("Scripting"), this);
48 scripting->setAllowedAreas(Qt::BottomDockWidgetArea);
49 addDockWidget(Qt::BottomDockWidgetArea, scripting);
50
51 listWidget = new QTreeWidget();
52 listWidget->setColumnCount(1);
53 listWidget->setDragDropMode(QAbstractItemView::InternalMove);
54 listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
55 connect(listWidget, SIGNAL(customContextMenuRequested(const QPoint&)),
56 this, SLOT(showListContextMenu(const QPoint&)));
57
58 stackedWidget = new QStackedWidget();
59 dockWidget = new QDockWidget(tr("Functions"), this);
60 dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea |
61 Qt::RightDockWidgetArea);
62 dockWidget->setWidget(listWidget);
63 addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
64 setCentralWidget(stackedWidget);
65
66 connect(listWidget, &QTreeWidget::currentItemChanged,
67 [=] (QTreeWidgetItem* current, QTreeWidgetItem*) {
68 switchMainPlane(current);
69 });
70
71 setWindowTitle(tr("FRIDA"));
72
73 QTreeWidgetItem * external = new QTreeWidgetItem(listWidget, QStringList("External Functions"));
74 external->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
75 external->setBackground(0, QBrush(QColor(0xff, 0xdd, 0xdd)));
76 mgr->connect_new_function_signal([&] (Function* fun) {addFunction(fun);});
77 mgr->connect_new_dyn_symbol_signal([=] (const std::string& name) {
78 auto item = new QTreeWidgetItem(external, QStringList(name.c_str()));
79 item->setBackground(0, QBrush(QColor(0xff, 0xdd, 0xdd)));
80 });
81 setGlobalHotkeys();
82 }
83
84 void Mainwindow::setGlobalHotkeys() {
85 QShortcut *shortcut = new QShortcut(QKeySequence("f"), this);
86 connect(shortcut, &QShortcut::activated, this, &Mainwindow::requestNewFunction);
87
88 shortcut = new QShortcut(QKeySequence("r"), listWidget);
89 connect(shortcut, &QShortcut::activated, [=]() {
90 QTreeWidgetItem * item = listWidget->currentItem();
91 if (item) renameFunction(objects_list[item]->getFunction());
92 });
93 }
94
95 void Mainwindow::quit()
96 {
97 QMessageBox messageBox;
98 messageBox.setWindowTitle(tr("Frida"));
99 messageBox.setText(tr("Do you really want to quit?"));
100 messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
101 messageBox.setDefaultButton(QMessageBox::No);
102 if (messageBox.exec() == QMessageBox::Yes)
103 qApp->quit();
104 }
105
106 void Mainwindow::open() {
107 QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "",
108 tr("Binaries (*)"));
109 manager->reset(fileName.toStdString());
110 }
111
112 void Mainwindow::load() {
113 QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "",
114 tr("Frida Archives (*.frida)"));
115 manager->load(fileName.toStdString());
116 }
117
118 void Mainwindow::save() {
119 QString filename = QFileDialog::getSaveFileName(this, tr("Save File"), "", tr("Frida Archives (*.frida)"));
120 manager->save(filename.toStdString());
121 }
122
123 void Mainwindow::switchMainPlaneToAddress(uint64_t address) {
124 if (objects_list_by_address.find(address) != objects_list_by_address.end()) {
125 LOG4CXX_DEBUG(logger, "Switching to function " << std::hex << address);
126 QTreeWidgetItem * item = objects_list_by_address[address];
127 listWidget->setCurrentItem(item);
128 stackedWidget->setCurrentWidget(objects_list[item]);
129 } else {
130 LOG4CXX_DEBUG(logger, "No function at " << std::hex << address
131 << " -- it's probably an imported Symbol");
132 }
133 }
134
135 void Mainwindow::switchMainPlane(QTreeWidgetItem* to) {
136 if (objects_list.end() != objects_list.find(to))
137 stackedWidget->setCurrentWidget(objects_list[to]);
138 }
139
140 void Mainwindow::showListContextMenu(const QPoint& point) {
141 QAction * act;
142 QTreeWidgetItem * item = listWidget->itemAt(point);
143 QMenu menu(this);
144
145 act = menu.addAction("Add Function");
146 connect(act, &QAction::triggered, this, &Mainwindow::requestNewFunction);
147
148 act = menu.addAction("Add Group");
149 connect(act, &QAction::triggered, this, &Mainwindow::requestNewGroup);
150
151 if (item) {
152 if (objects_list.find(item) != objects_list.end()) {
153 act = menu.addAction("Rename Function");
154 connect(act, &QAction::triggered, [=]() {this->renameFunction(objects_list[item]->getFunction());});
155 } else {
156 act = menu.addAction("Rename Group");
157 connect(act, &QAction::triggered, [=]() {renameGroup(item);});
158 }
159
160
161 QMenu* submenu = menu.addMenu("Move to group");
162
163 for (QTreeWidgetItem* groupitem : group_list) {
164 act = submenu->addAction(groupitem->text(0));
165 connect(act, &QAction::triggered,
166 [=] () {
167 listWidget->invisibleRootItem()->removeChild(item);
168 groupitem->addChild(item);
169 });
170 }
171 }
172
173 menu.exec(listWidget->mapToGlobal(point));
174 }
175
176 void Mainwindow::requestNewFunction() {
177 NewFunctionDialog dialog;
178 int result = dialog.exec();
179 if (QDialog::Accepted == result) {
180 requestNewFunctionByAddress(dialog.result());
181 } else {
182 LOG4CXX_DEBUG(logger, "requestNewFunction aborted");
183 }
184 }
185
186 void Mainwindow::requestNewGroup() {
187 SimpleStringDialog dialog("New Group");
188 int result = dialog.exec();
189 if (QDialog::Accepted == result) {
190 QTreeWidgetItem * external = new QTreeWidgetItem(listWidget, QStringList(dialog.result()));
191 external->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
192 group_list.push_back(external);
193 } else {
194 LOG4CXX_DEBUG(logger, "requestNewGroup aborted");
195 }
196 }
197
198 void Mainwindow::requestNewFunctionByAddress(uint64_t address) {
199 LOG4CXX_DEBUG(logger, "requesting Function at " << std::hex << address);
200 manager->getDisassembler()->disassembleFunctionAt(address);
201 switchMainPlaneToAddress(address);
202 }
203
204 void Mainwindow::renameFunction(Function* function) {
205 SimpleStringDialog dialog("New name");
206 int result = dialog.exec();
207 if (QDialog::Accepted == result) {
208 LOG4CXX_DEBUG(logger, "renaming Function " << function->getName()
209 << " to " << dialog.result().toStdString());
210 function->setName(dialog.result().toStdString());
211 objects_list_by_address[function->getStartAddress()]->setText(0, dialog.result());
212 } else {
213 LOG4CXX_DEBUG(logger, "renameFunction aborted");
214 }
215 }
216
217 void Mainwindow::renameGroup(QTreeWidgetItem* item) {
218 SimpleStringDialog dialog("New name");
219 int result = dialog.exec();
220 if (QDialog::Accepted == result) {
221 LOG4CXX_DEBUG(logger, "renaming group " << item->text(0).toStdString()
222 << " to " << dialog.result().toStdString());
223 item->setText(0, dialog.result());
224 } else {
225 LOG4CXX_DEBUG(logger, "renameFunction aborted");
226 }
227 }
228
229 void Mainwindow::addFunction(Function* fun) {
230 if (functions.find(fun->getStartAddress()) != functions.end())
231 return;
232
233 functions.insert(std::make_pair(fun->getStartAddress(), fun));
234
235 FunctionWidget * w = new FunctionWidget(fun);
236
237 // CFG
238 CFGScene * scene = new CFGScene;
239
240 BasicBlock * block = manager->getBasicBlock(fun->getStartAddress());
241
242 uint64_t start_address(std::numeric_limits<uint64_t>::max());
243 for (auto b : fun->blocks()) {
244 if (b.first < start_address)
245 start_address = b.first;
246 }
247
248 local__add_basic_block(block, this,
249 manager, blocks, scene, start_address, 100);
250
251 QGraphicsView * view = new QGraphicsView(scene);
252 w->addTab(view, "CFG");
253
254 // Listing
255 QTableWidget * t = new QTableWidget();
256 t->setColumnCount(3);
257 t->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
258
259 w->addTab(t, "Listing");
260
261 QTreeWidgetItem * item = new QTreeWidgetItem(listWidget, QStringList(fun->getName().c_str()));
262 stackedWidget->addWidget(w);
263 objects_list.insert(std::make_pair(item, w));
264 LOG4CXX_DEBUG(logger, "Adding function widget at " << std::hex
265 << fun->getStartAddress());
266 objects_list_by_address.insert(std::make_pair(fun->getStartAddress(), item));
267 }
268
269 namespace {
270 BasicBlockWidget *
271 local__add_basic_block(BasicBlock * block,
272 Mainwindow * mainwindow, InformationManager * manager,
273 std::map<uint64_t, BasicBlockWidget*>& known_blocks,
274 CFGScene * scene, uint64_t starty, uint64_t startx) {
275
276 decltype(known_blocks.begin()) old;
277 if ((old = known_blocks.find(block->getStartAddress())) != known_blocks.end())
278 return old->second;
279
280 std::stringstream s;
281 s << "BLOCK_" << std::hex << block->getStartAddress()
282 << "_" << block->getEndAddress();
283 BasicBlockWidget * widget = new BasicBlockWidget(s.str().c_str(),
284 block, mainwindow);
285
286 known_blocks.insert(std::make_pair(block->getStartAddress(), widget));
287
288 scene->addItem(widget);
289 widget->setFlag(QGraphicsItem::ItemIsMovable, true);
290 widget->moveBy(100*startx, block->getStartAddress() - starty);
291
292 manager->getDisassembler()
293 ->printEachInstruction(block->getStartAddress(),
294 block->getEndAddress(),
295 [&](uint8_t* bytes,
296 size_t byte_count,
297 const std::string& line,
298 const std::string& ref) {
299 widget->addItem(bytes, byte_count,
300 line.c_str() + 1, // remove \t
301 ref.c_str());
302 });
303
304 BasicBlockWidget *tmp, *nextl(NULL), *nextr(NULL);
305 BasicBlock * tmpblock;
306 if (block->getNextBlock(0) != 0) {
307 int xshift = 0;
308 if (block->getNextBlock(1) != 0)
309 xshift = 1;
310 tmpblock = manager->getBasicBlock(block->getNextBlock(0));
311 tmp = local__add_basic_block(tmpblock, mainwindow, manager,
312 known_blocks,
313 scene, starty, startx+xshift);
314 nextl = tmp;
315 tmp->addPrevious(widget);
316 }
317 if (block->getNextBlock(1) != 0) {
318 tmpblock = manager->getBasicBlock(block->getNextBlock(1));
319 tmp = local__add_basic_block(tmpblock, mainwindow, manager,
320 known_blocks,
321 scene, starty, startx-1);
322 nextr = tmp;
323 tmp->addPrevious(widget);
324 }
325 widget->addNext(nextl, nextr);
326 return widget;
327 }
328 }