Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breakpoint Menu and Debug Menu in the Decompiler Context Menu #2260

Merged
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0a945a8
Add option for breakpoints
NirmalManoj Jun 23, 2020
3100872
add debug menu
NirmalManoj Jun 22, 2020
bf05fa8
some suggested changes
NirmalManoj Jun 23, 2020
bb1e8db
make function to set shortcut context
NirmalManoj Jun 23, 2020
c08975d
renamed shortcut context setting function
NirmalManoj Jun 23, 2020
7663e97
replaced foreach, remove an unnecessary function
NirmalManoj Jun 23, 2020
c4a067e
formatted
NirmalManoj Jun 24, 2020
beff827
Implement logic for handling multiple breakpoints in a line
NirmalManoj Jun 25, 2020
fa7832c
suggested changes and complete formatting
NirmalManoj Jun 27, 2020
ac773e7
changed logic for adding/editing advanced offsets
NirmalManoj Jun 27, 2020
5e2f94b
breakpoints in line menu
NirmalManoj Jun 27, 2020
a85a9ab
suggested change
NirmalManoj Jun 27, 2020
cfcdb90
use RAddressString
NirmalManoj Jun 27, 2020
c9f6b45
use addAction() for creating and adding actions to breakpointsInLineMenu
NirmalManoj Jun 27, 2020
7e607f8
connect with breakpointsChanged
NirmalManoj Jun 27, 2020
1d5ef96
removed addAction() with lambda
NirmalManoj Jun 27, 2020
78f4361
made breakpointsInLineMenu a context sensitive submenu of breakpointMenu
NirmalManoj Jun 28, 2020
7928275
setupBreakpointsInLineMenu() in aboutToShowSlot
NirmalManoj Jun 28, 2020
88283b1
fixed the problem arised due to the connection with breakpointsChanged
NirmalManoj Jun 28, 2020
d7d78d2
made some functions private + formatted
NirmalManoj Jun 28, 2020
4f766c0
tried to fix memory leak associated with breakpointsInLineMenu
NirmalManoj Jun 28, 2020
7eee2e6
tried to fix potential memory leak with breakpointsInLineMenu
NirmalManoj Jun 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
176 changes: 173 additions & 3 deletions src/menus/DecompilerContextMenu.cpp
@@ -1,6 +1,7 @@
#include "DecompilerContextMenu.h"
#include "dialogs/preferences/PreferencesDialog.h"
#include "MainWindow.h"
#include "dialogs/BreakpointsDialog.h"

#include <QtCore>
#include <QShortcut>
Expand All @@ -12,12 +13,23 @@
DecompilerContextMenu::DecompilerContextMenu(QWidget *parent, MainWindow *mainWindow)
: QMenu(parent),
offset(0),
isTogglingBreakpoints(false),
mainWindow(mainWindow),
actionCopy(tr("Copy"), this)
actionCopy(tr("Copy"), this),
actionToggleBreakpoint(tr("Add/remove breakpoint"), this),
actionAdvancedBreakpoint(tr("Advanced breakpoint"), this),
breakpointsInLineMenu(new QMenu()),
karliss marked this conversation as resolved.
Show resolved Hide resolved
actionContinueUntil(tr("Continue until line"), this),
actionSetPC(tr("Set PC"), this)
{
setActionCopy();
addSeparator();

addBreakpointMenu();
addDebugMenu();

setShortcutContextInActions(this);

connect(this, &DecompilerContextMenu::aboutToShow,
this, &DecompilerContextMenu::aboutToShowSlot);
}
Expand All @@ -33,22 +45,118 @@ void DecompilerContextMenu::setOffset(RVA offset)
// this->actionSetFunctionVarTypes.setVisible(true);
}

void DecompilerContextMenu::setFirstOffsetInLine(RVA firstOffset)
{
this->firstOffsetInLine = firstOffset;
}

void DecompilerContextMenu::setAvailableBreakpoints(QVector<RVA> offsetList)
{
this->availableBreakpoints = offsetList;
}

void DecompilerContextMenu::setupBreakpointsInLineMenu()
{
breakpointsInLineMenu->clear();
for (auto curOffset : this->availableBreakpoints) {
QAction *action = breakpointsInLineMenu->addAction(RAddressString(curOffset));
connect(action, &QAction::triggered, this, [this, curOffset] {
BreakpointsDialog::editBreakpoint(Core()->getBreakpointAt(curOffset),
this);
});
}
}

void DecompilerContextMenu::setCanCopy(bool enabled)
{
actionCopy.setVisible(enabled);
}

void DecompilerContextMenu::setShortcutContextInActions(QMenu *menu)
{
for (QAction *action : menu->actions()) {
if (action->isSeparator()) {
//Do nothing
} else if (action->menu()) {
setShortcutContextInActions(action->menu());
} else {
action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
}
}
}

void DecompilerContextMenu::setIsTogglingBreakpoints(bool isToggling)
{
this->isTogglingBreakpoints = isToggling;
}

bool DecompilerContextMenu::getIsTogglingBreakpoints()
{
return this->isTogglingBreakpoints;
}

void DecompilerContextMenu::aboutToShowSlot()
{

setupBreakpointsInLineMenu();

// Only show debug options if we are currently debugging
debugMenu->menuAction()->setVisible(Core()->currentlyDebugging);

bool hasBreakpoint = !this->availableBreakpoints.isEmpty();
int numberOfBreakpoints = this->availableBreakpoints.size();
if (numberOfBreakpoints == 0) {
actionToggleBreakpoint.setText(tr("Add breakpoint"));
} else if (numberOfBreakpoints == 1) {
actionToggleBreakpoint.setText(tr("Remove breakpoint"));
} else {
actionToggleBreakpoint.setText(tr("Remove all breakpoints in line"));
}

if(numberOfBreakpoints > 1){
actionAdvancedBreakpoint.setMenu(breakpointsInLineMenu);
}else{
actionAdvancedBreakpoint.setMenu(nullptr);
}
actionAdvancedBreakpoint.setText(hasBreakpoint ?
tr("Edit breakpoint") : tr("Advanced breakpoint"));

QString progCounterName = Core()->getRegisterName("PC").toUpper();
actionSetPC.setText(tr("Set %1 here").arg(progCounterName));
}

// Set up actions

void DecompilerContextMenu::setActionCopy(){
void DecompilerContextMenu::setActionCopy()
{
connect(&actionCopy, &QAction::triggered, this, &DecompilerContextMenu::actionCopyTriggered);
addAction(&actionCopy);
actionCopy.setShortcut(QKeySequence::Copy);
actionCopy.setShortcutContext(Qt::WidgetWithChildrenShortcut);
}

void DecompilerContextMenu::setActionToggleBreakpoint()
{
connect(&actionToggleBreakpoint, &QAction::triggered, this,
&DecompilerContextMenu::actionToggleBreakpointTriggered);
actionToggleBreakpoint.setShortcuts({Qt::Key_F2, Qt::CTRL + Qt::Key_B});
}

void DecompilerContextMenu::setActionAdvancedBreakpoint()
{
connect(&actionAdvancedBreakpoint, &QAction::triggered, this,
&DecompilerContextMenu::actionAdvancedBreakpointTriggered);
actionAdvancedBreakpoint.setShortcut({Qt::CTRL + Qt::Key_F2});
}

void DecompilerContextMenu::setActionContinueUntil()
{
connect(&actionContinueUntil, &QAction::triggered, this,
&DecompilerContextMenu::actionContinueUntilTriggered);
}

void DecompilerContextMenu::setActionSetPC()
{
connect(&actionSetPC, &QAction::triggered, this, &DecompilerContextMenu::actionSetPCTriggered);
}

// Set up action responses
Expand All @@ -57,3 +165,65 @@ void DecompilerContextMenu::actionCopyTriggered()
{
emit copy();
}

void DecompilerContextMenu::actionToggleBreakpointTriggered()
{
if (!this->availableBreakpoints.isEmpty()) {
setIsTogglingBreakpoints(true);
for (auto offsetToRemove : this->availableBreakpoints) {
Core()->toggleBreakpoint(offsetToRemove);
}
this->availableBreakpoints.clear();
setIsTogglingBreakpoints(false);
return;
}
if (this->firstOffsetInLine == RVA_MAX)
return;

Core()->toggleBreakpoint(this->firstOffsetInLine);
}

void DecompilerContextMenu::actionAdvancedBreakpointTriggered()
{
if (!availableBreakpoints.empty()) {
// Edit the earliest breakpoint in the line
BreakpointsDialog::editBreakpoint(Core()->getBreakpointAt(this->availableBreakpoints.first()),
this);
} else {
// Add a breakpoint to the earliest offset in the line
BreakpointsDialog::createNewBreakpoint(this->firstOffsetInLine, this);
}
}

void DecompilerContextMenu::actionContinueUntilTriggered()
{
Core()->continueUntilDebug(RAddressString(offset));
}

void DecompilerContextMenu::actionSetPCTriggered()
{
QString progCounterName = Core()->getRegisterName("PC");
Core()->setRegister(progCounterName, RAddressString(offset).toUpper());
}

// Set up menus

void DecompilerContextMenu::addBreakpointMenu()
{
breakpointMenu = addMenu(tr("Breakpoint"));

setActionToggleBreakpoint();
breakpointMenu->addAction(&actionToggleBreakpoint);
setActionAdvancedBreakpoint();
breakpointMenu->addAction(&actionAdvancedBreakpoint);
}

void DecompilerContextMenu::addDebugMenu()
{
debugMenu = addMenu(tr("Debug"));

setActionContinueUntil();
debugMenu->addAction(&actionContinueUntil);
setActionSetPC();
debugMenu->addAction(&actionSetPC);
}
45 changes: 40 additions & 5 deletions src/menus/DecompilerContextMenu.h
Expand Up @@ -13,33 +13,68 @@ class DecompilerContextMenu : public QMenu
DecompilerContextMenu(QWidget *parent, MainWindow *mainWindow);
~DecompilerContextMenu();


signals:
void copy();

public slots:
void setOffset(RVA offset);
void setAvailableBreakpoints(QVector<RVA> offsetList);
void setFirstOffsetInLine(RVA firstOffset);
void setupBreakpointsInLineMenu();
karliss marked this conversation as resolved.
Show resolved Hide resolved
void setCanCopy(bool enabled);
void setIsTogglingBreakpoints(bool isToggling);
karliss marked this conversation as resolved.
Show resolved Hide resolved

bool getIsTogglingBreakpoints();

private slots:
void aboutToShowSlot();

void actionCopyTriggered();

private:
QKeySequence getCopySequence() const;
void actionToggleBreakpointTriggered();
void actionAdvancedBreakpointTriggered();

void actionContinueUntilTriggered();
void actionSetPCTriggered();

private:
void setShortcutContextInActions(QMenu *menu);
RVA offset;
RVA firstOffsetInLine;
bool isTogglingBreakpoints;
QVector<RVA> availableBreakpoints;
MainWindow *mainWindow;

QAction actionCopy;
QAction *copySeparator;


QMenu *breakpointMenu;
QAction actionToggleBreakpoint;
QAction actionAdvancedBreakpoint;

QMenu *breakpointsInLineMenu;

QMenu *debugMenu;
QAction actionContinueUntil;
QAction actionSetPC;

// Set actions
void setActionCopy();


void setActionToggleBreakpoint();
void setActionAdvancedBreakpoint();

void setActionContinueUntil();
void setActionSetPC();

// Add Menus
void addBreakpointMenu();
void addDebugMenu();
// I left out the following part from RAnnotatedCode. Probably, we will be returning/passing annotations
// from/to the function getThingUsedHere() and updateTargetMenuActions(). This block of comment will get removed in
// future PRs.
//
//
// struct ThingUsedHere {
// QString name;
// RVA offset;
Expand Down