]> git.siccegge.de Git - frida/frida.git/blob - src/gui/Mainwindow.cxx
Allow addition of new functions
[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 <iostream>
8 #include <sstream>
9 #include <map>
10
11 #include <QtGui>
12
13 namespace {
14 BasicBlockWidget *
15 local__add_basic_block(BasicBlock * block, Disassembler * dis,
16 std::map<uint64_t, BasicBlockWidget*>& known_blocks,
17 CFGScene * scene, uint64_t starty, uint64_t startx);
18 }
19
20 Mainwindow::Mainwindow(InformationManager* mgr)
21 : manager(mgr)
22 , logger(log4cxx::Logger::getLogger("Mainwindow")) {
23 openAction = new QAction(tr("&Open"), this);
24 // saveAction = new QAction(tr("&Save"), this);
25 exitAction = new QAction(tr("E&xit"), this);
26
27 connect(openAction, SIGNAL(triggered()),
28 this, SLOT(open()));
29 // connect(saveAction, SIGNAL(triggered()), 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 stackedWidget, SLOT(setCurrentIndex(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 }
67
68 void Mainwindow::quit()
69 {
70 QMessageBox messageBox;
71 messageBox.setWindowTitle(tr("Frida"));
72 messageBox.setText(tr("Do you really want to quit?"));
73 messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
74 messageBox.setDefaultButton(QMessageBox::No);
75 if (messageBox.exec() == QMessageBox::Yes)
76 qApp->quit();
77 }
78
79 void Mainwindow::open() {
80 QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "",
81 tr("Binaries (*)"));
82
83 manager->reset(fileName.toStdString());
84 }
85
86 void Mainwindow::showListContextMenu(const QPoint& point) {
87 QListWidgetItem * item = listWidget->itemAt(point);
88 if (item) {
89 LOG4CXX_DEBUG(logger, "WOHO " << item->text().toStdString());
90 } else {
91 QMenu menu(this);
92 QAction * act = menu.addAction("AddFunction");
93 connect(act, SIGNAL(triggered()), this, SLOT(requestNewFunction()));
94
95 menu.exec(listWidget->mapToGlobal(point));
96 }
97 }
98
99 void Mainwindow::requestNewFunction() {
100 NewFunctionDialog dialog;
101 int result = dialog.exec();
102 if (QDialog::Accepted == result) {
103 LOG4CXX_DEBUG(logger, "requesting Function at " << std::hex << dialog.result());
104 manager->getDisassembler()->disassembleFunctionAt(dialog.result());
105 } else {
106 LOG4CXX_DEBUG(logger, "requestNewFunction aborted");
107 }
108 }
109
110 void Mainwindow::addFunction(Function* fun) {
111 if (functions.find(fun) != functions.end())
112 return;
113
114 functions.insert(fun);
115
116 QTabWidget * w = new QTabWidget();
117
118 // CFG
119 CFGScene * scene = new CFGScene;
120
121 Disassembler * dis = manager->getDisassembler();
122 BasicBlock * block = dis->getBasicBlock(fun->getStartAddress());
123
124 uint64_t start_address(std::numeric_limits<uint64_t>::max());
125 for (auto b : fun->blocks()) {
126 if (b.first < start_address)
127 start_address = b.first;
128 }
129
130 local__add_basic_block(block, manager->getDisassembler(), blocks, scene,
131 start_address, 100);
132
133 QGraphicsView * view = new QGraphicsView(scene);
134 w->addTab(view, "CFG");
135
136 // Listing
137 QTableWidget * t = new QTableWidget();
138 t->setColumnCount(3);
139 t->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
140
141 w->addTab(t, "Listing");
142
143 listWidget->addItem(fun->getName().c_str());
144 stackedWidget->addWidget(w);
145 }
146
147 namespace {
148 BasicBlockWidget *
149 local__add_basic_block(BasicBlock * block, Disassembler * dis,
150 std::map<uint64_t, BasicBlockWidget*>& known_blocks,
151 CFGScene * scene, uint64_t starty, uint64_t startx) {
152
153 decltype(known_blocks.begin()) old;
154 if ((old = known_blocks.find(block->getStartAddress())) != known_blocks.end())
155 return old->second;
156
157 std::stringstream s;
158 s << "BLOCK_" << std::hex << block->getStartAddress()
159 << "_" << block->getEndAddress();
160 BasicBlockWidget * widget = new BasicBlockWidget(s.str().c_str(), block);
161
162 known_blocks.insert(std::make_pair(block->getStartAddress(), widget));
163
164 scene->addItem(widget);
165 widget->setFlag(QGraphicsItem::ItemIsMovable, true);
166 widget->moveBy(100*startx, block->getStartAddress() - starty);
167
168 dis->printEachInstruction(block->getStartAddress(),
169 block->getEndAddress(),
170 [&](uint8_t* bytes,
171 size_t byte_count,
172 const std::string& line,
173 const std::string& ref) {
174 widget->addItem(bytes, byte_count,
175 line.c_str() + 1, // remove \t
176 ref.c_str());
177 });
178
179 BasicBlockWidget *tmp, *nextl(NULL), *nextr(NULL);
180 BasicBlock * tmpblock;
181 if (block->getNextBlock(0) != 0) {
182 int xshift = 0;
183 if (block->getNextBlock(1) != 0)
184 xshift = 1;
185 tmpblock = dis->getBasicBlock(block->getNextBlock(0));
186 tmp = local__add_basic_block(tmpblock, dis,
187 known_blocks,
188 scene, starty, startx+xshift);
189 nextl = tmp;
190 tmp->addPrevious(widget);
191 }
192 if (block->getNextBlock(1) != 0) {
193 tmpblock = dis->getBasicBlock(block->getNextBlock(1));
194 tmp = local__add_basic_block(tmpblock, dis,
195 known_blocks,
196 scene, starty, startx-1);
197 nextr = tmp;
198 tmp->addPrevious(widget);
199 }
200 widget->addNext(nextl, nextr);
201 return widget;
202 }
203 }