From 3e8b76138c14030cf10fc34a3b9d742dd3bb4c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sun, 27 May 2018 18:03:29 +0200 Subject: [PATCH] Use AsyncTaskDialog for initial Analysis --- src/AnalTask.cpp | 76 +++++++++++---------------------- src/AnalTask.h | 44 ++++++++++++++++--- src/MainWindow.h | 2 +- src/dialogs/AsyncTaskDialog.cpp | 1 + src/dialogs/OptionsDialog.cpp | 73 +++++++++++++++++++++++-------- src/dialogs/OptionsDialog.h | 5 +-- src/utils/AsyncTask.cpp | 2 +- 7 files changed, 124 insertions(+), 79 deletions(-) diff --git a/src/AnalTask.cpp b/src/AnalTask.cpp index 1eccf96e..2b022204 100644 --- a/src/AnalTask.cpp +++ b/src/AnalTask.cpp @@ -6,10 +6,8 @@ #include #include -AnalTask::AnalTask(OptionsDialog *parent) : - AsyncTask(parent), - level(2), - main(nullptr) +AnalTask::AnalTask(QObject *parent) : + AsyncTask(parent) { } @@ -17,13 +15,6 @@ AnalTask::~AnalTask() { } -void AnalTask::setSettings(MainWindow *main, int level, QList advanced) -{ - this->main = main; - this->level = level; - this->advanced = advanced; -} - void AnalTask::interrupt() { AsyncTask::interrupt(); @@ -39,42 +30,27 @@ void AnalTask::interruptAndWait() void AnalTask::runTask() { - const auto optionsDialog = dynamic_cast(parent()); - const auto &ui = optionsDialog->ui; - bool va = ui->vaCheckBox->isChecked(); - ut64 binLoadAddr = UT64_MAX; // Where the bin header is located in the file (-B) - if (ui->entry_loadOffset->text().length() > 0) - binLoadAddr = Core()->math(ui->entry_loadOffset->text()); - ut64 mapAddr = Core()->math(ui->entry_mapOffset->text()); // Where to map the file once loaded (-m) - log(tr("Loading Binary...\n")); - // Set the CPU details (handle auto) - Core()->setCPU(optionsDialog->getSelectedArch(), optionsDialog->getSelectedCPU(), - optionsDialog->getSelectedBits()); + Core()->setCPU(options.arch, options.cpu, options.bits); - // Binary opening permissions (read/write/execute) int perms = R_IO_READ | R_IO_EXEC; - if (ui->writeCheckBox->isChecked()) + if (options.writeEnabled) perms |= R_IO_WRITE; - // Check if we must load and parse binary header (ELF, PE, ...) - bool loadBinInfo = !ui->binCheckBox->isChecked(); - QString forceBinPlugin = nullptr; - QVariant forceBinPluginData = ui->formatComboBox->currentData(); - if (!forceBinPluginData.isNull()) { - RBinPluginDescription pluginDesc = forceBinPluginData.value(); - forceBinPlugin = pluginDesc.name; - } - // Demangle (must be before file Core()->loadFile) - Core()->setConfig("bin.demangle", ui->demangleCheckBox->isChecked()); + Core()->setConfig("bin.demangle", options.demangle); // Do not reload the file if already loaded QJsonArray openedFiles = Core()->getOpenedFiles(); if (!openedFiles.size()) { - bool fileLoaded = Core()->loadFile(main->getFilename(), binLoadAddr, mapAddr, perms, va, loadBinInfo, - forceBinPlugin); + bool fileLoaded = Core()->loadFile(options.filename, + options.binLoadAddr, + options.mapAddr, + perms, + options.useVA, + options.loadBinInfo, + options.forceBinPlugin); if (!fileLoaded) { // Something wrong happened, fallback to open dialog emit openFileFailed(); @@ -83,32 +59,32 @@ void AnalTask::runTask() } } - // Set asm OS configuration - QString os = optionsDialog->getSelectedOS(); - if (!os.isNull()) { - Core()->cmd("e asm.os=" + os); + if (!options.os.isNull()) { + Core()->cmd("e asm.os=" + options.os); } // Load PDB and/or scripts - if (ui->pdbCheckBox->isChecked()) { - Core()->loadPDB(ui->pdbLineEdit->text()); - } - if (ui->scriptCheckBox->isChecked()) { - Core()->loadScript(ui->scriptLineEdit->text()); + if (!options.pdbFile.isNull()) { + Core()->loadPDB(options.pdbFile); } - // Set various options - if (optionsDialog->getSelectedEndianness() != OptionsDialog::Endianness::Auto) { - Core()->setEndianness(optionsDialog->getSelectedEndianness() == OptionsDialog::Endianness::Big); + if (!options.script.isNull()) { + Core()->loadScript(options.script); } - Core()->setBBSize(optionsDialog->getSelectedBBSize()); + + if (options.endian != InitialOptions::Endianness::Auto) { + Core()->setEndianness(options.endian == InitialOptions::Endianness::Big); + } + + Core()->setBBSize(options.bbsize); + // Use prj.simple as default as long as regular projects are broken Core()->setConfig("prj.simple", true); // Start analysis log(tr("Analysis in progress...\n")); - Core()->analyze(this->level, this->advanced); + Core()->analyze(options.analLevel, options.analAdvanced); log(tr("Analysis complete!")); } diff --git a/src/AnalTask.h b/src/AnalTask.h index cc46b837..be5bfe0f 100644 --- a/src/AnalTask.h +++ b/src/AnalTask.h @@ -2,20 +2,56 @@ #define ANALTHREAD_H #include "utils/AsyncTask.h" +#include "Cutter.h" class CutterCore; class MainWindow; class OptionsDialog; +struct InitialOptions +{ + enum class Endianness { Auto, Little, Big }; + + QString filename; + + bool useVA = true; + RVA binLoadAddr = RVA_INVALID; + RVA mapAddr = RVA_INVALID; + + QString arch; + QString cpu; + int bits = 0; + QString os; + + Endianness endian; + + bool writeEnabled = false; + bool loadBinInfo = true; + QString forceBinPlugin; + + bool demangle = true; + + QString pdbFile; + QString script; + + int bbsize = 0; + + int analLevel = 1; + QList analAdvanced; +}; + class AnalTask : public AsyncTask { Q_OBJECT public: - explicit AnalTask(OptionsDialog *parent = nullptr); + explicit AnalTask(QObject *parent = nullptr); ~AnalTask(); - void setSettings(MainWindow *main, int level, QList advanced); + QString getTitle() override { return tr("Initial Analysis"); } + + void setOptions(const InitialOptions &options) { this->options = options; } + void interrupt() override; void interruptAndWait(); @@ -26,9 +62,7 @@ signals: void openFileFailed(); private: - int level; - QList advanced; - MainWindow *main; + InitialOptions options; }; #endif // ANALTHREAD_H diff --git a/src/MainWindow.h b/src/MainWindow.h index abe16351..2bd13bee 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -71,7 +71,6 @@ public: void openProject(const QString &project_name); void initUI(); - void finalizeOpen(); /*! * @param quit whether to show destructive button in dialog @@ -99,6 +98,7 @@ public: public slots: + void finalizeOpen(); void refreshAll(); diff --git a/src/dialogs/AsyncTaskDialog.cpp b/src/dialogs/AsyncTaskDialog.cpp index 4fdc9390..15084b1d 100644 --- a/src/dialogs/AsyncTaskDialog.cpp +++ b/src/dialogs/AsyncTaskDialog.cpp @@ -18,6 +18,7 @@ AsyncTaskDialog::AsyncTaskDialog(AsyncTask *task, QWidget *parent) } connect(task, &AsyncTask::logChanged, this, &AsyncTaskDialog::updateLog); + connect(task, &AsyncTask::finished, this, &QWidget::close); updateLog(); diff --git a/src/dialogs/OptionsDialog.cpp b/src/dialogs/OptionsDialog.cpp index 9bbf3a2f..b7cf2647 100644 --- a/src/dialogs/OptionsDialog.cpp +++ b/src/dialogs/OptionsDialog.cpp @@ -11,7 +11,6 @@ OptionsDialog::OptionsDialog(MainWindow *main): QDialog(0), // parent may not be main - analTask(this), main(main), core(Core()), defaultAnalLevel(1), @@ -62,7 +61,7 @@ OptionsDialog::OptionsDialog(MainWindow *main): // Add this so the dialog resizes when widgets are shown/hidden //this->layout()->setSizeConstraint(QLayout::SetFixedSize); - connect(&analTask, SIGNAL(finished()), this, SLOT(analysisFinished())); + //connect(&analTask, SIGNAL(finished()), this, SLOT(analysisFinished())); connect(ui->cancelButton, SIGNAL(clicked()), this, SLOT(reject())); ui->programLineEdit->setText(main->getFilename()); @@ -128,15 +127,15 @@ int OptionsDialog::getSelectedBBSize() return 1024; } -OptionsDialog::Endianness OptionsDialog::getSelectedEndianness() +InitialOptions::Endianness OptionsDialog::getSelectedEndianness() { switch (ui->endiannessComboBox->currentIndex()) { case 1: - return Endianness::Little; + return InitialOptions::Endianness::Little; case 2: - return Endianness::Big; + return InitialOptions::Endianness::Big; default: - return Endianness::Auto; + return InitialOptions::Endianness::Auto; } } @@ -161,12 +160,50 @@ void OptionsDialog::setupAndStartAnalysis(int level, QList advanced) main->initUI(); - connect(&analTask, &AnalTask::openFileFailed, main, &MainWindow::openNewFileFailed); - analTask.setSettings(main, level, advanced); - Core()->getAsyncTaskManager()->start(&analTask); + InitialOptions options; - AsyncTaskDialog *taskDialog = new AsyncTaskDialog(&analTask, main); + options.filename = main->getFilename(); + + // Where the bin header is located in the file (-B) + if (ui->entry_loadOffset->text().length() > 0) { + options.binLoadAddr = Core()->math(ui->entry_loadOffset->text()); + } + + options.mapAddr = Core()->math(ui->entry_mapOffset->text()); // Where to map the file once loaded (-m) + options.arch = getSelectedArch(); + options.cpu = getSelectedCPU(); + options.bits = getSelectedBits(); + options.os = getSelectedOS(); + options.writeEnabled = ui->writeCheckBox->isChecked(); + options.loadBinInfo = !ui->binCheckBox->isChecked(); + QVariant forceBinPluginData = ui->formatComboBox->currentData(); + if (!forceBinPluginData.isNull()) { + RBinPluginDescription pluginDesc = forceBinPluginData.value(); + options.forceBinPlugin = pluginDesc.name; + } + options.demangle = ui->demangleCheckBox->isChecked(); + if (ui->pdbCheckBox->isChecked()) { + options.pdbFile = ui->pdbLineEdit->text(); + } + if (ui->scriptCheckBox->isChecked()) { + options.script = ui->scriptLineEdit->text(); + } + options.endian = getSelectedEndianness(); + options.bbsize = getSelectedBBSize(); + + AnalTask *analTask = new AnalTask(main); + analTask->setOptions(options); + + connect(analTask, &AnalTask::openFileFailed, main, &MainWindow::openNewFileFailed); + connect(analTask, &AsyncTask::finished, main, &MainWindow::finalizeOpen); + + Core()->getAsyncTaskManager()->start(analTask); + + AsyncTaskDialog *taskDialog = new AsyncTaskDialog(analTask); + taskDialog->setAttribute(Qt::WA_DeleteOnClose); taskDialog->show(); + + done(0); } @@ -225,11 +262,11 @@ void OptionsDialog::on_okButton_clicked() void OptionsDialog::analysisFinished() { - if (analTask.isInterrupted()) { - updateProgress(tr("Analysis aborted.")); - done(1); - return; - } + //if (analTask.isInterrupted()) { + // updateProgress(tr("Analysis aborted.")); + // done(1); + // return; + //} updateProgress(tr("Loading interface...")); main->addOutput(tr(" > Analysis finished")); @@ -240,9 +277,9 @@ void OptionsDialog::analysisFinished() void OptionsDialog::closeEvent(QCloseEvent *event) { - if (analTask.isRunning()) { - analTask.interruptAndWait(); - } + //if (analTask.isRunning()) { + // analTask.interruptAndWait(); + //} event->accept(); } diff --git a/src/dialogs/OptionsDialog.h b/src/dialogs/OptionsDialog.h index cc8c8589..a78baf74 100644 --- a/src/dialogs/OptionsDialog.h +++ b/src/dialogs/OptionsDialog.h @@ -44,7 +44,6 @@ protected: void closeEvent(QCloseEvent *event) override; private: - AnalTask analTask; MainWindow *main; CutterCore *core; int defaultAnalLevel; @@ -56,15 +55,13 @@ private: void setInteractionEnabled(bool enabled); public: - enum class Endianness { Auto, Little, Big }; - std::unique_ptr ui; QString getSelectedArch(); QString getSelectedCPU(); int getSelectedBits(); int getSelectedBBSize(); - Endianness getSelectedEndianness(); + InitialOptions::Endianness getSelectedEndianness(); QString getSelectedOS(); void reject() override; diff --git a/src/utils/AsyncTask.cpp b/src/utils/AsyncTask.cpp index 922bf808..e0c32e6a 100644 --- a/src/utils/AsyncTask.cpp +++ b/src/utils/AsyncTask.cpp @@ -5,7 +5,7 @@ AsyncTask::AsyncTask(QObject *parent) : QObject(parent), QRunnable() { - setAutoDelete(false); + setAutoDelete(true); running = false; }