diff --git a/src/dialogs/commentsdialog.ui b/src/dialogs/commentsdialog.ui index 249e7975..0aa44916 100644 --- a/src/dialogs/commentsdialog.ui +++ b/src/dialogs/commentsdialog.ui @@ -7,11 +7,11 @@ 0 0 400 - 61 + 75 - Dialog + Comment diff --git a/src/dialogs/flagdialog.cpp b/src/dialogs/flagdialog.cpp new file mode 100644 index 00000000..4febaeef --- /dev/null +++ b/src/dialogs/flagdialog.cpp @@ -0,0 +1,35 @@ + +#include "ui_flagdialog.h" +#include "flagdialog.h" + +FlagDialog::FlagDialog(IaitoRCore *core, RVA offset, QWidget *parent) : + QDialog(parent), + ui(new Ui::FlagDialog) +{ + ui->setupUi(this); + setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint)); + + this->core = core; + this->offset = offset; + + auto size_validator = new QIntValidator(ui->sizeEdit); + size_validator->setBottom(1); + ui->sizeEdit->setValidator(size_validator); +} + +FlagDialog::~FlagDialog() +{ + delete ui; +} + +void FlagDialog::on_buttonBox_accepted() +{ + QString name = ui->nameEdit->text(); + RVA size = ui->sizeEdit->text().toULongLong(); + core->addFlag(offset, name, size); +} + +void FlagDialog::on_buttonBox_rejected() +{ + close(); +} \ No newline at end of file diff --git a/src/dialogs/flagdialog.h b/src/dialogs/flagdialog.h new file mode 100644 index 00000000..fc929ecc --- /dev/null +++ b/src/dialogs/flagdialog.h @@ -0,0 +1,31 @@ +#ifndef FLAGDIALOG_H +#define FLAGDIALOG_H + +#include +#include + +namespace Ui +{ + class FlagDialog; +} + +class FlagDialog : public QDialog +{ + Q_OBJECT + +public: + explicit FlagDialog(IaitoRCore *core, RVA offset, QWidget *parent = 0); + ~FlagDialog(); + +private slots: + void on_buttonBox_accepted(); + void on_buttonBox_rejected(); + +private: + Ui::FlagDialog *ui; + + IaitoRCore *core; + RVA offset; +}; + +#endif // FLAGDIALOG_H diff --git a/src/dialogs/flagdialog.ui b/src/dialogs/flagdialog.ui new file mode 100644 index 00000000..18721689 --- /dev/null +++ b/src/dialogs/flagdialog.ui @@ -0,0 +1,126 @@ + + + FlagDialog + + + + 0 + 0 + 452 + 121 + + + + Add Flag + + + + + + 12 + + + + + + 75 + true + + + + Flag: + + + + + + + false + + + + + + + + + + + 100 + 16777215 + + + + 1 + + + false + + + + + + + + + + + 75 + true + + + + Size: + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + FlagDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FlagDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/iaito.pro b/src/iaito.pro index bf16a0e1..4b3d7f01 100644 --- a/src/iaito.pro +++ b/src/iaito.pro @@ -66,7 +66,8 @@ SOURCES += \ hexhighlighter.cpp \ widgets/sectionsdock.cpp \ widgets/consolewidget.cpp \ - radarewebserver.cpp + radarewebserver.cpp \ + dialogs/flagdialog.cpp HEADERS += \ mainwindow.h \ @@ -106,7 +107,8 @@ HEADERS += \ radarewebserver.h \ settings.h \ iaitorcore.h \ - iaitordisasm.h + iaitordisasm.h \ + dialogs/flagdialog.h FORMS += \ mainwindow.ui \ @@ -131,7 +133,8 @@ FORMS += \ widgets/dashboard.ui \ dialogs/xrefsdialog.ui \ widgets/sectionsdock.ui \ - widgets/consolewidget.ui + widgets/consolewidget.ui \ + dialogs/flagdialog.ui RESOURCES += \ resources.qrc diff --git a/src/iaitorcore.h b/src/iaitorcore.h index 5eb27fb4..f74f053d 100644 --- a/src/iaitorcore.h +++ b/src/iaitorcore.h @@ -46,6 +46,8 @@ public: typedef ut64 RVA; +#define RVA_INVALID UT64_MAX + inline QString RAddressString(RVA addr) { return QString::asprintf("%#010llx", addr); @@ -163,6 +165,7 @@ public: ~IaitoRCore(); RVA getOffset() const { return core_->offset; } + static QString sanitizeStringForCommand(QString s); int getCycloComplex(ut64 addr); int getFcnSize(ut64 addr); int fcnCyclomaticComplexity(ut64 addr); @@ -172,7 +175,6 @@ public: QJsonDocument cmdj(const QString &str); void renameFunction(QString prev_name, QString new_name); void setComment(RVA addr, QString cmt); - void setComment(QString addr, QString cmt); void delComment(ut64 addr); QMap>> getNestedComments(); void setOptions(QString key); @@ -236,6 +238,8 @@ public: QList getXRefs(RVA addr, bool to, bool whole_function, const QString &filterType = QString::null); + void addFlag(RVA offset, QString name, RVA size); + RCoreLocked core() const; /* fields */ @@ -243,7 +247,10 @@ public: Sdb *db; signals: + // TODO: create a more sophisticated update-event system void functionRenamed(QString prev_name, QString new_name); + void flagsChanged(); + void commentsChanged(); public slots: diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index e52b7b4c..624bf804 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -767,9 +767,10 @@ void MainWindow::seek(const RVA offset, const QString &name, bool raise_memory_d this->hexdumpTopOffset = 0; this->hexdumpBottomOffset = 0; core->seek(offset); + emit globalSeekTo(offset); setCursorAddress(offset); - refreshMem(); + //refreshMem(); this->memoryDock->disasTextEdit->setFocus(); // Rise and shine baby! diff --git a/src/mainwindow.h b/src/mainwindow.h index 1d621857..6510af67 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -80,6 +80,7 @@ public: void refreshOmniBar(const QStringList &flags); signals: + void globalSeekTo(RVA address); void cursorAddressChanged(RVA address); public slots: diff --git a/src/qrcore.cpp b/src/qrcore.cpp index 304d2196..77a7bf64 100644 --- a/src/qrcore.cpp +++ b/src/qrcore.cpp @@ -167,6 +167,12 @@ IaitoRCore::~IaitoRCore() r_cons_free(); } +QString IaitoRCore::sanitizeStringForCommand(QString s) +{ + static const QRegExp regexp(";|@"); + return s.replace(regexp, "_"); +} + QString IaitoRCore::cmd(const QString &str) { CORE_LOCK(); @@ -325,13 +331,9 @@ void IaitoRCore::setComment(RVA addr, QString cmt) { //r_meta_add (core->anal, 'C', addr, 1, cmt.toUtf8()); cmd("CC " + cmt + " @ " + QString::number(addr)); + emit commentsChanged(); } -void IaitoRCore::setComment(QString addr, QString cmt) -{ - //r_meta_add (core->anal, 'C', addr, 1, cmt.toUtf8()); - cmd("CC " + cmt + " @ " + addr); -} void IaitoRCore::delComment(ut64 addr) { @@ -1125,4 +1127,11 @@ QList IaitoRCore::getXRefs(RVA addr, bool to, bool whole_functi } return ret; +} + +void IaitoRCore::addFlag(RVA offset, QString name, RVA size) +{ + name = sanitizeStringForCommand(name); + cmd(QString("f %1 %2 @ %3").arg(name).arg(size).arg(offset)); + emit flagsChanged(); } \ No newline at end of file diff --git a/src/widgets/commentswidget.cpp b/src/widgets/commentswidget.cpp index a03f6081..f73f978a 100644 --- a/src/widgets/commentswidget.cpp +++ b/src/widgets/commentswidget.cpp @@ -28,6 +28,8 @@ CommentsWidget::CommentsWidget(MainWindow *main, QWidget *parent) : connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showTitleContextMenu(const QPoint &))); + connect(main->core, SIGNAL(commentsChanged()), this, SLOT(refreshTree())); + // Hide the buttons frame ui->frame->hide(); } diff --git a/src/widgets/flagswidget.cpp b/src/widgets/flagswidget.cpp index d06ee28e..d845c665 100644 --- a/src/widgets/flagswidget.cpp +++ b/src/widgets/flagswidget.cpp @@ -140,6 +140,8 @@ FlagsWidget::FlagsWidget(MainWindow *main, QWidget *parent) : connect(ui->filterLineEdit, SIGNAL(textChanged(const QString &)), flags_proxy_model, SLOT(setFilterWildcard(const QString &))); ui->flagsTreeView->setModel(flags_proxy_model); ui->flagsTreeView->sortByColumn(FlagsModel::OFFSET, Qt::AscendingOrder); + + connect(main->core, SIGNAL(flagsChanged()), this, SLOT(flagsChanged())); } FlagsWidget::~FlagsWidget() @@ -172,6 +174,11 @@ void FlagsWidget::on_flagspaceCombo_currentTextChanged(const QString &arg1) refreshFlags(); } +void FlagsWidget::flagsChanged() +{ + refreshFlagspaces(); +} + void FlagsWidget::refreshFlagspaces() { int cur_idx = ui->flagspaceCombo->currentIndex(); diff --git a/src/widgets/flagswidget.h b/src/widgets/flagswidget.h index 7f5d85ef..956a1eab 100644 --- a/src/widgets/flagswidget.h +++ b/src/widgets/flagswidget.h @@ -70,6 +70,8 @@ private slots: void on_flagsTreeView_doubleClicked(const QModelIndex &index); void on_flagspaceCombo_currentTextChanged(const QString &arg1); + void flagsChanged(); + private: Ui::FlagsWidget *ui; MainWindow *main; diff --git a/src/widgets/memorywidget.cpp b/src/widgets/memorywidget.cpp index 437b12d4..d8e445c9 100644 --- a/src/widgets/memorywidget.cpp +++ b/src/widgets/memorywidget.cpp @@ -6,6 +6,7 @@ #include "dialogs/xrefsdialog.h" #include "dialogs/renamedialog.h" #include "dialogs/commentsdialog.h" +#include "dialogs/flagdialog.h" #include #include @@ -41,10 +42,12 @@ MemoryWidget::MemoryWidget(MainWindow *main) : this->memTabWidget = ui->memTabWidget; this->last_fcn = "entry0"; - this->last_disasm_fcn = 0; //""; this->last_graph_fcn = 0; //""; this->last_hexdump_fcn = 0; //""; + disasm_top_offset = 0; + next_disasm_top_offset = 0; + // Increase asm text edit margin QTextDocument *asm_docu = this->disasTextEdit->document(); asm_docu->setDocumentMargin(10); @@ -188,12 +191,19 @@ MemoryWidget::MemoryWidget(MainWindow *main) : connect(ui->graphWebView->page(), SIGNAL(loadFinished(bool)), this, SLOT(frameLoadFinished(bool))); + connect(main, SIGNAL(globalSeekTo(RVA)), this, SLOT(on_globalSeekTo(RVA))); connect(main, SIGNAL(cursorAddressChanged(RVA)), this, SLOT(on_cursorAddressChanged(RVA))); + connect(main->core, SIGNAL(flagsChanged()), this, SLOT(updateViews())); + connect(main->core, SIGNAL(commentsChanged()), this, SLOT(updateViews())); fillPlugins(); } +void MemoryWidget::on_globalSeekTo(RVA addr) +{ + updateViews(addr); +} void MemoryWidget::on_cursorAddressChanged(RVA addr) { @@ -386,6 +396,23 @@ void MemoryWidget::highlightDecoCurrentLine() ui->decoTextEdit->setExtraSelections(extraSelections); } +RVA MemoryWidget::readCurrentDisassemblyOffset() +{ + // TODO: do this in a different way without parsing the disassembly text + QTextCursor tc = this->disasTextEdit->textCursor(); + tc.select(QTextCursor::LineUnderCursor); + QString lastline = tc.selectedText(); + QStringList parts = lastline.split(" ", QString::SkipEmptyParts); + + if (parts.isEmpty()) + return RVA_INVALID; + + QString ele = parts[0]; + if (!ele.contains("0x")) + return RVA_INVALID; + + return ele.toULongLong(0, 16); +} MemoryWidget::~MemoryWidget() { @@ -397,11 +424,13 @@ void MemoryWidget::setup() setScrollMode(); const QString off = main->core->cmd("afo entry0").trimmed(); + RVA offset = off.toULongLong(0, 16); + updateViews(offset); - refreshDisasm(off); - refreshHexdump(off); - create_graph(off); - get_refs_data(off.toLongLong(0, 16)); + //refreshDisasm(); + //refreshHexdump(off); + //create_graph(off); + get_refs_data(offset); //setFcnName(off); } @@ -438,31 +467,32 @@ void MemoryWidget::replaceTextDisasm(QString txt) ui->disasTextEdit_2->setPlainText(txt); } -void MemoryWidget::disasmScrolled() +bool MemoryWidget::loadMoreDisassembly() { /* - * Add more disasm as the user scrolls - * Not working properly when scrolling upwards - * r2 doesn't handle properly 'pd-' for archs with variable instruction size - */ + * Add more disasm as the user scrolls + * Not working properly when scrolling upwards + * r2 doesn't handle properly 'pd-' for archs with variable instruction size + */ // Disconnect scroll signals to add more content disconnect(this->disasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled())); QScrollBar *sb = this->disasTextEdit->verticalScrollBar(); + bool loaded = false; + if (sb->value() > sb->maximum() - 10) { //this->main->add_debug_output("End is coming"); QTextCursor tc = this->disasTextEdit->textCursor(); tc.movePosition(QTextCursor::End); - tc.select(QTextCursor::LineUnderCursor); - QString lastline = tc.selectedText(); - QString ele = lastline.split(" ", QString::SkipEmptyParts)[0]; - if (ele.contains("0x")) + RVA offset = readCurrentDisassemblyOffset(); + + if (offset != RVA_INVALID) { - this->main->core->seek(ele); + main->core->seek(offset); QString raw = this->main->core->cmd("pd 200"); QString txt = raw.section("\n", 1, -1); //this->disasTextEdit->appendPlainText(" ;\n ; New content here\n ;\n " + txt.trimmed()); @@ -475,6 +505,9 @@ void MemoryWidget::disasmScrolled() QString lastline = tc.selectedText(); this->main->addDebugOutput("Last line: " + lastline); } + + loaded = true; + // Code below will be used to append more disasm upwards, one day } /* else if (sb->value() < sb->minimum() + 10) { //this->main->add_debug_output("Begining is coming"); @@ -510,65 +543,63 @@ void MemoryWidget::disasmScrolled() // Reconnect scroll signals connect(this->disasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled())); + + return loaded; } -void MemoryWidget::refreshDisasm(const QString &offset) + +void MemoryWidget::disasmScrolled() +{ + loadMoreDisassembly(); +} + +void MemoryWidget::refreshDisasm() { RCoreLocked lcore = this->main->core->core(); - // we must store those ranges somewhere, to handle scroll - //ut64 addr = lcore->offset; - //int length = lcore->num->value; - - //printf("refreshDisasm %s\n", offset.toLocal8Bit().constData()); // Prevent further scroll disconnect(this->disasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled())); disconnect(this->disasTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(on_disasTextEdit_2_cursorPositionChanged())); - // Get disas at offset - if (!offset.isEmpty()) + RVA offset = next_disasm_top_offset; + next_disasm_top_offset = RVA_INVALID; + bool offset_changed = offset != RVA_INVALID; + + if (offset_changed) // new offset (seek) { - this->main->core->cmd("s " + offset); + disasm_top_offset = offset; + this->main->core->cmd(QString("s %1").arg(offset)); } - else + else // simple refresh { - // Get current offset - QTextCursor tc = this->disasTextEdit->textCursor(); - tc.select(QTextCursor::LineUnderCursor); - QString lastline = tc.selectedText(); - QStringList elements = lastline.split(" ", QString::SkipEmptyParts); - if (elements.length() > 0) - { - QString ele = elements[0]; - if (ele.contains("0x")) - { - QString fcn = this->main->core->cmdFunctionAt(ele); - if (fcn != "") - { - this->main->core->cmd("s " + fcn); - } - else - { - this->main->core->cmd("s " + ele); - } - } - } + main->core->cmd(QString("s %1").arg(disasm_top_offset)); } - QString txt2 = this->main->core->cmd("pd 100"); + QString txt2 = this->main->core->cmd("pd 200"); + + disasTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + // if the offset changed, jump to the top + // otherwise try to retain the position + int cursor_pos = offset_changed ? 0 : disasTextEdit->textCursor().position(); + int scroll_pos = offset_changed ? 0 : disasTextEdit->verticalScrollBar()->value(); + this->disasTextEdit->setPlainText(txt2.trimmed()); - // TODO: Fixx this ugly code - //QString temp_seek = this->main->core->cmd("s").split("0x")[1].trimmed(); - QString s = this->normalize_addr(this->main->core->cmd("s")); - //this->main->add_debug_output("Offset to search: " + s); - this->disasTextEdit->ensureCursorVisible(); - /*this->disasTextEdit->moveCursor(QTextCursor::End); + auto cursor = disasTextEdit->textCursor(); + cursor.setPosition(cursor_pos); + disasTextEdit->setTextCursor(cursor); - while (this->disasTextEdit->find(QRegExp("^" + s), QTextDocument::FindBackward)) + disasTextEdit->verticalScrollBar()->setValue(scroll_pos); + + // load more disassembly if necessary + static const int load_more_limit = 10; // limit passes, so it can't take forever + for (int load_more_i = 0; load_more_i < load_more_limit; load_more_i++) { - this->disasTextEdit->moveCursor(QTextCursor::StartOfWord, QTextCursor::MoveAnchor); - }*/ + if (!loadMoreDisassembly()) + break; + disasTextEdit->verticalScrollBar()->setValue(scroll_pos); + } connect(this->disasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled())); connect(this->disasTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(on_disasTextEdit_2_cursorPositionChanged())); @@ -998,6 +1029,7 @@ void MemoryWidget::showDisasContextMenu(const QPoint &pt) // Add menu actions menu->clear(); menu->addAction(ui->actionDisasAdd_comment); + menu->addAction(ui->actionAddFlag); menu->addAction(ui->actionFunctionsRename); menu->addAction(ui->actionFunctionsUndefine); menu->addSeparator(); @@ -1260,31 +1292,43 @@ void MemoryWidget::on_actionSend_to_Notepad_triggered() void MemoryWidget::on_actionDisasAdd_comment_triggered() { - // Get current offset - QTextCursor tc = this->disasTextEdit->textCursor(); - tc.select(QTextCursor::LineUnderCursor); - QString lastline = tc.selectedText(); - QString ele = lastline.split(" ", QString::SkipEmptyParts)[0]; - if (ele.contains("0x")) + RVA offset = readCurrentDisassemblyOffset(); + + // Get function for clicked offset + RAnalFunction *fcn = this->main->core->functionAt(offset); + CommentsDialog *c = new CommentsDialog(this); + if (c->exec()) { - // Get function for clicked offset - RAnalFunction *fcn = this->main->core->functionAt(ele.toLongLong(0, 16)); - CommentsDialog *c = new CommentsDialog(this); - if (c->exec()) + // Get new function name + QString comment = c->getComment(); + //this->main->add_debug_output("Comment: " + comment + " at: " + ele); + // Rename function in r2 core + this->main->core->setComment(offset, comment); + // Seek to new renamed function + if (fcn) { - // Get new function name - QString comment = c->getComment(); - //this->main->add_debug_output("Comment: " + comment + " at: " + ele); - // Rename function in r2 core - this->main->core->setComment(ele, comment); - // Seek to new renamed function - if (fcn) - { - this->main->seek(fcn->name); - } - // TODO: Refresh functions tree widget + this->main->seek(fcn->name); } + // TODO: Refresh functions tree widget } + + this->main->refreshComments(); +} + + +void MemoryWidget::on_actionAddFlag_triggered() +{ + RVA offset = readCurrentDisassemblyOffset(); + + FlagDialog *dialog = new FlagDialog(main->core, offset, this); + if (dialog->exec()) + { + //QString comment = dialog->getFlagName(); + // Rename function in r2 core + + //this->main->core->setComment(offset, comment); + } + this->main->refreshComments(); } @@ -1939,7 +1983,7 @@ void MemoryWidget::on_memTabWidget_currentChanged(int /*index*/) this->updateViews(); } -void MemoryWidget::updateViews() +void MemoryWidget::updateViews(RVA offset) { // Update only the selected view to improve performance @@ -1949,14 +1993,13 @@ void MemoryWidget::updateViews() QString cursor_addr_string = RAddressString(cursor_addr); + if (offset != RVA_INVALID) + next_disasm_top_offset = offset; + if (index == 0) { // Disasm - if (this->last_disasm_fcn != cursor_addr) - { - this->refreshDisasm(cursor_addr_string); - this->last_disasm_fcn = cursor_addr; - } + this->refreshDisasm(); } else if (index == 1) { diff --git a/src/widgets/memorywidget.h b/src/widgets/memorywidget.h index 2ecc6778..c9db0219 100644 --- a/src/widgets/memorywidget.h +++ b/src/widgets/memorywidget.h @@ -66,7 +66,7 @@ public slots: void replaceTextDisasm(QString txt); - void refreshDisasm(const QString &offset = QString()); + void refreshDisasm(); void refreshHexdump(const QString &where = QString()); @@ -92,7 +92,7 @@ public slots: void frameLoadFinished(bool ok); - void updateViews(); + void updateViews(RVA offset = RVA_INVALID); protected: void resizeEvent(QResizeEvent *event) override; @@ -105,7 +105,9 @@ private: ut64 hexdumpBottomOffset; QString last_fcn; - RVA last_disasm_fcn; + RVA disasm_top_offset; + RVA next_disasm_top_offset; + RVA last_graph_fcn; RVA last_hexdump_fcn; @@ -114,7 +116,10 @@ private: void setScrollMode(); + bool loadMoreDisassembly(); + private slots: + void on_globalSeekTo(RVA addr); void on_cursorAddressChanged(RVA addr); void highlightCurrentLine(); @@ -122,6 +127,7 @@ private slots: void highlightHexCurrentLine(); void highlightPreviewCurrentLine(); void highlightDecoCurrentLine(); + RVA readCurrentDisassemblyOffset(); void setFonts(QFont font); void highlightHexWords(const QString &str); @@ -138,6 +144,7 @@ private slots: void showHexASCIIContextMenu(const QPoint &pt); void on_actionSend_to_Notepad_triggered(); void on_actionDisasAdd_comment_triggered(); + void on_actionAddFlag_triggered(); void on_actionFunctionsRename_triggered(); void on_actionDisas_ShowHideBytes_triggered(); diff --git a/src/widgets/memorywidget.ui b/src/widgets/memorywidget.ui index 9915f99d..9bc79b6d 100644 --- a/src/widgets/memorywidget.ui +++ b/src/widgets/memorywidget.ui @@ -3036,6 +3036,11 @@ QToolTip { Show stack pointer + + + Add flag + + @@ -3050,7 +3055,7 @@ QToolTip { - +