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