Make link to local functions clickable
authorChristoph Egger <christoph@christoph-egger.org>
Thu, 29 Jan 2015 22:08:56 +0000 (23:08 +0100)
committerChristoph Egger <christoph@christoph-egger.org>
Thu, 29 Jan 2015 22:08:56 +0000 (23:08 +0100)
call instructions now have a clickable target address that gets you to
the corresponding function iff this function is local to the object.

It still does just nothing on functions that are linked in from shared
objects or functionsthat were not created (shouldn't happen right now)

This also adds yet another map to the MainWindow with key/value pairs
that are not quite semantically nice but made implementation easy. We
need to think about how which objects are referenced from ithin the
mainwindow some tim in the future.

src/gui/Mainwindow.cxx
src/gui/Mainwindow.hxx
src/gui/widgets/BasicBlockWidget.cxx
src/gui/widgets/BasicBlockWidget.hxx

index 8a62ef8d2257386cf17b6df7074d48b82a414c29..0f2486ddc13e2ed82227107d0f791368f82bb8b6 100644 (file)
@@ -10,6 +10,7 @@
 namespace {
        BasicBlockWidget *
        local__add_basic_block(BasicBlock * block, Disassembler * dis,
+                              Mainwindow * mainwindow,
                               std::map<uint64_t, BasicBlockWidget*>& known_blocks,
                               CFGScene * scene, uint64_t starty, uint64_t startx);
 }
@@ -80,6 +81,18 @@ void Mainwindow::open() {
        manager->reset(fileName.toStdString());
 }
 
+void Mainwindow::switchMainPlaneToAddress(uint64_t address) {
+       if (objects_list_by_address.find(address) != objects_list_by_address.end()) {
+               LOG4CXX_DEBUG(logger, "Switching to function " << std::hex << address);
+               QListWidgetItem * item = objects_list_by_address[address];
+               listWidget->setCurrentItem(item);
+               stackedWidget->setCurrentWidget(objects_list[item]);
+       } else {
+               LOG4CXX_DEBUG(logger, "No function at " << std::hex << address
+                             << " -- it's probably an imported Symbol");
+       }
+}
+
 void Mainwindow::switchMainPlane(int index) {
        stackedWidget->setCurrentWidget(objects_list[listWidget->currentItem()]);
 }
@@ -128,8 +141,8 @@ void Mainwindow::addFunction(Function* fun) {
                        start_address = b.first;
        }
 
-       local__add_basic_block(block, manager->getDisassembler(), blocks, scene,
-                              start_address, 100);
+       local__add_basic_block(block, manager->getDisassembler(), this,
+                              blocks, scene, start_address, 100);
 
        QGraphicsView * view = new QGraphicsView(scene);
        w->addTab(view, "CFG");
@@ -144,11 +157,15 @@ void Mainwindow::addFunction(Function* fun) {
        QListWidgetItem * item = new QListWidgetItem(fun->getName().c_str(), listWidget);
        stackedWidget->addWidget(w);
        objects_list.insert(std::make_pair(item, w));
+       LOG4CXX_DEBUG(logger, "Adding function widget at " << std::hex
+                     << fun->getStartAddress());
+       objects_list_by_address.insert(std::make_pair(fun->getStartAddress(), item));
 }
 
 namespace {
        BasicBlockWidget *
        local__add_basic_block(BasicBlock * block, Disassembler * dis,
+                              Mainwindow * mainwindow,
                               std::map<uint64_t, BasicBlockWidget*>& known_blocks,
                               CFGScene * scene, uint64_t starty, uint64_t startx) {
 
@@ -159,7 +176,8 @@ namespace {
                std::stringstream s;
                s << "BLOCK_" << std::hex << block->getStartAddress()
                  << "_" << block->getEndAddress();
-               BasicBlockWidget * widget = new BasicBlockWidget(s.str().c_str(), block);
+               BasicBlockWidget * widget = new BasicBlockWidget(s.str().c_str(),
+                                                                block, mainwindow);
 
                known_blocks.insert(std::make_pair(block->getStartAddress(), widget));
 
@@ -186,6 +204,7 @@ namespace {
                                xshift = 1;
                        tmpblock = dis->getBasicBlock(block->getNextBlock(0));
                        tmp = local__add_basic_block(tmpblock, dis,
+                                                    mainwindow,
                                                     known_blocks,
                                                     scene, starty, startx+xshift);
                        nextl = tmp;
@@ -194,6 +213,7 @@ namespace {
                if (block->getNextBlock(1) != 0) {
                        tmpblock = dis->getBasicBlock(block->getNextBlock(1));
                        tmp = local__add_basic_block(tmpblock, dis,
+                                                    mainwindow,
                                                     known_blocks,
                                                     scene, starty, startx-1);
                        nextr = tmp;
index efc7d99bd10facf51483c8ba5d3831fad4f427c6..14d41b3fa6ebe46ae8ea035f0ea739c53927d037 100644 (file)
@@ -41,10 +41,13 @@ private:
 
        std::map<uint64_t, BasicBlockWidget*> blocks;
        std::map<QListWidgetItem*, QWidget*> objects_list;
+       std::map<uint64_t, QListWidgetItem*> objects_list_by_address;
        std::set<Function*> functions;
        InformationManager* manager;
 
        log4cxx::LoggerPtr logger;
+public Q_SLOTS:
+       void switchMainPlaneToAddress(uint64_t);
 private Q_SLOTS:
        void quit();
        void open();
index 0377be3fa2b31882d7a342c75b972eef68b87d40..2880af34a8cf2ff23ca13798d1f81291aa3ee99b 100644 (file)
@@ -1,20 +1,15 @@
 #include "BasicBlockWidget.hxx"
+#include "gui/Mainwindow.hxx"
 
-BasicBlockWidget::BasicBlockWidget(const QString& name, BasicBlock * block)
+BasicBlockWidget::BasicBlockWidget(const QString& name, BasicBlock * block,
+                                   Mainwindow * mainwindow)
        : width(270), height(45)
-       , name(name), block(block)
-       , _proxy(this) {
+       , _proxy(this), name(name)
+       , block(block), mainwindow(mainwindow) {
        next[0] = NULL; next[1] = NULL;
-       _widget.setStyleSheet("QTableWidget { background-color : #ddddff; }");
-       _widget.setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
-       _widget.verticalHeader()->setDefaultSectionSize(18);
-       _widget.setColumnCount(3);
-       _widget.verticalHeader()->hide();
-       _widget.horizontalHeader()->hide();
-       _widget.setShowGrid(false);
-       _widget.setWordWrap(false);
-       _widget.setMinimumSize(210, 20);
-
+       _widget.setStyleSheet("QWidget { background-color : #ddddff; }");
+       _widget.setLayout(&_layout);
+       _layout.setContentsMargins(0, 0, 0, 0);
        _proxy.setWidget(&_widget);
        _proxy.setPos(5, 20);
 
@@ -32,18 +27,37 @@ void BasicBlockWidget::addItem(uint8_t* bytes, size_t num_bytes,
                bytestring += ' ';
        }
 
-       int current_row = _widget.rowCount();
-       _widget.setRowCount(1 + current_row);
-       _widget.setItem(current_row, 0, new QTableWidgetItem(bytestring));
-       _widget.setItem(current_row, 1, new QTableWidgetItem(line.replace('\t', ' ')));
-//     _widget.setItem(current_row, 2, new QTableWidgetItem(href));
+       int current_row = _layout.rowCount();
+       QLabel * bytestring_label = new QLabel(bytestring);
+       bytestring_label->setTextInteractionFlags(Qt::TextSelectableByMouse|
+                                                 Qt::LinksAccessibleByMouse);
+       bytestring_label->setWordWrap(false);
+       _layout.addWidget(bytestring_label, current_row, 0);
+       bytestring_label->setVisible(true);
 
-       _widget.resizeColumnToContents(0);
-       _widget.resizeColumnToContents(1);
-       _widget.resizeColumnToContents(2);
+       line = line.replace('\t', ' ').toHtmlEscaped();
+       if (href != "") {
+               line = "<a href=\"" + href + "\">" + line + "</a>";
+       }
+       QLabel * instruction_label = new QLabel(line);
+       instruction_label->setTextInteractionFlags(Qt::TextSelectableByMouse|
+                                                  Qt::LinksAccessibleByMouse);
+       instruction_label->setWordWrap(false);
+       instruction_label->setFocusPolicy(Qt::StrongFocus);
+       if (href != "") {
+               QObject::connect(instruction_label, &QLabel::linkActivated,
+                                [=](QString str) {
+                                        if (str.startsWith("function:")) {
+                                                        QString address = str.remove("function:");
+                                                        mainwindow->switchMainPlaneToAddress(address.toInt(NULL, 16));
+                                                }
+                                });
+       }
+       _layout.addWidget(instruction_label, current_row, 1);
+       instruction_label->setVisible(true);
 
        width = 12 + _widget.sizeHint().width();
-       height = 25 + _widget.sizeHint().height();
+       height = 25 + _widget.childrenRect().height();
 
        if (width < 250) width = 250;
        _widget.resize(width - 12, height - 25);
index 30f2babce3ff260d84b0152b9987423739304408..c351c3a69a28093762c600a079b7b7acca0de2ca 100644 (file)
@@ -8,10 +8,12 @@
 #include <tuple>
 #include <array>
 
+class Mainwindow;
+
 class BasicBlockWidget : public QGraphicsItem
 {
 public:
-       BasicBlockWidget(const QString& name, BasicBlock * block);
+       BasicBlockWidget(const QString& name, BasicBlock * block, Mainwindow * mainwindow);
 
        void addItem(uint8_t* bytes, size_t num_bytes, QString line, const QString& href);
 
@@ -64,9 +66,11 @@ public:
 private:
        uint32_t width, height;
        QGraphicsProxyWidget _proxy;
-       QTableWidget _widget;
+       QGridLayout _layout;
+       QLabel _widget;
        QString name;
        BasicBlock * block;
+       Mainwindow * mainwindow;
        std::vector<BasicBlockWidget*> previous;
        BasicBlockWidget* next[2];
 };