diff --git a/src/AnalThread.cpp b/src/AnalThread.cpp index c3d9e51a..196889a4 100644 --- a/src/AnalThread.cpp +++ b/src/AnalThread.cpp @@ -46,7 +46,7 @@ void AnalThread::run() core->setCPU(optionsDialog->getSelectedArch(), optionsDialog->getSelectedCPU(), optionsDialog->getSelectedBits()); - bool rw = false; + bool rw = ui->writeCheckBox->isChecked(); bool loadBinInfo = !ui->binCheckBox->isChecked(); if (loadBinInfo) diff --git a/src/cutter.cpp b/src/cutter.cpp index 7bba9608..f7ad5fbf 100644 --- a/src/cutter.cpp +++ b/src/cutter.cpp @@ -219,7 +219,7 @@ bool CutterCore::loadFile(QString path, uint64_t loadaddr, uint64_t mapaddr, boo if (va == 0 || va == 2) r_config_set_i(core_->config, "io.va", va); - f = r_core_file_open(core_, path.toUtf8().constData(), rw ? (R_IO_READ | R_IO_WRITE) : R_IO_READ, mapaddr); + f = r_core_file_open(core_, path.toUtf8().constData(), rw ? R_IO_RW : R_IO_READ, mapaddr); if (!f) { eprintf("r_core_file_open failed\n"); @@ -324,6 +324,18 @@ void CutterCore::delFlag(RVA addr) emit flagsChanged(); } +void CutterCore::editInstruction(RVA addr, const QString &inst) +{ + cmd("wa " + inst); + emit instructionChanged(addr); +} + +void CutterCore::editBytes(RVA addr, const QString &bytes) +{ + cmd("wx " + bytes); + emit instructionChanged(addr); +} + void CutterCore::setComment(RVA addr, const QString &cmt) { cmd("CCu base64:" + cmt.toLocal8Bit().toBase64() + " @ " + QString::number(addr)); diff --git a/src/cutter.h b/src/cutter.h index 43e00e79..7ac9ba9f 100644 --- a/src/cutter.h +++ b/src/cutter.h @@ -254,6 +254,9 @@ public: void renameFlag(QString old_name, QString new_name); void delFlag(RVA addr); + void editInstruction(RVA addr, const QString &inst); + void editBytes(RVA addr, const QString &inst); + void setComment(RVA addr, const QString &cmt); void delComment(RVA addr); diff --git a/src/cutter.pro b/src/cutter.pro index f1c04b21..d5bc892d 100644 --- a/src/cutter.pro +++ b/src/cutter.pro @@ -40,6 +40,7 @@ SOURCES += \ dialogs/OptionsDialog.cpp \ dialogs/AboutDialog.cpp \ dialogs/CommentsDialog.cpp \ + dialogs/EditInstructionDialog.cpp \ dialogs/FlagDialog.cpp \ dialogs/RenameDialog.cpp \ dialogs/XrefsDialog.cpp \ @@ -99,6 +100,7 @@ HEADERS += \ dialogs/AboutDialog.h \ dialogs/preferences/AsmOptionsWidget.h \ dialogs/CommentsDialog.h \ + dialogs/EditInstructionDialog.h \ dialogs/FlagDialog.h \ dialogs/RenameDialog.h \ dialogs/XrefsDialog.h \ @@ -154,6 +156,7 @@ FORMS += \ dialogs/AboutDialog.ui \ dialogs/preferences/AsmOptionsWidget.ui \ dialogs/CommentsDialog.ui \ + dialogs/EditInstructionDialog.ui \ dialogs/FlagDialog.ui \ dialogs/RenameDialog.ui \ dialogs/XrefsDialog.ui \ diff --git a/src/dialogs/EditInstructionDialog.cpp b/src/dialogs/EditInstructionDialog.cpp new file mode 100644 index 00000000..f9d4f492 --- /dev/null +++ b/src/dialogs/EditInstructionDialog.cpp @@ -0,0 +1,56 @@ +#include "EditInstructionDialog.h" +#include "ui_EditInstructionDialog.h" + +EditInstructionDialog::EditInstructionDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::EditInstructionDialog) +{ + ui->setupUi(this); + setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint)); + + // Event filter for capturing Ctrl/Cmd+Return + ui->lineEdit->installEventFilter(this); +} + +EditInstructionDialog::~EditInstructionDialog() {} + +void EditInstructionDialog::on_buttonBox_accepted() +{ +} + +void EditInstructionDialog::on_buttonBox_rejected() +{ + close(); +} + +QString EditInstructionDialog::getInstruction() +{ + QString ret = ui->lineEdit->text(); + return ret; +} + +void EditInstructionDialog::setInstruction(const QString &instruction) +{ + ui->lineEdit->setText(instruction); +} + +bool EditInstructionDialog::eventFilter(QObject *obj, QEvent *event) +{ + Q_UNUSED(obj); + + if (event -> type() == QEvent::KeyPress) + { + QKeyEvent *keyEvent = static_cast (event); + + // Confirm comment by pressing Ctrl/Cmd+Return + if ((keyEvent -> modifiers() & Qt::ControlModifier) && + ((keyEvent -> key() == Qt::Key_Enter) || (keyEvent -> key() == Qt::Key_Return))) + { + this->accept(); + return true; + } + } + + + return false; +} diff --git a/src/dialogs/EditInstructionDialog.h b/src/dialogs/EditInstructionDialog.h new file mode 100644 index 00000000..13ea690d --- /dev/null +++ b/src/dialogs/EditInstructionDialog.h @@ -0,0 +1,35 @@ +#ifndef EDITINSTRUCTIONDIALOG_H +#define EDITINSTRUCTIONDIALOG_H + +#include +#include +#include + +namespace Ui +{ + class EditInstructionDialog; +} + +class EditInstructionDialog : public QDialog +{ + Q_OBJECT + +public: + explicit EditInstructionDialog(QWidget *parent = 0); + ~EditInstructionDialog(); + + QString getInstruction(); + void setInstruction(const QString &instruction); + +private slots: + void on_buttonBox_accepted(); + + void on_buttonBox_rejected(); + +private: + std::unique_ptr ui; + + bool eventFilter(QObject *obj, QEvent *event); +}; + +#endif // EDITINSTRUCTIONDIALOG_H diff --git a/src/dialogs/EditInstructionDialog.ui b/src/dialogs/EditInstructionDialog.ui new file mode 100644 index 00000000..e1d9f848 --- /dev/null +++ b/src/dialogs/EditInstructionDialog.ui @@ -0,0 +1,89 @@ + + + EditInstructionDialog + + + + 0 + 0 + 400 + 118 + + + + Edit Instruction + + + + 2 + + + 2 + + + 5 + + + 2 + + + 2 + + + + + 0 + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + EditInstructionDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + EditInstructionDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/dialogs/OptionsDialog.ui b/src/dialogs/OptionsDialog.ui index a37de1e7..548b4a8f 100644 --- a/src/dialogs/OptionsDialog.ui +++ b/src/dialogs/OptionsDialog.ui @@ -435,6 +435,16 @@ QLayout::SetMinimumSize + + + + Load in write mode (-w) + + + false + + + diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 2fb9b71c..ff9b1096 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -1,16 +1,20 @@ #include "DisassemblyContextMenu.h" #include "dialogs/preferences/PreferencesDialog.h" +#include "dialogs/EditInstructionDialog.h" #include "dialogs/CommentsDialog.h" #include "dialogs/FlagDialog.h" #include "dialogs/RenameDialog.h" #include "dialogs/XrefsDialog.h" #include #include +#include DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent) : QMenu(parent), offset(0), canCopy(false), + actionEditInstruction(this), + actionEditBytes(this), actionCopy(this), actionAddComment(this), actionAddFlag(this), @@ -78,6 +82,17 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent) createAction(&actionXRefs, tr("Show X-Refs"), getXRefSequence(), SLOT(on_actionXRefs_triggered())); createAction(&actionDisplayOptions, tr("Show Options"), getDisplayOptionsSequence(), SLOT(on_actionDisplayOptions_triggered())); + addSeparator(); + editMenu = new QMenu(tr("Edit"), this); + editMenuAction = addMenu(editMenu); + actionEditInstruction.setText(tr("Instruction")); + editMenu->addAction(&actionEditInstruction); + actionEditBytes.setText(tr("Bytes")); + editMenu->addAction(&actionEditBytes); + + connect(&actionEditInstruction, SIGNAL(triggered(bool)), this, SLOT(on_actionEditInstruction_triggered())); + connect(&actionEditBytes, SIGNAL(triggered(bool)), this, SLOT(on_actionEditBytes_triggered())); + connect(&actionSetBaseBinary, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBaseBinary_triggered())); connect(&actionSetBaseOctal, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBaseOctal_triggered())); connect(&actionSetBaseDecimal, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBaseDecimal_triggered())); @@ -220,6 +235,42 @@ QKeySequence DisassemblyContextMenu::getDisplayOptionsSequence() const return {}; //TODO insert correct sequence } +void DisassemblyContextMenu::on_actionEditInstruction_triggered() +{ + EditInstructionDialog *e = new EditInstructionDialog(this); + e->setWindowTitle(tr("Edit Instruction at %1").arg(RAddressString(offset))); + + QString oldInstruction = Core()->cmdj("aoj").array().first().toObject()["opcode"].toString(); + e->setInstruction(oldInstruction); + + if (e->exec()){} + { + QString instruction = e->getInstruction(); + if (instruction != oldInstruction) + { + Core()->editInstruction(offset, instruction); + } + } +} + +void DisassemblyContextMenu::on_actionEditBytes_triggered() +{ + EditInstructionDialog *e = new EditInstructionDialog(this); + e->setWindowTitle(tr("Edit Bytes at %1").arg(RAddressString(offset))); + + QString oldBytes = Core()->cmdj("aoj").array().first().toObject()["bytes"].toString(); + e->setInstruction(oldBytes); + + if (e->exec()){} + { + QString bytes = e->getInstruction(); + if (bytes != oldBytes) + { + Core()->editBytes(offset, bytes); + } + } +} + void DisassemblyContextMenu::on_actionCopy_triggered() { emit copy(); diff --git a/src/menus/DisassemblyContextMenu.h b/src/menus/DisassemblyContextMenu.h index 5b94a02e..9dd5f705 100644 --- a/src/menus/DisassemblyContextMenu.h +++ b/src/menus/DisassemblyContextMenu.h @@ -23,6 +23,9 @@ public slots: private slots: void aboutToShowSlot(); + void on_actionEditInstruction_triggered(); + void on_actionEditBytes_triggered(); + void on_actionCopy_triggered(); void on_actionAddComment_triggered(); @@ -64,6 +67,11 @@ private: QList anonymousActions; + QMenu *editMenu; + QAction *editMenuAction; + QAction actionEditInstruction; + QAction actionEditBytes; + QAction actionCopy; QAction *copySeparator;