Rework API for getting at instructions
authorChristoph Egger <Christoph.Egger@fau.de>
Thu, 19 Mar 2015 16:56:49 +0000 (17:56 +0100)
committerChristoph Egger <Christoph.Egger@fau.de>
Thu, 19 Mar 2015 17:02:43 +0000 (18:02 +0100)
Now we don't hand a callback to the Disassembler, instead we just get a
list of Instruction objects and use that

src/core/BasicBlock.cxx
src/core/BasicBlock.hxx
src/disassembler/Disassembler.hxx
src/disassembler/Instruction.hxx [new file with mode: 0644]
src/disassembler/llvm/LLVMDisassembler.cxx
src/disassembler/llvm/LLVMDisassembler.hxx
src/gui/widgets/BasicBlockWidget.cxx
src/gui/widgets/BasicBlockWidget.hxx
src/gui/widgets/FunctionWidget.cxx

index 5e2efd7860662de04f8aba491185da3895fb0416..7af6bd85f47af3ebc59701c26160539c9e297dbf 100644 (file)
@@ -89,3 +89,7 @@ BasicBlock* BasicBlock::deserialize(QXmlStreamReader& stream, InformationManager
        manager->finishBasicBlock(block);
        return block;
 }
+
+std::list<Instruction> BasicBlock::getInstructions() const {
+       return manager->getDisassembler()->getInstructions(this);
+}
index 0df07b2a7283d3b270712d7be1477f996ea3cea9..3f877879c95942f6defc15111a69938b02948969 100644 (file)
@@ -4,7 +4,9 @@
 #include <cassert>
 #include <string>
 #include <sstream>
+#include <list>
 
+class Instruction;
 class Disassembler;
 class InformationManager;
 class QXmlStreamWriter;
@@ -12,13 +14,11 @@ class QXmlStreamReader;
 
 class BasicBlock {
 public:
-       uint64_t getStartAddress() const {
-               return start_address;
-       }
-
-       uint64_t getEndAddress() const {
-               return end_address;
-       }
+       InformationManager* getManager() const {return manager;}
+       uint64_t getStartAddress() const {return start_address;}
+       uint64_t getEndAddress() const {return end_address;}
+       void setStartAddress(uint64_t address) {start_address = address;}
+       void setEndAddress(uint64_t address) {end_address = address;}
 
        uint64_t getNextBlock(size_t index) const {
                assert(index < 2);
@@ -30,24 +30,13 @@ public:
                next_blocks[index] = address;
        }
 
-       void setStartAddress(uint64_t address) {
-               start_address = address;
-       }
-
-       void setEndAddress(uint64_t address) {
-               end_address = address;
-       }
-
        std::string getName() const {
                std::stringstream s;
                s << "BLOCK_" << std::hex << start_address << '_' << end_address;
                return s.str();
        }
 
-       InformationManager* getManager() const {
-               return manager;
-       }
-
+       std::list<Instruction> getInstructions() const;
        void serialize(QXmlStreamWriter& stream);
        static BasicBlock* deserialize(QXmlStreamReader& stream, InformationManager* manager);
 
index fe240a93c46eae6798d32e6817cea66ab051a09c..78c67c6610ac5b75d709d2ac0b2e0d15a4058aba 100644 (file)
@@ -3,6 +3,9 @@
 
 #include <string>
 #include <functional>
+#include <list>
+
+#include "Instruction.hxx"
 
 class Function;
 class BasicBlock;
@@ -21,6 +24,7 @@ public:
                                          std::function<void (uint8_t*, size_t, const std::string&,
                                                              const std::string&)> fun) = 0;
        virtual Function * disassembleFunctionAt(uint64_t address, const std::string& name = "") = 0;
+       virtual std::list<Instruction> getInstructions(const BasicBlock* block) = 0;
 };
 
 #endif
diff --git a/src/disassembler/Instruction.hxx b/src/disassembler/Instruction.hxx
new file mode 100644 (file)
index 0000000..e79b24f
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef INCLUDE__Instruction_hxx_
+#define INCLUDE__Instruction_hxx_
+
+#include <vector>
+#include <cstdint>
+#include <string>
+
+class Instruction {
+public:
+       Instruction(uint64_t address, const std::string& text, const std::vector<uint8_t>& bytes, const std::string& reference)
+               : address(address), text(text), bytes(bytes), reference(reference) {}
+       uint64_t getAddress() const {return address;}
+       const std::string& getText() const {return text;}
+       const std::vector<uint8_t>& getBytes() const {return bytes;}
+       const std::string& getReference() const {return reference;}
+private:
+       uint64_t address;
+       std::string text;
+       std::vector<uint8_t> bytes;
+       std::string reference;
+};
+
+#endif /* INCLUDE__Instruction_hxx_ */
index 58d122ab4d51472715c5288c99e7e846080f429a..3023f9397d8f2339230c75c2d4e8169a91aa464d 100644 (file)
@@ -1,3 +1,4 @@
+#include "disassembler/Instruction.hxx"
 #include "disassembler/llvm/LLVMDisassembler.hxx"
 #include "core/InformationManager.hxx"
 #include "core/Function.hxx"
@@ -524,6 +525,60 @@ void LLVMDisassembler<ELFT>::readSections() {
 //     //               });
 // }
 
+template <typename ELFT>
+std::list<Instruction> LLVMDisassembler<ELFT>::getInstructions(const BasicBlock *block) {
+       std::list<Instruction> result;
+       SectionRef text_section = getTextSection();
+       uint64_t base_address;
+       text_section.getAddress(base_address);
+       uint64_t current_address = block->getStartAddress() - base_address;
+       uint64_t end_position = block->getEndAddress() - base_address;
+
+       StringRef bytes;
+       text_section.getContents(bytes);
+       StringRefMemoryObject ref(bytes);
+
+       while (current_address < end_position) {
+               uint64_t inst_size;
+               MCInst inst;
+               std::string buf;
+               llvm::raw_string_ostream s(buf);
+
+               if(llvm::MCDisassembler::Success ==
+                  DisAsm->getInstruction(inst, inst_size, ref, current_address, nulls(), nulls())) {
+
+                       uint8_t bytes[inst_size+2];
+                       ref.readBytes(current_address, inst_size, bytes);
+
+                       uint64_t jmptarget;
+                       std::string ref("");
+                       IP->printInst(&inst, s, "");
+                       if (MIA->evaluateBranch(inst, current_address, inst_size, jmptarget)) {
+                               std::stringstream stream;
+                               if (MIA->isCall(inst))
+                                       stream << "function:";
+                               else
+                                       stream << "block:";
+
+                               stream << std::hex << (base_address + jmptarget);
+                               ref = stream.str();
+                       }
+                       result.push_back(Instruction(current_address + base_address, s.str(),
+                                                    std::vector<uint8_t>(bytes, bytes+inst_size), ref));
+               } else {
+                       LOG4CXX_WARN(logger, "Invalid byte at" << std::hex << current_address + base_address);
+                       uint8_t bytes[1];
+                       ref.readBytes(current_address, 1, bytes);
+                       result.push_back(Instruction(current_address + base_address, "Invalid Instruction",
+                                                    std::vector<uint8_t>(bytes, bytes+1), ""));
+                       inst_size = 1;
+               }
+
+               current_address += inst_size;
+       }
+       return result;
+}
+
 template <typename ELFT>
 void LLVMDisassembler<ELFT>::printEachInstruction(uint64_t start, uint64_t end,
                                                   std::function<void (uint8_t*, size_t,
index e0b26e19f7d70a430908c03c029c809ff1a44bf4..a64dc2c66e451131f9187ab82ca5a70342a9e1ab 100644 (file)
@@ -31,6 +31,7 @@ public:
                                                      const std::string&)> fun);
 
        Function * disassembleFunctionAt(uint64_t address, const std::string& name = "");
+       std::list<Instruction> getInstructions(const BasicBlock* block);
 
 private:
        // http://llvm.org/docs/doxygen/html/MCObjectDisassembler_8cpp_source.html +197
index 128b9fb5401d0e4b3977057af4d5ffe5212e8315..37814014596b29e860a53778b9b09cfbc551ff33 100644 (file)
@@ -84,6 +84,8 @@ BasicBlockWidget::BasicBlockWidget(const QString& name, BasicBlock * block,
                                         mainwindow->switchMainPlaneToAddress(address.toInt(NULL, 16));
                                 }
                         });
+       instructions = block->getInstructions();
+       populateWidget();
 }
 
 void BasicBlockWidget::updateFunctionName(RenameFunctionEvent *event) {
@@ -111,47 +113,48 @@ void BasicBlockWidget::updateFunctionName(RenameFunctionEvent *event) {
        }
 }
 
-void BasicBlockWidget::addItem(uint8_t* bytes, size_t num_bytes,
-                               QString line, const QString& href) {
-       QString bytestring;
+void BasicBlockWidget::populateWidget() {
        int row;
-
-       if (_table) {
-               row = _table->rows();
-               _table->appendRows(1);
-       } else {
-               row = 0;
-               QTextTableFormat format;
-               format.setBorderStyle(QTextFrameFormat::BorderStyle_None);
-               format.setBorder(0);
-               _table = _widget->textCursor().insertTable(1, 3, format);
-       }
-
-       for (size_t i(0); i < num_bytes; ++i) {
-               const char * hexdigits = "0123456789ABCDEF";
-               bytestring += hexdigits[(bytes[i] >> 4) & 0xF];
-               bytestring += hexdigits[bytes[i] & 0xF];
-               bytestring += ' ';
-       }
-
-       _table->cellAt(row, 0).firstCursorPosition().insertText(bytestring);
-
-       line = line.replace('\t', ' ').toHtmlEscaped();
-       if (href != "") {
-               QStringList list = href.split(":");
-               if (list[0] == "function") {
-                       uint64_t address = href.split(":")[1].toLongLong(NULL, 16);
-                       Function* fun = block->getManager()->getFunction(address);
-
-                       if (fun) {
-                               line = line.split(" ")[0] + " " + QString(fun->getName().c_str()).toHtmlEscaped();
-                               LOG4CXX_DEBUG(logger, "Naming function at " << address << " " << fun->getName());
+       QTextTableFormat format;
+       format.setBorderStyle(QTextFrameFormat::BorderStyle_None);
+       format.setBorder(0);
+
+       for (Instruction& inst : instructions) {
+               if (_table) {
+                       row = _table->rows();
+                       _table->appendRows(1);
+               } else {
+                       row = 0;
+                       _table = _widget->textCursor().insertTable(1, 3, format);
+               }
+               QString bytestring;
+               for (uint8_t byte : inst.getBytes()) {
+                       const char * hexdigits = "0123456789ABCDEF";
+                       bytestring += hexdigits[(byte >> 4) & 0xF];
+                       bytestring += hexdigits[byte & 0xF];
+                       bytestring += ' ';
+               }
+               _table->cellAt(row, 0).firstCursorPosition().insertText(bytestring);
+
+               QString line = inst.getText().c_str();
+               line = line.replace('\t', ' ').toHtmlEscaped();
+               if (inst.getReference() != "") {
+                       QString href = inst.getReference().c_str();
+                       QStringList list = href.split(":");
+                       if (list[0] == "function") {
+                               uint64_t address = href.split(":")[1].toLongLong(NULL, 16);
+                               Function* fun = block->getManager()->getFunction(address);
+
+                               if (fun) {
+                                       line = line.split(" ")[0] + " " + QString(fun->getName().c_str()).toHtmlEscaped();
+                                       LOG4CXX_DEBUG(logger, "Naming function at " << address << " " << fun->getName());
+                               }
                        }
+                       line = "<a href=\"" + href + "\">" + line + "</a>";
                }
-               line = "<a href=\"" + href + "\">" + line + "</a>";
-       }
 
-       _table->cellAt(row, 1).firstCursorPosition().insertHtml(line);
+               _table->cellAt(row, 1).firstCursorPosition().insertHtml(line);
+       }
 }
 
 void BasicBlockWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem*,
index 8cf709c9f2f821449ac689c6af147ada50db34e8..22bc22021c43bd581a5bfa5af1b198451da24317 100644 (file)
@@ -8,6 +8,9 @@
 #include <array>
 #include <memory>
 #include <log4cxx/logger.h>
+#include <list>
+
+#include "disassembler/Instruction.hxx"
 
 class Mainwindow;
 class CustomQGraphicsTextItem;
@@ -23,7 +26,6 @@ class BasicBlockWidget : public QObject, public QGraphicsItem
 public:
        BasicBlockWidget(const QString& name, BasicBlock * block, Mainwindow * mainwindow);
 
-       void addItem(uint8_t* bytes, size_t num_bytes, QString line, const QString& href);
        void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                   QWidget *widget);
        QRectF boundingRect() const;
@@ -48,12 +50,14 @@ public:
                { return name; }
 private:
        void updateFunctionName(RenameFunctionEvent* event);
+       void populateWidget();
 
        uint32_t width, height;
        QString name;
        std::unique_ptr<QGraphicsTextItem> _widget;
        QTextTable* _table;
        BasicBlock* block;
+       std::list<Instruction> instructions;
        Mainwindow* mainwindow;
        std::vector<BasicBlockWidget*> previous;
        BasicBlockWidget* next[2];
index ba96e5d4af18fe3732de18e9c9e9ef6a0f9e8b3c..576e848368b3f6972c81b89632ce9dba238233af 100644 (file)
@@ -77,18 +77,6 @@ namespace {
                widget->setFlag(QGraphicsItem::ItemIsMovable, true);
                widget->moveBy(100*startx, block->getStartAddress() - starty);
 
-               manager->getDisassembler()
-                       ->printEachInstruction(block->getStartAddress(),
-                                              block->getEndAddress(),
-                                              [&](uint8_t* bytes,
-                                                  size_t byte_count,
-                                                  const std::string& line,
-                                                  const std::string& ref) {
-                                                      widget->addItem(bytes, byte_count,
-                                                                      line.c_str() + 1, // remove \t
-                                                                      ref.c_str());
-                                              });
-
                BasicBlockWidget *tmp, *nextl(NULL), *nextr(NULL);
                BasicBlock * tmpblock;
                if (block->getNextBlock(0) != 0) {