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 <QCheckBox>
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<QString> 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<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"));
// 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<RBinPluginDescription>();
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!"));
}

View File

@ -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<QString> 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<QString> 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<QString> advanced;
MainWindow *main;
InitialOptions options;
};
#endif // ANALTHREAD_H

View File

@ -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();

View File

@ -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();

View File

@ -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<QString> 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<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();
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();
}

View File

@ -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::OptionsDialog> ui;
QString getSelectedArch();
QString getSelectedCPU();
int getSelectedBits();
int getSelectedBBSize();
Endianness getSelectedEndianness();
InitialOptions::Endianness getSelectedEndianness();
QString getSelectedOS();
void reject() override;

View File

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