* GUI: working prototype for ActionHelperProxy * GUI: fully implemented ActionHelperProxy * GUI: display breakpoints in Graph view * GUI: move breakpoint context menu into separate class * GUI: add breakpoint context menu to graph view
This commit is contained in:
parent
2bd32aee32
commit
451807f8ae
|
@ -555,6 +555,13 @@ void AppearanceDialog::colorInfoListInit()
|
|||
colorInfoListAppend(tr("Unconditional branch line"), "GraphJmpColor", "");
|
||||
colorInfoListAppend(tr("True branch line"), "GraphBrtrueColor", "");
|
||||
colorInfoListAppend(tr("False branch line"), "GraphBrfalseColor", "");
|
||||
#ifdef _WIN64
|
||||
colorInfoListAppend(tr("RIP"), "GraphCipColor", "");
|
||||
#else //x86
|
||||
colorInfoListAppend(tr("EIP"), "GraphCipColor", "");
|
||||
#endif //_WIN64
|
||||
colorInfoListAppend(tr("Breakpoint"), "GraphBreakpointColor", "");
|
||||
colorInfoListAppend(tr("Disabled Breakpoint"), "GraphDisabledBreakpointColor", "");
|
||||
|
||||
colorInfoListAppend(tr("Other:"), "", "");
|
||||
colorInfoListAppend(tr("Current Thread"), "ThreadCurrentColor", "ThreadCurrentBackgroundColor");
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
#include "BreakpointMenu.h"
|
||||
#include "MenuBuilder.h"
|
||||
#include <QAction>
|
||||
#include <QMessageBox>
|
||||
#include "StringUtil.h"
|
||||
#include "MiscUtil.h"
|
||||
#include "Breakpoints.h"
|
||||
|
||||
|
||||
BreakpointMenu::BreakpointMenu(QWidget* parent, ActionHelperFuncs funcs, GetSelectionFunc getSelection)
|
||||
: QObject(parent), ActionHelperProxy(funcs), mGetSelection(getSelection)
|
||||
{
|
||||
}
|
||||
|
||||
void BreakpointMenu::build(MenuBuilder* builder)
|
||||
{
|
||||
QAction* toggleBreakpointAction = makeShortcutAction(DIcon("breakpoint_toggle.png"), tr("Toggle"), std::bind(&BreakpointMenu::toggleInt3BPActionSlot, this), "ActionToggleBreakpoint");
|
||||
QAction* editSoftwareBreakpointAction = makeShortcutAction(DIcon("breakpoint_edit_alt.png"), tr("Edit"), std::bind(&BreakpointMenu::editSoftBpActionSlot, this), "ActionEditBreakpoint");
|
||||
QAction* setHwBreakpointAction = makeShortcutAction(DIcon("breakpoint_execute.png"), tr("Set Hardware on Execution"), std::bind(&BreakpointMenu::toggleHwBpActionSlot, this), "ActionSetHwBpE");
|
||||
QAction* removeHwBreakpointAction = makeShortcutAction(DIcon("breakpoint_remove.png"), tr("Remove Hardware"), std::bind(&BreakpointMenu::toggleHwBpActionSlot, this), "ActionRemoveHwBp");
|
||||
|
||||
QMenu* replaceSlotMenu = makeMenu(DIcon("breakpoint_execute.png"), tr("Set Hardware on Execution"));
|
||||
QAction* replaceSlot0Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot1.png"), tr("Replace Slot 0 (Free)"), std::bind(&BreakpointMenu::setHwBpOnSlot0ActionSlot, this));
|
||||
QAction* replaceSlot1Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot2.png"), tr("Replace Slot 1 (Free)"), std::bind(&BreakpointMenu::setHwBpOnSlot1ActionSlot, this));
|
||||
QAction* replaceSlot2Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot3.png"), tr("Replace Slot 2 (Free)"), std::bind(&BreakpointMenu::setHwBpOnSlot2ActionSlot, this));
|
||||
QAction* replaceSlot3Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot4.png"), tr("Replace Slot 3 (Free)"), std::bind(&BreakpointMenu::setHwBpOnSlot3ActionSlot, this));
|
||||
|
||||
builder->addMenu(makeMenu(DIcon("breakpoint.png"), tr("Breakpoint")), [ = ](QMenu * menu)
|
||||
{
|
||||
BPXTYPE bpType = DbgGetBpxTypeAt(mGetSelection());
|
||||
if((bpType & bp_normal) == bp_normal)
|
||||
menu->addAction(editSoftwareBreakpointAction);
|
||||
|
||||
menu->addAction(toggleBreakpointAction);
|
||||
|
||||
if((bpType & bp_hardware) == bp_hardware)
|
||||
{
|
||||
menu->addAction(removeHwBreakpointAction);
|
||||
}
|
||||
else
|
||||
{
|
||||
BPMAP bpList;
|
||||
DbgGetBpList(bp_hardware, &bpList);
|
||||
|
||||
//get enabled hwbp count
|
||||
int enabledCount = bpList.count;
|
||||
for(int i = 0; i < bpList.count; i++)
|
||||
if(!bpList.bp[i].enabled)
|
||||
enabledCount--;
|
||||
|
||||
if(enabledCount < 4)
|
||||
{
|
||||
menu->addAction(setHwBreakpointAction);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
switch(bpList.bp[i].slot)
|
||||
{
|
||||
case 0:
|
||||
replaceSlot0Action->setText(tr("Replace Slot %1 (0x%2)").arg(1).arg(ToPtrString(bpList.bp[i].addr)));
|
||||
break;
|
||||
case 1:
|
||||
replaceSlot1Action->setText(tr("Replace Slot %1 (0x%2)").arg(2).arg(ToPtrString(bpList.bp[i].addr)));
|
||||
break;
|
||||
case 2:
|
||||
replaceSlot2Action->setText(tr("Replace Slot %1 (0x%2)").arg(3).arg(ToPtrString(bpList.bp[i].addr)));
|
||||
break;
|
||||
case 3:
|
||||
replaceSlot3Action->setText(tr("Replace Slot %1 (0x%2)").arg(4).arg(ToPtrString(bpList.bp[i].addr)));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
menu->addMenu(replaceSlotMenu);
|
||||
}
|
||||
if(bpList.count)
|
||||
BridgeFree(bpList.bp);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void BreakpointMenu::toggleInt3BPActionSlot()
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
duint wVA = mGetSelection();
|
||||
BPXTYPE wBpType = DbgGetBpxTypeAt(wVA);
|
||||
QString wCmd;
|
||||
|
||||
if((wBpType & bp_normal) == bp_normal)
|
||||
{
|
||||
wCmd = "bc " + ToPtrString(wVA);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(DbgFunctions()->IsDepEnabled() && !DbgFunctions()->MemIsCodePage(wVA, false))
|
||||
{
|
||||
QMessageBox msgyn(QMessageBox::Warning, tr("Current address is not executable"),
|
||||
tr("Setting software breakpoint here may result in crash. Do you really want to continue?"), QMessageBox::Yes | QMessageBox::No, (QWidget*)parent());
|
||||
msgyn.setWindowIcon(DIcon("compile-warning.png"));
|
||||
msgyn.setParent((QWidget*)parent(), Qt::Dialog);
|
||||
msgyn.setWindowFlags(msgyn.windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
if(msgyn.exec() == QMessageBox::No)
|
||||
return;
|
||||
}
|
||||
wCmd = "bp " + ToPtrString(wVA);
|
||||
}
|
||||
|
||||
DbgCmdExec(wCmd.toUtf8().constData());
|
||||
//emit Disassembly::repainted();
|
||||
}
|
||||
|
||||
void BreakpointMenu::editSoftBpActionSlot()
|
||||
{
|
||||
Breakpoints::editBP(bp_normal, ToHexString(mGetSelection()), (QWidget*)parent());
|
||||
}
|
||||
|
||||
void BreakpointMenu::toggleHwBpActionSlot()
|
||||
{
|
||||
duint wVA = mGetSelection();
|
||||
BPXTYPE wBpType = DbgGetBpxTypeAt(wVA);
|
||||
QString wCmd;
|
||||
|
||||
if((wBpType & bp_hardware) == bp_hardware)
|
||||
{
|
||||
wCmd = "bphwc " + ToPtrString(wVA);
|
||||
}
|
||||
else
|
||||
{
|
||||
wCmd = "bphws " + ToPtrString(wVA);
|
||||
}
|
||||
|
||||
DbgCmdExec(wCmd.toUtf8().constData());
|
||||
}
|
||||
|
||||
|
||||
void BreakpointMenu::setHwBpOnSlot0ActionSlot()
|
||||
{
|
||||
setHwBpAt(mGetSelection(), 0);
|
||||
}
|
||||
|
||||
void BreakpointMenu::setHwBpOnSlot1ActionSlot()
|
||||
{
|
||||
setHwBpAt(mGetSelection(), 1);
|
||||
}
|
||||
|
||||
void BreakpointMenu::setHwBpOnSlot2ActionSlot()
|
||||
{
|
||||
setHwBpAt(mGetSelection(), 2);
|
||||
}
|
||||
|
||||
void BreakpointMenu::setHwBpOnSlot3ActionSlot()
|
||||
{
|
||||
setHwBpAt(mGetSelection(), 3);
|
||||
}
|
||||
|
||||
void BreakpointMenu::setHwBpAt(duint va, int slot)
|
||||
{
|
||||
int wI = 0;
|
||||
int wSlotIndex = -1;
|
||||
BPMAP wBPList;
|
||||
QString wCmd = "";
|
||||
|
||||
DbgGetBpList(bp_hardware, &wBPList);
|
||||
|
||||
// Find index of slot slot in the list
|
||||
for(wI = 0; wI < wBPList.count; wI++)
|
||||
{
|
||||
if(wBPList.bp[wI].slot == (unsigned short)slot)
|
||||
{
|
||||
wSlotIndex = wI;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(wSlotIndex < 0) // Slot not used
|
||||
{
|
||||
wCmd = "bphws " + ToPtrString(va);
|
||||
DbgCmdExec(wCmd.toUtf8().constData());
|
||||
}
|
||||
else // Slot used
|
||||
{
|
||||
wCmd = "bphwc " + ToPtrString((duint)(wBPList.bp[wSlotIndex].addr));
|
||||
DbgCmdExec(wCmd.toUtf8().constData());
|
||||
|
||||
Sleep(200);
|
||||
|
||||
wCmd = "bphws " + ToPtrString(va);
|
||||
DbgCmdExec(wCmd.toUtf8().constData());
|
||||
}
|
||||
if(wBPList.count)
|
||||
BridgeFree(wBPList.bp);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <functional>
|
||||
#include "ActionHelpers.h"
|
||||
#include "Imports.h"
|
||||
|
||||
class BreakpointMenu : public QObject, public ActionHelperProxy
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using GetSelectionFunc = std::function<duint()>;
|
||||
|
||||
explicit BreakpointMenu(QWidget* parent, ActionHelperFuncs funcs, GetSelectionFunc getSelection);
|
||||
void build(MenuBuilder* builder);
|
||||
|
||||
public slots:
|
||||
void toggleInt3BPActionSlot();
|
||||
void editSoftBpActionSlot();
|
||||
void toggleHwBpActionSlot();
|
||||
void setHwBpOnSlot0ActionSlot();
|
||||
void setHwBpOnSlot1ActionSlot();
|
||||
void setHwBpOnSlot2ActionSlot();
|
||||
void setHwBpOnSlot3ActionSlot();
|
||||
void setHwBpAt(duint va, int slot);
|
||||
|
||||
private:
|
||||
GetSelectionFunc mGetSelection;
|
||||
};
|
|
@ -25,6 +25,7 @@
|
|||
#include "DataCopyDialog.h"
|
||||
#include "SnowmanView.h"
|
||||
#include "MemoryPage.h"
|
||||
#include "BreakpointMenu.h"
|
||||
|
||||
CPUDisassembly::CPUDisassembly(CPUWidget* parent) : Disassembly(parent)
|
||||
{
|
||||
|
@ -95,7 +96,7 @@ void CPUDisassembly::mouseDoubleClickEvent(QMouseEvent* event)
|
|||
|
||||
// (Opcodes) Set INT3 breakpoint
|
||||
case 1:
|
||||
toggleInt3BPActionSlot();
|
||||
mBreakpointMenu->toggleInt3BPActionSlot();
|
||||
break;
|
||||
|
||||
// (Disassembly) Assemble dialog
|
||||
|
@ -269,73 +270,11 @@ void CPUDisassembly::setupRightClickContextMenu()
|
|||
return DbgFunctions()->PatchInRange(start, end); //something patched in selected range
|
||||
});
|
||||
|
||||
QAction* toggleBreakpointAction = makeShortcutAction(DIcon("breakpoint_toggle.png"), tr("Toggle"), SLOT(toggleInt3BPActionSlot()), "ActionToggleBreakpoint");
|
||||
QAction* editSoftwareBreakpointAction = makeShortcutAction(DIcon("breakpoint_edit_alt.png"), tr("Edit"), SLOT(editSoftBpActionSlot()), "ActionEditBreakpoint");
|
||||
QAction* setHwBreakpointAction = makeShortcutAction(DIcon("breakpoint_execute.png"), tr("Set Hardware on Execution"), SLOT(toggleHwBpActionSlot()), "ActionSetHwBpE");
|
||||
QAction* removeHwBreakpointAction = makeShortcutAction(DIcon("breakpoint_remove.png"), tr("Remove Hardware"), SLOT(toggleHwBpActionSlot()), "ActionRemoveHwBp");
|
||||
|
||||
QMenu* replaceSlotMenu = makeMenu(DIcon("breakpoint_execute.png"), tr("Set Hardware on Execution"));
|
||||
QAction* replaceSlot0Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot1.png"), tr("Replace Slot 0 (Free)"), SLOT(setHwBpOnSlot0ActionSlot()));
|
||||
QAction* replaceSlot1Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot2.png"), tr("Replace Slot 1 (Free)"), SLOT(setHwBpOnSlot1ActionSlot()));
|
||||
QAction* replaceSlot2Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot3.png"), tr("Replace Slot 2 (Free)"), SLOT(setHwBpOnSlot2ActionSlot()));
|
||||
QAction* replaceSlot3Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot4.png"), tr("Replace Slot 3 (Free)"), SLOT(setHwBpOnSlot3ActionSlot()));
|
||||
|
||||
mMenuBuilder->addMenu(makeMenu(DIcon("breakpoint.png"), tr("Breakpoint")), [ = ](QMenu * menu)
|
||||
mBreakpointMenu = new BreakpointMenu(this, getActionHelperFuncs(), [this]()
|
||||
{
|
||||
BPXTYPE bpType = DbgGetBpxTypeAt(rvaToVa(getInitialSelection()));
|
||||
if((bpType & bp_normal) == bp_normal)
|
||||
menu->addAction(editSoftwareBreakpointAction);
|
||||
|
||||
menu->addAction(toggleBreakpointAction);
|
||||
|
||||
if((bpType & bp_hardware) == bp_hardware)
|
||||
{
|
||||
menu->addAction(removeHwBreakpointAction);
|
||||
}
|
||||
else
|
||||
{
|
||||
BPMAP bpList;
|
||||
DbgGetBpList(bp_hardware, &bpList);
|
||||
|
||||
//get enabled hwbp count
|
||||
int enabledCount = bpList.count;
|
||||
for(int i = 0; i < bpList.count; i++)
|
||||
if(!bpList.bp[i].enabled)
|
||||
enabledCount--;
|
||||
|
||||
if(enabledCount < 4)
|
||||
{
|
||||
menu->addAction(setHwBreakpointAction);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
switch(bpList.bp[i].slot)
|
||||
{
|
||||
case 0:
|
||||
replaceSlot0Action->setText(tr("Replace Slot %1 (0x%2)").arg(1).arg(ToPtrString(bpList.bp[i].addr)));
|
||||
break;
|
||||
case 1:
|
||||
replaceSlot1Action->setText(tr("Replace Slot %1 (0x%2)").arg(2).arg(ToPtrString(bpList.bp[i].addr)));
|
||||
break;
|
||||
case 2:
|
||||
replaceSlot2Action->setText(tr("Replace Slot %1 (0x%2)").arg(3).arg(ToPtrString(bpList.bp[i].addr)));
|
||||
break;
|
||||
case 3:
|
||||
replaceSlot3Action->setText(tr("Replace Slot %1 (0x%2)").arg(4).arg(ToPtrString(bpList.bp[i].addr)));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
menu->addMenu(replaceSlotMenu);
|
||||
}
|
||||
if(bpList.count)
|
||||
BridgeFree(bpList.bp);
|
||||
}
|
||||
return true;
|
||||
return rvaToVa(getInitialSelection());
|
||||
});
|
||||
mBreakpointMenu->build(mMenuBuilder);
|
||||
|
||||
mMenuBuilder->addMenu(makeMenu(DIcon("dump.png"), tr("&Follow in Dump")), [this](QMenu * menu)
|
||||
{
|
||||
|
@ -706,114 +645,7 @@ void CPUDisassembly::gotoOriginSlot()
|
|||
}
|
||||
|
||||
|
||||
void CPUDisassembly::toggleInt3BPActionSlot()
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
duint wVA = rvaToVa(getInitialSelection());
|
||||
BPXTYPE wBpType = DbgGetBpxTypeAt(wVA);
|
||||
QString wCmd;
|
||||
|
||||
if((wBpType & bp_normal) == bp_normal)
|
||||
{
|
||||
wCmd = "bc " + ToPtrString(wVA);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(DbgFunctions()->IsDepEnabled() && !DbgFunctions()->MemIsCodePage(wVA, false))
|
||||
{
|
||||
QMessageBox msgyn(QMessageBox::Warning, tr("Current address is not executable"),
|
||||
tr("Setting software breakpoint here may result in crash. Do you really want to continue?"), QMessageBox::Yes | QMessageBox::No, this);
|
||||
msgyn.setWindowIcon(DIcon("compile-warning.png"));
|
||||
msgyn.setParent(this, Qt::Dialog);
|
||||
msgyn.setWindowFlags(msgyn.windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
if(msgyn.exec() == QMessageBox::No)
|
||||
return;
|
||||
}
|
||||
wCmd = "bp " + ToPtrString(wVA);
|
||||
}
|
||||
|
||||
DbgCmdExec(wCmd.toUtf8().constData());
|
||||
//emit Disassembly::repainted();
|
||||
}
|
||||
|
||||
|
||||
void CPUDisassembly::toggleHwBpActionSlot()
|
||||
{
|
||||
duint wVA = rvaToVa(getInitialSelection());
|
||||
BPXTYPE wBpType = DbgGetBpxTypeAt(wVA);
|
||||
QString wCmd;
|
||||
|
||||
if((wBpType & bp_hardware) == bp_hardware)
|
||||
{
|
||||
wCmd = "bphwc " + ToPtrString(wVA);
|
||||
}
|
||||
else
|
||||
{
|
||||
wCmd = "bphws " + ToPtrString(wVA);
|
||||
}
|
||||
|
||||
DbgCmdExec(wCmd.toUtf8().constData());
|
||||
}
|
||||
|
||||
|
||||
void CPUDisassembly::setHwBpOnSlot0ActionSlot()
|
||||
{
|
||||
setHwBpAt(rvaToVa(getInitialSelection()), 0);
|
||||
}
|
||||
|
||||
void CPUDisassembly::setHwBpOnSlot1ActionSlot()
|
||||
{
|
||||
setHwBpAt(rvaToVa(getInitialSelection()), 1);
|
||||
}
|
||||
|
||||
void CPUDisassembly::setHwBpOnSlot2ActionSlot()
|
||||
{
|
||||
setHwBpAt(rvaToVa(getInitialSelection()), 2);
|
||||
}
|
||||
|
||||
void CPUDisassembly::setHwBpOnSlot3ActionSlot()
|
||||
{
|
||||
setHwBpAt(rvaToVa(getInitialSelection()), 3);
|
||||
}
|
||||
|
||||
void CPUDisassembly::setHwBpAt(duint va, int slot)
|
||||
{
|
||||
int wI = 0;
|
||||
int wSlotIndex = -1;
|
||||
BPMAP wBPList;
|
||||
QString wCmd = "";
|
||||
|
||||
DbgGetBpList(bp_hardware, &wBPList);
|
||||
|
||||
// Find index of slot slot in the list
|
||||
for(wI = 0; wI < wBPList.count; wI++)
|
||||
{
|
||||
if(wBPList.bp[wI].slot == (unsigned short)slot)
|
||||
{
|
||||
wSlotIndex = wI;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(wSlotIndex < 0) // Slot not used
|
||||
{
|
||||
wCmd = "bphws " + ToPtrString(va);
|
||||
DbgCmdExec(wCmd.toUtf8().constData());
|
||||
}
|
||||
else // Slot used
|
||||
{
|
||||
wCmd = "bphwc " + ToPtrString((duint)(wBPList.bp[wSlotIndex].addr));
|
||||
DbgCmdExec(wCmd.toUtf8().constData());
|
||||
|
||||
Sleep(200);
|
||||
|
||||
wCmd = "bphws " + ToPtrString(va);
|
||||
DbgCmdExec(wCmd.toUtf8().constData());
|
||||
}
|
||||
if(wBPList.count)
|
||||
BridgeFree(wBPList.bp);
|
||||
}
|
||||
|
||||
void CPUDisassembly::setNewOriginHereActionSlot()
|
||||
{
|
||||
|
@ -1935,11 +1767,6 @@ void CPUDisassembly::labelHelpSlot()
|
|||
}
|
||||
}
|
||||
|
||||
void CPUDisassembly::editSoftBpActionSlot()
|
||||
{
|
||||
Breakpoints::editBP(bp_normal, ToHexString(rvaToVa(getInitialSelection())), this);
|
||||
}
|
||||
|
||||
void CPUDisassembly::ActionTraceRecordBitSlot()
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define CPUDISASSEMBLY_H
|
||||
|
||||
#include "Disassembly.h"
|
||||
#include "BreakpointMenu.h"
|
||||
|
||||
// Needed forward declaration for parent container class
|
||||
class CPUWidget;
|
||||
|
@ -24,7 +25,6 @@ public:
|
|||
void setupRightClickContextMenu();
|
||||
void addFollowReferenceMenuItem(QString name, dsint value, QMenu* menu, bool isReferences, bool isFollowInCPU);
|
||||
void setupFollowReferenceMenu(dsint wVA, QMenu* menu, bool isReferences, bool isFollowInCPU);
|
||||
void setHwBpAt(duint va, int slot);
|
||||
void copySelectionSlot(bool copyBytes);
|
||||
void copySelectionToFileSlot(bool copyBytes);
|
||||
|
||||
|
@ -37,12 +37,6 @@ signals:
|
|||
void displayGraphWidget();
|
||||
|
||||
public slots:
|
||||
void toggleInt3BPActionSlot();
|
||||
void toggleHwBpActionSlot();
|
||||
void setHwBpOnSlot0ActionSlot();
|
||||
void setHwBpOnSlot1ActionSlot();
|
||||
void setHwBpOnSlot2ActionSlot();
|
||||
void setHwBpOnSlot3ActionSlot();
|
||||
void setNewOriginHereActionSlot();
|
||||
void gotoOriginSlot();
|
||||
void setLabelSlot();
|
||||
|
@ -105,7 +99,6 @@ public slots:
|
|||
void ActionTraceRecordDisableSlot();
|
||||
void displayWarningSlot(QString title, QString text);
|
||||
void labelHelpSlot();
|
||||
void editSoftBpActionSlot();
|
||||
void analyzeSingleFunctionSlot();
|
||||
void removeAnalysisSelectionSlot();
|
||||
void removeAnalysisModuleSlot();
|
||||
|
@ -174,6 +167,7 @@ private:
|
|||
MenuBuilder* mMenuBuilder;
|
||||
MenuBuilder* mHighlightMenuBuilder;
|
||||
bool mHighlightContextMenu = false;
|
||||
BreakpointMenu* mBreakpointMenu;
|
||||
};
|
||||
|
||||
#endif // CPUDISASSEMBLY_H
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <QMimeData>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include "BreakpointMenu.h"
|
||||
|
||||
DisassemblerGraphView::DisassemblerGraphView(QWidget* parent)
|
||||
: QAbstractScrollArea(parent),
|
||||
|
@ -259,12 +260,34 @@ void DisassemblerGraphView::paintNormal(QPainter & p, QRect & viewportRect, int
|
|||
{
|
||||
for(auto & line : instr.text.lines)
|
||||
{
|
||||
if(instr.addr == mCip)
|
||||
int rectSize = qRound(this->charWidth);
|
||||
if(rectSize % 2)
|
||||
rectSize++;
|
||||
|
||||
// Assume charWidth <= charHeight
|
||||
QRectF bpRect(x - rectSize / 3.0, y + (this->charHeight - rectSize) / 2.0, rectSize, rectSize);
|
||||
|
||||
bool isbp = DbgGetBpxTypeAt(instr.addr) != bp_none;
|
||||
bool isbpdisabled = DbgIsBpDisabled(instr.addr);
|
||||
bool iscip = instr.addr == mCip;
|
||||
|
||||
if(isbp || isbpdisabled)
|
||||
{
|
||||
p.setPen(mCipColor);
|
||||
p.fillRect(x, y, this->charWidth, this->charHeight, mCipBackgroundColor);
|
||||
p.drawText(x, y, this->charWidth, this->charHeight, 0, QString("\xE2\x80\xA2"));
|
||||
if(iscip)
|
||||
{
|
||||
// Left half is cip
|
||||
bpRect.setWidth(bpRect.width() / 2);
|
||||
p.fillRect(bpRect, mCipColor);
|
||||
|
||||
// Right half is breakpoint
|
||||
bpRect.translate(bpRect.width(), 0);
|
||||
}
|
||||
|
||||
p.fillRect(bpRect, isbp ? mBreakpointColor : mDisabledBreakpointColor);
|
||||
}
|
||||
else if(iscip)
|
||||
p.fillRect(bpRect, mCipColor);
|
||||
|
||||
RichTextPainter::paintRichText(&p, x + this->charWidth, y, block.width - this->charWidth, this->charHeight, 0, line, mFontMetrics);
|
||||
y += this->charHeight;
|
||||
}
|
||||
|
@ -358,7 +381,7 @@ void DisassemblerGraphView::paintOverview(QPainter & p, QRect & viewportRect, in
|
|||
pen.setColor(graphNodeColor);
|
||||
p.setPen(pen);
|
||||
if(isCip)
|
||||
p.setBrush(mCipBackgroundColor);
|
||||
p.setBrush(mCipColor);
|
||||
else if(traceCount)
|
||||
{
|
||||
// Color depending on how often a sequence of code is executed
|
||||
|
@ -1625,6 +1648,11 @@ void DisassemblerGraphView::setupContextMenu()
|
|||
});
|
||||
mMenuBuilder->addSeparator();
|
||||
|
||||
auto breakpointMenu = new BreakpointMenu(this, getActionHelperFuncs(), [this]()
|
||||
{
|
||||
return cur_instr;
|
||||
});
|
||||
breakpointMenu->build(mMenuBuilder);
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("comment.png"), tr("&Comment"), SLOT(setCommentSlot()), "ActionSetComment"));
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("label.png"), tr("&Label"), SLOT(setLabelSlot()), "ActionSetLabel"));
|
||||
MenuBuilder* gotoMenu = new MenuBuilder(this);
|
||||
|
@ -1656,8 +1684,6 @@ void DisassemblerGraphView::setupContextMenu()
|
|||
mediumLayout->setChecked(true);
|
||||
mMenuBuilder->addMenu(makeMenu(DIcon("layout.png"), tr("Layout")), layoutMenu);
|
||||
|
||||
mMenuBuilder->addSeparator();
|
||||
|
||||
mMenuBuilder->loadFromConfig();
|
||||
}
|
||||
|
||||
|
@ -1699,8 +1725,6 @@ void DisassemblerGraphView::colorsUpdatedSlot()
|
|||
mCommentBackgroundColor = ConfigColor("DisassemblyCommentBackgroundColor");
|
||||
mLabelColor = ConfigColor("DisassemblyLabelColor");
|
||||
mLabelBackgroundColor = ConfigColor("DisassemblyLabelBackgroundColor");
|
||||
mCipBackgroundColor = ConfigColor("DisassemblyCipBackgroundColor");
|
||||
mCipColor = ConfigColor("DisassemblyCipColor");
|
||||
mAddressColor = ConfigColor("DisassemblyAddressColor");
|
||||
mAddressBackgroundColor = ConfigColor("DisassemblyAddressBackgroundColor");
|
||||
|
||||
|
@ -1712,6 +1736,9 @@ void DisassemblerGraphView::colorsUpdatedSlot()
|
|||
backgroundColor = ConfigColor("GraphBackgroundColor");
|
||||
if(!backgroundColor.alpha())
|
||||
backgroundColor = disassemblySelectionColor;
|
||||
mCipColor = ConfigColor("GraphCipColor");
|
||||
mBreakpointColor = ConfigColor("GraphBreakpointColor");
|
||||
mDisabledBreakpointColor = ConfigColor("GraphDisabledBreakpointColor");
|
||||
|
||||
fontChanged();
|
||||
loadCurrentGraph();
|
||||
|
|
|
@ -332,11 +332,12 @@ private:
|
|||
QColor mCommentBackgroundColor;
|
||||
QColor mLabelColor;
|
||||
QColor mLabelBackgroundColor;
|
||||
QColor mCipColor;
|
||||
QColor mCipBackgroundColor;
|
||||
QColor graphNodeColor;
|
||||
QColor mAddressColor;
|
||||
QColor mAddressBackgroundColor;
|
||||
QColor mCipColor;
|
||||
QColor mBreakpointColor;
|
||||
QColor mDisabledBreakpointColor;
|
||||
|
||||
BridgeCFGraph currentGraph;
|
||||
std::unordered_map<duint, duint> currentBlockMap;
|
||||
|
|
|
@ -2,6 +2,35 @@
|
|||
#define ACTIONHELPERS_H
|
||||
|
||||
#include <QAction>
|
||||
#include <functional>
|
||||
#include "Configuration.h"
|
||||
|
||||
//TODO: find the right "const &" "&", "&&" "" etc for passing around std::function
|
||||
using SlotFunc = std::function<void()>;
|
||||
using MakeMenuFunc1 = std::function<QMenu*(const QString &)>;
|
||||
using MakeMenuFunc2 = std::function<QMenu*(const QIcon &, const QString &)>;
|
||||
using MakeActionFunc1 = std::function<QAction*(const QString &, const SlotFunc &)>;
|
||||
using MakeActionFunc2 = std::function<QAction*(const QIcon &, const QString &, const SlotFunc &)>;
|
||||
using MakeShortcutActionFunc1 = std::function<QAction*(const QString &, const SlotFunc &, const char*)>;
|
||||
using MakeShortcutActionFunc2 = std::function<QAction*(const QIcon &, const QString &, const SlotFunc &, const char*)>;
|
||||
using MakeMenuActionFunc1 = std::function<QAction*(QMenu*, const QString &, const SlotFunc &)>;
|
||||
using MakeMenuActionFunc2 = std::function<QAction*(QMenu*, const QIcon &, const QString &, const SlotFunc &)>;
|
||||
using MakeShortcutMenuActionFunc1 = std::function<QAction*(QMenu*, const QString &, const SlotFunc &, const char*)>;
|
||||
using MakeShortcutMenuActionFunc2 = std::function<QAction*(QMenu*, const QIcon &, const QString &, const SlotFunc &, const char*)>;
|
||||
|
||||
struct ActionHelperFuncs
|
||||
{
|
||||
MakeMenuFunc1 makeMenu1;
|
||||
MakeMenuFunc2 makeMenu2;
|
||||
MakeActionFunc1 makeAction1;
|
||||
MakeActionFunc2 makeAction2;
|
||||
MakeShortcutActionFunc1 makeShortcutAction1;
|
||||
MakeShortcutActionFunc2 makeShortcutAction2;
|
||||
MakeMenuActionFunc1 makeMenuAction1;
|
||||
MakeMenuActionFunc2 makeMenuAction2;
|
||||
MakeShortcutMenuActionFunc1 makeShortcutMenuAction1;
|
||||
MakeShortcutMenuActionFunc2 makeShortcutMenuAction2;
|
||||
};
|
||||
|
||||
template<class Base>
|
||||
class ActionHelper
|
||||
|
@ -32,7 +61,6 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
inline QAction* connectAction(QAction* action, const char* slot)
|
||||
{
|
||||
QObject::connect(action, SIGNAL(triggered(bool)), getBase(), slot);
|
||||
|
@ -42,6 +70,7 @@ private:
|
|||
template<class T> // lambda or base member pointer
|
||||
inline QAction* connectAction(QAction* action, T callback)
|
||||
{
|
||||
//in case of a lambda getBase() is used as the 'context' object and not the 'receiver'
|
||||
QObject::connect(action, &QAction::triggered, getBase(), callback);
|
||||
return action;
|
||||
}
|
||||
|
@ -60,7 +89,53 @@ private:
|
|||
menu->addAction(action);
|
||||
return action;
|
||||
}
|
||||
|
||||
protected:
|
||||
inline ActionHelperFuncs getActionHelperFuncs()
|
||||
{
|
||||
ActionHelperFuncs funcs;
|
||||
funcs.makeMenu1 = [this](const QString & title)
|
||||
{
|
||||
return makeMenu(title);
|
||||
};
|
||||
funcs.makeMenu2 = [this](const QIcon & icon, const QString & title)
|
||||
{
|
||||
return makeMenu(icon, title);
|
||||
};
|
||||
funcs.makeAction1 = [this](const QString & text, const SlotFunc & slot)
|
||||
{
|
||||
return makeAction(text, slot);
|
||||
};
|
||||
funcs.makeAction2 = [this](const QIcon & icon, const QString & text, const SlotFunc & slot)
|
||||
{
|
||||
return makeAction(icon, text, slot);
|
||||
};
|
||||
funcs.makeShortcutAction1 = [this](const QString & text, const SlotFunc & slot, const char* shortcut)
|
||||
{
|
||||
return makeShortcutAction(text, slot, shortcut);
|
||||
};
|
||||
funcs.makeShortcutAction2 = [this](const QIcon & icon, const QString & text, const SlotFunc & slot, const char* shortcut)
|
||||
{
|
||||
return makeShortcutAction(icon, text, slot, shortcut);
|
||||
};
|
||||
funcs.makeMenuAction1 = [this](QMenu * menu, const QString & text, const SlotFunc & slot)
|
||||
{
|
||||
return makeMenuAction(menu, text, slot);
|
||||
};
|
||||
funcs.makeMenuAction2 = [this](QMenu * menu, const QIcon & icon, const QString & text, const SlotFunc & slot)
|
||||
{
|
||||
return makeMenuAction(menu, icon, text, slot);
|
||||
};
|
||||
funcs.makeShortcutMenuAction1 = [this](QMenu * menu, const QString & text, const SlotFunc & slot, const char* shortcut)
|
||||
{
|
||||
return makeShortcutMenuAction(menu, text, slot, shortcut);
|
||||
};
|
||||
funcs.makeShortcutMenuAction2 = [this](QMenu * menu, const QIcon & icon, const QString & text, const SlotFunc & slot, const char* shortcut)
|
||||
{
|
||||
return makeShortcutMenuAction(menu, icon, text, slot, shortcut);
|
||||
};
|
||||
return funcs;
|
||||
}
|
||||
|
||||
inline QMenu* makeMenu(const QString & title)
|
||||
{
|
||||
|
@ -126,4 +201,66 @@ private:
|
|||
std::vector<ActionShortcut> actionShortcutPairs;
|
||||
};
|
||||
|
||||
class MenuBuilder;
|
||||
|
||||
class ActionHelperProxy
|
||||
{
|
||||
ActionHelperFuncs funcs;
|
||||
|
||||
public:
|
||||
ActionHelperProxy(ActionHelperFuncs funcs)
|
||||
: funcs(funcs) { }
|
||||
|
||||
protected:
|
||||
inline QMenu* makeMenu(const QString & title)
|
||||
{
|
||||
return funcs.makeMenu1(title);
|
||||
}
|
||||
|
||||
inline QMenu* makeMenu(const QIcon & icon, const QString & title)
|
||||
{
|
||||
return funcs.makeMenu2(icon, title);
|
||||
}
|
||||
|
||||
inline QAction* makeAction(const QString & text, const SlotFunc & slot)
|
||||
{
|
||||
return funcs.makeAction1(text, slot);
|
||||
}
|
||||
|
||||
inline QAction* makeAction(const QIcon & icon, const QString & text, const SlotFunc & slot)
|
||||
{
|
||||
return funcs.makeAction2(icon, text, slot);
|
||||
}
|
||||
|
||||
inline QAction* makeShortcutAction(const QString & text, const SlotFunc & slot, const char* shortcut)
|
||||
{
|
||||
return funcs.makeShortcutAction1(text, slot, shortcut);
|
||||
}
|
||||
|
||||
inline QAction* makeShortcutAction(const QIcon & icon, const QString & text, const SlotFunc & slot, const char* shortcut)
|
||||
{
|
||||
return funcs.makeShortcutAction2(icon, text, slot, shortcut);
|
||||
}
|
||||
|
||||
inline QAction* makeMenuAction(QMenu* menu, const QString & text, const SlotFunc & slot)
|
||||
{
|
||||
return funcs.makeMenuAction1(menu, text, slot);
|
||||
}
|
||||
|
||||
inline QAction* makeMenuAction(QMenu* menu, const QIcon & icon, const QString & text, const SlotFunc & slot)
|
||||
{
|
||||
return funcs.makeMenuAction2(menu, icon, text, slot);
|
||||
}
|
||||
|
||||
inline QAction* makeShortcutMenuAction(QMenu* menu, const QString & text, const SlotFunc & slot, const char* shortcut)
|
||||
{
|
||||
return funcs.makeShortcutMenuAction1(menu, text, slot, shortcut);
|
||||
}
|
||||
|
||||
inline QAction* makeShortcutMenuAction(QMenu* menu, const QIcon & icon, const QString & text, const SlotFunc & slot, const char* shortcut)
|
||||
{
|
||||
return funcs.makeShortcutMenuAction2(menu, icon, text, slot, shortcut);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -218,6 +218,9 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
|
|||
defaultColors.insert("GraphBackgroundColor", Qt::transparent);
|
||||
defaultColors.insert("GraphNodeColor", QColor("#000000"));
|
||||
defaultColors.insert("GraphNodeBackgroundColor", Qt::transparent);
|
||||
defaultColors.insert("GraphCipColor", QColor("#000000"));
|
||||
defaultColors.insert("GraphBreakpointColor", QColor("#FF0000"));
|
||||
defaultColors.insert("GraphDisabledBreakpointColor", QColor("#00AA00"));
|
||||
|
||||
defaultColors.insert("ThreadCurrentColor", QColor("#FFFFFF"));
|
||||
defaultColors.insert("ThreadCurrentBackgroundColor", QColor("#000000"));
|
||||
|
|
|
@ -178,7 +178,8 @@ SOURCES += \
|
|||
Src/Utils/MRUList.cpp \
|
||||
Src/Gui/LocalVarsView.cpp \
|
||||
Src/Gui/MessagesBreakpoints.cpp \
|
||||
Src/Gui/AboutDialog.cpp
|
||||
Src/Gui/AboutDialog.cpp \
|
||||
Src/Gui/BreakpointMenu.cpp
|
||||
|
||||
|
||||
HEADERS += \
|
||||
|
@ -291,7 +292,8 @@ HEADERS += \
|
|||
Src/Utils/MRUList.h \
|
||||
Src/Gui/LocalVarsView.h \
|
||||
Src/Gui/MessagesBreakpoints.h \
|
||||
Src/Gui/AboutDialog.h
|
||||
Src/Gui/AboutDialog.h \
|
||||
Src/Gui/BreakpointMenu.h
|
||||
|
||||
|
||||
FORMS += \
|
||||
|
|
|
@ -218,7 +218,8 @@ SOURCES += \
|
|||
gui/Src/Utils/MRUList.cpp \
|
||||
gui/Src/Gui/LocalVarsView.cpp \
|
||||
gui/Src/Gui/MessagesBreakpoints.cpp \
|
||||
gui/Src/Gui/AboutDialog.cpp
|
||||
gui/Src/Gui/AboutDialog.cpp \
|
||||
gui/Src/Gui/BreakpointMenu.cpp
|
||||
|
||||
HEADERS += \
|
||||
gui/Src/Exports.h \
|
||||
|
@ -447,7 +448,8 @@ HEADERS += \
|
|||
gui/Src/Utils/MRUList.h \
|
||||
gui/Src/Gui/LocalVarsView.h \
|
||||
gui/Src/Gui/MessagesBreakpoints.h \
|
||||
gui/Src/Gui/AboutDialog.h
|
||||
gui/Src/Gui/AboutDialog.h \
|
||||
gui/Src/Gui/BreakpointMenu.h
|
||||
|
||||
FORMS += \
|
||||
gui/Src/Gui/AppearanceDialog.ui \
|
||||
|
|
Loading…
Reference in New Issue