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