From 79af7e656d659e053c4e9344f4d5f73354d19692 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Mon, 19 Oct 2020 12:11:09 +0800 Subject: [PATCH] Replace BreakpointMenu with CommonActions, which now handles more commands --- src/gui/Src/Gui/BreakpointMenu.cpp | 220 -------------- src/gui/Src/Gui/BreakpointMenu.h | 29 -- src/gui/Src/Gui/CPUDisassembly.cpp | 29 +- src/gui/Src/Gui/CPUDisassembly.h | 10 +- src/gui/Src/Gui/CPUDump.cpp | 67 ++-- src/gui/Src/Gui/CPUDump.h | 12 +- src/gui/Src/Gui/DisassemblerGraphView.cpp | 30 +- src/gui/Src/Gui/DisassemblerGraphView.h | 8 +- src/gui/Src/Gui/SourceView.cpp | 34 +-- src/gui/Src/Gui/SourceView.h | 6 +- src/gui/Src/Tracer/TraceBrowser.cpp | 105 ++----- src/gui/Src/Tracer/TraceBrowser.h | 8 +- src/gui/Src/Utils/CommonActions.cpp | 352 ++++++++++++++++++++++ src/gui/Src/Utils/CommonActions.h | 74 +++++ src/gui/x64dbg.pro | 4 +- src/x64dbg_translations.pro | 4 +- 16 files changed, 541 insertions(+), 451 deletions(-) delete mode 100644 src/gui/Src/Gui/BreakpointMenu.cpp delete mode 100644 src/gui/Src/Gui/BreakpointMenu.h create mode 100644 src/gui/Src/Utils/CommonActions.cpp create mode 100644 src/gui/Src/Utils/CommonActions.h diff --git a/src/gui/Src/Gui/BreakpointMenu.cpp b/src/gui/Src/Gui/BreakpointMenu.cpp deleted file mode 100644 index 259918c5..00000000 --- a/src/gui/Src/Gui/BreakpointMenu.cpp +++ /dev/null @@ -1,220 +0,0 @@ -#include "BreakpointMenu.h" -#include "MenuBuilder.h" -#include -#include -#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")); - // Replacement slot menu are only used when the breakpoints are full, so using "Unknown" as the placeholder. Might want to change this in case we display the menu when there are still free slots. - QAction* replaceSlot0Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot1.png"), tr("Replace Slot 0 (Unknown)"), std::bind(&BreakpointMenu::setHwBpOnSlot0ActionSlot, this)); - QAction* replaceSlot1Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot2.png"), tr("Replace Slot 1 (Unknown)"), std::bind(&BreakpointMenu::setHwBpOnSlot1ActionSlot, this)); - QAction* replaceSlot2Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot3.png"), tr("Replace Slot 2 (Unknown)"), std::bind(&BreakpointMenu::setHwBpOnSlot2ActionSlot, this)); - QAction* replaceSlot3Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot4.png"), tr("Replace Slot 3 (Unknown)"), std::bind(&BreakpointMenu::setHwBpOnSlot3ActionSlot, this)); - - builder->addMenu(makeMenu(DIcon("breakpoint.png"), tr("Breakpoint")), [ = ](QMenu * menu) - { - auto selection = mGetSelection(); - if(selection == 0) - return false; - BPXTYPE bpType = DbgGetBpxTypeAt(selection); - if((bpType & bp_normal) == bp_normal || (bpType & bp_hardware) == bp_hardware) - editSoftwareBreakpointAction->setText(tr("Edit")); - else - editSoftwareBreakpointAction->setText(tr("Set Conditional Breakpoint")); - 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 < bpList.count; i++) - { - if(bpList.bp[i].enabled) - { - 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); - //emit Disassembly::repainted(); -} - -void BreakpointMenu::editSoftBpActionSlot() -{ - auto selection = mGetSelection(); - if(selection == 0) - return; - BPXTYPE bpType = DbgGetBpxTypeAt(selection); - if((bpType & bp_hardware) == bp_hardware) - Breakpoints::editBP(bp_hardware, ToHexString(selection), dynamic_cast(parent())); - else if((bpType & bp_normal) == bp_normal) - Breakpoints::editBP(bp_normal, ToHexString(selection), dynamic_cast(parent())); - else - { - DbgCmdExecDirect(QString("bp %1").arg(ToHexString(selection))); //Blocking call - if(!Breakpoints::editBP(bp_normal, ToHexString(selection), dynamic_cast(parent()))) - Breakpoints::removeBP(bp_normal, selection); - } -} - -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); -} - - -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); - } - else // Slot used - { - wCmd = "bphwc " + ToPtrString((duint)(wBPList.bp[wSlotIndex].addr)); - DbgCmdExec(wCmd); - - Sleep(200); - - wCmd = "bphws " + ToPtrString(va); - DbgCmdExec(wCmd); - } - if(wBPList.count) - BridgeFree(wBPList.bp); -} diff --git a/src/gui/Src/Gui/BreakpointMenu.h b/src/gui/Src/Gui/BreakpointMenu.h deleted file mode 100644 index e1c88468..00000000 --- a/src/gui/Src/Gui/BreakpointMenu.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include -#include -#include "ActionHelpers.h" -#include "Imports.h" - -class BreakpointMenu : public QObject, public ActionHelperProxy -{ - Q_OBJECT -public: - using GetSelectionFunc = std::function; - - 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; -}; diff --git a/src/gui/Src/Gui/CPUDisassembly.cpp b/src/gui/Src/Gui/CPUDisassembly.cpp index 9dcdabba..0f8cc8c5 100644 --- a/src/gui/Src/Gui/CPUDisassembly.cpp +++ b/src/gui/Src/Gui/CPUDisassembly.cpp @@ -18,12 +18,11 @@ #include "HexEditDialog.h" #include "AssembleDialog.h" #include "StringUtil.h" -#include "Breakpoints.h" #include "XrefBrowseDialog.h" #include "SourceViewerManager.h" #include "MiscUtil.h" #include "MemoryPage.h" -#include "BreakpointMenu.h" +#include "CommonActions.h" #include "BrowseDialog.h" CPUDisassembly::CPUDisassembly(QWidget* parent, bool isMain) : Disassembly(parent, isMain) @@ -96,7 +95,7 @@ void CPUDisassembly::mouseDoubleClickEvent(QMouseEvent* event) // (Opcodes) Set INT3 breakpoint case 1: - mBreakpointMenu->toggleInt3BPActionSlot(); + mCommonActions->toggleInt3BPActionSlot(); break; // (Disassembly) Assemble dialog @@ -111,7 +110,7 @@ void CPUDisassembly::mouseDoubleClickEvent(QMouseEvent* event) // (Comments) Set comment dialog case 3: - setCommentSlot(); + mCommonActions->setCommentSlot(); break; // Undefined area @@ -308,11 +307,11 @@ void CPUDisassembly::setupRightClickContextMenu() return DbgFunctions()->PatchInRange(start, end); //something patched in selected range }); - mBreakpointMenu = new BreakpointMenu(this, getActionHelperFuncs(), [this]() + mCommonActions = new CommonActions(this, getActionHelperFuncs(), [this]() { return rvaToVa(getInitialSelection()); }); - mBreakpointMenu->build(mMenuBuilder); + mCommonActions->build(mMenuBuilder, CommonActions::ActionBreakpoint | CommonActions::ActionMemoryMap | CommonActions::ActionComment | CommonActions::ActionBookmark); mMenuBuilder->addMenu(makeMenu(DIcon("dump.png"), tr("&Follow in Dump")), [this](QMenu * menu) { @@ -326,7 +325,7 @@ void CPUDisassembly::setupRightClickContextMenu() return menu->actions().length() != 0; //only add this menu if there is something to follow }); - mMenuBuilder->addAction(makeShortcutAction(DIcon("memmap_find_address_page.png"), tr("Follow in Memory Map"), SLOT(followInMemoryMapSlot()), "ActionFollowMemMap")); + //mMenuBuilder->addAction(makeShortcutAction(DIcon("memmap_find_address_page.png"), tr("Follow in Memory Map"), SLOT(followInMemoryMapSlot()), "ActionFollowMemMap")); mMenuBuilder->addAction(makeShortcutAction(DIcon("source.png"), tr("Open Source File"), SLOT(openSourceSlot()), "ActionOpenSourceFile"), [this](QMenu*) { @@ -406,8 +405,8 @@ void CPUDisassembly::setupRightClickContextMenu() return true; }); - mMenuBuilder->addAction(makeShortcutAction(DIcon("comment.png"), tr("Comment"), SLOT(setCommentSlot()), "ActionSetComment")); - mMenuBuilder->addAction(makeShortcutAction(DIcon("bookmark_toggle.png"), tr("Toggle Bookmark"), SLOT(setBookmarkSlot()), "ActionToggleBookmark")); + //mMenuBuilder->addAction(makeShortcutAction(DIcon("comment.png"), tr("Comment"), SLOT(setCommentSlot()), "ActionSetComment")); + //mMenuBuilder->addAction(makeShortcutAction(DIcon("bookmark_toggle.png"), tr("Toggle Bookmark"), SLOT(setBookmarkSlot()), "ActionToggleBookmark")); mMenuBuilder->addSeparator(); MenuBuilder* analysisMenu = new MenuBuilder(this); @@ -785,7 +784,7 @@ restart: GuiUpdateAllViews(); } -void CPUDisassembly::setCommentSlot() +/*void CPUDisassembly::setCommentSlot() { if(!DbgIsDebugging()) return; @@ -843,7 +842,7 @@ void CPUDisassembly::setBookmarkSlot() GuiUpdateAllViews(); } - +*/ void CPUDisassembly::toggleFunctionSlot() { if(!DbgIsDebugging()) @@ -2040,10 +2039,10 @@ bool CPUDisassembly::getTokenValueText(QString & text) return true; } -void CPUDisassembly::followInMemoryMapSlot() -{ - DbgCmdExec(QString("memmapdump %1").arg(ToHexString(rvaToVa(getInitialSelection())))); -} +//void CPUDisassembly::followInMemoryMapSlot() +//{ +// DbgCmdExec(QString("memmapdump %1").arg(ToHexString(rvaToVa(getInitialSelection())))); +//} void CPUDisassembly::downloadCurrentSymbolsSlot() { diff --git a/src/gui/Src/Gui/CPUDisassembly.h b/src/gui/Src/Gui/CPUDisassembly.h index 59c67700..c52f95cc 100644 --- a/src/gui/Src/Gui/CPUDisassembly.h +++ b/src/gui/Src/Gui/CPUDisassembly.h @@ -2,12 +2,12 @@ #define CPUDISASSEMBLY_H #include "Disassembly.h" -#include "BreakpointMenu.h" // Needed forward declaration for parent container class class CPUSideBar; class GotoDialog; class XrefBrowseDialog; +class CommonActions; class CPUDisassembly : public Disassembly { @@ -41,8 +41,8 @@ public slots: void gotoOriginSlot(); void setLabelSlot(); void setLabelAddressSlot(); - void setCommentSlot(); - void setBookmarkSlot(); + //void setCommentSlot(); + //void setBookmarkSlot(); void toggleFunctionSlot(); void toggleArgumentSlot(); void addLoopSlot(); @@ -110,7 +110,7 @@ public slots: void createThreadSlot(); void copyTokenTextSlot(); void copyTokenValueSlot(); - void followInMemoryMapSlot(); + //void followInMemoryMapSlot(); void downloadCurrentSymbolsSlot(); protected: @@ -169,7 +169,7 @@ private: MenuBuilder* mMenuBuilder; MenuBuilder* mHighlightMenuBuilder; bool mHighlightContextMenu = false; - BreakpointMenu* mBreakpointMenu; + CommonActions* mCommonActions; }; #endif // CPUDISASSEMBLY_H diff --git a/src/gui/Src/Gui/CPUDump.cpp b/src/gui/Src/Gui/CPUDump.cpp index 8bb3ac98..346f5057 100644 --- a/src/gui/Src/Gui/CPUDump.cpp +++ b/src/gui/Src/Gui/CPUDump.cpp @@ -10,6 +10,7 @@ #include "CPUMultiDump.h" #include "GotoDialog.h" #include "CPUDisassembly.h" +#include "CommonActions.h" #include "WordEditDialog.h" #include "CodepageSelectionDialog.h" #include "MiscUtil.h" @@ -41,6 +42,11 @@ void CPUDump::setupContextMenu() return DbgIsDebugging(); }); + mCommonActions = new CommonActions(this, getActionHelperFuncs(), [this]() + { + return rvaToVa(getInitialSelection()); + }); + MenuBuilder* wBinaryMenu = new MenuBuilder(this); wBinaryMenu->addAction(makeShortcutAction(DIcon("binary_edit.png"), tr("&Edit"), SLOT(binaryEditSlot()), "ActionBinaryEdit")); wBinaryMenu->addAction(makeShortcutAction(DIcon("binary_fill.png"), tr("&Fill..."), SLOT(binaryFillSlot()), "ActionBinaryFill")); @@ -75,13 +81,16 @@ void CPUDump::setupContextMenu() { return DbgFunctions()->PatchInRange(rvaToVa(getSelectionStart()), rvaToVa(getSelectionEnd())); }); - mMenuBuilder->addAction(makeShortcutAction(DIcon("stack.png"), tr("Follow in Stack"), SLOT(followStackSlot()), "ActionFollowStack"), [this](QMenu*) - { - auto start = rvaToVa(getSelectionStart()); - return (DbgMemIsValidReadPtr(start) && DbgMemFindBaseAddr(start, 0) == DbgMemFindBaseAddr(DbgValFromString("csp"), 0)); - }); - mMenuBuilder->addAction(makeShortcutAction(DIcon("memmap_find_address_page.png"), tr("Follow in Memory Map"), SLOT(followInMemoryMapSlot()), "ActionFollowMemMap")); - mMenuBuilder->addAction(makeShortcutAction(DIcon(ArchValue("processor32.png", "processor64.png")), tr("Follow in Disassembler"), SLOT(followInDisasmSlot()), "ActionFollowDisasm")); + //mMenuBuilder->addAction(makeShortcutAction(DIcon("stack.png"), tr("Follow in Stack"), SLOT(followStackSlot()), "ActionFollowStack"), [this](QMenu*) + //{ + // auto start = rvaToVa(getSelectionStart()); + // return (DbgMemIsValidReadPtr(start) && DbgMemFindBaseAddr(start, 0) == DbgMemFindBaseAddr(DbgValFromString("csp"), 0)); + //}); + + mCommonActions->build(mMenuBuilder, CommonActions::ActionDisasm | CommonActions::ActionMemoryMap | CommonActions::ActionDumpData | CommonActions::ActionDisasmData + | CommonActions::ActionStackDump); + //mMenuBuilder->addAction(makeShortcutAction(DIcon("memmap_find_address_page.png"), tr("Follow in Memory Map"), SLOT(followInMemoryMapSlot()), "ActionFollowMemMap")); + //mMenuBuilder->addAction(makeShortcutAction(DIcon(ArchValue("processor32.png", "processor64.png")), tr("Follow in Disassembler"), SLOT(followInDisasmSlot()), "ActionFollowDisasm")); auto wIsValidReadPtrCallback = [this](QMenu*) { duint ptr = 0; @@ -89,8 +98,8 @@ void CPUDump::setupContextMenu() return DbgMemIsValidReadPtr(ptr); }; - mMenuBuilder->addAction(makeShortcutAction(DIcon("processor32.png"), ArchValue(tr("&Follow DWORD in Disassembler"), tr("&Follow QWORD in Disassembler")), SLOT(followDataSlot()), "ActionFollowDwordQwordDisasm"), wIsValidReadPtrCallback); - mMenuBuilder->addAction(makeShortcutAction(DIcon("dump.png"), ArchValue(tr("&Follow DWORD in Current Dump"), tr("&Follow QWORD in Current Dump")), SLOT(followDataDumpSlot()), "ActionFollowDwordQwordDump"), wIsValidReadPtrCallback); + //mMenuBuilder->addAction(makeShortcutAction(DIcon("processor32.png"), ArchValue(tr("&Follow DWORD in Disassembler"), tr("&Follow QWORD in Disassembler")), SLOT(followDataSlot()), "ActionFollowDwordQwordDisasm"), wIsValidReadPtrCallback); + //mMenuBuilder->addAction(makeShortcutAction(DIcon("dump.png"), ArchValue(tr("&Follow DWORD in Current Dump"), tr("&Follow QWORD in Current Dump")), SLOT(followDataDumpSlot()), "ActionFollowDwordQwordDump"), wIsValidReadPtrCallback); MenuBuilder* wFollowInDumpMenu = new MenuBuilder(this, [wIsValidReadPtrCallback, this](QMenu * menu) { @@ -1610,25 +1619,25 @@ void CPUDump::undoSelectionSlot() reloadData(); } -void CPUDump::followStackSlot() -{ - DbgCmdExec(QString("sdump " + ToPtrString(rvaToVa(getSelectionStart())))); -} +//void CPUDump::followStackSlot() +//{ +// DbgCmdExec(QString("sdump " + ToPtrString(rvaToVa(getSelectionStart())))); +//} -void CPUDump::followInDisasmSlot() -{ - DbgCmdExec(QString("disasm " + ToPtrString(rvaToVa(getSelectionStart())))); -} +//void CPUDump::followInDisasmSlot() +//{ +// DbgCmdExec(QString("disasm " + ToPtrString(rvaToVa(getSelectionStart())))); +//} -void CPUDump::followDataSlot() -{ - DbgCmdExec(QString("disasm \"[%1]\"").arg(ToPtrString(rvaToVa(getSelectionStart())))); -} +//void CPUDump::followDataSlot() +//{ +// DbgCmdExec(QString("disasm \"[%1]\"").arg(ToPtrString(rvaToVa(getSelectionStart())))); +//} -void CPUDump::followDataDumpSlot() -{ - DbgCmdExec(QString("dump \"[%1]\"").arg(ToPtrString(rvaToVa(getSelectionStart())))); -} +//void CPUDump::followDataDumpSlot() +//{ +// DbgCmdExec(QString("dump \"[%1]\"").arg(ToPtrString(rvaToVa(getSelectionStart())))); +//} void CPUDump::selectionUpdatedSlot() { @@ -1774,10 +1783,10 @@ void CPUDump::setView(ViewEnum_t view) } } -void CPUDump::followInMemoryMapSlot() -{ - DbgCmdExec(QString("memmapdump %1").arg(ToHexString(rvaToVa(getSelectionStart())))); -} +//void CPUDump::followInMemoryMapSlot() +//{ +// DbgCmdExec(QString("memmapdump %1").arg(ToHexString(rvaToVa(getSelectionStart())))); +//} void CPUDump::headerButtonReleasedSlot(int colIndex) { diff --git a/src/gui/Src/Gui/CPUDump.h b/src/gui/Src/Gui/CPUDump.h index e1694305..560cf0e5 100644 --- a/src/gui/Src/Gui/CPUDump.h +++ b/src/gui/Src/Gui/CPUDump.h @@ -7,6 +7,7 @@ class CPUMultiDump; class CPUDisassembly; class GotoDialog; +class CommonActions; class CPUDump : public HexDump { @@ -97,11 +98,11 @@ public slots: void findPattern(); void copyFileOffsetSlot(); void undoSelectionSlot(); - void followStackSlot(); + //void followStackSlot(); void findReferencesSlot(); - void followInDisasmSlot(); - void followDataSlot(); - void followDataDumpSlot(); + //void followInDisasmSlot(); + //void followDataSlot(); + //void followDataDumpSlot(); void watchSlot(); @@ -110,11 +111,12 @@ public slots: void followInDumpNSlot(); void allocMemorySlot(); - void followInMemoryMapSlot(); + //void followInMemoryMapSlot(); void headerButtonReleasedSlot(int colIndex); private: MenuBuilder* mMenuBuilder; + CommonActions* mCommonActions; QMenu* mPluginMenu; QMenu* mFollowInDumpMenu; diff --git a/src/gui/Src/Gui/DisassemblerGraphView.cpp b/src/gui/Src/Gui/DisassemblerGraphView.cpp index 9d4fb591..d1255779 100644 --- a/src/gui/Src/Gui/DisassemblerGraphView.cpp +++ b/src/gui/Src/Gui/DisassemblerGraphView.cpp @@ -13,7 +13,7 @@ #include #include #include -#include "BreakpointMenu.h" +#include "CommonActions.h" #include "StringUtil.h" #include "MiscUtil.h" #include @@ -2181,26 +2181,26 @@ void DisassemblerGraphView::setupContextMenu() return DbgIsDebugging() && this->ready; }); - mMenuBuilder->addAction(makeShortcutAction(DIcon(QString("processor%1.png").arg(ArchValue("32", "64"))), tr("Follow in &Disassembler"), SLOT(followDisassemblerSlot()), "ActionGraphFollowDisassembler"), [this](QMenu*) - { - return this->cur_instr != 0; - }); + //mMenuBuilder->addAction(makeShortcutAction(DIcon(QString("processor%1.png").arg(ArchValue("32", "64"))), tr("Follow in &Disassembler"), SLOT(followDisassemblerSlot()), "ActionGraphFollowDisassembler"), [this](QMenu*) + //{ + // return this->cur_instr != 0; + //}); mMenuBuilder->addSeparator(); - auto breakpointMenu = new BreakpointMenu(this, getActionHelperFuncs(), [this]() + mCommonActions = new CommonActions(this, getActionHelperFuncs(), [this]() { return zoomActionHelper(); }); - breakpointMenu->build(mMenuBuilder); + mCommonActions->build(mMenuBuilder, CommonActions::ActionBookmark | CommonActions::ActionComment | CommonActions::ActionDisasm); auto zoomActionHelperNonZero = [this](QMenu*) { return zoomActionHelper() != 0; }; - mMenuBuilder->addAction(makeShortcutAction(DIcon("comment.png"), tr("&Comment"), SLOT(setCommentSlot()), "ActionSetComment"), zoomActionHelperNonZero); + //mMenuBuilder->addAction(makeShortcutAction(DIcon("comment.png"), tr("&Comment"), SLOT(setCommentSlot()), "ActionSetComment"), zoomActionHelperNonZero); mMenuBuilder->addAction(makeShortcutAction(DIcon("label.png"), tr("&Label"), SLOT(setLabelSlot()), "ActionSetLabel"), zoomActionHelperNonZero); - mMenuBuilder->addAction(makeShortcutAction(DIcon("bookmark_toggle.png"), tr("Toggle Bookmark"), SLOT(setBookmarkSlot()), "ActionToggleBookmark")); + //mMenuBuilder->addAction(makeShortcutAction(DIcon("bookmark_toggle.png"), tr("Toggle Bookmark"), SLOT(setBookmarkSlot()), "ActionToggleBookmark")); mMenuBuilder->addAction(makeShortcutAction(DIcon("xrefs.png"), tr("Xrefs..."), SLOT(xrefSlot()), "ActionXrefs"), zoomActionHelperNonZero); MenuBuilder* gotoMenu = new MenuBuilder(this); @@ -2363,10 +2363,10 @@ void DisassemblerGraphView::keyPressEvent(QKeyEvent* event) } } -void DisassemblerGraphView::followDisassemblerSlot() +/*void DisassemblerGraphView::followDisassemblerSlot() { DbgCmdExec(QString("disasm %1").arg(ToPtrString(this->cur_instr))); -} +}*/ void DisassemblerGraphView::colorsUpdatedSlot() { @@ -2514,7 +2514,7 @@ void DisassemblerGraphView::saveImageSlot() this->viewport()->update(); } -void DisassemblerGraphView::setCommentSlot() +/*void DisassemblerGraphView::setCommentSlot() { duint wVA = this->get_cursor_pos(); LineEditDialog mLineEdit(this); @@ -2543,7 +2543,7 @@ void DisassemblerGraphView::setCommentSlot() SimpleErrorBox(this, tr("Error!"), tr("DbgSetCommentAt failed!")); this->refreshSlot(); -} +}*/ void DisassemblerGraphView::setLabelSlot() { @@ -2583,7 +2583,7 @@ restart: this->refreshSlot(); } -void DisassemblerGraphView::setBookmarkSlot() +/*void DisassemblerGraphView::setBookmarkSlot() { if(!DbgIsDebugging()) return; @@ -2603,7 +2603,7 @@ void DisassemblerGraphView::setBookmarkSlot() } GuiUpdateAllViews(); -} +}*/ void DisassemblerGraphView::xrefSlot() { diff --git a/src/gui/Src/Gui/DisassemblerGraphView.h b/src/gui/Src/Gui/DisassemblerGraphView.h index e1d02d6f..3cb0db63 100644 --- a/src/gui/Src/Gui/DisassemblerGraphView.h +++ b/src/gui/Src/Gui/DisassemblerGraphView.h @@ -23,6 +23,7 @@ class MenuBuilder; class CachedFontMetrics; class GotoDialog; class XrefBrowseDialog; +class CommonActions; class DisassemblerGraphView : public QAbstractScrollArea, public ActionHelper { @@ -267,7 +268,7 @@ public slots: void loadGraphSlot(BridgeCFGraphList* graph, duint addr); void graphAtSlot(duint addr); void updateGraphSlot(); - void followDisassemblerSlot(); + //void followDisassemblerSlot(); void colorsUpdatedSlot(); void fontsUpdatedSlot(); void shortcutsUpdatedSlot(); @@ -285,9 +286,9 @@ public slots: void followActionSlot(); void refreshSlot(); void saveImageSlot(); - void setCommentSlot(); + //void setCommentSlot(); void setLabelSlot(); - void setBookmarkSlot(); + //void setBookmarkSlot(); void xrefSlot(); void mnemonicHelpSlot(); void fitToWindowSlot(); @@ -334,6 +335,7 @@ private: std::vector row_edge_y; CachedFontMetrics* mFontMetrics; MenuBuilder* mMenuBuilder; + CommonActions* mCommonActions; QMenu* mPluginMenu; bool drawOverview; bool onlySummary; diff --git a/src/gui/Src/Gui/SourceView.cpp b/src/gui/Src/Gui/SourceView.cpp index 0f23802c..2f57797c 100644 --- a/src/gui/Src/Gui/SourceView.cpp +++ b/src/gui/Src/Gui/SourceView.cpp @@ -7,6 +7,7 @@ #include #include "FileLines.h" #include "Bridge.h" +#include "CommonActions.h" SourceView::SourceView(QString path, duint addr, QWidget* parent) : AbstractStdTable(parent), @@ -117,14 +118,6 @@ void SourceView::contextMenuSlot(const QPoint & pos) wMenu.exec(mapToGlobal(pos)); } -void SourceView::followDisassemblerSlot() -{ - duint addr = addrFromIndex(getInitialSelection()); - if(!DbgMemIsValidReadPtr(addr)) - return; - DbgCmdExec(QString("disasm %1").arg(ToPtrString(addr))); -} - void SourceView::followDumpSlot() { duint addr = addrFromIndex(getInitialSelection()); @@ -133,22 +126,6 @@ void SourceView::followDumpSlot() DbgCmdExec(QString("dump %1").arg(ToPtrString(addr))); } -void SourceView::toggleBookmarkSlot() -{ - duint addr = addrFromIndex(getInitialSelection()); - if(!DbgMemIsValidReadPtr(addr)) - return; - - bool result; - if(DbgGetBookmarkAt(addr)) - result = DbgSetBookmarkAt(addr, false); - else - result = DbgSetBookmarkAt(addr, true); - if(!result) - SimpleErrorBox(this, tr("Error!"), tr("DbgSetBookmarkAt failed!")); - GuiUpdateAllViews(); -} - void SourceView::gotoLineSlot() { bool ok = false; @@ -176,21 +153,16 @@ void SourceView::showInDirectorySlot() void SourceView::setupContextMenu() { mMenuBuilder = new MenuBuilder(this); - mMenuBuilder->addAction(makeAction(DIcon(ArchValue("processor32.png", "processor64.png")), tr("&Follow in Disassembler"), SLOT(followDisassemblerSlot())), [this](QMenu*) - { - return DbgMemIsValidReadPtr(addrFromIndex(getInitialSelection())); - }); mMenuBuilder->addAction(makeAction(DIcon("dump.png"), tr("Follow in &Dump"), SLOT(followDumpSlot())), [this](QMenu*) { return DbgMemIsValidReadPtr(addrFromIndex(getInitialSelection())); }); mMenuBuilder->addSeparator(); - mBreakpointMenu = new BreakpointMenu(this, getActionHelperFuncs(), [this]() + mCommonActions = new CommonActions(this, getActionHelperFuncs(), [this]() { return addrFromIndex(getInitialSelection()); }); - mBreakpointMenu->build(mMenuBuilder); - mMenuBuilder->addAction(makeShortcutAction(DIcon("bookmark_toggle.png"), tr("Toggle Bookmark"), SLOT(toggleBookmarkSlot()), "ActionToggleBookmark")); + mCommonActions->build(mMenuBuilder, CommonActions::ActionDisasm | CommonActions::ActionBreakpoint | CommonActions::ActionBookmark); mMenuBuilder->addSeparator(); mMenuBuilder->addAction(makeShortcutAction(DIcon("geolocation-goto.png"), tr("Go to line"), SLOT(gotoLineSlot()), "ActionGotoExpression")); mMenuBuilder->addAction(makeAction(DIcon("source.png"), tr("Open source file"), SLOT(openSourceFileSlot()))); diff --git a/src/gui/Src/Gui/SourceView.h b/src/gui/Src/Gui/SourceView.h index a9a9adef..1dc2eb6b 100644 --- a/src/gui/Src/Gui/SourceView.h +++ b/src/gui/Src/Gui/SourceView.h @@ -3,9 +3,9 @@ #include #include -#include "BreakpointMenu.h" class FileLines; +class CommonActions; class SourceView : public AbstractStdTable { @@ -25,16 +25,14 @@ public: private slots: void contextMenuSlot(const QPoint & pos); - void followDisassemblerSlot(); void followDumpSlot(); - void toggleBookmarkSlot(); void gotoLineSlot(); void openSourceFileSlot(); void showInDirectorySlot(); private: MenuBuilder* mMenuBuilder = nullptr; - BreakpointMenu* mBreakpointMenu = nullptr; + CommonActions* mCommonActions = nullptr; QString mSourcePath; duint mModBase; int mTabSize = 4; //TODO: make customizable? diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index 99a64c04..32f47dbe 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -6,10 +6,10 @@ #include "BrowseDialog.h" #include "QBeaEngine.h" #include "GotoDialog.h" +#include "CommonActions.h" #include "LineEditDialog.h" #include "WordEditDialog.h" #include "CachedFontMetrics.h" -#include "BreakpointMenu.h" #include "MRUList.h" #include @@ -796,6 +796,13 @@ void TraceBrowser::prepareData() void TraceBrowser::setupRightClickContextMenu() { mMenuBuilder = new MenuBuilder(this); + mCommonActions = new CommonActions(this, getActionHelperFuncs(), [this] + { + if(mTraceFile == nullptr || mTraceFile->Progress() < 100 || mTraceFile->Length() == 0) + return (duint)0; + else + return mTraceFile->Registers(getInitialSelection()).regcontext.cip; + }); QAction* toggleRunTrace = makeShortcutAction(DIcon("trace.png"), tr("Start Run Trace"), SLOT(toggleRunTraceSlot()), "ActionToggleRunTrace"); mMenuBuilder->addAction(toggleRunTrace, [toggleRunTrace](QMenu*) { @@ -854,19 +861,12 @@ void TraceBrowser::setupRightClickContextMenu() copyMenu->addAction(makeAction(DIcon("copy_address.png"), tr("Index"), SLOT(copyIndexSlot()))); mMenuBuilder->addMenu(makeMenu(DIcon("copy.png"), tr("&Copy")), copyMenu); - mMenuBuilder->addAction(makeShortcutAction(DIcon(ArchValue("processor32.png", "processor64.png")), tr("&Follow in Disassembler"), SLOT(followDisassemblySlot()), "ActionFollowDisasm"), isValid); + //mMenuBuilder->addAction(makeShortcutAction(DIcon(ArchValue("processor32.png", "processor64.png")), tr("&Follow in Disassembler"), SLOT(followDisassemblySlot()), "ActionFollowDisasm"), isValid); - mBreakpointMenu = new BreakpointMenu(this, getActionHelperFuncs(), [this, isValid]() - { - if(isValid(nullptr)) - return mTraceFile->Registers(getInitialSelection()).regcontext.cip; - else - return (duint)0; - }); - mBreakpointMenu->build(mMenuBuilder); + mCommonActions->build(mMenuBuilder, CommonActions::ActionDisasm | CommonActions::ActionBreakpoint | CommonActions::ActionComment | CommonActions::ActionBookmark); mMenuBuilder->addAction(makeShortcutAction(DIcon("label.png"), tr("Label Current Address"), SLOT(setLabelSlot()), "ActionSetLabel"), isDebugging); - mMenuBuilder->addAction(makeShortcutAction(DIcon("comment.png"), tr("&Comment"), SLOT(setCommentSlot()), "ActionSetComment"), isDebugging); - mMenuBuilder->addAction(makeShortcutAction(DIcon("bookmark_toggle.png"), tr("Toggle Bookmark"), SLOT(setBookmarkSlot()), "ActionToggleBookmark"), isDebugging); + //mMenuBuilder->addAction(makeShortcutAction(DIcon("comment.png"), tr("&Comment"), SLOT(setCommentSlot()), "ActionSetComment"), isDebugging); + //mMenuBuilder->addAction(makeShortcutAction(DIcon("bookmark_toggle.png"), tr("Toggle Bookmark"), SLOT(setBookmarkSlot()), "ActionToggleBookmark"), isDebugging); mMenuBuilder->addAction(makeShortcutAction(DIcon("highlight.png"), tr("&Highlighting mode"), SLOT(enableHighlightingModeSlot()), "ActionHighlightingMode"), isValid); mMenuBuilder->addAction(makeShortcutAction(DIcon("helpmnemonic.png"), tr("Help on mnemonic"), SLOT(mnemonicHelpSlot()), "ActionHelpOnMnemonic"), isValid); QAction* mnemonicBrief = makeShortcutAction(DIcon("helpbrief.png"), tr("Show mnemonic brief"), SLOT(mnemonicBriefSlot()), "ActionToggleMnemonicBrief"); @@ -1038,7 +1038,7 @@ void TraceBrowser::mouseDoubleClickEvent(QMouseEvent* event) switch(getColumnIndexFromX(event->x())) { case Index://Index: follow - followDisassemblySlot(); + mCommonActions->followDisassemblySlot(); break; case Address://Address: set RVA if(mRvaDisplayEnabled && mTraceFile->Registers(getInitialSelection()).regcontext.cip == mRvaDisplayBase) @@ -1051,13 +1051,13 @@ void TraceBrowser::mouseDoubleClickEvent(QMouseEvent* event) reloadData(); break; case Opcode: //Opcode: Breakpoint - mBreakpointMenu->toggleInt3BPActionSlot(); + mCommonActions->toggleInt3BPActionSlot(); break; case Disassembly: //Instructions: follow - followDisassemblySlot(); + mCommonActions->followDisassemblySlot(); break; case Comments: //Comment - setCommentSlot(); + mCommonActions->setCommentSlot(); break; } } @@ -1153,7 +1153,7 @@ void TraceBrowser::keyPressEvent(QKeyEvent* event) void TraceBrowser::onSelectionChanged(unsigned long long selection) { if(mAutoDisassemblyFollowSelection) - followDisassemblySlot(); + mCommonActions->followDisassemblySlot(); } void TraceBrowser::tokenizerConfigUpdatedSlot() @@ -1770,65 +1770,6 @@ void TraceBrowser::exportSlot() }); } -void TraceBrowser::setCommentSlot() -{ - if(!DbgIsDebugging() || mTraceFile == nullptr || mTraceFile->Progress() < 100) - return; - duint wVA = mTraceFile->Registers(getInitialSelection()).regcontext.cip; - LineEditDialog mLineEdit(this); - mLineEdit.setTextMaxLength(MAX_COMMENT_SIZE - 2); - QString addr_text = ToPtrString(wVA); - char comment_text[MAX_COMMENT_SIZE] = ""; - if(DbgGetCommentAt((duint)wVA, comment_text)) - { - if(comment_text[0] == '\1') //automatic comment - mLineEdit.setText(QString(comment_text + 1)); - else - mLineEdit.setText(QString(comment_text)); - } - mLineEdit.setWindowTitle(tr("Add comment at ") + addr_text); - if(mLineEdit.exec() != QDialog::Accepted) - return; - QString comment = mLineEdit.editText.replace('\r', "").replace('\n', ""); - if(!DbgSetCommentAt(wVA, comment.toUtf8().constData())) - SimpleErrorBox(this, tr("Error!"), tr("DbgSetCommentAt failed!")); - - static bool easter = isEaster(); - if(easter && comment.toLower() == "oep") - { - QFile file(":/icons/images/egg.wav"); - if(file.open(QIODevice::ReadOnly)) - { - QByteArray egg = file.readAll(); - PlaySoundA(egg.data(), 0, SND_MEMORY | SND_ASYNC | SND_NODEFAULT); - } - } - - GuiUpdateAllViews(); -} - -void TraceBrowser::setBookmarkSlot() -{ - if(!DbgIsDebugging()) - return; - duint wVA = mTraceFile->Registers(getInitialSelection()).regcontext.cip; - bool result; - if(DbgGetBookmarkAt(wVA)) - result = DbgSetBookmarkAt(wVA, false); - else - result = DbgSetBookmarkAt(wVA, true); - if(!result) - { - QMessageBox msg(QMessageBox::Critical, tr("Error!"), tr("DbgSetBookmarkAt failed!")); - msg.setWindowIcon(DIcon("compile-error.png")); - msg.setParent(this, Qt::Dialog); - msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint)); - msg.exec(); - } - - GuiUpdateAllViews(); -} - void TraceBrowser::setLabelSlot() { if(!DbgIsDebugging() || mTraceFile == nullptr || mTraceFile->Progress() < 100) @@ -1871,18 +1812,6 @@ void TraceBrowser::enableHighlightingModeSlot() reloadData(); } -void TraceBrowser::followDisassemblySlot() -{ - if(mTraceFile == nullptr || mTraceFile->Progress() < 100) - return; - - duint cip = mTraceFile->Registers(getInitialSelection()).regcontext.cip; - if(DbgMemIsValidReadPtr(cip)) - DbgCmdExec(QString("dis ").append(ToPtrString(cip))); - else - GuiAddStatusBarMessage(tr("Cannot follow %1. Address is invalid.\n").arg(ToPtrString(cip)).toUtf8().constData()); -} - void TraceBrowser::searchConstantSlot() { WordEditDialog constantDlg(this); diff --git a/src/gui/Src/Tracer/TraceBrowser.h b/src/gui/Src/Tracer/TraceBrowser.h index 8e459480..b76ee7e2 100644 --- a/src/gui/Src/Tracer/TraceBrowser.h +++ b/src/gui/Src/Tracer/TraceBrowser.h @@ -8,6 +8,7 @@ class TraceFileReader; class BreakpointMenu; class MRUList; +class CommonActions; class TraceBrowser : public AbstractTableView { @@ -60,6 +61,7 @@ private: ZydisTokenizer::InstructionToken registersTokens(unsigned long long atIndex); VaHistory mHistory; MenuBuilder* mMenuBuilder; + CommonActions* mCommonActions; bool mRvaDisplayEnabled; duint mRvaDisplayBase; @@ -160,11 +162,11 @@ public slots: void gotoSlot(); void gotoPreviousSlot(); void gotoNextSlot(); - void followDisassemblySlot(); + //void followDisassemblySlot(); void enableHighlightingModeSlot(); void setLabelSlot(); - void setCommentSlot(); - void setBookmarkSlot(); + //void setCommentSlot(); + //void setBookmarkSlot(); void mnemonicBriefSlot(); void mnemonicHelpSlot(); void copyDisassemblySlot(); diff --git a/src/gui/Src/Utils/CommonActions.cpp b/src/gui/Src/Utils/CommonActions.cpp new file mode 100644 index 00000000..09d7c99e --- /dev/null +++ b/src/gui/Src/Utils/CommonActions.cpp @@ -0,0 +1,352 @@ +#include "CommonActions.h" +#include "MenuBuilder.h" +#include +#include +#include +#include "StringUtil.h" +#include "MiscUtil.h" +#include "Breakpoints.h" +#include "LineEditDialog.h" + +CommonActions::CommonActions(QWidget* parent, ActionHelperFuncs funcs, GetSelectionFunc getSelection) + : QObject(parent), ActionHelperProxy(funcs), mGetSelection(getSelection) +{ +} + +void CommonActions::build(MenuBuilder* builder, int actions) +{ + build(builder, actions, [](QList> &, CommonActionsList) {}); +} + +void CommonActions::build(MenuBuilder* builder, int actions, std::function>&, CommonActionsList)> additionalAddress) +{ + // Condition Lambda + auto wIsValidCallback = [this](QMenu*) + { + return mGetSelection() != 0; + }; + auto wIsValidReadPtrCallback = [this](QMenu*) + { + duint ptr = 0; + DbgMemRead(mGetSelection(), (unsigned char*)&ptr, sizeof(duint)); + return DbgMemIsValidReadPtr(ptr); + }; + + // Menu action + if(actions & ActionDisasm) + { + builder->addAction(makeShortcutAction(DIcon(ArchValue("processor32.png", "processor64.png")), tr("Follow in Disassembler"), std::bind(&CommonActions::followDisassemblySlot, this), "ActionFollowDisasm"), wIsValidCallback); + } + if(actions & ActionDisasmData) + { + builder->addAction(makeCommandAction(DIcon("processor32.png"), ArchValue(tr("&Follow DWORD in Disassembler"), tr("&Follow QWORD in Disassembler")), "disasm [$]", "ActionFollowDwordQwordDisasm"), wIsValidReadPtrCallback); + } + if(actions & ActionDumpData) + { + builder->addAction(makeCommandAction(DIcon("dump.png"), ArchValue(tr("&Follow DWORD in Current Dump"), tr("&Follow QWORD in Current Dump")), "dump [$]", "ActionFollowDwordQwordDump"), wIsValidReadPtrCallback); + } + if(actions & ActionStackDump) + { + builder->addAction(makeCommandAction(DIcon("stack.png"), tr("Follow in Stack"), "sdump $", "ActionFollowStack"), [this](QMenu*) + { + auto start = mGetSelection(); + return (DbgMemIsValidReadPtr(start) && DbgMemFindBaseAddr(start, 0) == DbgMemFindBaseAddr(DbgValFromString("csp"), 0)); + }); + } + if(actions & ActionMemoryMap) + { + builder->addAction(makeCommandAction(DIcon("memmap_find_address_page.png"), tr("Follow in Memory Map"), "memmapdump $", "ActionFollowMemMap"), wIsValidCallback); + } + if(actions & ActionBreakpoint) + { + QAction* toggleBreakpointAction = makeShortcutAction(DIcon("breakpoint_toggle.png"), tr("Toggle"), std::bind(&CommonActions::toggleInt3BPActionSlot, this), "ActionToggleBreakpoint"); + QAction* editSoftwareBreakpointAction = makeShortcutAction(DIcon("breakpoint_edit_alt.png"), tr("Edit"), std::bind(&CommonActions::editSoftBpActionSlot, this), "ActionEditBreakpoint"); + QAction* setHwBreakpointAction = makeShortcutAction(DIcon("breakpoint_execute.png"), tr("Set Hardware on Execution"), std::bind(&CommonActions::toggleHwBpActionSlot, this), "ActionSetHwBpE"); + QAction* removeHwBreakpointAction = makeShortcutAction(DIcon("breakpoint_remove.png"), tr("Remove Hardware"), std::bind(&CommonActions::toggleHwBpActionSlot, this), "ActionRemoveHwBp"); + + QMenu* replaceSlotMenu = makeMenu(DIcon("breakpoint_execute.png"), tr("Set Hardware on Execution")); + // Replacement slot menu are only used when the breakpoints are full, so using "Unknown" as the placeholder. Might want to change this in case we display the menu when there are still free slots. + QAction* replaceSlot0Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot1.png"), tr("Replace Slot 0 (Unknown)"), std::bind(&CommonActions::setHwBpOnSlot0ActionSlot, this)); + QAction* replaceSlot1Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot2.png"), tr("Replace Slot 1 (Unknown)"), std::bind(&CommonActions::setHwBpOnSlot1ActionSlot, this)); + QAction* replaceSlot2Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot3.png"), tr("Replace Slot 2 (Unknown)"), std::bind(&CommonActions::setHwBpOnSlot2ActionSlot, this)); + QAction* replaceSlot3Action = makeMenuAction(replaceSlotMenu, DIcon("breakpoint_execute_slot4.png"), tr("Replace Slot 3 (Unknown)"), std::bind(&CommonActions::setHwBpOnSlot3ActionSlot, this)); + + builder->addMenu(makeMenu(DIcon("breakpoint.png"), tr("Breakpoint")), [ = ](QMenu * menu) + { + auto selection = mGetSelection(); + if(selection == 0) + return false; + BPXTYPE bpType = DbgGetBpxTypeAt(selection); + if((bpType & bp_normal) == bp_normal || (bpType & bp_hardware) == bp_hardware) + editSoftwareBreakpointAction->setText(tr("Edit")); + else + editSoftwareBreakpointAction->setText(tr("Set Conditional Breakpoint")); + 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 < bpList.count; i++) + { + if(bpList.bp[i].enabled) + { + 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; + }); + } + if(actions & ActionComment) + { + builder->addAction(makeShortcutAction(DIcon("comment.png"), tr("Comment"), std::bind(&CommonActions::setCommentSlot, this), "ActionSetComment"), wIsValidCallback); + } + if(actions & ActionBookmark) + { + builder->addAction(makeShortcutAction(DIcon("bookmark_toggle.png"), tr("Toggle Bookmark"), std::bind(&CommonActions::setBookmarkSlot, this), "ActionToggleBookmark"), wIsValidCallback); + } +} + +QAction* CommonActions::makeCommandAction(const QIcon & icon, const QString & text, const char* cmd, const char* shortcut) +{ + QAction* action; + action = makeShortcutAction(icon, text, [cmd, this]() + { + DbgCmdExec(QString(cmd).replace("$", ToPtrString(mGetSelection()))); + }, shortcut); + action->setData(QVariant(cmd)); + return action; +} + +QWidget* CommonActions::widgetparent() +{ + return dynamic_cast(parent()); +} + +// Actions slots +void CommonActions::followDisassemblySlot() +{ + duint cip = mGetSelection(); + if(DbgMemIsValidReadPtr(cip)) + DbgCmdExec(QString("dis ").append(ToPtrString(cip))); + else + GuiAddStatusBarMessage(tr("Cannot follow %1. Address is invalid.\n").arg(ToPtrString(cip)).toUtf8().constData()); +} + +void CommonActions::setCommentSlot() +{ + if(!DbgIsDebugging()) + return; + duint wVA = mGetSelection(); + LineEditDialog mLineEdit(widgetparent()); + mLineEdit.setTextMaxLength(MAX_COMMENT_SIZE - 2); + QString addr_text = ToPtrString(wVA); + char comment_text[MAX_COMMENT_SIZE] = ""; + if(DbgGetCommentAt((duint)wVA, comment_text)) + { + if(comment_text[0] == '\1') //automatic comment + mLineEdit.setText(QString(comment_text + 1)); + else + mLineEdit.setText(QString(comment_text)); + } + mLineEdit.setWindowTitle(tr("Add comment at ") + addr_text); + if(mLineEdit.exec() != QDialog::Accepted) + return; + QString comment = mLineEdit.editText.replace('\r', "").replace('\n', ""); + if(!DbgSetCommentAt(wVA, comment.toUtf8().constData())) + SimpleErrorBox(widgetparent(), tr("Error!"), tr("DbgSetCommentAt failed!")); + + static bool easter = isEaster(); + if(easter && comment.toLower() == "oep") + { + QFile file(":/icons/images/egg.wav"); + if(file.open(QIODevice::ReadOnly)) + { + QByteArray egg = file.readAll(); + PlaySoundA(egg.data(), 0, SND_MEMORY | SND_ASYNC | SND_NODEFAULT); + } + } + + GuiUpdateAllViews(); +} + +void CommonActions::setBookmarkSlot() +{ + if(!DbgIsDebugging()) + return; + duint wVA = mGetSelection(); + bool result; + if(DbgGetBookmarkAt(wVA)) + result = DbgSetBookmarkAt(wVA, false); + else + result = DbgSetBookmarkAt(wVA, true); + if(!result) + SimpleErrorBox(widgetparent(), tr("Error!"), tr("DbgSetBookmarkAt failed!")); + GuiUpdateAllViews(); +} + +void CommonActions::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); + //emit Disassembly::repainted(); +} + +void CommonActions::editSoftBpActionSlot() +{ + auto selection = mGetSelection(); + if(selection == 0) + return; + BPXTYPE bpType = DbgGetBpxTypeAt(selection); + if((bpType & bp_hardware) == bp_hardware) + Breakpoints::editBP(bp_hardware, ToHexString(selection), dynamic_cast(parent())); + else if((bpType & bp_normal) == bp_normal) + Breakpoints::editBP(bp_normal, ToHexString(selection), dynamic_cast(parent())); + else + { + DbgCmdExecDirect(QString("bp %1").arg(ToHexString(selection))); //Blocking call + if(!Breakpoints::editBP(bp_normal, ToHexString(selection), dynamic_cast(parent()))) + Breakpoints::removeBP(bp_normal, selection); + } +} + +void CommonActions::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); +} + + +void CommonActions::setHwBpOnSlot0ActionSlot() +{ + setHwBpAt(mGetSelection(), 0); +} + +void CommonActions::setHwBpOnSlot1ActionSlot() +{ + setHwBpAt(mGetSelection(), 1); +} + +void CommonActions::setHwBpOnSlot2ActionSlot() +{ + setHwBpAt(mGetSelection(), 2); +} + +void CommonActions::setHwBpOnSlot3ActionSlot() +{ + setHwBpAt(mGetSelection(), 3); +} + +void CommonActions::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); + } + else // Slot used + { + wCmd = "bphwc " + ToPtrString((duint)(wBPList.bp[wSlotIndex].addr)); + DbgCmdExec(wCmd); + + Sleep(200); + + wCmd = "bphws " + ToPtrString(va); + DbgCmdExec(wCmd); + } + if(wBPList.count) + BridgeFree(wBPList.bp); +} diff --git a/src/gui/Src/Utils/CommonActions.h b/src/gui/Src/Utils/CommonActions.h new file mode 100644 index 00000000..679657bd --- /dev/null +++ b/src/gui/Src/Utils/CommonActions.h @@ -0,0 +1,74 @@ +#ifndef COMMONACTIONS_H +#define COMMONACTIONS_H + +#include +#include +#include "ActionHelpers.h" + +class MenuBuilder; + +class CommonActions : public QObject, public ActionHelperProxy +{ + Q_OBJECT + +public: + typedef enum + { + ActionDisasm = 1, + ActionDisasmMore = 1 << 1, + ActionDisasmDump = 1 << 2, + ActionDisasmDumpMore = 1 << 3, + ActionDisasmData = 1 << 4, + ActionDump = 1 << 5, + ActionDumpMore = 1 << 6, + ActionDumpN = 1 << 7, + ActionDumpData = 1 << 8, + ActionStackDump = 1 << 9, + ActionMemoryMap = 1 << 10, + ActionGraph = 1 << 11, + ActionBreakpoint = 1 << 12, + ActionMemoryBreakpoint = 1 << 13, + ActionMnemonicHelp = 1 << 14, + ActionLabel = 1 << 15, + ActionLabelMore = 1 << 16, + ActionComment = 1 << 17, + ActionCommentMore = 1 << 18, + ActionBookmark = 1 << 19, + ActionBookmarkMore = 1 << 20, + ActionFindref = 1 << 21, + ActionFindrefMore = 1 << 22, + ActionXref = 1 << 23, + ActionXrefMore = 1 << 24, + ActionNewOrigin = 1 << 25, + ActionNewThread = 1 << 26, + ActionWatch = 1 << 27 + } CommonActionsList; + + using GetSelectionFunc = std::function; + + explicit CommonActions(QWidget* parent, ActionHelperFuncs funcs, GetSelectionFunc getSelection); + void build(MenuBuilder* builder, int actions); + void build(MenuBuilder* builder, int actions, std::function>&, CommonActionsList)> additionalAddress); + + QAction* makeCommandAction(const QIcon & icon, const QString & text, const char* cmd, const char* shortcut); +public slots: + void followDisassemblySlot(); + void setCommentSlot(); + void setBookmarkSlot(); + + void toggleInt3BPActionSlot(); + void editSoftBpActionSlot(); + void toggleHwBpActionSlot(); + void setHwBpOnSlot0ActionSlot(); + void setHwBpOnSlot1ActionSlot(); + void setHwBpOnSlot2ActionSlot(); + void setHwBpOnSlot3ActionSlot(); + void setHwBpAt(duint va, int slot); + +private: + GetSelectionFunc mGetSelection; + QWidget* widgetparent(); +}; + + +#endif //COMMONACTIONS_H diff --git a/src/gui/x64dbg.pro b/src/gui/x64dbg.pro index ff1ee59b..2e891c7e 100644 --- a/src/gui/x64dbg.pro +++ b/src/gui/x64dbg.pro @@ -81,6 +81,7 @@ SOURCES += \ Src/Imports.cpp \ Src/Tracer/TraceRegisters.cpp \ Src/Tracer/TraceWidget.cpp \ + Src/Utils/CommonActions.cpp \ Src/main.cpp \ Src/Gui/MainWindow.cpp \ Src/Gui/CPUWidget.cpp \ @@ -180,7 +181,6 @@ SOURCES += \ Src/Gui/LocalVarsView.cpp \ Src/Gui/MessagesBreakpoints.cpp \ Src/Gui/AboutDialog.cpp \ - Src/Gui/BreakpointMenu.cpp \ Src/Gui/ComboBoxDialog.cpp \ Src/Utils/SymbolAutoCompleteModel.cpp \ Src/Tracer/TraceBrowser.cpp \ @@ -201,6 +201,7 @@ HEADERS += \ Src/Gui/SystemBreakpointScriptDialog.h \ Src/Tracer/TraceRegisters.h \ Src/Tracer/TraceWidget.h \ + Src/Utils/CommonActions.h \ Src/main.h \ Src/Gui/MainWindow.h \ Src/Gui/CPUWidget.h \ @@ -304,7 +305,6 @@ HEADERS += \ Src/Gui/LocalVarsView.h \ Src/Gui/MessagesBreakpoints.h \ Src/Gui/AboutDialog.h \ - Src/Gui/BreakpointMenu.h \ Src/Gui/ComboBoxDialog.h \ Src/Utils/VaHistory.h \ Src/Utils/SymbolAutoCompleteModel.h \ diff --git a/src/x64dbg_translations.pro b/src/x64dbg_translations.pro index cc67aab7..732f9ea5 100644 --- a/src/x64dbg_translations.pro +++ b/src/x64dbg_translations.pro @@ -217,7 +217,7 @@ SOURCES += \ gui/Src/Gui/LocalVarsView.cpp \ gui/Src/Gui/MessagesBreakpoints.cpp \ gui/Src/Gui/AboutDialog.cpp \ - gui/Src/Gui/BreakpointMenu.cpp \ + gui/Src/Gui/CommonActions.cpp \ gui/Src/Utils/SymbolAutoCompleteModel.cpp \ gui/Src/Tracer/TraceBrowser.cpp \ gui/Src/Tracer/TraceFileReader.cpp \ @@ -457,7 +457,7 @@ HEADERS += \ gui/Src/Gui/LocalVarsView.h \ gui/Src/Gui/MessagesBreakpoints.h \ gui/Src/Gui/AboutDialog.h \ - gui/Src/Gui/BreakpointMenu.h \ + gui/Src/Gui/CommonActions.h \ gui/Src/Utils/SymbolAutoCompleteModel.h \ gui/Src/Tracer/TraceBrowser.h \ gui/Src/Tracer/TraceFileReader.h \