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;