From ebe33ffe8eabe10cf1af8fcd08b5b6c6ea684212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 28 Apr 2017 15:09:40 +0200 Subject: [PATCH] Refactor FunctionsWidget, new features and much more (#149) * Add RFunction struct and get functions from json * Fix QRCore::cmdj * Add Analysis command line argument * Replace MainWindow::current_address with cursur address * Use Cursor Address in MemoryWidget, Change some more String addresses to RVA * FunctionsWidget cleanup * Use QTreeView in FunctionsWidget * Re-enabled Nested Functions Widget * Nested Functions Tree View with Model * FunctionsWidget font, only one function highlighted * Removed explicit font sizes * FunctionsWidget re-enabled sorting and context menu * FunctionWidget Quick Filter * FunctionsWidget show decoration for imports * QRCore lists refactoring, Imports Icon * FunctionModel: Fix emitting dataChanged * Fix some smaller things * Fixes and cleanups * Raise MemoryDock on seek from Omnibar * FunctionsWidget: Remove margins * FunctionWidget: Restore correct Tooltip font * FunctionsWidget: import icon in separate column --- src/helpers.cpp | 6 +- src/helpers.h | 6 +- src/img/icons/import_light.svg | 53 +++ src/main.cpp | 34 +- src/mainwindow.cpp | 68 ++-- src/mainwindow.h | 18 +- src/optionsdialog.cpp | 19 +- src/optionsdialog.h | 2 + src/qrcore.cpp | 315 +++++++++++------ src/qrcore.h | 87 ++++- src/resources.qrc | 1 + src/widgets/commentswidget.cpp | 32 +- src/widgets/flagswidget.cpp | 2 +- src/widgets/flagswidget.ui | 14 +- src/widgets/functionswidget.cpp | 609 ++++++++++++++++++++------------ src/widgets/functionswidget.h | 87 ++++- src/widgets/functionswidget.ui | 89 ++--- src/widgets/importswidget.cpp | 10 +- src/widgets/importswidget.ui | 5 - src/widgets/memorywidget.cpp | 93 +++-- src/widgets/memorywidget.h | 13 +- src/widgets/omnibar.cpp | 2 +- src/widgets/relocswidget.cpp | 20 +- src/widgets/relocswidget.ui | 5 - src/widgets/stringswidget.cpp | 15 +- src/widgets/stringswidget.h | 2 + src/widgets/stringswidget.ui | 5 - src/widgets/symbolswidget.cpp | 19 +- src/widgets/symbolswidget.ui | 5 - 29 files changed, 1075 insertions(+), 561 deletions(-) create mode 100644 src/img/icons/import_light.svg diff --git a/src/helpers.cpp b/src/helpers.cpp index 05474fe1..361b7507 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -58,7 +58,7 @@ namespace qhelpers } } - void appendRow(QTreeWidget *tw, const QString &str, const QString &str2, + QTreeWidgetItem *appendRow(QTreeWidget *tw, const QString &str, const QString &str2, const QString &str3, const QString &str4, const QString &str5) { QTreeWidgetItem *tempItem = new QTreeWidgetItem(); @@ -75,9 +75,11 @@ namespace qhelpers tempItem->setText(5, str5); tw->insertTopLevelItem(0, tempItem); + + return tempItem; } - void setVerticalScrollMode(QTreeWidget *tw) + void setVerticalScrollMode(QAbstractItemView *tw) { tw->setVerticalScrollMode(scrollMode()); } diff --git a/src/helpers.h b/src/helpers.h index 442717a0..ef2dc160 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -7,6 +7,8 @@ class QPlainTextEdit; class QTextEdit; class QString; class QTreeWidget; +class QTreeWidgetItem; +class QAbstractItemView; namespace qhelpers { @@ -17,10 +19,10 @@ namespace qhelpers void adjustColumns(QTreeWidget *tw, int columnCount = 0, int padding = 0); - void appendRow(QTreeWidget *tw, const QString &str, const QString &str2 = QString(), + QTreeWidgetItem *appendRow(QTreeWidget *tw, const QString &str, const QString &str2 = QString(), const QString &str3 = QString(), const QString &str4 = QString(), const QString &str5 = QString()); - void setVerticalScrollMode(QTreeWidget *tw); + void setVerticalScrollMode(QAbstractItemView *tw); } #endif // HELPERS_H diff --git a/src/img/icons/import_light.svg b/src/img/icons/import_light.svg new file mode 100644 index 00000000..ec2e4e8f --- /dev/null +++ b/src/img/icons/import_light.svg @@ -0,0 +1,53 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 3ce22be4..8c79906d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,7 +27,13 @@ int main(int argc, char *argv[]) cmdParser.setApplicationDescription("A Qt and C++ GUI for radare2 reverse engineering framework"); cmdParser.addHelpOption(); cmdParser.addVersionOption(); - cmdParser.addPositionalArgument("filename", QCoreApplication::translate("main", "Filename to open.")); + cmdParser.addPositionalArgument("filename", QObject::tr("Filename to open.")); + + QCommandLineOption analOption({"a", "anal"}, + QObject::tr("Automatically start analysis. Needs filename to be specified. May be a value between 0 and 4."), + QObject::tr("level")); + cmdParser.addOption(analOption); + cmdParser.process(a); QStringList args = cmdParser.positionalArguments(); @@ -47,8 +53,31 @@ int main(int argc, char *argv[]) return 1; } + + + bool analLevelSpecified = false; + int analLevel = 0; + + if(cmdParser.isSet(analOption)) + { + analLevel = cmdParser.value(analOption).toInt(&analLevelSpecified); + + if(!analLevelSpecified || analLevel < 0 || analLevel > 4) + { + printf("%s\n", QObject::tr("Invalid Analysis Level. May be a value between 0 and 4.").toLocal8Bit().constData()); + return 1; + } + } + + if (args.empty()) { + if(analLevelSpecified) + { + printf("%s\n", QObject::tr("Filename must be specified to start analysis automatically.").toLocal8Bit().constData()); + return 1; + } + NewFileDialog *n = new NewFileDialog(); n->setAttribute(Qt::WA_DeleteOnClose); n->show(); @@ -58,6 +87,9 @@ int main(int argc, char *argv[]) OptionsDialog *o = new OptionsDialog(args[0]); o->setAttribute(Qt::WA_DeleteOnClose); o->show(); + + if(analLevelSpecified) + o->setupAndStartAnalysis(analLevel); } return a.exec(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ba7e83df..023d2f78 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -110,7 +110,7 @@ MainWindow::MainWindow(QWidget *parent, QRCore *kore) : ui->setupUi(this); doLock = false; - this->current_address = "entry0"; + this->cursor_address = core->getOffset(); registerCustomFonts(); @@ -721,24 +721,50 @@ void MainWindow::on_actionRefresh_Panels_triggered() this->updateFrames(); } -void MainWindow::seek(const QString &offset, const QString &name) + +void MainWindow::seek(const QString &offset, const QString &name, bool raise_memory_dock) { - if (offset.length() == 0) + // TODO: remove this method and use the one with RVA only! + + if(offset.length() < 2) return; + + bool ok; + RVA addr = offset.mid(2).toULongLong(&ok, 16); + if(!ok) + return; + + seek(addr, name, raise_memory_dock); +} + + +void MainWindow::seek(const RVA offset, const QString &name, bool raise_memory_dock) +{ if (name != NULL) { this->memoryDock->setWindowTitle(name); - this->current_address = name; + //this->current_address = name; } this->hexdumpTopOffset = 0; this->hexdumpBottomOffset = 0; core->seek(offset); + setCursorAddress(offset); refreshMem(offset); this->memoryDock->disasTextEdit->setFocus(); + + // Rise and shine baby! + if(raise_memory_dock) + this->memoryDock->raise(); } -void MainWindow::refreshMem(const QString &offset) +void MainWindow::refreshMem() +{ + this->memoryDock->updateViews(); + +} + +void MainWindow::refreshMem(RVA offset) { //add_debug_output("Refreshing to: " + off); //graphicsBar->refreshColorBar(); @@ -747,20 +773,18 @@ void MainWindow::refreshMem(const QString &offset) this->memoryDock->refreshHexdump(off); this->memoryDock->create_graph(off); */ - this->memoryDock->updateViews(); - this->memoryDock->get_refs_data(offset); - this->memoryDock->setFcnName(offset); + refreshMem(); + this->memoryDock->get_refs_data(RAddressString(offset)); + //this->memoryDock->setFcnName(offset); } void MainWindow::on_backButton_clicked() { + QList seek_history = core->getSeekHistory(); this->core->cmd("s-"); - QString back_offset = this->core->cmd("s=").split(" > ").last().trimmed(); - if (back_offset != "") - { - QString fcn = this->core->cmdFunctionAt(back_offset); - this->seek(this->memoryDock->normalizeAddr(back_offset), fcn); - } + RVA offset = this->core->getOffset(); + QString fcn = this->core->cmdFunctionAt(QString::number(offset)); + this->seek(offset, fcn); } void MainWindow::on_actionCalculator_triggered() @@ -907,6 +931,7 @@ void MainWindow::add_output(QString msg) void MainWindow::add_debug_output(QString msg) { + printf("debug output: %s\n", msg.toLocal8Bit().constData()); ui->consoleOutputTextEdit->appendHtml(" [DEBUG]:\t" + msg + ""); ui->consoleOutputTextEdit->verticalScrollBar()->setValue(ui->consoleOutputTextEdit->verticalScrollBar()->maximum()); } @@ -996,12 +1021,9 @@ void MainWindow::on_actionDashboard_triggered() void MainWindow::on_actionForward_triggered() { this->core->cmd("s+"); - QString offset = this->core->cmd("s=").split(" > ").last().trimmed(); - if (offset != "") - { - this->add_debug_output(offset); - this->seek(offset); - } + RVA offset = core->getOffset(); + this->add_debug_output(QString::number(offset)); + this->seek(offset); } void MainWindow::toggleResponsive(bool maybe) @@ -1035,6 +1057,12 @@ void MainWindow::on_actionQuit_triggered() close(); } +void MainWindow::setCursorAddress(RVA addr) +{ + this->cursor_address = addr; + emit cursorAddressChanged(addr); +} + void MainWindow::refreshVisibleDockWidgets() { // There seems to be no convenience function to check if a QDockWidget diff --git a/src/mainwindow.h b/src/mainwindow.h index 0f123842..3e2fc544 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -47,7 +47,6 @@ public: Notepad *notepadDock; bool responsive; - QString current_address; explicit MainWindow(QWidget *parent = 0, QRCore *kore = nullptr); ~MainWindow(); @@ -56,8 +55,9 @@ public: void closeEvent(QCloseEvent *event); void readSettings(); void setFilename(QString fn); - void setCore(QRCore *core); - void seek(const QString &offset, const QString &name = NULL); + //void setCore(QRCore *core); + void seek(const QString &offset, const QString &name = NULL, bool raise_memory_dock = false); + void seek(const RVA offset, const QString &name = NULL, bool raise_memory_dock = false); void updateFrames(); void refreshFunctions(); void refreshComments(); @@ -70,6 +70,9 @@ public: void toggleSideBarTheme(); void refreshOmniBar(const QStringList &flags); +signals: + void cursorAddressChanged(RVA address); + public slots: void dark(); @@ -185,7 +188,8 @@ private: SideBar *sideBar; bool doLock; - void refreshMem(const QString &offset = QString()); + void refreshMem(); + void refreshMem(RVA offset); ut64 hexdumpTopOffset; ut64 hexdumpBottomOffset; QString filename; @@ -207,6 +211,12 @@ private: QAction *sidebar_action; SectionsDock *sectionsDock; WebServerThread webserverThread; + + RVA cursor_address; + +public: + RVA getCursorAddress() const { return cursor_address; } + void setCursorAddress(RVA addr); }; #endif // MAINWINDOW_H diff --git a/src/optionsdialog.cpp b/src/optionsdialog.cpp index fbd9a77c..135e4755 100644 --- a/src/optionsdialog.cpp +++ b/src/optionsdialog.cpp @@ -61,13 +61,10 @@ OptionsDialog::~OptionsDialog() delete ui; } -void OptionsDialog::on_closeButton_clicked() +void OptionsDialog::setupAndStartAnalysis(int level) { - close(); -} + ui->analSlider->setValue(level); -void OptionsDialog::on_okButton_clicked() -{ this->setEnabled(0); ui->logo->setEnabled(true); @@ -199,7 +196,17 @@ void OptionsDialog::on_okButton_clicked() // Threads stuff // connect signal/slot - analThread.start(core, ui->analSlider->value()); + analThread.start(core, level); +} + +void OptionsDialog::on_closeButton_clicked() +{ + close(); +} + +void OptionsDialog::on_okButton_clicked() +{ + setupAndStartAnalysis(ui->analSlider->value()); } void OptionsDialog::anal_finished() diff --git a/src/optionsdialog.h b/src/optionsdialog.h index a37a0838..5d501eb8 100644 --- a/src/optionsdialog.h +++ b/src/optionsdialog.h @@ -24,6 +24,8 @@ public: RAnalFunction functionAt(ut64 addr); QStringList asm_plugins; + void setupAndStartAnalysis(int level); + private slots: void on_closeButton_clicked(); diff --git a/src/qrcore.cpp b/src/qrcore.cpp index a2c2cf1a..a9fe6463 100644 --- a/src/qrcore.cpp +++ b/src/qrcore.cpp @@ -222,8 +222,20 @@ QJsonDocument QRCore::cmdj(const QString &str) { CORE_LOCK(); QByteArray cmd = str.toUtf8(); + char *res = r_core_cmd_str(this->core_, cmd.constData()); - QJsonDocument doc = res ? QJsonDocument::fromJson(QByteArray(res)) : QJsonDocument(); + + QString resString = QString(res); + + QJsonParseError jsonError; + QJsonDocument doc = res ? QJsonDocument::fromJson(resString.toUtf8(), &jsonError) : QJsonDocument(); + + if(jsonError.error != QJsonParseError::NoError) + { + eprintf("Failed to parse JSON: %s\n", jsonError.errorString().toLocal8Bit().constData()); + eprintf("%s\n", resString.toLocal8Bit().constData()); + } + r_mem_free(res); return doc; } @@ -345,6 +357,13 @@ void QRCore::analyze(int level) void QRCore::renameFunction(QString prev_name, QString new_name) { cmd("afn " + new_name + " " + prev_name); + emit functionRenamed(prev_name, new_name); +} + +void QRCore::setComment(RVA addr, QString cmt) +{ + //r_meta_add (core->anal, 'C', addr, 1, cmt.toUtf8()); + cmd("CC " + cmt + " @ " + QString::number(addr)); } void QRCore::setComment(QString addr, QString cmt) @@ -360,24 +379,6 @@ void QRCore::delComment(ut64 addr) //cmd (QString("CC-@")+addr); } -QList> QRCore::getComments() -{ - QList> ret; - QString comments = cmd("CC~CCu"); - for (QString line : comments.split("\n")) - { - QStringList fields = line.split("CCu"); - if (fields.length() == 2) - { - QList tmp = QList(); - tmp << fields[1].split("\"")[1].trimmed(); - tmp << fields[0].trimmed(); - ret << tmp; - } - } - return ret; -} - QMap>> QRCore::getNestedComments() { QMap>> ret; @@ -404,10 +405,12 @@ void QRCore::seek(QString addr) seek(this->math(addr.toUtf8().constData())); } -void QRCore::seek(ut64 addr) + + +void QRCore::seek(ut64 offset) { CORE_LOCK(); - r_core_seek(this->core_, addr, true); + r_core_seek(this->core_, offset, true); } bool QRCore::tryFile(QString path, bool rw) @@ -457,84 +460,11 @@ QList QRCore::getList(const QString &type, const QString &subtype) if (ft && *ft) ret << ft; } - else if (subtype == "imports") - { - QJsonArray importsArray = cmdj("iij").array(); - - foreach (QJsonValue value, importsArray) - { - QJsonObject importObject = value.toObject(); - unsigned long plt = (unsigned long)importObject["plt"].toVariant().toULongLong(); - int ordinal = importObject["ordinal"].toInt(); - - QString final = QString("%1,%2,%3,%4,%5,").arg( - QString::asprintf("%#o", ordinal), - QString::asprintf("%#010lx", plt), - importObject["bind"].toString(), - importObject["type"].toString(), - importObject["name"].toString()); - - - ret << final; - } - } else if (subtype == "entrypoints") { if (math("entry0") != 0) ret << "entry0"; } - else if (subtype == "relocs") - { - RBinReloc *br; - if (core_ && core_->bin && core_->bin->cur && core_->bin->cur->o) - { - QRListForeach(core_->bin->cur->o->relocs, it, RBinReloc, br) - { - if (br->import) - { - // TODO: we want the offset too! - QString type = (br->additive ? "ADD_" : "SET_") + QString::number(br->type); - ret << QString("0x%1,%2,%3").arg(QString::number(br->vaddr, 16), type, br->import->name); - } - else - { - // TODO: we want the offset too! - QString type = (br->additive ? "ADD_" : "SET_") + QString::number(br->type); - ret << QString("0x%1,%2,reloc_%3").arg(QString::number(br->vaddr, 16), type, QString::number(br->vaddr, 16)); - } - } - } - } - else if (subtype == "symbols") - { - RBinSymbol *bs; - if (core_ && core_->bin && core_->bin->cur && core_->bin->cur->o) - { - QRListForeach(core_->bin->cur->o->symbols, it, RBinSymbol, bs) - { - QString type = QString(bs->bind) + " " + QString(bs->type); - ret << QString("0x%1,%2,%3").arg(QString::number(bs->vaddr, 16), type, bs->name); - } - /* list entrypoints as symbols too */ - int n = 0; - RBinAddr *entry; - QRListForeach(core_->bin->cur->o->entries, it, RBinAddr, entry) - { - ret << QString("0x%1,%2,%3%4").arg(QString::number(entry->vaddr, 16), "entry", "entry", QString::number(n++)); - } - } - } - else if (subtype == "strings") - { - RBinString *bs; - if (core_ && core_->bin && core_->bin->cur && core_->bin->cur->o) - { - QRListForeach(core_->bin->cur->o->strings, it, RBinString, bs) - { - ret << QString("0x%1,%2").arg(QString::number(bs->vaddr, 16), bs->string); - } - } - } } else if (type == "asm") { @@ -566,18 +496,6 @@ QList QRCore::getList(const QString &type, const QString &subtype) ret << ap->name; } } - else if (subtype == "functions") - { - QString funcs = cmd("afl"); - QStringList lines = funcs.split("\n"); - for (auto i : lines) - { - if (i != "") - { - ret << i.replace(" ", ",").replace(",,", ",").replace(",,", ",").replace(",,", ","); - } - } - } } else if (type == "flagspaces") { @@ -744,10 +662,15 @@ QString QRCore::cmdFunctionAt(QString addr) QString ret; //afi~name:1[1] @ 0x08048e44 //ret = cmd("afi~name[1] @ " + addr); - ret = cmd("fd @ " + addr + "~[0]"); + ret = cmd(QString("fd @ ") + addr + "~[0]"); return ret.trimmed(); } +QString QRCore::cmdFunctionAt(RVA addr) +{ + return cmdFunctionAt(QString::number(addr)); +} + int QRCore::get_size() { CORE_LOCK(); @@ -922,3 +845,181 @@ void QRCore::setSettings() cmd("ec graph.false rgb:FF6666"); cmd("ec graph.trufae rgb:4183D7"); } + + + + + +QList QRCore::getSeekHistory() +{ + CORE_LOCK(); + QList ret; + + QJsonArray jsonArray = cmdj("sj").array(); + foreach(QJsonValue value, jsonArray) + ret << value.toVariant().toULongLong(); + + return ret; +} + +QList QRCore::getAllFunctions() +{ + CORE_LOCK(); + QList ret; + + QJsonArray jsonArray = cmdj("aflj").array(); + + foreach(QJsonValue value, jsonArray) + { + QJsonObject jsonObject = value.toObject(); + + FunctionDescription function; + + function.offset = (RVA)jsonObject["offset"].toVariant().toULongLong(); + function.size = (RVA)jsonObject["size"].toVariant().toULongLong(); + function.name = jsonObject["name"].toString(); + + ret << function; + } + + return ret; +} + + +QList QRCore::getAllImports() +{ + CORE_LOCK(); + QList ret; + + QJsonArray importsArray = cmdj("iij").array(); + + foreach(QJsonValue value, importsArray) + { + QJsonObject importObject = value.toObject(); + + ImportDescription import; + + import.plt = importObject["plt"].toVariant().toULongLong(); + import.ordinal = importObject["ordinal"].toInt(); + import.bind = importObject["bind"].toString(); + import.type = importObject["type"].toString(); + import.name = importObject["name"].toString(); + + ret << import; + } + + return ret; +} + + +QList QRCore::getAllSymbols() +{ + CORE_LOCK(); + RListIter *it; + + QList ret; + + RBinSymbol *bs; + if (core_ && core_->bin && core_->bin->cur && core_->bin->cur->o) + { + QRListForeach(core_->bin->cur->o->symbols, it, RBinSymbol, bs) + { + QString type = QString(bs->bind) + " " + QString(bs->type); + SymbolDescription symbol; + symbol.vaddr = bs->vaddr; + symbol.name = QString(bs->name); + symbol.bind = QString(bs->bind); + symbol.type = QString(bs->type); + ret << symbol; + } + + /* list entrypoints as symbols too */ + int n = 0; + RBinAddr *entry; + QRListForeach(core_->bin->cur->o->entries, it, RBinAddr, entry) + { + SymbolDescription symbol; + symbol.vaddr = entry->vaddr; + symbol.name = QString("entry") + QString::number(n++); + symbol.bind = ""; + symbol.type = "entry"; + ret << symbol; + } + } + + return ret; +} + + +QList QRCore::getAllComments(QString filterType) +{ + CORE_LOCK(); + QList ret; + + QJsonArray commentsArray = cmdj("CCj").array(); + for(QJsonValue value : commentsArray) + { + QJsonObject commentObject = value.toObject(); + + QString type = commentObject["type"].toString(); + if(type != filterType) + continue; + + CommentDescription comment; + comment.offset = commentObject["offset"].toVariant().toULongLong(); + comment.name = commentObject["name"].toString(); + + ret << comment; + } + return ret; +} + +QList QRCore::getAllRelocs() +{ + CORE_LOCK(); + RListIter *it; + QList ret; + + RBinReloc *br; + if (core_ && core_->bin && core_->bin->cur && core_->bin->cur->o) + { + QRListForeach(core_->bin->cur->o->relocs, it, RBinReloc, br) + { + RelocDescription reloc; + + reloc.vaddr = br->vaddr; + reloc.paddr = br->paddr; + reloc.type = (br->additive ? "ADD_" : "SET_") + QString::number(br->type); + + if (br->import) + reloc.name = br->import->name; + else + reloc.name = QString("reloc_%1").arg(QString::number(br->vaddr, 16)); + + ret << reloc; + } + } + + return ret; +} + +QList QRCore::getAllStrings() +{ + CORE_LOCK(); + RListIter *it; + QList ret; + + RBinString *bs; + if (core_ && core_->bin && core_->bin->cur && core_->bin->cur->o) + { + QRListForeach(core_->bin->cur->o->strings, it, RBinString, bs) + { + StringDescription str; + str.vaddr = bs->vaddr; + str.string = bs->string; + ret << str; + } + } + + return ret; +} \ No newline at end of file diff --git a/src/qrcore.h b/src/qrcore.h index 81c9becc..73d36434 100644 --- a/src/qrcore.h +++ b/src/qrcore.h @@ -44,13 +44,82 @@ public: #define QNOTUSED(x) do { (void)(x); } while ( 0 ); +typedef ut64 RVA; + +inline QString RAddressString(RVA addr) +{ + return QString::asprintf("%#010llx", addr); +} + +inline QString RSizeString(RVA size) +{ + return QString::asprintf("%lld", size); +} + +struct FunctionDescription +{ + RVA offset; + RVA size; + QString name; + + bool contains(RVA addr) const { return addr >= offset && addr < offset + size; } +}; + +struct ImportDescription +{ + RVA plt; + int ordinal; + QString bind; + QString type; + QString name; +}; + +struct SymbolDescription +{ + RVA vaddr; + QString bind; + QString type; + QString name; +}; + +struct CommentDescription +{ + RVA offset; + QString name; +}; + +struct RelocDescription +{ + RVA vaddr; + RVA paddr; + QString type; + QString name; +}; + +struct StringDescription +{ + RVA vaddr; + QString string; +}; + +Q_DECLARE_METATYPE(FunctionDescription) +Q_DECLARE_METATYPE(ImportDescription) +Q_DECLARE_METATYPE(SymbolDescription) +Q_DECLARE_METATYPE(CommentDescription) +Q_DECLARE_METATYPE(RelocDescription) +Q_DECLARE_METATYPE(StringDescription) + class QRCore : public QObject { Q_OBJECT + public: QString projectPath; + explicit QRCore(QObject *parent = 0); ~QRCore(); + + RVA getOffset() const { return core_->offset; } QList getFunctionXrefs(ut64 addr); QList getFunctionRefs(ut64 addr, char type); int getCycloComplex(ut64 addr); @@ -61,27 +130,27 @@ public: QString cmd(const QString &str); 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); - QList> getComments(); QMap>> getNestedComments(); void setOptions(QString key); bool loadFile(QString path, uint64_t loadaddr = 0LL, uint64_t mapaddr = 0LL, bool rw = false, int va = 0, int bits = 0, int idx = 0, bool loadbin = false); bool tryFile(QString path, bool rw); void analyze(int level); void seek(QString addr); - void seek(ut64 addr); + void seek(ut64 offset); ut64 math(const QString &expr); QString itoa(ut64 num, int rdx = 16); QString config(const QString &k, const QString &v = NULL); int config(const QString &k, int v); - QList getList(const QString &type, const QString &subtype = ""); QString assemble(const QString &code); QString disassemble(const QString &hex); void setDefaultCPU(); void setCPU(QString arch, QString cpu, int bits, bool temporary = false); RAnalFunction *functionAt(ut64 addr); QString cmdFunctionAt(QString addr); + QString cmdFunctionAt(RVA addr); /* sdb */ QList sdbList(QString path); QList sdbListKeys(QString path); @@ -103,12 +172,24 @@ public: QList regs; void setSettings(); + QList getList(const QString &type, const QString &subtype = ""); + + QList getSeekHistory(); + QList getAllFunctions(); + QList getAllImports(); + QList getAllSymbols(); + QList getAllComments(QString type); + QList getAllRelocs(); + QList getAllStrings(); + RCoreLocked core() const; /* fields */ Sdb *db; + signals: + void functionRenamed(QString prev_name, QString new_name); public slots: diff --git a/src/resources.qrc b/src/resources.qrc index b0e18c09..ee80ab66 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -68,6 +68,7 @@ html/bar.html html/stats.html img/icons/spin_grey.png + img/icons/import_light.svg html/utils.js html/radar.html diff --git a/src/widgets/commentswidget.cpp b/src/widgets/commentswidget.cpp index 5ae5d7c6..a9185131 100644 --- a/src/widgets/commentswidget.cpp +++ b/src/widgets/commentswidget.cpp @@ -52,11 +52,9 @@ void CommentsWidget::on_commentsTreeWidget_itemDoubleClicked(QTreeWidgetItem *it QNOTUSED(column); // Get offset and name of item double clicked - // TODO: use this info to change disasm contents - QString offset = item->text(1); - QString name = item->text(2); - this->main->add_debug_output(offset + ": " + name); - this->main->seek(offset, name); + CommentDescription comment = item->data(0, Qt::UserRole).value(); + this->main->add_debug_output(RAddressString(comment.offset) + ": " + comment.name); + this->main->seek(comment.offset, comment.name, true); } void CommentsWidget::on_toolButton_clicked() @@ -122,32 +120,36 @@ void CommentsWidget::resizeEvent(QResizeEvent *event) QDockWidget::resizeEvent(event); } + + void CommentsWidget::refreshTree() { - ui->commentsTreeWidget->clear(); - const QList> &comments = main->core->getComments(); - for (const QList &comment : comments) + ui->nestedCmtsTreeWidget->clear(); + QList comments = this->main->core->getAllComments("CCu"); + + for (CommentDescription comment : comments) { - //this->main->add_debug_output(comment[1]); - QString fcn_name = this->main->core->cmdFunctionAt(comment[1]); - qhelpers::appendRow(ui->commentsTreeWidget, comment[1], fcn_name, QString(comment[0]).remove('"')); + //this->main->add_debug_output(RAddressString(comment.offset)); + QString fcn_name = this->main->core->cmdFunctionAt(comment.offset); + QTreeWidgetItem *item = qhelpers::appendRow(ui->commentsTreeWidget, RAddressString(comment.offset), fcn_name, comment.name); + item->setData(0, Qt::UserRole, QVariant::fromValue(comment)); } qhelpers::adjustColumns(ui->commentsTreeWidget); // Add nested comments ui->nestedCmtsTreeWidget->clear(); - const QMap>> &cmts = main->core->getNestedComments(); + QMap>> cmts = this->main->core->getNestedComments(); for (auto cmt : cmts.keys()) { QTreeWidgetItem *item = new QTreeWidgetItem(ui->nestedCmtsTreeWidget); item->setText(0, cmt); - const QList> &meow = cmts.value(cmt); + QList> meow = cmts.value(cmt); for (int i = 0; i < meow.size(); ++i) { - const QList &tmp = meow.at(i); + QList tmp = meow.at(i); QTreeWidgetItem *it = new QTreeWidgetItem(); it->setText(0, tmp[1]); - it->setText(1, QString(tmp[0]).remove('"')); + it->setText(1, tmp[0].remove('"')); item->addChild(it); } ui->nestedCmtsTreeWidget->addTopLevelItem(item); diff --git a/src/widgets/flagswidget.cpp b/src/widgets/flagswidget.cpp index bf270a43..570150a9 100644 --- a/src/widgets/flagswidget.cpp +++ b/src/widgets/flagswidget.cpp @@ -47,7 +47,7 @@ void FlagsWidget::on_flagsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, in QString offset = item->text(2); QString name = item->text(3); - this->main->seek(offset, name); + this->main->seek(offset, name, true); } void FlagsWidget::on_flagspaceCombo_currentTextChanged(const QString &arg1) diff --git a/src/widgets/flagswidget.ui b/src/widgets/flagswidget.ui index dd409324..841a1e69 100644 --- a/src/widgets/flagswidget.ui +++ b/src/widgets/flagswidget.ui @@ -6,7 +6,7 @@ 0 0 - 400 + 463 300 @@ -71,11 +71,6 @@ - - - 12 - - QTreeWidget::item { @@ -113,7 +108,7 @@ QTreeWidget::item:selected false - 5 + 4 @@ -135,11 +130,6 @@ QTreeWidget::item:selected Name - - - Comment - - diff --git a/src/widgets/functionswidget.cpp b/src/widgets/functionswidget.cpp index 36492f46..ea50086b 100644 --- a/src/widgets/functionswidget.cpp +++ b/src/widgets/functionswidget.cpp @@ -7,10 +7,316 @@ #include "dialogs/renamedialog.h" #include "dialogs/xrefsdialog.h" -#include +#include #include #include #include +#include + +FunctionModel::FunctionModel(QList *functions, QSet *import_addresses, bool nested, QFont default_font, QFont highlight_font, MainWindow *main, QObject *parent) + : functions(functions), + import_addresses(import_addresses), + main(main), + nested(nested), + default_font(default_font), + highlight_font(highlight_font), + QAbstractItemModel(parent) +{ + current_index = -1; + + connect(main, SIGNAL(cursorAddressChanged(RVA)), this, SLOT(cursorAddressChanged(RVA))); + connect(main->core, SIGNAL(functionRenamed(QString, QString)), this, SLOT(functionRenamed(QString, QString))); +} + +QModelIndex FunctionModel::index(int row, int column, const QModelIndex &parent) const +{ + if(!parent.isValid()) + return createIndex(row, column, (quintptr)0); // root function nodes have id = 0 + + return createIndex(row, column, (quintptr)(parent.row() + 1)); // sub-nodes have id = function index + 1 +} + +QModelIndex FunctionModel::parent(const QModelIndex &index) const +{ + if(!index.isValid() || index.column() != 0) + return QModelIndex(); + + if(index.internalId() == 0) // root function node + return QModelIndex(); + else // sub-node + return this->index((int)(index.internalId()-1), 0); +} + +int FunctionModel::rowCount(const QModelIndex &parent) const +{ + if(!parent.isValid()) + return functions->count(); + + if(nested) + { + if(parent.internalId() == 0) + return 3; // sub-nodes for nested functions + return 0; + } + else + return 0; +} + +int FunctionModel::columnCount(const QModelIndex &parent) const +{ + if(nested) + return 1; + else + return 4; +} + + +QVariant FunctionModel::data(const QModelIndex &index, int role) const +{ + if(!index.isValid()) + return QVariant(); + + int function_index; + bool subnode; + if(index.internalId() != 0) // sub-node + { + function_index = index.parent().row(); + subnode = true; + } + else // root function node + { + function_index = index.row(); + subnode = false; + } + + const FunctionDescription &function = functions->at(function_index); + + if(function_index >= functions->count()) + return QVariant(); + + switch(role) + { + case Qt::DisplayRole: + if(nested) + { + if(subnode) + { + switch(index.row()) + { + case 0: + return tr("Offset: %1").arg(RAddressString(function.offset)); + case 1: + return tr("Size: %1").arg(RSizeString(function.size)); + case 2: + return tr("Import: %1").arg(import_addresses->contains(function.offset) ? tr("true") : tr("false")); + default: + return QVariant(); + } + } + else + return function.name; + } + else + { + switch(index.column()) + { + case 0: + return RAddressString(function.offset); + case 1: + return RSizeString(function.size); + case 3: + return function.name; + default: + return QVariant(); + } + } + + case Qt::DecorationRole: + if(import_addresses->contains(function.offset) && + (nested ? false :index.column() == 2)) + return QIcon(":/img/icons/import_light.svg"); + return QVariant(); + + case Qt::FontRole: + if(current_index == function_index) + return highlight_font; + return default_font; + + case Qt::ToolTipRole: + { + QList info = main->core->cmd("afi @ " + function.name).split("\n"); + if (info.length() > 2) + { + QString size = info[4].split(" ")[1]; + QString complex = info[8].split(" ")[1]; + QString bb = info[11].split(" ")[1]; + return QString("Summary:\n\n Size: " + size + + "\n Cyclomatic complexity: " + complex + + "\n Basic blocks: " + bb + + "\n\nDisasm preview:\n\n" + main->core->cmd("pdi 10 @ " + function.name) + + "\nStrings:\n\n" + main->core->cmd("pdsf @ " + function.name)); + } + return QVariant(); + } + + case FunctionDescriptionRole: + return QVariant::fromValue(function); + + case IsImportRole: + return import_addresses->contains(function.offset); + + default: + return QVariant(); + } +} + +QVariant FunctionModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if(role == Qt::DisplayRole && orientation == Qt::Horizontal) + { + if(nested) + { + return tr("Name"); + } + else + { + switch (section) + { + case 0: + return tr("Offset"); + case 1: + return tr("Size"); + case 2: + return tr("Imp."); + case 3: + return tr("Name"); + default: + return QVariant(); + } + } + } + + return QVariant(); +} + +void FunctionModel::beginReloadFunctions() +{ + beginResetModel(); +} + +void FunctionModel::endReloadFunctions() +{ + updateCurrentIndex(); + endResetModel(); +} + +void FunctionModel::cursorAddressChanged(RVA) +{ + updateCurrentIndex(); + emit dataChanged(index(0, 0), index(rowCount()-1, columnCount()-1)); +} + +void FunctionModel::updateCurrentIndex() +{ + RVA addr = main->getCursorAddress(); + + int index = -1; + RVA offset = 0; + + for(int i=0; icount(); i++) + { + const FunctionDescription &function = functions->at(i); + + if(function.contains(addr) + && function.offset >= offset) + { + offset = function.offset; + index = i; + } + } + + current_index = index; +} + +void FunctionModel::functionRenamed(QString prev_name, QString new_name) +{ + for(int i=0; icount(); i++) + { + FunctionDescription &function = (*functions)[i]; + if(function.name == prev_name) + { + function.name = new_name; + emit dataChanged(index(i, 0), index(i, columnCount()-1)); + } + } +} + + + + +FunctionSortFilterProxyModel::FunctionSortFilterProxyModel(FunctionModel *source_model, QObject *parent) + : QSortFilterProxyModel(parent) +{ + setSourceModel(source_model); + setFilterCaseSensitivity(Qt::CaseInsensitive); + setSortCaseSensitivity(Qt::CaseInsensitive); +} + +bool FunctionSortFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const +{ + QModelIndex index = sourceModel()->index(row, 0, parent); + FunctionDescription function = index.data(FunctionModel::FunctionDescriptionRole).value(); + return function.name.contains(filterRegExp()); +} + + +bool FunctionSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + if(!left.isValid() || !right.isValid()) + return false; + + if(left.parent().isValid() || right.parent().isValid()) + return false; + + FunctionDescription left_function = left.data(FunctionModel::FunctionDescriptionRole).value(); + FunctionDescription right_function = right.data(FunctionModel::FunctionDescriptionRole).value(); + + + if(static_cast(sourceModel())->isNested()) + { + return left_function.name < right_function.name; + } + else + { + switch (left.column()) + { + case 0: + return left_function.offset < right_function.offset; + case 1: + if (left_function.size != right_function.size) + return left_function.size < right_function.size; + break; + case 2: + { + bool left_is_import = left.data(FunctionModel::IsImportRole).toBool(); + bool right_is_import = right.data(FunctionModel::IsImportRole).toBool(); + if(!left_is_import && right_is_import) + return true; + break; + } + case 3: + return left_function.name < right_function.name; + default: + return false; + } + + return left_function.offset < right_function.offset; + } +} + + + + FunctionsWidget::FunctionsWidget(MainWindow *main, QWidget *parent) : @@ -20,15 +326,33 @@ FunctionsWidget::FunctionsWidget(MainWindow *main, QWidget *parent) : { ui->setupUi(this); - ui->functionsTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); - //ui->functionsTreeWidget->setFont(QFont("Monospace", 8)); + // Radare core found in: + this->main = main; + + QFontInfo font_info = ui->functionsTreeView->fontInfo(); + QFont default_font = QFont(font_info.family(), font_info.pointSize()); + QFont highlight_font = QFont(font_info.family(), font_info.pointSize(), QFont::Bold); + + function_model = new FunctionModel(&functions, &import_addresses, false, default_font, highlight_font, main, this); + function_proxy_model = new FunctionSortFilterProxyModel(function_model, this); + connect(ui->filterLineEdit, SIGNAL(textChanged(const QString &)), function_proxy_model, SLOT(setFilterWildcard(const QString &))); + ui->functionsTreeView->setModel(function_proxy_model); + + nested_function_model = new FunctionModel(&functions, &import_addresses, true, default_font, highlight_font, main, this); + nested_function_proxy_model = new FunctionSortFilterProxyModel(nested_function_model, this); + connect(ui->filterLineEdit, SIGNAL(textChanged(const QString &)), nested_function_proxy_model, SLOT(setFilterWildcard(const QString &))); + ui->nestedFunctionsTreeView->setModel(nested_function_proxy_model); + + // Set Functions context menu - connect(ui->functionsTreeWidget, SIGNAL(customContextMenuRequested(const QPoint &)), + connect(ui->functionsTreeView, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showFunctionsContextMenu(const QPoint &))); - connect(ui->nestedFunctionsTree, SIGNAL(customContextMenuRequested(const QPoint &)), + connect(ui->nestedFunctionsTreeView, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showFunctionsContextMenu(const QPoint &))); - ui->functionsTreeWidget->hideColumn(0); + + connect(ui->functionsTreeView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(on_functionsTreeView_itemDoubleClicked(const QModelIndex &))); + connect(ui->nestedFunctionsTreeView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(on_functionsTreeView_itemDoubleClicked(const QModelIndex &))); // Hide the tabs QTabBar *tabs = ui->tabWidget->tabBar(); @@ -50,8 +374,7 @@ FunctionsWidget::~FunctionsWidget() void FunctionsWidget::setup() { setScrollMode(); - - fillFunctions(); + refreshTree(); } void FunctionsWidget::refresh() @@ -59,72 +382,46 @@ void FunctionsWidget::refresh() setup(); } -void FunctionsWidget::fillFunctions() +void FunctionsWidget::refreshTree() { - ui->functionsTreeWidget->clear(); - ui->nestedFunctionsTree->clear(); - for (auto i : this->main->core->getList("anal", "functions")) - { - QStringList a = i.split(","); - // off,sz,unk,name - // "0x0804ada3,1,13,,fcn.0804ada3" - // "0x0804ad4a,6,,1,,fcn.0804ad4a" - if (a.length() == 5) - { - // Add list function - qhelpers::appendRow(ui->functionsTreeWidget, a[0], a[1], a[4]); - // Add nested function - QTreeWidgetItem *item = new QTreeWidgetItem(ui->nestedFunctionsTree); - item->setText(0, a[4]); - QTreeWidgetItem *size_it = new QTreeWidgetItem(); - size_it->setText(0, "Offset: " + a[0]); - item->addChild(size_it); - QTreeWidgetItem *off_it = new QTreeWidgetItem(); - off_it->setText(0, "Size: " + a[1]); - item->addChild(off_it); - ui->nestedFunctionsTree->addTopLevelItem(item); - } - else if (a.length() == 6) - { - // Add list function - qhelpers::appendRow(ui->functionsTreeWidget, a[0], a[1], a[5]); - // Add nested function - QTreeWidgetItem *item = new QTreeWidgetItem(ui->nestedFunctionsTree); - item->setText(0, a[5]); - QTreeWidgetItem *size_it = new QTreeWidgetItem(); - size_it->setText(0, "Offset: " + a[0]); - item->addChild(size_it); - QTreeWidgetItem *off_it = new QTreeWidgetItem(); - off_it->setText(0, "Size: " + a[1]); - item->addChild(off_it); - ui->nestedFunctionsTree->addTopLevelItem(item); - } - else - { - qDebug() << "fillFunctions()" << a; - } - } - ui->functionsTreeWidget->sortByColumn(3, Qt::AscendingOrder); - ui->nestedFunctionsTree->sortByColumn(0, Qt::AscendingOrder); - qhelpers::adjustColumns(ui->functionsTreeWidget); + function_model->beginReloadFunctions(); + nested_function_model->beginReloadFunctions(); - this->addTooltips(); + functions = this->main->core->getAllFunctions(); + + import_addresses.clear(); + foreach(ImportDescription import, main->core->getAllImports()) + import_addresses.insert(import.plt); + + function_model->endReloadFunctions(); + nested_function_model->endReloadFunctions(); + + // resize offset and size columns + ui->functionsTreeView->resizeColumnToContents(0); + ui->functionsTreeView->resizeColumnToContents(1); + ui->functionsTreeView->resizeColumnToContents(2); } -void FunctionsWidget::on_functionsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column) +QTreeView *FunctionsWidget::getCurrentTreeView() { - QNOTUSED(column); + if (ui->tabWidget->currentIndex() == 0) + return ui->functionsTreeView; + else + return ui->nestedFunctionsTreeView; +} - QString offset = item->text(1); - QString name = item->text(3); - this->main->seek(offset, name); - this->main->raiseMemoryDock(); +void FunctionsWidget::on_functionsTreeView_itemDoubleClicked(const QModelIndex &index) +{ + FunctionDescription function = index.data(FunctionModel::FunctionDescriptionRole).value(); + this->main->seek(function.offset, function.name, true); } void FunctionsWidget::showFunctionsContextMenu(const QPoint &pt) { + QTreeView *treeView = getCurrentTreeView(); + // Set functions popup menu - QMenu *menu = new QMenu(ui->functionsTreeWidget); + QMenu *menu = new QMenu(ui->functionsTreeView); menu->clear(); menu->addAction(ui->actionDisasAdd_comment); menu->addAction(ui->actionFunctionsRename); @@ -132,189 +429,76 @@ void FunctionsWidget::showFunctionsContextMenu(const QPoint &pt) menu->addSeparator(); menu->addAction(ui->action_References); - if (ui->tabWidget->currentIndex() == 0) - { - ui->functionsTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); - menu->exec(ui->functionsTreeWidget->mapToGlobal(pt)); - } - else - { - ui->nestedFunctionsTree->setContextMenuPolicy(Qt::CustomContextMenu); - menu->exec(ui->nestedFunctionsTree->mapToGlobal(pt)); - } + menu->exec(treeView->mapToGlobal(pt)); + delete menu; } -void FunctionsWidget::refreshTree() -{ - ui->functionsTreeWidget->clear(); - ui->nestedFunctionsTree->clear(); - for (auto i : this->main->core->getList("anal", "functions")) - { - QStringList a = i.split(","); - // off,sz,unk,name - // "0x0804ada3,1,13,,fcn.0804ada3" - // "0x0804ad4a,6,,1,,fcn.0804ad4a" - if (a.length() == 5) - { - // Add list function - qhelpers::appendRow(ui->functionsTreeWidget, a[0], a[1], a[4]); - // Add nested function - QTreeWidgetItem *item = new QTreeWidgetItem(ui->nestedFunctionsTree); - item->setText(0, a[4]); - QTreeWidgetItem *size_it = new QTreeWidgetItem(); - size_it->setText(0, "Offset: " + a[0]); - item->addChild(size_it); - QTreeWidgetItem *off_it = new QTreeWidgetItem(); - off_it->setText(0, "Size: " + a[1]); - item->addChild(off_it); - ui->nestedFunctionsTree->addTopLevelItem(item); - } - else if (a.length() == 6) - { - // Add list function - qhelpers::appendRow(ui->functionsTreeWidget, a[0], a[1], a[5]); - // Add nested function - QTreeWidgetItem *item = new QTreeWidgetItem(ui->nestedFunctionsTree); - item->setText(0, a[5]); - QTreeWidgetItem *size_it = new QTreeWidgetItem(); - size_it->setText(0, "Offset: " + a[0]); - item->addChild(size_it); - QTreeWidgetItem *off_it = new QTreeWidgetItem(); - off_it->setText(0, "Size: " + a[1]); - item->addChild(off_it); - ui->nestedFunctionsTree->addTopLevelItem(item); - } - else - { - qDebug() << "fillFunctions()" << a; - } - } - ui->functionsTreeWidget->sortByColumn(3, Qt::AscendingOrder); - ui->nestedFunctionsTree->sortByColumn(0, Qt::AscendingOrder); - qhelpers::adjustColumns(ui->functionsTreeWidget); - - this->addTooltips(); -} - void FunctionsWidget::on_actionDisasAdd_comment_triggered() { - QString fcn_name = ""; + // Get selected item in functions tree view + QTreeView *treeView = getCurrentTreeView(); + FunctionDescription function = treeView->selectionModel()->currentIndex().data(FunctionModel::FunctionDescriptionRole).value(); + // Create dialog CommentsDialog *c = new CommentsDialog(this); - // Get selected item in functions tree widget - if (ui->tabWidget->currentIndex() == 0) - { - QList selected_rows = ui->functionsTreeWidget->selectedItems(); - // Get selected function name - fcn_name = selected_rows.first()->text(3); - } - else - { - QList selected_rows = ui->nestedFunctionsTree->selectedItems(); - // Get selected function name - fcn_name = selected_rows.first()->text(0); - } + if (c->exec()) { // Get new function name QString comment = c->getComment(); - this->main->add_debug_output("Comment: " + comment + " at: " + fcn_name); + this->main->add_debug_output("Comment: " + comment + " at: " + function.name); // Rename function in r2 core - this->main->core->setComment(fcn_name, comment); + this->main->core->setComment(function.offset, comment); // Seek to new renamed function - this->main->seek(fcn_name); + this->main->seek(function.offset, function.name); // TODO: Refresh functions tree widget } this->main->refreshComments(); } -void FunctionsWidget::addTooltips() -{ - - // Add comments to list functions - QList clist = ui->functionsTreeWidget->findItems("*", Qt::MatchWildcard, 3); - foreach (QTreeWidgetItem *item, clist) - { - QString name = item->text(3); - QList info = this->main->core->cmd("afi @ " + name).split("\n"); - if (info.length() > 2) - { - QString size = info[4].split(" ")[1]; - QString complex = info[8].split(" ")[1]; - QString bb = info[11].split(" ")[1]; - item->setToolTip(3, "Summary:\n\n Size: " + size + - "\n Cyclomatic complexity: " + complex + - "\n Basic blocks: " + bb + - "\n\nDisasm preview:\n\n" + this->main->core->cmd("pdi 10 @ " + name) + - "\nStrings:\n\n" + this->main->core->cmd("pdsf @ " + name)); - //"\nStrings:\n\n" + this->main->core->cmd("pds @ " + name + "!$F")); - } - } - - // Add comments to nested functions - QList nlist = ui->nestedFunctionsTree->findItems("*", Qt::MatchWildcard, 0); - foreach (QTreeWidgetItem *item, nlist) - { - QString name = item->text(0); - QList info = this->main->core->cmd("afi @ " + name).split("\n"); - if (info.length() > 2) - { - QString size = info[4].split(" ")[1]; - QString complex = info[8].split(" ")[1]; - QString bb = info[11].split(" ")[1]; - item->setToolTip(0, "Summary:\n\n Size: " + size + - "\n Cyclomatic complexity: " + complex + - "\n Basic blocks: " + bb + - "\n\nDisasm preview:\n\n" + this->main->core->cmd("pdi 10 @ " + name) + - "\nStrings:\n\n" + this->main->core->cmd("pdsf @ " + name)); - //"\nStrings:\n\n" + this->main->core->cmd("pds @ " + name + "!$F")); - } - } -} - void FunctionsWidget::on_actionFunctionsRename_triggered() { + // Get selected item in functions tree view + QTreeView *treeView = getCurrentTreeView(); + FunctionDescription function = treeView->selectionModel()->currentIndex().data(FunctionModel::FunctionDescriptionRole).value(); + // Create dialog RenameDialog *r = new RenameDialog(this); - // Get selected item in functions tree widget - QList selected_rows = ui->functionsTreeWidget->selectedItems(); - // Get selected function name - QString old_name = selected_rows.first()->text(3); + // Set function name in dialog - r->setFunctionName(old_name); + r->setFunctionName(function.name); // If user accepted if (r->exec()) { // Get new function name QString new_name = r->getFunctionName(); // Rename function in r2 core - this->main->core->renameFunction(old_name, new_name); - // Change name in functions tree widget - selected_rows.first()->setText(3, new_name); + this->main->core->renameFunction(function.name, new_name); + // Scroll to show the new name in functions tree widget - /* - * QAbstractItemView::EnsureVisible - * QAbstractItemView::PositionAtTop - * QAbstractItemView::PositionAtBottom - * QAbstractItemView::PositionAtCenter - */ - ui->functionsTreeWidget->scrollToItem(selected_rows.first(), QAbstractItemView::PositionAtTop); + // + // QAbstractItemView::EnsureVisible + // QAbstractItemView::PositionAtTop + // QAbstractItemView::PositionAtBottom + // QAbstractItemView::PositionAtCenter + // + //ui->functionsTreeWidget->scrollToItem(selected_rows.first(), QAbstractItemView::PositionAtTop); // Seek to new renamed function - this->main->seek(new_name); + this->main->seek(function.offset); } } void FunctionsWidget::on_action_References_triggered() { - QList selected_rows = ui->functionsTreeWidget->selectedItems(); - // Get selected function address - QString address = selected_rows.first()->text(1); + // Get selected item in functions tree view + QTreeView *treeView = getCurrentTreeView(); + FunctionDescription function = treeView->selectionModel()->currentIndex().data(FunctionModel::FunctionDescriptionRole).value(); //this->main->add_debug_output("Addr: " + address); // Get function for clicked offset - RAnalFunction *fcn = this->main->core->functionAt(address.toLongLong(0, 16)); + RAnalFunction *fcn = this->main->core->functionAt(function.offset); XrefsDialog *x = new XrefsDialog(this->main, this); x->setWindowTitle("X-Refs for function " + QString::fromUtf8(fcn->name)); @@ -396,17 +580,6 @@ void FunctionsWidget::on_actionVertical_triggered() ui->tabWidget->setCurrentIndex(1); } -void FunctionsWidget::on_nestedFunctionsTree_itemDoubleClicked(QTreeWidgetItem *item, int column) -{ - QNOTUSED(column); - - //QString offset = item->text(1); - QString name = item->text(0); - QString offset = item->child(0)->text(0).split(":")[1]; - this->main->seek(offset, name); - this->main->raiseMemoryDock(); -} - void FunctionsWidget::resizeEvent(QResizeEvent *event) { if (main->responsive && isVisible()) @@ -427,5 +600,5 @@ void FunctionsWidget::resizeEvent(QResizeEvent *event) void FunctionsWidget::setScrollMode() { - qhelpers::setVerticalScrollMode(ui->functionsTreeWidget); + qhelpers::setVerticalScrollMode(ui->functionsTreeView); } diff --git a/src/widgets/functionswidget.h b/src/widgets/functionswidget.h index 951a74f2..f3cfabed 100644 --- a/src/widgets/functionswidget.h +++ b/src/widgets/functionswidget.h @@ -1,6 +1,10 @@ #ifndef FUNCTIONSWIDGET_H #define FUNCTIONSWIDGET_H +#include +#include +#include +#include "qrcore.h" #include "dashboard.h" class MainWindow; @@ -11,6 +15,67 @@ namespace Ui class FunctionsWidget; } + +class FunctionModel : public QAbstractItemModel +{ + Q_OBJECT + +private: + MainWindow *main; + + QList *functions; + QSet *import_addresses; + + + QFont highlight_font; + QFont default_font; + bool nested; + + int current_index; + +public: + static const int FunctionDescriptionRole = Qt::UserRole; + static const int IsImportRole = Qt::UserRole + 1; + + FunctionModel(QList *functions, QSet *import_addresses, bool nested, QFont default_font, QFont highlight_font, MainWindow *main, QObject *parent = 0); + + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + void beginReloadFunctions(); + void endReloadFunctions(); + + void updateCurrentIndex(); + + bool isNested() { return nested; } + +private slots: + void cursorAddressChanged(RVA addr); + void functionRenamed(QString prev_name, QString new_name); + +}; + + +class FunctionSortFilterProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + FunctionSortFilterProxyModel(FunctionModel *source_model, QObject *parent = 0); + +protected: + bool filterAcceptsRow(int row, const QModelIndex &parent) const override; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; +}; + + + class FunctionsWidget : public DockWidget { Q_OBJECT @@ -23,11 +88,8 @@ public: void refresh() override; - void fillFunctions(); - void addTooltips(); - private slots: - void on_functionsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column); + void on_functionsTreeView_itemDoubleClicked(const QModelIndex &index); void showFunctionsContextMenu(const QPoint &pt); void on_actionDisasAdd_comment_triggered(); @@ -42,17 +104,30 @@ private slots: void on_actionVertical_triggered(); - void on_nestedFunctionsTree_itemDoubleClicked(QTreeWidgetItem *item, int column); - protected: void resizeEvent(QResizeEvent *event) override; private: + QTreeView *getCurrentTreeView(); + Ui::FunctionsWidget *ui; MainWindow *main; + QList functions; + QSet import_addresses; + + FunctionModel *function_model; + FunctionSortFilterProxyModel *function_proxy_model; + + FunctionModel *nested_function_model; + FunctionSortFilterProxyModel *nested_function_proxy_model; + void refreshTree(); void setScrollMode(); }; + + + + #endif // FUNCTIONSWIDGET_H diff --git a/src/widgets/functionswidget.ui b/src/widgets/functionswidget.ui index 7a7db471..830d1c01 100644 --- a/src/widgets/functionswidget.ui +++ b/src/widgets/functionswidget.ui @@ -6,8 +6,8 @@ 0 0 - 400 - 300 + 603 + 314 @@ -67,23 +67,12 @@ border-top: 0px; 0 - - - - 0 - 0 - - - - - 12 - - + Qt::CustomContextMenu - QTreeWidget::item + QTreeView::item { padding-left:10px; padding-top: 1px; @@ -91,20 +80,20 @@ border-top: 0px; border-left: 10px; } -QTreeWidget::item:hover +QTreeView::item:hover { background: rgb(242, 246, 248); color: black; } -QTreeWidget::item:selected +QTreeView::item:selected { background: gray; color: white; } - -QToolTip { +QToolTip +{ background-color: #444; border: 3px solid #444; color: rgb(232, 232, 232); @@ -120,47 +109,12 @@ QToolTip { QAbstractScrollArea::AdjustToContents - - false - - 10 - - - false + 0 true - - false - - - 4 - - - false - - - - Dummy - - - - - Offset - - - - - Size - - - - - Name - - @@ -186,12 +140,12 @@ QToolTip { 0 - + Qt::CustomContextMenu - QTreeWidget::item + QTreeView::item { padding-left:10px; padding-top: 1px; @@ -199,17 +153,17 @@ QToolTip { border-left: 10px; } -QTreeWidget::item:selected +QTreeView::item:selected { background: gray; color: white; } -QTreeWidget::branch:selected +QTreeView::branch:selected { background: gray; } -QTreeWidget::item:hover +QTreeView::item:hover { background: rgb(242, 246, 248); color: black; @@ -225,20 +179,25 @@ QToolTip { QFrame::NoFrame + + true + false - - - Name - - + + + + Quick Filter + + + diff --git a/src/widgets/importswidget.cpp b/src/widgets/importswidget.cpp index feac5e83..81966517 100644 --- a/src/widgets/importswidget.cpp +++ b/src/widgets/importswidget.cpp @@ -68,13 +68,9 @@ void ImportsWidget::refresh() void ImportsWidget::fillImports() { ui->importsTreeWidget->clear(); - for (auto i : this->main->core->getList("bin", "imports")) - { - QStringList a = i.split(","); - // ord,plt,name - if (a.length() == 6) - qhelpers::appendRow(ui->importsTreeWidget, a[1], a[3], "", a[4]); - } + for (auto i : this->main->core->getAllImports()) + qhelpers::appendRow(ui->importsTreeWidget, RAddressString(i.plt), i.type, "", i.name); + highlightUnsafe(); qhelpers::adjustColumns(ui->importsTreeWidget, 0, 10); } diff --git a/src/widgets/importswidget.ui b/src/widgets/importswidget.ui index 033bf372..820c03a5 100644 --- a/src/widgets/importswidget.ui +++ b/src/widgets/importswidget.ui @@ -29,11 +29,6 @@ - - - 12 - - QTreeWidget::item { diff --git a/src/widgets/memorywidget.cpp b/src/widgets/memorywidget.cpp index 1431a562..d5a1e39f 100644 --- a/src/widgets/memorywidget.cpp +++ b/src/widgets/memorywidget.cpp @@ -41,9 +41,9 @@ MemoryWidget::MemoryWidget(MainWindow *main) : this->memTabWidget = ui->memTabWidget; this->last_fcn = "entry0"; - this->last_disasm_fcn = ""; - this->last_graph_fcn = ""; - this->last_hexdump_fcn = ""; + this->last_disasm_fcn = 0; //""; + this->last_graph_fcn = 0; //""; + this->last_hexdump_fcn = 0; //""; // Increase asm text edit margin QTextDocument *asm_docu = this->disasTextEdit->document(); @@ -191,6 +191,15 @@ MemoryWidget::MemoryWidget(MainWindow *main) : connect(this->hexASCIIText->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(hexScrolled())); connect(ui->graphWebView->page(), SIGNAL(loadFinished(bool)), this, SLOT(frameLoadFinished(bool))); + + connect(main, SIGNAL(cursorAddressChanged(RVA)), this, SLOT(on_cursorAddressChanged(RVA))); +} + + + +void MemoryWidget::on_cursorAddressChanged(RVA addr) +{ + setFcnName(addr); } /* @@ -394,7 +403,7 @@ void MemoryWidget::setup() refreshHexdump(off); create_graph(off); get_refs_data(off); - setFcnName(off); + //setFcnName(off); } void MemoryWidget::refresh() @@ -454,7 +463,7 @@ void MemoryWidget::disasmScrolled() QString ele = lastline.split(" ", QString::SkipEmptyParts)[0]; if (ele.contains("0x")) { - this->main->core->cmd("ss " + ele); + this->main->core->seek(ele); 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()); @@ -511,6 +520,8 @@ void MemoryWidget::refreshDisasm(const QString &offset) //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())); @@ -553,12 +564,12 @@ void MemoryWidget::refreshDisasm(const QString &offset) 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); + /*this->disasTextEdit->moveCursor(QTextCursor::End); while (this->disasTextEdit->find(QRegExp("^" + s), QTextDocument::FindBackward)) { this->disasTextEdit->moveCursor(QTextCursor::StartOfWord, QTextCursor::MoveAnchor); - } + }*/ connect(this->disasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled())); connect(this->disasTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(on_disasTextEdit_2_cursorPositionChanged())); @@ -1568,20 +1579,25 @@ QString MemoryWidget::normalize_addr(QString addr) } } -void MemoryWidget::setFcnName(QString addr) +void MemoryWidget::setFcnName(RVA addr) { - // TDOD: FIX ME, ugly - if (addr.contains("0x")) + RAnalFunction *fcn; + bool ok; + + QString addr_string; + + fcn = this->main->core->functionAt(addr); + if (ok && fcn) { - bool ok = false; - RAnalFunction *fcn = this->main->core->functionAt(addr.toULongLong(&ok, 16)); - if (ok && fcn) - { - QString segment = this->main->core->cmd("S. @ " + addr).split(" ").last(); - addr = segment.trimmed() + ":" + fcn->name; - } + QString segment = this->main->core->cmd("S. @ " + QString::number(addr)).split(" ").last(); + addr_string = segment.trimmed() + ":" + fcn->name; } - ui->fcnNameEdit->setText(addr); + else + { + addr_string = main->core->cmdFunctionAt(addr); + } + + ui->fcnNameEdit->setText(addr_string); } void MemoryWidget::on_disasTextEdit_2_cursorPositionChanged() @@ -1601,6 +1617,10 @@ void MemoryWidget::on_disasTextEdit_2_cursorPositionChanged() QString at = this->main->core->cmdFunctionAt(ele); QString deco = this->main->core->getDecompiledCode(at); + + RVA addr = ele.midRef(2).toULongLong(0, 16); + this->main->setCursorAddress(addr); + if (deco != "") { ui->decoTextEdit->setPlainText(deco); @@ -1635,7 +1655,6 @@ void MemoryWidget::on_disasTextEdit_2_cursorPositionChanged() this->main->memoryDock->get_refs_data(ele); //this->main->memoryDock->create_graph(ele); this->setMiniGraph(at); - this->main->current_address = at; } } } @@ -1972,12 +1991,10 @@ void MemoryWidget::frameLoadFinished(bool ok) void MemoryWidget::on_memTabWidget_currentChanged(int /*index*/) { - /* - this->main->add_debug_output("Update index: " + QString::number(index) + " to function: " + this->main->current_address); - this->main->add_debug_output("Last disasm: " + this->last_disasm_fcn); - this->main->add_debug_output("Last graph: " + this->last_graph_fcn); - this->main->add_debug_output("Last hexdump: " + this->last_hexdump_fcn); - */ + /*this->main->add_debug_output("Update index: " + QString::number(index) + " to function: " + RAddressString(main->getCursorAddress())); + this->main->add_debug_output("Last disasm: " + RAddressString(this->last_disasm_fcn)); + this->main->add_debug_output("Last graph: " + RAddressString(this->last_graph_fcn)); + this->main->add_debug_output("Last hexdump: " + RAddressString(this->last_hexdump_fcn));*/ this->updateViews(); } @@ -1986,34 +2003,36 @@ void MemoryWidget::updateViews() // Update only the selected view to improve performance int index = ui->memTabWidget->tabBar()->currentIndex(); + + RVA cursor_addr = main->getCursorAddress(); + + QString cursor_addr_string = RAddressString(cursor_addr); + if (index == 0) { // Disasm - if (this->last_disasm_fcn != this->main->current_address) + if (this->last_disasm_fcn != cursor_addr) { - //this->main->add_debug_output("Doing disasm"); - this->refreshDisasm(this->main->current_address); - this->last_disasm_fcn = this->main->current_address; + this->refreshDisasm(cursor_addr_string); + this->last_disasm_fcn = cursor_addr; } } else if (index == 1) { // Hex - if (this->last_hexdump_fcn != this->main->current_address) + if (this->last_hexdump_fcn != cursor_addr) { - //this->main->add_debug_output("Doing hex"); - this->refreshHexdump(this->main->current_address); - this->last_hexdump_fcn = this->main->current_address; + this->refreshHexdump(cursor_addr_string); + this->last_hexdump_fcn = cursor_addr; } } else if (index == 2) { // Graph - if (this->last_graph_fcn != this->main->current_address) + if (this->last_graph_fcn != cursor_addr) { - //this->main->add_debug_output("Doing graph"); - this->create_graph(this->main->current_address); - this->last_graph_fcn = this->main->current_address; + this->create_graph(cursor_addr_string); + this->last_graph_fcn = cursor_addr; } } } diff --git a/src/widgets/memorywidget.h b/src/widgets/memorywidget.h index 725d6caf..ee617993 100644 --- a/src/widgets/memorywidget.h +++ b/src/widgets/memorywidget.h @@ -84,8 +84,6 @@ public slots: QString normalizeAddr(QString addr); - void setFcnName(QString addr); - void setMiniGraph(QString at); void switchTheme(bool dark); @@ -108,13 +106,18 @@ private: ut64 hexdumpTopOffset; ut64 hexdumpBottomOffset; QString last_fcn; - QString last_disasm_fcn; - QString last_graph_fcn; - QString last_hexdump_fcn; + + RVA last_disasm_fcn; + RVA last_graph_fcn; + RVA last_hexdump_fcn; + + void setFcnName(RVA addr); void setScrollMode(); private slots: + void on_cursorAddressChanged(RVA offset); + void highlightCurrentLine(); void highlightHexCurrentLine(); diff --git a/src/widgets/omnibar.cpp b/src/widgets/omnibar.cpp index 86bc3b12..4f54de2b 100644 --- a/src/widgets/omnibar.cpp +++ b/src/widgets/omnibar.cpp @@ -152,7 +152,7 @@ void Omnibar::on_gotoEntry_returnPressed() { //this->main->seek(this->main->core->cmd("?v " + this->text()), this->text()); QString off = this->main->core->cmd("afo " + this->text()); - this->main->seek(off.trimmed(), this->text()); + this->main->seek(off.trimmed(), this->text(), true); } } diff --git a/src/widgets/relocswidget.cpp b/src/widgets/relocswidget.cpp index c526d6bd..4e3aae61 100644 --- a/src/widgets/relocswidget.cpp +++ b/src/widgets/relocswidget.cpp @@ -14,6 +14,9 @@ RelocsWidget::RelocsWidget(MainWindow *main, QWidget *parent) : { ui->setupUi(this); + // Radare core found in: + this->main = main; + ui->relocsTreeWidget->hideColumn(0); } @@ -39,23 +42,20 @@ void RelocsWidget::on_relocsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, QNOTUSED(column); // Get offset and name of item double clicked - // TODO: use this info to change disasm contents - QString offset = item->text(1); - QString name = item->text(2); - main->seek(offset, name); - - main->raiseMemoryDock(); + RelocDescription reloc = item->data(0, Qt::UserRole).value(); + main->seek(reloc.vaddr, reloc.name, true); } void RelocsWidget::fillTreeWidget() { ui->relocsTreeWidget->clear(); - for (auto i : main->core->getList("bin", "relocs")) + + for (auto i : main->core->getAllRelocs()) { - QStringList pieces = i.split(","); - if (pieces.length() == 3) - qhelpers::appendRow(ui->relocsTreeWidget, pieces[0], pieces[1], pieces[2]); + QTreeWidgetItem *item = qhelpers::appendRow(ui->relocsTreeWidget, RAddressString(i.vaddr), i.type, i.name); + item->setData(0, Qt::UserRole, QVariant::fromValue(i)); } + qhelpers::adjustColumns(ui->relocsTreeWidget); } diff --git a/src/widgets/relocswidget.ui b/src/widgets/relocswidget.ui index cc6393c3..27ffb78d 100644 --- a/src/widgets/relocswidget.ui +++ b/src/widgets/relocswidget.ui @@ -29,11 +29,6 @@ - - - 12 - - QTreeWidget::item { diff --git a/src/widgets/stringswidget.cpp b/src/widgets/stringswidget.cpp index a337b9d4..761ed8f0 100644 --- a/src/widgets/stringswidget.cpp +++ b/src/widgets/stringswidget.cpp @@ -6,6 +6,7 @@ #include "helpers.h" #include +#include StringsWidget::StringsWidget(MainWindow *main, QWidget *parent) : @@ -41,21 +42,17 @@ void StringsWidget::on_stringsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item // Get offset and name of item double clicked // TODO: use this info to change disasm contents - QString offset = item->text(1); - QString name = item->text(2); - this->main->seek(offset); - // Rise and shine baby! - this->main->raiseMemoryDock(); + StringDescription str = item->data(0, Qt::UserRole).value(); + this->main->seek(str.vaddr, NULL, true); } void StringsWidget::fillTreeWidget() { ui->stringsTreeWidget->clear(); - for (auto i : main->core->getList("bin", "strings")) + for (auto i : main->core->getAllStrings()) { - QStringList pieces = i.split(","); - if (pieces.length() == 2) - qhelpers::appendRow(ui->stringsTreeWidget, pieces[0], pieces[1]); + QTreeWidgetItem *item = qhelpers::appendRow(ui->stringsTreeWidget, RAddressString(i.vaddr), i.string); + item->setData(0, Qt::UserRole, QVariant::fromValue(i)); } qhelpers::adjustColumns(ui->stringsTreeWidget); } diff --git a/src/widgets/stringswidget.h b/src/widgets/stringswidget.h index 2adb38a1..2f4b7598 100644 --- a/src/widgets/stringswidget.h +++ b/src/widgets/stringswidget.h @@ -23,6 +23,8 @@ public: void refresh() override; + void fillStrings(); + private slots: void on_stringsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column); diff --git a/src/widgets/stringswidget.ui b/src/widgets/stringswidget.ui index e2b87c4d..af43235c 100644 --- a/src/widgets/stringswidget.ui +++ b/src/widgets/stringswidget.ui @@ -35,11 +35,6 @@ 0 - - - 12 - - QTreeWidget::item { diff --git a/src/widgets/symbolswidget.cpp b/src/widgets/symbolswidget.cpp index 4d58cd28..4ce919b6 100644 --- a/src/widgets/symbolswidget.cpp +++ b/src/widgets/symbolswidget.cpp @@ -39,22 +39,21 @@ void SymbolsWidget::on_symbolsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item QNOTUSED(column); // Get offset and name of item double clicked - // TODO: use this info to change disasm contents - QString offset = item->text(1); - QString name = item->text(3); - //qDebug() << "Item Text: " << name; - this->main->seek(offset, name); - //ui->memDock->setWindowTitle(name); + SymbolDescription symbol = item->data(0, Qt::UserRole).value(); + this->main->seek(symbol.vaddr, symbol.name, true); } void SymbolsWidget::fillSymbols() { ui->symbolsTreeWidget->clear(); - for (auto i : this->main->core->getList("bin", "symbols")) + for (auto symbol : this->main->core->getAllSymbols()) { - QStringList pieces = i.split(","); - if (pieces.length() == 3) - qhelpers::appendRow(ui->symbolsTreeWidget, pieces[0], pieces[1], pieces[2]); + QTreeWidgetItem *item = qhelpers::appendRow(ui->symbolsTreeWidget, + RAddressString(symbol.vaddr), + QString("%1 %2").arg(symbol.bind, symbol.type).trimmed(), + symbol.name); + + item->setData(0, Qt::UserRole, QVariant::fromValue(symbol)); } qhelpers::adjustColumns(ui->symbolsTreeWidget); } diff --git a/src/widgets/symbolswidget.ui b/src/widgets/symbolswidget.ui index a9311803..cd9321de 100644 --- a/src/widgets/symbolswidget.ui +++ b/src/widgets/symbolswidget.ui @@ -29,11 +29,6 @@ - - - 12 - - QTreeWidget::item {