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