Use AsyncTaskDialog for initial Analysis

This commit is contained in:
Florian Märkl 2018-05-27 18:03:29 +02:00
parent 896925736f
commit 3e8b76138c
7 changed files with 124 additions and 79 deletions

View File

@ -6,10 +6,8 @@
#include <QDebug> #include <QDebug>
#include <QCheckBox> #include <QCheckBox>
AnalTask::AnalTask(OptionsDialog *parent) : AnalTask::AnalTask(QObject *parent) :
AsyncTask(parent), AsyncTask(parent)
level(2),
main(nullptr)
{ {
} }
@ -17,13 +15,6 @@ AnalTask::~AnalTask()
{ {
} }
void AnalTask::setSettings(MainWindow *main, int level, QList<QString> advanced)
{
this->main = main;
this->level = level;
this->advanced = advanced;
}
void AnalTask::interrupt() void AnalTask::interrupt()
{ {
AsyncTask::interrupt(); AsyncTask::interrupt();
@ -39,42 +30,27 @@ void AnalTask::interruptAndWait()
void AnalTask::runTask() void AnalTask::runTask()
{ {
const auto optionsDialog = dynamic_cast<OptionsDialog *>(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")); log(tr("Loading Binary...\n"));
// Set the CPU details (handle auto) Core()->setCPU(options.arch, options.cpu, options.bits);
Core()->setCPU(optionsDialog->getSelectedArch(), optionsDialog->getSelectedCPU(),
optionsDialog->getSelectedBits());
// Binary opening permissions (read/write/execute)
int perms = R_IO_READ | R_IO_EXEC; int perms = R_IO_READ | R_IO_EXEC;
if (ui->writeCheckBox->isChecked()) if (options.writeEnabled)
perms |= R_IO_WRITE; 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<RBinPluginDescription>();
forceBinPlugin = pluginDesc.name;
}
// Demangle (must be before file Core()->loadFile) // 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 // Do not reload the file if already loaded
QJsonArray openedFiles = Core()->getOpenedFiles(); QJsonArray openedFiles = Core()->getOpenedFiles();
if (!openedFiles.size()) { if (!openedFiles.size()) {
bool fileLoaded = Core()->loadFile(main->getFilename(), binLoadAddr, mapAddr, perms, va, loadBinInfo, bool fileLoaded = Core()->loadFile(options.filename,
forceBinPlugin); options.binLoadAddr,
options.mapAddr,
perms,
options.useVA,
options.loadBinInfo,
options.forceBinPlugin);
if (!fileLoaded) { if (!fileLoaded) {
// Something wrong happened, fallback to open dialog // Something wrong happened, fallback to open dialog
emit openFileFailed(); emit openFileFailed();
@ -83,32 +59,32 @@ void AnalTask::runTask()
} }
} }
// Set asm OS configuration if (!options.os.isNull()) {
QString os = optionsDialog->getSelectedOS(); Core()->cmd("e asm.os=" + options.os);
if (!os.isNull()) {
Core()->cmd("e asm.os=" + os);
} }
// Load PDB and/or scripts // Load PDB and/or scripts
if (ui->pdbCheckBox->isChecked()) { if (!options.pdbFile.isNull()) {
Core()->loadPDB(ui->pdbLineEdit->text()); Core()->loadPDB(options.pdbFile);
}
if (ui->scriptCheckBox->isChecked()) {
Core()->loadScript(ui->scriptLineEdit->text());
} }
// Set various options if (!options.script.isNull()) {
if (optionsDialog->getSelectedEndianness() != OptionsDialog::Endianness::Auto) { Core()->loadScript(options.script);
Core()->setEndianness(optionsDialog->getSelectedEndianness() == OptionsDialog::Endianness::Big);
} }
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 // Use prj.simple as default as long as regular projects are broken
Core()->setConfig("prj.simple", true); Core()->setConfig("prj.simple", true);
// Start analysis // Start analysis
log(tr("Analysis in progress...\n")); log(tr("Analysis in progress...\n"));
Core()->analyze(this->level, this->advanced); Core()->analyze(options.analLevel, options.analAdvanced);
log(tr("Analysis complete!")); log(tr("Analysis complete!"));
} }

View File

@ -2,20 +2,56 @@
#define ANALTHREAD_H #define ANALTHREAD_H
#include "utils/AsyncTask.h" #include "utils/AsyncTask.h"
#include "Cutter.h"
class CutterCore; class CutterCore;
class MainWindow; class MainWindow;
class OptionsDialog; 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<QString> analAdvanced;
};
class AnalTask : public AsyncTask class AnalTask : public AsyncTask
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit AnalTask(OptionsDialog *parent = nullptr); explicit AnalTask(QObject *parent = nullptr);
~AnalTask(); ~AnalTask();
void setSettings(MainWindow *main, int level, QList<QString> advanced); QString getTitle() override { return tr("Initial Analysis"); }
void setOptions(const InitialOptions &options) { this->options = options; }
void interrupt() override; void interrupt() override;
void interruptAndWait(); void interruptAndWait();
@ -26,9 +62,7 @@ signals:
void openFileFailed(); void openFileFailed();
private: private:
int level; InitialOptions options;
QList<QString> advanced;
MainWindow *main;
}; };
#endif // ANALTHREAD_H #endif // ANALTHREAD_H

View File

@ -71,7 +71,6 @@ public:
void openProject(const QString &project_name); void openProject(const QString &project_name);
void initUI(); void initUI();
void finalizeOpen();
/*! /*!
* @param quit whether to show destructive button in dialog * @param quit whether to show destructive button in dialog
@ -99,6 +98,7 @@ public:
public slots: public slots:
void finalizeOpen();
void refreshAll(); void refreshAll();

View File

@ -18,6 +18,7 @@ AsyncTaskDialog::AsyncTaskDialog(AsyncTask *task, QWidget *parent)
} }
connect(task, &AsyncTask::logChanged, this, &AsyncTaskDialog::updateLog); connect(task, &AsyncTask::logChanged, this, &AsyncTaskDialog::updateLog);
connect(task, &AsyncTask::finished, this, &QWidget::close);
updateLog(); updateLog();

View File

@ -11,7 +11,6 @@
OptionsDialog::OptionsDialog(MainWindow *main): OptionsDialog::OptionsDialog(MainWindow *main):
QDialog(0), // parent may not be main QDialog(0), // parent may not be main
analTask(this),
main(main), main(main),
core(Core()), core(Core()),
defaultAnalLevel(1), defaultAnalLevel(1),
@ -62,7 +61,7 @@ OptionsDialog::OptionsDialog(MainWindow *main):
// Add this so the dialog resizes when widgets are shown/hidden // Add this so the dialog resizes when widgets are shown/hidden
//this->layout()->setSizeConstraint(QLayout::SetFixedSize); //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())); connect(ui->cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
ui->programLineEdit->setText(main->getFilename()); ui->programLineEdit->setText(main->getFilename());
@ -128,15 +127,15 @@ int OptionsDialog::getSelectedBBSize()
return 1024; return 1024;
} }
OptionsDialog::Endianness OptionsDialog::getSelectedEndianness() InitialOptions::Endianness OptionsDialog::getSelectedEndianness()
{ {
switch (ui->endiannessComboBox->currentIndex()) { switch (ui->endiannessComboBox->currentIndex()) {
case 1: case 1:
return Endianness::Little; return InitialOptions::Endianness::Little;
case 2: case 2:
return Endianness::Big; return InitialOptions::Endianness::Big;
default: default:
return Endianness::Auto; return InitialOptions::Endianness::Auto;
} }
} }
@ -161,12 +160,50 @@ void OptionsDialog::setupAndStartAnalysis(int level, QList<QString> advanced)
main->initUI(); main->initUI();
connect(&analTask, &AnalTask::openFileFailed, main, &MainWindow::openNewFileFailed); InitialOptions options;
analTask.setSettings(main, level, advanced);
Core()->getAsyncTaskManager()->start(&analTask);
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<RBinPluginDescription>();
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(); taskDialog->show();
done(0);
} }
@ -225,11 +262,11 @@ void OptionsDialog::on_okButton_clicked()
void OptionsDialog::analysisFinished() void OptionsDialog::analysisFinished()
{ {
if (analTask.isInterrupted()) { //if (analTask.isInterrupted()) {
updateProgress(tr("Analysis aborted.")); // updateProgress(tr("Analysis aborted."));
done(1); // done(1);
return; // return;
} //}
updateProgress(tr("Loading interface...")); updateProgress(tr("Loading interface..."));
main->addOutput(tr(" > Analysis finished")); main->addOutput(tr(" > Analysis finished"));
@ -240,9 +277,9 @@ void OptionsDialog::analysisFinished()
void OptionsDialog::closeEvent(QCloseEvent *event) void OptionsDialog::closeEvent(QCloseEvent *event)
{ {
if (analTask.isRunning()) { //if (analTask.isRunning()) {
analTask.interruptAndWait(); // analTask.interruptAndWait();
} //}
event->accept(); event->accept();
} }

View File

@ -44,7 +44,6 @@ protected:
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
private: private:
AnalTask analTask;
MainWindow *main; MainWindow *main;
CutterCore *core; CutterCore *core;
int defaultAnalLevel; int defaultAnalLevel;
@ -56,15 +55,13 @@ private:
void setInteractionEnabled(bool enabled); void setInteractionEnabled(bool enabled);
public: public:
enum class Endianness { Auto, Little, Big };
std::unique_ptr<Ui::OptionsDialog> ui; std::unique_ptr<Ui::OptionsDialog> ui;
QString getSelectedArch(); QString getSelectedArch();
QString getSelectedCPU(); QString getSelectedCPU();
int getSelectedBits(); int getSelectedBits();
int getSelectedBBSize(); int getSelectedBBSize();
Endianness getSelectedEndianness(); InitialOptions::Endianness getSelectedEndianness();
QString getSelectedOS(); QString getSelectedOS();
void reject() override; void reject() override;

View File

@ -5,7 +5,7 @@ AsyncTask::AsyncTask(QObject *parent)
: QObject(parent), : QObject(parent),
QRunnable() QRunnable()
{ {
setAutoDelete(false); setAutoDelete(true);
running = false; running = false;
} }