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