From 8fa898fe9a6ac5a090320613957ed5d511d05a28 Mon Sep 17 00:00:00 2001 From: Sepalani Date: Mon, 21 May 2018 18:46:03 +0400 Subject: [PATCH] DebugInterface: MemoryPatches methods added CodeView: Restore instruction added --- Source/Core/Common/CMakeLists.txt | 1 + Source/Core/Common/Common.vcxproj | 2 + Source/Core/Common/Common.vcxproj.filters | 8 +- Source/Core/Common/Debug/MemoryPatches.cpp | 99 +++++++++++++++++++ Source/Core/Common/Debug/MemoryPatches.h | 52 ++++++++++ Source/Core/Common/DebugInterface.h | 13 ++- .../Core/Core/Debugger/PPCDebugInterface.cpp | 80 +++++++++++++-- Source/Core/Core/Debugger/PPCDebugInterface.h | 19 +++- .../Core/Core/HW/DSPLLE/DSPDebugInterface.cpp | 56 ++++++++++- .../Core/Core/HW/DSPLLE/DSPDebugInterface.h | 19 +++- Source/Core/DolphinQt2/CheatsManager.cpp | 2 +- .../DolphinQt2/Debugger/CodeViewWidget.cpp | 37 +++---- .../Core/DolphinQt2/Debugger/CodeViewWidget.h | 8 +- Source/Core/DolphinWX/Debugger/CodeView.cpp | 43 +++----- Source/Core/DolphinWX/Debugger/CodeView.h | 7 -- 15 files changed, 365 insertions(+), 81 deletions(-) create mode 100644 Source/Core/Common/Debug/MemoryPatches.cpp create mode 100644 Source/Core/Common/Debug/MemoryPatches.h diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index c0e3e94462..0feb950b91 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -9,6 +9,7 @@ add_library(common Crypto/AES.cpp Crypto/bn.cpp Crypto/ec.cpp + Debug/MemoryPatches.cpp Debug/Watches.cpp ENetUtil.cpp File.cpp diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj index c03dd0b6ac..995c6e733e 100644 --- a/Source/Core/Common/Common.vcxproj +++ b/Source/Core/Common/Common.vcxproj @@ -60,6 +60,7 @@ + @@ -176,6 +177,7 @@ + diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters index b26498b90b..dd041d490b 100644 --- a/Source/Core/Common/Common.vcxproj.filters +++ b/Source/Core/Common/Common.vcxproj.filters @@ -269,6 +269,9 @@ Debug + + Debug + @@ -292,7 +295,6 @@ - @@ -344,6 +346,10 @@ Debug + + + Debug + diff --git a/Source/Core/Common/Debug/MemoryPatches.cpp b/Source/Core/Common/Debug/MemoryPatches.cpp new file mode 100644 index 0000000000..db7a40c58b --- /dev/null +++ b/Source/Core/Common/Debug/MemoryPatches.cpp @@ -0,0 +1,99 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "Common/Debug/MemoryPatches.h" + +#include +#include + +namespace Common::Debug +{ +MemoryPatch::MemoryPatch(u32 address_, std::vector value_) + : address(address_), value(value_), is_enabled(State::Enabled) +{ +} + +MemoryPatch::MemoryPatch(u32 address, u32 value) + : MemoryPatch(address, {static_cast(value >> 24), static_cast(value >> 16), + static_cast(value >> 8), static_cast(value)}) +{ +} + +MemoryPatches::MemoryPatches() = default; +MemoryPatches::~MemoryPatches() = default; + +void MemoryPatches::SetPatch(u32 address, u32 value) +{ + const std::size_t index = m_patches.size(); + m_patches.emplace_back(address, value); + Patch(index); +} + +void MemoryPatches::SetPatch(u32 address, std::vector value) +{ + const std::size_t index = m_patches.size(); + m_patches.emplace_back(address, std::move(value)); + Patch(index); +} + +const std::vector& MemoryPatches::GetPatches() const +{ + return m_patches; +} + +void MemoryPatches::UnsetPatch(u32 address) +{ + const auto it = std::remove_if(m_patches.begin(), m_patches.end(), + [address](const auto& patch) { return patch.address == address; }); + + if (it == m_patches.end()) + return; + + const std::size_t size = m_patches.size(); + std::size_t index = size - std::distance(it, m_patches.end()); + while (index < size) + { + DisablePatch(index); + ++index; + } + m_patches.erase(it, m_patches.end()); +} + +void MemoryPatches::EnablePatch(std::size_t index) +{ + if (m_patches[index].is_enabled == MemoryPatch::State::Enabled) + return; + m_patches[index].is_enabled = MemoryPatch::State::Enabled; + Patch(index); +} + +void MemoryPatches::DisablePatch(std::size_t index) +{ + if (m_patches[index].is_enabled == MemoryPatch::State::Disabled) + return; + m_patches[index].is_enabled = MemoryPatch::State::Disabled; + Patch(index); +} + +bool MemoryPatches::HasEnabledPatch(u32 address) const +{ + return std::any_of(m_patches.begin(), m_patches.end(), [address](const MemoryPatch& patch) { + return patch.address == address && patch.is_enabled == MemoryPatch::State::Enabled; + }); +} + +void MemoryPatches::RemovePatch(std::size_t index) +{ + DisablePatch(index); + m_patches.erase(m_patches.begin() + index); +} + +void MemoryPatches::ClearPatches() +{ + const std::size_t size = m_patches.size(); + for (std::size_t index = 0; index < size; ++index) + DisablePatch(index); + m_patches.clear(); +} +} // namespace Common::Debug diff --git a/Source/Core/Common/Debug/MemoryPatches.h b/Source/Core/Common/Debug/MemoryPatches.h new file mode 100644 index 0000000000..cee814c6b5 --- /dev/null +++ b/Source/Core/Common/Debug/MemoryPatches.h @@ -0,0 +1,52 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "Common/CommonTypes.h" + +namespace Common::Debug +{ +struct MemoryPatch +{ + enum class State + { + Enabled, + Disabled + }; + + u32 address; + std::vector value; + State is_enabled; + + MemoryPatch(u32 address, std::vector value); + MemoryPatch(u32 address, u32 value); +}; + +class MemoryPatches +{ +public: + MemoryPatches(); + virtual ~MemoryPatches(); + + void SetPatch(u32 address, u32 value); + void SetPatch(u32 address, std::vector value); + const std::vector& GetPatches() const; + void UnsetPatch(u32 address); + void EnablePatch(std::size_t index); + void DisablePatch(std::size_t index); + bool HasEnabledPatch(u32 address) const; + void RemovePatch(std::size_t index); + void ClearPatches(); + +protected: + virtual void Patch(std::size_t index) = 0; + + std::vector m_patches; +}; +} // namespace Common::Debug diff --git a/Source/Core/Common/DebugInterface.h b/Source/Core/Common/DebugInterface.h index 363c8743e4..0d1ea6159a 100644 --- a/Source/Core/Common/DebugInterface.h +++ b/Source/Core/Common/DebugInterface.h @@ -10,6 +10,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/Debug/MemoryPatches.h" #include "Common/Debug/Watches.h" class DebugInterface @@ -34,6 +35,17 @@ public: virtual std::vector SaveWatchesToStrings() const = 0; virtual void ClearWatches() = 0; + // Memory Patches + virtual void SetPatch(u32 address, u32 value) = 0; + virtual void SetPatch(u32 address, std::vector value) = 0; + virtual const std::vector& GetPatches() const = 0; + virtual void UnsetPatch(u32 address) = 0; + virtual void EnablePatch(std::size_t index) = 0; + virtual void DisablePatch(std::size_t index) = 0; + virtual bool HasEnabledPatch(u32 address) const = 0; + virtual void RemovePatch(std::size_t index) = 0; + virtual void ClearPatches() = 0; + virtual std::string Disassemble(unsigned int /*address*/) { return "NODEBUGGER"; } virtual std::string GetRawMemoryString(int /*memory*/, unsigned int /*address*/) { @@ -59,7 +71,6 @@ public: virtual void SetPC(unsigned int /*address*/) {} virtual void Step() {} virtual void RunToBreakpoint() {} - virtual void Patch(unsigned int /*address*/, unsigned int /*value*/) {} virtual int GetColor(unsigned int /*address*/) { return 0xFFFFFFFF; } virtual std::string GetDescription(unsigned int /*address*/) = 0; virtual void Clear() = 0; diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.cpp b/Source/Core/Core/Debugger/PPCDebugInterface.cpp index b931307502..6222a94c34 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.cpp +++ b/Source/Core/Core/Debugger/PPCDebugInterface.cpp @@ -7,6 +7,7 @@ #include #include +#include "Common/Align.h" #include "Common/GekkoDisassembler.h" #include "Common/StringUtil.h" @@ -16,6 +17,33 @@ #include "Core/PowerPC/PPCSymbolDB.h" #include "Core/PowerPC/PowerPC.h" +void PPCPatches::Patch(std::size_t index) +{ + auto& patch = m_patches[index]; + if (patch.value.empty()) + return; + + const u32 address = patch.address; + const std::size_t size = patch.value.size(); + if (!PowerPC::HostIsRAMAddress(address)) + return; + + for (u32 offset = 0; offset < size; ++offset) + { + const u8 value = PowerPC::HostRead_U8(address + offset); + PowerPC::HostWrite_U8(patch.value[offset], address + offset); + patch.value[offset] = value; + + if (((address + offset) % 4) == 3) + PowerPC::ScheduleInvalidateCacheThreadSafe(Common::AlignDown(address + offset, 4)); + } + if (((address + size) % 4) != 0) + { + PowerPC::ScheduleInvalidateCacheThreadSafe( + Common::AlignDown(address + static_cast(size), 4)); + } +} + std::size_t PPCDebugInterface::SetWatch(u32 address, const std::string& name) { return m_watches.SetWatch(address, name); @@ -86,6 +114,51 @@ void PPCDebugInterface::ClearWatches() m_watches.Clear(); } +void PPCDebugInterface::SetPatch(u32 address, u32 value) +{ + m_patches.SetPatch(address, value); +} + +void PPCDebugInterface::SetPatch(u32 address, std::vector value) +{ + m_patches.SetPatch(address, value); +} + +const std::vector& PPCDebugInterface::GetPatches() const +{ + return m_patches.GetPatches(); +} + +void PPCDebugInterface::UnsetPatch(u32 address) +{ + m_patches.UnsetPatch(address); +} + +void PPCDebugInterface::EnablePatch(std::size_t index) +{ + m_patches.EnablePatch(index); +} + +void PPCDebugInterface::DisablePatch(std::size_t index) +{ + m_patches.DisablePatch(index); +} + +bool PPCDebugInterface::HasEnabledPatch(u32 address) const +{ + return m_patches.HasEnabledPatch(address); +} + +void PPCDebugInterface::RemovePatch(std::size_t index) +{ + m_patches.RemovePatch(index); +} + +void PPCDebugInterface::ClearPatches() +{ + m_patches.ClearPatches(); +} + std::string PPCDebugInterface::Disassemble(unsigned int address) { // PowerPC::HostRead_U32 seemed to crash on shutdown @@ -220,12 +293,6 @@ void PPCDebugInterface::ToggleMemCheck(unsigned int address, bool read, bool wri } } -void PPCDebugInterface::Patch(unsigned int address, unsigned int value) -{ - PowerPC::HostWrite_U32(value, address); - PowerPC::ScheduleInvalidateCacheThreadSafe(address); -} - // ======================================================= // Separate the blocks with colors. // ------------- @@ -275,5 +342,6 @@ void PPCDebugInterface::Clear() { ClearAllBreakpoints(); ClearAllMemChecks(); + ClearPatches(); ClearWatches(); } diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.h b/Source/Core/Core/Debugger/PPCDebugInterface.h index d6cafb93e0..e231ce71dd 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.h +++ b/Source/Core/Core/Debugger/PPCDebugInterface.h @@ -9,6 +9,12 @@ #include "Common/DebugInterface.h" +class PPCPatches : public Common::Debug::MemoryPatches +{ +private: + void Patch(std::size_t index) override; +}; + // wrapper between disasm control and Dolphin debugger class PPCDebugInterface final : public DebugInterface @@ -31,6 +37,17 @@ public: std::vector SaveWatchesToStrings() const override; void ClearWatches() override; + // Memory Patches + void SetPatch(u32 address, u32 value); + void SetPatch(u32 address, std::vector value); + const std::vector& GetPatches() const; + void UnsetPatch(u32 address); + void EnablePatch(std::size_t index); + void DisablePatch(std::size_t index); + bool HasEnabledPatch(u32 address) const; + void RemovePatch(std::size_t index); + void ClearPatches(); + std::string Disassemble(unsigned int address) override; std::string GetRawMemoryString(int memory, unsigned int address) override; int GetInstructionSize(int /*instruction*/) override { return 4; } @@ -57,7 +74,6 @@ public: void SetPC(unsigned int address) override; void Step() override {} void RunToBreakpoint() override; - void Patch(unsigned int address, unsigned int value) override; int GetColor(unsigned int address) override; std::string GetDescription(unsigned int address) override; @@ -65,4 +81,5 @@ public: private: Common::Debug::Watches m_watches; + PPCPatches m_patches; }; diff --git a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp index 4f755af9cb..ddc28d6e23 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp +++ b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp @@ -17,6 +17,11 @@ namespace DSP { namespace LLE { +void DSPPatches::Patch(std::size_t index) +{ + PanicAlert("Patch functionality not supported in DSP module."); +} + std::size_t DSPDebugInterface::SetWatch(u32 address, const std::string& name) { return m_watches.SetWatch(address, name); @@ -87,6 +92,51 @@ void DSPDebugInterface::ClearWatches() m_watches.Clear(); } +void DSPDebugInterface::SetPatch(u32 address, u32 value) +{ + m_patches.SetPatch(address, value); +} + +void DSPDebugInterface::SetPatch(u32 address, std::vector value) +{ + m_patches.SetPatch(address, value); +} + +const std::vector& DSPDebugInterface::GetPatches() const +{ + return m_patches.GetPatches(); +} + +void DSPDebugInterface::UnsetPatch(u32 address) +{ + m_patches.UnsetPatch(address); +} + +void DSPDebugInterface::EnablePatch(std::size_t index) +{ + m_patches.EnablePatch(index); +} + +void DSPDebugInterface::DisablePatch(std::size_t index) +{ + m_patches.DisablePatch(index); +} + +void DSPDebugInterface::RemovePatch(std::size_t index) +{ + m_patches.RemovePatch(index); +} + +bool DSPDebugInterface::HasEnabledPatch(u32 address) const +{ + return m_patches.HasEnabledPatch(address); +} + +void DSPDebugInterface::ClearPatches() +{ + m_patches.ClearPatches(); +} + std::string DSPDebugInterface::Disassemble(unsigned int address) { // we'll treat addresses as line numbers. @@ -202,11 +252,6 @@ void DSPDebugInterface::ToggleMemCheck(unsigned int address, bool read, bool wri PanicAlert("MemCheck functionality not supported in DSP module."); } -void DSPDebugInterface::Patch(unsigned int address, unsigned int value) -{ - PanicAlert("Patch functionality not supported in DSP module."); -} - // ======================================================= // Separate the blocks with colors. // ------------- @@ -264,6 +309,7 @@ void DSPDebugInterface::RunToBreakpoint() void DSPDebugInterface::Clear() { + ClearPatches(); ClearWatches(); } } // namespace LLE diff --git a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h index d0eb2e17c9..05dbc0245a 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h +++ b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h @@ -14,6 +14,12 @@ namespace DSP { namespace LLE { +class DSPPatches : public Common::Debug::MemoryPatches +{ +private: + void Patch(std::size_t index) override; +}; + class DSPDebugInterface final : public DebugInterface { public: @@ -34,6 +40,17 @@ public: std::vector SaveWatchesToStrings() const override; void ClearWatches() override; + // Memory Patches + void SetPatch(u32 address, u32 value); + void SetPatch(u32 address, std::vector value); + const std::vector& GetPatches() const; + void UnsetPatch(u32 address); + void EnablePatch(std::size_t index); + void DisablePatch(std::size_t index); + void RemovePatch(std::size_t index); + bool HasEnabledPatch(u32 address) const; + void ClearPatches(); + std::string Disassemble(unsigned int address) override; std::string GetRawMemoryString(int memory, unsigned int address) override; int GetInstructionSize(int instruction) override { return 1; } @@ -53,7 +70,6 @@ public: void SetPC(unsigned int address) override; void Step() override {} void RunToBreakpoint() override; - void Patch(unsigned int address, unsigned int value) override; int GetColor(unsigned int address) override; std::string GetDescription(unsigned int address) override; @@ -61,6 +77,7 @@ public: private: Common::Debug::Watches m_watches; + DSPPatches m_patches; }; } // namespace LLE } // namespace DSP diff --git a/Source/Core/DolphinQt2/CheatsManager.cpp b/Source/Core/DolphinQt2/CheatsManager.cpp index 59ca0f5c06..f1b6e904d8 100644 --- a/Source/Core/DolphinQt2/CheatsManager.cpp +++ b/Source/Core/DolphinQt2/CheatsManager.cpp @@ -549,7 +549,7 @@ void CheatsManager::Update() { if (m_watch[i].locked) { - PowerPC::debug_interface.Patch(m_watch[i].address, m_watch[i].locked_value); + PowerPC::debug_interface.SetPatch(m_watch[i].address, m_watch[i].locked_value); } switch (m_watch[i].type) diff --git a/Source/Core/DolphinQt2/Debugger/CodeViewWidget.cpp b/Source/Core/DolphinQt2/Debugger/CodeViewWidget.cpp index 01e9f726c9..5cf89ebc60 100644 --- a/Source/Core/DolphinQt2/Debugger/CodeViewWidget.cpp +++ b/Source/Core/DolphinQt2/Debugger/CodeViewWidget.cpp @@ -199,26 +199,8 @@ void CodeViewWidget::SetAddress(u32 address, SetAddressUpdate update) void CodeViewWidget::ReplaceAddress(u32 address, ReplaceWith replace) { - auto found = std::find_if(m_repl_list.begin(), m_repl_list.end(), - [address](ReplStruct r) { return r.address == address; }); - - if (found != m_repl_list.end()) - { - PowerPC::debug_interface.WriteExtraMemory(0, found->old_value, address); - m_repl_list.erase(found); - } - else - { - ReplStruct repl; - - repl.address = address; - repl.old_value = PowerPC::debug_interface.ReadInstruction(address); - - m_repl_list.push_back(repl); - - PowerPC::debug_interface.Patch(address, replace == ReplaceWith::BLR ? 0x4e800020 : 0x60000000); - } - + PowerPC::debug_interface.UnsetPatch(address); + PowerPC::debug_interface.SetPatch(address, replace == ReplaceWith::BLR ? 0x4e800020 : 0x60000000); Update(); } @@ -261,6 +243,8 @@ void CodeViewWidget::OnContextMenu() auto* insert_nop_action = AddAction(menu, tr("Insert &nop"), this, &CodeViewWidget::OnInsertNOP); auto* replace_action = AddAction(menu, tr("Re&place instruction"), this, &CodeViewWidget::OnReplaceInstruction); + auto* restore_action = + AddAction(menu, tr("Restore instruction"), this, &CodeViewWidget::OnRestoreInstruction); follow_branch_action->setEnabled(running && GetBranchFromAddress(addr)); @@ -271,6 +255,8 @@ void CodeViewWidget::OnContextMenu() for (auto* action : {symbol_rename_action, symbol_size_action, symbol_end_action}) action->setEnabled(has_symbol); + restore_action->setEnabled(running && PowerPC::debug_interface.HasEnabledPatch(addr)); + menu->exec(QCursor::pos()); Update(); } @@ -474,11 +460,20 @@ void CodeViewWidget::OnReplaceInstruction() if (good) { - PowerPC::debug_interface.Patch(addr, code); + PowerPC::debug_interface.UnsetPatch(addr); + PowerPC::debug_interface.SetPatch(addr, code); Update(); } } +void CodeViewWidget::OnRestoreInstruction() +{ + const u32 addr = GetContextAddress(); + + PowerPC::debug_interface.UnsetPatch(addr); + Update(); +} + void CodeViewWidget::resizeEvent(QResizeEvent*) { Update(); diff --git a/Source/Core/DolphinQt2/Debugger/CodeViewWidget.h b/Source/Core/DolphinQt2/Debugger/CodeViewWidget.h index c879b70d4b..e93280a500 100644 --- a/Source/Core/DolphinQt2/Debugger/CodeViewWidget.h +++ b/Source/Core/DolphinQt2/Debugger/CodeViewWidget.h @@ -70,14 +70,8 @@ private: void OnInsertBLR(); void OnInsertNOP(); void OnReplaceInstruction(); + void OnRestoreInstruction(); - struct ReplStruct - { - u32 address; - u32 old_value; - }; - - std::vector m_repl_list; bool m_updating = false; u32 m_address = 0; diff --git a/Source/Core/DolphinWX/Debugger/CodeView.cpp b/Source/Core/DolphinWX/Debugger/CodeView.cpp index da6f29abb7..3a55c61c3f 100644 --- a/Source/Core/DolphinWX/Debugger/CodeView.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeView.cpp @@ -45,6 +45,7 @@ enum IDM_INSERTBLR, IDM_INSERTNOP, IDM_ASSEMBLE, + IDM_RESTORE, IDM_RUNTOHERE, IDM_JITRESULTS, IDM_FOLLOWBRANCH, @@ -201,36 +202,10 @@ u32 CCodeView::AddrToBranch(u32 addr) return 0; } -void CCodeView::InsertBlrNop(int Blr) +void CCodeView::InsertBlrNop(int blr) { - // Check if this address has been modified - int find = -1; - for (u32 i = 0; i < m_blrList.size(); i++) - { - if (m_blrList.at(i).address == m_selection) - { - find = i; - break; - } - } - - // Save the old value - if (find >= 0) - { - m_debugger->WriteExtraMemory(0, m_blrList.at(find).oldValue, m_selection); - m_blrList.erase(m_blrList.begin() + find); - } - else - { - BlrStruct temp; - temp.address = m_selection; - temp.oldValue = m_debugger->ReadMemory(m_selection); - m_blrList.push_back(temp); - if (Blr == 0) - m_debugger->Patch(m_selection, 0x4e800020); - else - m_debugger->Patch(m_selection, 0x60000000); - } + m_debugger->UnsetPatch(m_selection); + m_debugger->SetPatch(m_selection, (blr == 0) ? 0x4e800020 : 0x60000000); Refresh(); } @@ -320,13 +295,19 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event) unsigned long code; if (dialog.GetValue().ToULong(&code, 0) && code <= std::numeric_limits::max()) { - m_debugger->Patch(m_selection, code); + m_debugger->UnsetPatch(m_selection); + m_debugger->SetPatch(m_selection, code); Refresh(); } } break; } + case IDM_RESTORE: + m_debugger->UnsetPatch(m_selection); + Refresh(); + break; + case IDM_JITRESULTS: { // Propagate back to the parent window and tell it @@ -451,6 +432,8 @@ void CCodeView::OnMouseUpR(wxMouseEvent& event) menu.Append(IDM_INSERTBLR, _("&Insert blr"))->Enable(Core::IsRunning()); menu.Append(IDM_INSERTNOP, _("Insert &nop"))->Enable(Core::IsRunning()); menu.Append(IDM_ASSEMBLE, _("Re&place instruction"))->Enable(Core::IsRunning()); + menu.Append(IDM_RESTORE, _("Restore instruction")) + ->Enable(Core::IsRunning() && m_debugger->HasEnabledPatch(m_selection)); // menu.Append(IDM_PATCHALERT, _("Patch alert"))->Enable(Core::IsRunning()); PopupMenu(&menu); event.Skip(); diff --git a/Source/Core/DolphinWX/Debugger/CodeView.h b/Source/Core/DolphinWX/Debugger/CodeView.h index b94a822455..77e9302ff2 100644 --- a/Source/Core/DolphinWX/Debugger/CodeView.h +++ b/Source/Core/DolphinWX/Debugger/CodeView.h @@ -55,13 +55,6 @@ private: u32 AddrToBranch(u32 addr); void OnResize(wxSizeEvent& event); - struct BlrStruct // for IDM_INSERTBLR - { - u32 address; - u32 oldValue; - }; - std::vector m_blrList; - static constexpr int LEFT_COL_WIDTH = 16; DebugInterface* m_debugger;