"Fossies" - the Fresh Open Source Software Archive

Member "cutter-1.10.3/src/menus/DisassemblyContextMenu.cpp" (8 May 2020, 35045 Bytes) of package /linux/privat/cutter-1.10.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "DisassemblyContextMenu.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.10.2_vs_1.10.3.

    1 #include "DisassemblyContextMenu.h"
    2 #include "dialogs/preferences/PreferencesDialog.h"
    3 #include "dialogs/EditInstructionDialog.h"
    4 #include "dialogs/CommentsDialog.h"
    5 #include "dialogs/FlagDialog.h"
    6 #include "dialogs/RenameDialog.h"
    7 #include "dialogs/XrefsDialog.h"
    8 #include "dialogs/EditVariablesDialog.h"
    9 #include "dialogs/SetToDataDialog.h"
   10 #include "dialogs/EditFunctionDialog.h"
   11 #include "dialogs/LinkTypeDialog.h"
   12 #include "dialogs/EditStringDialog.h"
   13 #include "dialogs/BreakpointsDialog.h"
   14 #include "MainWindow.h"
   15 
   16 #include <QtCore>
   17 #include <QShortcut>
   18 #include <QJsonArray>
   19 #include <QClipboard>
   20 #include <QApplication>
   21 #include <QPushButton>
   22 
   23 DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *mainWindow)
   24     :   QMenu(parent),
   25         offset(0),
   26         canCopy(false),
   27         mainWindow(mainWindow),
   28         actionEditInstruction(this),
   29         actionNopInstruction(this),
   30         actionJmpReverse(this),
   31         actionEditBytes(this),
   32         actionCopy(this),
   33         actionCopyAddr(this),
   34         actionAddComment(this),
   35         actionAddFlag(this),
   36         actionAnalyzeFunction(this),
   37         actionEditFunction(this),
   38         actionRename(this),
   39         actionRenameUsedHere(this),
   40         actionSetFunctionVarTypes(this),
   41         actionXRefs(this),
   42         actionDisplayOptions(this),
   43         actionDeleteComment(this),
   44         actionDeleteFlag(this),
   45         actionDeleteFunction(this),
   46         actionLinkType(this),
   47         actionSetBaseBinary(this),
   48         actionSetBaseOctal(this),
   49         actionSetBaseDecimal(this),
   50         actionSetBaseHexadecimal(this),
   51         actionSetBasePort(this),
   52         actionSetBaseIPAddr(this),
   53         actionSetBaseSyscall(this),
   54         actionSetBaseString(this),
   55         actionSetBits16(this),
   56         actionSetBits32(this),
   57         actionSetBits64(this),
   58         actionContinueUntil(this),
   59         actionAddBreakpoint(this),
   60         actionAdvancedBreakpoint(this),
   61         actionSetPC(this),
   62         actionSetToCode(this),
   63         actionSetAsStringAuto(this),
   64         actionSetAsStringRemove(this),
   65         actionSetAsStringAdvanced(this),
   66         actionSetToDataEx(this),
   67         actionSetToDataByte(this),
   68         actionSetToDataWord(this),
   69         actionSetToDataDword(this),
   70         actionSetToDataQword(this),
   71         showInSubmenu(this)
   72 {
   73     initAction(&actionCopy, tr("Copy"), SLOT(on_actionCopy_triggered()), getCopySequence());
   74     addAction(&actionCopy);
   75 
   76     initAction(&actionCopyAddr, tr("Copy address"), SLOT(on_actionCopyAddr_triggered()),
   77                getCopyAddressSequence());
   78     addAction(&actionCopyAddr);
   79 
   80     initAction(&showInSubmenu, tr("Show in"), nullptr);
   81     addAction(&showInSubmenu);
   82 
   83     copySeparator = addSeparator();
   84 
   85     initAction(&actionAddComment, tr("Add Comment"),
   86                SLOT(on_actionAddComment_triggered()), getCommentSequence());
   87     addAction(&actionAddComment);
   88 
   89     initAction(&actionAddFlag, tr("Add Flag"),
   90                SLOT(on_actionAddFlag_triggered()), getAddFlagSequence());
   91     addAction(&actionAddFlag);
   92 
   93     initAction(&actionRename, tr("Rename"),
   94                SLOT(on_actionRename_triggered()), getRenameSequence());
   95     addAction(&actionRename);
   96 
   97     initAction(&actionEditFunction, tr("Edit function"),
   98                SLOT(on_actionEditFunction_triggered()), getEditFunctionSequence());
   99     addAction(&actionEditFunction);
  100 
  101     initAction(&actionRenameUsedHere, tr("Rename Flag/Fcn/Var Used Here"),
  102                SLOT(on_actionRenameUsedHere_triggered()), getRenameUsedHereSequence());
  103     addAction(&actionRenameUsedHere);
  104 
  105     initAction(&actionSetFunctionVarTypes, tr("Re-type function local vars"),
  106                SLOT(on_actionSetFunctionVarTypes_triggered()), getRetypeSequence());
  107     addAction(&actionSetFunctionVarTypes);
  108 
  109     initAction(&actionDeleteComment, tr("Delete comment"), SLOT(on_actionDeleteComment_triggered()));
  110     addAction(&actionDeleteComment);
  111 
  112     initAction(&actionDeleteFlag, tr("Delete flag"), SLOT(on_actionDeleteFlag_triggered()));
  113     addAction(&actionDeleteFlag);
  114 
  115     initAction(&actionDeleteFunction, tr("Undefine function"),
  116                SLOT(on_actionDeleteFunction_triggered()), getUndefineFunctionSequence());
  117     addAction(&actionDeleteFunction);
  118 
  119     initAction(&actionAnalyzeFunction, tr("Define function here"),
  120                SLOT(on_actionAnalyzeFunction_triggered()), getDefineNewFunctionSequence());
  121     addAction(&actionAnalyzeFunction);
  122 
  123     addSeparator();
  124 
  125     addSetBaseMenu();
  126 
  127     addSetBitsMenu();
  128 
  129     structureOffsetMenu = addMenu(tr("Structure offset"));
  130     connect(structureOffsetMenu, SIGNAL(triggered(QAction*)),
  131             this, SLOT(on_actionStructureOffsetMenu_triggered(QAction*)));
  132 
  133     initAction(&actionLinkType, tr("Link Type to Address"),
  134                SLOT(on_actionLinkType_triggered()), getLinkTypeSequence());
  135     addAction(&actionLinkType);
  136 
  137     addSetAsMenu();
  138 
  139     addSeparator();
  140 
  141     initAction(&actionXRefs, tr("Show X-Refs"),
  142                SLOT(on_actionXRefs_triggered()), getXRefSequence());
  143     addAction(&actionXRefs);
  144 
  145     initAction(&actionDisplayOptions, tr("Show Options"),
  146                SLOT(on_actionDisplayOptions_triggered()), getDisplayOptionsSequence());
  147 
  148     addSeparator();
  149 
  150     addEditMenu();
  151 
  152     addSeparator();
  153 
  154     addBreakpointMenu();
  155     addDebugMenu();
  156 
  157     addSeparator();
  158 
  159     if (mainWindow) {
  160         pluginMenu = mainWindow->getContextMenuExtensions(MainWindow::ContextMenuType::Disassembly);
  161         pluginActionMenuAction = addMenu(pluginMenu);
  162     }
  163 
  164     addSeparator();
  165 
  166     connect(this, &DisassemblyContextMenu::aboutToShow,
  167             this, &DisassemblyContextMenu::aboutToShowSlot);
  168 }
  169 
  170 DisassemblyContextMenu::~DisassemblyContextMenu()
  171 {
  172 }
  173 
  174 void DisassemblyContextMenu::addSetBaseMenu()
  175 {
  176     setBaseMenu = addMenu(tr("Set Immediate Base to..."));
  177 
  178     initAction(&actionSetBaseBinary, tr("Binary"));
  179     setBaseMenu->addAction(&actionSetBaseBinary);
  180     connect(&actionSetBaseBinary, &QAction::triggered, this, [this] { setBase("b"); });
  181 
  182     initAction(&actionSetBaseOctal, tr("Octal"));
  183     setBaseMenu->addAction(&actionSetBaseOctal);
  184     connect(&actionSetBaseOctal, &QAction::triggered, this, [this] { setBase("o"); });
  185 
  186     initAction(&actionSetBaseDecimal, tr("Decimal"));
  187     setBaseMenu->addAction(&actionSetBaseDecimal);
  188     connect(&actionSetBaseDecimal, &QAction::triggered, this, [this] { setBase("d"); });
  189 
  190     initAction(&actionSetBaseHexadecimal, tr("Hexadecimal"));
  191     setBaseMenu->addAction(&actionSetBaseHexadecimal);
  192     connect(&actionSetBaseHexadecimal, &QAction::triggered, this, [this] { setBase("h"); });
  193 
  194     initAction(&actionSetBasePort, tr("Network Port"));
  195     setBaseMenu->addAction(&actionSetBasePort);
  196     connect(&actionSetBasePort, &QAction::triggered, this, [this] { setBase("p"); });
  197 
  198     initAction(&actionSetBaseIPAddr, tr("IP Address"));
  199     setBaseMenu->addAction(&actionSetBaseIPAddr);
  200     connect(&actionSetBaseIPAddr, &QAction::triggered, this, [this] { setBase("i"); });
  201 
  202     initAction(&actionSetBaseSyscall, tr("Syscall"));
  203     setBaseMenu->addAction(&actionSetBaseSyscall);
  204     connect(&actionSetBaseSyscall, &QAction::triggered, this, [this] { setBase("S"); });
  205 
  206     initAction(&actionSetBaseString, tr("String"));
  207     setBaseMenu->addAction(&actionSetBaseString);
  208     connect(&actionSetBaseString, &QAction::triggered, this, [this] { setBase("s"); });
  209 }
  210 
  211 void DisassemblyContextMenu::addSetBitsMenu()
  212 {
  213     setBitsMenu = addMenu(tr("Set current bits to..."));
  214 
  215     initAction(&actionSetBits16, "16");
  216     setBitsMenu->addAction(&actionSetBits16);
  217     connect(&actionSetBits16, &QAction::triggered, this, [this] { setBits(16); });
  218 
  219     initAction(&actionSetBits32, "32");
  220     setBitsMenu->addAction(&actionSetBits32);
  221     connect(&actionSetBits32, &QAction::triggered, this, [this] { setBits(32); });
  222 
  223     initAction(&actionSetBits64, "64");
  224     setBitsMenu->addAction(&actionSetBits64);
  225     connect(&actionSetBits64, &QAction::triggered, this, [this] { setBits(64); });
  226 }
  227 
  228 
  229 void DisassemblyContextMenu::addSetAsMenu()
  230 {
  231     setAsMenu = addMenu(tr("Set as..."));
  232 
  233     initAction(&actionSetToCode, tr("Code"),
  234                SLOT(on_actionSetToCode_triggered()), getSetToCodeSequence());
  235     setAsMenu->addAction(&actionSetToCode);
  236 
  237     setAsString = setAsMenu->addMenu(tr("String..."));
  238 
  239     initAction(&actionSetAsStringAuto, tr("Auto-detect"),
  240                SLOT(on_actionSetAsString_triggered()), getSetAsStringSequence());
  241     initAction(&actionSetAsStringRemove, tr("Remove"),
  242                SLOT(on_actionSetAsStringRemove_triggered()));
  243     initAction(&actionSetAsStringAdvanced, tr("Advanced"),
  244                SLOT(on_actionSetAsStringAdvanced_triggered()));
  245 
  246 
  247     setAsString->addAction(&actionSetAsStringAuto);
  248     setAsString->addAction(&actionSetAsStringRemove);
  249     setAsString->addAction(&actionSetAsStringAdvanced);
  250 
  251     addSetToDataMenu();
  252 }
  253 
  254 void DisassemblyContextMenu::addSetToDataMenu()
  255 {
  256     setToDataMenu = setAsMenu->addMenu(tr("Data..."));
  257 
  258     initAction(&actionSetToDataByte, tr("Byte"));
  259     setToDataMenu->addAction(&actionSetToDataByte);
  260     connect(&actionSetToDataByte, &QAction::triggered, this, [this] { setToData(1); });
  261 
  262     initAction(&actionSetToDataWord, tr("Word"));
  263     setToDataMenu->addAction(&actionSetToDataWord);
  264     connect(&actionSetToDataWord, &QAction::triggered, this, [this] { setToData(2); });
  265 
  266     initAction(&actionSetToDataDword, tr("Dword"));
  267     setToDataMenu->addAction(&actionSetToDataDword);
  268     connect(&actionSetToDataDword, &QAction::triggered, this, [this] { setToData(4); });
  269 
  270     initAction(&actionSetToDataQword, tr("Qword"));
  271     setToDataMenu->addAction(&actionSetToDataQword);
  272     connect(&actionSetToDataQword, &QAction::triggered, this, [this] { setToData(8); });
  273 
  274     initAction(&actionSetToDataEx, "...",
  275                SLOT(on_actionSetToDataEx_triggered()), getSetToDataExSequence());
  276     setToDataMenu->addAction(&actionSetToDataEx);
  277 
  278     auto switchAction = new QAction(this);
  279     initAction(switchAction, "Switch Data",
  280                SLOT(on_actionSetToData_triggered()), getSetToDataSequence());
  281 }
  282 
  283 void DisassemblyContextMenu::addEditMenu()
  284 {
  285     editMenu = addMenu(tr("Edit"));
  286 
  287     initAction(&actionEditInstruction, tr("Instruction"), SLOT(on_actionEditInstruction_triggered()));
  288     editMenu->addAction(&actionEditInstruction);
  289 
  290     initAction(&actionNopInstruction, tr("Nop Instruction"), SLOT(on_actionNopInstruction_triggered()));
  291     editMenu->addAction(&actionNopInstruction);
  292 
  293     initAction(&actionEditBytes, tr("Bytes"), SLOT(on_actionEditBytes_triggered()));
  294     editMenu->addAction(&actionEditBytes);
  295 
  296     initAction(&actionJmpReverse, tr("Reverse Jump"), SLOT(on_actionJmpReverse_triggered()));
  297     editMenu->addAction(&actionJmpReverse);
  298 }
  299 
  300 void DisassemblyContextMenu::addBreakpointMenu()
  301 {
  302     breakpointMenu = addMenu(tr("Breakpoint"));
  303 
  304     initAction(&actionAddBreakpoint, tr("Add/remove breakpoint"),
  305                SLOT(on_actionAddBreakpoint_triggered()), getAddBPSequence());
  306     breakpointMenu->addAction(&actionAddBreakpoint);
  307     initAction(&actionAdvancedBreakpoint, tr("Advanced breakpoint"),
  308                SLOT(on_actionAdvancedBreakpoint_triggered()), QKeySequence(Qt::CTRL+Qt::Key_F2));
  309     breakpointMenu->addAction(&actionAdvancedBreakpoint);
  310 }
  311 
  312 void DisassemblyContextMenu::addDebugMenu()
  313 {
  314     debugMenu = addMenu(tr("Debug"));
  315 
  316     initAction(&actionContinueUntil, tr("Continue until line"),
  317                SLOT(on_actionContinueUntil_triggered()));
  318     debugMenu->addAction(&actionContinueUntil);
  319 
  320     initAction(&actionSetPC, "Set PC", SLOT(on_actionSetPC_triggered()));
  321     debugMenu->addAction(&actionSetPC);
  322 }
  323 
  324 QVector<DisassemblyContextMenu::ThingUsedHere> DisassemblyContextMenu::getThingUsedHere(RVA offset)
  325 {
  326     QVector<ThingUsedHere> result;
  327     const QJsonArray array = Core()->cmdj("anj @ " + QString::number(offset)).array();
  328     result.reserve(array.size());
  329     for (const auto &thing : array) {
  330         auto obj = thing.toObject();
  331         RVA offset = obj["offset"].toVariant().toULongLong();
  332         QString name;
  333 
  334         // If real names display is enabled, show flag's real name instead of full flag name
  335         if (Config()->getConfigBool("asm.flags.real") && obj.contains("realname")) {
  336             name = obj["realname"].toString();
  337         } else {
  338             name = obj["name"].toString();
  339         }
  340 
  341         QString typeString = obj["type"].toString();
  342         ThingUsedHere::Type type = ThingUsedHere::Type::Address;
  343         if (typeString == "var") {
  344             type = ThingUsedHere::Type::Var;
  345         } else if (typeString == "flag") {
  346             type = ThingUsedHere::Type::Flag;
  347         } else if (typeString == "function") {
  348             type = ThingUsedHere::Type::Function;
  349         } else if (typeString == "address") {
  350             type = ThingUsedHere::Type::Address;
  351         }
  352         result.push_back(ThingUsedHere{name, offset, type});
  353     }
  354     return result;
  355 }
  356 
  357 void DisassemblyContextMenu::updateTargetMenuActions(const QVector<ThingUsedHere> &targets)
  358 {
  359     for (auto action : showTargetMenuActions) {
  360         removeAction(action);
  361         auto menu = action->menu();
  362         if (menu) {
  363             menu->deleteLater();
  364         }
  365         action->deleteLater();
  366     }
  367     showTargetMenuActions.clear();
  368     for (auto &target : targets) {
  369         QString name;
  370         if (target.name.isEmpty()) {
  371             name = tr("%1 (used here)").arg(RAddressString(target.offset));
  372         } else {
  373             name = tr("%1 (%2)").arg(target.name, RAddressString(target.offset));
  374         }
  375         auto action = new QAction(name, this);
  376         showTargetMenuActions.append(action);
  377         auto menu = mainWindow->createShowInMenu(this, target.offset);
  378         action->setMenu(menu);
  379         QAction *copyAddress = new QAction(tr("Copy address"), menu);
  380         RVA offset = target.offset;
  381         connect(copyAddress, &QAction::triggered, copyAddress, [offset]() {
  382             QClipboard *clipboard = QApplication::clipboard();
  383             clipboard->setText(RAddressString(offset));
  384         });
  385         menu->addSeparator();
  386         menu->addAction(copyAddress);
  387     }
  388     insertActions(copySeparator, showTargetMenuActions);
  389 }
  390 
  391 void DisassemblyContextMenu::setOffset(RVA offset)
  392 {
  393     this->offset = offset;
  394 
  395     this->actionSetFunctionVarTypes.setVisible(true);
  396 }
  397 
  398 void DisassemblyContextMenu::setCanCopy(bool enabled)
  399 {
  400     this->canCopy = enabled;
  401 }
  402 
  403 void DisassemblyContextMenu::setCurHighlightedWord(const QString &text)
  404 {
  405     this->curHighlightedWord = text;
  406 }
  407 
  408 void DisassemblyContextMenu::aboutToShowSlot()
  409 {
  410     // check if set immediate base menu makes sense
  411     QJsonObject instObject = Core()->cmdj("aoj @ " + QString::number(
  412                                               offset)).array().first().toObject();
  413     auto keys = instObject.keys();
  414     bool immBase = keys.contains("val") || keys.contains("ptr");
  415     setBaseMenu->menuAction()->setVisible(immBase);
  416     setBitsMenu->menuAction()->setVisible(true);
  417 
  418     // Create structure offset menu if it makes sense
  419     QString memBaseReg; // Base register
  420     QVariant memDisp; // Displacement
  421     if (instObject.contains("opex") && instObject["opex"].toObject().contains("operands")) {
  422         // Loop through both the operands of the instruction
  423         for (const QJsonValue value: instObject["opex"].toObject()["operands"].toArray()) {
  424             QJsonObject operand = value.toObject();
  425             if (operand.contains("type") && operand["type"].toString() == "mem" &&
  426                     operand.contains("base") && !operand["base"].toString().contains("bp") &&
  427                     operand.contains("disp") && operand["disp"].toVariant().toLongLong() > 0) {
  428 
  429                     // The current operand is the one which has an immediate displacement
  430                     memBaseReg = operand["base"].toString();
  431                     memDisp = operand["disp"].toVariant();
  432                     break;
  433 
  434             }
  435         }
  436     }
  437     if (memBaseReg.isEmpty()) {
  438         // hide structure offset menu
  439         structureOffsetMenu->menuAction()->setVisible(false);
  440     } else {
  441         // show structure offset menu
  442         structureOffsetMenu->menuAction()->setVisible(true);
  443         structureOffsetMenu->clear();
  444 
  445         // Get the possible offsets using the "ahts" command
  446         // TODO: add ahtj command to radare2 and then use it here
  447         QStringList ret = Core()->cmdList("ahts " + memDisp.toString());
  448         for (const QString &val : ret) {
  449             if (val.isEmpty()) {
  450                 continue;
  451             }
  452             structureOffsetMenu->addAction("[" + memBaseReg + " + " + val + "]")->setData(val);
  453         }
  454         if (structureOffsetMenu->isEmpty()) {
  455             // No possible offset was found so hide the menu
  456             structureOffsetMenu->menuAction()->setVisible(false);
  457         }
  458     }
  459 
  460     actionAnalyzeFunction.setVisible(true);
  461 
  462     // Show the option to remove a defined string only if a string is defined in this address
  463     QString stringDefinition = Core()->cmdRawAt("Cs.", offset);
  464     actionSetAsStringRemove.setVisible(!stringDefinition.isEmpty());
  465 
  466     QString comment = Core()->cmdRawAt("CC.", offset);
  467 
  468     if (comment.isNull() || comment.isEmpty()) {
  469         actionDeleteComment.setVisible(false);
  470         actionAddComment.setText(tr("Add Comment"));
  471     } else {
  472         actionDeleteComment.setVisible(true);
  473         actionAddComment.setText(tr("Edit Comment"));
  474     }
  475 
  476     actionCopy.setVisible(canCopy);
  477     copySeparator->setVisible(canCopy);
  478 
  479 
  480     RCore *core = Core()->core();
  481     RAnalFunction *fcn = Core()->functionAt(offset);
  482     RAnalFunction *in_fcn = Core()->functionIn(offset);
  483     RFlagItem *f = r_flag_get_i (core->flags, offset);
  484 
  485     actionDeleteFlag.setVisible(f ? true : false);
  486     actionDeleteFunction.setVisible(fcn ? true : false);
  487 
  488     if (fcn) {
  489         actionAnalyzeFunction.setVisible(false);
  490         actionRename.setVisible(true);
  491         actionRename.setText(tr("Rename function \"%1\"").arg(fcn->name));
  492     } else if (f) {
  493         QString name;
  494 
  495         // Check if Realname is enabled. If yes, show it instead of the full flag-name.
  496         if (Config()->getConfigBool("asm.flags.real") && f->realname) {
  497             name = f->realname;
  498         } else {
  499             name = f->name;
  500         }
  501 
  502         actionRename.setVisible(true);
  503         actionRename.setText(tr("Rename flag \"%1\"").arg(name));
  504     } else {
  505         actionRename.setVisible(false);
  506     }
  507 
  508     // Only show retype for local vars if in a function
  509     if (in_fcn) {
  510         auto vars = Core()->getVariables(offset);
  511         actionSetFunctionVarTypes.setVisible(!vars.empty());
  512         actionEditFunction.setVisible(true);
  513         actionEditFunction.setText(tr("Edit function \"%1\"").arg(in_fcn->name));
  514     } else {
  515         actionSetFunctionVarTypes.setVisible(false);
  516         actionEditFunction.setVisible(false);
  517     }
  518 
  519 
  520     // Only show "rename X used here" if there is something to rename
  521     auto thingsUsedHere = getThingUsedHere(offset);
  522     if (!thingsUsedHere.isEmpty()) {
  523         actionRenameUsedHere.setVisible(true);
  524         auto &thingUsedHere = thingsUsedHere.first();
  525         if (thingUsedHere.type == ThingUsedHere::Type::Address) {
  526             RVA offset = thingUsedHere.offset;
  527             actionRenameUsedHere.setText(tr("Add flag at %1 (used here)").arg(RAddressString(offset)));
  528         } else if (thingUsedHere.type == ThingUsedHere::Type::Function) {
  529             actionRenameUsedHere.setText(tr("Rename \"%1\"").arg(thingUsedHere.name));
  530         }  else {
  531             actionRenameUsedHere.setText(tr("Rename \"%1\" (used here)").arg(thingUsedHere.name));
  532         }
  533     } else {
  534         actionRenameUsedHere.setVisible(false);
  535     }
  536     updateTargetMenuActions(thingsUsedHere);
  537 
  538     // Decide to show Reverse jmp option
  539     showReverseJmpQuery();
  540 
  541     if (showInSubmenu.menu() != nullptr) {
  542         showInSubmenu.menu()->deleteLater();
  543     }
  544     showInSubmenu.setMenu(mainWindow->createShowInMenu(this, offset));
  545 
  546     // Only show debug options if we are currently debugging
  547     debugMenu->menuAction()->setVisible(Core()->currentlyDebugging);
  548     bool hasBreakpoint = Core()->breakpointIndexAt(offset) > -1;
  549     actionAddBreakpoint.setText(hasBreakpoint ?
  550                                      tr("Remove breakpoint") : tr("Add breakpoint"));
  551     actionAdvancedBreakpoint.setText(hasBreakpoint ?
  552                                      tr("Edit breakpoint") : tr("Advanced breakpoint"));
  553     QString progCounterName = Core()->getRegisterName("PC").toUpper();
  554     actionSetPC.setText("Set " + progCounterName + " here");
  555 
  556     if (pluginMenu) {
  557         pluginActionMenuAction->setVisible(!pluginMenu->isEmpty());
  558         for (QAction *pluginAction : pluginMenu->actions()) {
  559             pluginAction->setData(QVariant::fromValue(offset));
  560         }
  561     }
  562 }
  563 
  564 QKeySequence DisassemblyContextMenu::getCopySequence() const
  565 {
  566     return QKeySequence::Copy;
  567 }
  568 
  569 QKeySequence DisassemblyContextMenu::getCommentSequence() const
  570 {
  571     return {Qt::Key_Semicolon};
  572 }
  573 
  574 QKeySequence DisassemblyContextMenu::getCopyAddressSequence() const
  575 {
  576     return {Qt::CTRL + Qt::SHIFT + Qt::Key_C};
  577 }
  578 
  579 QKeySequence DisassemblyContextMenu::getSetToCodeSequence() const
  580 {
  581     return {Qt::Key_C};
  582 }
  583 
  584 QKeySequence DisassemblyContextMenu::getSetAsStringSequence() const
  585 {
  586     return {Qt::Key_A};
  587 }
  588 
  589 
  590 QKeySequence DisassemblyContextMenu::getSetToDataSequence() const
  591 {
  592     return {Qt::Key_D};
  593 }
  594 
  595 QKeySequence DisassemblyContextMenu::getSetToDataExSequence() const
  596 {
  597     return {Qt::Key_Asterisk};
  598 }
  599 
  600 QKeySequence DisassemblyContextMenu::getAddFlagSequence() const
  601 {
  602     return {}; //TODO insert correct sequence
  603 }
  604 
  605 QKeySequence DisassemblyContextMenu::getRenameSequence() const
  606 {
  607     return {Qt::Key_N};
  608 }
  609 
  610 QKeySequence DisassemblyContextMenu::getRenameUsedHereSequence() const
  611 {
  612     return {Qt::SHIFT + Qt::Key_N};
  613 }
  614 
  615 QKeySequence DisassemblyContextMenu::getRetypeSequence() const
  616 {
  617     return {Qt::Key_Y};
  618 }
  619 
  620 QKeySequence DisassemblyContextMenu::getXRefSequence() const
  621 {
  622     return {Qt::Key_X};
  623 }
  624 
  625 QKeySequence DisassemblyContextMenu::getDisplayOptionsSequence() const
  626 {
  627     return {}; //TODO insert correct sequence
  628 }
  629 
  630 QKeySequence DisassemblyContextMenu::getLinkTypeSequence() const
  631 {
  632     return {Qt::Key_L};
  633 }
  634 
  635 QList<QKeySequence> DisassemblyContextMenu::getAddBPSequence() const
  636 {
  637     return {Qt::Key_F2, Qt::CTRL + Qt::Key_B};
  638 }
  639 
  640 QKeySequence DisassemblyContextMenu::getDefineNewFunctionSequence() const
  641 {
  642     return {Qt::Key_P};
  643 }
  644 
  645 QKeySequence DisassemblyContextMenu::getEditFunctionSequence() const
  646 {
  647     return {Qt::SHIFT + Qt::Key_P};
  648 }
  649 
  650 QKeySequence DisassemblyContextMenu::getUndefineFunctionSequence() const
  651 {
  652     return {Qt::Key_U};
  653 }
  654 
  655 
  656 void DisassemblyContextMenu::on_actionEditInstruction_triggered()
  657 {
  658     if (!ioModesController.prepareForWriting()) {
  659         return;
  660     }
  661     EditInstructionDialog e(EDIT_TEXT, this);
  662     e.setWindowTitle(tr("Edit Instruction at %1").arg(RAddressString(offset)));
  663 
  664     QString oldInstructionOpcode = Core()->getInstructionOpcode(offset);
  665     QString oldInstructionBytes = Core()->getInstructionBytes(offset);
  666 
  667     e.setInstruction(oldInstructionOpcode);
  668 
  669     if (e.exec()) {
  670         QString userInstructionOpcode = e.getInstruction();
  671         if (userInstructionOpcode != oldInstructionOpcode) {
  672             Core()->editInstruction(offset, userInstructionOpcode);
  673         }
  674     }
  675 }
  676 
  677 void DisassemblyContextMenu::on_actionNopInstruction_triggered()
  678 {
  679     if (!ioModesController.prepareForWriting()) {
  680         return;
  681     }
  682     Core()->nopInstruction(offset);
  683 }
  684 
  685 void DisassemblyContextMenu::showReverseJmpQuery()
  686 {
  687     QString type;
  688 
  689     QJsonArray array = Core()->cmdj("pdj 1 @ " + RAddressString(offset)).array();
  690     if (array.isEmpty()) {
  691         return;
  692     }
  693 
  694     type = array.first().toObject()["type"].toString();
  695     if (type == "cjmp") {
  696         actionJmpReverse.setVisible(true);
  697     } else {
  698         actionJmpReverse.setVisible(false);
  699     }
  700 }
  701 
  702 void DisassemblyContextMenu::on_actionJmpReverse_triggered()
  703 {
  704     if (!ioModesController.prepareForWriting()) {
  705         return;
  706     }
  707     Core()->jmpReverse(offset);
  708 }
  709 
  710 void DisassemblyContextMenu::on_actionEditBytes_triggered()
  711 {
  712     if (!ioModesController.prepareForWriting()) {
  713         return;
  714     }
  715     EditInstructionDialog e(EDIT_BYTES, this);
  716     e.setWindowTitle(tr("Edit Bytes at %1").arg(RAddressString(offset)));
  717 
  718     QString oldBytes = Core()->getInstructionBytes(offset);
  719     e.setInstruction(oldBytes);
  720 
  721     if (e.exec()) {
  722         QString bytes = e.getInstruction();
  723         if (bytes != oldBytes) {
  724             Core()->editBytes(offset, bytes);
  725         }
  726     }
  727 }
  728 
  729 void DisassemblyContextMenu::on_actionCopy_triggered()
  730 {
  731     emit copy();
  732 }
  733 
  734 void DisassemblyContextMenu::on_actionCopyAddr_triggered()
  735 {
  736     QClipboard *clipboard = QApplication::clipboard();
  737     clipboard->setText(RAddressString(offset));
  738 }
  739 
  740 void DisassemblyContextMenu::on_actionAddBreakpoint_triggered()
  741 {
  742     Core()->toggleBreakpoint(offset);
  743 }
  744 
  745 void DisassemblyContextMenu::on_actionAdvancedBreakpoint_triggered()
  746 {
  747     int index = Core()->breakpointIndexAt(offset);
  748     if (index >= 0) {
  749         BreakpointsDialog::editBreakpoint(Core()->getBreakpointAt(offset), this);
  750     } else {
  751         BreakpointsDialog::createNewBreakpoint(offset, this);
  752     }
  753 }
  754 
  755 void DisassemblyContextMenu::on_actionContinueUntil_triggered()
  756 {
  757     Core()->continueUntilDebug(RAddressString(offset));
  758 }
  759 
  760 void DisassemblyContextMenu::on_actionSetPC_triggered()
  761 {
  762     QString progCounterName = Core()->getRegisterName("PC");
  763     Core()->setRegister(progCounterName, RAddressString(offset).toUpper());
  764 }
  765 
  766 void DisassemblyContextMenu::on_actionAddComment_triggered()
  767 {
  768     CommentsDialog::addOrEditComment(offset, this);
  769 }
  770 
  771 void DisassemblyContextMenu::on_actionAnalyzeFunction_triggered()
  772 {
  773     RenameDialog dialog(mainWindow);
  774     dialog.setWindowTitle(tr("Analyze function at %1").arg(RAddressString(offset)));
  775     dialog.setPlaceholderText(tr("Function name"));
  776     if (dialog.exec()) {
  777         QString function_name = dialog.getName();
  778         Core()->createFunctionAt(offset, function_name);
  779     }
  780 }
  781 
  782 void DisassemblyContextMenu::on_actionAddFlag_triggered()
  783 {
  784     FlagDialog dialog(offset, this->parentWidget());
  785     dialog.exec();
  786 }
  787 
  788 void DisassemblyContextMenu::on_actionRename_triggered()
  789 {
  790     RCore *core = Core()->core();
  791 
  792     RenameDialog dialog(mainWindow);
  793 
  794     RAnalFunction *fcn = Core()->functionIn (offset);
  795     RFlagItem *f = r_flag_get_i (core->flags, offset);
  796     if (fcn) {
  797         /* Rename function */
  798         dialog.setWindowTitle(tr("Rename function %1").arg(fcn->name));
  799         dialog.setName(fcn->name);
  800         if (dialog.exec()) {
  801             QString new_name = dialog.getName();
  802             Core()->renameFunction(fcn->name, new_name);
  803         }
  804     } else if (f) {
  805         /* Rename current flag */
  806         dialog.setWindowTitle(tr("Rename flag %1").arg(f->name));
  807         dialog.setName(f->name);
  808         if (dialog.exec()) {
  809             QString new_name = dialog.getName();
  810             Core()->renameFlag(f->name, new_name);
  811         }
  812     } else {
  813         return;
  814     }
  815 }
  816 
  817 void DisassemblyContextMenu::on_actionRenameUsedHere_triggered()
  818 {
  819     auto array = getThingUsedHere(offset);
  820     if (array.isEmpty()) {
  821         return;
  822     }
  823 
  824     auto thingUsedHere = array.first();
  825 
  826     RenameDialog dialog(mainWindow);
  827 
  828     QString oldName;
  829     auto type = thingUsedHere.type;
  830 
  831     if (type == ThingUsedHere::Type::Address) {
  832         RVA offset = thingUsedHere.offset;
  833         dialog.setWindowTitle(tr("Add flag at %1").arg(RAddressString(offset)));
  834         dialog.setName("label." + QString::number(offset, 16));
  835     } else {
  836         oldName = thingUsedHere.name;
  837         dialog.setWindowTitle(tr("Rename %1").arg(oldName));
  838         dialog.setName(oldName);
  839     }
  840 
  841 
  842     if (dialog.exec()) {
  843         QString newName = dialog.getName().trimmed();
  844         if (!newName.isEmpty()) {
  845             Core()->cmdRawAt(QString("an %1").arg(newName), offset);
  846 
  847             if (type == ThingUsedHere::Type::Address || type == ThingUsedHere::Type::Flag) {
  848                 Core()->triggerFlagsChanged();
  849             } else if (type == ThingUsedHere::Type::Var) {
  850                 Core()->triggerVarsChanged();
  851             } else if (type == ThingUsedHere::Type::Function) {
  852                 Core()->triggerFunctionRenamed(oldName, newName);
  853             }
  854         }
  855     }
  856 }
  857 
  858 void DisassemblyContextMenu::on_actionSetFunctionVarTypes_triggered()
  859 {
  860     RAnalFunction *fcn = Core()->functionIn(offset);
  861 
  862     if (!fcn) {
  863         QMessageBox::critical(this, tr("Re-type function local vars"),
  864                               tr("You must be in a function to define variable types."));
  865         return;
  866     }
  867 
  868     EditVariablesDialog dialog(Core()->getOffset(), curHighlightedWord, this);
  869     if (dialog.empty()) { // don't show the dialog if there are no variables
  870         return;
  871     }
  872     dialog.exec();
  873 }
  874 
  875 void DisassemblyContextMenu::on_actionXRefs_triggered()
  876 {
  877     XrefsDialog dialog(mainWindow, nullptr);
  878     dialog.fillRefsForAddress(offset, RAddressString(offset), false);
  879     dialog.exec();
  880 }
  881 
  882 void DisassemblyContextMenu::on_actionDisplayOptions_triggered()
  883 {
  884     PreferencesDialog dialog(this->window());
  885     dialog.showSection(PreferencesDialog::Section::Disassembly);
  886     dialog.exec();
  887 }
  888 
  889 void DisassemblyContextMenu::on_actionSetToCode_triggered()
  890 {
  891     Core()->setToCode(offset);
  892 }
  893 
  894 void DisassemblyContextMenu::on_actionSetAsString_triggered()
  895 {
  896     Core()->setAsString(offset);
  897 }
  898 
  899 void DisassemblyContextMenu::on_actionSetAsStringRemove_triggered()
  900 {
  901     Core()->removeString(offset);
  902 }
  903 
  904 void DisassemblyContextMenu::on_actionSetAsStringAdvanced_triggered()
  905 {
  906     EditStringDialog dialog(parentWidget());
  907     const int predictedStrSize = Core()->getString(offset).size();
  908     dialog.setStringSizeValue(predictedStrSize);
  909     dialog.setStringStartAddress(offset);
  910 
  911     if(!dialog.exec())
  912     {
  913         return;
  914     }
  915 
  916     uint64_t strAddr = 0U;
  917     if( !dialog.getStringStartAddress(strAddr) ) {
  918         QMessageBox::critical(this->window(), tr("Wrong address"), tr("Can't edit string at this address"));
  919         return;
  920     }
  921     CutterCore::StringTypeFormats coreStringType = CutterCore::StringTypeFormats::None;
  922 
  923     const auto strSize = dialog.getStringSizeValue();
  924     const auto strType = dialog.getStringType();
  925     switch(strType)
  926     {
  927     case EditStringDialog::StringType::Auto:
  928         coreStringType = CutterCore::StringTypeFormats::None;
  929         break;
  930     case EditStringDialog::StringType::ASCII_LATIN1:
  931         coreStringType = CutterCore::StringTypeFormats::ASCII_LATIN1;
  932         break;
  933     case EditStringDialog::StringType::UTF8:
  934         coreStringType = CutterCore::StringTypeFormats::UTF8;
  935         break;
  936     };
  937 
  938     Core()->setAsString(strAddr, strSize, coreStringType);
  939 }
  940 
  941 void DisassemblyContextMenu::on_actionSetToData_triggered()
  942 {
  943     int size = Core()->sizeofDataMeta(offset);
  944     if (size > 8 || (size && (size & (size - 1)))) {
  945         return;
  946     }
  947     if (size == 0 || size == 8) {
  948         size = 1;
  949     } else {
  950         size *= 2;
  951     }
  952     setToData(size);
  953 }
  954 
  955 void DisassemblyContextMenu::on_actionSetToDataEx_triggered()
  956 {
  957     SetToDataDialog dialog(offset, this->window());
  958     if (!dialog.exec()) {
  959         return;
  960     }
  961     setToData(dialog.getItemSize(), dialog.getItemCount());
  962 }
  963 
  964 void DisassemblyContextMenu::on_actionStructureOffsetMenu_triggered(QAction *action)
  965 {
  966     Core()->applyStructureOffset(action->data().toString(), offset);
  967 }
  968 
  969 void DisassemblyContextMenu::on_actionLinkType_triggered()
  970 {
  971     LinkTypeDialog dialog(mainWindow);
  972     if (!dialog.setDefaultAddress(curHighlightedWord)) {
  973         dialog.setDefaultAddress(RAddressString(offset));
  974     }
  975     dialog.exec();
  976 }
  977 
  978 void DisassemblyContextMenu::on_actionDeleteComment_triggered()
  979 {
  980     Core()->delComment(offset);
  981 }
  982 
  983 void DisassemblyContextMenu::on_actionDeleteFlag_triggered()
  984 {
  985     Core()->delFlag(offset);
  986 }
  987 
  988 void DisassemblyContextMenu::on_actionDeleteFunction_triggered()
  989 {
  990     Core()->delFunction(offset);
  991 }
  992 
  993 void DisassemblyContextMenu::on_actionEditFunction_triggered()
  994 {
  995     RCore *core = Core()->core();
  996     EditFunctionDialog dialog(mainWindow);
  997     RAnalFunction *fcn = r_anal_get_fcn_in(core->anal, offset, 0);
  998 
  999     if (fcn) {
 1000         dialog.setWindowTitle(tr("Edit function %1").arg(fcn->name));
 1001         dialog.setNameText(fcn->name);
 1002 
 1003         QString startAddrText = "0x" + QString::number(fcn->addr, 16);
 1004         dialog.setStartAddrText(startAddrText);
 1005 
 1006         QString stackSizeText;
 1007         stackSizeText.sprintf("%d", fcn->stack);
 1008         dialog.setStackSizeText(stackSizeText);
 1009 
 1010         QStringList callConList = Core()->cmdRaw("afcl").split("\n");
 1011         callConList.removeLast();
 1012         dialog.setCallConList(callConList);
 1013         dialog.setCallConSelected(fcn->cc);
 1014 
 1015 
 1016         if (dialog.exec()) {
 1017             QString new_name = dialog.getNameText();
 1018             Core()->renameFunction(fcn->name, new_name);
 1019             QString new_start_addr = dialog.getStartAddrText();
 1020             fcn->addr = Core()->math(new_start_addr);
 1021             QString new_stack_size = dialog.getStackSizeText();
 1022             fcn->stack = int(Core()->math(new_stack_size));
 1023             Core()->cmdRaw("afc " + dialog.getCallConSelected());
 1024             emit Core()->functionsChanged();
 1025         }
 1026     }
 1027 }
 1028 
 1029 void DisassemblyContextMenu::setBase(QString base)
 1030 {
 1031     Core()->setImmediateBase(base, offset);
 1032 }
 1033 
 1034 void DisassemblyContextMenu::setBits(int bits)
 1035 {
 1036     Core()->setCurrentBits(bits, offset);
 1037 }
 1038 
 1039 void DisassemblyContextMenu::setToData(int size, int repeat)
 1040 {
 1041     Core()->setToData(offset, size, repeat);
 1042 }
 1043 
 1044 QAction *DisassemblyContextMenu::addAnonymousAction(QString name, const char *slot,
 1045                                                     QKeySequence keySequence)
 1046 {
 1047     auto action = new QAction(this);
 1048     addAction(action);
 1049     anonymousActions.append(action);
 1050     initAction(action, name, slot, keySequence);
 1051     return action;
 1052 }
 1053 
 1054 void DisassemblyContextMenu::initAction(QAction *action, QString name, const char *slot)
 1055 {
 1056     action->setParent(this);
 1057     parentWidget()->addAction(action);
 1058     action->setText(name);
 1059     if (slot) {
 1060         connect(action, SIGNAL(triggered(bool)), this, slot);
 1061     }
 1062 }
 1063 
 1064 void DisassemblyContextMenu::initAction(QAction *action, QString name,
 1065                                         const char *slot, QKeySequence keySequence)
 1066 {
 1067     initAction(action, name, slot);
 1068     if (keySequence.isEmpty()) {
 1069         return;
 1070     }
 1071     action->setShortcut(keySequence);
 1072     action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
 1073 }
 1074 
 1075 void DisassemblyContextMenu::initAction(QAction *action, QString name,
 1076                                         const char *slot, QList<QKeySequence> keySequenceList)
 1077 {
 1078     initAction(action, name, slot);
 1079     if (keySequenceList.empty()) {
 1080         return;
 1081     }
 1082     action->setShortcuts(keySequenceList);
 1083     action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
 1084 }