cutter/src/dialogs/OptionsDialog.cpp

374 lines
9.9 KiB
C++
Raw Normal View History

2018-05-28 14:19:04 +00:00
#include "utils/AsyncTask.h"
2017-10-01 19:09:42 +00:00
#include "OptionsDialog.h"
#include "ui_OptionsDialog.h"
#include "MainWindow.h"
2017-10-02 09:41:28 +00:00
#include "dialogs/NewFileDialog.h"
2018-05-26 18:49:57 +00:00
#include "dialogs/AsyncTaskDialog.h"
2017-10-01 19:09:42 +00:00
#include "utils/Helpers.h"
#include <QSettings>
#include <QFileInfo>
#include <QFileDialog>
OptionsDialog::OptionsDialog(MainWindow *main):
QDialog(0), // parent may not be main
2017-10-09 18:08:35 +00:00
main(main),
2018-04-12 06:33:30 +00:00
core(Core()),
2017-10-24 08:18:16 +00:00
defaultAnalLevel(1),
ui(new Ui::OptionsDialog)
{
ui->setupUi(this);
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
2018-02-12 12:22:53 +00:00
ui->logoSvgWidget->load(Config()->getLogoFile());
ui->analSlider->setValue(defaultAnalLevel);
// Fill the plugins combo
2017-10-09 18:08:35 +00:00
asm_plugins = core->getAsmPluginNames();
for (auto plugin : asm_plugins)
ui->archComboBox->addItem(plugin, plugin);
2017-10-09 18:08:35 +00:00
ui->archComboBox->setToolTip(core->cmd("e? asm.arch").trimmed());
// cpu combo box
ui->cpuComboBox->lineEdit()->setPlaceholderText(tr("Auto"));
2017-10-09 18:08:35 +00:00
ui->cpuComboBox->setToolTip(core->cmd("e? asm.cpu").trimmed());
updateCPUComboBox();
// os combo box
2017-10-09 18:08:35 +00:00
for (const auto &plugin : core->cmdList("e asm.os=?"))
ui->kernelComboBox->addItem(plugin, plugin);
2017-10-09 18:08:35 +00:00
ui->kernelComboBox->setToolTip(core->cmd("e? asm.os").trimmed());
2017-10-09 18:08:35 +00:00
ui->bitsComboBox->setToolTip(core->cmd("e? asm.bits").trimmed());
ui->entry_analbb->setToolTip(core->cmd("e? anal.bb.maxsize").trimmed());
2018-03-21 20:32:32 +00:00
2017-10-09 18:08:35 +00:00
for (auto plugin : core->getRBinPluginDescriptions("bin"))
ui->formatComboBox->addItem(plugin.name, QVariant::fromValue(plugin));
ui->hideFrame->setVisible(false);
ui->analoptionsFrame->setVisible(false);
updatePDBLayout();
connect(ui->pdbCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updatePDBLayout()));
updateScriptLayout();
connect(ui->scriptCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updateScriptLayout()));
2017-12-06 12:32:35 +00:00
connect(ui->cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
2017-04-09 19:55:06 +00:00
ui->programLineEdit->setText(main->getFilename());
}
2017-10-02 09:41:28 +00:00
OptionsDialog::~OptionsDialog() {}
void OptionsDialog::updateCPUComboBox()
{
QString currentText = ui->cpuComboBox->lineEdit()->text();
ui->cpuComboBox->clear();
QString cmd = "e asm.cpu=?";
QString arch = getSelectedArch();
if (!arch.isNull())
cmd += " @a:" + arch;
ui->cpuComboBox->addItem("");
2017-10-09 18:08:35 +00:00
ui->cpuComboBox->addItems(core->cmdList(cmd));
ui->cpuComboBox->lineEdit()->setText(currentText);
}
QString OptionsDialog::getSelectedArch()
{
QVariant archValue = ui->archComboBox->currentData();
return archValue.isValid() ? archValue.toString() : nullptr;
}
QString OptionsDialog::getSelectedCPU()
{
QString cpu = ui->cpuComboBox->currentText();
if (cpu.isNull() || cpu.isEmpty())
return nullptr;
return cpu;
}
int OptionsDialog::getSelectedBits()
{
QString sel_bits = ui->bitsComboBox->currentText();
2018-03-21 20:32:32 +00:00
if (sel_bits != "Auto") {
return sel_bits.toInt();
}
return 0;
}
int OptionsDialog::getSelectedBBSize()
{
QString sel_bbsize = ui->entry_analbb->text();
bool ok;
int bbsize = sel_bbsize.toInt(&ok);
if (ok)
return bbsize;
return 1024;
}
InitialOptions::Endianness OptionsDialog::getSelectedEndianness()
2018-01-20 10:35:31 +00:00
{
2018-03-21 20:32:32 +00:00
switch (ui->endiannessComboBox->currentIndex()) {
2018-01-20 10:35:31 +00:00
case 1:
return InitialOptions::Endianness::Little;
2018-01-20 10:35:31 +00:00
case 2:
return InitialOptions::Endianness::Big;
2018-01-20 10:35:31 +00:00
default:
return InitialOptions::Endianness::Auto;
2018-01-20 10:35:31 +00:00
}
}
QString OptionsDialog::getSelectedOS()
{
QVariant os = ui->kernelComboBox->currentData();
return os.isValid() ? os.toString() : nullptr;
}
2018-05-27 19:38:19 +00:00
QList<QString> OptionsDialog::getSelectedAdvancedAnalCmds()
{
QList<QString> advanced = QList<QString>();
if (ui->analSlider->value() == 3) {
if (ui->aa_symbols->isChecked()) {
advanced << "aa";
}
if (ui->aar_references->isChecked()) {
advanced << "aar";
}
if (ui->aac_calls->isChecked()) {
advanced << "aac";
}
if (ui->aab_basicblocks->isChecked()) {
advanced << "aab";
}
if (ui->aan_rename->isChecked()) {
advanced << "aan";
}
if (ui->aae_emulate->isChecked()) {
advanced << "aae";
}
if (ui->aat_consecutive->isChecked()) {
advanced << "aat";
}
if (ui->afta_typeargument->isChecked()) {
advanced << "afta";
}
if (ui->aaT_aftertrap->isChecked()) {
advanced << "aaT";
}
if (ui->aap_preludes->isChecked()) {
advanced << "aap";
}
if (ui->jmptbl->isChecked()) {
advanced << "e! anal.jmptbl";
}
if (ui->pushret->isChecked()) {
advanced << "e! anal.pushret";
}
if (ui->hasnext->isChecked()) {
advanced << "e! anal.hasnext";
}
}
return advanced;
}
void OptionsDialog::setupAndStartAnalysis(int level, QList<QString> advanced)
{
ui->analSlider->setValue(level);
main->initUI();
InitialOptions options;
2018-05-26 18:49:57 +00:00
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();
2018-05-27 19:38:19 +00:00
switch(level) {
case 1:
options.analCmd = { "aaa" };
break;
case 2:
options.analCmd = { "aaaa" };
break;
case 3:
options.analCmd = advanced;
break;
default:
options.analCmd = {};
break;
}
2018-05-28 14:19:04 +00:00
AnalTask *analTask = new AnalTask();
analTask->setOptions(options);
connect(analTask, &AnalTask::openFileFailed, main, &MainWindow::openNewFileFailed);
connect(analTask, &AsyncTask::finished, main, &MainWindow::finalizeOpen);
2018-05-28 14:19:04 +00:00
AsyncTask::Ptr analTaskPtr(analTask);
Core()->getAsyncTaskManager()->start(analTaskPtr);
2018-05-28 14:19:04 +00:00
AsyncTaskDialog *taskDialog = new AsyncTaskDialog(analTaskPtr);
taskDialog->setInterruptOnClose(true);
taskDialog->setAttribute(Qt::WA_DeleteOnClose);
2018-05-26 18:49:57 +00:00
taskDialog->show();
done(0);
}
void OptionsDialog::on_okButton_clicked()
{
2018-05-27 19:38:19 +00:00
setupAndStartAnalysis(ui->analSlider->value(), getSelectedAdvancedAnalCmds());
}
void OptionsDialog::closeEvent(QCloseEvent *event)
{
event->accept();
}
QString OptionsDialog::analysisDescription(int level)
{
//TODO: replace this with meaningful descriptions
2018-03-21 20:32:32 +00:00
switch (level) {
case 0:
return tr("No analysis");
case 1:
return tr("Auto-Analysis (aaa)");
case 2:
return tr("Auto-Analysis Experimental (aaaa)");
case 3:
return tr("Advanced");
default:
return tr("Unknown");
}
}
void OptionsDialog::on_analSlider_valueChanged(int value)
{
2017-04-12 15:02:35 +00:00
ui->analDescription->setText(tr("Level") + QString(": %1").arg(analysisDescription(value)));
2018-03-21 20:32:32 +00:00
if (value == 0) {
ui->analCheckBox->setChecked(false);
ui->analCheckBox->setText(tr("Analysis: Disabled"));
2018-03-21 20:32:32 +00:00
} else {
ui->analCheckBox->setChecked(true);
ui->analCheckBox->setText(tr("Analysis: Enabled"));
2018-03-21 20:32:32 +00:00
if (value == 3) {
ui->analoptionsFrame->setVisible(true);
2018-03-21 20:32:32 +00:00
} else {
ui->analoptionsFrame->setVisible(false);
}
}
}
void OptionsDialog::on_AdvOptButton_clicked()
{
2018-03-21 20:32:32 +00:00
if (ui->AdvOptButton->isChecked()) {
ui->hideFrame->setVisible(true);
ui->AdvOptButton->setArrowType(Qt::DownArrow);
2018-03-21 20:32:32 +00:00
} else {
ui->hideFrame->setVisible(false);
ui->AdvOptButton->setArrowType(Qt::RightArrow);
}
}
void OptionsDialog::on_analCheckBox_clicked(bool checked)
{
2017-04-13 15:51:58 +00:00
if (!checked)
defaultAnalLevel = ui->analSlider->value();
ui->analSlider->setValue(checked ? defaultAnalLevel : 0);
}
void OptionsDialog::on_archComboBox_currentIndexChanged(int)
{
updateCPUComboBox();
}
void OptionsDialog::updatePDBLayout()
{
ui->pdbWidget->setEnabled(ui->pdbCheckBox->isChecked());
}
void OptionsDialog::on_pdbSelectButton_clicked()
{
QFileDialog dialog(this);
dialog.setWindowTitle(tr("Select PDB file"));
dialog.setNameFilters({ tr("PDB file (*.pdb)"), tr("All files (*)") });
2018-03-21 20:32:32 +00:00
if (!dialog.exec()) {
return;
}
QString fileName = dialog.selectedFiles().first();
2018-03-21 20:32:32 +00:00
if (!fileName.isEmpty()) {
ui->pdbLineEdit->setText(fileName);
}
}
2017-12-06 12:32:35 +00:00
void OptionsDialog::updateScriptLayout()
{
ui->scriptWidget->setEnabled(ui->scriptCheckBox->isChecked());
}
void OptionsDialog::on_scriptSelectButton_clicked()
{
QFileDialog dialog(this);
dialog.setWindowTitle(tr("Select radare2 script file"));
dialog.setNameFilters({ tr("Script file (*.r2)"), tr("All files (*)") });
if (!dialog.exec()) {
return;
}
QString fileName = dialog.selectedFiles().first();
if (!fileName.isEmpty()) {
ui->scriptLineEdit->setText(fileName);
}
}
2017-12-06 12:32:35 +00:00
void OptionsDialog::reject()
{
done(0);
NewFileDialog *n = new NewFileDialog(nullptr);
n->show();
}